#!/bin/bash # # template script for generating Void linux container for LXC # # # lxc: linux Container library # Authors: # Juan RP # 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" # Install 'base-voidstrap' by default base_packages=('base-voidstrap') 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 ## 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 <> $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" echo "root:root" | chroot ${rootfs} chpasswd -c SHA512 echo echo "Root password is 'root', please change!" echo return 0 } usage() { cat < [-P|--packages=] [-p|--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