From aafa88b648b83af8c854d533ab2e4a6d939dbcab Mon Sep 17 00:00:00 2001 From: Joachim Wiberg Date: Wed, 24 Jan 2024 14:10:07 +0100 Subject: [PATCH] confd: add support for container volumes This commit adds support for writable container volumes. A volume, when compared to a mount, is a writable directory created when the container starts and is automatically rsync'ed with the underlying directory it is mounted on on first use. A mount otoh does not rsync so it results only in an empty directory inside the container. The podman/docker mount feature will be used later to bind mount single files or sharing directories from the host, e.g., /sys/class/leds/ to one of more containers. Note: unused volumes are automatically pruned. Hence, a volume currently cannot be moved to another container. Signed-off-by: Joachim Wiberg --- board/common/rootfs/usr/sbin/container | 31 +++++++++++++++++-- src/confd/src/infix-containers.c | 5 +++ .../yang/infix-containers@2023-12-14.yang | 28 ++++++++++++++++- src/klish-plugin-infix/xml/infix.xml | 25 ++++++++------- 4 files changed, 74 insertions(+), 15 deletions(-) diff --git a/board/common/rootfs/usr/sbin/container b/board/common/rootfs/usr/sbin/container index 4dc4a06d..12c836b0 100755 --- a/board/common/rootfs/usr/sbin/container +++ b/board/common/rootfs/usr/sbin/container @@ -43,10 +43,10 @@ create() fi # --syslog --log-level info - log "Calling \"podman create --name $name --conmon-pidfile=$pidfn $ro $hostname $entrypoint $env $network $port $args $image $*\"" + log "Calling \"podman create --name $name --conmon-pidfile=$pidfn $ro $vol $hostname $entrypoint $env $network $port $args $image $*\"" set -x # shellcheck disable=SC2048 - if podman create --name "$name" --conmon-pidfile="$pidfn" $ro $hostname $entrypoint $env $network $port $args "$image" $*; then + if podman create --name "$name" --conmon-pidfile="$pidfn" $ro $vol $hostname $entrypoint $env $network $port $args "$image" $*; then log "Successfully created container $name from $image" rm -f "/run/containers/env/${name}.env" initctl show "container:$name" |grep -q manual:yes || initctl -bq start "container:$name" @@ -93,6 +93,7 @@ options: Syntax: [[ip:][hostPort]:]containerPort[/protocol] --read-only Do not create a writable layer -s, --simple Show output in simplified format + -v, --volume NAME:PATH Create named volume mounted inside container on PATH commands: create NAME IMAGE NET Create container NAME using IMAGE with networks NET @@ -102,9 +103,10 @@ commands: remove IMAGE Remove an (unused) container image restart NAME Restart a crashed container run NAME CMD Execute a command (interactively) in container - show [image] Show containers or container images + show [image | volume] Show containers, images, or volumes start NAME Start a container stop NAME Stop a container + volume [prune] Prune unused volumes EOF } @@ -153,6 +155,10 @@ while [ "$1" != "" ]; do -s | --simple) simple=true ;; + -v | --volume) + shift + vol="$vol -v $1" + ;; *) break ;; @@ -214,6 +220,13 @@ case $cmd in podman images $all fi ;; + volume*) + printf "%-20s CONTAINER\n" "VOLUME" + for v in $(podman volume ls --format "{{.Name}}"); do + printf "%-20s" "$v" + podman ps -a --filter volume="$v" --format '{{.Names}}' | sed 's/^/ /' + done + ;; *) if [ -n "$simple" ]; then podman ps $all --format "{{.ID}} {{.Names}} {{.Image}}" \ @@ -233,6 +246,18 @@ case $cmd in stop) initctl -bq stop "container:$1" || podman kill "$1" ;; + volume) + cmd=$1 + shift + case $cmd in + prune) + podman $force volume prune + ;; + *) + false + ;; + esac + ;; *) usage exit 1 diff --git a/src/confd/src/infix-containers.c b/src/confd/src/infix-containers.c index 74172e16..95f8a022 100644 --- a/src/confd/src/infix-containers.c +++ b/src/confd/src/infix-containers.c @@ -62,6 +62,9 @@ static int add(const char *name, struct lyd_node *cif) if (lydx_is_enabled(cif, "read-only")) fprintf(fp, " --read-only"); + LYX_LIST_FOR_EACH(lyd_child(cif), node, "volume") + fprintf(fp, " -v %s-%s:%s", name, lydx_get_cattr(node, "name"), lydx_get_cattr(node, "dir")); + ap = NULL; LYX_LIST_FOR_EACH(lyd_child(cif), node, "env") { if (!ap) { @@ -243,6 +246,8 @@ void infix_containers_launch(void) if (movefile(next, JOB_QUEUE)) ERRNO("Failed moving %s to job queue %s", next, JOB_QUEUE); } + + systemf("container -f volume prune"); } int infix_containers_init(struct confd *confd) diff --git a/src/confd/yang/infix-containers@2023-12-14.yang b/src/confd/yang/infix-containers@2023-12-14.yang index c3dc5589..62282d90 100644 --- a/src/confd/yang/infix-containers@2023-12-14.yang +++ b/src/confd/yang/infix-containers@2023-12-14.yang @@ -163,10 +163,36 @@ module infix-containers { } leaf read-only { - description "Create a read-only container."; + description "Create a read-only container. Use volumes for writable directories."; type boolean; } + list volume { + description "Create a writable volume that survive container upgrades. + + Volumes are retained over the lifetime of a container and survive + both upgrading the image as well as configuration changes, which + otherwise wipe the default writable layer a container is given. + + Volumes combine well with 'read-only' containers, when you know + which files/directories you want to persist."; + key name; + + leaf name { + description "Single word, [A-Za-z_], to identify this volume. + For example, a volume for /etc may be labled etc. + + Note: will be prefixed with container name globally."; + type string; + } + + leaf dir { + description "Directory to mount the volume on inside the container, e.g., /etc"; + mandatory true; + type string; + } + } + container statistics { description "Statistics of the container"; config false; diff --git a/src/klish-plugin-infix/xml/infix.xml b/src/klish-plugin-infix/xml/infix.xml index a1d8384c..c74abe7d 100644 --- a/src/klish-plugin-infix/xml/infix.xml +++ b/src/klish-plugin-infix/xml/infix.xml @@ -183,7 +183,7 @@ replace config - + @@ -327,23 +327,26 @@ - podman ps + container show - - podman images - - - podman images -a - - - - podman ps -a + container -a show cat /log/container + + container show images + + + container -a show images + + + + + container show volumes +