mirror of
https://git.proxmox.com/git/mirror_lxc
synced 2025-06-30 15:29:19 +00:00

Howdy, I was playing around with LXC containers this past weekend, and noticed a couple of issues with the lxc-fedora script: #1: Line 96 should be ${ROOTFS}/etc/sysconfig/network instead of ${ROOTFS}/sysconfig/network #2 Line 249 contains a reference to $PKG, which isn't used in the program. I adjusted the variable to point to the correct package, and use this in the calls to yumdownloader: PKG="${DISTRO}-release.noarch.rpm" ..... yumdownloader --destdir="${CACHE}/partial" "${PKG}" #3 The $CACHE/partial path is escaped unnecessarily: RPM="rpm --root \"${CACHE}/partial\"" #4 The program assumes yumdownloader will work, which isn't always the case. I added an if statement to check the return code: echo "Downloading distribution release file ${PKG}" yumdownloader --destdir="${CACHE}/partial" "${PKG}" RESULT=$? if [ "${RESULT}" != "0" ]; then echo "Enable to download the distribution release file" exit 1 fi #5 The package name passed to yumdownloader is incorrect: yumdownloader --destdir="${CACHE}/partial" "${DISTRO}-release.noarch.rpm" On Fedora 10 and 11, this evaluates to: fedora-release.noarch.rpm When we need it to evaluate to: fedora-{RELEASE_VER}.release.noarch This is fixed in the PKG variable listed above. A patch that addresses these issues is attached. Thanks, - Ryan Signed-off-by: Matty <matty91@gmail.com> Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>
425 lines
9.5 KiB
Bash
425 lines
9.5 KiB
Bash
#!/bin/bash
|
|
# set -ex
|
|
|
|
DISTRO="fedora"
|
|
CACHE="@LOCALSTATEDIR@/cache/lxc/${DISTRO}"
|
|
|
|
# Default container name
|
|
NAME="fedora"
|
|
CONFFILE="lxc.conf"
|
|
MNTFILE="mount.conf"
|
|
UTSNAME=
|
|
IPV4="172.20.0.21"
|
|
GATEWAY="172.20.0.1"
|
|
MTU="1500"
|
|
|
|
# These paths are within the container so do not need to obey configure prefixes
|
|
INITTAB="/etc/inittab"
|
|
FSTAB="/etc/fstab"
|
|
SSHD_CONFIG="/etc/ssh/sshd_config"
|
|
|
|
################################################################################
|
|
# DISTRO custom configuration files
|
|
################################################################################
|
|
|
|
# custom selinux
|
|
|
|
write_distro_selinux() {
|
|
mkdir -p ${ROOTFS}/selinux
|
|
echo 0 > ${ROOTFS}/selinux/enforce
|
|
}
|
|
|
|
# custom fstab
|
|
|
|
write_distro_fstab() {
|
|
cat <<EOF > ${ROOTFS}/${FSTAB}
|
|
tmpfs /dev/shm tmpfs defaults 0 0
|
|
EOF
|
|
}
|
|
|
|
# custom inittab
|
|
|
|
write_distro_inittab() {
|
|
cat <<EOF > ${ROOTFS}/${INITTAB}
|
|
id:3:initdefault:
|
|
si::sysinit:/etc/init.d/rcS
|
|
l0:0:wait:/etc/init.d/rc 0
|
|
l1:1:wait:/etc/init.d/rc 1
|
|
l2:2:wait:/etc/init.d/rc 2
|
|
l3:3:wait:/etc/init.d/rc 3
|
|
l4:4:wait:/etc/init.d/rc 4
|
|
l5:5:wait:/etc/init.d/rc 5
|
|
l6:6:wait:/etc/init.d/rc 6
|
|
# Normally not reached, but fallthrough in case of emergency.
|
|
z6:6:respawn:/sbin/sulogin
|
|
1:2345:respawn:/sbin/getty 38400 console
|
|
c1:12345:respawn:/sbin/getty 38400 tty1 linux
|
|
c2:12345:respawn:/sbin/getty 38400 tty2 linux
|
|
c3:12345:respawn:/sbin/getty 38400 tty3 linux
|
|
c4:12345:respawn:/sbin/getty 38400 tty4 linux
|
|
EOF
|
|
}
|
|
|
|
# custom network configuration
|
|
write_distro_network() {
|
|
cat <<EOF > ${ROOTFS}/etc/sysconfig/network-scripts/ifcfg-lo
|
|
DEVICE=lo
|
|
IPADDR=127.0.0.1
|
|
NETMASK=255.0.0.0
|
|
NETWORK=127.0.0.0
|
|
# If you're having problems with gated making 127.0.0.0/8 a martian,
|
|
# you can change this to something else (255.255.255.255, for example)
|
|
BROADCAST=127.255.255.255
|
|
ONBOOT=yes
|
|
NAME=loopback
|
|
EOF
|
|
cat <<EOF > ${ROOTFS}/etc/sysconfig/network-scripts/ifcfg-eth0
|
|
DEVICE=eth0
|
|
BOOTPROTO=static
|
|
HWADDR=52:54:00:12:34:56
|
|
ONBOOT=yes
|
|
HOSTNAME=${UTSNAME}
|
|
NM_CONTROLLED=no
|
|
TYPE=Ethernet
|
|
IPADDR=${IPV4}
|
|
NETWORK=$(ipcalc -sn ${IPV4} 255.255.255.0)
|
|
GATEWAY=${GATEWAY}
|
|
BROADCAST=$(ipcalc -sb ${IPV4} 255.255.255.0)
|
|
NETMASK=255.255.255.0
|
|
MTU=${MTU}
|
|
EOF
|
|
}
|
|
|
|
# custom hostname
|
|
|
|
write_distro_hostname() {
|
|
cat <<EOF > ${ROOTFS}/etc/sysconfig/network
|
|
NETWORKING=yes
|
|
HOSTNAME=${UTSNAME}
|
|
EOF
|
|
}
|
|
|
|
# custom sshd configuration file
|
|
|
|
write_distro_sshd_config() {
|
|
cat <<EOF > ${ROOTFS}/${SSHD_CONFIG}
|
|
Port 22
|
|
Protocol 2
|
|
HostKey /etc/ssh/ssh_host_rsa_key
|
|
HostKey /etc/ssh/ssh_host_dsa_key
|
|
UsePrivilegeSeparation yes
|
|
KeyRegenerationInterval 3600
|
|
ServerKeyBits 768
|
|
SyslogFacility AUTH
|
|
LogLevel INFO
|
|
LoginGraceTime 120
|
|
PermitRootLogin yes
|
|
StrictModes yes
|
|
RSAAuthentication yes
|
|
PubkeyAuthentication yes
|
|
IgnoreRhosts yes
|
|
RhostsRSAAuthentication no
|
|
HostbasedAuthentication no
|
|
PermitEmptyPasswords yes
|
|
ChallengeResponseAuthentication no
|
|
EOF
|
|
}
|
|
|
|
################################################################################
|
|
# lxc configuration files
|
|
################################################################################
|
|
|
|
write_lxc_configuration() {
|
|
cat <<EOF > ${CONFFILE}
|
|
lxc.utsname = ${UTSNAME}
|
|
lxc.tty = 4
|
|
lxc.network.type = veth
|
|
lxc.network.flags = up
|
|
lxc.network.link = br0
|
|
lxc.network.name = eth0
|
|
lxc.network.mtu = ${MTU}
|
|
lxc.mount = ${MNTFILE}
|
|
lxc.rootfs = ${ROOTFS}
|
|
lxc.cgroup.devices.deny = a
|
|
# /dev/null and zero
|
|
lxc.cgroup.devices.allow = c 1:3 rwm
|
|
lxc.cgroup.devices.allow = c 1:5 rwm
|
|
# consoles
|
|
lxc.cgroup.devices.allow = c 5:1 rwm
|
|
lxc.cgroup.devices.allow = c 5:0 rwm
|
|
lxc.cgroup.devices.allow = c 4:0 rwm
|
|
lxc.cgroup.devices.allow = c 4:1 rwm
|
|
# /dev/{,u}random
|
|
lxc.cgroup.devices.allow = c 1:9 rwm
|
|
lxc.cgroup.devices.allow = c 1:8 rwm
|
|
# /dev/pts/* - pts namespaces are "coming soon"
|
|
lxc.cgroup.devices.allow = c 136:* rwm
|
|
lxc.cgroup.devices.allow = c 5:2 rwm
|
|
# rtc
|
|
lxc.cgroup.devices.allow = c 254:0 rwm
|
|
EOF
|
|
}
|
|
|
|
write_lxc_mounts() {
|
|
cat <<EOF > ${MNTFILE}
|
|
|
|
EOF
|
|
}
|
|
|
|
create() {
|
|
|
|
# choose a container name, default is already in shell NAME variable
|
|
echo -n "What is the name for the container ? [${NAME}] "
|
|
read _NAME_
|
|
|
|
if [ ! -z "${_NAME_}" ]; then
|
|
NAME=${_NAME_}
|
|
fi
|
|
|
|
# choose a hostname, default is the container name
|
|
echo -n "What hostname do you wish for this container ? [${NAME}] "
|
|
read _UTSNAME_
|
|
|
|
if [ ! -z "${_UTSNAME_}" ]; then
|
|
UTSNAME=${_UTSNAME_}
|
|
else
|
|
UTSNAME=${NAME}
|
|
fi
|
|
|
|
# choose an ipv4 address, better to choose the same network than
|
|
# your host
|
|
echo -n "What IP address do you wish for this container ? [${IPV4}] "
|
|
read _IPV4_
|
|
|
|
if [ ! -z "${_IPV4_}" ]; then
|
|
IPV4=${_IPV4_}
|
|
fi
|
|
|
|
# choose the gateway ip address
|
|
echo -n "What is the gateway IP address ? [${GATEWAY}] "
|
|
read _GATEWAY_
|
|
|
|
if [ ! -z "${_GATEWAY_}" ]; then
|
|
GATEWAY=${_GATEWAY_}
|
|
fi
|
|
|
|
# choose the MTU size
|
|
echo -n "What is the MTU size ? [$MTU] "
|
|
read _MTU_
|
|
|
|
if [ ! -z "$_MTU_" ]; then
|
|
MTU=$_MTU_
|
|
fi
|
|
|
|
# the rootfs name will be build with the container name
|
|
ROOTFS="./rootfs.${NAME}"
|
|
|
|
# check if the rootfs does already exist
|
|
if [ ! -e "${ROOTFS}" ]; then
|
|
mkdir -p @LOCALSTATEDIR@/lock/subsys/
|
|
(
|
|
flock -n -x 200
|
|
|
|
|
|
RES=$?
|
|
if [ "${RES}" != "0" ]; then
|
|
echo "Cache repository is busy."
|
|
break
|
|
fi
|
|
|
|
# check the mini distro was not already downloaded
|
|
echo -n "Checking cache download ..."
|
|
if [ ! -e "${CACHE}/rootfs" ]; then
|
|
|
|
echo "not cached"
|
|
|
|
# Rather than write a special yum config we just make the
|
|
# default RPM and yum layout in ${CACHE}. The alternative is
|
|
# to copy /etc/yum/yum.conf or /etc/yum.conf and fiddle with
|
|
# some settings.
|
|
mkdir -p "${CACHE}/partial/var/lib/rpm"
|
|
mkdir -p "${CACHE}/partial/var/log"
|
|
touch "${CACHE}/partial/var/log/yum.log"
|
|
|
|
RELEASE="$(yum info ${DISTRO}-release | \
|
|
awk -F '[[:space:]]*:[[:space:]]*' \
|
|
'/^Release/ { release = $2 }
|
|
/^Version/ { version = $2 }
|
|
END { print version "-" release }')"
|
|
|
|
PKG="${DISTRO}-release-${RELEASE}.noarch"
|
|
RPM="rpm --root ${CACHE}/partial"
|
|
|
|
echo "Initializing RPM cache ..."
|
|
${RPM} --initdb
|
|
echo "Downloading distribution release file ${PKG}"
|
|
yumdownloader --destdir="${CACHE}/partial" "${PKG}"
|
|
RESULT=$?
|
|
|
|
if [ "${RESULT}" != "0" ]; then
|
|
echo "Enable to download the distribution release file"
|
|
exit 1
|
|
fi
|
|
|
|
${RPM} --nodeps -ihv "${CACHE}/partial/${PKG}.rpm"
|
|
|
|
echo "Downloading ${DISTRO} minimal ..."
|
|
yum --installroot="${CACHE}/partial" -y groupinstall Base
|
|
RESULT=$?
|
|
if [ "${RESULT}" != "0" ]; then
|
|
echo "Failed to download the rootfs, aborting."
|
|
exit 1
|
|
fi
|
|
mv "${CACHE}/partial" "${CACHE}/rootfs"
|
|
echo "Download complete."
|
|
else
|
|
echo "Found."
|
|
fi
|
|
|
|
# make a local copy of the mini
|
|
echo -n "Copying rootfs ..."
|
|
cp -a ${CACHE}/rootfs ${ROOTFS} && echo "Done." || exit
|
|
) 200> "@LOCALSTATEDIR@/lock/subsys/lxc"
|
|
fi
|
|
|
|
write_lxc_mounts
|
|
|
|
write_lxc_configuration
|
|
|
|
write_distro_inittab
|
|
|
|
write_distro_hostname
|
|
|
|
write_distro_fstab
|
|
|
|
write_distro_network
|
|
|
|
write_distro_sshd_config
|
|
|
|
write_distro_selinux
|
|
|
|
@BINDIR@/lxc-create -n ${NAME} -f ${CONFFILE}
|
|
RES=$?
|
|
|
|
# remove the configuration files
|
|
rm -f ${CONFFILE}
|
|
rm -f ${MNTFILE}
|
|
|
|
if [ "${RES}" != "0" ]; then
|
|
echo "Failed to create '${NAME}'"
|
|
exit 1
|
|
fi
|
|
|
|
echo "Done."
|
|
echo -e "\nYou can run your container with the 'lxc-start -n ${NAME}'\n"
|
|
}
|
|
|
|
destroy() {
|
|
|
|
echo -n "What is the name for the container ? [${NAME}] "
|
|
read _NAME_
|
|
|
|
if [ ! -z "${_NAME_}" ]; then
|
|
NAME=${_NAME_}
|
|
fi
|
|
|
|
@BINDIR@/lxc-destroy -n ${NAME}
|
|
RETVAL=$?
|
|
if [ ! ${RETVAL} -eq 0 ]; then
|
|
echo "Failed to destroyed '${NAME}'"
|
|
return ${RETVAL}
|
|
fi
|
|
|
|
ROOTFS="./rootfs.${NAME}"
|
|
|
|
echo -n "Shall I remove the rootfs [y/n] ? "
|
|
read
|
|
if [ "${REPLY}" = "y" ]; then
|
|
rm -rf ${ROOTFS}
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
help() {
|
|
cat <<EOF
|
|
|
|
This script is a helper to create ${DISTRO} system containers.
|
|
|
|
The script will create the container configuration file following
|
|
the informations submitted interactively with 'lxc-${DISTRO} create'
|
|
|
|
The first creation will download, with yum, a ${DISTRO} minimal
|
|
install and store it into a cache.
|
|
|
|
The script will copy from the cache the root filesystem to the
|
|
current directory.
|
|
|
|
If there is a problem with the container, (bad configuration for
|
|
example), you can destroy the container with 'lxc-${DISTRO} destroy'
|
|
but without removing the rootfs and recreate it again with
|
|
'lxc-${DISTRO} create'.
|
|
|
|
If you want to create another ${DISTRO} container, call the 'lxc-${DISTRO}
|
|
create' again, specifying another name and new parameters.
|
|
|
|
At any time you can purge the ${DISTRO} cache download by calling
|
|
'lxc-${DISTRO} purge'
|
|
|
|
Have fun :)
|
|
|
|
EOF
|
|
}
|
|
|
|
purge() {
|
|
|
|
if [ ! -e ${CACHE} ]; then
|
|
exit 0
|
|
fi
|
|
|
|
# lock, so we won't purge while someone is creating a repository
|
|
(
|
|
flock -n -x 200
|
|
|
|
RES=$?
|
|
if [ "${RES}" != "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
|
|
|
|
) 200> "@LOCALSTATEDIR@/lock/subsys/lxc"
|
|
}
|
|
|
|
# Note: assuming uid==0 is root -- might break with userns??
|
|
if [ "$(id -u)" != "0" ]; then
|
|
echo "This script should be run as 'root'"
|
|
exit 1
|
|
fi
|
|
|
|
# Detect which executable we were run as, lxc-fedora or lxc-redhat
|
|
case "$0" in
|
|
*lxc-redhat)
|
|
DISTRO="redhat";;
|
|
*) # default is fedora
|
|
DISTRO="fedora";;
|
|
esac
|
|
CACHE="@LOCALSTATEDIR@/cache/lxc/${DISTRO}"
|
|
|
|
case "$1" in
|
|
create)
|
|
create;;
|
|
destroy)
|
|
destroy;;
|
|
help)
|
|
help;;
|
|
purge)
|
|
purge;;
|
|
*)
|
|
echo "Usage: $0 {create|destroy|purge|help}"
|
|
exit 1;;
|
|
esac
|