From cd4e8b0a9f856274735026d11d3b3c95675ceee2 Mon Sep 17 00:00:00 2001 From: Joachim Wiberg Date: Mon, 29 Jan 2024 11:32:55 +0100 Subject: [PATCH] confd: add support for mounting read-only files in containers In the container configuration context: edit file ntp.conf set path /etc/ntp.conf set content The last command opens a text editor where you can paste the contents of the file. This is stored base64 encoded in the datastore as well as in JSON/XML. Signed-off-by: Joachim Wiberg --- board/common/rootfs/usr/sbin/container | 9 +++++-- package/execd/tmpfiles.conf | 1 + src/confd/src/infix-containers.c | 21 ++++++++++++++++ .../yang/infix-containers@2023-12-14.yang | 24 +++++++++++++++++++ 4 files changed, 53 insertions(+), 2 deletions(-) diff --git a/board/common/rootfs/usr/sbin/container b/board/common/rootfs/usr/sbin/container index 23521d65..dfcf0429 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 $vol $hostname $entrypoint $env $network $port $args $image $*\"" + log "Calling \"podman create --name $name --conmon-pidfile=$pidfn $ro $vol $mount $hostname $entrypoint $env $network $port $args $image $*\"" set -x # shellcheck disable=SC2048 - if podman create --name "$name" --conmon-pidfile="$pidfn" $ro $vol $hostname $entrypoint $env $network $port $args "$image" $*; then + if podman create --name "$name" --conmon-pidfile="$pidfn" $ro $vol $mount $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" @@ -89,6 +89,7 @@ options: -h, --help Show this help text --hostname NAME Set hostname when creating container --net NETWORK Set network(s) when creating container + -m, --mount HOST:DEST Bind mount a read-only file inside a container -p, --publish PORT Publish ports when creating container Syntax: [[ip:][hostPort]:]containerPort[/protocol] --read-only Do not create a writable layer @@ -141,6 +142,10 @@ while [ "$1" != "" ]; do shift hostname="--hostname $1" ;; + -m | --mount) + shift + mount="--mount=$1" + ;; --net) shift network="$network --net $1" diff --git a/package/execd/tmpfiles.conf b/package/execd/tmpfiles.conf index 0f2b116a..0fb963cf 100644 --- a/package/execd/tmpfiles.conf +++ b/package/execd/tmpfiles.conf @@ -1,4 +1,5 @@ d /run/containers/args 0700 - - +d /run/containers/files 0700 - - d /var/lib/containers/active 0700 - - d /run/containers/inbox 0700 - - d /run/containers/queue 0700 - - diff --git a/src/confd/src/infix-containers.c b/src/confd/src/infix-containers.c index 6e9dbdfa..38a18c7d 100644 --- a/src/confd/src/infix-containers.c +++ b/src/confd/src/infix-containers.c @@ -65,6 +65,27 @@ static int add(const char *name, struct lyd_node *cif) 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")); + LYX_LIST_FOR_EACH(lyd_child(cif), node, "file") { + const char *filenm = lydx_get_cattr(node, "name"); + const char *contdir = "/run/containers/files"; + char nm[strlen(filenm) + strlen(name) + 32]; + char buf[256]; + FILE *pp; + + snprintf(nm, sizeof(nm), "%s/%s-%s", contdir, name, filenm); + snprintf(buf, sizeof(buf), "base64 -d > %s", nm); + pp = popen(buf, "w"); + if (pp) { + const char *data = lydx_get_cattr(node, "content"); + + fputs(data, pp); + pclose(pp); + + fprintf(fp, " -m type=bind,source=%s,destination=%s,readonly=true", + nm, lydx_get_cattr(node, "path")); + } + } + ap = NULL; LYX_LIST_FOR_EACH(lyd_child(cif), node, "env") { if (!ap) { diff --git a/src/confd/yang/infix-containers@2023-12-14.yang b/src/confd/yang/infix-containers@2023-12-14.yang index 62282d90..d5912423 100644 --- a/src/confd/yang/infix-containers@2023-12-14.yang +++ b/src/confd/yang/infix-containers@2023-12-14.yang @@ -193,6 +193,30 @@ module infix-containers { } } + list file { + description "Files to mount inside container."; + key name; + + leaf name { + description "File to store in host's startup-config as binary. + + Note: will be prefixed with container name globally."; + type string; + } + + leaf path { + description "Path to location inside container to mount file on, e.g., /etc/ntpd.conf"; + type string { + pattern '/.*'; + } + } + + leaf content { + description "File contents, in base64 native format (XML/JSON)."; + type binary; + } + } + container statistics { description "Statistics of the container"; config false;