]> git.proxmox.com Git - mirror_lxc.git/blame - templates/lxc-centos.in
Added templates/lxc-centos for CentOS containers.
[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@
33# We really need something better here!
34root_password=root
35
36lxc_network_type=veth
37lxc_network_link=lxcbr0
38
39# is this centos?
40# Alow for weird remixes like the Raspberry Pi
41#
42# Use the Mitre standard CPE identifier for the release ID if possible...
43# This may be in /etc/os-release or /etc/system-release-cpe. We
44# should be able to use EITHER. Give preference to /etc/os-release for now.
45
46if [ -e /etc/os-release ]
47then
48# This is a shell friendly configuration file. We can just source it.
49# What we're looking for in here is the ID, VERSION_ID and the CPE_NAME
50 . /etc/os-release
51 echo "Host CPE ID from /etc/os-release: ${CPE_NAME}"
52fi
53
54if [ "${CPE_NAME}" = "" -a -e /etc/system-release-cpe ]
55then
56 CPE_NAME=$(head -n1 /etc/system-release-cpe)
57 CPE_URI=$(expr ${CPE_NAME} : '\([^:]*:[^:*]\)')
58 if [ "${CPE_URI}" != "cpe:/o" ]
59 then
60 CPE_NAME=
61 else
62 echo "Host CPE ID from /etc/system-release-cpe: ${CPE_NAME}"
63 # Probably a better way to do this but sill remain posix
64 # compatible but this works, shrug...
65 # Must be nice and not introduce convenient bashisms here.
66 ID=$(expr ${CPE_NAME} : '[^:]*:[^:]*:[^:]*:\([^:]*\)')
67 VERSION_ID=$(expr ${CPE_NAME} : '[^:]*:[^:]*:[^:]*:[^:]*:\([^:]*\)')
68 fi
69fi
70
71if [ "${CPE_NAME}" != "" -a "${ID}" = "centos" -a "${VERSION_ID}" != "" ]
72then
73 centos_host_ver=${VERSION_ID}
74 is_centos=true
75elif [ -e /etc/redhat-release ]
76then
77 # Only if all other methods fail, try to parse the redhat-release file.
78 centos_host_ver=$( sed -e '/^CentOS /!d' -e 's/CentOS*\srelease\s*\([0-9][0-9]*\)\s.*/\1/' < /etc/redhat-release )
79 if [ "$centos_host_ver" != "" ]
80 then
81 is_centos=true
82 fi
83fi
84
85# Map a few architectures to their generic Centos repository archs.
86#
87# CentOS currently doesn't support ARM but it's copied here from
88# the Fedora template for completeness and that it will in the future.
89#
90# The two ARM archs are a bit of a guesstimate for the v5 and v6
91# archs. V6 should have hardware floating point (Rasberry Pi).
92# The "arm" arch is safer (no hardware floating point). So
93# there may be cases where we "get it wrong" for some v6 other
94# than RPi.
95case "$arch" in
96i686) arch=i386 ;;
97armv3l|armv4l|armv5l) arch=arm ;;
98armv6l|armv7l|armv8l) arch=armhfp ;;
99esac
100
101force_mknod()
102{
103 # delete a device node if exists, and create a new one
104 rm -f $2 && mknod -m $1 $2 $3 $4 $5
105}
106
107configure_centos()
108{
109
110 # disable selinux in centos
111 mkdir -p $rootfs_path/selinux
112 echo 0 > $rootfs_path/selinux/enforce
113
114 # Also kill it in the /etc/selinux/config file if it's there...
115 if [[ -f $rootfs_path/etc/selinux/config ]]
116 then
117 sed -i '/^SELINUX=/s/.*/SELINUX=disabled/' $rootfs_path/etc/selinux/config
118 fi
119
120 # Nice catch from Dwight Engen in the Oracle template.
121 # Wantonly plagerized here with much appreciation.
122 if [ -f $rootfs_path/usr/sbin/selinuxenabled ]; then
123 mv $rootfs_path/usr/sbin/selinuxenabled $rootfs_path/usr/sbin/selinuxenabled.lxcorig
124 ln -s /bin/false $rootfs_path/usr/sbin/selinuxenabled
125 fi
126
127 # This is a known problem and documented in RedHat bugzilla as relating
128 # to a problem with auditing enabled. This prevents an error in
129 # the container "Cannot make/remove an entry for the specified session"
130 sed -i '/^session.*pam_loginuid.so/s/^session/# session/' ${rootfs_path}/etc/pam.d/login
131 sed -i '/^session.*pam_loginuid.so/s/^session/# session/' ${rootfs_path}/etc/pam.d/sshd
132
133 # configure the network using the dhcp
134 cat <<EOF > ${rootfs_path}/etc/sysconfig/network-scripts/ifcfg-eth0
135DEVICE=eth0
136BOOTPROTO=dhcp
137ONBOOT=yes
138HOSTNAME=${UTSNAME}
139NM_CONTROLLED=no
140TYPE=Ethernet
141MTU=${MTU}
142EOF
143
144 # set the hostname
145 cat <<EOF > ${rootfs_path}/etc/sysconfig/network
146NETWORKING=yes
147HOSTNAME=${UTSNAME}
148EOF
149
150 # set minimal hosts
151 cat <<EOF > $rootfs_path/etc/hosts
152127.0.0.1 localhost $name
153EOF
154
155 # set minimal fstab
156 cat <<EOF > $rootfs_path/etc/fstab
157/dev/root / rootfs defaults 0 0
158none /dev/shm tmpfs nosuid,nodev 0 0
159EOF
160
161 # create lxc compatibility init script
162 if [ "$release" = "6" ]; then
163 cat <<EOF > $rootfs_path/etc/init/lxc-sysinit.conf
164start on startup
165env container
166
167pre-start script
168 if [ "x$container" != "xlxc" -a "x$container" != "xlibvirt" ]; then
169 stop;
170 fi
171 initctl start tty TTY=console
172 rm -f /var/lock/subsys/*
173 rm -f /var/run/*.pid
174 telinit 3
175 exit 0;
176end script
177EOF
178 elif [ "$release" = "5" ]; then
179 cat <<EOF > $rootfs_path/etc/rc.d/lxc.sysinit
180#! /bin/bash
181rm -f /etc/mtab /var/run/*.{pid,lock} /var/lock/subsys/*
182rm -rf {/,/var}/tmp/*
183echo "/dev/root / rootfs defaults 0 0" > /etc/mtab
184exit 0
185EOF
186 chmod 755 $rootfs_path/etc/rc.d/lxc.sysinit
187 sed -i 's|si::sysinit:/etc/rc.d/rc.sysinit|si::bootwait:/etc/rc.d/lxc.sysinit|' $rootfs_path/etc/inittab
188 sed -i 's|^1:|co:2345:respawn:/sbin/mingetty console\n1:|' $rootfs_path/etc/inittab
189 sed -i 's|^\([56]:\)|#\1|' $rootfs_path/etc/inittab
190 fi
191
192 dev_path="${rootfs_path}/dev"
193 rm -rf $dev_path
194 mkdir -p $dev_path
195 mknod -m 666 ${dev_path}/null c 1 3
196 mknod -m 666 ${dev_path}/zero c 1 5
197 mknod -m 666 ${dev_path}/random c 1 8
198 mknod -m 666 ${dev_path}/urandom c 1 9
199 mkdir -m 755 ${dev_path}/pts
200 mkdir -m 1777 ${dev_path}/shm
201 mknod -m 666 ${dev_path}/tty c 5 0
202 mknod -m 666 ${dev_path}/tty0 c 4 0
203 mknod -m 666 ${dev_path}/tty1 c 4 1
204 mknod -m 666 ${dev_path}/tty2 c 4 2
205 mknod -m 666 ${dev_path}/tty3 c 4 3
206 mknod -m 666 ${dev_path}/tty4 c 4 4
207 mknod -m 600 ${dev_path}/console c 5 1
208 mknod -m 666 ${dev_path}/full c 1 7
209 mknod -m 600 ${dev_path}/initctl p
210 mknod -m 666 ${dev_path}/ptmx c 5 2
211
212 echo "setting root passwd to $root_password"
213 echo "root:$root_password" | chroot $rootfs_path chpasswd
214
215 # This will need to be enhanced for CentOS 7 when systemd
216 # comes into play... /\/\|=mhw=|\/\/
217
218 return 0
219}
220
221configure_centos_init()
222{
223 sed -i 's|.sbin.start_udev||' ${rootfs_path}/etc/rc.sysinit
224 sed -i 's|.sbin.start_udev||' ${rootfs_path}/etc/rc.d/rc.sysinit
225 if [ "$release" = "6" ]; then
226 chroot ${rootfs_path} chkconfig udev-post off
227 fi
228 chroot ${rootfs_path} chkconfig network on
229}
230
231download_centos()
232{
233
234 # check the mini centos was not already downloaded
235 INSTALL_ROOT=$cache/partial
236 mkdir -p $INSTALL_ROOT
237 if [ $? -ne 0 ]; then
238 echo "Failed to create '$INSTALL_ROOT' directory"
239 return 1
240 fi
241
242 # download a mini centos into a cache
243 echo "Downloading centos minimal ..."
244 YUM="yum --installroot $INSTALL_ROOT -y --nogpgcheck"
245 PKG_LIST="yum initscripts passwd rsyslog vim-minimal openssh-server openssh-clients dhclient chkconfig rootfiles policycoreutils"
246
247 # use temporary repository definition
248 REPO_FILE=$INSTALL_ROOT/etc/yum.repos.d/lxc-centos-temp.repo
249 mkdir -p $(dirname $REPO_FILE)
250 cat <<EOF > $REPO_FILE
251[base]
252name=CentOS-$release - Base
253mirrorlist=http://mirrorlist.centos.org/?release=$release&arch=$arch&repo=os
254
255[updates]
256name=CentOS-$release - Updates
257mirrorlist=http://mirrorlist.centos.org/?release=$release&arch=$arch&repo=updates
258EOF
259
260 # create minimal device nodes, needed for "yum install" and "yum update" process
261 mkdir -p $INSTALL_ROOT/dev
262 force_mknod 666 $INSTALL_ROOT/dev/null c 1 3
263 force_mknod 666 $INSTALL_ROOT/dev/urandom c 1 9
264
265 $YUM install $PKG_LIST
266
267 if [ $? -ne 0 ]; then
268 echo "Failed to download the rootfs, aborting."
269 return 1
270 fi
271
272 # use same nameservers as hosts, needed for "yum update later"
273 cp /etc/resolv.conf $INSTALL_ROOT/etc/
274
275 # check whether rpmdb is under $HOME
276 if [ ! -e $INSTALL_ROOT/var/lib/rpm/Packages -a -e $INSTALL_ROOT/$HOME/.rpmdb/Packages ]; then
277 echo "Fixing rpmdb location ..."
278 mv $INSTALL_ROOT/$HOME/.rpmdb/[A-Z]* $INSTALL_ROOT/var/lib/rpm/
279 rm -rf $INSTALL_ROOT/$HOME/.rpmdb
280 chroot $INSTALL_ROOT rpm --rebuilddb 2>/dev/null
281 fi
282
283 # check whether rpmdb version is correct
284 chroot $INSTALL_ROOT rpm --quiet -q yum 2>/dev/null
285 ret=$?
286
287 # if "rpm -q" doesn't work due to rpmdb version difference,
288 # then we need to redo the process using the newly-installed yum
289 if [ $ret -gt 0 ]; then
290 echo "Reinstalling packages ..."
291 mv $REPO_FILE $REPO_FILE.tmp
292 mkdir $INSTALL_ROOT/etc/yum.repos.disabled
293 mv $INSTALL_ROOT/etc/yum.repos.d/*.repo $INSTALL_ROOT/etc/yum.repos.disabled/
294 mv $REPO_FILE.tmp $REPO_FILE
295 mkdir -p $INSTALL_ROOT/$INSTALL_ROOT/etc
296 cp /etc/resolv.conf $INSTALL_ROOT/$INSTALL_ROOT/etc/
297 mkdir -p $INSTALL_ROOT/$INSTALL_ROOT/dev
298 mknod -m 666 $INSTALL_ROOT/$INSTALL_ROOT/dev/null c 1 3
299 mknod -m 666 $INSTALL_ROOT/$INSTALL_ROOT/dev/urandom c 1 9
300 mkdir -p $INSTALL_ROOT/$INSTALL_ROOT/var/cache/yum
301 cp -al $INSTALL_ROOT/var/cache/yum/* $INSTALL_ROOT/$INSTALL_ROOT/var/cache/yum/
302 chroot $INSTALL_ROOT $YUM install $PKG_LIST
303 if [ $? -ne 0 ]; then
304 echo "Failed to download the rootfs, aborting."
305 return 1
306 fi
307 mv $INSTALL_ROOT/$INSTALL_ROOT $INSTALL_ROOT.tmp
308 rm -rf $INSTALL_ROOT
309 mv $INSTALL_ROOT.tmp $INSTALL_ROOT
310 fi
311
312 rm -f $REPO_FILE
313 rm -rf $INSTALL_ROOT/var/cache/yum/*
314
315 mv "$INSTALL_ROOT" "$cache/rootfs"
316 echo "Download complete."
317
318 return 0
319}
320
321copy_centos()
322{
323
324 # make a local copy of the mini centos
325 echo -n "Copying rootfs to $rootfs_path ..."
326 #cp -a $cache/rootfs-$arch $rootfs_path || return 1
327 # i prefer rsync (no reason really)
328 mkdir -p $rootfs_path
329 rsync -a $cache/rootfs/ $rootfs_path/
330 return 0
331}
332
333update_centos()
334{
335 YUM="chroot $cache/rootfs yum -y --nogpgcheck"
336 $YUM update
337 if [ $? -ne 0 ]; then
338 return 1
339 fi
340 $YUM clean packages
341}
342
343install_centos()
344{
345 mkdir -p /var/lock/subsys/
346 (
347 flock -x 200
348 if [ $? -ne 0 ]; then
349 echo "Cache repository is busy."
350 return 1
351 fi
352
353 echo "Checking cache download in $cache/rootfs ... "
354 if [ ! -e "$cache/rootfs" ]; then
355 download_centos
356 if [ $? -ne 0 ]; then
357 echo "Failed to download 'centos base'"
358 return 1
359 fi
360 else
361 echo "Cache found. Updating..."
362 update_centos
363 if [ $? -ne 0 ]; then
364 echo "Failed to update 'centos base', continuing with last known good cache"
365 else
366 echo "Update finished"
367 fi
368 fi
369
370 echo "Copy $cache/rootfs to $rootfs_path ... "
371 copy_centos
372 if [ $? -ne 0 ]; then
373 echo "Failed to copy rootfs"
374 return 1
375 fi
376
377 return 0
378
379 ) 200>/var/lock/subsys/lxc
380
381 return $?
382}
383
384copy_configuration()
385{
386
387 mkdir -p $config_path
388 cat <<EOF >> $config_path/config
389lxc.utsname = $utsname
390lxc.tty = 4
391lxc.pts = 1024
392lxc.rootfs = $rootfs_path
393lxc.mount = $config_path/fstab
394lxc.cap.drop = sys_module mac_admin mac_override sys_time
395
396lxc.autodev = $auto_dev
397
398# example simple networking setup, uncomment to enable
399#lxc.network.type = $lxc_network_type
400#lxc.network.flags = up
401#lxc.network.link = $lxc_network_link
402#lxc.network.name = eth0
403# additional example for veth network type, static MAC address,
404# and persistent veth device name on host side
405#lxc.network.hwaddr = 00:16:3e:77:52:20
406#lxc.network.veth.pair = v-$name-e0
407
408#cgroups
409lxc.cgroup.devices.deny = a
410# /dev/null and zero
411lxc.cgroup.devices.allow = c 1:3 rwm
412lxc.cgroup.devices.allow = c 1:5 rwm
413# consoles
414lxc.cgroup.devices.allow = c 5:1 rwm
415lxc.cgroup.devices.allow = c 5:0 rwm
416lxc.cgroup.devices.allow = c 4:0 rwm
417lxc.cgroup.devices.allow = c 4:1 rwm
418# /dev/{,u}random
419lxc.cgroup.devices.allow = c 1:9 rwm
420lxc.cgroup.devices.allow = c 1:8 rwm
421lxc.cgroup.devices.allow = c 136:* rwm
422lxc.cgroup.devices.allow = c 5:2 rwm
423# rtc
424lxc.cgroup.devices.allow = c 254:0 rwm
425EOF
426
427 cat <<EOF > $config_path/fstab
428proc proc proc nodev,noexec,nosuid 0 0
429devpts dev/pts devpts defaults 0 0
430sysfs sys sysfs defaults 0 0
431EOF
432
433 if [ $? -ne 0 ]; then
434 echo "Failed to add configuration"
435 return 1
436 fi
437
438 return 0
439}
440
441clean()
442{
443
444 if [ ! -e $cache ]; then
445 exit 0
446 fi
447
448 # lock, so we won't purge while someone is creating a repository
449 (
450 flock -x 200
451 if [ $? != 0 ]; then
452 echo "Cache repository is busy."
453 exit 1
454 fi
455
456 echo -n "Purging the download cache for centos-$release..."
457 rm --preserve-root --one-file-system -rf $cache && echo "Done." || exit 1
458 exit 0
459
460 ) 200>/var/lock/subsys/lxc
461}
462
463usage()
464{
465 cat <<EOF
466usage:
467 $1 -n|--name=<container_name>
468 [-p|--path=<path>] [-c|--clean] [-R|--release=<CentOS_release>] [-A|--arch=<arch of the container>]
469 [-h|--help]
470Mandatory args:
471 -n,--name container name, used to as an identifier for that container from now on
472Optional args:
473 -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
474 -c,--clean clean the cache
475 -R,--release Centos release for the new container. if the host is Centos, then it will defaultto the host's release.
476 --fqdn fully qualified domain name (FQDN) for DNS and system naming
477 -A,--arch NOT USED YET. Define what arch the container will be [i686,x86_64]
478 -h,--help print this help
479EOF
480 return 0
481}
482
483options=$(getopt -o hp:n:cR: -l help,path:,rootfs:,name:,clean,release:,fqdn: -- "$@")
484if [ $? -ne 0 ]; then
485 usage $(basename $0)
486 exit 1
487fi
488eval set -- "$options"
489
490while true
491do
492 case "$1" in
493 -h|--help) usage $0 && exit 0;;
494 -p|--path) path=$2; shift 2;;
495 --rootfs) rootfs=$2; shift 2;;
496 -n|--name) name=$2; shift 2;;
497 -c|--clean) clean=$2; shift 2;;
498 -R|--release) release=$2; shift 2;;
499 --fqdn) utsname=$2; shift 2;;
500 --) shift 1; break ;;
501 *) break ;;
502 esac
503done
504
505if [ ! -z "$clean" -a -z "$path" ]; then
506 clean || exit 1
507 exit 0
508fi
509
510if [ -z "${utsname}" ]; then
511 utsname=${name}
512fi
513
514# This follows a standard "resolver" convention that an FQDN must have
515# at least two dots or it is considered a local relative host name.
516# If it doesn't, append the dns domain name of the host system.
517#
518# This changes one significant behavior when running
519# "lxc_create -n Container_Name" without using the
520# --fqdn option.
521#
522# Old behavior:
523# utsname and hostname = Container_Name
524# New behavior:
525# utsname and hostname = Container_Name.Domain_Name
526
527if [ $(expr "$utsname" : '.*\..*\.') = 0 ]; then
528 if [ -n "$(dnsdomainname)" ]; then
529 utsname=${utsname}.$(dnsdomainname)
530 fi
531fi
532
533type yum >/dev/null 2>&1
534if [ $? -ne 0 ]; then
535 echo "'yum' command is missing"
536 exit 1
537fi
538
539if [ -z "$path" ]; then
540 path=$default_path/$name
541fi
542
543if [ -z "$release" ]; then
544 if [ "$is_centos" -a "$centos_host_ver" ]; then
545 release=$centos_host_ver
546 else
547 echo "This is not a centos host and release missing, defaulting to 6 use -R|--release to specify release"
548 release=6
549 fi
550fi
551
552# CentOS 7 and above should run systemd. We need autodev enabled to keep
553# systemd from causing problems.
554if [ $release -gt 6 ]; then
555 auto_dev="1"
556else
557 auto_dev="0"
558fi
559
560if [ "$(id -u)" != "0" ]; then
561 echo "This script should be run as 'root'"
562 exit 1
563fi
564
565
566if [ -z "$rootfs_path" ]; then
567 rootfs_path=$path/rootfs
568 # check for 'lxc.rootfs' passed in through default config by lxc-create
569 if grep -q '^lxc.rootfs' $path/config 2>/dev/null ; then
570 rootfs_path=`grep 'lxc.rootfs =' $path/config | awk -F= '{ print $2 }'`
571 fi
572fi
573config_path=$default_path/$name
574cache=$cache_base/$release
575
576revert()
577{
578 echo "Interrupted, so cleaning up"
579 lxc-destroy -n $name
580 # maybe was interrupted before copy config
581 rm -rf $path
582 rm -rf $default_path/$name
583 echo "exiting..."
584 exit 1
585}
586
587trap revert SIGHUP SIGINT SIGTERM
588
589copy_configuration
590if [ $? -ne 0 ]; then
591 echo "failed write configuration file"
592 exit 1
593fi
594
595install_centos
596if [ $? -ne 0 ]; then
597 echo "failed to install centos"
598 exit 1
599fi
600
601configure_centos
602if [ $? -ne 0 ]; then
603 echo "failed to configure centos for a container"
604 exit 1
605fi
606
607configure_centos_init
608
609if [ ! -z $clean ]; then
610 clean || exit 1
611 exit 0
612fi
613echo "container rootfs and config created, default root password is '$root_password'"
614echo "edit the config file to check/enable networking setup"