]> git.proxmox.com Git - mirror_lxc.git/blob - templates/lxc-centos.in
Merge pull request #540 from ysbnim/master
[mirror_lxc.git] / templates / lxc-centos.in
1 #!/bin/bash
2
3 #
4 # template script for generating centos container for LXC
5
6 #
7 # lxc: linux Container library
8
9 # Authors:
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>
14
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.
19
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.
24
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
28
29 #Configurations
30 default_path=@LXCPATH@
31
32 # Some combinations of the tuning knobs below do not exactly make sense.
33 # but that's ok.
34 #
35 # If the "root_password" is non-blank, use it, else set a default.
36 # This can be passed to the script as an environment variable and is
37 # set by a shell conditional assignment. Looks weird but it is what it is.
38 #
39 # If the root password contains a ding ($) then try to expand it.
40 # That will pick up things like ${name} and ${RANDOM}.
41 # If the root password contains more than 3 consecutive X's, pass it as
42 # a template to mktemp and take the result.
43 #
44 # If root_display_password = yes, display the temporary root password at exit.
45 # If root_store_password = yes, store it in the configuration directory
46 # If root_prompt_password = yes, invoke "passwd" to force the user to change
47 # the root password after the container is created.
48 # If root_expire_password = yes, you will be prompted to change the root
49 # password at the first login.
50 #
51 # These are conditional assignments... The can be overridden from the
52 # preexisting environment variables...
53 #
54 # Make sure this is in single quotes to defer expansion to later!
55 # :{root_password='Root-${name}-${RANDOM}'}
56 : ${root_password='Root-${name}-XXXXXX'}
57
58 # Now, it doesn't make much sense to display, store, and force change
59 # together. But, we gotta test, right???
60 : ${root_display_password='no'}
61 : ${root_store_password='yes'}
62 # Prompting for something interactive has potential for mayhem
63 # with users running under the API... Don't default to "yes"
64 : ${root_prompt_password='no'}
65
66 # Expire root password? Default to yes, but can be overridden from
67 # the environment variable
68 : ${root_expire_password='yes'}
69
70 # These are only going into comments in the resulting config...
71 lxc_network_type=veth
72 lxc_network_link=lxcbr0
73
74 # is this centos?
75 # Alow for weird remixes like the Raspberry Pi
76 #
77 # Use the Mitre standard CPE identifier for the release ID if possible...
78 # This may be in /etc/os-release or /etc/system-release-cpe. We
79 # should be able to use EITHER. Give preference to /etc/os-release for now.
80
81 # Detect use under userns (unsupported)
82 for arg in "$@"; do
83 [ "$arg" = "--" ] && break
84 if [ "$arg" = "--mapped-uid" -o "$arg" = "--mapped-gid" ]; then
85 echo "This template can't be used for unprivileged containers." 1>&2
86 echo "You may want to try the \"download\" template instead." 1>&2
87 exit 1
88 fi
89 done
90
91 # Make sure the usual locations are in PATH
92 export PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin
93
94 if [ -e /etc/os-release ]
95 then
96 # This is a shell friendly configuration file. We can just source it.
97 # What we're looking for in here is the ID, VERSION_ID and the CPE_NAME
98 . /etc/os-release
99 echo "Host CPE ID from /etc/os-release: ${CPE_NAME}"
100 fi
101
102 if [ "${CPE_NAME}" = "" -a -e /etc/system-release-cpe ]
103 then
104 CPE_NAME=$(head -n1 /etc/system-release-cpe)
105 CPE_URI=$(expr ${CPE_NAME} : '\([^:]*:[^:]*\)')
106 if [ "${CPE_URI}" != "cpe:/o" ]
107 then
108 CPE_NAME=
109 else
110 # Probably a better way to do this but sill remain posix
111 # compatible but this works, shrug...
112 # Must be nice and not introduce convenient bashisms here.
113 #
114 # According to the official registration at Mitre and NIST,
115 # this should have been something like this for CentOS:
116 # cpe:/o:centos:centos:6
117 # or this:
118 # cpe:/o:centos:centos:6.5
119 #
120 ID=$(expr ${CPE_NAME} : '[^:]*:[^:]*:[^:]*:\([^:]*\)')
121 # The "enterprise_linux" is a bone toss back to RHEL.
122 # Since CentOS and RHEL are so tightly coupled, we'll
123 # take the RHEL version if we're running on it and do the
124 # equivalent version for CentOS.
125 if [ ${ID} = "linux" -o ${ID} = "enterprise_linux" ]
126 then
127 # Instead we got this: cpe:/o:centos:linux:6
128 ID=$(expr ${CPE_NAME} : '[^:]*:[^:]*:\([^:]*\)')
129 fi
130
131 VERSION_ID=$(expr ${CPE_NAME} : '[^:]*:[^:]*:[^:]*:[^:]*:\([^:]*\)')
132 echo "Host CPE ID from /etc/system-release-cpe: ${CPE_NAME}"
133 fi
134 fi
135
136 if [ "${CPE_NAME}" != "" -a "${ID}" = "centos" -a "${VERSION_ID}" != "" ]
137 then
138 centos_host_ver=${VERSION_ID}
139 is_centos=true
140 elif [ "${CPE_NAME}" != "" -a "${ID}" = "redhat" -a "${VERSION_ID}" != "" ]
141 then
142 redhat_host_ver=${VERSION_ID}
143 is_redhat=true
144 elif [ -e /etc/centos-release ]
145 then
146 # Only if all other methods fail, try to parse the redhat-release file.
147 centos_host_ver=$( sed -e '/^CentOS /!d' -e 's/CentOS.*\srelease\s*\([0-9][0-9.]*\)\s.*/\1/' < /etc/centos-release )
148 if [ "$centos_host_ver" != "" ]
149 then
150 is_centos=true
151 fi
152 fi
153
154 force_mknod()
155 {
156 # delete a device node if exists, and create a new one
157 rm -f $2 && mknod -m $1 $2 $3 $4 $5
158 }
159
160 configure_centos()
161 {
162
163 # disable selinux in centos
164 mkdir -p $rootfs_path/selinux
165 echo 0 > $rootfs_path/selinux/enforce
166
167 # Also kill it in the /etc/selinux/config file if it's there...
168 if [ -f $rootfs_path/etc/selinux/config ]
169 then
170 sed -i '/^SELINUX=/s/.*/SELINUX=disabled/' $rootfs_path/etc/selinux/config
171 fi
172
173 # Nice catch from Dwight Engen in the Oracle template.
174 # Wantonly plagerized here with much appreciation.
175 if [ -f $rootfs_path/usr/sbin/selinuxenabled ]; then
176 mv $rootfs_path/usr/sbin/selinuxenabled $rootfs_path/usr/sbin/selinuxenabled.lxcorig
177 ln -s /bin/false $rootfs_path/usr/sbin/selinuxenabled
178 fi
179
180 # This is a known problem and documented in RedHat bugzilla as relating
181 # to a problem with auditing enabled. This prevents an error in
182 # the container "Cannot make/remove an entry for the specified session"
183 sed -i '/^session.*pam_loginuid.so/s/^session/# session/' ${rootfs_path}/etc/pam.d/login
184 sed -i '/^session.*pam_loginuid.so/s/^session/# session/' ${rootfs_path}/etc/pam.d/sshd
185
186 if [ -f ${rootfs_path}/etc/pam.d/crond ]
187 then
188 sed -i '/^session.*pam_loginuid.so/s/^session/# session/' ${rootfs_path}/etc/pam.d/crond
189 fi
190
191 # In addition to disabling pam_loginuid in the above config files
192 # we'll also disable it by linking it to pam_permit to catch any
193 # we missed or any that get installed after the container is built.
194 #
195 # Catch either or both 32 and 64 bit archs.
196 if [ -f ${rootfs_path}/lib/security/pam_loginuid.so ]
197 then
198 ( cd ${rootfs_path}/lib/security/
199 mv pam_loginuid.so pam_loginuid.so.disabled
200 ln -s pam_permit.so pam_loginuid.so
201 )
202 fi
203
204 if [ -f ${rootfs_path}/lib64/security/pam_loginuid.so ]
205 then
206 ( cd ${rootfs_path}/lib64/security/
207 mv pam_loginuid.so pam_loginuid.so.disabled
208 ln -s pam_permit.so pam_loginuid.so
209 )
210 fi
211
212 # Set default localtime to the host localtime if not set...
213 if [ -e /etc/localtime -a ! -e ${rootfs_path}/etc/localtime ]
214 then
215 # if /etc/localtime is a symlink, this should preserve it.
216 cp -a /etc/localtime ${rootfs_path}/etc/localtime
217 fi
218
219 # Deal with some dain bramage in the /etc/init.d/halt script.
220 # Trim it and make it our own and link it in before the default
221 # halt script so we can intercept it. This also preventions package
222 # updates from interferring with our interferring with it.
223 #
224 # There's generally not much in the halt script that useful but what's
225 # in there from resetting the hardware clock down is generally very bad.
226 # So we just eliminate the whole bottom half of that script in making
227 # ourselves a copy. That way a major update to the init scripts won't
228 # trash what we've set up.
229 if [ -f ${rootfs_path}/etc/init.d/halt ]
230 then
231 sed -e '/hwclock/,$d' \
232 < ${rootfs_path}/etc/init.d/halt \
233 > ${rootfs_path}/etc/init.d/lxc-halt
234
235 echo '$command -f' >> ${rootfs_path}/etc/init.d/lxc-halt
236 chmod 755 ${rootfs_path}/etc/init.d/lxc-halt
237
238 # Link them into the rc directories...
239 (
240 cd ${rootfs_path}/etc/rc.d/rc0.d
241 ln -s ../init.d/lxc-halt S00lxc-halt
242 cd ${rootfs_path}/etc/rc.d/rc6.d
243 ln -s ../init.d/lxc-halt S00lxc-reboot
244 )
245 fi
246
247 # configure the network using the dhcp
248 cat <<EOF > ${rootfs_path}/etc/sysconfig/network-scripts/ifcfg-eth0
249 DEVICE=eth0
250 BOOTPROTO=dhcp
251 ONBOOT=yes
252 HOSTNAME=${UTSNAME}
253 NM_CONTROLLED=no
254 TYPE=Ethernet
255 MTU=${MTU}
256 DHCP_HOSTNAME=\`hostname\`
257 EOF
258
259 # set the hostname
260 cat <<EOF > ${rootfs_path}/etc/sysconfig/network
261 NETWORKING=yes
262 HOSTNAME=${UTSNAME}
263 EOF
264
265 # set minimal hosts
266 cat <<EOF > $rootfs_path/etc/hosts
267 127.0.0.1 localhost $name
268 EOF
269
270 # set minimal fstab
271 cat <<EOF > $rootfs_path/etc/fstab
272 /dev/root / rootfs defaults 0 0
273 EOF
274
275 # create lxc compatibility init script
276 if [ "$release" = "6" ]; then
277 cat <<EOF > $rootfs_path/etc/init/lxc-sysinit.conf
278 start on startup
279 env container
280
281 pre-start script
282 if [ "x\$container" != "xlxc" -a "x\$container" != "xlibvirt" ]; then
283 stop;
284 fi
285
286 rm -f /var/lock/subsys/*
287 rm -f /var/run/*.pid
288 [ -e /etc/mtab ] || ln -s /proc/mounts /etc/mtab
289 mkdir -p /dev/shm
290 mount -t tmpfs -o nosuid,nodev tmpfs /dev/shm
291
292 initctl start tty TTY=console
293 telinit 3
294 exit 0
295 end script
296 EOF
297 elif [ "$release" = "5" ]; then
298 cat <<EOF > $rootfs_path/etc/rc.d/lxc.sysinit
299 #! /bin/bash
300 rm -f /etc/mtab /var/run/*.{pid,lock} /var/lock/subsys/*
301 rm -rf {/,/var}/tmp/*
302 echo "/dev/root / rootfs defaults 0 0" > /etc/mtab
303 exit 0
304 EOF
305 chmod 755 $rootfs_path/etc/rc.d/lxc.sysinit
306 sed -i 's|si::sysinit:/etc/rc.d/rc.sysinit|si::bootwait:/etc/rc.d/lxc.sysinit|' $rootfs_path/etc/inittab
307 # prevent mingetty from calling vhangup(2) since it fails with userns.
308 # Same issue as oracle template: prevent mingetty from calling vhangup(2)
309 # commit 2e83f7201c5d402478b9849f0a85c62d5b9f1589.
310 sed -i 's|^1:|co:2345:respawn:/sbin/mingetty --nohangup console\n1:|' $rootfs_path/etc/inittab
311 sed -i 's|^\([56]:\)|#\1|' $rootfs_path/etc/inittab
312 fi
313
314 dev_path="${rootfs_path}/dev"
315 rm -rf $dev_path
316 mkdir -p $dev_path
317 mknod -m 666 ${dev_path}/null c 1 3
318 mknod -m 666 ${dev_path}/zero c 1 5
319 mknod -m 666 ${dev_path}/random c 1 8
320 mknod -m 666 ${dev_path}/urandom c 1 9
321 mkdir -m 755 ${dev_path}/pts
322 mkdir -m 1777 ${dev_path}/shm
323 mknod -m 666 ${dev_path}/tty c 5 0
324 mknod -m 666 ${dev_path}/tty0 c 4 0
325 mknod -m 666 ${dev_path}/tty1 c 4 1
326 mknod -m 666 ${dev_path}/tty2 c 4 2
327 mknod -m 666 ${dev_path}/tty3 c 4 3
328 mknod -m 666 ${dev_path}/tty4 c 4 4
329 mknod -m 600 ${dev_path}/console c 5 1
330 mknod -m 666 ${dev_path}/full c 1 7
331 mknod -m 600 ${dev_path}/initctl p
332 mknod -m 666 ${dev_path}/ptmx c 5 2
333
334 # setup console and tty[1-4] for login. note that /dev/console and
335 # /dev/tty[1-4] will be symlinks to the ptys /dev/lxc/console and
336 # /dev/lxc/tty[1-4] so that package updates can overwrite the symlinks.
337 # lxc will maintain these links and bind mount ptys over /dev/lxc/*
338 # since lxc.devttydir is specified in the config.
339
340 # allow root login on console, tty[1-4], and pts/0 for libvirt
341 echo "# LXC (Linux Containers)" >>${rootfs_path}/etc/securetty
342 echo "lxc/console" >>${rootfs_path}/etc/securetty
343 echo "lxc/tty1" >>${rootfs_path}/etc/securetty
344 echo "lxc/tty2" >>${rootfs_path}/etc/securetty
345 echo "lxc/tty3" >>${rootfs_path}/etc/securetty
346 echo "lxc/tty4" >>${rootfs_path}/etc/securetty
347 echo "# For libvirt/Virtual Machine Monitor" >>${rootfs_path}/etc/securetty
348 echo "pts/0" >>${rootfs_path}/etc/securetty
349
350 # prevent mingetty from calling vhangup(2) since it fails with userns.
351 # Same issue as oracle template: prevent mingetty from calling vhangup(2)
352 # commit 2e83f7201c5d402478b9849f0a85c62d5b9f1589.
353 sed -i 's|mingetty|mingetty --nohangup|' $rootfs_path/etc/init/tty.conf
354
355 if [ ${root_display_password} = "yes" ]
356 then
357 echo "Setting root password to '$root_password'"
358 fi
359 if [ ${root_store_password} = "yes" ]
360 then
361 touch ${config_path}/tmp_root_pass
362 chmod 600 ${config_path}/tmp_root_pass
363 echo ${root_password} > ${config_path}/tmp_root_pass
364 echo "Storing root password in '${config_path}/tmp_root_pass'"
365 fi
366
367 echo "root:$root_password" | chroot $rootfs_path chpasswd
368
369 if [ ${root_expire_password} = "yes" ]
370 then
371 # Also set this password as expired to force the user to change it!
372 chroot $rootfs_path passwd -e root
373 fi
374
375 # This will need to be enhanced for CentOS 7 when systemd
376 # comes into play... /\/\|=mhw=|\/\/
377
378 return 0
379 }
380
381 configure_centos_init()
382 {
383 sed -i 's|.sbin.start_udev||' ${rootfs_path}/etc/rc.sysinit
384 sed -i 's|.sbin.start_udev||' ${rootfs_path}/etc/rc.d/rc.sysinit
385 if [ "$release" = "6" ]; then
386 chroot ${rootfs_path} chkconfig udev-post off
387 fi
388 chroot ${rootfs_path} chkconfig network on
389
390 if [ -d ${rootfs_path}/etc/init ]
391 then
392 # This is to make upstart honor SIGPWR
393 cat <<EOF >${rootfs_path}/etc/init/power-status-changed.conf
394 # power-status-changed - shutdown on SIGPWR
395 #
396 start on power-status-changed
397
398 exec /sbin/shutdown -h now "SIGPWR received"
399 EOF
400 fi
401 }
402
403 download_centos()
404 {
405
406 # check the mini centos was not already downloaded
407 INSTALL_ROOT=$cache/partial
408 mkdir -p $INSTALL_ROOT
409 if [ $? -ne 0 ]; then
410 echo "Failed to create '$INSTALL_ROOT' directory"
411 return 1
412 fi
413
414 # download a mini centos into a cache
415 echo "Downloading centos minimal ..."
416 YUM0="yum --installroot $INSTALL_ROOT -y --nogpgcheck"
417
418 if yum -h | grep -q 'releasever=RELEASEVER'; then
419 YUM="$YUM0 --releasever=$release"
420 else
421 YUM="$YUM0"
422 fi
423 PKG_LIST="yum initscripts passwd rsyslog vim-minimal openssh-server openssh-clients dhclient chkconfig rootfiles policycoreutils"
424
425 # use temporary repository definition
426 REPO_FILE=$INSTALL_ROOT/etc/yum.repos.d/lxc-centos-temp.repo
427 mkdir -p $(dirname $REPO_FILE)
428 if [ -n "$repo" ]; then
429 cat <<EOF > $REPO_FILE
430 [base]
431 name=local repository
432 baseurl="$repo"
433 EOF
434 else
435 cat <<EOF > $REPO_FILE
436 [base]
437 name=CentOS-$release - Base
438 mirrorlist=http://mirrorlist.centos.org/?release=$release&arch=$basearch&repo=os
439
440 [updates]
441 name=CentOS-$release - Updates
442 mirrorlist=http://mirrorlist.centos.org/?release=$release&arch=$basearch&repo=updates
443 EOF
444 fi
445
446 # create minimal device nodes, needed for "yum install" and "yum update" process
447 mkdir -p $INSTALL_ROOT/dev
448 force_mknod 666 $INSTALL_ROOT/dev/null c 1 3
449 force_mknod 666 $INSTALL_ROOT/dev/urandom c 1 9
450
451 $YUM install $PKG_LIST
452
453 if [ $? -ne 0 ]; then
454 echo "Failed to download the rootfs, aborting."
455 return 1
456 fi
457
458 # use same nameservers as hosts, needed for "yum update later"
459 cp /etc/resolv.conf $INSTALL_ROOT/etc/
460
461 # check whether rpmdb is under $HOME
462 if [ ! -e $INSTALL_ROOT/var/lib/rpm/Packages -a -e $INSTALL_ROOT/$HOME/.rpmdb/Packages ]; then
463 echo "Fixing rpmdb location ..."
464 mv $INSTALL_ROOT/$HOME/.rpmdb/[A-Z]* $INSTALL_ROOT/var/lib/rpm/
465 rm -rf $INSTALL_ROOT/$HOME/.rpmdb
466 chroot $INSTALL_ROOT rpm --rebuilddb 2>/dev/null
467 fi
468
469 # check whether rpmdb version is correct
470 chroot $INSTALL_ROOT rpm --quiet -q yum 2>/dev/null
471 ret=$?
472
473 # if "rpm -q" doesn't work due to rpmdb version difference,
474 # then we need to redo the process using the newly-installed yum
475 if [ $ret -gt 0 ]; then
476 echo "Reinstalling packages ..."
477 mv $REPO_FILE $REPO_FILE.tmp
478 mkdir $INSTALL_ROOT/etc/yum.repos.disabled
479 mv $INSTALL_ROOT/etc/yum.repos.d/*.repo $INSTALL_ROOT/etc/yum.repos.disabled/
480 mv $REPO_FILE.tmp $REPO_FILE
481 mkdir -p $INSTALL_ROOT/$INSTALL_ROOT/etc
482 cp /etc/resolv.conf $INSTALL_ROOT/$INSTALL_ROOT/etc/
483 mkdir -p $INSTALL_ROOT/$INSTALL_ROOT/dev
484 mknod -m 666 $INSTALL_ROOT/$INSTALL_ROOT/dev/null c 1 3
485 mknod -m 666 $INSTALL_ROOT/$INSTALL_ROOT/dev/urandom c 1 9
486 mkdir -p $INSTALL_ROOT/$INSTALL_ROOT/var/cache/yum
487 cp -al $INSTALL_ROOT/var/cache/yum/* $INSTALL_ROOT/$INSTALL_ROOT/var/cache/yum/
488 chroot $INSTALL_ROOT $YUM0 install $PKG_LIST
489 if [ $? -ne 0 ]; then
490 echo "Failed to download the rootfs, aborting."
491 return 1
492 fi
493 mv $INSTALL_ROOT/$INSTALL_ROOT $INSTALL_ROOT.tmp
494 rm -rf $INSTALL_ROOT
495 mv $INSTALL_ROOT.tmp $INSTALL_ROOT
496 fi
497
498 rm -f $REPO_FILE
499 rm -rf $INSTALL_ROOT/var/cache/yum/*
500
501 mv "$INSTALL_ROOT" "$cache/rootfs"
502 echo "Download complete."
503
504 return 0
505 }
506
507 copy_centos()
508 {
509
510 # make a local copy of the mini centos
511 echo -n "Copying rootfs to $rootfs_path ..."
512 #cp -a $cache/rootfs-$arch $rootfs_path || return 1
513 # i prefer rsync (no reason really)
514 mkdir -p $rootfs_path
515 rsync -a $cache/rootfs/ $rootfs_path/
516 echo
517 return 0
518 }
519
520 update_centos()
521 {
522 YUM="chroot $cache/rootfs yum -y --nogpgcheck"
523 $YUM update
524 if [ $? -ne 0 ]; then
525 return 1
526 fi
527 $YUM clean packages
528 }
529
530 install_centos()
531 {
532 mkdir -p /var/lock/subsys/
533 (
534 flock -x 9
535 if [ $? -ne 0 ]; then
536 echo "Cache repository is busy."
537 return 1
538 fi
539
540 echo "Checking cache download in $cache/rootfs ... "
541 if [ ! -e "$cache/rootfs" ]; then
542 download_centos
543 if [ $? -ne 0 ]; then
544 echo "Failed to download 'centos base'"
545 return 1
546 fi
547 else
548 echo "Cache found. Updating..."
549 update_centos
550 if [ $? -ne 0 ]; then
551 echo "Failed to update 'centos base', continuing with last known good cache"
552 else
553 echo "Update finished"
554 fi
555 fi
556
557 echo "Copy $cache/rootfs to $rootfs_path ... "
558 copy_centos
559 if [ $? -ne 0 ]; then
560 echo "Failed to copy rootfs"
561 return 1
562 fi
563
564 return 0
565
566 ) 9>/var/lock/subsys/lxc-centos
567
568 return $?
569 }
570
571 create_hwaddr()
572 {
573 openssl rand -hex 5 | sed -e 's/\(..\)/:\1/g; s/^/fe/'
574 }
575
576 copy_configuration()
577 {
578 mkdir -p $config_path
579
580 grep -q "^lxc.rootfs" $config_path/config 2>/dev/null || echo "
581 lxc.rootfs = $rootfs_path
582 " >> $config_path/config
583
584 # The following code is to create static MAC addresses for each
585 # interface in the container. This code will work for multiple
586 # interfaces in the default config.
587 mv $config_path/config $config_path/config.def
588 while read LINE
589 do
590 # This should catch variable expansions from the default config...
591 if expr "${LINE}" : '.*\$' > /dev/null 2>&1
592 then
593 LINE=$(eval "echo \"${LINE}\"")
594 fi
595
596 # There is a tab and a space in the regex bracket below!
597 # Seems that \s doesn't work in brackets.
598 KEY=$(expr "${LINE}" : '\s*\([^ ]*\)\s*=')
599
600 if [[ "${KEY}" != "lxc.network.hwaddr" ]]
601 then
602 echo ${LINE} >> $config_path/config
603
604 if [[ "${KEY}" == "lxc.network.link" ]]
605 then
606 echo "lxc.network.hwaddr = $(create_hwaddr)" >> $config_path/config
607 fi
608 fi
609 done < $config_path/config.def
610
611 rm -f $config_path/config.def
612
613 if [ -e "@LXCTEMPLATECONFIG@/centos.common.conf" ]; then
614 echo "
615 # Include common configuration
616 lxc.include = @LXCTEMPLATECONFIG@/centos.common.conf
617 " >> $config_path/config
618 fi
619
620 # Append things which require expansion here...
621 cat <<EOF >> $config_path/config
622 lxc.arch = $arch
623 lxc.utsname = $utsname
624
625 # When using LXC with apparmor, uncomment the next line to run unconfined:
626 #lxc.aa_profile = unconfined
627
628 # example simple networking setup, uncomment to enable
629 #lxc.network.type = $lxc_network_type
630 #lxc.network.flags = up
631 #lxc.network.link = $lxc_network_link
632 #lxc.network.name = eth0
633 # Additional example for veth network type
634 # static MAC address,
635 #lxc.network.hwaddr = 00:16:3e:77:52:20
636 # persistent veth device name on host side
637 # Note: This may potentially collide with other containers of same name!
638 #lxc.network.veth.pair = v-$name-e0
639
640 EOF
641
642 if [ $? -ne 0 ]; then
643 echo "Failed to add configuration"
644 return 1
645 fi
646
647 return 0
648 }
649
650 clean()
651 {
652
653 if [ ! -e $cache ]; then
654 exit 0
655 fi
656
657 # lock, so we won't purge while someone is creating a repository
658 (
659 flock -x 9
660 if [ $? != 0 ]; then
661 echo "Cache repository is busy."
662 exit 1
663 fi
664
665 echo -n "Purging the download cache for centos-$release..."
666 rm --preserve-root --one-file-system -rf $cache && echo "Done." || exit 1
667 exit 0
668
669 ) 9>@LOCALSTATEDIR@/lock/subsys/lxc-centos
670 }
671
672 usage()
673 {
674 cat <<EOF
675 usage:
676 $1 -n|--name=<container_name>
677 [-p|--path=<path>] [-c|--clean] [-R|--release=<CentOS_release>] [-a|--arch=<arch of the container>]
678 [-h|--help]
679 Mandatory args:
680 -n,--name container name, used to as an identifier for that container from now on
681 Optional args:
682 -p,--path path to where the container rootfs will be created, defaults to /var/lib/lxc/name.
683 -c,--clean clean the cache
684 -R,--release Centos release for the new container. if the host is Centos, then it will defaultto the host's release.
685 --fqdn fully qualified domain name (FQDN) for DNS and system naming
686 --repo repository to use (url)
687 -a,--arch Define what arch the container will be [i686,x86_64]
688 -h,--help print this help
689 EOF
690 return 0
691 }
692
693 options=$(getopt -o a:hp:n:cR: -l help,path:,rootfs:,name:,clean,release:,repo:,arch:,fqdn: -- "$@")
694 if [ $? -ne 0 ]; then
695 usage $(basename $0)
696 exit 1
697 fi
698
699 arch=$(uname -m)
700 eval set -- "$options"
701 while true
702 do
703 case "$1" in
704 -h|--help) usage $0 && exit 0;;
705 -p|--path) path=$2; shift 2;;
706 --rootfs) rootfs_path=$2; shift 2;;
707 -n|--name) name=$2; shift 2;;
708 -c|--clean) clean=1; shift 1;;
709 -R|--release) release=$2; shift 2;;
710 --repo) repo="$2"; shift 2;;
711 -a|--arch) newarch=$2; shift 2;;
712 --fqdn) utsname=$2; shift 2;;
713 --) shift 1; break ;;
714 *) break ;;
715 esac
716 done
717
718 if [ ! -z "$clean" -a -z "$path" ]; then
719 clean || exit 1
720 exit 0
721 fi
722
723 basearch=${arch}
724 # Map a few architectures to their generic CentOS repository archs.
725 # The two ARM archs are a bit of a guesstimate for the v5 and v6
726 # archs. V6 should have hardware floating point (Rasberry Pi).
727 # The "arm" arch is safer (no hardware floating point). So
728 # there may be cases where we "get it wrong" for some v6 other
729 # than RPi.
730 case "$arch" in
731 i686) basearch=i386 ;;
732 armv3l|armv4l|armv5l) basearch=arm ;;
733 armv6l|armv7l|armv8l) basearch=armhfp ;;
734 *) ;;
735 esac
736
737 # Somebody wants to specify an arch. This is very limited case.
738 # i386/i586/i686 on i386/x86_64
739 # - or -
740 # x86_64 on x86_64
741 if [ "${newarch}" != "" -a "${newarch}" != "${arch}" ]
742 then
743 case "${newarch}" in
744 i386|i586|i686)
745 if [ "${basearch}" = "i386" -o "${basearch}" = "x86_64" ]
746 then
747 # Make the arch a generic x86 32 bit...
748 arch=${newarch}
749 basearch=i386
750 else
751 basearch=bad
752 fi
753 ;;
754 *)
755 basearch=bad
756 ;;
757 esac
758
759 if [ "${basearch}" = "bad" ]
760 then
761 echo "You cannot build a ${newarch} CentOS container on a ${arch} host. Sorry!"
762 exit 1
763 fi
764 fi
765
766 # Allow the cache base to be set by environment variable
767 cache_base=${LXC_CACHE_PATH:-"@LOCALSTATEDIR@/cache/lxc"}/centos/$basearch
768
769 # Let's do something better for the initial root password.
770 # It's not perfect but it will defeat common scanning brute force
771 # attacks in the case where ssh is exposed. It will also be set to
772 # expired, forcing the user to change it at first login.
773 if [ "${root_password}" = "" ]
774 then
775 root_password=Root-${name}-${RANDOM}
776 else
777 # If it's got a ding in it, try and expand it!
778 if [ $(expr "${root_password}" : '.*$.') != 0 ]
779 then
780 root_password=$(eval echo "${root_password}")
781 fi
782
783 # If it has more than 3 consecutive X's in it, feed it
784 # through mktemp as a template.
785 if [ $(expr "${root_password}" : '.*XXXX') != 0 ]
786 then
787 root_password=$(mktemp -u ${root_password})
788 fi
789 fi
790
791 if [ -z "${utsname}" ]; then
792 utsname=${name}
793 fi
794
795 # This follows a standard "resolver" convention that an FQDN must have
796 # at least two dots or it is considered a local relative host name.
797 # If it doesn't, append the dns domain name of the host system.
798 #
799 # This changes one significant behavior when running
800 # "lxc_create -n Container_Name" without using the
801 # --fqdn option.
802 #
803 # Old behavior:
804 # utsname and hostname = Container_Name
805 # New behavior:
806 # utsname and hostname = Container_Name.Domain_Name
807
808 if [ $(expr "$utsname" : '.*\..*\.') = 0 ]; then
809 if [[ "$(dnsdomainname)" != "" && "$(dnsdomainname)" != "localdomain" ]]; then
810 utsname=${utsname}.$(dnsdomainname)
811 fi
812 fi
813
814 type yum >/dev/null 2>&1
815 if [ $? -ne 0 ]; then
816 echo "'yum' command is missing"
817 exit 1
818 fi
819
820 if [ -z "$path" ]; then
821 path=$default_path/$name
822 fi
823
824 if [ -z "$release" ]; then
825 if [ "$is_centos" -a "$centos_host_ver" ]; then
826 release=$centos_host_ver
827 elif [ "$is_redhat" -a "$redhat_host_ver" ]; then
828 # This is needed to clean out bullshit like 6workstation and 6server.
829 release=$(expr $redhat_host_ver : '\([0-9.]*\)')
830 else
831 echo "This is not a CentOS or Redhat host and release is missing, defaulting to 6 use -R|--release to specify release"
832 release=6
833 fi
834 fi
835
836 if [ "$(id -u)" != "0" ]; then
837 echo "This script should be run as 'root'"
838 exit 1
839 fi
840
841 if [ -z "$rootfs_path" ]; then
842 rootfs_path=$path/rootfs
843 # check for 'lxc.rootfs' passed in through default config by lxc-create
844 if grep -q '^lxc.rootfs' $path/config 2>/dev/null ; then
845 rootfs_path=$(sed -e '/^lxc.rootfs\s*=/!d' -e 's/\s*#.*//' \
846 -e 's/^lxc.rootfs\s*=\s*//' -e q $path/config)
847 fi
848 fi
849 config_path=$path
850 cache=$cache_base/$release
851
852 revert()
853 {
854 echo "Interrupted, so cleaning up"
855 lxc-destroy -n $name
856 # maybe was interrupted before copy config
857 rm -rf $path
858 echo "exiting..."
859 exit 1
860 }
861
862 trap revert SIGHUP SIGINT SIGTERM
863
864 copy_configuration
865 if [ $? -ne 0 ]; then
866 echo "failed write configuration file"
867 exit 1
868 fi
869
870 install_centos
871 if [ $? -ne 0 ]; then
872 echo "failed to install centos"
873 exit 1
874 fi
875
876 configure_centos
877 if [ $? -ne 0 ]; then
878 echo "failed to configure centos for a container"
879 exit 1
880 fi
881
882 configure_centos_init
883
884 if [ ! -z "$clean" ]; then
885 clean || exit 1
886 exit 0
887 fi
888 echo "
889 Container rootfs and config have been created.
890 Edit the config file to check/enable networking setup.
891 "
892
893 if [ ${root_display_password} = "yes" ]
894 then
895 echo "The temporary password for root is: '$root_password'
896
897 You may want to note that password down before starting the container.
898 "
899 fi
900
901 if [ ${root_store_password} = "yes" ]
902 then
903 echo "The temporary root password is stored in:
904
905 '${config_path}/tmp_root_pass'
906 "
907 fi
908
909 if [ ${root_prompt_password} = "yes" ]
910 then
911 echo "Invoking the passwd command in the container to set the root password.
912
913 chroot ${rootfs_path} passwd
914 "
915 chroot ${rootfs_path} passwd
916 else
917 if [ ${root_expire_password} = "yes" ]
918 then
919 echo "
920 The root password is set up as "expired" and will require it to be changed
921 at first login, which you should do as soon as possible. If you lose the
922 root password or wish to change it without starting the container, you
923 can change it from the host by running the following command (which will
924 also reset the expired flag):
925
926 chroot ${rootfs_path} passwd
927 "
928 fi
929 fi