[prev in list] [next in list] [prev in thread] [next in thread] 

List:       centos-virt
Subject:    [CentOS-virt] "lxc-centos" container automation script
From:       Johannes Graumann <johannes_graumann () web ! de>
Date:       2013-09-03 10:51:01
Message-ID: l04ets$llr$1 () ger ! gmane ! org
[Download RAW message or body]

Hello,

For me as a debianista who has need to run some software (Kolab) in the 
vendor(provider)-supported OS (CentOS), LXC is a godsend. However, lxc 
distributions I am aware of do not ship the "lxc-fedora" or "lxc-debian" 
equivalent to construct a container.
I have thus set out to modify the former (please find the result attached).

In the process of getting that to work yum/rpm presents me with the 
following errors:

Installing     : filesystem-2.4.30-3.el6.x86_64                                                           \
 3/128 
  warning: group lock does not exist - using root
  warning: group mail does not exist - using root

Installing     : sysvinit-tools-2.87-4.dsf.el6.x86_64                                                     \
 47/128 
  warning: group tty does not exist - using root

Installing     : libutempter-1.1.5-4.1.el6.x86_64                                                         \
 59/128 
  warning: group utempter does not exist - using root
  warning: group utmp does not exist - using root

Installing     : util-linux-ng-2.17.2-12.9.el6_4.3.x86_64                                                 \
 121/128 
warning: group tty does not exist - using root

