[lxc-devel] [PATCH] gentoo template

Guillaume ZITTA lxc at zitta.fr
Sat Jan 11 11:40:14 UTC 2014


Template for Gentoo Linux

Signed-off-by: gza <lxc at zitta.fr>
---
  configure.ac            |   1 +
  templates/Makefile.am   |   3 +-
  templates/lxc-gentoo.in | 864 
++++++++++++++++++++++++++++++++++++++++++++++++
  3 files changed, 867 insertions(+), 1 deletion(-)
  create mode 100644 templates/lxc-gentoo.in

diff --git a/configure.ac b/configure.ac
index cbaa38b..ec7d835 100644
--- a/configure.ac
+++ b/configure.ac
@@ -644,6 +644,7 @@ AC_CONFIG_FILES([
  	templates/lxc-archlinux
  	templates/lxc-alpine
  	templates/lxc-plamo
+	templates/lxc-gentoo

  	src/Makefile
  	src/lxc/Makefile
diff --git a/templates/Makefile.am b/templates/Makefile.am
index abdca6f..168a999 100644
--- a/templates/Makefile.am
+++ b/templates/Makefile.am
@@ -15,4 +15,5 @@ templates_SCRIPTS = \
  	lxc-archlinux \
  	lxc-alpine \
  	lxc-cirros \
-	lxc-plamo
+	lxc-plamo \
+	lxc-gentoo
diff --git a/templates/lxc-gentoo.in b/templates/lxc-gentoo.in
new file mode 100644
index 0000000..fba4ad1
--- /dev/null
+++ b/templates/lxc-gentoo.in
@@ -0,0 +1,864 @@
+#!/bin/bash
+
+###############################################################################
+#
+# LXC template for gentoo
+#
+# Widely inspired from lxc-gentoo script at 
https://github.com/globalcitizen/lxc-gentoo
+#
+# this version is reworked with :
+# - out of the lxc-create compat
+# - vanilla gentoo config
+# - ready to use cache
+#
+# TODOLIST:
+#       - test all options
+#       - re test all options
+#       - wait for gentoo #496054
+#       - wait for response to LXC proposal 
http://lists.linuxcontainers.org/pipermail/lxc-devel/2013-December/006771.html
+#          - added bash version of this feature here
+#
+###############################################################################
+
+# Ensure strict root's umask doesen't render the VM unusable
+umask 022
+
+################################################################################
+#                        Various helper functions
+################################################################################
+
+# param: $1: the name of the lock
+# param: $2: the timeout for the lock
+# The rest contain the command to execute and its parameters
+execute_exclusively()
+{
+	mkdir -p @LOCALSTATEDIR@/lock/subsys/
+
+	local lock_name="$1"
+	local timeout="$2"
+	shift 2
+
+	{
+		printf "Attempting to obtain an exclusive lock (timeout: %s sec) 
named \"%s\"...\n" "${timeout}" "$lock_name"
+
+		flock -x -w "${timeout}" 50
+
+		if [[ $? -ne 0 ]]; then
+			printf " => unable to obtain lock, aborting.\n"
+			return 2
+		else
+			printf " => done.\n"
+		fi
+
+		printf " => Executing \"%s\"\n" "$*"
+		"$@"
+		retval=$?
+	} 50> "@LOCALSTATEDIR@/lock/subsys/lxc-gentoo-${lock_name}"
+	return $retval
+}
+
+# a die function is always a good idea
+die()
+{
+	printf "\n[the last exit code leading to this death was: %s ]\n" "$?"
+	local retval="$1"
+	shift 1
+	printf "$@"
+	exit "$retval"
+}
+
+# gentoo arch/variant detection
+set_default_arch()
+{
+	printf "### set_default_arch: default arch/variant autodetect...\n"
+	arch=$(arch)
+	if [[ $arch =~ i.86 ]]; then
+		arch="x86"
+		variant="x86"
+	elif [[ $arch == "x86_64" ]]; then
+		arch="amd64"
+		variant="amd64"
+	elif [[ $arch =~ arm.* ]]; then
+		arch="arm"
+		variant="armv7a"
+	else
+		#who knows, it may work...
+		printf " => warn: unexpected arch:${arch} let me knows if it works 
:)\n"
+		variant="${arch}"
+	fi
+	printf " => Got: arch=%s variant=%s\n" "${arch}" "${variant}"
+}
+
+store_user_message()
+{
+	user_message="${user_message}=> $@\n"
+}
+
+################################################################################
+#                    CACHE Preparation
+################################################################################
+# during setup cachedir is $cacheroot/partial-$arch-$variant
+# at the end, it will be   $cacheroot/rootfs-$arch-$variant
+
+cache_setup(){
+	partialfs="${cacheroot}/partial-${arch}-${variant}"
+
+	#if cache exists and flush not needed, return
+	[[ -d "${cachefs}" && -z "${flush_cache}" ]] && return 0
+
+	printf "###### cache_setup(): doing cache preparation\n"
+	local retval=1
+
+	#clean from failed previous run
+	rm -rf "${partialfs}"
+	mkdir -p "${partialfs}"
+
+	#let's go
+	cache_precheck && \
+	cache_stage3 && \
+	cache_portage && \
+	cache_inittab && \
+	cache_net && \
+	cache_dev && \
+	cache_openrc && \
+	rm -rf "${cachefs}" && \
+	mv "${partialfs}" "${cachefs}" && \
+	printf "###### cache_setup: Cache should be ready\n"
+
+	return $?
+}
+
+cache_precheck()
+{
+	printf "### cache_precheck(): doing some pre-start checks ...\n"
+	# never hurts to have a fail-safe.
+	[[ -n "${cacheroot//\/}" ]] \
+		|| die 8 "\$cacheroot (%s) IS EMPTY OR MADE OF ONLY DIRECTORY 
SEPERATORS, THIS IS *VERY* BAD!\n" "${cacheroot}"
+}
+
+#get latest stage3 tarball
+cache_stage3()
+{
+	printf "### cache_stage3(): stage3 cache deployment...\n"
+
+	if [ -z "${tarball}" ]; then
+		#variables init
+		local stage3_baseurl="${mirror}/releases/${arch}/autobuilds"
+
+		# get latest-stage3....txt file for subpath
+		local stage3_pointer="${stage3_baseurl}/latest-stage3-${variant}.txt"
+
+		printf "Determining path to latest Gentoo %s (%s) stage3 
archive...\n" "${arch}" "${variant}"
+		printf " => downloading and processing %s\n" "${stage3_pointer}"
+
+		local stage3_latest_tarball=$(wget -q -O - "${stage3_pointer}" | tail 
-n1 ) \
+			|| die 6 "Error: unable to fetch\n"
+
+		printf " => Got: %s\n" "${stage3_latest_tarball}"
+
+		printf "Downloading/untarring the actual stage3 tarball...\n"
+		wget -O - "${stage3_baseurl}/${stage3_latest_tarball}" | tar -xjpf - 
-C "${partialfs}" \
+			|| die 6 "Error: unable to fetch or untar\n"
+		printf " => extracted to: %s\n" "${partialfs}"
+	else
+		printf "Extracting the stage3 tarball...\n"
+		tar -xpf "${tarball}" -C "${partialfs}" || die 6 "unable to untar 
${tarball} to ${partialfs}"
+	fi
+
+	#check if it chroots
+	printf "chroot test..."
+	chroot ${partialfs} /bin/true || die 1 "Error: chroot %s /bin/true, 
failed" "${partialfs}"
+	printf " OK\n"
+	printf " => stage3 cache extracted in : %s\n" "${partialfs}"
+	return 0
+}
+
+cache_portage()
+{
+	printf "### cache_portage: caching portage tree tarball...\n"
+	[[ -z "${flush_cache}" && -f "${portage_cache}" ]] && return 0
+
+	rm -f ${portage_cache}
+
+	printf "Downloading Gentoo portage (software build database) 
snapshot...\n"
+	execute_exclusively portage 60 wget -O "${portage_cache}" 
"${mirror}/snapshots/portage-latest.tar.bz2" \
+	|| die 6 "Error: unable to fetch\n"
+	printf " => done.\n"
+}
+
+# custom inittab
+cache_inittab()
+{
+	printf "### cache_inittab: tuning inittab...\n"
+
+	INITTAB="${partialfs}/etc/inittab"
+
+	[[ -w "$INITTAB" ]] || die 1 "Error: $INITTAB is not writeable"
+
+	# create console
+	echo "# Lxc main console" >> "$INITTAB"
+	echo "1:12345:respawn:/sbin/agetty -a root --noclear 115200 console 
linux" >> "$INITTAB"
+
+	# finally we add a pf line to enable clean shutdown on SIGPWR (issue 
60)
+	echo "# clean container shutdown on SIGPWR" >> "$INITTAB"
+	echo "pf:12345:powerwait:/sbin/halt" >> "$INITTAB"
+
+	# we also blank out /etc/issue here in order to prevent delays 
spawning login
+	# caused by attempts to determine domainname on disconnected 
containers
+	sed -i 's/[\][Oo]//g' "${partialfs}/etc/issue"
+}
+
+cache_net()
+{
+	printf "### cache_net: doing some useful net tuning...\n"
+	# useful for chroot
+	# /etc/resolv.conf
+	grep -i 'search ' /etc/resolv.conf > "${partialfs}/etc/resolv.conf"
+	grep -i 'nameserver ' /etc/resolv.conf >> 
"${partialfs}/etc/resolv.conf"
+
+	# fix boot-time interface config wipe under aggressive cap drop
+	# (openrc 0.9.8.4 ~sep 2012 - 
https://bugs.gentoo.org/show_bug.cgi?id=436266)
+	# initial warkaround was: sed -i -e 
's/^#rc_nostop=""/rc_nostop="net.eth0 net.lo"/' 
"${partialfs}/etc/rc.conf"
+	# but this one does not depends on interfaces names
+	echo 'rc_keyword="-stop"' >> "${partialfs}/etc/conf.d/net"
+}
+
+cache_dev()
+{
+	printf "### cache_dev(): /dev tuning...\n"
+
+	#Wait for https://bugs.gentoo.org/show_bug.cgi?id=496054
+	mkdir "${partialfs}/dev/pts"
+
+	if [ -n "${nettun}" ]; then
+		mkdir -m 755 "${partialfs}/net"
+		mknod -m 666 "${partialfs}/net/tun"        c 10 200
+	fi
+
+	return 0
+}
+
+# fix openrc system
+cache_openrc()
+{
+	printf "### cache_openrc(): doing openrc tuning\n"
+
+	#Wait for https://bugs.gentoo.org/show_bug.cgi?id=496054
+	chroot "${partialfs}" sed s/-lxc//g -i "/etc/init.d/devfs"
+
+	return 0
+}
+
+################################################################################
+#                    CONTAINER Preparation
+################################################################################
+
+container_setup() {
+	printf "##### container_setup(): starting container setup\n"
+
+	#in most cases lxc-create should have provided a copy of default 
lxc.conf
+	#let's tag where template starts, or just create the files
+	echo '### lxc-gentoo template stuff starts here' >> "$path/config"
+
+	#Determine rootfs
+	#If backingstore was specified, lxc.rootfs should be present or 
--rootfs did the rootfs var creation
+	if [ -z "${rootfs}" ]; then
+		rootfs=`awk -F= '$1 ~ /^lxc.rootfs/ { print $2 }' "$path/config" 
2>/dev/null`
+		if [ -z "${rootfs}" ]; then
+			#OK it's default
+			rootfs="${path}/rootfs"
+		fi
+	fi
+	store_user_message "rootfs of container is : ${rootfs}"
+	store_user_message "config of container is : ${path}/config"
+
+	container_precheck && \
+	container_rootfs && \
+	container_consoles && \
+	container_tz && \
+	container_portage && \
+	container_net && \
+	container_hostname && \
+	container_auth && \
+	container_conf
+	if [ $? -ne 0 ]; then
+		die 1 "container_setup(): one step didn't complete, sorry\n"
+	fi
+
+	printf "###### container_setup(): container should be ready to 
start!\n"
+	printf "\n\n"
+	printf "You could now use you container with: lxc-start -n %s\n" 
"${name}"
+	printf "little things you should know about your container:\n"
+	printf "${user_message}"
+	return 0
+}
+
+container_precheck()
+{
+	printf "### container_precheck(): doing some pre-start checks ...\n"
+	# never hurts to have a fail-safe.
+	[[ -n "${name//\/}" ]] \
+		|| die 8 "\$name (%s) IS EMPTY OR MADE OF ONLY DIRECTORY SEPERATORS, 
THIS IS *VERY* BAD!\n" "${name}"
+
+	[[ -n "${rootfs//\/}" ]] \
+		|| die 8 "\$rootfs (%s) IS EMPTY OR MADE OF ONLY DIRECTORY 
SEPERATORS, THIS IS *VERY* BAD!\n" "${rootfs}"
+
+	[[ -n "${cachefs//\/}" ]] \
+		|| die 8 "\$cachefs (%s) IS EMPTY OR MADE OF ONLY DIRECTORY 
SEPERATORS, THIS IS *VERY* BAD!\n" "${cachefs}"
+
+	# check if the rootfs already exists
+	[[ -d "${rootfs}/etc" ]] && die 18 "Error: \$rootfs (%s) already 
exists!" "${rootfs}"
+
+	# check cache
+	[[ ! -d "${cachefs}/etc" ]] && die 1 "Error: \$cachefs (%s) not 
found!" "${cachefs}"
+
+	return 0
+}
+
+container_rootfs()
+{
+	printf "#### container_rootfs(): copying rootfs %s from cache %s 
...\n" "${rootfs}" "${cachefs}"
+	tar -c -f - -C "${cachefs}" . | tar -x -p -f - -C "${rootfs}" || die 1 
"Error: cache copy to rootfs failed"
+
+	printf "chroot test..."
+	chroot "${rootfs}" /bin/true || die 1 "Error: 'chroot %s /bin/true' 
failed"
+	printf " OK\n"
+
+	printf " => done\n"
+	return 0
+}
+
+container_consoles() {
+	printf "#### container_consoles(): setting container consoles ...\n"
+
+	# disable unwanted ttys
+	if [[ ${tty} < 6 ]]; then
+		local mindis=$(( ${tty} + 1 ))
+		sed -i "s/^c[${mindis}-6]/#&/" "${rootfs}/etc/inittab"
+	fi
+	printf " => main console + ${tty} ttys\n"
+
+	if [[ -z "${autologin}" ]]; then
+		sed 's/agetty -a root/agetty/' -i "${rootfs}/etc/inittab"
+	elif [[ "${user}" != "root" ]]; then
+		sed "s/agetty -a root/agetty -a ${user}/" -i "${rootfs}/etc/inittab"
+		printf " => Autologin on main console for %s enabled\n" "${user}"
+		[[ -z "${forced_password}" ]] && unset password
+		store_user_message "${user} has autologin on main console"
+	else
+		printf " => Autologin on main console for root enabled\n"
+		[[ -z "${forced_password}" ]] && unset password
+		store_user_message "${user} has autologin on main console"
+	fi
+	printf " => done\n"
+}
+
+container_tz()
+{
+	printf "#### container_tz(): setting container timezone ...\n"
+
+	#let's try to copy it from host
+	if [ -L "/etc/localtime" ]; then
+		#host has a symlink
+		#let see if we can reproduct symlink
+		target=$(readlink /etc/localtime)
+		if [[ "$target" != "" ]]; then
+			if [ -f "${rootfs}/${target}" ]; then
+				#same target exists in container
+				chroot "${rootfs}" ln -sf "${target}" "/etc/localtime"
+				printf " => host symlink reproducted in container : %s\n" 
"${target}"
+				store_user_message "timezone copyed from host"
+				return 0
+			fi
+		fi
+	fi
+
+	if [ -e /etc/localtime ]; then
+		# duplicate host timezone
+		cat /etc/localtime > "${rootfs}/etc/localtime"
+		printf " => host localtime copyed to container\n"
+		store_user_message "timezone was staticly copyed from host"
+	else
+		# otherwise set up UTC
+		chroot "${rootfs}" ln -sf /usr/share/zoneinfo/UTC /etc/localtime
+		printf " => fallback: fixed to UTC\n"
+		store_user_message "timezone was fixed to UTC"
+	fi
+}
+
+
+container_portage()
+{
+	printf "#### container_portage(): setting container portage... \n"
+
+	#default entry for conf
+	portage_mount="#container set with private portage tree, no mount 
here"
+
+	printf "Warnings are normal here, don't worry\n"
+	#container repos detection
+	if chroot ${rootfs} portageq get_repo_path / gentoo > /dev/null ; then
+		portage_container="$(chroot ${rootfs} portageq get_repo_path / 
gentoo)"
+	else
+		die 1 "Failed to figure out container portage tree location with 
portageq get_repo_path / gentoo\n"
+	fi
+
+	if [[ -n "${private_portage}" ]]; then
+		container_private_portage
+		return 0
+	fi
+
+	if [ -z "${portage_dir}" ]; then
+		#gentoo host detection
+		printf "trying to guess portage_dir from host...\n"
+		portage_dir="$(portageq get_repo_path / gentoo 2>/dev/null)"
+		if [ ! -d "${portage_dir}/profiles" ]; then
+			printf " => host portage detection failed (not gentoo host), 
fallback to private portage tree\n"
+			container_private_portage
+			return 0
+		fi
+	else
+		if [ ! -d "${portage_dir}/profiles" ]; then
+			die 1 "specified portage_dir (%s) does not contains profiles, is it 
a portage tree ?\n" "${portage_dir}"
+		fi
+	fi
+
+	# if we are here, we have shared portage_dir
+	#ensure dir exists
+	chroot "${rootfs}" mkdir ${portage_container}
+        portage_mount="#container set with shared portage
+	lxc.mount.entry=${portage_dir} ${portage_container/\//} none ro,bind 0 
0"
+	store_user_message "container has a shared portage from host's 
${portage_dir} to ${portage_container/\//}"
+        #Let's propose binary packages
+	cat <<- EOF >> "${rootfs}/etc/portage/make.conf"
+	# enable this to store built binary packages
+	#FEATURES="\$FEATURES buildpkg"
+
+	# enable this to use built binary packages
+	#EMERGE_DEFAULT_OPTS="\${EMERGE_DEFAULT_OPTS} --usepkg"
+
+	# enable and *tune* this kind of entry to slot binaries, specialy if 
you use multiples archs and variants
+	#PKGDIR="\${PKGDIR}/amd64
+	#or PKGDIR="\${PKGDIR}/hardened"
+EOF
+	printf " => portage stuff done, see /etc/portage/make.conf for 
additionnal tricks\n"
+
+}
+
+container_private_portage()
+{
+	#called from container_portage() do not call directly from 
container_setup
+	printf "# untaring private portage to %s from %s ... \n" 
"${rootfs}/${portage_container}" "${portage_cache}"
+	mkdir -p "${rootfs}/${portage_container}"
+	execute_exclusively portage 60 tar -xp --strip-components 1 -C 
"${rootfs}/${portage_container}" -f "${portage_cache}" \
+		|| die 2 "Error: unable to extract the portage tree.\n"
+	store_user_message "container has its own portage tree at 
${portage_container}"
+	printf "=> done\n"
+}
+
+#helper func for container_genconf_net()
+nic_write()
+{
+	#display with gentoo's confd.net format
+	echo "config_${nic_name}=\"${nic_conf}\""
+	#add to managed list
+	[[ "${nic_conf}" == "dhcp" ]] && nic_managed="${nic_managed} 
${nic_name}"
+	[[ "${nic_conf}" == "null" ]] && nic_unmanaged="${nic_unmanaged} 
${nic_name}"
+	nic_writed=1
+}
+
+#Analyse lxc.conf and print conf.d/net content
+container_conf_net()
+{
+	local file=${1}
+	[[ -z "${nic_last}" ]] && nic_last=-1
+	[[ -z "${nic_named}" ]] && nic_named=0
+	OLDIFS=$IFS
+	IFS="
+"
+	#I'll drink champagne the day we do templates in python
+	#let's do some drity bash things
+	for line in $( sed -r "s/[ ]*=[ ]*/_real_ugly_sep_42_/" "${file}" ); 
do
+		key=$(echo "${line}" | sed 's/_real_ugly_sep_42_.*$//')
+		value=$(echo "${line}" | sed 's/^.*_real_ugly_sep_42_//')
+
+		#new nic !
+		if [[ "${key}" == "lxc.network.type" ]]; then
+			#we don't know what to do with it.
+			[[ "${value}" == "empty" ]] && continue
+
+			#write conf from previous loops
+			[[ "${nic_writed}" == "0" ]] && nic_write
+
+			#init defaults
+			let nic_last=nic_last+1
+
+			nic_writed=0
+			#if 1 named between 2 not named: last is eth1
+			#=> Number is ID munis number of named NIC before
+			nic_name="eth$(( ${nic_last} - ${nic_named} ))"
+			nic_conf="dhcp"
+		fi
+		if [[ "${key}" =~ ^lxc.network.ipv(4|6) ]]; then
+			#tell openrc to not manage this NIC as LXC set there address
+			nic_conf="null"
+		fi
+		if [[ "${key}" =~ ^lxc.network.name ]]; then
+			nic_name="${value}"
+			let nic_named=nic_named+1
+		fi
+		if [[ "${key}" == "lxc.include" ]]; then
+			#recursive into include
+			container_conf_net "${value}"
+		fi
+	done
+	#write conf from previous loops
+	[[ "${nic_writed}" == "0" ]] && nic_write
+	IFS=$OLDIFS
+}
+
+container_net()
+{
+	printf "container_net(): setting container network conf... \n"
+
+	#let suppose all containers shoud have net if we found a bridge
+	if ! grep -q "^lxc.network.type" $path/config 2>/dev/null; then
+		## guess first bridge name
+		bridge=$(brctl show | awk 'NR==2 {print $1}')
+		if [[ "${bridge}" != "" ]]; then
+			cat <<EOF >> $path/config
+#Autodetected nic by lxc-gentoo
+lxc.network.type = veth
+lxc.network.link = ${bridge}
+lxc.network.flags = up
+EOF
+		store_user_message "network was autodetected, we use veth over 
bridge: ${bridge}, it will need a dhcp server to work"
+		fi
+	fi
+
+	#Analyse network configuration in config
+	container_conf_net "$path/config" >> "${rootfs}/etc/conf.d/net"
+
+	#For each openrc managed nic, activate
+	for nic in ${nic_managed}
+	do
+		chroot "${rootfs}" ln -s net.lo "/etc/init.d/net.${nic}"
+		chroot "${rootfs}" rc-update add net.${nic} default
+	done
+
+	# unless openrc manage a nic, we now have to force openrc to automatic
+	# provision of the 'net' dep. If we do not, network dependent services
+	# will fail to load
+	if [[ -z "${nic_managed}" ]]; then
+		#tell openrc that lxc already did the work
+		echo 'rc_provide="net"' >> "$CACHE/etc/rc.conf"
+	fi
+
+	# found how much nic finaly have
+	nic_count=$(( ${nic_last} + 1 ))
+	if [[ ${nic_count} == 0 ]]; then
+		#If no Nic, no need to continue
+		store_user_message "No network interface for this container"
+		return 0
+	fi
+
+	# Here is some tweak about static hwaddr
+	# if there is exactly one veth or macvlan network entry, make sure
+	# it has an associated mac address.
+	# Read explanations : 
http://lists.linuxcontainers.org/pipermail/lxc-devel/2013-December/006736.html
+	# Bash limits the ability to do this on more than 1 nic
+	if [ "${nic_count}" -eq 1 ] && ! grep -q "^lxc.network.hwaddr" 
$path/config; then
+		hwaddr="fe:$(dd if=/dev/urandom bs=8 count=1 2>/dev/null |od -t x8 | 
\
+			head -1 |awk '{print $2}' | cut -c1-10 |\
+			sed 's/\(..\)/\1:/g; s/.$//')"
+		echo "#Fixed hwaddr" >> $path/config
+		echo 
"#http://lists.linuxcontainers.org/pipermail/lxc-devel/2013-December/006736.html" 
 >> $path/config
+		echo "lxc.network.hwaddr = $hwaddr" >> $path/config
+		store_user_message "a static hardware addr was fixed for your NIC"
+	fi
+
+	#Wiser hwaddr management
+	# If you put a lxc.network.hwaddr containing "x", like 
fe:a2:xx:xx:xx:xx
+	# each x will be replaced with random hex number
+	# similar feature is proposed for lxc-create
+	# 
http://lists.linuxcontainers.org/pipermail/lxc-devel/2013-December/006771.html
+	# In the meantime, here is bash version
+
+	#generate enough random hex for all nics
+	randomhex=$(od -An -N $(( ${nic_count} * 6 )) -t x2 /dev/urandom | sed 
':a;N;$!ba;s/\n/ /g;s/\n/ /g' | sed 's/[^0-f]//g')
+
+	#replace "x" in hwaddr with
+	awk -F '[ \t]*=[ \t]*' '
+	BEGIN { split("'${randomhex}'", randomhex, ""); r=1 }
+	$1 != "lxc.network.hwaddr" { print $0 }
+	$1 == "lxc.network.hwaddr" { printf("%s = ",$1)
+		split($2, chars, "");
+		for (i=1; i <= length(chars); i++) {
+		if ( chars[i] == "x" ) {
+		printf("%s", randomhex[r]);
+		r=r+1;
+		}
+		else printf("%s", chars[i]);
+		}
+		printf("\n");
+	}' $path/config >> $path/config.hwaddr.awk
+
+	diff $path/config.hwaddr.awk $path/config >/dev/null 2>&1 || 
store_user_message "templated hwaddr generated"
+	[[ $? == 0 ]] && mv $path/config.hwaddr.awk $path/config
+
+	printf " => network conf done.\n"
+}
+
+# custom hostname
+container_hostname()
+{
+	printf "#### container_hostname(): setting hostname... \n"
+	printf "hostnale=%s\n" "${name}" > "${rootfs}/etc/conf.d/hostname"
+	printf " => done.\n"
+}
+
+container_auth()
+{
+	printf "#### container_auth(): setting authentification... \n"
+	if [[ "${user}" != "root" ]]; then
+		printf " non root user requested, creating... \n"
+		chroot "${rootfs}" useradd --create-home -s /bin/bash "${user}" || 
die 1 "failed to create user ${user}"
+		printf "  => user %s created\n" "${user}"
+	fi
+	store_user_message "Connection user is ${user}"
+	#Home of user
+	auth_home=$(chroot "${rootfs}" getent passwd "${user}" | cut -d : -f 
6)
+	if [[ -r "${auth_key}" ]]; then
+		printf " deploying auth_key %s for user %s ...\n" "${auth_key}" 
"${user}"
+		mkdir -p "${rootfs}/${auth_home}/.ssh"
+		cat >> "${rootfs}/${auth_home}/.ssh/authorized_keys"
+		chroot "${rootfs}" chown "${user}:" 
"${auth_home}/.ssh/authorized_keys"
+		printf "  => inserted public key in %s/.ssh/authorized_keys\n" 
"${auth_home}"
+		[[ -z "${forced_password}" ]] && unset password
+		store_user_message "${user} has the ssh key you gived us"
+	fi
+
+	if [[ -n "${password}" ]]; then
+		printf " setting password for %s ...\n" "${user}"
+		echo "${user}:${password}" | chroot "${rootfs}" chpasswd || die 1 
"failed to change password"
+		printf "  => done. if you didn't specify , default is 'toor'\n"
+		if [[ -n "${forced_password}" ]]; then
+			store_user_message "${user} has the password you give for him"
+		else
+			store_user_message "${user} has the default password 'toor', please 
change it ASAP"
+		fi
+	fi
+
+	printf " => done.\n"
+}
+
+################################################################################
+#                        lxc configuration files
+################################################################################
+
+container_conf()
+{
+	printf "container_configuration(): making lxc configuration file... 
\n"
+
+	#at this point if there
+	conf_file="${path}/config"
+
+	if grep -q "^lxc.rootfs" "${conf_file}" ; then
+		#lxc-create already provided one
+		conf_rootfs_line=""
+	else
+		conf_rootfs_line="lxc.rootfs = $(readlink -f "${rootfs}")"
+	fi
+	if [[ "${arch}" == "x86" || "${arch}" == "amd64" ]]; then
+		local conf_arch_line="lxc.arch = ${arch}"
+	else
+		local conf_arch_line="# lxc.arch = ${arch}"
+	fi
+
+	conf_lxc_cap_drop="sys_module mac_admin mac_override mknod sys_time"
+	conf_sysfs="lxc.mount.entry=sys sys sysfs defaults 0 0"
+
+	#more aggressive configuration, for your safety. But less things may 
work
+	if [ -n "${more_secure}" ]; then
+		conf_lxc_cap_drop="${conf_lxc_cap_drop} audit_control audit_write 
dac_read_search fsetid ipc_owner linux_immutable setfcap sys_admin 
sys_boot sys_pacct sys_ptrace sys_rawio sys_resource sys_tty_config 
syslog"
+		conf_sysfs="# disabled for security, see 
http://blog.bofh.it/debian/id_413
+#lxc.mount.entry=sys sys sysfs defaults 0 0"
+	fi
+
+        cat <<- EOF >> "${conf_file}"
+# sets container architecture
+# If desired architecture != amd64 or x86, then we leave it unset as
+# LXC does not oficially support anything other than x86 or amd64.
+${conf_arch_line}
+
+# console access
+lxc.tty = ${tty}
+lxc.pts = 1024
+
+# set the hostname
+lxc.utsname = ${name}
+
+${conf_rootfs_line}
+${portage_mount}
+${conf_sysfs}
+
+# this part is based on 'linux capabilities', see: man 7 capabilities
+#  eg: you may also wish to drop 'cap_net_raw' (though it breaks ping)
+#
+# WARNING: the security vulnerability reported for 'cap_net_admin' at
+# 
http://mainisusuallyafunction.blogspot.com/2012/11/attacking-hardened-linux-systems-with.html
+# via JIT spraying (the BPF JIT module disabled on most systems was 
used
+# in the example, but others are suggested vulnerable) meant that users
+# with root in a container, that capability and kernel module may 
escape
+# the container. ALWAYS be extremely careful granting any process root
+# within a container, use a minimal configuration at all levels -
+# including the kernel - and multiple layers of security on any system
+# where security is a priority.  note that not only LXC but PAX (and
+# others?) were vulnerable to this issue.
+#
+# conservative: lxc.cap.drop = sys_module mknod mac_override sys_boot
+# aggressive follows. (leaves open: chown dac_override fowner ipc_lock 
kill lease net_admin net_bind_service net_broadcast net_raw setgid 
setuid sys_chroot)
+# lxc.cap.drop = audit_control audit_write dac_read_search fsetid 
ipc_owner linux_immutable mac_admin mac_override mknod setfcap sys_admin 
sys_boot sys_module sys_pacct sys_ptrace sys_rawio sys_resource sys_time 
sys_tty_config syslog
+
+lxc.cap.drop = ${conf_lxc_cap_drop}
+
+${conf_mounts}
+
+# deny access to all devices by default, explicitly grant some 
permissions
+#
+# format is [c|b] [major|*]:[minor|*] [r][w][m]
+#            ^     ^                   ^
+# char/block -'     \`- device number    \`-- read, write, mknod
+#
+# first deny all...
+lxc.cgroup.devices.deny = a
+# /dev/null and zero
+lxc.cgroup.devices.allow = c 1:3 rw
+lxc.cgroup.devices.allow = c 1:5 rw
+# /dev/{,u}random
+lxc.cgroup.devices.allow = c 1:9 rw
+lxc.cgroup.devices.allow = c 1:8 r
+# /dev/pts/*
+lxc.cgroup.devices.allow = c 136:* rw
+lxc.cgroup.devices.allow = c 5:2 rw
+# /dev/tty{0,1}
+lxc.cgroup.devices.allow = c 4:1 rwm
+lxc.cgroup.devices.allow = c 4:0 rwm
+# /dev/tty
+lxc.cgroup.devices.allow = c 5:0 rwm
+# /dev/console
+lxc.cgroup.devices.allow = c 5:1 rwm
+EOF
+	if [ -n "${nettun}" ]; then
+		cat <<- EOF >> "${conf_file}"
+# /dev/net/tun
+lxc.cgroup.devices.allow = c 10:200 rwm
+EOF
+	fi
+	printf  " => done.\n"
+}
+
+usage()
+{
+	cat <<EOF
+$1 -h|--help [-a|--arch <arch>] [-v|--variant <variant>] 
[-P|--private-portage] [--portage-dir <protagedir>] [-t|--tarball 
<stage3file>]
+ [-F|--flush-cache] [-c|--cache-only] [-u|--user <username>] 
[-w|--password <password>] [-S|--auth-key <keyfile>]
+ [-s|--more-secure] [-m|--mirror <gentoomirror>] [--tty <number>] 
[--nettun]
+
+arch: the container architecture (e.g. amd64): defaults to host arch 
(currently: '${arch}')
+	If you choose one that needs emulation
+	tested: amd64, x86
+	You could try any other gentoo arch, why not...
+
+variant: gentoo's Architecture variant as of dec 2013 : (currently: 
'${variant}')
+	for amd64 arch: amd64 (default), amd64-hardened+nomultilib, 
amd64-hardened, amd64-nomultilib, x32
+	for x86 arch: i686 (default), i486, i686-hardened
+	for arm arch: armv7a (default), armv7a_hardfp, armv6j, armv6j_hardfp, 
armv5tel, armv4tl
+
+private-portage: by default, /usr/portage is mount-binded with host one 
if exists (currently: '${private_portage}')
+	this force container to have his own copy
+
+portage-dir: portage dir used for shared portage
+	by default the host on if any (currently: '${portage_dir}')
+
+tarball: force usage of local stage3 archive (currently: '${arch}')
+	If empty, latest will be downloaded
+
+flush-cache: do like there is no previous cache
+
+cache-only: just ensure cache is present
+	if cache exists and "flush-cache" not specified, does nothing
+
+user: user used in auth oriented options (currently: '${user}')
+
+password: password for user (currently: '${password}')
+	if default, usage of auth-key will disable password setting
+
+autologin: enable autologin for user (currently: '${autologin}')
+	This unset default password setting
+
+auth-key: SSH Public key file to inject into container for user 
(currently: '${auth_key}')
+	This unset default password setting
+
+more-secure: does some additional security agressive settings (may 
prevent things to run) (currently: '${more_secure}')
+
+mirror: gentoo mirror for download (currently: '${mirror}')
+
+tty: number of tty (6 max) (currently: '${tty}')
+
+nettun: enable creation of /dev/net/tun (for private container VPN) 
(currently: '${nettun}')
+EOF
+	exit 0
+}
+
+#some overridable defaults
+set_default_arch
+
+mirror="http://distfiles.gentoo.org"
+user="root"
+password="toor"
+tty=0
+options=$(getopt -o hp:n:a:FcPv:t:S:u:w:sm: -l 
help,rootfs:,path:,name:,arch:,flush-cache,cache-only,private-portage,variant:,portage-dir:,tarball:,auth_key:,user:,autologin,password:,more-secure,mirror:,tty:,nettun 
-- "$@")
+
+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;;
+	-n|--name)             name=$2; shift 2;;
+	-a|--arch)             arch=$2; shift 2;;
+	-F|--flush-cache)      flush_cache=1; shift 1;;
+	-c|--cache-only)       cache_only=1; shitf 1;;
+	-P|--private-portage)  private_portage=1; shift 1;;
+	-v|--variant)          variant=$2; shift 2;;
+	--portage-dir)         portage_dir=$2; shift 2;;
+	-t|--tarball)          tarball=$2; shift 2;;
+	-S|--auth-key)         auth_key=$2; shift 2;;
+	-u|--user)             user=$2; shift 2;;
+	-w|--password)         forced_password=1; password=$2; shift 2;;
+	-s|--more-secure)      more_secure=1; shift 1;;
+	-m|--mirror)           mirror=$2; shift 2;;
+	--nettun)              nettun=1; shift 1;;
+	--tty)                 [[ $2 -lt 6 ]] && tty=$2; shift 2;;
+	--autologin)            autologin=1; shift 1;;
+	--) shift 1; break ;;
+	*)           break ;;
+	esac
+done
+
+cacheroot="@LOCALSTATEDIR@/cache/lxc/gentoo"
+portage_cache="${cacheroot}/portage.tbz"
+cachefs="${cacheroot}/rootfs-${arch}-${variant}"
+
+alias wget="wget --timeout=8 --read-timeout=15 -c -t10 -nd"
+
+do_all() {
+	cache_setup
+	if [ -z "${cache_only}" ]; then
+		container_setup
+	fi
+}
+
+execute_exclusively "cache-${arch}-${variant}" 60 do_all
-- 
1.8.3.2




More information about the lxc-devel mailing list