lxc-centos.in revision 99c2fb07d74c20d0eec38c05c4ac64e5782d8e7d
#
# template script for generating centos container for LXC
#
# lxc: linux Container library
# Authors:
# Daniel Lezcano <daniel.lezcano@free.fr>
# Ramez Hanna <rhanna@informatiq.org>
# Fajar A. Nugraha <github@fajar.net>
# Michael H. Warfield <mhw@WittsEnd.com>
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#Configurations
# We really need something better here!
# is this centos?
# Alow for weird remixes like the Raspberry Pi
#
# Use the Mitre standard CPE identifier for the release ID if possible...
# This may be in /etc/os-release or /etc/system-release-cpe. We
# should be able to use EITHER. Give preference to /etc/os-release for now.
if [ -e /etc/os-release ]
then
# This is a shell friendly configuration file. We can just source it.
# What we're looking for in here is the ID, VERSION_ID and the CPE_NAME
. /etc/os-release
echo "Host CPE ID from /etc/os-release: ${CPE_NAME}"
fi
then
CPE_NAME=$(head -n1 /etc/system-release-cpe)
if [ "${CPE_URI}" != "cpe:/o" ]
then
else
# Probably a better way to do this but sill remain posix
# compatible but this works, shrug...
# Must be nice and not introduce convenient bashisms here.
#
# According to the official registration at Mitre and NIST,
# this should have been something like this for CentOS:
# cpe:/o:centos:centos:6
# or this:
# cpe:/o:centos:centos:6.5
#
# The "enterprise_linux" is a bone toss back to RHEL.
# Since CentOS and RHEL are so tightly coupled, we'll
# take the RHEL version if we're running on it and do the
# equivalent version for CentOS.
then
# Instead we got this: cpe:/o:centos:linux:6
fi
echo "Host CPE ID from /etc/system-release-cpe: ${CPE_NAME}"
fi
fi
if [ "${CPE_NAME}" != "" -a "${ID}" = "centos" -a "${VERSION_ID}" != "" ]
then
is_centos=true
elif [ "${CPE_NAME}" != "" -a "${ID}" = "redhat" -a "${VERSION_ID}" != "" ]
then
is_redhat=true
elif [ -e /etc/centos-release ]
then
# Only if all other methods fail, try to parse the redhat-release file.
centos_host_ver=$( sed -e '/^CentOS /!d' -e 's/CentOS.*\srelease\s*\([0-9][0-9.]*\)\s.*/\1/' < /etc/centos-release )
if [ "$centos_host_ver" != "" ]
then
is_centos=true
fi
fi
# Map a few architectures to their generic Centos repository archs.
#
# CentOS currently doesn't support ARM but it's copied here from
# the Fedora template for completeness and that it will in the future.
#
# The two ARM archs are a bit of a guesstimate for the v5 and v6
# archs. V6 should have hardware floating point (Rasberry Pi).
# The "arm" arch is safer (no hardware floating point). So
# there may be cases where we "get it wrong" for some v6 other
# than RPi.
esac
{
# delete a device node if exists, and create a new one
}
{
# disable selinux in centos
echo 0 > $rootfs_path/selinux/enforce
if [[ -f $rootfs_path/etc/selinux/config ]]
then
fi
# Nice catch from Dwight Engen in the Oracle template.
# Wantonly plagerized here with much appreciation.
if [ -f $rootfs_path/usr/sbin/selinuxenabled ]; then
fi
# This is a known problem and documented in RedHat bugzilla as relating
# to a problem with auditing enabled. This prevents an error in
if [ -f ${rootfs_path}/etc/pam.d/crond ]
then
fi
# In addition to disabling pam_loginuid in the above config files
# we'll also disable it by linking it to pam_permit to catch any
# we missed or any that get installed after the container is built.
#
# Catch either or both 32 and 64 bit archs.
if [ -f ${rootfs_path}/lib/security/pam_loginuid.so ]
then
( cd ${rootfs_path}/lib/security/
)
fi
if [ -f ${rootfs_path}/lib64/security/pam_loginuid.so ]
then
( cd ${rootfs_path}/lib64/security/
)
fi
# Trim it and make it our own and link it in before the default
# halt script so we can intercept it. This also preventions package
# updates from interferring with our interferring with it.
#
# There's generally not much in the halt script that useful but what's
# in there from resetting the hardware clock down is generally very bad.
# So we just eliminate the whole bottom half of that script in making
# ourselves a copy. That way a major update to the init scripts won't
# trash what we've set up.
if [ -f ${rootfs_path}/etc/init.d/halt ]
then
< ${rootfs_path}/etc/init.d/halt \
> ${rootfs_path}/etc/init.d/lxc-halt
chmod 755 ${rootfs_path}/etc/init.d/lxc-halt
# Link them into the rc directories...
(
cd ${rootfs_path}/etc/rc.d/rc0.d
cd ${rootfs_path}/etc/rc.d/rc6.d
)
fi
# configure the network using the dhcp
cat <<EOF > ${rootfs_path}/etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth0
BOOTPROTO=dhcp
ONBOOT=yes
HOSTNAME=${UTSNAME}
NM_CONTROLLED=no
TYPE=Ethernet
MTU=${MTU}
EOF
# set the hostname
cat <<EOF > ${rootfs_path}/etc/sysconfig/network
NETWORKING=yes
HOSTNAME=${UTSNAME}
EOF
# set minimal hosts
cat <<EOF > $rootfs_path/etc/hosts
127.0.0.1 localhost $name
EOF
# set minimal fstab
cat <<EOF > $rootfs_path/etc/fstab
/dev/root / rootfs defaults 0 0
none /dev/shm tmpfs nosuid,nodev 0 0
EOF
# create lxc compatibility init script
cat <<EOF > $rootfs_path/etc/init/lxc-sysinit.conf
start on startup
env container
pre-start script
if [ "x$container" != "xlxc" -a "x$container" != "xlibvirt" ]; then
stop;
fi
initctl start tty TTY=console
rm -f /var/lock/subsys/*
rm -f /var/run/*.pid
telinit 3
exit 0;
end script
EOF
cat <<EOF > $rootfs_path/etc/rc.d/lxc.sysinit
#! /bin/bash
rm -f /etc/mtab /var/run/*.{pid,lock} /var/lock/subsys/*
rm -rf {/,/var}/tmp/*
echo "/dev/root / rootfs defaults 0 0" > /etc/mtab
exit 0
EOF
sed -i 's|si::sysinit:/etc/rc.d/rc.sysinit|si::bootwait:/etc/rc.d/lxc.sysinit|' $rootfs_path/etc/inittab
fi
dev_path="${rootfs_path}/dev"
echo "setting root passwd to $root_password"
# This will need to be enhanced for CentOS 7 when systemd
# comes into play... /\/\|=mhw=|\/\/
return 0
}
{
fi
}
{
# check the mini centos was not already downloaded
if [ $? -ne 0 ]; then
echo "Failed to create '$INSTALL_ROOT' directory"
return 1
fi
# download a mini centos into a cache
echo "Downloading centos minimal ..."
YUM="yum --installroot $INSTALL_ROOT -y --nogpgcheck"
PKG_LIST="yum initscripts passwd rsyslog vim-minimal openssh-server openssh-clients dhclient chkconfig rootfiles policycoreutils"
# use temporary repository definition
mkdir -p $(dirname $REPO_FILE)
cat <<EOF > $REPO_FILE
[base]
name=CentOS-$release - Base
mirrorlist=http://mirrorlist.centos.org/?release=$release&arch=$arch&repo=os
[updates]
name=CentOS-$release - Updates
mirrorlist=http://mirrorlist.centos.org/?release=$release&arch=$arch&repo=updates
EOF
# create minimal device nodes, needed for "yum install" and "yum update" process
force_mknod 666 $INSTALL_ROOT/dev/null c 1 3
force_mknod 666 $INSTALL_ROOT/dev/urandom c 1 9
if [ $? -ne 0 ]; then
echo "Failed to download the rootfs, aborting."
return 1
fi
# use same nameservers as hosts, needed for "yum update later"
# check whether rpmdb is under $HOME
if [ ! -e $INSTALL_ROOT/var/lib/rpm/Packages -a -e $INSTALL_ROOT/$HOME/.rpmdb/Packages ]; then
echo "Fixing rpmdb location ..."
mv $INSTALL_ROOT/$HOME/.rpmdb/[A-Z]* $INSTALL_ROOT/var/lib/rpm/
fi
# check whether rpmdb version is correct
ret=$?
# if "rpm -q" doesn't work due to rpmdb version difference,
# then we need to redo the process using the newly-installed yum
echo "Reinstalling packages ..."
mknod -m 666 $INSTALL_ROOT/$INSTALL_ROOT/dev/null c 1 3
mknod -m 666 $INSTALL_ROOT/$INSTALL_ROOT/dev/urandom c 1 9
if [ $? -ne 0 ]; then
echo "Failed to download the rootfs, aborting."
return 1
fi
fi
rm -f $REPO_FILE
mv "$INSTALL_ROOT" "$cache/rootfs"
echo "Download complete."
return 0
}
{
# make a local copy of the mini centos
echo -n "Copying rootfs to $rootfs_path ..."
# i prefer rsync (no reason really)
rsync -a $cache/rootfs/ $rootfs_path/
return 0
}
{
if [ $? -ne 0 ]; then
return 1
fi
}
{
(
flock -x 200
if [ $? -ne 0 ]; then
echo "Cache repository is busy."
return 1
fi
echo "Checking cache download in $cache/rootfs ... "
if [ $? -ne 0 ]; then
echo "Failed to download 'centos base'"
return 1
fi
else
echo "Cache found. Updating..."
if [ $? -ne 0 ]; then
echo "Failed to update 'centos base', continuing with last known good cache"
else
echo "Update finished"
fi
fi
echo "Copy $cache/rootfs to $rootfs_path ... "
if [ $? -ne 0 ]; then
echo "Failed to copy rootfs"
return 1
fi
return 0
) 200>/var/lock/subsys/lxc-centos
return $?
}
{
cat <<EOF >> $config_path/config
lxc.utsname = $utsname
lxc.tty = 4
lxc.pts = 1024
lxc.rootfs = $rootfs_path
lxc.mount = $config_path/fstab
lxc.cap.drop = sys_module mac_admin mac_override sys_time
lxc.autodev = $auto_dev
# example simple networking setup, uncomment to enable
#lxc.network.type = $lxc_network_type
#lxc.network.flags = up
#lxc.network.link = $lxc_network_link
#lxc.network.name = eth0
# additional example for veth network type, static MAC address,
# and persistent veth device name on host side
#lxc.network.hwaddr = 00:16:3e:77:52:20
#lxc.network.veth.pair = v-$name-e0
#cgroups
lxc.cgroup.devices.deny = a
# /dev/null and zero
lxc.cgroup.devices.allow = c 1:3 rwm
lxc.cgroup.devices.allow = c 1:5 rwm
# consoles
lxc.cgroup.devices.allow = c 5:1 rwm
lxc.cgroup.devices.allow = c 5:0 rwm
lxc.cgroup.devices.allow = c 4:0 rwm
lxc.cgroup.devices.allow = c 4:1 rwm
# /dev/{,u}random
lxc.cgroup.devices.allow = c 1:9 rwm
lxc.cgroup.devices.allow = c 1:8 rwm
lxc.cgroup.devices.allow = c 136:* rwm
lxc.cgroup.devices.allow = c 5:2 rwm
# rtc
lxc.cgroup.devices.allow = c 254:0 rwm
EOF
cat <<EOF > $config_path/fstab
proc proc proc nodev,noexec,nosuid 0 0
devpts dev/pts devpts defaults 0 0
sysfs sys sysfs defaults 0 0
EOF
if [ $? -ne 0 ]; then
echo "Failed to add configuration"
return 1
fi
return 0
}
clean()
{
if [ ! -e $cache ]; then
exit 0
fi
# lock, so we won't purge while someone is creating a repository
(
flock -x 200
if [ $? != 0 ]; then
echo "Cache repository is busy."
exit 1
fi
echo -n "Purging the download cache for centos-$release..."
exit 0
) 200>/var/lock/subsys/lxc-centos
}
usage()
{
cat <<EOF
usage:
$1 -n|--name=<container_name>
[-p|--path=<path>] [-c|--clean] [-R|--release=<CentOS_release>] [-A|--arch=<arch of the container>]
[-h|--help]
Mandatory args:
-n,--name container name, used to as an identifier for that container from now on
Optional args:
-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
-c,--clean clean the cache
-R,--release Centos release for the new container. if the host is Centos, then it will defaultto the host's release.
--fqdn fully qualified domain name (FQDN) for DNS and system naming
-A,--arch NOT USED YET. Define what arch the container will be [i686,x86_64]
-h,--help print this help
EOF
return 0
}
if [ $? -ne 0 ]; then
exit 1
fi
eval set -- "$options"
while true
do
case "$1" in
--) shift 1; break ;;
*) break ;;
esac
done
clean || exit 1
exit 0
fi
if [ -z "${utsname}" ]; then
fi
# This follows a standard "resolver" convention that an FQDN must have
# at least two dots or it is considered a local relative host name.
# If it doesn't, append the dns domain name of the host system.
#
# This changes one significant behavior when running
# "lxc_create -n Container_Name" without using the
# --fqdn option.
#
# Old behavior:
# utsname and hostname = Container_Name
# New behavior:
# utsname and hostname = Container_Name.Domain_Name
fi
fi
if [ $? -ne 0 ]; then
echo "'yum' command is missing"
exit 1
fi
if [ -z "$path" ]; then
fi
if [ -z "$release" ]; then
if [ "$is_centos" -a "$centos_host_ver" ]; then
elif [ "$is_redhat" -a "$redhat_host_ver" ]; then
# This is needed to clean out bullshit like 6workstation and 6server.
else
echo "This is not a CentOS or Redhat host and release is missing, defaulting to 6 use -R|--release to specify release"
release=6
fi
fi
# CentOS 7 and above should run systemd. We need autodev enabled to keep
# systemd from causing problems.
#
# There is some ambiguity here due to the differnce between versioning
# of point specific releases such as 6.5 and the rolling release 6. We
# only want the major number here if it's a point release...
auto_dev="1"
else
auto_dev="0"
fi
echo "This script should be run as 'root'"
exit 1
fi
if [ -z "$rootfs_path" ]; then
# check for 'lxc.rootfs' passed in through default config by lxc-create
fi
fi
revert()
{
echo "Interrupted, so cleaning up"
# maybe was interrupted before copy config
echo "exiting..."
exit 1
}
if [ $? -ne 0 ]; then
echo "failed write configuration file"
exit 1
fi
if [ $? -ne 0 ]; then
echo "failed to install centos"
exit 1
fi
if [ $? -ne 0 ]; then
echo "failed to configure centos for a container"
exit 1
fi
if [ ! -z $clean ]; then
clean || exit 1
exit 0
fi
echo "container rootfs and config created, default root password is '$root_password'"