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