[lxc-devel] Not a Patch: 03/02... The follow-on script...

Michael H. Warfield mhw at WittsEnd.com
Tue Nov 12 03:29:00 UTC 2013


Ok all...

This is my 3rd piece.  It's "my script" that runs with "my setup" to
start up containers at boot with systemd on Fedora.

I don't want to step on the valuable work that Stéphane is doing in this
area but I hope this provides him with ideas.  Installed
in /usr/libexec/lxc/lxc-startup, it provides the additional
functionality to start containers when Fedora restarts.

Out of respect for other people's work right now, I'm not offering this
as a patch to the source tree.  It's just a suggestion how I would do
this.  There are a lot of things in this script that is very maliable
and it depends on a couple of things that need to be refined (such as
LXC_PATH).

In this script, a formalized way of obtaining a list of containers (and
configuration files) qualified to be autobooted would be good.  I
currently use the output of lxc-ls in combination of an arbitrary
LCM_PATH of /var/lib/lxc, neither of which may be optimal

Offered with the proviso that "it works for me"...  Attached below the
jump.

Regards,
Mike
-- 
Michael H. Warfield (AI4NB) | (770) 978-7061 |  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 -

# lxc-startup
#	Start up a list of containers...

# lxc-run [-b] [-f] [-h] [vm list]

# Wrapper script to run a bunch of containers optionally at boot time
#
#    -l n    : Boot all stopped containers with bootlevel >= n
#            :   default 0
#    -b      : Only start the container if onboot is true
#            :   equivalent to "-l 1" (also sets -q)
#    -F      : Force boot a container even if disabled is true
#            :   equivalent to "-l -1"
#    -h      : Print this message and exit
#    -q      : Quiet (disable ECHO)
#    -v      : Enable debug prints (enable ECHO)
#    -n      : Optional individual VM (maybe be used multiple times)
# [vm list] - list of VM's to start.  Default is any that are not disabled.
#

# Authors:
# Michael H. Warfield <mhw at wittsend.com>

#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

declare -i VERBOSITY=1
START_LEVEL=0
LASTCONFIG=undefined

# Not sure what the deal is but it seems to be a problem if we
# start kicking off containers too soon and this is non-blocking
# anyways, so let's just give the system a little time to catch
# it's breath before kicking these babies off...

# This is a variable to start next delay and is fed from the configuration
# files...
#
# This sets the initial delay...
DELAY=5
DELAY_DEFAULT=2

# A few generic ECHO commands for verbosity...
# Most of these are not currently used...

ECHO_OFF=": echo"
ECHO=": echo"
ECHO1=": echo"
ECHO2=": echo"
ECHO3=": echo"
ECHO4=": echo"

# BOOTLIST will be a newline delimited prioritized list of our
# containers to be processed.
#
# Currently, this list is space delimited.  This is not good if
# we allow white space in container names or paths.  A '/' may
# be better as a delimiter just because it screws up pathnames
# and nobody in their right mind would use it in a name.
#
# Fields:
#	Priority
#	Post Start Delay
#	Container Name
#	Container Config file

BOOTLIST=

function usage() {
	echo "usage: $0 [-b] [-F] [-h] [-q] [-v] [-l n] [-n VM] [--] [VM list]"
}


function help() {
	usage
	echo "

Run one or more containers with a halt monitor
Register a new container if necessary

Options:
    -b      : Only start the container if lxc.onboot is true
    -F      : Force boot a container even if lxc.disabled is true
    -l n    : Boot containers with bootlevel >= n
    -h      : Print this message and exit
    -q      : Quiet (disable ECHO)
    -v      : Enable debug prints (enable ECHO)
    -n      : Optional individual VM (maybe be used multiple times)
    VM list : Optional list of VM's to start

        If the list of VM names is empty, it defaults to all available
        subject to boot and force options.
"
}

# Rotate log based on date
#	argvs == logfile to rotate...

function log_rotate() {
	local STAMP=$(date +%F-%T)

	while [[ ${1} != "" ]]
	do
		local FNAME=$1

		if [[ ${FNAME} != "" && -f ${FNAME} && ! -f ${FNAME}-${STAMP} ]]
		then
			mv ${FNAME} ${FNAME}-${STAMP}
		fi
		shift
	done
}

# Checks the boot order priority in a config file and
# returns it plus the post start delay befoer starting
# the next container...

# This is my own convention...  These are options in the config
# file under lxc-boot.* to control higher level boot options.

# For "legacy" reasons (my past efforts) this honors lxc-boot.disabled
# and lxc-boot.onboot, even though most of the functionality is
# subsumed under lxc-boot.autoboot.  All of these parameters are,
# of course, maliable and adaptable to what ever we want.

CCG_GROUP=lxc-boot

# Function is called with the realpath to the configuration file.
# Function returns echoing the value of "priority delay" where
# pritority is the positive value boot order priority of the
# container and the delay to wait before starting another container.

