lxc-archlinux.in revision 21ca73b980b0888edaed6e1674870c28c1f515d8
247N/A#!/bin/bash
247N/A
247N/A#
247N/A# template script for generating Arch linux container for LXC
247N/A#
247N/A
247N/A#
247N/A# lxc: linux Container library
6982N/A
6982N/A# Authors:
247N/A# Alexander Vladimirov <idkfa@vlan1.ru>
247N/A# John Lane <lxc@jelmail.com>
247N/A
247N/A# This library is free software; you can redistribute it and/or
6982N/A# modify it under the terms of the GNU Lesser General Public
6982N/A# License as published by the Free Software Foundation; either
6982N/A# version 2.1 of the License, or (at your option) any later version.
6982N/A
247N/A# This library is distributed in the hope that it will be useful,
247N/A# but WITHOUT ANY WARRANTY; without even the implied warranty of
247N/A# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
247N/A# Lesser General Public License for more details.
247N/A
5187N/A# You should have received a copy of the GNU Lesser General Public
6247N/A# License along with this library; if not, write to the Free Software
247N/A# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
247N/A
247N/A# Detect use under userns (unsupported)
247N/Afor arg in "$@"; do
247N/A [ "$arg" = "--" ] && break
247N/A if [ "$arg" = "--mapped-uid" -o "$arg" = "--mapped-gid" ]; then
247N/A echo "This template can't be used for unprivileged containers." 1>&2
247N/A echo "You may want to try the \"download\" template instead." 1>&2
247N/A exit 1
247N/A fi
247N/Adone
247N/A
247N/A# Make sure the usual locations are in PATH
1089N/Aexport PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin
1089N/A
1089N/A# defaults
247N/Aarch=$(uname -m)
247N/Alxc_network_type="veth"
247N/Alxc_network_link="br0"
247N/Adefault_path="@LXCPATH@"
247N/Adefault_locale="en-US.UTF-8"
247N/Adefault_timezone="UTC"
247N/Apacman_config="/etc/pacman.conf"
4134N/A
4134N/A# by default, install 'base' except the kernel
247N/Apkg_blacklist="linux"
4134N/Abase_packages=()
247N/Afor pkg in $(pacman -Sqg base); do
247N/A [ "${pkg_blacklist#*$pkg}" = "$pkg_blacklist" ] && base_packages+=($pkg)
247N/Adone
247N/Adeclare -a additional_packages
247N/A
247N/A# split comma-separated string into an array
247N/A# ${1} - string to split
247N/A# ${2} - separator (default is ",")
247N/A# ${result} - result value on success
247N/Asplit_string() {
247N/A local ifs=${IFS}
247N/A IFS="${2:-,}"
247N/A read -a result < <(echo "${1}")
247N/A IFS=${ifs}
247N/A return 0
247N/A}
247N/A
247N/A[ -f /etc/arch-release ] && is_arch=true
247N/A
247N/A# Arch-specific preconfiguration for container
247N/Aconfigure_arch() {
247N/A # on ArchLinux, read defaults from host systemd configuration
247N/A if [ "${is_arch}" ]; then
247N/A cp -p /etc/vconsole.conf /etc/locale.conf /etc/locale.gen \
247N/A "${rootfs_path}/etc/"
247N/A else
247N/A echo "LANG=${default_lang}" > "${rootfs_path}/etc/locale.conf"
247N/A echo "KEYMAP=us" > "${rootfs_path}/etc/vconsole.conf"
247N/A cat > "${rootfs_path}/etc/adjtime" << EOF
1089N/A0.0 0.0 0.0
247N/A0
1089N/ALOCAL
247N/AEOF
247N/A if [ -e "${rootfs_path}/etc/locale.gen" ]; then
247N/A sed -i 's@^#\(en_US\.UTF-8\)@\1@' "${rootfs_path}/etc/locale.gen"
247N/A if [ ! "${default_locale}" = "en_US.UTF-8" ]; then
247N/A echo "${default_locale} ${default_locale##*.}" >> "${rootfs_path}/etc/locale.gen"
247N/A fi
247N/A fi
247N/A fi
247N/A
247N/A # hostname and nameservers
247N/A echo "${name}" > "${rootfs_path}/etc/hostname"
247N/A while read r; do
2624N/A [ "${r#nameserver}" = "$r" ] || echo "$r"
247N/A done < /etc/resolv.conf > "${rootfs_path}/etc/resolv.conf"
2624N/A
247N/A # chroot and configure system
247N/A arch-chroot "${rootfs_path}" /bin/bash -s << EOF
247N/Amkdir /run/lock
247N/Alocale-gen
247N/Aln -s /usr/share/zoneinfo/${default_timezone} /etc/localtime
247N/A# disable services unavailable for container
2624N/Afor i in systemd-udevd.service \
247N/A systemd-udevd-control.socket \
2624N/A systemd-udevd-kernel.socket \
2624N/A proc-sys-fs-binfmt_misc.automount; do
247N/A ln -s /dev/null /etc/systemd/system/\$i
247N/Adone
247N/A# set default systemd target
247N/Aln -s /lib/systemd/system/multi-user.target /etc/systemd/system/default.target
247N/A# initialize pacman keyring
247N/Apacman-key --init
2624N/Apacman-key --populate archlinux
247N/AEOF
2624N/A return 0
2624N/A}
247N/A
247N/A# write container configuration files
247N/Acopy_configuration() {
247N/A mkdir -p "${config_path}"
247N/A cat > "${config_path}/config" << EOF
247N/Alxc.utsname=${name}
247N/Alxc.autodev=1
247N/Alxc.tty=1
247N/Alxc.pts=1024
247N/Alxc.mount=${config_path}/fstab
247N/Alxc.cap.drop=sys_module mac_admin mac_override sys_time
247N/Alxc.kmsg=0
247N/Alxc.stopsignal=SIGRTMIN+4
247N/A#networking
247N/Alxc.network.type=${lxc_network_type}
1089N/Alxc.network.link=${lxc_network_link}
247N/Alxc.network.flags=up
247N/Alxc.network.name=eth0
247N/Alxc.network.mtu=1500
247N/A#cgroups
247N/Alxc.cgroup.devices.deny = a
247N/Alxc.cgroup.devices.allow = c *:* m
247N/Alxc.cgroup.devices.allow = b *:* m
247N/Alxc.cgroup.devices.allow = c 1:3 rwm
247N/Alxc.cgroup.devices.allow = c 1:5 rwm
1089N/Alxc.cgroup.devices.allow = c 1:7 rwm
1089N/Alxc.cgroup.devices.allow = c 1:8 rwm
1089N/Alxc.cgroup.devices.allow = c 1:9 rwm
1089N/Alxc.cgroup.devices.allow = c 4:1 rwm
247N/Alxc.cgroup.devices.allow = c 5:0 rwm
247N/Alxc.cgroup.devices.allow = c 5:1 rwm
247N/Alxc.cgroup.devices.allow = c 5:2 rwm
1089N/Alxc.cgroup.devices.allow = c 136:* rwm
247N/AEOF
247N/A
247N/A grep -q "^lxc.rootfs" ${config_path}/config 2>/dev/null || echo "lxc.rootfs = ${rootfs_path}" >> ${config_path}/config
247N/A
247N/A cat > "${config_path}/fstab" << EOF
247N/Asysfs sys sysfs defaults 0 0
247N/Aproc proc proc nodev,noexec,nosuid 0 0
247N/AEOF
247N/A
247N/A return 0
247N/A}
247N/A
247N/A# install packages within container chroot
247N/Ainstall_arch() {
247N/A [ "${arch}" != "$(uname -m)" ] && different_arch=true
247N/A
247N/A if [ "${different_arch}" = "true" ]; then
247N/A container_pacman_config=$(mktemp)
247N/A container_mirrorlist=$(mktemp)
247N/A sed -e "s:Architecture =.*:Architecture = ${arch}:g" \
247N/A -e "s:/etc/pacman.d/mirrorlist:${container_mirrorlist}:g" \
247N/A "${pacman_config}" > "${container_pacman_config}"
247N/A sed -e "s:\(x86_64\|\$arch\):${arch}:g" \
3634N/A /etc/pacman.d/mirrorlist > "${container_mirrorlist}"
247N/A
247N/A pacman_config="${container_pacman_config}"
247N/A fi
247N/A
247N/A if ! pacstrap -dcGC "${pacman_config}" "${rootfs_path}" \
247N/A ${base_packages[@]}; then
247N/A echo "Failed to install container packages"
247N/A return 1
247N/A fi
247N/A
247N/A if [ "${different_arch}" = "true" ]; then
247N/A sed -i -e "s:Architecture =.*:Architecture = ${arch}:g" \
247N/A "${rootfs_path}"/etc/pacman.conf
247N/A cp "${container_mirrorlist}" "${rootfs_path}"/etc/pacman.d/mirrorlist
247N/A rm "${container_pacman_config}" "${container_mirrorlist}"
4134N/A fi
247N/A
247N/A [ -d "${rootfs_path}/lib/modules" ] && ldconfig -r "${rootfs_path}"
247N/A return 0
247N/A}
247N/A
247N/Ausage() {
3634N/A cat <<EOF
247N/Ausage:
247N/A ${1} -n|--name=<container_name>
247N/A [-P|--packages=<pkg1,pkg2,...>] [-p|--path=<path>] [-t|--network_type=<type>] [-l|--network_link=<link>] [-h|--help]
247N/AMandatory args:
247N/A -n,--name container name, used to as an identifier for that container from now on
247N/AOptional args:
247N/A -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
247N/A -P,--packages preinstall additional packages, comma-separated list
247N/A -e,--enable_units Enable additional systemd units, comma-separated list
247N/A -c,--config use specified pacman config when installing container packages
247N/A -a,--arch use specified architecture instead of host's architecture
247N/A -t,--network_type set container network interface type (${lxc_network_type})
247N/A -l,--network_link set network link device (${lxc_network_link})
247N/A -r,--root_passwd set container root password
247N/A -h,--help print this help
247N/AEOF
247N/A return 0
247N/A}
247N/A
247N/Aoptions=$(getopt -o hp:P:e:n:c:a:l:t:r: -l help,rootfs:,path:,packages:,enable_units:,name:,config:,arch:,network_type:,network_link:,root_passwd: -- "${@}")
247N/Aif [ ${?} -ne 0 ]; then
247N/A usage $(basename ${0})
247N/A exit 1
247N/Afi
247N/Aeval set -- "${options}"
247N/A
247N/Awhile true
247N/Ado
247N/A case "${1}" in
247N/A -h|--help) usage ${0} && exit 0;;
247N/A -p|--path) path=${2}; shift 2;;
247N/A -n|--name) name=${2}; shift 2;;
3634N/A --rootfs) rootfs_path=${2}; shift 2;;
247N/A -P|--packages) additional_packages=${2}; shift 2;;
247N/A -e|--enable_units) enable_units=${2}; shift 2;;
247N/A -c|--config) pacman_config=${2}; shift 2;;
247N/A -a|--arch) arch=${2}; shift 2;;
247N/A -t|--network_type) lxc_network_type=${2}; shift 2;;
247N/A -l|--network_link) lxc_network_link=${2}; shift 2;;
247N/A -r|--root_passwd) root_passwd=${2}; shift 2;;
247N/A --) shift 1; break ;;
247N/A *) break ;;
247N/A esac
247N/Adone
247N/A
247N/Aif [ -z "${name}" ]; then
247N/A echo "missing required 'name' parameter"
247N/A exit 1
247N/Afi
4134N/A
247N/Aif [ ! -e /sys/class/net/${lxc_network_link} ]; then
247N/A echo "network link interface does not exist"
247N/A exit 1
247N/Afi
247N/A
247N/Atype pacman >/dev/null 2>&1
3634N/Aif [ ${?} -ne 0 ]; then
247N/A echo "'pacman' command is missing, refer to wiki.archlinux.org for information about installing pacman"
247N/A exit 1
247N/Afi
247N/A
247N/Aif [ -z "${path}" ]; then
247N/A path="${default_path}/${name}"
247N/Afi
247N/A
247N/Aif [ "${EUID}" != "0" ]; then
247N/A echo "This script should be run as 'root'"
247N/A exit 1
247N/Afi
247N/A
247N/Aif [ -z "$rootfs_path" ]; then
247N/A rootfs_path="${path}/rootfs"
247N/Afi
247N/Aconfig_path="${default_path}/${name}"
247N/A
247N/Arevert() {
247N/A echo "Interrupted, cleaning up"
247N/A lxc-destroy -n "${name}"
247N/A rm -rf "${path}/${name}"
247N/A rm -rf "${default_path}/${name}"
247N/A exit 1
247N/A}
247N/A
247N/Atrap revert SIGHUP SIGINT SIGTERM
247N/A
247N/Acopy_configuration
247N/Aif [ ${?} -ne 0 ]; then
247N/A echo "failed to write configuration file"
247N/A rm -rf "${config_path}"
247N/A exit 1
3634N/Afi
247N/A
247N/Aif [ ${#additional_packages[@]} -gt 0 ]; then
247N/A split_string ${additional_packages}
247N/A base_packages+=(${result[@]})
247N/Afi
247N/A
247N/Amkdir -p "${rootfs_path}"
247N/Ainstall_arch
247N/Aif [ ${?} -ne 0 ]; then
247N/A echo "failed to install Arch Linux"
247N/A rm -rf "${config_path}" "${path}"
247N/A exit 1
247N/Afi
247N/A
4134N/Aconfigure_arch
247N/Aif [ ${?} -ne 0 ]; then
247N/A echo "failed to configure Arch Linux for a container"
247N/A rm -rf "${config_path}" "${path}"
247N/A exit 1
247N/Afi
247N/A
3634N/Aif [ ${#enable_units[@]} -gt 0 ]; then
247N/A split_string ${enable_units}
247N/A for unit in ${result[@]}; do
247N/A [ "${unit}" = *'.'* ] || unit="${unit}.service"
247N/A ln -s /usr/lib/systemd/system/"${unit}" \
247N/A "${rootfs_path}"/etc/systemd/system/multi-user.target.wants
247N/A done
247N/Afi
247N/A
247N/Aif [ -n "${root_passwd}" ]; then
247N/A echo "root:${root_passwd}" | chroot "${rootfs_path}" chpasswd
247N/Afi
247N/A
247N/Acat << EOF
247N/AArchLinux container ${name} is successfully created! The configuration is
247N/Astored in ${config_path}/config. Please refer to https://wiki.archlinux.org for
247N/Ainformation about configuring ArchLinux.
247N/AEOF
247N/A