]> git.proxmox.com Git - mirror_lxc.git/blame - templates/lxc-centos.in
Fix lxc-create -h with absolute template path
[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
273none /dev/shm tmpfs nosuid,nodev 0 0
274EOF
275
276 # create lxc compatibility init script
277 if [ "$release" = "6" ]; then
278 cat <<EOF > $rootfs_path/etc/init/lxc-sysinit.conf
279start on startup
280env container
281
282pre-start script
283 if [ "x$container" != "xlxc" -a "x$container" != "xlibvirt" ]; then
284 stop;
285 fi
286 initctl start tty TTY=console
287 rm -f /var/lock/subsys/*
288 rm -f /var/run/*.pid
289 telinit 3
290 exit 0;
291end script
292EOF
293 elif [ "$release" = "5" ]; then
294 cat <<EOF > $rootfs_path/etc/rc.d/lxc.sysinit
295#! /bin/bash
296rm -f /etc/mtab /var/run/*.{pid,lock} /var/lock/subsys/*
297rm -rf {/,/var}/tmp/*
298echo "/dev/root / rootfs defaults 0 0" > /etc/mtab
299exit 0
300EOF
301 chmod 755 $rootfs_path/etc/rc.d/lxc.sysinit
302 sed -i 's|si::sysinit:/etc/rc.d/rc.sysinit|si::bootwait:/etc/rc.d/lxc.sysinit|' $rootfs_path/etc/inittab
7edae51e
CAR
303 # prevent mingetty from calling vhangup(2) since it fails with userns.
304 # Same issue as oracle template: prevent mingetty from calling vhangup(2)
305 # commit 2e83f7201c5d402478b9849f0a85c62d5b9f1589.
306 sed -i 's|^1:|co:2345:respawn:/sbin/mingetty --nohangup console\n1:|' $rootfs_path/etc/inittab
164105f6
MW
307 sed -i 's|^\([56]:\)|#\1|' $rootfs_path/etc/inittab
308 fi
309
310 dev_path="${rootfs_path}/dev"
311 rm -rf $dev_path
312 mkdir -p $dev_path
313 mknod -m 666 ${dev_path}/null c 1 3
314 mknod -m 666 ${dev_path}/zero c 1 5
315 mknod -m 666 ${dev_path}/random c 1 8
316 mknod -m 666 ${dev_path}/urandom c 1 9
317 mkdir -m 755 ${dev_path}/pts
318 mkdir -m 1777 ${dev_path}/shm
319 mknod -m 666 ${dev_path}/tty c 5 0
320 mknod -m 666 ${dev_path}/tty0 c 4 0
321 mknod -m 666 ${dev_path}/tty1 c 4 1
322 mknod -m 666 ${dev_path}/tty2 c 4 2
323 mknod -m 666 ${dev_path}/tty3 c 4 3
324 mknod -m 666 ${dev_path}/tty4 c 4 4
325 mknod -m 600 ${dev_path}/console c 5 1
326 mknod -m 666 ${dev_path}/full c 1 7
327 mknod -m 600 ${dev_path}/initctl p
328 mknod -m 666 ${dev_path}/ptmx c 5 2
329
1ecee40b
MW
330 # setup console and tty[1-4] for login. note that /dev/console and
331 # /dev/tty[1-4] will be symlinks to the ptys /dev/lxc/console and
332 # /dev/lxc/tty[1-4] so that package updates can overwrite the symlinks.
333 # lxc will maintain these links and bind mount ptys over /dev/lxc/*
334 # since lxc.devttydir is specified in the config.
335
336 # allow root login on console, tty[1-4], and pts/0 for libvirt
337 echo "# LXC (Linux Containers)" >>${rootfs_path}/etc/securetty
338 echo "lxc/console" >>${rootfs_path}/etc/securetty
339 echo "lxc/tty1" >>${rootfs_path}/etc/securetty
340 echo "lxc/tty2" >>${rootfs_path}/etc/securetty
341 echo "lxc/tty3" >>${rootfs_path}/etc/securetty
342 echo "lxc/tty4" >>${rootfs_path}/etc/securetty
343 echo "# For libvirt/Virtual Machine Monitor" >>${rootfs_path}/etc/securetty
344 echo "pts/0" >>${rootfs_path}/etc/securetty
345
7edae51e
CAR
346 # prevent mingetty from calling vhangup(2) since it fails with userns.
347 # Same issue as oracle template: prevent mingetty from calling vhangup(2)
348 # commit 2e83f7201c5d402478b9849f0a85c62d5b9f1589.
349 sed -i 's|mingetty|mingetty --nohangup|' $container_rootfs/etc/init/tty.conf
350
b4f7af7a
MW
351 if [ ${root_display_password} = "yes" ]
352 then
353 echo "Setting root password to '$root_password'"
354 fi
355 if [ ${root_store_password} = "yes" ]
356 then
357 touch ${config_path}/tmp_root_pass
358 chmod 600 ${config_path}/tmp_root_pass
359 echo ${root_password} > ${config_path}/tmp_root_pass
360 echo "Storing root password in '${config_path}/tmp_root_pass'"
361 fi
362
164105f6 363 echo "root:$root_password" | chroot $rootfs_path chpasswd
826cde7c
MW
364
365 if [ ${root_expire_password} = "yes" ]
366 then
367 # Also set this password as expired to force the user to change it!
368 chroot $rootfs_path passwd -e root
369 fi
164105f6
MW
370
371 # This will need to be enhanced for CentOS 7 when systemd
372 # comes into play... /\/\|=mhw=|\/\/
373
374 return 0
375}
376
377configure_centos_init()
378{
379 sed -i 's|.sbin.start_udev||' ${rootfs_path}/etc/rc.sysinit
380 sed -i 's|.sbin.start_udev||' ${rootfs_path}/etc/rc.d/rc.sysinit
381 if [ "$release" = "6" ]; then
382 chroot ${rootfs_path} chkconfig udev-post off
383 fi
384 chroot ${rootfs_path} chkconfig network on
779b47fd
MW
385
386 if [ -d ${rootfs_path}/etc/init ]
387 then
388 # This is to make upstart honor SIGPWR
389 cat <<EOF >${rootfs_path}/etc/init/power-status-changed.conf
390# power-status-changed - shutdown on SIGPWR
391#
392start on power-status-changed
393
394exec /sbin/shutdown -h now "SIGPWR received"
395EOF
396 fi
164105f6
MW
397}
398
399download_centos()
400{
401
402 # check the mini centos was not already downloaded
403 INSTALL_ROOT=$cache/partial
404 mkdir -p $INSTALL_ROOT
405 if [ $? -ne 0 ]; then
406 echo "Failed to create '$INSTALL_ROOT' directory"
407 return 1
408 fi
409
410 # download a mini centos into a cache
411 echo "Downloading centos minimal ..."
97e1e9bb 412 YUM="yum --installroot $INSTALL_ROOT -y --nogpgcheck --releasever=$release"
164105f6
MW
413 PKG_LIST="yum initscripts passwd rsyslog vim-minimal openssh-server openssh-clients dhclient chkconfig rootfiles policycoreutils"
414
415 # use temporary repository definition
416 REPO_FILE=$INSTALL_ROOT/etc/yum.repos.d/lxc-centos-temp.repo
417 mkdir -p $(dirname $REPO_FILE)
3a6ef65a
HD
418 if [ -n "$repo" ]; then
419 cat <<EOF > $REPO_FILE
420[base]
421name=local repository
422baseurl="$repo"
423EOF
424else
425 cat <<EOF > $REPO_FILE
164105f6
MW
426[base]
427name=CentOS-$release - Base
08754f30 428mirrorlist=http://mirrorlist.centos.org/?release=$release&arch=$basearch&repo=os
164105f6
MW
429
430[updates]
431name=CentOS-$release - Updates
08754f30 432mirrorlist=http://mirrorlist.centos.org/?release=$release&arch=$basearch&repo=updates
164105f6 433EOF
3a6ef65a 434 fi
164105f6
MW
435
436 # create minimal device nodes, needed for "yum install" and "yum update" process
437 mkdir -p $INSTALL_ROOT/dev
438 force_mknod 666 $INSTALL_ROOT/dev/null c 1 3
439 force_mknod 666 $INSTALL_ROOT/dev/urandom c 1 9
440
441 $YUM install $PKG_LIST
442
443 if [ $? -ne 0 ]; then
444 echo "Failed to download the rootfs, aborting."
445 return 1
446 fi
447
448 # use same nameservers as hosts, needed for "yum update later"
449 cp /etc/resolv.conf $INSTALL_ROOT/etc/
450
451 # check whether rpmdb is under $HOME
452 if [ ! -e $INSTALL_ROOT/var/lib/rpm/Packages -a -e $INSTALL_ROOT/$HOME/.rpmdb/Packages ]; then
453 echo "Fixing rpmdb location ..."
454 mv $INSTALL_ROOT/$HOME/.rpmdb/[A-Z]* $INSTALL_ROOT/var/lib/rpm/
455 rm -rf $INSTALL_ROOT/$HOME/.rpmdb
456 chroot $INSTALL_ROOT rpm --rebuilddb 2>/dev/null
457 fi
458
459 # check whether rpmdb version is correct
460 chroot $INSTALL_ROOT rpm --quiet -q yum 2>/dev/null
461 ret=$?
462
463 # if "rpm -q" doesn't work due to rpmdb version difference,
464 # then we need to redo the process using the newly-installed yum
465 if [ $ret -gt 0 ]; then
466 echo "Reinstalling packages ..."
467 mv $REPO_FILE $REPO_FILE.tmp
468 mkdir $INSTALL_ROOT/etc/yum.repos.disabled
469 mv $INSTALL_ROOT/etc/yum.repos.d/*.repo $INSTALL_ROOT/etc/yum.repos.disabled/
470 mv $REPO_FILE.tmp $REPO_FILE
471 mkdir -p $INSTALL_ROOT/$INSTALL_ROOT/etc
472 cp /etc/resolv.conf $INSTALL_ROOT/$INSTALL_ROOT/etc/
473 mkdir -p $INSTALL_ROOT/$INSTALL_ROOT/dev
474 mknod -m 666 $INSTALL_ROOT/$INSTALL_ROOT/dev/null c 1 3
475 mknod -m 666 $INSTALL_ROOT/$INSTALL_ROOT/dev/urandom c 1 9
476 mkdir -p $INSTALL_ROOT/$INSTALL_ROOT/var/cache/yum
477 cp -al $INSTALL_ROOT/var/cache/yum/* $INSTALL_ROOT/$INSTALL_ROOT/var/cache/yum/
478 chroot $INSTALL_ROOT $YUM install $PKG_LIST
479 if [ $? -ne 0 ]; then
480 echo "Failed to download the rootfs, aborting."
481 return 1
482 fi
483 mv $INSTALL_ROOT/$INSTALL_ROOT $INSTALL_ROOT.tmp
484 rm -rf $INSTALL_ROOT
485 mv $INSTALL_ROOT.tmp $INSTALL_ROOT
486 fi
487
488 rm -f $REPO_FILE
489 rm -rf $INSTALL_ROOT/var/cache/yum/*
490
491 mv "$INSTALL_ROOT" "$cache/rootfs"
492 echo "Download complete."
493
494 return 0
495}
496
497copy_centos()
498{
499
500 # make a local copy of the mini centos
501 echo -n "Copying rootfs to $rootfs_path ..."
502 #cp -a $cache/rootfs-$arch $rootfs_path || return 1
503 # i prefer rsync (no reason really)
504 mkdir -p $rootfs_path
505 rsync -a $cache/rootfs/ $rootfs_path/
b4f7af7a 506 echo
164105f6
MW
507 return 0
508}
509
510update_centos()
511{
512 YUM="chroot $cache/rootfs yum -y --nogpgcheck"
513 $YUM update
514 if [ $? -ne 0 ]; then
515 return 1
516 fi
517 $YUM clean packages
518}
519
520install_centos()
521{
522 mkdir -p /var/lock/subsys/
523 (
17abf278 524 flock -x 9
164105f6
MW
525 if [ $? -ne 0 ]; then
526 echo "Cache repository is busy."
527 return 1
528 fi
529
530 echo "Checking cache download in $cache/rootfs ... "
531 if [ ! -e "$cache/rootfs" ]; then
532 download_centos
533 if [ $? -ne 0 ]; then
534 echo "Failed to download 'centos base'"
535 return 1
536 fi
537 else
538 echo "Cache found. Updating..."
539 update_centos
540 if [ $? -ne 0 ]; then
541 echo "Failed to update 'centos base', continuing with last known good cache"
542 else
543 echo "Update finished"
544 fi
545 fi
546
547 echo "Copy $cache/rootfs to $rootfs_path ... "
548 copy_centos
549 if [ $? -ne 0 ]; then
550 echo "Failed to copy rootfs"
551 return 1
552 fi
553
554 return 0
555
17abf278 556 ) 9>/var/lock/subsys/lxc-centos
164105f6
MW
557
558 return $?
559}
560
b4f7af7a 561create_hwaddr()
164105f6 562{
08754f30 563 openssl rand -hex 5 | sed -e 's/\(..\)/:\1/g; s/^/fe/'
b4f7af7a 564}
164105f6 565
b4f7af7a
MW
566copy_configuration()
567{
164105f6 568 mkdir -p $config_path
b4f7af7a
MW
569
570 grep -q "^lxc.rootfs" $config_path/config 2>/dev/null || echo "
571lxc.rootfs = $rootfs_path
572" >> $config_path/config
573
574 # The following code is to create static MAC addresses for each
575 # interface in the container. This code will work for multiple
576 # interfaces in the default config.
577 mv $config_path/config $config_path/config.def
578 while read LINE
579 do
580 # This should catch variable expansions from the default config...
581 if expr "${LINE}" : '.*\$' > /dev/null 2>&1
582 then
583 LINE=$(eval "echo \"${LINE}\"")
584 fi
585
586 # There is a tab and a space in the regex bracket below!
587 # Seems that \s doesn't work in brackets.
588 KEY=$(expr "${LINE}" : '\s*\([^ ]*\)\s*=')
589
590 if [[ "${KEY}" != "lxc.network.hwaddr" ]]
591 then
592 echo ${LINE} >> $config_path/config
593
594 if [[ "${KEY}" == "lxc.network.link" ]]
595 then
596 echo "lxc.network.hwaddr = $(create_hwaddr)" >> $config_path/config
597 fi
598 fi
599 done < $config_path/config.def
600
601 rm -f $config_path/config.def
602
1ecee40b
MW
603 if [ -e "@LXCTEMPLATECONFIG@/centos.common.conf" ]; then
604 echo "
605# Include common configuration
606lxc.include = @LXCTEMPLATECONFIG@/centos.common.conf
607" >> $config_path/config
608 fi
609
610 # Append things which require expansion here...
164105f6 611 cat <<EOF >> $config_path/config
e13923c7 612lxc.arch = $arch
164105f6 613lxc.utsname = $utsname
164105f6 614
b4f7af7a
MW
615# When using LXC with apparmor, uncomment the next line to run unconfined:
616#lxc.aa_profile = unconfined
617
164105f6
MW
618# example simple networking setup, uncomment to enable
619#lxc.network.type = $lxc_network_type
620#lxc.network.flags = up
621#lxc.network.link = $lxc_network_link
622#lxc.network.name = eth0
b4f7af7a
MW
623# Additional example for veth network type
624# static MAC address,
164105f6 625#lxc.network.hwaddr = 00:16:3e:77:52:20
b4f7af7a
MW
626# persistent veth device name on host side
627# Note: This may potentially collide with other containers of same name!
164105f6
MW
628#lxc.network.veth.pair = v-$name-e0
629
164105f6
MW
630EOF
631
632 if [ $? -ne 0 ]; then
b4f7af7a
MW
633 echo "Failed to add configuration"
634 return 1
164105f6
MW
635 fi
636
637 return 0
638}
639
640clean()
641{
642
643 if [ ! -e $cache ]; then
b4f7af7a 644 exit 0
164105f6
MW
645 fi
646
647 # lock, so we won't purge while someone is creating a repository
648 (
b4f7af7a
MW
649 flock -x 9
650 if [ $? != 0 ]; then
651 echo "Cache repository is busy."
652 exit 1
653 fi
164105f6 654
b4f7af7a
MW
655 echo -n "Purging the download cache for centos-$release..."
656 rm --preserve-root --one-file-system -rf $cache && echo "Done." || exit 1
657 exit 0
164105f6 658
b4f7af7a 659 ) 9>@LOCALSTATEDIR@/lock/subsys/lxc-centos
164105f6
MW
660}
661
662usage()
663{
664 cat <<EOF
665usage:
666 $1 -n|--name=<container_name>
6bfb727c 667 [-p|--path=<path>] [-c|--clean] [-R|--release=<CentOS_release>] [-a|--arch=<arch of the container>]
164105f6
MW
668 [-h|--help]
669Mandatory args:
670 -n,--name container name, used to as an identifier for that container from now on
671Optional args:
08754f30 672 -p,--path path to where the container rootfs will be created, defaults to /var/lib/lxc/name.
164105f6
MW
673 -c,--clean clean the cache
674 -R,--release Centos release for the new container. if the host is Centos, then it will defaultto the host's release.
675 --fqdn fully qualified domain name (FQDN) for DNS and system naming
3a6ef65a 676 --repo repository to use (url)
08754f30 677 -a,--arch Define what arch the container will be [i686,x86_64]
164105f6
MW
678 -h,--help print this help
679EOF
680 return 0
681}
682
3a6ef65a 683options=$(getopt -o a:hp:n:cR: -l help,path:,rootfs:,name:,clean,release:,repo:,arch:,fqdn: -- "$@")
164105f6
MW
684if [ $? -ne 0 ]; then
685 usage $(basename $0)
686 exit 1
687fi
164105f6 688
4849ab99 689arch=$(uname -m)
08754f30 690eval set -- "$options"
164105f6
MW
691while true
692do
693 case "$1" in
694 -h|--help) usage $0 && exit 0;;
695 -p|--path) path=$2; shift 2;;
696 --rootfs) rootfs=$2; shift 2;;
697 -n|--name) name=$2; shift 2;;
6976826f 698 -c|--clean) clean=1; shift 1;;
164105f6 699 -R|--release) release=$2; shift 2;;
2ae8252a 700 --repo) repo="$2"; shift 2;;
08754f30 701 -a|--arch) newarch=$2; shift 2;;
164105f6
MW
702 --fqdn) utsname=$2; shift 2;;
703 --) shift 1; break ;;
704 *) break ;;
705 esac
706done
707
708if [ ! -z "$clean" -a -z "$path" ]; then
709 clean || exit 1
710 exit 0
711fi
712
08754f30
MW
713basearch=${arch}
714# Map a few architectures to their generic CentOS repository archs.
715# The two ARM archs are a bit of a guesstimate for the v5 and v6
716# archs. V6 should have hardware floating point (Rasberry Pi).
717# The "arm" arch is safer (no hardware floating point). So
718# there may be cases where we "get it wrong" for some v6 other
719# than RPi.
720case "$arch" in
721i686) basearch=i386 ;;
722armv3l|armv4l|armv5l) basearch=arm ;;
723armv6l|armv7l|armv8l) basearch=armhfp ;;
724*) ;;
725esac
726
727# Somebody wants to specify an arch. This is very limited case.
728# i386/i586/i686 on i386/x86_64
729# - or -
730# x86_64 on x86_64
731if [ "${newarch}" != "" -a "${newarch}" != "${arch}" ]
732then
733 case "${newarch}" in
734 i386|i586|i686)
735 if [ "${basearch}" = "i386" -o "${basearch}" = "x86_64" ]
736 then
737 # Make the arch a generic x86 32 bit...
738 arch=${newarch}
739 basearch=i386
740 else
741 basearch=bad
742 fi
743 ;;
744 *)
745 basearch=bad
746 ;;
747 esac
748
749 if [ "${basearch}" = "bad" ]
750 then
751 echo "You cannot build a ${newarch} CentOS container on a ${arch} host. Sorry!"
752 exit 1
753 fi
754fi
755
756cache_base=@LOCALSTATEDIR@/cache/lxc/centos/$basearch
757
b4f7af7a
MW
758# Let's do something better for the initial root password.
759# It's not perfect but it will defeat common scanning brute force
760# attacks in the case where ssh is exposed. It will also be set to
761# expired, forcing the user to change it at first login.
762if [ "${root_password}" = "" ]
763then
764 root_password=Root-${name}-${RANDOM}
765else
766 # If it's got a ding in it, try and expand it!
767 if [ $(expr "${root_password}" : '.*$.') != 0 ]
768 then
769 root_password=$(eval echo "${root_password}")
770 fi
771
ec64264d 772 # If it has more than 3 consecutive X's in it, feed it
b4f7af7a
MW
773 # through mktemp as a template.
774 if [ $(expr "${root_password}" : '.*XXXX') != 0 ]
775 then
776 root_password=$(mktemp -u ${root_password})
777 fi
778fi
779
164105f6
MW
780if [ -z "${utsname}" ]; then
781 utsname=${name}
782fi
783
784# This follows a standard "resolver" convention that an FQDN must have
785# at least two dots or it is considered a local relative host name.
786# If it doesn't, append the dns domain name of the host system.
787#
788# This changes one significant behavior when running
789# "lxc_create -n Container_Name" without using the
790# --fqdn option.
791#
792# Old behavior:
793# utsname and hostname = Container_Name
794# New behavior:
795# utsname and hostname = Container_Name.Domain_Name
796
797if [ $(expr "$utsname" : '.*\..*\.') = 0 ]; then
b4f7af7a 798 if [[ "$(dnsdomainname)" != "" && "$(dnsdomainname)" != "localdomain" ]]; then
164105f6
MW
799 utsname=${utsname}.$(dnsdomainname)
800 fi
801fi
802
803type yum >/dev/null 2>&1
804if [ $? -ne 0 ]; then
805 echo "'yum' command is missing"
806 exit 1
807fi
808
809if [ -z "$path" ]; then
810 path=$default_path/$name
811fi
812
813if [ -z "$release" ]; then
814 if [ "$is_centos" -a "$centos_host_ver" ]; then
815 release=$centos_host_ver
c6df5ca4
MW
816 elif [ "$is_redhat" -a "$redhat_host_ver" ]; then
817 # This is needed to clean out bullshit like 6workstation and 6server.
818 release=$(expr $redhat_host_ver : '\([0-9.]*\)')
164105f6 819 else
c6df5ca4 820 echo "This is not a CentOS or Redhat host and release is missing, defaulting to 6 use -R|--release to specify release"
164105f6
MW
821 release=6
822 fi
823fi
824
164105f6
MW
825if [ "$(id -u)" != "0" ]; then
826 echo "This script should be run as 'root'"
827 exit 1
828fi
829
830
831if [ -z "$rootfs_path" ]; then
832 rootfs_path=$path/rootfs
833 # check for 'lxc.rootfs' passed in through default config by lxc-create
834 if grep -q '^lxc.rootfs' $path/config 2>/dev/null ; then
08754f30
MW
835 rootfs_path=$(sed -e '/^lxc.rootfs\s*=/!d' -e 's/\s*#.*//' \
836 -e 's/^lxc.rootfs\s*=\s*//' -e q $path/config)
164105f6
MW
837 fi
838fi
08754f30 839config_path=$path
164105f6
MW
840cache=$cache_base/$release
841
842revert()
843{
844 echo "Interrupted, so cleaning up"
845 lxc-destroy -n $name
846 # maybe was interrupted before copy config
847 rm -rf $path
164105f6
MW
848 echo "exiting..."
849 exit 1
850}
851
852trap revert SIGHUP SIGINT SIGTERM
853
854copy_configuration
855if [ $? -ne 0 ]; then
856 echo "failed write configuration file"
857 exit 1
858fi
859
860install_centos
861if [ $? -ne 0 ]; then
862 echo "failed to install centos"
863 exit 1
864fi
865
866configure_centos
867if [ $? -ne 0 ]; then
868 echo "failed to configure centos for a container"
869 exit 1
870fi
871
872configure_centos_init
873
a2780518 874if [ ! -z "$clean" ]; then
164105f6
MW
875 clean || exit 1
876 exit 0
877fi
b4f7af7a
MW
878echo "
879Container rootfs and config have been created.
880Edit the config file to check/enable networking setup.
881"
882
883if [ ${root_display_password} = "yes" ]
884then
885 echo "The temporary password for root is: '$root_password'
886
887You may want to note that password down before starting the container.
888"
889fi
890
891if [ ${root_store_password} = "yes" ]
892then
893 echo "The temporary root password is stored in:
894
895 '${config_path}/tmp_root_pass'
896"
897fi
898
899if [ ${root_prompt_password} = "yes" ]
900then
901 echo "Invoking the passwd command in the container to set the root password.
902
903 chroot ${rootfs_path} passwd
904"
905 chroot ${rootfs_path} passwd
906else
826cde7c
MW
907 if [ ${root_expire_password} = "yes" ]
908 then
909 echo "
b4f7af7a
MW
910The root password is set up as "expired" and will require it to be changed
911at first login, which you should do as soon as possible. If you lose the
912root password or wish to change it without starting the container, you
913can change it from the host by running the following command (which will
914also reset the expired flag):
915
916 chroot ${rootfs_path} passwd
917"
826cde7c 918 fi
b4f7af7a 919fi