[__lxc_container] initial work for lxc contaienr type

This should theoretically work, but is untested. It is able to create
and delete, change basic configuration and start/stop/freeze the
container.
This commit is contained in:
matze 2020-06-02 22:33:30 +02:00
parent 88400551f9
commit 8ee71e67f4
16 changed files with 699 additions and 0 deletions

View file

@ -0,0 +1,37 @@
#!/bin/sh -e
# explorer/config
# Prints out the current container configuration (if required). This makes
# it easy to differ changes.
# abort if container will be absent - no config required
if [ "$(cat "$__object/parameter/state")" = "absent" ]; then
exit 0
fi
# read the lxcpath (reusing explorer)
lxcpath="$( "$__type_explorer/lxcpath" )"
# get name
name="$__object/parameter/name"
if [ -f "$name" ]; then
name="$(cat "$name")"
else
name="$__object_id"
fi
# assemble the container configuration file
config="$lxcpath/$name/config"
# check if the file exist
if [ -r "$config" ]; then
# print configuration and strip files to just values
# grep will hide all comments and empty lines - all others must be key-values
# sed will uniform patterns, that no spaces will be problematic (before, in the middle and at end)
grep -E -v "^([[:blank:]]*)(#|$)" "$config" | sed 's/^[[:blank:]]*//; s/[[:blank:]]*=[[:blank:]]*/ = /; s/[[:blank:]]*$//'
else
>&2 printf "config file \"%s\" does not exist or is not readable\n" "$config"
exit 1
fi

View file

@ -0,0 +1,16 @@
#!/bin/sh -e
# explorer/lxcpath
# Echos the lxcpath variable for all container instances
# Load important functions and parameter handling
. "$__type/helper-param"
. "$__type/helper-exec"
# lxcpath parameter
if [ -z "$lxcpath" ]; then
lxc_g config "lxc.lxcpath"
else
echo "$lxcpath"
fi

View file

@ -0,0 +1,18 @@
#!/bin/sh -e
# explorer/state
# Outputs if the container exist
# possible values: present || absent || running || stopped || frozen
# source param lib
. "$__type/helper-param"
. "$__type/helper-exec"
# the lxc-info command will exit non-zero if container not exist
if ! lxc_c info -H -S >/dev/null 2>&1; then
# not exist
echo "absent"
else
# print state (command output matches to type states)
lxc_c info -H -s | tr '[[:upper:]]' '[[:lower:]]'
fi

View file

@ -0,0 +1,54 @@
#!/bin/sh -e
# gencode-local
# This uploads the diff of the configuration file, which is applied by gencode-remote
# check both states
state_is="$(cat "$__object/explorer/state")"
state_should="$(cat "$__object/parameter/state")"
# Check the configurations only if the container exists
if [ "$state_should" != "absent" ]; then
# do changes
# predict remote lxc config file
container_config="$(cat "$__object/explorer/lxcpath")/$name/config"
# IPv6 fix
if echo "${__target_host}" | grep -q -E '^[0-9a-fA-F:]+$'
then
my_target_host="[${__target_host}]"
else
my_target_host="${__target_host}"
fi
# config-present
# remove all config lines from config-present that are already set or absent anyway
if grep -v -f "$__object/explorer/config" -f "$__object/files/config-absent" \
"$__object/files/config-present" > "$__object/files/config.add"; then
# get temp file name
add_dest="$($__remote_exec $__target_host "mktemp $container_config-add.XXXXXXXXXX")"
printf "%s" "$add_dest" > "$__object/files/remote-tmpfile_add"
# upload diff
cat <<OUT
$__remote_copy "$__object/files/config.add" "$my_target_host:$add_dest"
OUT
fi
# config-absent
# only find those lines which should be absent in the config
if grep -f "$__object/explorer/config" "$__object/files/config-absent" \
> "$__object/files/config.del"; then
# get temp file name
del_dest="$($__remote_exec $__target_host "mktemp $container_config-del.XXXXXXXXXX")"
printf "%s" "$del_dest" > "$__object/files/remote-tmpfile_del"
# upload diff
cat <<OUT
$__remote_copy "$__object/files/config.add" "$my_target_host:$del_dest"
OUT
fi
fi

