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