2014-08-07 17:42:29 +02:00
#!/bin/bash
#
# template script for generating Void linux container for LXC
#
#
# lxc: linux Container library
# Authors:
# Juan RP <xtraeme@gmail.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
# defaults
arch=$(uname -m)
default_path="/var/lib/lxc"
LXC_TEMPLATE_CONFIG="/usr/share/lxc/config"
2014-08-07 22:08:59 +02:00
# Install 'base-voidstrap' and 'openssh-server' by default
base_packages=('base-voidstrap' 'openssh-server')
2014-08-07 17:42:29 +02:00
declare -a additional_packages
# split comma-separated string into an array
# ${1} - string to split
# ${2} - separator (default is ",")
# ${result} - result value on success
split_string() {
local ifs=${IFS}
IFS="${2:-,}"
read -a result < <(echo "${1}")
IFS=${ifs}
return 0
}
# write container configuration files
copy_configuration() {
path=$1
rootfs=$2
hostname=$3
arch=$4
2014-08-07 22:08:59 +02:00
# if there is exactly one veth network entry, make sure it has an
# associated hwaddr.
nics=`grep -e '^lxc\.network\.type[ \t]*=[ \t]*veth' $path/config | wc -l`
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
2014-08-07 17:42:29 +02:00
## Add all the includes
echo "" >> $path/config
echo "# Common configuration" >> $path/config
if [ -e "${LXC_TEMPLATE_CONFIG}/void.common.conf" ]; then
echo "lxc.include = ${LXC_TEMPLATE_CONFIG}/void.common.conf" >> $path/config
fi
## Add the container-specific config
echo "" >> $path/config
echo "# Container specific configuration" >> $path/config
grep -q "^lxc.rootfs" $path/config 2> /dev/null || echo "lxc.rootfs = $rootfs" >> $path/config
cat <<EOF >> $path/config
lxc.utsname = $hostname
lxc.arch = $arch
EOF
if [ $? -ne 0 ]; then
echo "Failed to add configuration"
return 1
fi
return 0
}
# install packages within container chroot
install_void() {
path=$1
rootfs=$2
hostname=$3
arch=$4
[ "${arch}" != "$(uname -m)" ] && different_arch=true
if [ "${different_arch}" = "true" ]; then
export XBPS_ARCH=${arch}
fi
# set the hostname
mkdir -p $rootfs/etc
echo $hostname > $rootfs/etc/hostname
# missing device nodes
mkdir -p $rootfs/dev
mknod -m 666 "$rootfs/dev/null" c 1 3
echo "Installing ${base_packages[@]}"
mkdir -p ${rootfs}/var/db/xbps/keys
# base64 encoded Void RSA public key
vkb64=$(mktemp || return 1)
cat > ${vkb64} << EOF
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPCFET0NUWVBFIHBsaXN0IFBV
QkxJQyAiLS8vQXBwbGUgQ29tcHV0ZXIvL0RURCBQTElTVCAxLjAvL0VOIiAiaHR0cDovL3d3dy5h
cHBsZS5jb20vRFREcy9Qcm9wZXJ0eUxpc3QtMS4wLmR0ZCI+CjxwbGlzdCB2ZXJzaW9uPSIxLjAi
Pgo8ZGljdD4KCTxrZXk+cHVibGljLWtleTwva2V5PgoJPGRhdGE+TFMwdExTMUNSVWRKVGlCUVZV
Sk1TVU1nUzBWWkxTMHRMUzBLVFVsSlEwbHFRVTVDWjJ0eGFHdHBSemwzTUVKQlVVVkdRVUZQUTBG
bk9FRk5TVWxEUTJkTFEwRm5SVUYyY2xONlFscE5kbWQyVDBOSk0wRllZazlxWVFveWNrdFNhMHBU
VkUwell5OUZhbFJKWjBOblJGaG5kVzA1TTBKUVEzUlpPRTFqUmxadlExVTBUMmxZU0VkbVZHMXhN
emxDVms1d1RIWk1TRXc1UzJzeENuQXlOemhUUW1oWVZrOTBZa0l5UlZadFJFdHVkbVpKUkVWVWJH
Uk1SM3BsTjNKYVRsSktaSFIxVGpKdFdpOVVWbkpWUWpsVE1IbFJZeXRKZFdZMGFIWUtNeXRFT1Rk
V1NXUlVTa2hCTjBGVGNqQTBNamh3Y0VWSFNrZDNVMU5vV1RKWVNtMDVSRFZKTUVWMVIxSlhZekUw
VFVWSE4yUkpTMHBwV1dsTk1HNUZOQXAwV1c4eUwzWklORWxHVkVoa2JsWkJNMmRaYVZwNVJHNWlk
VU5CVWk4NFJWTm1WVlJWTVROVFRrTlBaR0oxWkdZelJEVkNZM2tyVldsTlJFcEpNMWxsQ2pSTlJr
dENjbFE1V21oYUswZHpXRUphV1RRNE1teHhhVnBwTmtOTU5YQjBZemxKVVVabU9DOWxTMXBoT0dw
aGRHdHBWa1pXWjNKTFpVNVNhazlVZUU0S1psZFRkVEp1YTNoSFRsZ3JZbWhZV1hSb2FVZFhiVXBG
V1RoalEwRlFlVVpPSzB4Mk5WSmxkRXN5TlRablpHTmlNbk5yYlVWeFpXWjJNbnBRUXl0M1ZncFhR
bUprU0RWaVJEUmlXbXB1TUU0MldtdzRNWEoyTlZKNlJIWnVkbVlyZGtReE5HRkdWV0phT0ZGR2NY
VTNOVkJpVERSM05tMVpUVFJzWkUwdlp6QlNDalpPV0VVNFFYbzVRbmQ0TW5SRVpsbGxTM1YxZEhj
eFJYQlFiVEpaZGtaNVZGVmlNV052ZVVGMVZFZFNlVUZoY0RGVlZFaDJaemxzYUZCSlNtMW9SbEVL
U2pWclEyY3hjVVEzUVRNeFYyd3dVbXh1WlRab1owZHZNRnBhVGtvMVkwcE5MM1l2ZWxOVVMwcGpk
VVpuZDI4M1NEQm9UMGRwYkRaRVptODRPVUkwYWdwSE9UWkJRM2xRVXl0RVZrdFFSbGhTV1hkcUww
RnJZa2h3WVZFeVpqRkdUVUZ2VTNCQ2NYVkVjVWhvTTNWcmF6Y3hTMWcyYWpFNWREQnBSamhFVVV4
eUNuWjBSbE5UWkVscVJFRXdNbXgzWlZZNVRtRlJjRmR6UTBGM1JVRkJVVDA5Q2kwdExTMHRSVTVF
SUZCVlFreEpReUJMUlZrdExTMHRMUW89PC9kYXRhPgoJPGtleT5wdWJsaWMta2V5LXNpemU8L2tl
eT4KCTxpbnRlZ2VyPjQwOTY8L2ludGVnZXI+Cgk8a2V5PnNpZ25hdHVyZS1ieTwva2V5PgoJPHN0
cmluZz5Wb2lkIExpbnV4PC9zdHJpbmc+CjwvZGljdD4KPC9wbGlzdD4K
EOF
base64 -d ${vkb64} > ${rootfs}/var/db/xbps/keys/60\:ae\:0c\:d6\:f0\:95\:17\:80\:bc\:93\:46\:7a\:89\:af\:a3\:2d.plist
rm -f ${vkb64}
mkdir -p ${rootfs}/usr/share/xbps/repo.d
echo "repository=http://repo.voidlinux.eu/current" > ${rootfs}/usr/share/xbps/repo.d/00-main.conf
if ! xbps-install ${xbps_cachedir:+ -c $xbps_cachedir} \
${xbps_config:+-C $xbps_config} -r "${rootfs}" \
-Sy ${base_packages[@]}; then
echo "Failed to install container packages"
return 1
fi
grep nameserver /etc/resolv.conf > "${rootfs}/etc/resolv.conf"
2014-08-07 21:48:52 +02:00
# Enable agetty on /dev/console
ln -s /etc/sv/agetty-console $rootfs/etc/runit/runsvdir/default/
2014-08-07 22:08:59 +02:00
# Enable dhcpcd and sshd.
ln -s /etc/sv/dhcpcd $rootfs/etc/runit/runsvdir/default/
ln -s /etc/sv/sshd $rootfs/etc/runit/runsvdir/default/
# Copy host /etc/localtime
if [ -f /etc/localtime ]; then
cat /etc/localtime > $rootfs/etc/localtime
fi
2014-08-07 17:42:29 +02:00
echo "root:root" | chroot ${rootfs} chpasswd -c SHA512
echo
echo "Root password is 'root', please change!"
echo
return 0
}
usage() {
cat <<EOF
usage:
${1} -n|--name=<container_name>
[-P|--packages=<pkg1,pkg2,...>] [-p|--path=<path>] [-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 ${default_path}/rootfs. The container config will go under ${default_path} in that case
-P,--packages preinstall additional packages, comma-separated list
-c,--config use specified xbps config when installing container packages
--cachedir XBPS cache directory to store downloaded packages
-a,--arch use specified architecture instead of host's architecture
-r,--root_passwd set container root password
-h,--help print this help
EOF
return 0
}
options=$(getopt -o hp:P:e:n:c:a:l:t:r: -l help,rootfs:,path:,packages:,name:,config:,cachedir:,arch:,root_passwd: -- "${@}")
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;;
--rootfs) rootfs_path=${2}; shift 2;;
-P|--packages) additional_packages=${2}; shift 2;;
-c|--config) xbps_config=${2}; shift 2;;
--cachedir) xbps_cachedir=${2}; shift 2;;
-a|--arch) arch=${2}; shift 2;;
-r|--root_passwd) root_passwd=${2}; shift 2;;
--) shift 1; break ;;
*) break ;;
esac
done
if [ -z "${name}" ]; then
echo "missing required 'name' parameter"
exit 1
fi
type xbps-install >/dev/null 2>&1
if [ ${?} -ne 0 ]; then
echo "'xbps-install' command is missing, download xbps from http://repo.voidlinux.eu/static/"
exit 1
fi
if [ -z "${path}" ]; then
path="${default_path}/${name}"
fi
if [ "${EUID}" != "0" ]; then
echo "This script should be run as 'root'"
exit 1
fi
if [ -z "${rootfs_path}_path" ]; then
rootfs_path="${path}/rootfs"
fi
config_path="${default_path}/${name}"
revert() {
echo "Interrupted, cleaning up"
lxc-destroy -n "${name}"
rm -rf "${path}/${name}"
rm -rf "${default_path}/${name}"
exit 1
}
trap revert SIGHUP SIGINT SIGTERM
copy_configuration $path $rootfs_path $name $arch
if [ ${?} -ne 0 ]; then
echo "failed to write configuration file"
rm -rf "${config_path}"
exit 1
fi
if [ ${#additional_packages[@]} -gt 0 ]; then
split_string ${additional_packages}
base_packages+=(${result[@]})
fi
mkdir -p "${rootfs_path}"
install_void $path $rootfs_path $name $arch
if [ ${?} -ne 0 ]; then
echo "failed to install Void Linux"
rm -rf "${config_path}" "${path}"
exit 1
fi
cat << EOF
Void container ${name} is successfully created! The configuration is
stored in ${config_path}/config. Please refer to http://www.voidlinux.eu
for information about configuring your Void installation.
EOF