]> git.proxmox.com Git - mirror_lxc.git/blame - templates/lxc-centos.in
Really fix Android...
[mirror_lxc.git] / templates / lxc-centos.in
CommitLineData
164105f6
MW
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
96283b54 22# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
164105f6
MW
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
164105f6 30default_path=@LXCPATH@
164105f6 31
826cde7c 32# Some combinations of the tuning knobs below do not exactly make sense.
b4f7af7a
MW
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}.
ec64264d 41# If the root password contains more than 3 consecutive X's, pass it as
b4f7af7a
MW
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.
826cde7c
MW
48# If root_expire_password = yes, you will be prompted to change the root
49# password at the first login.
b4f7af7a
MW
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
826cde7c
MW
66# Expire root password? Default to yes, but can be overridden from
67# the environment variable
68: ${root_expire_password='yes'}
69
b4f7af7a 70# These are only going into comments in the resulting config...
164105f6
MW
71lxc_network_type=veth
72lxc_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
8ec981fc 81# Detect use under userns (unsupported)
c63c04fc 82for arg in "$@"; do
96283b54
SG
83 [ "$arg" = "--" ] && break
84 if [ "$arg" = "--mapped-uid" -o "$arg" = "--mapped-gid" ]; then
8ec981fc
SG
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
89done
90
207bf0e4
SG
91# Make sure the usual locations are in PATH
92export PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin
93
164105f6
MW
94if [ -e /etc/os-release ]
95then
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}"
100fi
101
102if [ "${CPE_NAME}" = "" -a -e /etc/system-release-cpe ]
103then
104 CPE_NAME=$(head -n1 /etc/system-release-cpe)
c6df5ca4 105 CPE_URI=$(expr ${CPE_NAME} : '\([^:]*:[^:]*\)')
164105f6
MW
106 if [ "${CPE_URI}" != "cpe:/o" ]
107 then
108 CPE_NAME=
109 else
164105f6
MW
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.
c6df5ca4
MW
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 #
164105f6 120 ID=$(expr ${CPE_NAME} : '[^:]*:[^:]*:[^:]*:\([^:]*\)')
c6df5ca4
MW
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
164105f6 131 VERSION_ID=$(expr ${CPE_NAME} : '[^:]*:[^:]*:[^:]*:[^:]*:\([^:]*\)')
c6df5ca4 132 echo "Host CPE ID from /etc/system-release-cpe: ${CPE_NAME}"
164105f6
MW
133 fi
134fi
135
136if [ "${CPE_NAME}" != "" -a "${ID}" = "centos" -a "${VERSION_ID}" != "" ]
137then
138 centos_host_ver=${VERSION_ID}
139 is_centos=true
c6df5ca4
MW
140elif [ "${CPE_NAME}" != "" -a "${ID}" = "redhat" -a "${VERSION_ID}" != "" ]
141then
142 redhat_host_ver=${VERSION_ID}
143 is_redhat=true
144elif [ -e /etc/centos-release ]
164105f6
MW
145then
146 # Only if all other methods fail, try to parse the redhat-release file.
c6df5ca4 147 centos_host_ver=$( sed -e '/^CentOS /!d' -e 's/CentOS.*\srelease\s*\([0-9][0-9.]*\)\s.*/\1/' < /etc/centos-release )
164105f6
MW
148 if [ "$centos_host_ver" != "" ]
149 then
150 is_centos=true
151 fi
152fi
153
164105f6
MW
154force_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
160configure_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...
17abf278 168 if [ -f $rootfs_path/etc/selinux/config ]
164105f6
MW
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
c6df5ca4
MW
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
f5067ecb
MW
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
99c2fb07
MW
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
164105f6
MW
248 cat <<EOF > ${rootfs_path}/etc/sysconfig/network-scripts/ifcfg-eth0
249DEVICE=eth0
250BOOTPROTO=dhcp
251ONBOOT=yes
252HOSTNAME=${UTSNAME}
253NM_CONTROLLED=no
254TYPE=Ethernet
255MTU=${MTU}
91c5c53f 256DHCP_HOSTNAME=$name
164105f6
MW
257EOF
258
259 # set the hostname
260 cat <<EOF > ${rootfs_path}/etc/sysconfig/network
261NETWORKING=yes
262HOSTNAME=${UTSNAME}
263EOF
264
265 # set minimal hosts
266 cat <<EOF > $rootfs_path/etc/hosts
267127.0.0.1 localhost $name
268EOF
269
270 # set minimal fstab
271 cat <<EOF > $rootfs_path/etc/fstab
272/dev/root / rootfs defaults 0 0
164105f6
MW
273EOF
274
275 # create lxc compatibility init script
276 if [ "$release" = "6" ]; then
277 cat <<EOF > $rootfs_path/etc/init/lxc-sysinit.conf
278start on startup
279env container
280
281pre-start script
a79df227 282 if [ "x\$container" != "xlxc" -a "x\$container" != "xlibvirt" ]; then
164105f6
MW
283 stop;
284 fi
a79df227 285
164105f6
MW
286 rm -f /var/lock/subsys/*
287 rm -f /var/run/*.pid
a79df227
SG
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
164105f6 293 telinit 3
a79df227 294 exit 0
164105f6
MW
295end script
296EOF
297 elif [ "$release" = "5" ]; then
298 cat <<EOF > $rootfs_path/etc/rc.d/lxc.sysinit
299#! /bin/bash
300rm -f /etc/mtab /var/run/*.{pid,lock} /var/lock/subsys/*
301rm -rf {/,/var}/tmp/*
302echo "/dev/root / rootfs defaults 0 0" > /etc/mtab
303exit 0
304EOF
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
7edae51e
CAR
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
164105f6
MW
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
1ecee40b
MW
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
7edae51e
CAR
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|' $container_rootfs/etc/init/tty.conf
354
b4f7af7a
MW
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
164105f6 367 echo "root:$root_password" | chroot $rootfs_path chpasswd
826cde7c
MW
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
164105f6
MW
374
375 # This will need to be enhanced for CentOS 7 when systemd
376 # comes into play... /\/\|=mhw=|\/\/
377
378 return 0
379}
380
381configure_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
779b47fd
MW
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#
396start on power-status-changed
397
398exec /sbin/shutdown -h now "SIGPWR received"
399EOF
400 fi
164105f6
MW
401}
402
403download_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 ..."
85ccd3d5 416 if yum -h | grep -q 'releasever=RELEASEVER'; then
6d41f7df 417 YUM="yum --installroot $INSTALL_ROOT -y --nogpgcheck --releasever=$release"
87a92d42
AL
418 else
419 YUM="yum --installroot $INSTALL_ROOT -y --nogpgcheck"
6d41f7df 420 fi
164105f6
MW
421 PKG_LIST="yum initscripts passwd rsyslog vim-minimal openssh-server openssh-clients dhclient chkconfig rootfiles policycoreutils"
422
423 # use temporary repository definition
424 REPO_FILE=$INSTALL_ROOT/etc/yum.repos.d/lxc-centos-temp.repo
425 mkdir -p $(dirname $REPO_FILE)
3a6ef65a
HD
426 if [ -n "$repo" ]; then
427 cat <<EOF > $REPO_FILE
428[base]
429name=local repository
430baseurl="$repo"
431EOF
432else
433 cat <<EOF > $REPO_FILE
164105f6
MW
434[base]
435name=CentOS-$release - Base
08754f30 436mirrorlist=http://mirrorlist.centos.org/?release=$release&arch=$basearch&repo=os
164105f6
MW
437
438[updates]
439name=CentOS-$release - Updates
08754f30 440mirrorlist=http://mirrorlist.centos.org/?release=$release&arch=$basearch&repo=updates
164105f6 441EOF
3a6ef65a 442 fi
164105f6
MW
443
444 # create minimal device nodes, needed for "yum install" and "yum update" process
445 mkdir -p $INSTALL_ROOT/dev
446 force_mknod 666 $INSTALL_ROOT/dev/null c 1 3
447 force_mknod 666 $INSTALL_ROOT/dev/urandom c 1 9
448
449 $YUM install $PKG_LIST
450
451 if [ $? -ne 0 ]; then
452 echo "Failed to download the rootfs, aborting."
453 return 1
454 fi
455
456 # use same nameservers as hosts, needed for "yum update later"
457 cp /etc/resolv.conf $INSTALL_ROOT/etc/
458
459 # check whether rpmdb is under $HOME
460 if [ ! -e $INSTALL_ROOT/var/lib/rpm/Packages -a -e $INSTALL_ROOT/$HOME/.rpmdb/Packages ]; then
461 echo "Fixing rpmdb location ..."
462 mv $INSTALL_ROOT/$HOME/.rpmdb/[A-Z]* $INSTALL_ROOT/var/lib/rpm/
463 rm -rf $INSTALL_ROOT/$HOME/.rpmdb
464 chroot $INSTALL_ROOT rpm --rebuilddb 2>/dev/null
465 fi
466
467 # check whether rpmdb version is correct
468 chroot $INSTALL_ROOT rpm --quiet -q yum 2>/dev/null
469 ret=$?
470
471 # if "rpm -q" doesn't work due to rpmdb version difference,
472 # then we need to redo the process using the newly-installed yum
473 if [ $ret -gt 0 ]; then
474 echo "Reinstalling packages ..."
475 mv $REPO_FILE $REPO_FILE.tmp
476 mkdir $INSTALL_ROOT/etc/yum.repos.disabled
477 mv $INSTALL_ROOT/etc/yum.repos.d/*.repo $INSTALL_ROOT/etc/yum.repos.disabled/
478 mv $REPO_FILE.tmp $REPO_FILE
479 mkdir -p $INSTALL_ROOT/$INSTALL_ROOT/etc
480 cp /etc/resolv.conf $INSTALL_ROOT/$INSTALL_ROOT/etc/
481 mkdir -p $INSTALL_ROOT/$INSTALL_ROOT/dev
482 mknod -m 666 $INSTALL_ROOT/$INSTALL_ROOT/dev/null c 1 3
483 mknod -m 666 $INSTALL_ROOT/$INSTALL_ROOT/dev/urandom c 1 9
484 mkdir -p $INSTALL_ROOT/$INSTALL_ROOT/var/cache/yum
485 cp -al $INSTALL_ROOT/var/cache/yum/* $INSTALL_ROOT/$INSTALL_ROOT/var/cache/yum/
486 chroot $INSTALL_ROOT $YUM install $PKG_LIST
487 if [ $? -ne 0 ]; then
488 echo "Failed to download the rootfs, aborting."
489 return 1
490 fi
491 mv $INSTALL_ROOT/$INSTALL_ROOT $INSTALL_ROOT.tmp
492 rm -rf $INSTALL_ROOT
493 mv $INSTALL_ROOT.tmp $INSTALL_ROOT
494 fi
495
496 rm -f $REPO_FILE
497 rm -rf $INSTALL_ROOT/var/cache/yum/*
498
499 mv "$INSTALL_ROOT" "$cache/rootfs"
500 echo "Download complete."
501
502 return 0
503}
504
505copy_centos()
506{
507
508 # make a local copy of the mini centos
509 echo -n "Copying rootfs to $rootfs_path ..."
510 #cp -a $cache/rootfs-$arch $rootfs_path || return 1
511 # i prefer rsync (no reason really)
512 mkdir -p $rootfs_path
513 rsync -a $cache/rootfs/ $rootfs_path/
b4f7af7a 514 echo
164105f6
MW
515 return 0
516}
517
518update_centos()
519{
520 YUM="chroot $cache/rootfs yum -y --nogpgcheck"
521 $YUM update
522 if [ $? -ne 0 ]; then
523 return 1
524 fi
525 $YUM clean packages
526}
527
528install_centos()
529{
530 mkdir -p /var/lock/subsys/
531 (
17abf278 532 flock -x 9
164105f6
MW
533 if [ $? -ne 0 ]; then
534 echo "Cache repository is busy."
535 return 1
536 fi
537
538 echo "Checking cache download in $cache/rootfs ... "
539 if [ ! -e "$cache/rootfs" ]; then
540 download_centos
541 if [ $? -ne 0 ]; then
542 echo "Failed to download 'centos base'"
543 return 1
544 fi
545 else
546 echo "Cache found. Updating..."
547 update_centos
548 if [ $? -ne 0 ]; then
549 echo "Failed to update 'centos base', continuing with last known good cache"
550 else
551 echo "Update finished"
552 fi
553 fi
554
555 echo "Copy $cache/rootfs to $rootfs_path ... "
556 copy_centos
557 if [ $? -ne 0 ]; then
558 echo "Failed to copy rootfs"
559 return 1
560 fi
561
562 return 0
563
17abf278 564 ) 9>/var/lock/subsys/lxc-centos
164105f6
MW
565
566 return $?
567}
568
b4f7af7a 569create_hwaddr()
164105f6 570{
08754f30 571 openssl rand -hex 5 | sed -e 's/\(..\)/:\1/g; s/^/fe/'
b4f7af7a 572}
164105f6 573
b4f7af7a
MW
574copy_configuration()
575{
164105f6 576 mkdir -p $config_path
b4f7af7a
MW
577
578 grep -q "^lxc.rootfs" $config_path/config 2>/dev/null || echo "
579lxc.rootfs = $rootfs_path
580" >> $config_path/config
581
582 # The following code is to create static MAC addresses for each
583 # interface in the container. This code will work for multiple
584 # interfaces in the default config.
585 mv $config_path/config $config_path/config.def
586 while read LINE
587 do
588 # This should catch variable expansions from the default config...
589 if expr "${LINE}" : '.*\$' > /dev/null 2>&1
590 then
591 LINE=$(eval "echo \"${LINE}\"")
592 fi
593
594 # There is a tab and a space in the regex bracket below!
595 # Seems that \s doesn't work in brackets.
596 KEY=$(expr "${LINE}" : '\s*\([^ ]*\)\s*=')
597
598 if [[ "${KEY}" != "lxc.network.hwaddr" ]]
599 then
600 echo ${LINE} >> $config_path/config
601
602 if [[ "${KEY}" == "lxc.network.link" ]]
603 then
604 echo "lxc.network.hwaddr = $(create_hwaddr)" >> $config_path/config
605 fi
606 fi
607 done < $config_path/config.def
608
609 rm -f $config_path/config.def
610
1ecee40b
MW
611 if [ -e "@LXCTEMPLATECONFIG@/centos.common.conf" ]; then
612 echo "
613# Include common configuration
614lxc.include = @LXCTEMPLATECONFIG@/centos.common.conf
615" >> $config_path/config
616 fi
617
618 # Append things which require expansion here...
164105f6 619 cat <<EOF >> $config_path/config
e13923c7 620lxc.arch = $arch
164105f6 621lxc.utsname = $utsname
164105f6 622
b4f7af7a
MW
623# When using LXC with apparmor, uncomment the next line to run unconfined:
624#lxc.aa_profile = unconfined
625
164105f6
MW
626# example simple networking setup, uncomment to enable
627#lxc.network.type = $lxc_network_type
628#lxc.network.flags = up
629#lxc.network.link = $lxc_network_link
630#lxc.network.name = eth0
b4f7af7a
MW
631# Additional example for veth network type
632# static MAC address,
164105f6 633#lxc.network.hwaddr = 00:16:3e:77:52:20
b4f7af7a
MW
634# persistent veth device name on host side
635# Note: This may potentially collide with other containers of same name!
164105f6
MW
636#lxc.network.veth.pair = v-$name-e0
637
164105f6
MW
638EOF
639
640 if [ $? -ne 0 ]; then
b4f7af7a
MW
641 echo "Failed to add configuration"
642 return 1
164105f6
MW
643 fi
644
645 return 0
646}
647
648clean()
649{
650
651 if [ ! -e $cache ]; then
b4f7af7a 652 exit 0
164105f6
MW
653 fi
654
655 # lock, so we won't purge while someone is creating a repository
656 (
b4f7af7a
MW
657 flock -x 9
658 if [ $? != 0 ]; then
659 echo "Cache repository is busy."
660 exit 1
661 fi
164105f6 662
b4f7af7a
MW
663 echo -n "Purging the download cache for centos-$release..."
664 rm --preserve-root --one-file-system -rf $cache && echo "Done." || exit 1
665 exit 0
164105f6 666
b4f7af7a 667 ) 9>@LOCALSTATEDIR@/lock/subsys/lxc-centos
164105f6
MW
668}
669
670usage()
671{
672 cat <<EOF
673usage:
674 $1 -n|--name=<container_name>
6bfb727c 675 [-p|--path=<path>] [-c|--clean] [-R|--release=<CentOS_release>] [-a|--arch=<arch of the container>]
164105f6
MW
676 [-h|--help]
677Mandatory args:
678 -n,--name container name, used to as an identifier for that container from now on
679Optional args:
08754f30 680 -p,--path path to where the container rootfs will be created, defaults to /var/lib/lxc/name.
164105f6
MW
681 -c,--clean clean the cache
682 -R,--release Centos release for the new container. if the host is Centos, then it will defaultto the host's release.
683 --fqdn fully qualified domain name (FQDN) for DNS and system naming
3a6ef65a 684 --repo repository to use (url)
08754f30 685 -a,--arch Define what arch the container will be [i686,x86_64]
164105f6
MW
686 -h,--help print this help
687EOF
688 return 0
689}
690
3a6ef65a 691options=$(getopt -o a:hp:n:cR: -l help,path:,rootfs:,name:,clean,release:,repo:,arch:,fqdn: -- "$@")
164105f6
MW
692if [ $? -ne 0 ]; then
693 usage $(basename $0)
694 exit 1
695fi
164105f6 696
4849ab99 697arch=$(uname -m)
08754f30 698eval set -- "$options"
164105f6
MW
699while true
700do
701 case "$1" in
702 -h|--help) usage $0 && exit 0;;
703 -p|--path) path=$2; shift 2;;
9f177a00 704 --rootfs) rootfs_path=$2; shift 2;;
164105f6 705 -n|--name) name=$2; shift 2;;
6976826f 706 -c|--clean) clean=1; shift 1;;
164105f6 707 -R|--release) release=$2; shift 2;;
2ae8252a 708 --repo) repo="$2"; shift 2;;
08754f30 709 -a|--arch) newarch=$2; shift 2;;
164105f6
MW
710 --fqdn) utsname=$2; shift 2;;
711 --) shift 1; break ;;
712 *) break ;;
713 esac
714done
715
716if [ ! -z "$clean" -a -z "$path" ]; then
717 clean || exit 1
718 exit 0
719fi
720
08754f30
MW
721basearch=${arch}
722# Map a few architectures to their generic CentOS repository archs.
723# The two ARM archs are a bit of a guesstimate for the v5 and v6
724# archs. V6 should have hardware floating point (Rasberry Pi).
725# The "arm" arch is safer (no hardware floating point). So
726# there may be cases where we "get it wrong" for some v6 other
727# than RPi.
728case "$arch" in
729i686) basearch=i386 ;;
730armv3l|armv4l|armv5l) basearch=arm ;;
731armv6l|armv7l|armv8l) basearch=armhfp ;;
732*) ;;
733esac
734
735# Somebody wants to specify an arch. This is very limited case.
736# i386/i586/i686 on i386/x86_64
737# - or -
738# x86_64 on x86_64
739if [ "${newarch}" != "" -a "${newarch}" != "${arch}" ]
740then
741 case "${newarch}" in
742 i386|i586|i686)
743 if [ "${basearch}" = "i386" -o "${basearch}" = "x86_64" ]
744 then
745 # Make the arch a generic x86 32 bit...
746 arch=${newarch}
747 basearch=i386
748 else
749 basearch=bad
750 fi
751 ;;
752 *)
753 basearch=bad
754 ;;
755 esac
756
757 if [ "${basearch}" = "bad" ]
758 then
759 echo "You cannot build a ${newarch} CentOS container on a ${arch} host. Sorry!"
760 exit 1
761 fi
762fi
763
764cache_base=@LOCALSTATEDIR@/cache/lxc/centos/$basearch
765
b4f7af7a
MW
766# Let's do something better for the initial root password.
767# It's not perfect but it will defeat common scanning brute force
768# attacks in the case where ssh is exposed. It will also be set to
769# expired, forcing the user to change it at first login.
770if [ "${root_password}" = "" ]
771then
772 root_password=Root-${name}-${RANDOM}
773else
774 # If it's got a ding in it, try and expand it!
775 if [ $(expr "${root_password}" : '.*$.') != 0 ]
776 then
777 root_password=$(eval echo "${root_password}")
778 fi
779
ec64264d 780 # If it has more than 3 consecutive X's in it, feed it
b4f7af7a
MW
781 # through mktemp as a template.
782 if [ $(expr "${root_password}" : '.*XXXX') != 0 ]
783 then
784 root_password=$(mktemp -u ${root_password})
785 fi
786fi
787
164105f6
MW
788if [ -z "${utsname}" ]; then
789 utsname=${name}
790fi
791
792# This follows a standard "resolver" convention that an FQDN must have
793# at least two dots or it is considered a local relative host name.
794# If it doesn't, append the dns domain name of the host system.
795#
796# This changes one significant behavior when running
797# "lxc_create -n Container_Name" without using the
798# --fqdn option.
799#
800# Old behavior:
801# utsname and hostname = Container_Name
802# New behavior:
803# utsname and hostname = Container_Name.Domain_Name
804
805if [ $(expr "$utsname" : '.*\..*\.') = 0 ]; then
b4f7af7a 806 if [[ "$(dnsdomainname)" != "" && "$(dnsdomainname)" != "localdomain" ]]; then
164105f6
MW
807 utsname=${utsname}.$(dnsdomainname)
808 fi
809fi
810
811type yum >/dev/null 2>&1
812if [ $? -ne 0 ]; then
813 echo "'yum' command is missing"
814 exit 1
815fi
816
817if [ -z "$path" ]; then
818 path=$default_path/$name
819fi
820
821if [ -z "$release" ]; then
822 if [ "$is_centos" -a "$centos_host_ver" ]; then
823 release=$centos_host_ver
c6df5ca4
MW
824 elif [ "$is_redhat" -a "$redhat_host_ver" ]; then
825 # This is needed to clean out bullshit like 6workstation and 6server.
826 release=$(expr $redhat_host_ver : '\([0-9.]*\)')
164105f6 827 else
c6df5ca4 828 echo "This is not a CentOS or Redhat host and release is missing, defaulting to 6 use -R|--release to specify release"
164105f6
MW
829 release=6
830 fi
831fi
832
164105f6
MW
833if [ "$(id -u)" != "0" ]; then
834 echo "This script should be run as 'root'"
835 exit 1
836fi
837
164105f6
MW
838if [ -z "$rootfs_path" ]; then
839 rootfs_path=$path/rootfs
840 # check for 'lxc.rootfs' passed in through default config by lxc-create
841 if grep -q '^lxc.rootfs' $path/config 2>/dev/null ; then
08754f30
MW
842 rootfs_path=$(sed -e '/^lxc.rootfs\s*=/!d' -e 's/\s*#.*//' \
843 -e 's/^lxc.rootfs\s*=\s*//' -e q $path/config)
164105f6
MW
844 fi
845fi
08754f30 846config_path=$path
164105f6
MW
847cache=$cache_base/$release
848
849revert()
850{
851 echo "Interrupted, so cleaning up"
852 lxc-destroy -n $name
853 # maybe was interrupted before copy config
854 rm -rf $path
164105f6
MW
855 echo "exiting..."
856 exit 1
857}
858
859trap revert SIGHUP SIGINT SIGTERM
860
861copy_configuration
862if [ $? -ne 0 ]; then
863 echo "failed write configuration file"
864 exit 1
865fi
866
867install_centos
868if [ $? -ne 0 ]; then
869 echo "failed to install centos"
870 exit 1
871fi
872
873configure_centos
874if [ $? -ne 0 ]; then
875 echo "failed to configure centos for a container"
876 exit 1
877fi
878
879configure_centos_init
880
a2780518 881if [ ! -z "$clean" ]; then
164105f6
MW
882 clean || exit 1
883 exit 0
884fi
b4f7af7a
MW
885echo "
886Container rootfs and config have been created.
887Edit the config file to check/enable networking setup.
888"
889
890if [ ${root_display_password} = "yes" ]
891then
892 echo "The temporary password for root is: '$root_password'
893
894You may want to note that password down before starting the container.
895"
896fi
897
898if [ ${root_store_password} = "yes" ]
899then
900 echo "The temporary root password is stored in:
901
902 '${config_path}/tmp_root_pass'
903"
904fi
905
906if [ ${root_prompt_password} = "yes" ]
907then
908 echo "Invoking the passwd command in the container to set the root password.
909
910 chroot ${rootfs_path} passwd
911"
912 chroot ${rootfs_path} passwd
913else
826cde7c
MW
914 if [ ${root_expire_password} = "yes" ]
915 then
916 echo "
b4f7af7a
MW
917The root password is set up as "expired" and will require it to be changed
918at first login, which you should do as soon as possible. If you lose the
919root password or wish to change it without starting the container, you
920can change it from the host by running the following command (which will
921also reset the expired flag):
922
923 chroot ${rootfs_path} passwd
924"
826cde7c 925 fi
b4f7af7a 926fi