View file

@ -0,0 +1,203 @@
#!/bin/sh -e
# gencode-remote
# Does all common stuff for the container on the host
# Source to the common parameters
. "$__type/helper-param"
# check both states
state_is="$(cat "$__object/explorer/state")"
state_should="$(cat "$__object/parameter/state")"
# Check if there is a difference within the states
if [ "$state_is" != "$state_should" ]; then
# change privileges (too complex to make exceptions)
cat <<USER
su "$user" - <<SU
USER
# handle if the container should exist or not
case "$state_should" in
present|running|stopped|frozen)
# check, if the container should be created or cloned
if [ -f "$__object/parameter/clone" ]; then
copy_from="$(cat "$__object/parameter/clone")"
copypath="$(cat "$__object/parameter/clonepath" || true)"
# assemble own optional lxc options
lxc_opts=""
if [ -n "$copypath" ]; then
# this is set as the default $lxcpath, because it is the origin
lxc_opts="$lxc_opts -P \"$copypath\""
fi
if [ -n "$lxcpath" ]; then
# this is set as the newpath, because it is the destination
lxc_opts="$lxc_opts -p \"$lxcpath\""
fi
# print lxc-copy code (because of the lxcpath thing, $LXC_PARAM conflicts)
cat <<LXC
lxc-copy $lxc_opts -n "$copy_from" --newname "$name"
LXC
else
template="$(cat "$__object/parameter/template")"
# assemble general creation options
create_opts=""
if [ -f "$__object/parameter/no-default-config" ]; then
# generate a random empty file and append
empty_config="$($__remote_exec $__target_host "mktemp \${TMPDIR:-/tmp}/cdist_lxc-empty.XXXXXXXXXX")"
create_opts="$create_opts -f \"$empty_config\""
elif [ -f "$__object/parameter/default-config" ]; then
# append the configuration
create_opts="$create_opts -f \"$(cat "$__object/parameter/default-config")\""
fi
# assemble template options
template_opts=""
# add common options
if [ -f "$__object/parameter/release" ]; then
template_opts="$template_opts -r \"$(cat "$__object/parameter/release")\""
fi
if [ -f "$__object/parameter/arch" ]; then
template_opts="$template_opts -a \"$(cat "$__object/parameter/arch")\""
fi
# at last, apply custom options
if [ -f "$__object/parameter/template-opts" ]; then
while read line; do
template_opts="$template_opts $line"
done < "$__object/parameter/template-opts"
fi
# print lxc-create code
cat <<LXC
lxc-create $LXC_PARAM -n "$name" -t "$template" $create_opts -- $template_opts
LXC
fi
# write to the message system
echo "create" >> "$__messages_out"
;;
absent)
# shutdown and delete the container
# we could force-delete, but better be polite
# snapshots are deleted, too - to keep everything clean. May someone does not want it?
cat <<LXC
lxc-stop $LXC_PARAM -n "$name"
lxc-destroy $LXC_PARAM --snapshots -n "$name"
LXC
# write to the message system
echo "destroy" >> "$__messages_out"
;;
# error handling: invalid state
*)
printf "Container '%s' in unknown state %s\n" "$name" "$state_should" >&2
exit 2
;;
esac
# end of su here-document
echo "SU"
fi
# Check the configurations only if the container exists and there are changes
if [ "$state_should" != "absent" ] && \
( [ -f "${tmppath}_add" ] || [ -f "${tmppath}_del" ] ); then
# shortcut
tmppath="$__object/files/remote-tmpfile"
# generate config path
container_config="$(cat "$__object/explorer/lxcpath")/$name/config"
# create remote tmpfile for config
cat <<DONE
tmpconfig="\$(mktemp "$container_config.XXXXXXXXXX")"
cp -p "$container_config" "\$tmpconfig"
DONE
# check if smth. to be added
if [ -f "${tmppath}_add" ]; then
cat <<DONE
cat "$(cat "${tmppath}_add")" >> "\$tmpconfig"
rm -rf "$(cat "${tmppath}_add")"
DONE
fi
# check if smth. to be deleted
if [ -f "${tmppath}_del" ]; then
cat <<DONE
grep -v -f "$(cat "${tmppath}_del")" "\$tmpconfig" > "\$tmpconfig"
rm -rf "$(cat "${tmppath}_del")"
DONE
fi
# apply all changes
cat <<DONE
rm -rf "$container_config"
mv "\$tmpconfig" "$container_config"
DONE
# write message
echo "config" >> "$__messages_out"
fi
# TODO user context again
# Check if there is a difference within the states
if [ "$state_is" != "$state_should" ] && [ "$state_should" != "absent" ]; then
# change privileges (too complex to make exceptions)
cat <<USER
su "$user" - <<SU
USER
# handle if the container should exist or not
case "$state_should" in
running)
if [ "$state_is" = "frozen" ]; then
cat <<LXC
lxc-unfreeze $LXC_PARAM -n "$name"
LXC
fi
cat <<LXC
lxc-start $LXC_PARAM -n "$name"
LXC
;;
stopped)
if [ "$state_is" = "frozen" ]; then
cat <<LXC
lxc-unfreeze $LXC_PARAM -n "$name"
LXC
fi
cat <<LXC
lxc-stop $LXC_PARAM -n "$name"
LXC
;;
frozen)
# stopped containers can't be frozen; they must be started first
if [ "$state_is" = "stopped" ]; then
cat <<LXC
lxc-start $LXC_PARAM -n "$name"
LXC
fi
cat <<LXC
lxc-freeze $LXC_PARAM -n "$name"
LXC
;;
*)
;; # must be checked by previous case
esac
# end of su here-document
echo "SU"
fi

