4 # template script for generating centos container for LXC
7 # lxc: linux Container library
10 # Daniel Lezcano <daniel.lezcano@free.fr>
11 # Ramez Hanna <rhanna@informatiq.org>
12 # Fajar A. Nugraha <github@fajar.net>
13 # Michael H. Warfield <mhw@WittsEnd.com>
15 # This library is free software; you can redistribute it and/or
16 # modify it under the terms of the GNU Lesser General Public
17 # License as published by the Free Software Foundation; either
18 # version 2.1 of the License, or (at your option) any later version.
20 # This library is distributed in the hope that it will be useful,
21 # but WITHOUT ANY WARRANTY; without even the implied warranty of
22 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 # Lesser General Public License for more details.
25 # You should have received a copy of the GNU Lesser General Public
26 # License along with this library; if not, write to the Free Software
27 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31 cache_base
=@LOCALSTATEDIR@
/cache
/lxc
/centos
/$arch
32 default_path
=@LXCPATH@
33 # We really need something better here!
37 lxc_network_link
=lxcbr0
40 # Alow for weird remixes like the Raspberry Pi
42 # Use the Mitre standard CPE identifier for the release ID if possible...
43 # This may be in /etc/os-release or /etc/system-release-cpe. We
44 # should be able to use EITHER. Give preference to /etc/os-release for now.
46 if [ -e /etc
/os-release
]
48 # This is a shell friendly configuration file. We can just source it.
49 # What we're looking for in here is the ID, VERSION_ID and the CPE_NAME
51 echo "Host CPE ID from /etc/os-release: ${CPE_NAME}"
54 if [ "${CPE_NAME}" = "" -a -e /etc
/system-release-cpe
]
56 CPE_NAME
=$
(head -n1 /etc
/system-release-cpe
)
57 CPE_URI
=$
(expr ${CPE_NAME} : '\([^:]*:[^:*]\)')
58 if [ "${CPE_URI}" != "cpe:/o" ]
62 echo "Host CPE ID from /etc/system-release-cpe: ${CPE_NAME}"
63 # Probably a better way to do this but sill remain posix
64 # compatible but this works, shrug...
65 # Must be nice and not introduce convenient bashisms here.
66 ID
=$
(expr ${CPE_NAME} : '[^:]*:[^:]*:[^:]*:\([^:]*\)')
67 VERSION_ID
=$
(expr ${CPE_NAME} : '[^:]*:[^:]*:[^:]*:[^:]*:\([^:]*\)')
71 if [ "${CPE_NAME}" != "" -a "${ID}" = "centos" -a "${VERSION_ID}" != "" ]
73 centos_host_ver
=${VERSION_ID}
75 elif [ -e /etc
/redhat-release
]
77 # Only if all other methods fail, try to parse the redhat-release file.
78 centos_host_ver
=$
( sed -e '/^CentOS /!d' -e 's/CentOS*\srelease\s*\([0-9][0-9]*\)\s.*/\1/' < /etc
/redhat-release
)
79 if [ "$centos_host_ver" != "" ]
85 # Map a few architectures to their generic Centos repository archs.
87 # CentOS currently doesn't support ARM but it's copied here from
88 # the Fedora template for completeness and that it will in the future.
90 # The two ARM archs are a bit of a guesstimate for the v5 and v6
91 # archs. V6 should have hardware floating point (Rasberry Pi).
92 # The "arm" arch is safer (no hardware floating point). So
93 # there may be cases where we "get it wrong" for some v6 other
97 armv3l|armv4l|armv5l
) arch
=arm
;;
98 armv6l|armv7l|armv8l
) arch
=armhfp
;;
103 # delete a device node if exists, and create a new one
104 rm -f $2 && mknod
-m $1 $2 $3 $4 $5
110 # disable selinux in centos
111 mkdir
-p $rootfs_path/selinux
112 echo 0 > $rootfs_path/selinux
/enforce
114 # Also kill it in the /etc/selinux/config file if it's there...
115 if [[ -f $rootfs_path/etc
/selinux
/config
]]
117 sed -i '/^SELINUX=/s/.*/SELINUX=disabled/' $rootfs_path/etc
/selinux
/config
120 # Nice catch from Dwight Engen in the Oracle template.
121 # Wantonly plagerized here with much appreciation.
122 if [ -f $rootfs_path/usr
/sbin
/selinuxenabled
]; then
123 mv $rootfs_path/usr
/sbin
/selinuxenabled
$rootfs_path/usr
/sbin
/selinuxenabled.lxcorig
124 ln -s /bin
/false
$rootfs_path/usr
/sbin
/selinuxenabled
127 # This is a known problem and documented in RedHat bugzilla as relating
128 # to a problem with auditing enabled. This prevents an error in
129 # the container "Cannot make/remove an entry for the specified session"
130 sed -i '/^session.*pam_loginuid.so/s/^session/# session/' ${rootfs_path}/etc
/pam.d
/login
131 sed -i '/^session.*pam_loginuid.so/s/^session/# session/' ${rootfs_path}/etc
/pam.d
/sshd
133 # configure the network using the dhcp
134 cat <<EOF > ${rootfs_path}/etc/sysconfig/network-scripts/ifcfg-eth0
145 cat <<EOF > ${rootfs_path}/etc/sysconfig/network
151 cat <<EOF > $rootfs_path/etc/hosts
152 127.0.0.1 localhost $name
156 cat <<EOF > $rootfs_path/etc/fstab
157 /dev/root / rootfs defaults 0 0
158 none /dev/shm tmpfs nosuid,nodev 0 0
161 # create lxc compatibility init script
162 if [ "$release" = "6" ]; then
163 cat <<EOF > $rootfs_path/etc/init/lxc-sysinit.conf
168 if [ "x$container" != "xlxc" -a "x$container" != "xlibvirt" ]; then
171 initctl start tty TTY=console
172 rm -f /var/lock/subsys/*
178 elif [ "$release" = "5" ]; then
179 cat <<EOF > $rootfs_path/etc/rc.d/lxc.sysinit
181 rm -f /etc/mtab /var/run/*.{pid,lock} /var/lock/subsys/*
182 rm -rf {/,/var}/tmp/*
183 echo "/dev/root / rootfs defaults 0 0" > /etc/mtab
186 chmod 755 $rootfs_path/etc
/rc.d
/lxc.sysinit
187 sed -i 's|si::sysinit:/etc/rc.d/rc.sysinit|si::bootwait:/etc/rc.d/lxc.sysinit|' $rootfs_path/etc
/inittab
188 sed -i 's|^1:|co:2345:respawn:/sbin/mingetty console\n1:|' $rootfs_path/etc
/inittab
189 sed -i 's|^\([56]:\)|#\1|' $rootfs_path/etc
/inittab
192 dev_path
="${rootfs_path}/dev"
195 mknod
-m 666 ${dev_path}/null c
1 3
196 mknod
-m 666 ${dev_path}/zero c
1 5
197 mknod
-m 666 ${dev_path}/random c
1 8
198 mknod
-m 666 ${dev_path}/urandom c
1 9
199 mkdir
-m 755 ${dev_path}/pts
200 mkdir
-m 1777 ${dev_path}/shm
201 mknod
-m 666 ${dev_path}/tty c
5 0
202 mknod
-m 666 ${dev_path}/tty0 c
4 0
203 mknod
-m 666 ${dev_path}/tty1 c
4 1
204 mknod
-m 666 ${dev_path}/tty2 c
4 2
205 mknod
-m 666 ${dev_path}/tty3 c
4 3
206 mknod
-m 666 ${dev_path}/tty4 c
4 4
207 mknod
-m 600 ${dev_path}/console c
5 1
208 mknod
-m 666 ${dev_path}/full c
1 7
209 mknod
-m 600 ${dev_path}/initctl p
210 mknod
-m 666 ${dev_path}/ptmx c
5 2
212 echo "setting root passwd to $root_password"
213 echo "root:$root_password" | chroot
$rootfs_path chpasswd
215 # This will need to be enhanced for CentOS 7 when systemd
216 # comes into play... /\/\|=mhw=|\/\/
221 configure_centos_init
()
223 sed -i 's|.sbin.start_udev||' ${rootfs_path}/etc
/rc.sysinit
224 sed -i 's|.sbin.start_udev||' ${rootfs_path}/etc
/rc.d
/rc.sysinit
225 if [ "$release" = "6" ]; then
226 chroot
${rootfs_path} chkconfig udev-post off
228 chroot
${rootfs_path} chkconfig network on
234 # check the mini centos was not already downloaded
235 INSTALL_ROOT
=$cache/partial
236 mkdir
-p $INSTALL_ROOT
237 if [ $?
-ne 0 ]; then
238 echo "Failed to create '$INSTALL_ROOT' directory"
242 # download a mini centos into a cache
243 echo "Downloading centos minimal ..."
244 YUM
="yum --installroot $INSTALL_ROOT -y --nogpgcheck"
245 PKG_LIST
="yum initscripts passwd rsyslog vim-minimal openssh-server openssh-clients dhclient chkconfig rootfiles policycoreutils"
247 # use temporary repository definition
248 REPO_FILE
=$INSTALL_ROOT/etc
/yum.repos.d
/lxc-centos-temp.repo
249 mkdir
-p $
(dirname $REPO_FILE)
250 cat <<EOF > $REPO_FILE
252 name=CentOS-$release - Base
253 mirrorlist=http://mirrorlist.centos.org/?release=$release&arch=$arch&repo=os
256 name=CentOS-$release - Updates
257 mirrorlist=http://mirrorlist.centos.org/?release=$release&arch=$arch&repo=updates
260 # create minimal device nodes, needed for "yum install" and "yum update" process
261 mkdir
-p $INSTALL_ROOT/dev
262 force_mknod
666 $INSTALL_ROOT/dev
/null c
1 3
263 force_mknod
666 $INSTALL_ROOT/dev
/urandom c
1 9
265 $YUM install $PKG_LIST
267 if [ $?
-ne 0 ]; then
268 echo "Failed to download the rootfs, aborting."
272 # use same nameservers as hosts, needed for "yum update later"
273 cp /etc
/resolv.conf
$INSTALL_ROOT/etc
/
275 # check whether rpmdb is under $HOME
276 if [ ! -e $INSTALL_ROOT/var
/lib
/rpm
/Packages
-a -e $INSTALL_ROOT/$HOME/.rpmdb
/Packages
]; then
277 echo "Fixing rpmdb location ..."
278 mv $INSTALL_ROOT/$HOME/.rpmdb
/[A-Z
]* $INSTALL_ROOT/var
/lib
/rpm
/
279 rm -rf $INSTALL_ROOT/$HOME/.rpmdb
280 chroot
$INSTALL_ROOT rpm
--rebuilddb 2>/dev
/null
283 # check whether rpmdb version is correct
284 chroot
$INSTALL_ROOT rpm
--quiet -q yum
2>/dev
/null
287 # if "rpm -q" doesn't work due to rpmdb version difference,
288 # then we need to redo the process using the newly-installed yum
289 if [ $ret -gt 0 ]; then
290 echo "Reinstalling packages ..."
291 mv $REPO_FILE $REPO_FILE.tmp
292 mkdir
$INSTALL_ROOT/etc
/yum.repos.disabled
293 mv $INSTALL_ROOT/etc
/yum.repos.d
/*.repo
$INSTALL_ROOT/etc
/yum.repos.disabled
/
294 mv $REPO_FILE.tmp
$REPO_FILE
295 mkdir
-p $INSTALL_ROOT/$INSTALL_ROOT/etc
296 cp /etc
/resolv.conf
$INSTALL_ROOT/$INSTALL_ROOT/etc
/
297 mkdir
-p $INSTALL_ROOT/$INSTALL_ROOT/dev
298 mknod
-m 666 $INSTALL_ROOT/$INSTALL_ROOT/dev
/null c
1 3
299 mknod
-m 666 $INSTALL_ROOT/$INSTALL_ROOT/dev
/urandom c
1 9
300 mkdir
-p $INSTALL_ROOT/$INSTALL_ROOT/var
/cache
/yum
301 cp -al $INSTALL_ROOT/var
/cache
/yum
/* $INSTALL_ROOT/$INSTALL_ROOT/var
/cache
/yum
/
302 chroot
$INSTALL_ROOT $YUM install $PKG_LIST
303 if [ $?
-ne 0 ]; then
304 echo "Failed to download the rootfs, aborting."
307 mv $INSTALL_ROOT/$INSTALL_ROOT $INSTALL_ROOT.tmp
309 mv $INSTALL_ROOT.tmp
$INSTALL_ROOT
313 rm -rf $INSTALL_ROOT/var
/cache
/yum
/*
315 mv "$INSTALL_ROOT" "$cache/rootfs"
316 echo "Download complete."
324 # make a local copy of the mini centos
325 echo -n "Copying rootfs to $rootfs_path ..."
326 #cp -a $cache/rootfs-$arch $rootfs_path || return 1
327 # i prefer rsync (no reason really)
328 mkdir
-p $rootfs_path
329 rsync
-a $cache/rootfs
/ $rootfs_path/
335 YUM
="chroot $cache/rootfs yum -y --nogpgcheck"
337 if [ $?
-ne 0 ]; then
345 mkdir
-p /var
/lock
/subsys
/
348 if [ $?
-ne 0 ]; then
349 echo "Cache repository is busy."
353 echo "Checking cache download in $cache/rootfs ... "
354 if [ ! -e "$cache/rootfs" ]; then
356 if [ $?
-ne 0 ]; then
357 echo "Failed to download 'centos base'"
361 echo "Cache found. Updating..."
363 if [ $?
-ne 0 ]; then
364 echo "Failed to update 'centos base', continuing with last known good cache"
366 echo "Update finished"
370 echo "Copy $cache/rootfs to $rootfs_path ... "
372 if [ $?
-ne 0 ]; then
373 echo "Failed to copy rootfs"
379 ) 200>/var
/lock
/subsys
/lxc-centos
387 mkdir
-p $config_path
388 cat <<EOF >> $config_path/config
389 lxc.utsname = $utsname
392 lxc.rootfs = $rootfs_path
393 lxc.mount = $config_path/fstab
394 lxc.cap.drop = sys_module mac_admin mac_override sys_time
396 lxc.autodev = $auto_dev
398 # example simple networking setup, uncomment to enable
399 #lxc.network.type = $lxc_network_type
400 #lxc.network.flags = up
401 #lxc.network.link = $lxc_network_link
402 #lxc.network.name = eth0
403 # additional example for veth network type, static MAC address,
404 # and persistent veth device name on host side
405 #lxc.network.hwaddr = 00:16:3e:77:52:20
406 #lxc.network.veth.pair = v-$name-e0
409 lxc.cgroup.devices.deny = a
411 lxc.cgroup.devices.allow = c 1:3 rwm
412 lxc.cgroup.devices.allow = c 1:5 rwm
414 lxc.cgroup.devices.allow = c 5:1 rwm
415 lxc.cgroup.devices.allow = c 5:0 rwm
416 lxc.cgroup.devices.allow = c 4:0 rwm
417 lxc.cgroup.devices.allow = c 4:1 rwm
419 lxc.cgroup.devices.allow = c 1:9 rwm
420 lxc.cgroup.devices.allow = c 1:8 rwm
421 lxc.cgroup.devices.allow = c 136:* rwm
422 lxc.cgroup.devices.allow = c 5:2 rwm
424 lxc.cgroup.devices.allow = c 254:0 rwm
427 cat <<EOF > $config_path/fstab
428 proc proc proc nodev,noexec,nosuid 0 0
429 devpts dev/pts devpts defaults 0 0
430 sysfs sys sysfs defaults 0 0
433 if [ $?
-ne 0 ]; then
434 echo "Failed to add configuration"
444 if [ ! -e $cache ]; then
448 # lock, so we won't purge while someone is creating a repository
452 echo "Cache repository is busy."
456 echo -n "Purging the download cache for centos-$release..."
457 rm --preserve-root --one-file-system -rf $cache && echo "Done." ||
exit 1
460 ) 200>/var
/lock
/subsys
/lxc-centos
467 $1 -n|--name=<container_name>
468 [-p|--path=<path>] [-c|--clean] [-R|--release=<CentOS_release>] [-A|--arch=<arch of the container>]
471 -n,--name container name, used to as an identifier for that container from now on
473 -p,--path path to where the container rootfs will be created, defaults to /var/lib/lxc. The container config will go under /var/lib/lxc in that case
474 -c,--clean clean the cache
475 -R,--release Centos release for the new container. if the host is Centos, then it will defaultto the host's release.
476 --fqdn fully qualified domain name (FQDN) for DNS and system naming
477 -A,--arch NOT USED YET. Define what arch the container will be [i686,x86_64]
478 -h,--help print this help
483 options
=$
(getopt
-o hp
:n
:cR
: -l help,path
:,rootfs
:,name
:,clean
,release
:,fqdn
: -- "$@")
484 if [ $?
-ne 0 ]; then
488 eval set -- "$options"
493 -h|
--help) usage
$0 && exit 0;;
494 -p|
--path) path
=$2; shift 2;;
495 --rootfs) rootfs
=$2; shift 2;;
496 -n|
--name) name
=$2; shift 2;;
497 -c|
--clean) clean
=$2; shift 2;;
498 -R|
--release) release
=$2; shift 2;;
499 --fqdn) utsname
=$2; shift 2;;
500 --) shift 1; break ;;
505 if [ ! -z "$clean" -a -z "$path" ]; then
510 if [ -z "${utsname}" ]; then
514 # This follows a standard "resolver" convention that an FQDN must have
515 # at least two dots or it is considered a local relative host name.
516 # If it doesn't, append the dns domain name of the host system.
518 # This changes one significant behavior when running
519 # "lxc_create -n Container_Name" without using the
523 # utsname and hostname = Container_Name
525 # utsname and hostname = Container_Name.Domain_Name
527 if [ $
(expr "$utsname" : '.*\..*\.') = 0 ]; then
528 if [ -n "$(dnsdomainname)" ]; then
529 utsname
=${utsname}.$
(dnsdomainname
)
533 type yum
>/dev
/null
2>&1
534 if [ $?
-ne 0 ]; then
535 echo "'yum' command is missing"
539 if [ -z "$path" ]; then
540 path
=$default_path/$name
543 if [ -z "$release" ]; then
544 if [ "$is_centos" -a "$centos_host_ver" ]; then
545 release
=$centos_host_ver
547 echo "This is not a centos host and release missing, defaulting to 6 use -R|--release to specify release"
552 # CentOS 7 and above should run systemd. We need autodev enabled to keep
553 # systemd from causing problems.
554 if [ $release -gt 6 ]; then
560 if [ "$(id -u)" != "0" ]; then
561 echo "This script should be run as 'root'"
566 if [ -z "$rootfs_path" ]; then
567 rootfs_path
=$path/rootfs
568 # check for 'lxc.rootfs' passed in through default config by lxc-create
569 if grep -q '^lxc.rootfs' $path/config
2>/dev
/null
; then
570 rootfs_path
=`grep 'lxc.rootfs =' $path/config | awk -F= '{ print $2 }'`
573 config_path
=$default_path/$name
574 cache
=$cache_base/$release
578 echo "Interrupted, so cleaning up"
580 # maybe was interrupted before copy config
582 rm -rf $default_path/$name
587 trap revert SIGHUP SIGINT SIGTERM
590 if [ $?
-ne 0 ]; then
591 echo "failed write configuration file"
596 if [ $?
-ne 0 ]; then
597 echo "failed to install centos"
602 if [ $?
-ne 0 ]; then
603 echo "failed to configure centos for a container"
607 configure_centos_init
609 if [ ! -z $clean ]; then
613 echo "container rootfs and config created, default root password is '$root_password'"
614 echo "edit the config file to check/enable networking setup"