Installing     : initscripts-9.03.38-1.el6.centos.2.x86_64                                                \
 122/128 
  chmod: cannot access `/var/lib/random-seed': No such file or directory
  Non-fatal POSTIN scriptlet failure in rpm package 
initscripts-9.03.38-1.el6.centos.2.x86_64
  warning: %post(initscripts-9.03.38-1.el6.centos.2.x86_64) scriptlet 
failed, exit status 1

I was wondering whether anyone here could advise on how to circumvent these 
issues. Optimally I'd like to prevent them (which may not be feasible given 
the "chroot" nature of the install). How to fix this from within a running 
container would also be most welcome information  ...

Thank you for your consideration.

Sincerely, Joh


["lxc-centos" (application/x-shellscript)]

#!/bin/bash

#
# template script for generating CentOS container for LXC
#

#
# lxc: linux Container library

# Authors:
# Daniel Lezcano <daniel.lezcano@free.fr>
# Ramez Hanna <rhanna@informatiq.org>

# This library is free software; you can redistribute it and/or
# 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
arch=$(arch)
cache_base=/var/cache/lxc/centos/$arch
default_path=/var/lib/lxc
root_password=root

# is this centos?
[ -f /etc/centos-release ] && is_centos=true

if [ "$arch" = "i686" ]; then
    arch=i386
fi
if [ "$arch" = "amd64" ]; then
    arch=x86_64
fi
if [ "$arch" = "x86_64" ]; then
    arch=x86_64
fi

configure_centos()
{

    # disable selinux in centos
    mkdir -p $rootfs_path/selinux
    echo 0 > $rootfs_path/selinux/enforce

   # configure the network using the dhcp
    cat <<EOF > ${rootfs_path}/etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth0
BOOTPROTO=dhcp
ONBOOT=yes
HOSTNAME=${name}
NM_CONTROLLED=no
TYPE=Ethernet
MTU=${MTU}
EOF

    # set the hostname
    cat <<EOF > ${rootfs_path}/etc/sysconfig/network
NETWORKING=yes
HOSTNAME=${name}
EOF

    # set minimal hosts
    cat <<EOF > $rootfs_path/etc/hosts
127.0.0.1 localhost $name
EOF

    dev_path="${rootfs_path}/dev"
    rm -rf $dev_path
    mkdir -p $dev_path
    mknod -m 666 ${dev_path}/null c 1 3
    mknod -m 666 ${dev_path}/zero c 1 5
    mknod -m 666 ${dev_path}/random c 1 8
    mknod -m 666 ${dev_path}/urandom c 1 9
    mkdir -m 755 ${dev_path}/pts
    mkdir -m 1777 ${dev_path}/shm
    mknod -m 666 ${dev_path}/tty c 5 0
    mknod -m 666 ${dev_path}/tty0 c 4 0
    mknod -m 666 ${dev_path}/tty1 c 4 1
    mknod -m 666 ${dev_path}/tty2 c 4 2
    mknod -m 666 ${dev_path}/tty3 c 4 3
    mknod -m 666 ${dev_path}/tty4 c 4 4
    mknod -m 600 ${dev_path}/console c 5 1
    mknod -m 666 ${dev_path}/full c 1 7
    mknod -m 600 ${dev_path}/initctl p
    mknod -m 666 ${dev_path}/ptmx c 5 2

    echo "setting root passwd to $root_password"
    echo "root:$root_password" | chroot $rootfs_path chpasswd

    # specifying this in the initial packages doesn't always work.
    ChrootNetworkUp=$(chroot ${rootfs_path} ping -w5 -c3 www.google.com  > /dev/null 2>&1 && echo "up" || \
echo "down")  case "$ChrootNetworkUp" in
	"down")
          echo "After fixing networking such that 'yum' has access to it, you should run 'yum \
--releaserver=${release} -y install centos-release' in the container."  ;;
	"up")
          echo "installing centos-release package"
    	  chroot ${rootfs_path} yum --releasever=${release} -y install centos-release
          ;;
        *)
          echo "ERROR: Unexpected response to checking the chroot network - aborting."
          exit -1
          ;;
    esac
    # silence some needless startup errors
    touch ${rootfs_path}/etc/fstab

    # give us a console on /dev/console
    sed -i 's/ACTIVE_CONSOLES=.*$/ACTIVE_CONSOLES="\/dev\/console \/dev\/tty[1-4]"/' \
        ${rootfs_path}/etc/sysconfig/init

    return 0
}
configure_centos_init()
{
    sed -i 's|.sbin.start_udev||' ${rootfs_path}/etc/rc.sysinit
    sed -i 's|.sbin.start_udev||' ${rootfs_path}/etc/rc.d/rc.sysinit
    # don't mount devpts, for pete's sake
    sed -i 's/^.*dev.pts.*$/#\0/' ${rootfs_path}/etc/rc.sysinit
    sed -i 's/^.*dev.pts.*$/#\0/' ${rootfs_path}/etc/rc.d/rc.sysinit
    chroot ${rootfs_path} chkconfig udev-post off
    chroot ${rootfs_path} chkconfig network on
}

configure_centos_systemd()
{
    unlink ${rootfs_path}/etc/systemd/system/default.target
    touch ${rootfs_path}/etc/fstab
    chroot ${rootfs_path} ln -s /dev/null //etc/systemd/system/udev.service
    chroot ${rootfs_path} ln -s /lib/systemd/system/multi-user.target /etc/systemd/system/default.target
    #dependency on a device unit fails it specially that we disabled udev
    sed -i 's/After=dev-%i.device/After=/' ${rootfs_path}/lib/systemd/system/getty\@.service
}

download_centos()
{

    # check the mini centos was not already downloaded
    INSTALL_ROOT=$cache/partial
    mkdir -p $INSTALL_ROOT
    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 dhclient chkconfig rootfiles policycoreutils \
centos-release"  MIRRORLIST_URL="http://mirrorlist.centos.org/?release=$release&arch=$arch&repo=os"

    DOWNLOAD_OK=no
    for trynumber in 1 2 3; do
        [ $trynumber != 1 ] && echo "Trying again..."
        MIRROR_URL=$(curl -s -S -f "$MIRRORLIST_URL" | head -n2 | tail -n1)
        if [ $? -ne 0 ] || [ -z "$MIRROR_URL" ]; then
            echo "Failed to get a mirror"
            continue
        fi
	update=$(expr match "$MIRROR_URL" '.*centos/.*\.\(.*\)/os')
	FILES_URL="$MIRROR_URL/Packages/"
        curl -f "$FILES_URL" > $INSTALL_ROOT/filelist-centos-$release.$update.html
	RELEASE_FILE=$(expr match "$(grep centos-release* $INSTALL_ROOT/filelist-centos-$release.$update.html)" \
'.*\(centos-release.*\.rpm\)')  RELEASE_URL="$MIRROR_URL/Packages/$RELEASE_FILE"
        echo "Fetching from $RELEASE_URL"
        curl -f "$RELEASE_URL" > $INSTALL_ROOT/$RELEASE_FILE
        if [ $? -ne 0 ]; then
            echo "Failed to download CentOS release rpm"
            continue
        fi
        DOWNLOAD_OK=yes
        break
    done
    if [ $DOWNLOAD_OK != yes ]; then
        echo "Aborting"
        return 1
    fi

    mkdir -p $INSTALL_ROOT/var/lib/rpm
    rpm --root $INSTALL_ROOT  --initdb
    rpm --root $INSTALL_ROOT -ivh $INSTALL_ROOT/$RELEASE_FILE
    $YUM install $PKG_LIST

    if [ $? -ne 0 ]; then
        echo "Failed to download the rootfs, aborting."
        return 1
    fi

    mv "$INSTALL_ROOT" "$cache/rootfs"
    echo "Download complete."

    return 0
}

copy_centos()
{

    # make a local copy of the minicentos
    echo -n "Copying rootfs to $rootfs_path ..."
    #cp -a $cache/rootfs-$arch $rootfs_path || return 1
    # i prefer rsync (no reason really)
    mkdir -p $rootfs_path
    rsync -Ha $cache/rootfs/ $rootfs_path/
    return 0
}

update_centos()
{
    YUM="yum --installroot $cache/rootfs -y --nogpgcheck"
    $YUM update
}

install_centos()
{
    mkdir -p /var/lock/subsys/
    (
        flock -x 200
        if [ $? -ne 0 ]; then
            echo "Cache repository is busy."
            return 1
        fi

        echo "Checking cache download in $cache/rootfs ... "
        if [ ! -e "$cache/rootfs" ]; then
            download_centos
            if [ $? -ne 0 ]; then
                echo "Failed to download 'CentOS base'"
                return 1
            fi
        else
            echo "Cache found. Updating..."
            update_centos
            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 ... "
        copy_centos
        if [ $? -ne 0 ]; then
            echo "Failed to copy rootfs"
            return 1
        fi

        return 0
    ) 200>/var/lock/subsys/lxc-centos

    return $?
}

copy_configuration()
{

    mkdir -p $config_path
    grep -q "^lxc.rootfs" $config_path/config 2>/dev/null || echo "lxc.rootfs = $rootfs_path" >> \
$config_path/config  cat <<EOF >> $config_path/config
lxc.utsname = $name
lxc.tty = 4
lxc.pts = 1024
lxc.mount = $config_path/fstab

# When using LXC with apparmor, uncomment the next line to run unconfined:
#lxc.aa_profile = unconfined

#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
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..."
        rm --preserve-root --one-file-system -rf $cache && echo "Done." || exit 1
        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.
  -A,--arch         Define what arch the container will be [i686,x86_64]
  -h,--help         print this help
EOF
    return 0
}

options=$(getopt -o hp:n:cR: -l help,path:,name:,clean,release:,arch: -- "$@")
if [ $? -ne 0 ]; then
    usage $(basename $0)
    exit 1
fi
eval set -- "$options"

while true
do
    case "$1" in
        -h|--help)      usage $0 && exit 0;;
        -p|--path)      path=$2; shift 2;;
        -n|--name)      name=$2; shift 2;;
        -c|--clean)     clean=$2; shift 2;;
        -R|--release)   release=$2; shift 2;;
	-A|--arch)	arch=$2; shift 2;;
        --)             shift 1; break ;;
        *)              break ;;
    esac
done

if [ ! -z "$clean" -a -z "$path" ]; then
    clean || exit 1
    exit 0
fi

needed_pkgs=""
type yum >/dev/null 2>&1
if [ $? -ne 0 ]; then
    needed_pkgs="yum $needed_pkgs"
fi

type curl >/dev/null 2>&1
if [ $? -ne 0 ]; then
    needed_pkgs="curl $needed_pkgs"
fi

if [ -n "$needed_pkgs" ]; then
    echo "Missing commands: $needed_pkgs"
    echo "Please install these using \"sudo apt-get install $needed_pkgs\""
    exit 1
fi

if [ -z "$path" ]; then
    path=$default_path
fi

if [ -z "$release" ]; then
    if [ "$is_centos" ]; then
        release=$(cat /etc/centos-release |awk '/^CentOS/ {print $3}')
    else
        echo "This is not a CentOS host and release missing, defaulting to 6. use -R|--release to specify \
release"  release=6
    fi
fi

if [ "$(id -u)" != "0" ]; then
    echo "This script should be run as 'root'"
    exit 1
fi


rootfs_path=$path/$name/rootfs
# check for 'lxc.rootfs' passed in through default config by lxc-create
if grep -q '^lxc.rootfs' $path/config 2>/dev/null ; then
    rootfs_path=`grep 'lxc.rootfs =' $path/config | awk -F= '{ print $2 }'`
fi
config_path=$default_path/$name
cache=$cache_base/$release

revert()
{
    echo "Interrupted, so cleaning up"
    lxc-destroy -n $name
    # maybe was interrupted before copy config
    rm -rf $path
    rm -rf $default_path/$name
    echo "exiting..."
    exit 1
}

trap revert SIGHUP SIGINT SIGTERM

copy_configuration
if [ $? -ne 0 ]; then
    echo "failed write configuration file"
    exit 1
fi

install_centos
if [ $? -ne 0 ]; then
    echo "failed to install centos"
    exit 1
fi

configure_centos
if [ $? -ne 0 ]; then
    echo "failed to configure CentOS for a container"
    exit 1
fi

type /bin/systemd >/dev/null 2>&1
if [ $? -ne 0 ]; then
    configure_centos_init
else
    configure_centos_systemd
fi

if [ ! -z $clean ]; then
    clean || exit 1
    exit 0
fi
echo "container rootfs and config created"



_______________________________________________
CentOS-virt mailing list
CentOS-virt@centos.org
http://lists.centos.org/mailman/listinfo/centos-virt


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic