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