View file

@ -0,0 +1,68 @@
# vi: syntax=sh
# helper-exec
# Adds functions to easily handle the execution of lxc commands
# requires to source the helper-param before .. ;)
# Following global variables required (from helper-param):
# $user: the unix user to execute lxc commands with
# $name: the lxc container name
# Execute a command with a special user.
#
# Parameters:
# 1: the execution user
# 2: the execution command
# 3: all further parameters for the command
exec_user() {
# save important arguments
_user="$1"
_cmd="$(which -- "$2")"
shift 2
# check if the user must be switched
if [ "$_user" != "$USER" ]; then
# execute it wit su
# here, compatibility to non-sudo systems is provided and the "shell parameter thing" is misused
# to provide more parameter safety.
su -s "$_cmd" -- "$_user" "$@"
# no switch of the user - keep the same
else
# execute the command
"$_cmd" "$@"
fi
}
# Function to execute lxc commands in the correct execution. Only works for container-specific commands.
# Default things such as default parameters (see $LXC_PARAM), execution user and the container name are
# applied within the function.
#
# Parameters:
# 1: the lxc command without the preceding "lxc"
# 2-n: all other lxc arguments
lxc_c() {
# get exec name
lxccmd="lxc-$1"
shift
# execute the command
exec_user "$user" "$lxccmd" $LXC_PARAM -n "$name" "$@"
}
# Function to execute global lxc commands within the correct execution environment. Container-specific
# commands require to pass the -n flag with the container name, rather lxc_c is recommended.
# Default things such as default parameters (see $LXC_PARAM) and execution are applied to the command.
#
# Parameters:
# 1: the lxc command without the preceding "lxc"
# 2-n: all other lxc arguments
lxc_g() {
# get exec name
lxccmd="lxc-$1"
shift
# execute the command
exec_user "$user" "$lxccmd" $LXC_PARAM "$@"
}

