[lxc-devel] [PATCH] add yum plugin to repatch rootfs on yum update

Serge Hallyn serge.hallyn at ubuntu.com
Sat Mar 29 15:36:34 UTC 2014


Quoting Dwight Engen (dwight.engen at oracle.com):
> oracle-template: Split patching rootfs vs one time setup into separate
> shell functions so the template can be run with --patch.
> 
> oracle-template: Update to install the yum plugin and itself (as lxc-patch)
> into a container. The plugin just runs lxc-patch --patch <path> so it is
> fairly generic, but in this case it is running a copy of the template inside
> the container.
> 
> Signed-off-by: Dwight Engen <dwight.engen at oracle.com>

Neat :)

Acked-by: Serge E. Hallyn <serge.hallyn at ubuntu.com>

> ---
>  config/Makefile.am      |   2 +-
>  config/yum/Makefile.am  |   6 ++
>  config/yum/lxc-patch.py |  56 +++++++++++++
>  configure.ac            |   1 +
>  templates/lxc-oracle.in | 205 +++++++++++++++++++++++++++++++-----------------
>  5 files changed, 197 insertions(+), 73 deletions(-)
>  create mode 100644 config/yum/Makefile.am
>  create mode 100644 config/yum/lxc-patch.py
> 
> diff --git a/config/Makefile.am b/config/Makefile.am
> index 9515965..e40f842 100644
> --- a/config/Makefile.am
> +++ b/config/Makefile.am
> @@ -1 +1 @@
> -SUBDIRS = apparmor bash etc init templates
> +SUBDIRS = apparmor bash etc init templates yum
> diff --git a/config/yum/Makefile.am b/config/yum/Makefile.am
> new file mode 100644
> index 0000000..fb9c3bd
> --- /dev/null
> +++ b/config/yum/Makefile.am
> @@ -0,0 +1,6 @@
> +yumpluginsdir=$(datadir)/lxc
> +
> +yumplugins_SCRIPTS = \
> +	lxc-patch.py
> +
> +EXTRA_DIST = $(yumplugins_SCRIPTS)
> diff --git a/config/yum/lxc-patch.py b/config/yum/lxc-patch.py
> new file mode 100644
> index 0000000..94854f4
> --- /dev/null
> +++ b/config/yum/lxc-patch.py
> @@ -0,0 +1,56 @@
> +# Yum plugin to re-patch container rootfs after a yum update is done
> +#
> +# Copyright (C) 2012 Oracle
> +#
> +# Authors:
> +# Dwight Engen <dwight.engen at oracle.com>
> +#
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 2 of the License, or
> +# (at your option) any later version.
> +#
> +# This program 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 Library General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program; if not, write to the Free Software
> +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
> +#
> +
> +import os
> +from fnmatch import fnmatch
> +from yum.plugins import TYPE_INTERACTIVE
> +from yum.plugins import PluginYumExit
> +
> +requires_api_version = '2.0'
> +plugin_type = (TYPE_INTERACTIVE,)
> +
> +def posttrans_hook(conduit):
> +    pkgs = []
> +    patch_required = False
> +
> +    # If we aren't root, we can't have updated anything
> +    if os.geteuid():
> +        return
> +
> +    # See what packages have files that were patched
> +    confpkgs = conduit.confString('main', 'packages')
> +    if not confpkgs:
> +        return
> +
> +    tmp = confpkgs.split(",")
> +    for confpkg in tmp:
> +        pkgs.append(confpkg.strip())
> +
> +    conduit.info(2, "lxc-patch: checking if updated pkgs need patching...")
> +    ts = conduit.getTsInfo()
> +    for tsmem in ts.getMembers():
> +        for pkg in pkgs:
> +            if fnmatch(pkg, tsmem.po.name):
> +                patch_required = True
> +    if patch_required:
> +        conduit.info(2, "lxc-patch: patching container...")
> +        os.spawnlp(os.P_WAIT, "lxc-patch", "lxc-patch", "--patch", "/")
> diff --git a/configure.ac b/configure.ac
> index 20d409f..ee49386 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -587,6 +587,7 @@ AC_CONFIG_FILES([
>  	config/templates/ubuntu.common.conf
>  	config/templates/ubuntu.lucid.conf
>  	config/templates/ubuntu.userns.conf
> +	config/yum/Makefile
>  
>  	doc/Makefile
>  	doc/api/Makefile
> diff --git a/templates/lxc-oracle.in b/templates/lxc-oracle.in
> index a82b81f..92361f8 100644
> --- a/templates/lxc-oracle.in
> +++ b/templates/lxc-oracle.in
> @@ -69,9 +69,44 @@ can_chcon()
>  }
>  
>  # fix up the container_rootfs
> -container_rootfs_configure()
> +container_rootfs_patch()
>  {
> -    echo "Configuring container for Oracle Linux $container_release_major.$container_release_minor"
> +    echo "Patching container rootfs $container_rootfs for Oracle Linux $container_release_major.$container_release_minor"
> +
> +    # copy ourself into the container to be used to --patch the rootfs when
> +    # yum update on certain packages is done. we do this here instead of in
> +    # container_rootfs_configure() in case the patching done in this function
> +    # is updated in the future, we can inject the updated version of ourself
> +    # into older containers.
> +    if [ $container_rootfs != "/" ]; then
> +        cp -f `readlink -f $0` $container_rootfs/usr/bin/lxc-patch
> +        if [ $container_release_major -lt "6" ]; then
> +            mkdir -p $container_rootfs/usr/lib/yum-plugins
> +            cp @DATADIR@/lxc/lxc-patch.py $container_rootfs/usr/lib/yum-plugins
> +        fi
> +        if [ $container_release_major = "6" ]; then
> +            mkdir -p $container_rootfs/usr/share/yum-plugins
> +            cp @DATADIR@/lxc/lxc-patch.py $container_rootfs/usr/share/yum-plugins
> +        fi
> +        mkdir -p $container_rootfs/etc/yum/pluginconf.d
> +        cat <<EOF > $container_rootfs/etc/yum/pluginconf.d/lxc-patch.conf
> +[main]
> +enabled=1
> +packages=initscripts,iptables,selinux-policy,readahead,udev,util-linux-ng
> +EOF
> +    fi
> +
> +    if [ $container_release_major = "4" ]; then
> +        # yum plugin type of TYPE_INTERFACE works in all releases but gives a
> +        # deprecation warning on major > 4, so we default to TYPE_INTERACTIVE
> +        # and fix it up here
> +        sed -i 's|TYPE_INTERACTIVE|TYPE_INTERFACE|' $container_rootfs/usr/lib/yum-plugins/lxc-patch.py
> +        if [ -f $container_rootfs/etc/yum.repos.d/ULN-Base.repo ]; then
> +            mv $container_rootfs/etc/yum.repos.d/ULN-Base.repo \
> +               $container_rootfs/etc/yum.repos.d/ULN-Base.repo.lxc-disabled
> +        fi
> +        echo "plugins = 1" >>$container_rootfs/etc/yum.conf
> +    fi
>  
>      # "disable" selinux in the guest. The policy in the container isn't
>      # likely to match the hosts (unless host == guest exactly) and the
> @@ -114,48 +149,26 @@ container_rootfs_configure()
>          sed -i 's|session[ \t]*required[ \t]*/lib/security/\$ISA/pam_limits.so|#session required /lib/security/$ISA/pam_limits.so|' $container_rootfs/etc/pam.d/system-auth
>      fi
>  
> -    # configure the network to use dhcp. we set DHCP_HOSTNAME so the guest
> -    # will report its name and be resolv'able by the hosts dnsmasq
> -    cat <<EOF > $container_rootfs/etc/sysconfig/network-scripts/ifcfg-eth0
> -DEVICE=eth0
> -BOOTPROTO=dhcp
> -ONBOOT=yes
> -HOSTNAME=$name
> -DHCP_HOSTNAME=$name
> -NM_CONTROLLED=no
> -TYPE=Ethernet
> -EOF
> -
>      # avoid error in ol5 attempting to copy non-existent resolv.conf
>      if [ $container_release_major = "5" ]; then
>          sed -i 's|resolv.conf.predhclient|resolv.conf.predhclient 2>/dev/null|' $container_rootfs/sbin/dhclient-script
>      fi
>  
> -    # set the hostname
> -    cat <<EOF > $container_rootfs/etc/sysconfig/network
> -NETWORKING=yes
> -NETWORKING_IPV6=no
> -HOSTNAME=$name
> -EOF
> -
>      # disable interactive ovmd asking questions
>      if [ -f $container_rootfs/etc/sysconfig/ovmd ]; then
>          sed -i 's|INITIAL_CONFIG=yes|INITIAL_CONFIG=no|' $container_rootfs/etc/sysconfig/ovmd
>      fi
>  
> -    # set minimal hosts
> -    echo "127.0.0.1 localhost $name" > $container_rootfs/etc/hosts
> +    # disable disabling of ipv4 forwarding and defrag on shutdown since
> +    # we mount /proc/sys ro
> +    if [ $container_release_major = "5" ]; then
> +        sed -i 's|-f /proc/sys/net/ipv4/ip_forward|-w /proc/sys/net/ipv4/ip_forward|' $container_rootfs/etc/rc.d/init.d/network
> +        sed -i 's|-f /proc/sys/net/ipv4/ip_always_defrag|-w /proc/sys/net/ipv4/ip_always_defrag|' $container_rootfs/etc/rc.d/init.d/network
> +    fi
>  
>      # disable ipv6 on ol6
>      rm -f $container_rootfs/etc/sysconfig/network-scripts/init.ipv6-global
>  
> -    # this file has to exist for libvirt/Virtual machine monitor to boot the container
> -    touch $container_rootfs/etc/mtab
> -
> -    # don't put devpts,proc, nor sysfs in here, it will already be mounted for us by lxc/libvirt
> -    cat <<EOF > $container_rootfs/etc/fstab
> -EOF
> -
>      # remove module stuff for iptables it just shows errors that are not
>      # relevant in a container
>      if [ -f "$container_rootfs/etc/sysconfig/iptables-config" ]; then
> @@ -182,17 +195,6 @@ EOF
>          sed -i 's|action $"Setting network parameters|# LXC action $"Setting network parameters|' $container_rootfs/etc/init.d/NetworkManager 2>/dev/null
>      fi
>  
> -    # sem_open(3) checks that /dev/shm is SHMFS_SUPER_MAGIC, so make sure to mount /dev/shm (normally done by dracut initrd) as tmpfs
> -    if [ $container_release_major = "4" -o $container_release_major = "5" ]; then
> -        echo "mount -t tmpfs tmpfs /dev/shm" >>$container_rootfs/etc/rc.sysinit
> -        echo "mount -t tmpfs tmpfs /dev/shm" >>$container_rootfs/etc/rc.d/rc.sysinit
> -    fi
> -
> -    if [ $container_release_major = "6" ]; then
> -        sed -i 's|mount -n -o remount /dev/shm >/dev/null 2>&1$|mount -t tmpfs tmpfs /dev/shm # LXC|' $container_rootfs/etc/rc.sysinit
> -        sed -i 's|mount -n -o remount /dev/shm >/dev/null 2>&1$|mount -t tmpfs tmpfs /dev/shm # LXC|' $container_rootfs/etc/rc.d/rc.sysinit
> -    fi
> -
>      # no need to attempt to mount /
>      sed -i 's|mount -f /$|# LXC mount -f /|' $container_rootfs/etc/rc.sysinit
>      sed -i 's|mount -f /$|# LXC mount -f /|' $container_rootfs/etc/rc.d/rc.sysinit
> @@ -231,8 +233,12 @@ EOF
>      sed -i 's|^/sbin/hwclock|# LXC /sbin/nohwclock|' $container_rootfs/etc/rc.d/rc.sysinit
>  
>      # dont start lvm
> -    sed -i 's|action $"Setting up Logical Volume Management:"|#action $"Setting up Logical Volume Management:"|' $container_rootfs/etc/rc.sysinit
> -    sed -i 's|action $"Setting up Logical Volume Management:"|/bin/true #action $"Setting up Logical Volume Management:"|' $container_rootfs/etc/rc.d/rc.sysinit
> +    if [ $container_release_major -lt "6" -a -f $container_rootfs/sbin/lvm.static ]; then
> +        mv $container_rootfs/sbin/lvm.static $container_rootfs/sbin/lvm.static.lxc-disabled
> +    fi
> +    if [ $container_release_major = "6" ]; then
> +        touch $container_rootfs/.nolvm
> +    fi
>  
>      # fix assumptions that plymouth is available
>      sed -i 's|\[ "$PROMPT" != no \] && plymouth|[ "$PROMPT" != no ] \&\& [ -n "$PLYMOUTH" ] \&\& plymouth|' $container_rootfs/etc/rc.sysinit
> @@ -241,6 +247,80 @@ EOF
>      rm -f $container_rootfs/etc/init/quit-plymouth.conf
>      rm -f $container_rootfs/etc/init/splash-manager.conf
>  
> +    # dont try to unmount /dev/lxc devices
> +    sed -i 's|&& $1 !~ /^\\/dev\\/ram/|\&\& $2 !~ /^\\/dev\\/lxc/ \&\& $1 !~ /^\\/dev\\/ram/|' $container_rootfs/etc/init.d/halt
> +
> +    # don't try to unmount swap
> +    sed -i 's|\[ -f /proc/swaps \]|# LXC [ -f /proc/swaps ]|' $container_rootfs/etc/init.d/halt
> +
> +    # there might be other services that are useless but the below set is a good start
> +    # some of these might not exist in the image, so we silence chkconfig complaining
> +    # about the service file not being found
> +    for service in \
> +        acpid apmd auditd autofs cpuspeed dund gpm haldaemon hidd	\
> +        ip6tables irqbalance iscsi iscsid isdn kdump kudzu		\
> +        lm_sensors lvm2-monitor mdmonitor microcode_ctl			\
> +        ntpd pcmcia postfix sendmail udev-post xfs ;
> +    do
> +        chroot $container_rootfs chkconfig 2>/dev/null $service off
> +    done
> +
> +    for service in rsyslog ;
> +    do
> +        chroot $container_rootfs chkconfig 2>/dev/null $service on
> +    done
> +
> +    # ensure /dev/ptmx refers to the newinstance devpts of the container, or
> +    # pty's will get crossed up with the hosts (https://lkml.org/lkml/2012/1/23/512)
> +    rm -f $container_rootfs/dev/ptmx
> +    ln -s pts/ptmx $container_rootfs/dev/ptmx
> +}
> +
> +container_rootfs_configure()
> +{
> +    container_rootfs_patch
> +    echo "Configuring container for Oracle Linux $container_release_major.$container_release_minor"
> +
> +    # configure the network to use dhcp. we set DHCP_HOSTNAME so the guest
> +    # will report its name and be resolv'able by the hosts dnsmasq
> +    cat <<EOF > $container_rootfs/etc/sysconfig/network-scripts/ifcfg-eth0
> +DEVICE=eth0
> +BOOTPROTO=dhcp
> +ONBOOT=yes
> +HOSTNAME=$name
> +DHCP_HOSTNAME=$name
> +NM_CONTROLLED=no
> +TYPE=Ethernet
> +EOF
> +
> +    # set the hostname
> +    cat <<EOF > $container_rootfs/etc/sysconfig/network
> +NETWORKING=yes
> +NETWORKING_IPV6=no
> +HOSTNAME=$name
> +EOF
> +
> +    # set minimal hosts
> +    echo "127.0.0.1 localhost $name" > $container_rootfs/etc/hosts
> +
> +    # this file has to exist for libvirt/Virtual machine monitor to boot the container
> +    touch $container_rootfs/etc/mtab
> +
> +    # don't put devpts,proc, nor sysfs in here, it will already be mounted for us by lxc/libvirt
> +    cat <<EOF > $container_rootfs/etc/fstab
> +EOF
> +
> +    # sem_open(3) checks that /dev/shm is SHMFS_SUPER_MAGIC, so make sure to mount /dev/shm (normally done by dracut initrd) as tmpfs
> +    if [ $container_release_major = "4" -o $container_release_major = "5" ]; then
> +        echo "mount -t tmpfs tmpfs /dev/shm" >>$container_rootfs/etc/rc.sysinit
> +        echo "mount -t tmpfs tmpfs /dev/shm" >>$container_rootfs/etc/rc.d/rc.sysinit
> +    fi
> +
> +    if [ $container_release_major = "6" ]; then
> +        sed -i 's|mount -n -o remount /dev/shm >/dev/null 2>&1$|mount -t tmpfs tmpfs /dev/shm # LXC|' $container_rootfs/etc/rc.sysinit
> +        sed -i 's|mount -n -o remount /dev/shm >/dev/null 2>&1$|mount -t tmpfs tmpfs /dev/shm # LXC|' $container_rootfs/etc/rc.d/rc.sysinit
> +    fi
> +
>      # setup console and tty[1-4] for login. note that /dev/console and
>      # /dev/tty[1-4] will be symlinks to the ptys /dev/lxc/console and
>      # /dev/lxc/tty[1-4] so that package updates can overwrite the symlinks.
> @@ -262,12 +342,6 @@ EOF
>          sed -i 's|mingetty|mingetty --nohangup|' $container_rootfs/etc/init/tty.conf
>      fi
>  
> -    # dont try to unmount /dev/lxc devices
> -    sed -i 's|&& $1 !~ /^\\/dev\\/ram/|\&\& $2 !~ /^\\/dev\\/lxc/ \&\& $1 !~ /^\\/dev\\/ram/|' $container_rootfs/etc/init.d/halt
> -
> -    # don't try to unmount swap
> -    sed -i 's|\[ -f /proc/swaps \]|# LXC [ -f /proc/swaps ]|' $container_rootfs/etc/init.d/halt
> -
>      # start a getty on /dev/console, /dev/tty[1-4]
>      if [ $container_release_major = "4" -o $container_release_major = "5" ]; then
>          sed -i 's|mingetty|mingetty --nohangup|' $container_rootfs/etc/inittab
> @@ -312,23 +386,6 @@ exec init 0
>  EOF
>      fi
>  
> -    # there might be other services that are useless but the below set is a good start
> -    # some of these might not exist in the image, so we silence chkconfig complaining
> -    # about the service file not being found
> -    for service in \
> -        acpid apmd auditd autofs cpuspeed dund gpm haldaemon hidd	\
> -        ip6tables irqbalance iscsi iscsid isdn kdump kudzu		\
> -        lm_sensors lvm2-monitor mdmonitor microcode_ctl			\
> -        ntpd pcmcia postfix sendmail udev-post xfs ;
> -    do
> -        chroot $container_rootfs chkconfig 2>/dev/null $service off
> -    done
> -
> -    for service in rsyslog ;
> -    do
> -        chroot $container_rootfs chkconfig 2>/dev/null $service on
> -    done
> -
>      # create required devices. note that /dev/console will be created by lxc
>      # or libvirt itself to be a symlink to the right pty.
>      # take care to not nuke /dev in case $container_rootfs isn't set
> @@ -365,11 +422,6 @@ EOF
>          done
>      fi
>  
> -    # ensure /dev/ptmx refers to the newinstance devpts of the container, or
> -    # pty's will get crossed up with the hosts (https://lkml.org/lkml/2012/1/23/512)
> -    rm -f $container_rootfs/dev/ptmx
> -    ln -s pts/ptmx $container_rootfs/dev/ptmx
> -
>      # start with a clean /var/log/messages
>      rm -f $container_rootfs/var/log/messages
>  
> @@ -631,6 +683,7 @@ usage()
>    -r|--rpms=<rpm name>    additional rpms to install into container
>    -u|--url=<url>          replace yum repo url (ie. local yum mirror)
>    -t|--templatefs=<path>  copy/clone rootfs at path instead of downloading
> +  -P|--patch=<path>       only patch the rootfs at path for use as a container
>    -h|--help
>  
>  Release is of the format "major.minor", for example "5.8", "6.3", or "6.latest"
> @@ -638,7 +691,7 @@ EOF
>      return 0
>  }
>  
> -options=$(getopt -o hp:n:a:R:r:u:t: -l help,rootfs:,path:,name:,arch:,release:,rpms:,url:,templatefs: -- "$@")
> +options=$(getopt -o hp:n:a:R:r:u:t: -l help,rootfs:,path:,name:,arch:,release:,rpms:,url:,templatefs:,patch: -- "$@")
>  if [ $? -ne 0 ]; then
>      usage $(basename $0)
>      exit 1
> @@ -658,6 +711,7 @@ do
>          -r|--rpms)		user_pkgs=$2; shift 2;;
>          -u|--url)		repourl=$2; shift 2;;
>          -t|--templatefs)	template_rootfs=$2; shift 2;;
> +        --patch)		patch_rootfs=$2; shift 2;;
>          --)             	shift 1; break ;;
>          *)              	break ;;
>      esac
> @@ -669,6 +723,13 @@ if [ "$(id -u)" != "0" ]; then
>      exit 1
>  fi
>  
> +if [ -n "$patch_rootfs" ]; then
> +    container_rootfs="$patch_rootfs"
> +    container_release_get $container_rootfs
> +    container_rootfs_patch
> +    exit 0
> +fi
> +
>  if [ -z $name ]; then
>      echo "Container name must be given"
>      usage
> -- 
> 1.8.5.3
> 
> _______________________________________________
> lxc-devel mailing list
> lxc-devel at lists.linuxcontainers.org
> http://lists.linuxcontainers.org/listinfo/lxc-devel


More information about the lxc-devel mailing list