]> git.proxmox.com Git - mirror_lxc.git/blame - templates/lxc-centos.in
lxc-centos: fix tab/space mixup in help text.
[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 ..."
412 YUM="yum --installroot $INSTALL_ROOT -y --nogpgcheck"
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
MW
614
615lxc.autodev = $auto_dev
616
b4f7af7a
MW
617# When using LXC with apparmor, uncomment the next line to run unconfined:
618#lxc.aa_profile = unconfined
619
164105f6
MW
620# example simple networking setup, uncomment to enable
621#lxc.network.type = $lxc_network_type
622#lxc.network.flags = up
623#lxc.network.link = $lxc_network_link
624#lxc.network.name = eth0
b4f7af7a
MW
625# Additional example for veth network type
626# static MAC address,
164105f6 627#lxc.network.hwaddr = 00:16:3e:77:52:20
b4f7af7a
MW
628# persistent veth device name on host side
629# Note: This may potentially collide with other containers of same name!
164105f6
MW
630#lxc.network.veth.pair = v-$name-e0
631
164105f6
MW
632EOF
633
634 if [ $? -ne 0 ]; then
b4f7af7a
MW
635 echo "Failed to add configuration"
636 return 1
164105f6
MW
637 fi
638
639 return 0
640}
641
642clean()
643{
644
645 if [ ! -e $cache ]; then
b4f7af7a 646 exit 0
164105f6
MW
647 fi
648
649 # lock, so we won't purge while someone is creating a repository
650 (
b4f7af7a
MW
651 flock -x 9
652 if [ $? != 0 ]; then
653 echo "Cache repository is busy."
654 exit 1
655 fi
164105f6 656
b4f7af7a
MW
657 echo -n "Purging the download cache for centos-$release..."
658 rm --preserve-root --one-file-system -rf $cache && echo "Done." || exit 1
659 exit 0
164105f6 660
b4f7af7a 661 ) 9>@LOCALSTATEDIR@/lock/subsys/lxc-centos
164105f6
MW
662}
663
664usage()
665{
666 cat <<EOF
667usage:
668 $1 -n|--name=<container_name>
6bfb727c 669 [-p|--path=<path>] [-c|--clean] [-R|--release=<CentOS_release>] [-a|--arch=<arch of the container>]
164105f6
MW
670 [-h|--help]
671Mandatory args:
672 -n,--name container name, used to as an identifier for that container from now on
673Optional args:
08754f30 674 -p,--path path to where the container rootfs will be created, defaults to /var/lib/lxc/name.
164105f6
MW
675 -c,--clean clean the cache
676 -R,--release Centos release for the new container. if the host is Centos, then it will defaultto the host's release.
677 --fqdn fully qualified domain name (FQDN) for DNS and system naming
3a6ef65a 678 --repo repository to use (url)
08754f30 679 -a,--arch Define what arch the container will be [i686,x86_64]
164105f6
MW
680 -h,--help print this help
681EOF
682 return 0
683}
684
3a6ef65a 685options=$(getopt -o a:hp:n:cR: -l help,path:,rootfs:,name:,clean,release:,repo:,arch:,fqdn: -- "$@")
164105f6
MW
686if [ $? -ne 0 ]; then
687 usage $(basename $0)
688 exit 1
689fi
164105f6 690
4849ab99 691arch=$(uname -m)
08754f30 692eval set -- "$options"
164105f6
MW
693while true
694do
695 case "$1" in
696 -h|--help) usage $0 && exit 0;;
697 -p|--path) path=$2; shift 2;;
698 --rootfs) rootfs=$2; shift 2;;
699 -n|--name) name=$2; shift 2;;
6976826f 700 -c|--clean) clean=1; shift 1;;
164105f6 701 -R|--release) release=$2; shift 2;;
2ae8252a 702 --repo) repo="$2"; shift 2;;
08754f30 703 -a|--arch) newarch=$2; shift 2;;
164105f6
MW
704 --fqdn) utsname=$2; shift 2;;
705 --) shift 1; break ;;
706 *) break ;;
707 esac
708done
709
710if [ ! -z "$clean" -a -z "$path" ]; then
711 clean || exit 1
712 exit 0
713fi
714
08754f30
MW
715basearch=${arch}
716# Map a few architectures to their generic CentOS repository archs.
717# The two ARM archs are a bit of a guesstimate for the v5 and v6
718# archs. V6 should have hardware floating point (Rasberry Pi).
719# The "arm" arch is safer (no hardware floating point). So
720# there may be cases where we "get it wrong" for some v6 other
721# than RPi.
722case "$arch" in
723i686) basearch=i386 ;;
724armv3l|armv4l|armv5l) basearch=arm ;;
725armv6l|armv7l|armv8l) basearch=armhfp ;;
726*) ;;
727esac
728
729# Somebody wants to specify an arch. This is very limited case.
730# i386/i586/i686 on i386/x86_64
731# - or -
732# x86_64 on x86_64
733if [ "${newarch}" != "" -a "${newarch}" != "${arch}" ]
734then
735 case "${newarch}" in
736 i386|i586|i686)
737 if [ "${basearch}" = "i386" -o "${basearch}" = "x86_64" ]
738 then
739 # Make the arch a generic x86 32 bit...
740 arch=${newarch}
741 basearch=i386
742 else
743 basearch=bad
744 fi
745 ;;
746 *)
747 basearch=bad
748 ;;
749 esac
750
751 if [ "${basearch}" = "bad" ]
752 then
753 echo "You cannot build a ${newarch} CentOS container on a ${arch} host. Sorry!"
754 exit 1
755 fi
756fi
757
758cache_base=@LOCALSTATEDIR@/cache/lxc/centos/$basearch
759
b4f7af7a
MW
760# Let's do something better for the initial root password.
761# It's not perfect but it will defeat common scanning brute force
762# attacks in the case where ssh is exposed. It will also be set to
763# expired, forcing the user to change it at first login.
764if [ "${root_password}" = "" ]
765then
766 root_password=Root-${name}-${RANDOM}
767else
768 # If it's got a ding in it, try and expand it!
769 if [ $(expr "${root_password}" : '.*$.') != 0 ]
770 then
771 root_password=$(eval echo "${root_password}")
772 fi
773
ec64264d 774 # If it has more than 3 consecutive X's in it, feed it
b4f7af7a
MW
775 # through mktemp as a template.
776 if [ $(expr "${root_password}" : '.*XXXX') != 0 ]
777 then
778 root_password=$(mktemp -u ${root_password})
779 fi
780fi
781
164105f6
MW
782if [ -z "${utsname}" ]; then
783 utsname=${name}
784fi
785
786# This follows a standard "resolver" convention that an FQDN must have
787# at least two dots or it is considered a local relative host name.
788# If it doesn't, append the dns domain name of the host system.
789#
790# This changes one significant behavior when running
791# "lxc_create -n Container_Name" without using the
792# --fqdn option.
793#
794# Old behavior:
795# utsname and hostname = Container_Name
796# New behavior:
797# utsname and hostname = Container_Name.Domain_Name
798
799if [ $(expr "$utsname" : '.*\..*\.') = 0 ]; then
b4f7af7a 800 if [[ "$(dnsdomainname)" != "" && "$(dnsdomainname)" != "localdomain" ]]; then
164105f6
MW
801 utsname=${utsname}.$(dnsdomainname)
802 fi
803fi
804
805type yum >/dev/null 2>&1
806if [ $? -ne 0 ]; then
807 echo "'yum' command is missing"
808 exit 1
809fi
810
811if [ -z "$path" ]; then
812 path=$default_path/$name
813fi
814
815if [ -z "$release" ]; then
816 if [ "$is_centos" -a "$centos_host_ver" ]; then
817 release=$centos_host_ver
c6df5ca4
MW
818 elif [ "$is_redhat" -a "$redhat_host_ver" ]; then
819 # This is needed to clean out bullshit like 6workstation and 6server.
820 release=$(expr $redhat_host_ver : '\([0-9.]*\)')
164105f6 821 else
c6df5ca4 822 echo "This is not a CentOS or Redhat host and release is missing, defaulting to 6 use -R|--release to specify release"
164105f6
MW
823 release=6
824 fi
825fi
826
827# CentOS 7 and above should run systemd. We need autodev enabled to keep
828# systemd from causing problems.
c6df5ca4
MW
829#
830# There is some ambiguity here due to the differnce between versioning
831# of point specific releases such as 6.5 and the rolling release 6. We
832# only want the major number here if it's a point release...
833
834mrelease=$(expr $release : '\([0-9]*\)')
835if [ $mrelease -gt 6 ]; then
164105f6
MW
836 auto_dev="1"
837else
838 auto_dev="0"
839fi
840
841if [ "$(id -u)" != "0" ]; then
842 echo "This script should be run as 'root'"
843 exit 1
844fi
845
846
847if [ -z "$rootfs_path" ]; then
848 rootfs_path=$path/rootfs
849 # check for 'lxc.rootfs' passed in through default config by lxc-create
850 if grep -q '^lxc.rootfs' $path/config 2>/dev/null ; then
08754f30
MW
851 rootfs_path=$(sed -e '/^lxc.rootfs\s*=/!d' -e 's/\s*#.*//' \
852 -e 's/^lxc.rootfs\s*=\s*//' -e q $path/config)
164105f6
MW
853 fi
854fi
08754f30 855config_path=$path
164105f6
MW
856cache=$cache_base/$release
857
858revert()
859{
860 echo "Interrupted, so cleaning up"
861 lxc-destroy -n $name
862 # maybe was interrupted before copy config
863 rm -rf $path
164105f6
MW
864 echo "exiting..."
865 exit 1
866}
867
868trap revert SIGHUP SIGINT SIGTERM
869
870copy_configuration
871if [ $? -ne 0 ]; then
872 echo "failed write configuration file"
873 exit 1
874fi
875
876install_centos
877if [ $? -ne 0 ]; then
878 echo "failed to install centos"
879 exit 1
880fi
881
882configure_centos
883if [ $? -ne 0 ]; then
884 echo "failed to configure centos for a container"
885 exit 1
886fi
887
888configure_centos_init
889
890if [ ! -z $clean ]; then
891 clean || exit 1
892 exit 0
893fi
b4f7af7a
MW
894echo "
895Container rootfs and config have been created.
896Edit the config file to check/enable networking setup.
897"
898
899if [ ${root_display_password} = "yes" ]
900then
901 echo "The temporary password for root is: '$root_password'
902
903You may want to note that password down before starting the container.
904"
905fi
906
907if [ ${root_store_password} = "yes" ]
908then
909 echo "The temporary root password is stored in:
910
911 '${config_path}/tmp_root_pass'
912"
913fi
914
915if [ ${root_prompt_password} = "yes" ]
916then
917 echo "Invoking the passwd command in the container to set the root password.
918
919 chroot ${rootfs_path} passwd
920"
921 chroot ${rootfs_path} passwd
922else
826cde7c
MW
923 if [ ${root_expire_password} = "yes" ]
924 then
925 echo "
b4f7af7a
MW
926The root password is set up as "expired" and will require it to be changed
927at first login, which you should do as soon as possible. If you lose the
928root password or wish to change it without starting the container, you
929can change it from the host by running the following command (which will
930also reset the expired flag):
931
932 chroot ${rootfs_path} passwd
933"
826cde7c 934 fi
b4f7af7a 935fi