function check_boot_level() {
	local CNAME
	local AUTOBOOT
	local DISABLED
	local ONBOOT
	local MY_DELAY
	local ret

	CNAME=$1
	ret=$2

	DISABLED=`sed -e "/$CFG_GROUP\.disabled\s*=\s*/!d" -e 's/.*=\s*//' -e q ${CNAME}`
	ONBOOT=`sed -e "/$CFG_GROUP\.onboot\s*=\s*/!d" -e 's/.*=\s*//' -e q ${CNAME}`
	AUTOBOOT=`sed -e "/$CFG_GROUP\.autoboot\s*=\s*/!d" -e 's/.*=\s*//' -e q  ${CNAME}`
	MY_DELAY=`sed -e "/$CFG_GROUP\.delay\s*=\s*/!d" -e 's/.*=\s*//' -e q  ${CNAME}`

	# If disabled is true, then override everything...
	# More severe disables can be applied more negative numbers.
	if [[ "${DISABLED}" == true || "${DISABLED}" == yes ]]
	then
		AUTOBOOT=-1;
	fi

	# If onboot is set and autoboot is not set, set autoboot to 1
	if [[ "${ONBOOT}" == true || "${ONBOOT}" == yes ]]
	then
		if [[ ${AUTOBOOT} == "" ]]
		then
			AUTOBOOT=1;
		fi
	fi

	if [[ "${AUTOBOOT}" != "" ]]
	then
		ret=${AUTOBOOT}
	fi

	if [[ "${MY_DELAY}" == "" ]]
	then
		MY_DELAY=${DELAY_DEFAULT}
	fi
 
	echo "${ret} ${MY_DELAY}"
	return 0
}

#
# Need to process our command line options
#

# We'll take a couple of shortcuts first.
# If there are no other parameters other than "start", "stop", or "restart",
# then we'll take that...  That makes this compatible with System V init
# and Upstart.

if [[ ${1} == "start" ]]
then
	shift
	# This is an exect out of init.  Make ssshhh...
	VERBOSITY=0
	START_LEVEL=1
fi

if [[ ${1} == "stop" ]]
then
	echo "Stop is not currently implimented"
	VERBOSITY=0
	exit 0
fi

if [[ ${1} == "restart" ]]
then
	echo "Restart is not currently implimented"
	VERBOSITY=0
	exit 0
fi

shortoptions='vqhl:n:Fb'
longoptions='verbose,quiet,help,level:,name:,force,boot'

getopt=$(getopt -o $shortoptions --longoptions  $longoptions -- "$@")
if [[ $? != 0 ]]
then
    usage
    exit 1;
fi

eval set -- "$getopt"

while true; do
        case "$1" in
            -h|--help)
                help
                exit 1
                ;;
            -n|--name)
                shift
                VM_LIST="$VM_LIST $1"
                shift
                ;;
            -F|--force)
                shift
                START_LEVEL=-1
                ;;
            -v|--verbose)
                shift
		VERBOSITY=$(( $VERBOSITY + 1 ))
                ECHO="echo"
                ;;
            -q|--quiet)
                shift
		VERBOSITY=0
                ECHO=": echo"
                ;;
            -b|--boot)
		VERBOSITY=0
                shift
                START_LEVEL=1
                ;;
            -l|--level)
                shift
                START_LEVEL=$1
		shift
                ;;
            --)
                shift
                break
		;;
            -*)
                echo $1
                usage
                exit 1
                ;;
	    *)
		break
		;;
        esac
done

if [[ ${VERBOSITY} -gt 0 ]]
then
	ECHO="echo"
else
	ECHO=": echo"
fi

# What ever is left should be a list of VM's or NULL

if [[ "$*" ]]
then
	VM_LIST="$VM_LIST $*"
	for CNAME in $VM_LIST
	do
		if [[ -f /var/lib/lxc/${CNAME}/config ]]
		then
			STATUS=$(lxc-info -n ${CNAME} 2> /dev/null | sed -e '/[Ss]tate:/!d' -e 's/[Ss]tate:.*\s//')
			FNAME=$(realpath /var/lib/lxc/${CNAME}/config)
			BOOT=$(check_boot_level "${FNAME}" 0)
			${ECHO_OFF} "${BOOT} ${CNAME} ${FNAME}"
			BOOTLIST="${BOOTLIST}
${BOOT} ${CNAME} ${FNAME}"
		fi
	done
fi

