[lxc-devel] [lxc/master] [RFC] New fedora-cloud container template

ganto on Github lxc-bot at linuxcontainers.org
Sat Dec 24 01:44:12 UTC 2016


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 1610 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20161224/b47c5217/attachment.bin>
-------------- next part --------------
From bff195aecc37dd6e18e0e96c0635947ea36a25dc Mon Sep 17 00:00:00 2001
From: Reto Gantenbein <reto.gantenbein at linuxmonk.ch>
Date: Sat, 24 Dec 2016 01:55:02 +0100
Subject: [PATCH] New fedora-cloud container template

---
 templates/lxc-fedora-cloud.in | 513 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 513 insertions(+)
 create mode 100644 templates/lxc-fedora-cloud.in

diff --git a/templates/lxc-fedora-cloud.in b/templates/lxc-fedora-cloud.in
new file mode 100644
index 0000000..af5b5f0
--- /dev/null
+++ b/templates/lxc-fedora-cloud.in
@@ -0,0 +1,513 @@
+#!/bin/bash
+
+#
+# template script for generating Fedora Cloud container for LXC
+#
+
+#
+# lxc: linux Container library
+
+# Authors:
+# Daniel Lezcano <daniel.lezcano at free.fr>
+# Ramez Hanna <rhanna at informatiq.org>
+# Michael H. Warfield <mhw at WittsEnd.com>
+# Reto Gantenbein <reto.gantenbein at linuxmonk.ch>
+
+# 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+set -e
+
+# configurations
+FEDORA_RELEASE_MIN=24
+FEDORA_RELEASE_DEFAULT=${FEDORA_RELEASE_DEFAULT:-25}
+MIRROR=${MIRROR:-https://archives.fedoraproject.org/pub}
+
+local_state_dir="@LOCALSTATEDIR@"
+lxc_path="@LXCPATH@"
+lxc_template_config="@LXCTEMPLATECONFIG@"
+lxc_default_conf="@LXC_DEFAULT_CONFIG@"
+
+# allows the lxc-cache directory to be set by environment variable
+LXC_CACHE_PATH="${LXC_CACHE_PATH:-"${local_state_dir}/cache/lxc"}"
+
+# these are only going into comments in the resulting config...
+lxc_network_type=veth
+lxc_network_link=lxcbr0
+
+# detect use under userns (unsupported)
+for arg in "$@"; do
+    [ "${arg}" = "--" ] && break
+    if [ "${arg}" = "--mapped-uid" ] || [ "${arg}" = "--mapped-gid" ]
+    then
+        echo "This template can't be used for unprivileged containers." 1>&2
+        echo "You may want to try the \"download\" template instead." 1>&2
+        exit 1
+    fi
+done
+
+# make sure the usual locations are in PATH
+export PATH=${PATH}:/usr/sbin:/usr/bin:/sbin:/bin
+
+# Is this fedora?
+# Allow 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
+
+if [ "${CPE_NAME}" = "" ] && [ -e /etc/system-release-cpe ]
+then
+    CPE_NAME=$(head -n1 /etc/system-release-cpe)
+    CPE_URI=$(expr "${CPE_NAME}" : '\([^:]*:[^:]*\)')
+    if [ "${CPE_URI}" != "cpe:/o" ]
+    then
+        CPE_NAME=
+    else
+        echo "Host CPE ID from /etc/system-release-cpe: ${CPE_NAME}"
+        # 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.
+        ID=$(expr "${CPE_NAME}" : '[^:]*:[^:]*:[^:]*:\([^:]*\)')
+        VERSION_ID=$(expr "${CPE_NAME}" : '[^:]*:[^:]*:[^:]*:[^:]*:\([^:]*\)')
+    fi
+fi
+
+if [ "${CPE_NAME}" != "" ] && [ "${ID}" = "fedora" ] && [ "${VERSION_ID}" != "" ]
+then
+    fedora_host_ver="${VERSION_ID}"
+    is_fedora=true
+elif [ -e /etc/redhat-release ]
+then
+    # Only if all other methods fail, try to parse the redhat-release file.
+    fedora_host_ver=$( sed -e '/^Fedora /!d' -e 's/Fedora.*\srelease\s*\([0-9][0-9]*\)\s.*/\1/' < /etc/redhat-release )
+    if [ "${fedora_host_ver}" != "" ]
+    then
+        is_fedora=true
+    fi
+fi
+
+clean()
+{
+    if [ ! -e "${cache}" ]
+    then
+        return 0
+    fi
+
+    # lock, so we won't purge while someone is creating a repository
+    (
+        if ! flock -x 9
+        then
+            echo "Error: Cache repository is busy."
+            exit 1
+        fi
+
+        echo -n "Purging the download cache for Fedora ${release} ..."
+        rm --preserve-root --one-file-system -rf "${cache}" && echo "Done." || exit 1
+
+        exit 0
+
+    ) 9>"${local_state_dir}/lock/subsys/$(basename "${0}")"
+}
+
+configure_fedora()
+{
+    local rootfs=${rootfs}
+    local release=${release}
+    local utsname=${utsname}
+
+    # disable selinux
+    mkdir -p "${rootfs}/selinux"
+    echo 0 > "${rootfs}/selinux/enforce"
+
+    # also kill it in the /etc/selinux/config file if it's there...
+    if [ -f "${rootfs}/etc/selinux/config" ]
+    then
+        sed -i '/^SELINUX=/s/.*/SELINUX=disabled/' "${rootfs}/etc/selinux/config"
+    fi
+
+    # nice catch from Dwight Engen in the Oracle template.
+    # wantonly plagerized here with much appreciation.
+    if [ -f "${rootfs}/usr/sbin/selinuxenabled" ]
+    then
+        rm -f "${rootfs}/usr/sbin/selinuxenabled"
+        ln -s /bin/false "${rootfs}/usr/sbin/selinuxenabled"
+    fi
+
+    echo "${utsname}" > "${rootfs}/etc/hostname"
+
+    # set default localtime to the host localtime if not set...
+    if [ -e /etc/localtime ] && [ ! -e "${rootfs}/etc/localtime" ]
+    then
+        # if /etc/localtime is a symlink, this should preserve it.
+        cp -a /etc/localtime "${rootfs}/etc/localtime"
+    fi
+
+    # make sure fstab is empty
+    echo -n > "${rootfs}/etc/fstab"
+
+    # enable networking via systemd-networkd
+    test -d "${rootfs}/etc/systemd/network" || mkdir "${rootfs}/etc/systemd/network"
+    cat <<EOF > "${rootfs}/etc/systemd/network/eth0.network"
+[Match]
+Name=eth0
+
+[Network]
+DHCP=yes
+EOF
+    mkdir -p "${rootfs}/etc/systemd/system/socket.target.wants"
+    chroot "${rootfs}" ln -s /usr/lib/systemd/system/systemd-networkd.socket \
+        /etc/systemd/system/socket.target.wants/systemd-networkd.socket
+    chroot "${rootfs}" ln -s /usr/lib/systemd/system/systemd-networkd.service \
+        /etc/systemd/system/multi-user.target.wants/systemd-networkd.service
+    mkdir -p "${rootfs}/etc/systemd/system/network-online.target.wants"
+    chroot "${rootfs}" ln -s /usr/lib/systemd/system/systemd-networkd-wait-online.service \
+        /etc/systemd/system/network-online.target.wants/systemd-networkd-wait-online.service
+
+    # disable traditional network init
+    chroot "${rootfs}" chkconfig network off
+
+    # enable systemd-resolved
+    rm -f "${rootfs}/etc/resolv.conf"
+    chroot "${rootfs}" ln -s /run/systemd/resolve/resolv.conf /etc/resolv.conf
+    chroot "${rootfs}" ln -s /usr/lib/systemd/system/systemd-resolved.service \
+        /etc/systemd/system/multi-user.target.wants/systemd-resolved.service
+
+    # disable systemd default units which won't work a container
+    for svc in plymouth-start.service systemd-sysctl.service
+    do
+        chroot "${rootfs}" ln -s /dev/null /etc/systemd/system/${svc}
+    done
+
+    # disable system services
+    for svc in auditd chronyd
+    do
+        rm -f "${rootfs}/etc/systemd/system/multi-user.target.wants/${svc}.service"
+    done
+
+    # if desired, prevent systemd from over-mounting /tmp with tmpfs
+    rm -f "${rootfs}/etc/systemd/system/tmp.mount"
+    if [ "${masktmp}" -eq 1 ]
+    then
+        chroot "${rootfs}" ln -s /dev/null /etc/systemd/system/tmp.mount
+    fi
+}
+
+copy_configuration()
+{
+    local path="${1}"
+    local rootfs="${2}"
+    local hostname="${3}"
+
+    # include configuration from default.conf if available
+    grep -q "^lxc." "${lxc_default_conf}" > "${path}/config" 2>/dev/null || true
+
+    grep -q "^lxc.rootfs" "${path}/config" 2>/dev/null || echo "
+lxc.rootfs = ${rootfs}
+" >> "${path}/config"
+
+    # if there is exactly one veth network entry, make sure it has an
+    # associated hwaddr.
+    local nics
+    nics=$(grep -c -e '^lxc\.network\.type[ \t]*=[ \t]*veth' "${path}/config")
+    if [ "${nics}" -eq 1 ]
+    then
+        grep -q '^lxc.network.hwaddr' "${path}/config" || sed -i -e "/^lxc\.network\.type[ \t]*=[ \t]*veth/a lxc.network.hwaddr = 00:16:3e:$(openssl rand -hex 3| sed 's/\(..\)/\1:/g; s/.$//')" "${path}/config"
+    fi
+
+    # include common Fedora configuration
+    if [ -f "${lxc_template_config}/fedora.common.conf" ]
+    then
+        echo "
+# Include common configuration
+lxc.include = ${lxc_template_config}/fedora.common.conf
+" >> "${path}/config"
+    fi
+
+    cat <<EOF >> "${path}/config"
+# Container specific configuration
+lxc.arch = $(uname -m)
+lxc.utsname = ${hostname}
+
+# When using LXC with apparmor, uncomment the next line to run unconfined:
+#lxc.aa_profile = unconfined
+
+# 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,
+#lxc.network.hwaddr = 00:16:3e:$(openssl rand -hex 3| sed 's/\(..\)/\1:/g; s/.$//')
+#    persistent veth device name on host side
+#        Note: This may potentially collide with other containers of same name!
+#lxc.network.veth.pair = v-${name}-e0
+
+EOF
+
+
+}
+
+copy_fedora()
+{
+    local rootfs="${1}"
+
+    echo -n "Copy Fedora ${release} rootfs to ${rootfs} ... "
+    mkdir -p "${rootfs}"
+    rsync -Ha "${cache}/rootfs/" "${rootfs}/"
+    echo
+}
+
+download_fedora()
+{
+    local url_base="${mirror}/fedora/linux/releases/${release}/CloudImages/x86_64/images/"
+
+    # as the cloud image will be updated regularly, parse the directory index for
+    # for the exact file name
+    echo "Query cloud image name from ${url_base} ... "
+    image=$(curl -s -S -f "${url_base}" | sed -n -e '/raw\.xz/ s/.*href="\(.*\.raw\.xz\)">.*/\1/p' | tail -1)
+    # shellcheck disable=SC2181
+    if [ $? -ne 0 ] || [ -z "${image}" ]
+    then
+        echo "Error: Failed to get the latest cloud image name"
+        exit 1
+    fi
+
+    if [ -e "${image%%.xz}" ]
+    then
+        return 0
+    fi
+
+    echo "Download cloud image ${image} ... "
+
+    if ! curl -s -S -f -O "${url_base}${image}"
+    then
+        echo "Error: Failed to download cloud image from ${url_base}"
+        exit 1
+    fi
+
+    unxz "${image}"
+}
+
+install_fedora()
+{
+    local rootfs=$1
+    local release=$2
+    local clean=$3
+    local cache=$4
+
+    mkdir -p ${local_state_dir}/lock/subsys/
+
+
+
+    (
+        if ! flock -x 9
+        then
+            echo "Error: Cache repository is busy."
+            return 1
+        fi
+
+        echo "Checking cache download in ${cache}/rootfs ... "
+        if [ ! -e "${cache}/rootfs" ]
+        then
+            mkdir -p "${cache}"
+            pushd "${cache}" >/dev/null
+
+            download_fedora
+
+            test -d image || mkdir image
+            mount -o loop,offset="$(echo 2048*512 | bc)" "${image%%.xz}" image
+
+            echo -n "Copy image content to ${cache}/rootfs ... "
+            mkdir rootfs
+            rsync -Ha --exclude='lost+found' image/ rootfs/
+            echo
+
+            umount image
+            rmdir image
+            popd >/dev/null
+        fi
+
+        copy_fedora "${rootfs}"
+
+        return 0
+    ) 9>"${local_state_dir}/lock/subsys/$(basename "${0}")"
+
+    return $?
+}
+
+revert()
+{
+    echo "Interrupted, so cleaning up"
+    lxc-destroy -n "${name}"
+    # maybe was interrupted before copy config
+    # Too risky to run... there was not much path validation before
+#    rm -rf "${path}"
+    echo "Exiting..."
+    exit 1
+}
+
+usage()
+{
+    cat <<EOF
+LXC Container configuration for Fedora Cloud images.
+
+Template specific options can be passed to lxc-create after a '--' like this:
+
+  lxc-create --name=NAME -t fedora-cloud [OPTION..] -- [TEMPLATE_OPTION..]
+
+Template options:
+
+  -c, --clean            Clean download cache before creating new container
+  -d, --debug            Run with 'set -x' to debug errors
+      --fqdn             Fully qualified domain name (FQDN)
+  -h, --help             Print this help text
+      --mask-tmp         Prevent systemd from over-mounting /tmp with tmpfs.
+      --mirror=MIRROR    Fedora mirror to use during installation. Overrides the
+                         MIRROR environment variable (see below).
+  -p, --path=PATH        Path to where the container will be created,
+                         defaults to @LXCPATH at .
+  -R, --release=RELEASE  Fedora release number of the container, defaults
+                         to host's release if the host is Fedora.
+      --rootfs=ROOTFS    Path for the actual container root file system
+
+Environment variables:
+
+  LXC_CACHE_PATH         Cache directory for image bootstrap. Is set to
+                         '${LXC_CACHE_PATH}'
+
+  MIRROR                 The Fedora package mirror to use.
+                         Is set to '${MIRROR}'
+
+  FEDORA_RELEASE_DEFAULT Set default Fedora release if not detected from the
+                         host. Is set to '${FEDORA_RELEASE_DEFAULT}'
+
+EOF
+    return 0
+}
+
+options=$(getopt -o hp:n:cR:d -l help,path:,rootfs:,name:,clean,release:,debug,fqdn:,mask-tmp,mirror: -- "$@")
+# shellcheck disable=SC2181
+if [ $? -ne 0 ]; then
+    usage "$(basename "${0}")"
+    exit 1
+fi
+
+clean=0
+debug=0
+masktmp=0
+mirror=${MIRROR}
+
+eval set -- "$options"
+while true
+do
+    case "${1}" in
+        -h|--help)      usage "${0}" && exit 0  ;;
+        --rootfs)       rootfs="${2}";  shift 2 ;;
+        -p|--path)      path="${2}";    shift 2 ;;
+        --mirror)       mirror="${2}";  shift 2 ;;
+        -n|--name)      name="${2}";    shift 2 ;;
+        -c|--clean)     clean=1;        shift 1 ;;
+        -R|--release)   release="${2}"; shift 2 ;;
+        -d|--debug)     debug=1;        shift 1 ;;
+        --fqdn)         utsname="${2}"; shift 2 ;;
+        --mask-tmp)     masktmp=1;      shift 1 ;;
+        --)             shift 1;        break   ;;
+        *)                              break   ;;
+    esac
+done
+
+if [ "${debug}" -eq 1 ]
+then
+    set -x
+fi
+
+if [ -z "${release}" ]
+then
+    # set default release
+    if [ "${is_fedora}" ]
+    then
+        echo "Set Fedora release to ${fedora_host_ver}"
+        release="${fedora_host_ver}"
+    else
+        echo "This is not a Fedora host, defaulting to ${FEDORA_RELEASE_DEFAULT}. Use -R|--release to specify release"
+        release=${FEDORA_RELEASE_DEFAULT}
+    fi
+fi
+
+if [ "${release}" -lt "${FEDORA_RELEASE_MIN}" ]
+then
+    echo "Fedora release ${release} is not supported. Set -R at least to ${FEDORA_RELEASE_MIN}"
+    exit 1
+fi
+
+if [ "$(id -u)" != "0" ]
+then
+    echo "This script should be run as 'root'"
+    exit 1
+fi
+
+if [ "$(uname -m)" != "x86_64" ]; then
+    echo "Error: Fedora Cloud is only available on x86_64"
+    exit 1
+fi
+
+if [ -z "${path}" ]
+then
+    path="${lxc_path}/${name}"
+fi
+
+# detect rootfs
+config="${path}/config"
+if [ -z "${rootfs}" ]
+then
+    if grep -q '^lxc.rootfs' "${config}" 2>/dev/null ; then
+        rootfs=$(awk -F= '/^lxc.rootfs =/{ print $2 }' "${config}")
+    else
+        rootfs="${path}/rootfs"
+    fi
+fi
+
+cache=${LXC_CACHE_PATH}/fedora-cloud-${release}
+
+trap revert SIGHUP SIGINT SIGTERM
+
+# delete template cache
+if [ "${clean}" -eq 1 ]
+then
+    clean
+fi
+
+# bootstrap rootfs from Fedora Cloud image and copy to container file system
+install_fedora "${rootfs}" "${release}" "${cache}"
+
+# customize container file system
+configure_fedora "${rootfs}" "${release}" "${utsname:-${name}}"
+
+# create container configuration (will be overwritten by newer lxc-create)
+copy_configuration "${path}" "${rootfs}" "${utsname:-${name}}"
+
+echo "Container ${name} created."
+exit 0
+
+# vim: set ts=4 sw=4 expandtab:


More information about the lxc-devel mailing list