View file

@ -0,0 +1,27 @@
# vi: syntax=sh
# helper-param
# Shortcut to optain all basic required parameters for working.
# Parameter gathering
name="$__object/parameter/name"
if [ -f "$name" ]; then
name="$(cat "$name")"
else
name="$__object_id"
fi
user="$(cat "$__object/parameter/user")"
# general lxc things
lxcpath="$(cat "$__object/parameter/lxcpath" || true)"
# Summerize common parameter arguments, listed in manual as "COMMON OPTIONS"
# will passed raw; must qouted manually
LXC_PARAM="-q"
# if lxcpath given
if [ -n "$lxcpath" ]; then
LXC_PARAM="$LXC_PARAM -P \"$lxcpath\""
fi

View file

@ -0,0 +1 @@
$__object_id == name ? sperate parameter required?? multiple same names possible due to --lxcpath!

View file

@ -0,0 +1,125 @@
cdist-type__lxc_container(7)
============================
NAME
----
cdist-type__lxc_container - Controls the configuration of a lxc container
DESCRIPTION
-----------
TBA.
REQUIRED PARAMETERS
-------------------
None.
OPTIONAL PARAMETERS
-------------------
name
String which will used as container name instead of the object id. This should only required
if multiple lxc instances used from different users/directories (in junction with `--lxcpath`).
user
The unix user name in which lxc commands are executed. Each user have a different lxc instance.
state
The state of the container, if it should exist or not.
running
The container exist and is running (default)
stopped
The container exist, but does not run
frozen
The container exist and is frozen
present
The container exist, but it is ignored if the container will run or not
absent
The container does not exist
lxcpath
Set an other directory as lxc container location instead of the program default. This will passed
to all lxc commands who do smth. with containers.
config
Contains configuration file paths and/or single configuration lines to assemble the lxc container
configuration file. There is no deep dive into files referenced with `lxc.include`. Can be used
multiple times.
config-absent
Contains configuration file paths and/ro single configuration lines which makes the same as the
`--config` parameter execpt all configuration lines will be removed instead of being added, Can
be used multiple times.
BOOLEAN PARAMETERS
------------------
None.
TEMPLATE PARAMETERS
-------------------
This or the *CLONE PARAMETERS* are required to create an container and must be present if the container
should be created. If the template parameters are choosen, `--template` must be present. Then, none of
the *CLONE PARAMETERS* must be present.
Because the templates vary in the possiblities of arguments and unkown arguments causing the abort of the
container creation, the type will throw an error if the compatibility is not garanteed to the given
template.
The template options are only applied if the container will be created, there are not applied when
the container is already present.
template
The template which is used to create the the container. The name of the template must passed with
this argument and should exist on the target host.
default-config
Alternative path to the user-defined default config. For the root user, this is commonly at
`/etc/lxc/default.conf`. It will be included into the container configuration file at creation
time.
no-default-config
**(Boolean value)** This parameter avoids using a default config file by using an empty file instead.
template-opts
Raw options which get passed to the template directly. Can be used multiple times. The argument must
contain a single string (*at best, everything is inside one quote*), else it will interpreted as an
further argument for the type. Some values should be quoted inside the quotes, too.
release
TBA.
arch
TBA.
CLONE PARAMETERS
----------------
This or the *TEMPLATE PARAMETERS* are required to create an container and must be present if the container
should be created. If the clone parameters are choosen, `--clone` must be present. Then, none of the
*TEMPLATE PARAMETERS* must be present.
clone
Instead of creating a new container with a given template, clone an other container and use him. The
argument takes the container name, which will be cloned. He should exist.
clonepath
The container path for the container to clone. It is like the `--lxcpath` parameter, but for the container
which will be cloned, not the target container.
MESSAGES
--------
create
The container was created by a template or clone.
destroy
The container was destroyed.
config
The container configuration changed.