if [[ ! "$VM_LIST" ]]
then
	# Ubuntu convention...
	# These should be links to conf files
	# name format "container_name{.conf}
	if [[ -d /etc/lxc/auto ]]
	then
		for f in $( ls /etc/lxc/auto )
		do
			if [[ -s /etc/lxc/auto/$f ]]
			then
				FNAME=$( realpath -e "/etc/lxc/auto/$f" )
				CNAME="$(basename $f .conf)"
				# Ok...  Just for giggles, let's do a
				# little comparison...  The config file
				# SHOULD be in a directory which matches
				# the container name or maymhem may follow.
				DIRNAME=$(dirname ${FNAME})
				CDIR=$(basename ${DIRNAME})
				STATUS=$(lxc-info -n ${CNAME} 2> /dev/null | sed -e '/[Ss]tate:/!d' -e 's/[Ss]tate:.*\s//')
				if [[ "${CNAME}" != "${CDIR}" ]]
				then
					${ECHO} "Warning!  Container directory does not match autoboot name - ${CNAME} != ${CDIR}"
					NSTATUS=$(lxc-info -n ${CDIR} 2> /dev/null | sed -e '/[Ss]tate:/!d' -e 's/[Ss]tate:.*\s//')

					if [[ ${STATUS} == "" && ${NSTATUS} != "" ]]
					then
						${ECHO} "Switching to $CDIR for container name"
						# This is a bit of a heuristic but, if it fails,
						# some chump is doing something stupid that they
						# need to manually correct.
						CNAME=$CDIR
						STATUS=${NSTATUS}
					fi
				fi
				if [[ ${STATUS} == "STOPPED" ]]
				then
					BOOT=$(check_boot_level "${FNAME}" 1)
					${ECHO} "${BOOT} ${CNAME} ${FNAME}"
					BOOTLIST="${BOOTLIST}
${BOOT} ${CNAME} ${FNAME}"
				else
					${ECHO} "Container ${CNAME} is ${STATUS} and not in state STOPPED, skipping"
				fi
			else
				${ECHO} "/etc/lxc/auto/$f not a symlink"
			fi
		done
	fi

	VM_LIST=$(lxc-ls)
	for CNAME in $VM_LIST
	do
		if [[ -f /var/lib/lxc/${CNAME}/config ]]
		then
			STATUS=$(lxc-info -n ${CNAME} 2> /dev/null | sed -e '/[Ss]tate:/!d' -e 's/[Ss]tate:.*\s//')
			FNAME=$(realpath /var/lib/lxc/${CNAME}/config)
			BOOT=$(check_boot_level "${FNAME}" 0)
			${ECHO_OFF} "${BOOT} ${CNAME} ${FNAME}"
			BOOTLIST="${BOOTLIST}
${BOOT} ${CNAME} ${FNAME}"
		fi
	done
fi

# Need to deal with the condition where VMLIST is not NULL...

SORTBOOT=$( echo -n "$BOOTLIST" | sort --key=1nr,4  )

${ECHO} "START_LEVEL = ${START_LEVEL} ${DELAY}"

echo "$SORTBOOT" | while read PRIORITY POST_DELAY CNAME CONFIG
do

	if [[ ${PRIORITY} = "" ]]
	then
		continue;
	fi

	# Only one startup per config!
	# We sorted on this but this is only good if
	# it's within the same priority!  Not robust!

	if [[ "${CONFIG}" == "${LASTCONFIG}" ]]
	then
		continue
	fi
	LASTCONFIG="${CONFIG}"

	if [[ ${PRIORITY} -ge ${START_LEVEL} ]]
	then
		STATUS=$(lxc-info -n ${CNAME} 2> /dev/null | sed -e '/[Ss]tate:/!d' -e 's/[Ss]tate:.*\s//')
		if [[ ${STATUS} == "" ]]
		then
			${ECHO} "Unknown container:	${PRIORITY} ${POST_DELAY}	\"${CNAME}\"	\"${CONFIG}\""
		elif [[ ${STATUS} != "STOPPED" ]]
		then
			${ECHO} "Not Stopped:	${PRIORITY} ${POST_DELAY}	\"${CNAME}\"	\"${CONFIG}\""
		else
			${ECHO} "Will boot:	${PRIORITY} ${POST_DELAY}	\"${CNAME}\"	\"${CONFIG}\""
			LXC_LOGDIR=$(dirname "${CONFIG}")

			log_rotate ${LXC_LOGDIR}/console_out.log ${LXC_LOGDIR}/console_log.log ${LXC_LOGDIR}/logfile.log
			if [[ ${DELAY} != "" && ${DELAY} -gt 0 ]]
			then
				sleep ${DELAY}
			fi
			lxc-start -d -c ${LXC_LOGDIR}/console_out.log -L ${LXC_LOGDIR}/console_log.log -o ${LXC_LOGDIR}/logfile.log -n ${CNAME}

			# Now set the delay to this container's delay...
			DELAY=${POST_DELAY}
		fi
	else
		${ECHO} "Won't boot:	${PRIORITY} ${POST_DELAY}	\"${CNAME}\"	\"${CONFIG}\""
	fi
done


-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 482 bytes
Desc: This is a digitally signed message part
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20131111/c36f9bbe/attachment.pgp>


More information about the lxc-devel mailing list