[lxc-devel] Container autostart proposal V2
Michael H. Warfield
mhw at WittsEnd.com
Tue May 28 20:37:29 UTC 2013
On Tue, 2013-05-28 at 15:58 -0400, Stéphane Graber wrote:
> Hey everyone,
> Thanks for the feedback on my previous autostart proposal.
> Here's a detailed bullet-point list of what should be done to implement
> autostarting containers in upstream LXC.
Yes. I concur with virtually (excuse the pun) all of this...
> Changes to the container config:
> - ADD: lxc.start.auto (integer, 0 = disabled, 1 = enabled, default: 0)
This default could be conditional. That's how I would incorporate the
Ubuntu paradigm. Anything in /etc/lxc/auto should be default: 1.
> - ADD: lxc.start.delay (integer, time in second, default: 0)
> - ADD: lxc.start.order (integer, boot order, default: 0)
> - ADD: lxc.group (string, multi-value, default: empty)
I would also like to see an "lxc.start.disabled" flag, ala OpenVZ. It
has been surprisingly helpful at times at preventing accidents when
working on large systems. If disabled is set to 1 you prohibit starting
unless some sort of override is issued (force parameter or edit the
config). It may not seem like a major thing and there are ways around
it but it has been handy back in my OpenVZ days. Just a suggestion. If
it's too complicated, it's no big thing.
> - NOTE: lxc.start.auto is an integer as there are plans to implement a
> third value 2 = last-state.
YES!
I'm attaching some bash pseudo code that implements
scanning /etc/lxc/auto (autoboot default on) and
then /var/lib/lxc/*/config (autoboot default off) and then sorting the
boot order off all enabled containers into a list and emitting that list
on stdout.
The "last state" is conditionalized based on the existence of a
file /var/lib/lxc/{CONTAINER}/state file and that file containing the
line "running". Just a thought.
I did not implement group filtering or boot order filtering (both good
ideas). The issue of the "delay" parameter is up to the actual startup
code itself.
This issue of the container name vs the container config is a royal
PITA. You can't really deterministically say what the container name
name should be based on the contents of the container config but it
relates to the LXC /var/lib/lxc subdirectory (but then the Ubuntu
autoboot paradigm breaks that) but there's nothing in the content of the
config file that directly relates back to the putative container name
(NO it's NOT the utsname). Maybe that's something else we should
address.
It's strictly proof of concept code but it parses my config files and
does basically the right thing. It's a strawman to show that this isn't
really all that difficult to implement. Use as you see fit. I've tried
to comment it with the gotcha's and ideas I see. Code is attached way
below the jump.
Let me repeat this one last time and make it very clear. This is proof
of concept code entirely. It is NOT READY FOR PRIME TIME. It is not
intended to go into the repositories and it has a lot of loose ends
(which I tried to document in the comments - spaces in path names WILL
break it!). It's not intended as a patch but just an idea of how "I
would do it." Your mileage may vary.
Let the rock throwing commence.
> Changes to the system config:
> - ADD: lxc.autostart.enabled (boolean, default: false)
> - ADD: lxc.autostart.group (string, multi-value, default: empty)
> Changes to the commands:
> - lxc-config
> * Add a "-n <container>" option to query the container config instead
> of the system config
>
> - lxc-list
> * Allow filtering by group
> * Allow showing the groups in the fancy view
>
> - lxc-start
> * Add a "-a" option which will match any container that has
> lxc.start.auto set to 1
> * Add a "-g <groups>" option which will match any container that has
> one of the groups in lxc.group matching one of the groups in <groups>
> (comma separated).
> * Both options imply -n.
> * NOTE: When starting containers, sort them by start order
> (lxc.start.order) and wait until the delay is passed before starting the
> next one (lxc.start.delay).
>
> - lxc-stop
> * Add a "-a" option which will match any container that has
> lxc.start.auto set to 1
> * Add a "-g <groups>" option which will match any container that has
> one of the groups in lxc.group matching one of the groups in <groups>
> (comma separated).
> * Both options imply -n.
>
> Examples:
> - lxc-start -a => Starts all auto-started containers that are in one of
> the groups listed in lxc.autostart.group (system config). If the system
> config entry isn't set, start all containers that DO NOT have
> lxc.start.group set (container config).
> - lxc-start -g django => Starts all the containers that have django in
> their lxc.start.group regardless of the autostart flag.
> - lxc-start -g django -a => Starts all autostarted containers that have
> django in their lxc.start.group.
> - lxc-start -g django,graphite -a => Starts all autostarted containers
> that have either django or graphite in their lxc.start.group
> - lxc-start -g any => Starts all defined containers regardless of
> autostart flag or group.
>
> - lxc-stop behaves in the exact same way as lxc-start but
> stopping/shutting down/rebooting the container instead.
>
> - lxc-config -n p1 lxc.utsname => returns p1
> - lxc.config lxc.autostart.enabled => returns true
Regards,
Mike
--
Michael H. Warfield (AI4NB) | (770) 985-6132 | mhw at WittsEnd.com
/\/\|=mhw=|\/\/ | (678) 463-0932 | http://www.wittsend.com/mhw/
NIC whois: MHW9 | An optimist believes we live in the best of all
PGP Key: 0x674627FF | possible worlds. A pessimist is sure of it!
--
#!/bin/sh -
# First find containers to autoboot based on Ubuntu system of
# links in /etc/lxc/auto. We are going to ASSUME that the rootfs
# parameter is the "unique" key to the container, since we're getting
# config files from different directories which may be copies or may
# be links. We will only consider one container for a given rootfs.
# This may or may not be a good assumption but it's the best we've got
# and if some fool is running more than one container on a given rootfs
# and he expects both to autoboot properly, maybe he should read up
# on symlinks and get a life to save us all from grief.
#
# Maybe we should use the uts_name for the unique key? Would that even work?
DEFAULT_PRIORITY=100
DEFAULT_DELAY=0
DEFAULT_GROUP=default
DEFAULT_AUTO_BOOT=1
# Prime this one with a single space for our regex matches...
CONTAINER_ROOTFS_LIST=" "
# Check the state of a configutation function based on $1.
#
# Four return possiblities...
# Return true
# Return false
# Return default value (passed by caller in $2).
# Return to previous state (to be determined by caller).
#
function check_state () {
case $1 in
0|n*|N*|[Ff][Aa][Ll][Ss][Ee]|[Oo][Nn])
echo "0"
return 1
;;
1|y*|Y*|[Tr][Uu][Rr][Ee]|[Oo][Ff][Ff])
echo "1"
return 0
;;
# This is a special case for power on where we want a "last state".
2|[Ll][Aa][Ss][Tt])
echo "2"
return -1
;;
*)
echo "$2"
return $2
esac
}
function read_config () {
BOOT_CONFIG=$1
LXC_ROOTFS=$(sed -e '/lxc\.rootfs\s*=\s*/!d' -e 's/.*=\s*//' -e q ${BOOT_CONFIG})
# Minimum required...
if [[ -z "${LXC_ROOTFS}" ]]
then
echo "No rootfs found. Abandoning ship."
return
fi
# Not sure this is useful, but it should be, some way or another.
LXC_UTSNAME=`sed -e '/lxc\.utsname\s*=\s*/!d' -e 's/.*=\s*//' -e q \
${BOOT_CONFIG}`
LXC_DISABLED=`sed -e "/lxc\.start\.disabled\s*=\s*/!d" -e 's/.*=\s*//' -e q \
${BOOT_CONFIG}`
LXC_DISABLED=$(check_state ${TMP_STR} 0)
LXC_AUTOBOOT=`sed -e "/lxc\.start\.auto\s*=\s*/!d" -e 's/.*=\s*//' -e q \
${BOOT_CONFIG}`
LXC_AUTOBOOT=$(check_state ${TMP_STR} ${DEFAULT_AUTO_BOOT})
# We may want to filter on this. That's for others to decide. It's
# sort of similar and orthogonal to "priority".
TMP_STR=`sed -e "/lxc\.group\s*=\s*/!d" -e 's/.*=\s*//' -e q \
${BOOT_CONFIG}`
if [[ -n "${TMP_STR}" ]]
then
LXC_GROUP=${TMP_STR}
else
LXC_GROUP=${DEFAULT_GROUP}
fi
TMP_STR=`sed -e "/lxc\.start\.order\s*=\s*/!d" -e 's/.*=\s*//' -e q \
${BOOT_CONFIG}`
if [[ -n "${TMP_STR}" ]]
then
LXC_PRIORITY=${TMP_STR}
else
LXC_PRIORITY=${DEFAULT_PRIORITY}
fi
# This should be numeric! Should we validate it?
TMP_STR=$(sed -e "/lxc\.start\.delay\s*=\s*/!d" -e 's/.*=\s*//' -e q ${BOOT_CONFIG})
if [[ -n "${TMP_STR}" ]]
then
LXC_DELAY=${TMP_STR}
else
LXC_DELAY=${DEFAULT_DELAY}
fi
}
# Build an initial list based on the conf names. Look for priority and
# group names in the config files
if [[ -d /etc/lxc/auto ]]
then
cd /etc/lxc/auto
# This needs some adjustment logic for what Serge was refering to about
# priorities and container name prefixes in the Ubuntu paradigm.2s
# Would it be appropriate to do a readlink here to find the -n container name?
# What if the admin had copied the file rather than linked to the file?
# What if this filename is different from the intended container name.
# There seems to be no nice clean way to relate this back from a "-f config"
# back to a "-n config" which really is problematical with the Ubuntu
# paradigm but it is what it is.
# I have no idea how we would incorporate the whole idea of power state
# recovery into this paradigm since the link only points to the configuration
# file (or is a configuration file) and we have no idea where the putative
# "power on" state was stored... That sucks. Ignore for now and let other
# hash it out. Assume that "Power On Recovery" can only be "On" or "Off"
# and "Last" is not applicable in this paradigm.
# A lot of this logic is going to be problematical if anyone puts spaces
# into path names. This code is not intended to deal with that. It can
# be managed by character escaping name mapping if anyone wants to go to
# the effort but I recognize that "here there be dragons".
for CONFIG in *
do
read_config ${CONFIG}
if [[ -z "${LXC_ROOTFS}" ]]
then
echo "$CONFIG: We have to at least have a rootfs. Ignoring container"
continue
fi
# Is this POSIX or a bashism? This could be a problem
if [[ ${CONTAINER_ROOTFS_LIST} =~ " ${LXC_ROOTFS} " ]]
then
echo "Duplicate rootfs ${CONFIG} ${LXC_ROOTFS} detected. Ignoring container"
continue
fi
if [[ ${LXC_AUTOBOOT} != 0 && ${LXC_DISABLED} = 0 ]]
then
# He's not disabled and has autoboot enabled or last state. Add him
# to the list.
echo "Adding: ${LXC_PRIORITY} ${LXC_GROUP} ${CONFIG} ${LXC_ROOTFS}"
CONTAINER_BOOT_LIST="${CONTAINER_BOOT_LIST}
${LXC_PRIORITY} ${LXC_GROUP} /etc/lxc/auto/${CONFIG}"
CONTAINER_ROOTFS_LIST="${CONTAINER_ROOTFS_LIST}${LXC_ROOTFS} "
fi
done
fi
cd /var/lib/lxc
# Now swap the autoboot to default to 0
DEFAULT_AUTOBOOT=0
for CONTAINER in *
do
if [[ -f ${CONTAINER}/config ]]
then
CONFIG=${CONTAINER}/config
read_config ${CONFIG}
if [[ -z "$LXC_ROOTFS" ]]
then
echo "$CONFIG: We have to at least have a rootfs. Ignoring container"
continue
fi
if [[ $(expr "${CONTAINER_ROOTFS_LIST}" : " ${LXC_ROOTFS} " ) != 0 ]]
then
echo "Duplicate rootfs ${CONFIG} ${LXC_ROOTFS} detected. Ignoring container"
continue
fi
if [[ ${LXC_AUTOBOOT} != 0 && ${LXC_DISABLED} = 0 ]]
then
if [[ ${LXC_AUTOBOOT} = 2 ]]
then
if [[ -f ${CONFIG}/state && $(cat ${CONFIG}/state) = running ]]
then
LXC_AUTOBOOT=1
else
LXC_AUTOBOOT=0
continue
fi
fi
echo "Adding: ${LXC_PRIORITY} ${LXC_GROUP} ${CONFIG} ${LXC_ROOTFS}"
# He's not disabled and has autoboot enabled. Add him to the list.
CONTAINER_BOOT_LIST="${CONTAINER_BOOT_LIST}
${LXC_PRIORITY} ${LXC_GROUP} /var/lib/lxc/${CONTAINER}/config"
CONTAINER_ROOTFS_LIST="${CONTAINER_ROOTFS_LIST}${LXC_ROOTFS} "
fi
else
echo "This is a container directory with no config? What's this?"
fi
done
echo "${CONTAINER_BOOT_LIST}" | sort
More information about the lxc-devel
mailing list