[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