mirror of
https://github.com/lxc/lxc-templates.git
synced 2024-12-23 15:00:14 +00:00
92d4e109f1
Signed-off-by: Tanya Degurechaff <34323200+TanyaEleventhGoddess@users.noreply.github.com>
546 lines
16 KiB
Bash
546 lines
16 KiB
Bash
#!/bin/bash
|
|
|
|
#
|
|
# template script for generating OpenSUSE container for LXC
|
|
#
|
|
|
|
#
|
|
# lxc: linux Container library
|
|
|
|
# Authors:
|
|
# Daniel Lezcano <daniel.lezcano@free.fr>
|
|
# Frederic Crozat <fcrozat@suse.com>
|
|
# Michael H. Warfield <mhw@WittsEnd.com>
|
|
# Johannes Kastl <mail@ojkastl.de>
|
|
# Thomas Lamprecht <t.lamprecht@proxmox.com>
|
|
|
|
# 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
|
|
|
|
# Detect use under userns (unsupported)
|
|
for arg in "$@"; do
|
|
[ "$arg" = "--" ] && break
|
|
if [ "$arg" = "--mapped-uid" -o "$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
|
|
|
|
if [ -x /usr/bin/obs-build ]; then
|
|
BUILD=/usr/bin/obs-build
|
|
export BUILD_DIR=/usr/lib/obs-build
|
|
else
|
|
BUILD=/usr/bin/build
|
|
export BUILD_DIR=/usr/lib/build
|
|
fi
|
|
|
|
configure_opensuse()
|
|
{
|
|
rootfs=$1
|
|
hostname=$2
|
|
|
|
# set first network adapter as dhcp. This is the most common config.
|
|
cat <<EOF > $rootfs/etc/sysconfig/network/ifcfg-eth0
|
|
STARTMODE='auto'
|
|
BOOTPROTO='dhcp'
|
|
EOF
|
|
|
|
# create empty fstab
|
|
touch $rootfs/etc/fstab
|
|
|
|
# set the hostname
|
|
cat <<EOF > $rootfs/etc/HOSTNAME
|
|
$hostname
|
|
EOF
|
|
# ensure /etc/hostname is available too
|
|
ln -s -f HOSTNAME $rootfs/etc/hostname
|
|
|
|
# do not use hostname from HOSTNAME variable
|
|
cat <<EOF >> $rootfs/etc/sysconfig/cron
|
|
unset HOSTNAME
|
|
EOF
|
|
|
|
# set minimal hosts
|
|
cat <<EOF > $rootfs/etc/hosts
|
|
127.0.0.1 localhost $hostname
|
|
EOF
|
|
|
|
# disable yast->bootloader in container
|
|
cat <<EOF > $rootfs/etc/sysconfig/bootloader
|
|
LOADER_TYPE=none
|
|
LOADER_LOCATION=none
|
|
EOF
|
|
|
|
# set /dev/console as securetty
|
|
cat << EOF >> $rootfs/etc/securetty
|
|
console
|
|
EOF
|
|
|
|
cat <<EOF >> $rootfs/etc/sysconfig/boot
|
|
# disable root fsck
|
|
ROOTFS_FSCK="0"
|
|
ROOTFS_BLKDEV="/dev/null"
|
|
EOF
|
|
|
|
|
|
# remove pointless services in a container
|
|
ln -s /dev/null $rootfs/etc/systemd/system/proc-sys-fs-binfmt_misc.automount
|
|
ln -s /dev/null $rootfs/etc/systemd/system/console-shell.service
|
|
ln -s /dev/null $rootfs/etc/systemd/system/systemd-vconsole-setup.service
|
|
# enable getty and console services
|
|
sed -e 's/ConditionPathExists=.*//' $rootfs/usr/lib/systemd/system/getty@.service > $rootfs/etc/systemd/system/getty@.service
|
|
ln -s getty@.service $rootfs/etc/systemd/system/getty@tty1.service
|
|
mkdir -p $rootfs/etc/systemd/system/getty.target.wants/
|
|
ln -s ../getty@.service $rootfs/etc/systemd/system/getty.target.wants/getty@console.service
|
|
ln -s -f ../getty@.service $rootfs/etc/systemd/system/getty.target.wants/getty@tty1.service
|
|
ln -s ../getty@.service $rootfs/etc/systemd/system/getty.target.wants/getty@tty2.service
|
|
ln -s ../getty@.service $rootfs/etc/systemd/system/getty.target.wants/getty@tty3.service
|
|
ln -s ../getty@.service $rootfs/etc/systemd/system/getty.target.wants/getty@tty4.service
|
|
|
|
touch $rootfs/etc/sysconfig/kernel
|
|
|
|
echo "Please change root-password !"
|
|
|
|
return 0
|
|
}
|
|
|
|
download_opensuse()
|
|
{
|
|
cache=$1
|
|
arch=$2
|
|
|
|
if [ ! -x ${BUILD} ]; then
|
|
echo "Could not create openSUSE template :"
|
|
echo "you need to install \"build\" package"
|
|
return 1
|
|
fi
|
|
|
|
# check the mini opensuse was not already downloaded
|
|
mkdir -p "$cache/partial-$arch"
|
|
|
|
if [ $? -ne 0 ]; then
|
|
echo "Failed to create '$cache/partial-$arch' directory"
|
|
return 1
|
|
fi
|
|
|
|
# download a mini opensuse into a cache
|
|
echo "Downloading opensuse minimal ..."
|
|
mkdir -p "$cache/partial-$arch-packages"
|
|
|
|
oss_repo_url="http://download.opensuse.org/distribution/$DISTRO/repo/oss/"
|
|
if [[ $DISTRO == "tumbleweed" ]]; then
|
|
oss_repo_url="http://download.opensuse.org/$DISTRO/repo/oss/"
|
|
fi
|
|
zypper --quiet --root $cache/partial-$arch-packages --non-interactive ar "$oss_repo_url" repo-oss || return 1
|
|
|
|
# Leap update repos were rearranged
|
|
if [[ $DISTRO != "tumbleweed" ]]; then
|
|
update_repo_url="http://download.opensuse.org/update/$DISTRO/oss/"
|
|
zypper --quiet --root $cache/partial-$arch-packages --non-interactive ar "$update_repo_url" update || return 1
|
|
fi
|
|
|
|
support_packages=(zypper patterns-openSUSE-base lxc ncurses-utils iputils udev netcfg hwinfo insserv-compat module-init-tools openSUSE-release openssh pwdutils sysconfig net-tools iproute2)
|
|
|
|
zypper --quiet --root $cache/partial-$arch-packages --non-interactive --gpg-auto-import-keys update || return 1
|
|
zypper --root $cache/partial-$arch-packages --non-interactive in --no-recommends --auto-agree-with-licenses --download-only zypper lxc patterns-openSUSE-base bash iputils sed tar rsyslog ${support_packages[*]} || return 1
|
|
|
|
cat > $cache/partial-$arch-packages/opensuse.conf << EOF
|
|
Preinstall: aaa_base bash coreutils diffutils
|
|
Preinstall: filesystem fillup glibc grep insserv-compat perl-base
|
|
Preinstall: libbz2-1 pam
|
|
Preinstall: permissions rpm sed tar libz1 libselinux1
|
|
Preinstall: liblzma5 libcap2 libacl1 libattr1
|
|
Preinstall: libpopt0 libelf1
|
|
Preinstall: libpcre1
|
|
|
|
RunScripts: aaa_base
|
|
|
|
Support: ${support_packages[*]}
|
|
|
|
Ignore: rpm:suse-build-key,build-key
|
|
Ignore: systemd:systemd-presets-branding
|
|
EOF
|
|
|
|
if [[ $DISTRO == "tumbleweed" ]]; then
|
|
echo "Preinstall: liblua5_3 libncurses6 libreadline7" >> $cache/partial-$arch-packages/opensuse.conf
|
|
elif [[ $DISTRO == "leap/1"* ]]; then
|
|
echo "Preinstall: liblua5_3-5 libncurses6 libreadline7" >> $cache/partial-$arch-packages/opensuse.conf
|
|
elif [[ $DISTRO == "leap/4"* ]]; then
|
|
echo "Preinstall: liblua5_1 libncurses5 libreadline6" >> $cache/partial-$arch-packages/opensuse.conf
|
|
echo "Support: rpcbind" >> $cache/partial-$arch-packages/opensuse.conf
|
|
fi
|
|
|
|
if [ "$arch" = "i686" ]; then
|
|
mkdir -p $cache/partial-$arch-packages/var/cache/zypp/packages/repo-oss/suse/i686/
|
|
for i in "$cache/partial-$arch-packages/var/cache/zypp/packages/repo-oss/suse/i586/*" ; do
|
|
ln -s $i $cache/partial-$arch-packages/var/cache/zypp/packages/repo-oss/suse/i686/
|
|
done
|
|
mkdir -p $cache/partial-$arch-packages/var/cache/zypp/packages/update/i686
|
|
for i in "$cache/partial-$arch-packages/var/cache/zypp/packages/update/i586/*" ; do
|
|
ln -s $i $cache/partial-$arch-packages/var/cache/zypp/packages/update/i686/
|
|
done
|
|
fi
|
|
|
|
# openSUSE 13.2 has no noarch directory in update
|
|
[ -d $cache/partial-$arch-packages/var/cache/zypp/packages/update/noarch ] || mkdir -p $cache/partial-$arch-packages/var/cache/zypp/packages/update/noarch
|
|
if [[ $DISTRO == "leap/4"* ]]; then
|
|
repos=("--repository" "$cache/partial-$arch-packages/var/cache/zypp/packages/repo-oss/suse/$arch" "--repository" "$cache/partial-$arch-packages/var/cache/zypp/packages/repo-oss/suse/noarch")
|
|
else
|
|
# Leap 15 has a different repo structure compared to 42.3
|
|
repos=("--repository" "$cache/partial-$arch-packages/var/cache/zypp/packages/repo-oss/$arch" "--repository" "$cache/partial-$arch-packages/var/cache/zypp/packages/repo-oss/noarch")
|
|
fi
|
|
if [[ $DISTRO != "tumbleweed" ]]; then # tumbleweed has no update repo
|
|
repos+=("--repository" "$cache/partial-$arch-packages/var/cache/zypp/packages/update/$arch" "--repository" "$cache/partial-$arch-packages/var/cache/zypp/packages/update/noarch")
|
|
fi
|
|
|
|
CLEAN_BUILD=1 BUILD_ARCH="$arch" BUILD_ROOT="$cache/partial-$arch" BUILD_DIST="$cache/partial-$arch-packages/opensuse.conf" PATH="$PATH:$BUILD_DIR" $BUILD_DIR/init_buildsystem --clean --configdir $BUILD_DIR/configs --cachedir $cache/partial-$arch-cache ${repos[*]} || return 1
|
|
|
|
chroot $cache/partial-$arch /usr/bin/zypper --quiet --non-interactive ar "$oss_repo_url" repo-oss || return 1
|
|
if [[ $DISTRO != "tumbleweed" ]]; then
|
|
chroot $cache/partial-$arch /usr/bin/zypper --quiet --non-interactive ar "$update_repo_url" update || return 1
|
|
fi
|
|
|
|
# really clean the image
|
|
rm -fr $cache/partial-$arch/{.build,.guessed_dist,.srcfiles*,installed-pkg}
|
|
rm -fr $cache/partial-$arch/dev
|
|
# make sure we have a minimal /dev
|
|
mkdir -p "$cache/partial-$arch/dev"
|
|
mknod -m 666 $cache/partial-$arch/dev/null c 1 3
|
|
mknod -m 666 $cache/partial-$arch/dev/zero c 1 5
|
|
# create mtab symlink
|
|
rm -f $cache/partial-$arch/etc/mtab
|
|
ln -sf /proc/self/mounts $cache/partial-$arch/etc/mtab
|
|
|
|
# ensure /var/run and /run are symlinked
|
|
rm -fr $cache/partial-$arch/var/run
|
|
ln -s -f ../run $cache/partial-$arch/var/run
|
|
if [ $? -ne 0 ]; then
|
|
echo "Failed to download the rootfs, aborting."
|
|
return 1
|
|
fi
|
|
|
|
rm -fr "$cache/partial-$arch-packages"
|
|
mv "$1/partial-$arch" "$1/rootfs-$arch"
|
|
echo "Download complete."
|
|
|
|
return 0
|
|
}
|
|
|
|
copy_opensuse()
|
|
{
|
|
cache=$1
|
|
arch=$2
|
|
rootfs=$3
|
|
|
|
# make a local copy of the mini opensuse
|
|
echo "Copying rootfs to $rootfs ..."
|
|
mkdir -p $rootfs
|
|
rsync -SHaAX $cache/rootfs-$arch/ $rootfs/ || return 1
|
|
return 0
|
|
}
|
|
|
|
install_opensuse()
|
|
{
|
|
# Allow the cache base to be set by environment variable
|
|
cache="${LXC_CACHE_PATH:-@LOCALSTATEDIR@/cache/lxc/opensuse/$DISTRO}"
|
|
rootfs=$1
|
|
mkdir -p @LOCALSTATEDIR@/lock/subsys/
|
|
(
|
|
flock -x 9
|
|
if [ $? -ne 0 ]; then
|
|
echo "Cache repository is busy."
|
|
return 1
|
|
fi
|
|
|
|
echo "Checking cache download in $cache/rootfs-$arch ... "
|
|
if [ ! -e "$cache/rootfs-$arch" ]; then
|
|
download_opensuse $cache $arch
|
|
if [ $? -ne 0 ]; then
|
|
echo "Failed to download 'opensuse base'"
|
|
return 1
|
|
fi
|
|
fi
|
|
|
|
echo "Copy $cache/rootfs-$arch to $rootfs ... "
|
|
copy_opensuse $cache $arch $rootfs
|
|
if [ $? -ne 0 ]; then
|
|
echo "Failed to copy rootfs"
|
|
return 1
|
|
fi
|
|
|
|
return 0
|
|
) 9>@LOCALSTATEDIR@/lock/subsys/lxc-opensuse
|
|
|
|
return $?
|
|
}
|
|
|
|
# Generate a random hardware (MAC) address composed of FE followed by
|
|
# 5 random bytes...
|
|
create_hwaddr()
|
|
{
|
|
openssl rand -hex 5 | sed -e 's/\(..\)/:\1/g; s/^/fe/'
|
|
}
|
|
|
|
copy_configuration()
|
|
{
|
|
path=$1
|
|
rootfs=$2
|
|
name=$3
|
|
|
|
grep -q "^lxc.rootfs.path" $path/config 2>/dev/null || echo "
|
|
lxc.rootfs.path = $rootfs_path
|
|
" >> $path/config
|
|
|
|
# The following code is to create static MAC addresses for each
|
|
# interface in the container. This code will work for multiple
|
|
# interfaces in the default config. It will also strip any
|
|
# hwaddr stanzas out of the default config since we can not share
|
|
# MAC addresses between containers.
|
|
#
|
|
# This code is largely mimiced from the Fedora Template.
|
|
mv $path/config $path/config.def
|
|
while read LINE
|
|
do
|
|
# This should catch variable expansions from the default config...
|
|
if expr "${LINE}" : '.*\$' > /dev/null 2>&1
|
|
then
|
|
LINE=$(eval "echo \"${LINE}\"")
|
|
fi
|
|
|
|
# There is a tab and a space in the regex bracket below!
|
|
# Seems that \s doesn't work in brackets.
|
|
KEY=$(expr "${LINE}" : '\s*\([^ ]*\)\s*=')
|
|
|
|
if [[ "${KEY}" != "lxc.net.0.hwaddr" ]]
|
|
then
|
|
echo "${LINE}" >> $path/config
|
|
|
|
if [[ "${KEY}" == "lxc.net.0.link" ]]
|
|
then
|
|
echo "lxc.net.0.hwaddr = $(create_hwaddr)" >> $path/config
|
|
fi
|
|
fi
|
|
done < $path/config.def
|
|
|
|
rm -f $path/config.def
|
|
|
|
if [ -e "@LXCTEMPLATECONFIG@/opensuse.common.conf" ]; then
|
|
echo "
|
|
# Include common configuration
|
|
lxc.include = @LXCTEMPLATECONFIG@/opensuse.common.conf
|
|
" >> $path/config
|
|
fi
|
|
|
|
# Append things which require expansion here...
|
|
cat <<EOF >> $path/config
|
|
lxc.arch = $arch
|
|
lxc.uts.name = $name
|
|
|
|
lxc.mount.auto = cgroup:mixed proc:mixed sys:mixed
|
|
|
|
# When using LXC with apparmor, uncomment the next line to run unconfined:
|
|
lxc.apparmor.profile = unconfined
|
|
|
|
# example simple networking setup, uncomment to enable
|
|
#lxc.net.0.type = $lxc_network_type
|
|
#lxc.net.0.flags = up
|
|
#lxc.net.0.link = $lxc_network_link
|
|
#lxc.net.0.name = eth0
|
|
# Additional example for veth network type
|
|
# static MAC address,
|
|
#lxc.net.0.hwaddr = 00:16:3e:77:52:20
|
|
# persistent veth device name on host side
|
|
# Note: This may potentially collide with other containers of same name!
|
|
#lxc.net.0.veth.pair = v-$name-e0
|
|
|
|
EOF
|
|
|
|
if [ $? -ne 0 ]; then
|
|
echo "Failed to add configuration"
|
|
return 1
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
clean()
|
|
{
|
|
cache="${LXC_CACHE_PATH:-@LOCALSTATEDIR@/cache/lxc/opensuse}"
|
|
|
|
if [ ! -e $cache ]; then
|
|
exit 0
|
|
fi
|
|
|
|
# lock, so we won't purge while someone is creating a repository
|
|
(
|
|
flock -x 9
|
|
if [ $? != 0 ]; then
|
|
echo "Cache repository is busy."
|
|
exit 1
|
|
fi
|
|
|
|
echo -n "Purging the download cache..."
|
|
rm --preserve-root --one-file-system -rf $cache && echo "Done." || exit 1
|
|
exit 0
|
|
) 9>@LOCALSTATEDIR@/lock/subsys/lxc-opensuse
|
|
}
|
|
|
|
usage()
|
|
{
|
|
cat <<EOF
|
|
$1 -h|--help -p|--path=<path> -r|--release nn.n --clean
|
|
Please give the release as 13.1, 13.2 etc.
|
|
If no release is given, openSUSE Leap 42.2 is installed.
|
|
EOF
|
|
return 0
|
|
}
|
|
|
|
# Make arch a global. This may become configurable?
|
|
arch=$(uname -m)
|
|
|
|
options=$(getopt -o hp:n:r:c -l help,rootfs:,path:,name:,release:,clean -- "$@")
|
|
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;;
|
|
--rootfs) rootfs=$2; shift 2;;
|
|
-n|--name) name=$2; shift 2;;
|
|
-r|--release) DISTRO=$2; shift 2;;
|
|
-c|--clean) clean=1; shift 1;;
|
|
--) shift 1; break ;;
|
|
*) break ;;
|
|
esac
|
|
done
|
|
|
|
if [ ! -z "$clean" -a -z "$path" ]; then
|
|
clean || exit 1
|
|
exit 0
|
|
fi
|
|
|
|
type zypper > /dev/null
|
|
if [ $? -ne 0 ]; then
|
|
echo "'zypper' command is missing"
|
|
exit 1
|
|
fi
|
|
|
|
if [ -z "$path" ]; then
|
|
echo "'path' parameter is required"
|
|
exit 1
|
|
fi
|
|
|
|
if grep -q Harlequin /etc/os-release || grep -q Tumbleweed /etc/os-release ; then
|
|
BVER=`rpm -q --qf '%{version}\n' build`
|
|
if [ $? -ne 0 -o "$BVER" -lt "20141120" ]; then
|
|
echo "Building openSUSE containers with your version of the build package is broken. Please install the update to version 20141120 or newer."
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
if [ -z "$DISTRO" ]; then
|
|
echo ""
|
|
echo "No release selected, using openSUSE Leap 15.0"
|
|
DISTRO="leap/15.0"
|
|
else
|
|
echo ""
|
|
case "$DISTRO" in
|
|
13.1)
|
|
echo "Selected openSUSE 13.1"
|
|
;;
|
|
|
|
13.2)
|
|
echo "Selected openSUSE 13.2"
|
|
;;
|
|
|
|
42.1|leap/42.1|421)
|
|
echo "Selected openSUSE Leap 42.1"
|
|
DISTRO="leap/42.1"
|
|
;;
|
|
|
|
42.2|leap/42.2|422)
|
|
echo "Selected openSUSE Leap 42.2"
|
|
DISTRO="leap/42.2"
|
|
;;
|
|
|
|
42.3|leap/42.3|423)
|
|
echo "Selected openSUSE Leap 42.3"
|
|
DISTRO="leap/42.3"
|
|
;;
|
|
|
|
15.0|leap/15.0|150|leap)
|
|
echo "Selected openSUSE Leap 15.0"
|
|
DISTRO="leap/15.0"
|
|
;;
|
|
|
|
tumbleweed|factory)
|
|
echo "Selected openSUSE Leap Tumbleweed"
|
|
DISTRO="tumbleweed"
|
|
;;
|
|
|
|
*)
|
|
echo "You have chosen an invalid release, quitting..."
|
|
exit 1
|
|
;;
|
|
esac
|
|
fi
|
|
|
|
|
|
if [ "$(id -u)" != "0" ]; then
|
|
echo "This script should be run as 'root'"
|
|
exit 1
|
|
fi
|
|
|
|
# detect rootfs
|
|
config="$path/config"
|
|
if [ -z "$rootfs" ]; then
|
|
if grep -q '^lxc.rootfs.path' $config 2>/dev/null ; then
|
|
rootfs=$(awk -F= '/^lxc.rootfs.path =/{ print $2 }' $config)
|
|
else
|
|
rootfs=$path/rootfs
|
|
fi
|
|
fi
|
|
|
|
install_opensuse $rootfs
|
|
if [ $? -ne 0 ]; then
|
|
echo "failed to install opensuse"
|
|
exit 1
|
|
fi
|
|
|
|
configure_opensuse $rootfs $name
|
|
if [ $? -ne 0 ]; then
|
|
echo "failed to configure opensuse for a container"
|
|
exit 1
|
|
fi
|
|
|
|
copy_configuration $path $rootfs $name
|
|
if [ $? -ne 0 ]; then
|
|
echo "failed write configuration file"
|
|
exit 1
|
|
fi
|
|
|
|
if [ ! -z "$clean" ]; then
|
|
clean || exit 1
|
|
exit 0
|
|
fi
|