View file

@ -0,0 +1,106 @@
#!/bin/sh -e
# manifest
# Manifest; check if everything is valid
# Exit codes:
# 0: successful or warnings
# 2: parameters in wrong context given
# basepath of the parameter folder (shortcut)
param="$__object/parameter/"
# ====================== #
# == WARNING CHECKS == #
# ====================== #
# ==================== #
# == ERROR CHECKS == #
# ==================== #
# valid check if only --template or --clone given
if [ -f "$param/template" ] && [ -f "$param/clone" ]; then
# error and exit
>&2 echo "error: can not create and clone a container at once!"
>&2 echo "error: --template and --clone can not work together"
exit 2
fi
# no clone option if --template given
if [ -f "$param/template" ]; then
if [ -f "$param/clonepath" ]
then
>&2 echo "error: container will created by template, no clone options required!"
exit 2
fi
fi
# no template options if --clone given
if [ -f "$__object/parameter/clone" ]; then
if [ -f "$param/template-opts" ] \
|| [ -f "$param/default-config" ] \
|| [ -f "$param/no-default-config" ] \
|| [ -f "$param/release" ] \
|| [ -f "$param/arch" ]
then
>&2 echo "error: container will created by clone, no template options required!"
exit 2
fi
fi
# ============================== #
# == CONFIGURATION HANDLING == #
# ============================== #
# Function to read multiple parameter input for configuration and print it to a single file.
# It will handle file paths as well as the stdin. Instead of the file, the content will be printed.
#
# Parameters:
# 1: parameter name
# 2: file to print
write_multi_param() {
touch "$2"
while read line; do
if [ "$line" = "-" ]; then
# append stdin
cat "$__object/stdin" >> "$2"
elif [ -f "$line" ]; then
# append file content
cat "$line" >> "$2"
else
# print out content
printf "%s\n" "$line" >> "$2"
fi
done < "$__object/parameter/$1"
}
# Function to get rid of whitespaces inside of key-value pairs. It will clear all of these.
#
# Parameters:
# 1: the file which should be handled
trimm_whitespaces() {
cp "$1" "$1"~ # backup file to see original content
grep -E -v "^([[:blank:]]*)(#|$)" "$1" \
| sed 's/^[[:blank:]]*//; s/[[:blank:]]*=[[:blank:]]*/ = /; s/[[:blank:]]*$//'
}
# Only required if container will not be absent
# get the wanted configuration lines
if [ "$(cat "$__object/parameter/state")" != "absent" ]; then
# Create the files directory
mkdir "$__object/files/"
# Create the file of the locally configuration
conffile="$__object/files/config-present"
write_multi_param config "$conffile"
trimm_whitespaces "$conffile" > "$conffile"
# Create the file of the absent configuration
absentfile="$__object/files/config-absent"
write_multi_param config-absent "$absentfile"
trimm_whitespaces "$absentfile" > "$absentfile"
fi

View file

@ -0,0 +1 @@
no-default-config

View file

@ -0,0 +1 @@
present

View file

@ -0,0 +1 @@
root

View file

@ -0,0 +1,10 @@
name
user
state
lxcpath
template
default-config
release
arch
clone
clonepath

View file

@ -0,0 +1,3 @@
config
config-absent
template-opts

View file

@ -0,0 +1,28 @@
# List of all featues that should be implemented
storage:
- backing_storage
- other settings prior to storage
template:
- type: a.E. debian, ubuntu -> what on change?
- release
- arch
- possible ssh auth key?
- possible root_password?
- possible packages?
- possible mirrors?
- other options??
auto..:
- group
- start
lxc config ..
how to find lxc containers path?
lxc-copy: ephemeral containers? -> seperate type if it makes sense
If config already created, it's considered the container is already created
-> first create; then setup
detection if template changed??
lxc configuration at startup:
flag -f can used to set a default config (instead the system default)
there is no problem to change config before the first startup