[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