diff options
author | Frantisek Sumsal <frantisek@sumsal.cz> | 2023-05-16 17:26:25 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-05-16 17:26:25 +0200 |
commit | a5a4d5a18e6270b3623dc5c48f1c61344f1d0555 (patch) | |
tree | 136327df8a5acd02c2692c6ef9c34b9a75c8dade | |
parent | 329f4b06f5124a8db042e8bd42fbc3265744aaa6 (diff) | |
parent | cd70372b934bded2249f26c72d4b6ab9bdf50a13 (diff) | |
download | systemd-a5a4d5a18e6270b3623dc5c48f1c61344f1d0555.tar.gz |
Merge pull request #27651 from mrc0mmand/more-nspawn-tests
nspawn: OCI related fixes & tests
-rw-r--r-- | src/nspawn/nspawn-oci.c | 33 | ||||
-rw-r--r-- | src/nspawn/nspawn-settings.c | 26 | ||||
-rw-r--r-- | src/nspawn/nspawn.c | 1 | ||||
-rw-r--r-- | test/fuzz/fuzz-nspawn-oci/basic.json | 247 | ||||
-rwxr-xr-x | test/units/testsuite-13.nspawn-oci.sh | 383 | ||||
-rwxr-xr-x | test/units/testsuite-13.nspawn.sh | 21 |
6 files changed, 641 insertions, 70 deletions
diff --git a/src/nspawn/nspawn-oci.c b/src/nspawn/nspawn-oci.c index 3c6bfd3eaf..5e21538597 100644 --- a/src/nspawn/nspawn-oci.c +++ b/src/nspawn/nspawn-oci.c @@ -605,7 +605,7 @@ static int oci_namespace_type(const char *name, JsonVariant *v, JsonDispatchFlag *nsflags = CLONE_NEWCGROUP; else return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL), - "Unknown cgroup type, refusing: %s", n); + "Unknown namespace type, refusing: %s", n); return 0; } @@ -663,7 +663,7 @@ static int oci_namespaces(const char *name, JsonVariant *v, JsonDispatchFlags fl if (!FLAGS_SET(n, CLONE_NEWNS)) return json_log(v, flags, SYNTHETIC_ERRNO(EOPNOTSUPP), - "Containers without file system namespace aren't supported."); + "Containers without a mount namespace aren't supported."); s->private_network = FLAGS_SET(n, CLONE_NEWNET); s->userns_mode = FLAGS_SET(n, CLONE_NEWUSER) ? USER_NAMESPACE_FIXED : USER_NAMESPACE_NO; @@ -819,7 +819,7 @@ static int oci_device_file_mode(const char *name, JsonVariant *v, JsonDispatchFl return json_log(v, flags, SYNTHETIC_ERRNO(ERANGE), "fileMode out of range, refusing."); - *mode = m; + *mode = (*mode & ~07777) | m; return 0; } @@ -874,7 +874,7 @@ static int oci_devices(const char *name, JsonVariant *v, JsonDispatchFlags flags /* Suppress a couple of implicit device nodes */ r = devname_from_devnum(node->mode, makedev(node->major, node->minor), &path); if (r < 0) - json_log(e, flags|JSON_DEBUG, 0, "Failed to resolve device node %u:%u, ignoring: %m", node->major, node->minor); + json_log(e, flags|JSON_DEBUG, r, "Failed to resolve device node %u:%u, ignoring: %m", node->major, node->minor); else { if (PATH_IN_SET(path, "/dev/null", @@ -1177,13 +1177,13 @@ static int oci_cgroup_memory(const char *name, JsonVariant *v, JsonDispatchFlags }; static const JsonDispatch table[] = { - { "limit", JSON_VARIANT_NUMBER, oci_cgroup_memory_limit, offsetof(struct memory_data, limit), 0 }, - { "reservation", JSON_VARIANT_NUMBER, oci_cgroup_memory_limit, offsetof(struct memory_data, reservation), 0 }, - { "swap", JSON_VARIANT_NUMBER, oci_cgroup_memory_limit, offsetof(struct memory_data, swap), 0 }, - { "kernel", JSON_VARIANT_NUMBER, oci_unsupported, 0, JSON_PERMISSIVE }, - { "kernelTCP", JSON_VARIANT_NUMBER, oci_unsupported, 0, JSON_PERMISSIVE }, - { "swapiness", JSON_VARIANT_NUMBER, oci_unsupported, 0, JSON_PERMISSIVE }, - { "disableOOMKiller", JSON_VARIANT_NUMBER, oci_unsupported, 0, JSON_PERMISSIVE }, + { "limit", JSON_VARIANT_NUMBER, oci_cgroup_memory_limit, offsetof(struct memory_data, limit), 0 }, + { "reservation", JSON_VARIANT_NUMBER, oci_cgroup_memory_limit, offsetof(struct memory_data, reservation), 0 }, + { "swap", JSON_VARIANT_NUMBER, oci_cgroup_memory_limit, offsetof(struct memory_data, swap), 0 }, + { "kernel", JSON_VARIANT_NUMBER, oci_unsupported, 0, JSON_PERMISSIVE }, + { "kernelTCP", JSON_VARIANT_NUMBER, oci_unsupported, 0, JSON_PERMISSIVE }, + { "swapiness", JSON_VARIANT_NUMBER, oci_unsupported, 0, JSON_PERMISSIVE }, + { "disableOOMKiller", JSON_VARIANT_BOOLEAN, oci_unsupported, 0, JSON_PERMISSIVE }, {} }; @@ -1589,7 +1589,7 @@ static int oci_sysctl(const char *name, JsonVariant *v, JsonDispatchFlags flags, assert_se(m = json_variant_string(w)); - if (sysctl_key_valid(k)) + if (!sysctl_key_valid(k)) return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL), "sysctl key invalid, refusing: %s", k); @@ -1829,6 +1829,7 @@ static int oci_seccomp_syscalls(const char *name, JsonVariant *v, JsonDispatchFl { "names", JSON_VARIANT_ARRAY, json_dispatch_strv, offsetof(struct syscall_rule, names), JSON_MANDATORY }, { "action", JSON_VARIANT_STRING, oci_seccomp_action, offsetof(struct syscall_rule, action), JSON_MANDATORY }, { "args", JSON_VARIANT_ARRAY, oci_seccomp_args, 0, 0 }, + {} }; struct syscall_rule rule = { .action = UINT32_MAX, @@ -2083,7 +2084,7 @@ static int oci_hooks_array(const char *name, JsonVariant *v, JsonDispatchFlags f .timeout = USEC_INFINITY, }; - r = json_dispatch(e, table, oci_unexpected, flags, userdata); + r = json_dispatch(e, table, oci_unexpected, flags, new_item); if (r < 0) { free(new_item->path); strv_free(new_item->args); @@ -2100,9 +2101,9 @@ static int oci_hooks_array(const char *name, JsonVariant *v, JsonDispatchFlags f static int oci_hooks(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) { static const JsonDispatch table[] = { - { "prestart", JSON_VARIANT_OBJECT, oci_hooks_array, 0, 0 }, - { "poststart", JSON_VARIANT_OBJECT, oci_hooks_array, 0, 0 }, - { "poststop", JSON_VARIANT_OBJECT, oci_hooks_array, 0, 0 }, + { "prestart", JSON_VARIANT_ARRAY, oci_hooks_array, 0, 0 }, + { "poststart", JSON_VARIANT_ARRAY, oci_hooks_array, 0, 0 }, + { "poststop", JSON_VARIANT_ARRAY, oci_hooks_array, 0, 0 }, {} }; diff --git a/src/nspawn/nspawn-settings.c b/src/nspawn/nspawn-settings.c index 7500eabd18..161b1c1c70 100644 --- a/src/nspawn/nspawn-settings.c +++ b/src/nspawn/nspawn-settings.c @@ -97,27 +97,25 @@ int settings_load(FILE *f, const char *path, Settings **ret) { return 0; } -static void free_oci_hooks(OciHook *h, size_t n) { - size_t i; +static void free_oci_hooks(OciHook *hooks, size_t n) { + assert(hooks || n == 0); - assert(h || n == 0); - - for (i = 0; i < n; i++) { - free(h[i].path); - strv_free(h[i].args); - strv_free(h[i].env); + FOREACH_ARRAY(hook, hooks, n) { + free(hook->path); + strv_free(hook->args); + strv_free(hook->env); } - free(h); + free(hooks); } -void device_node_array_free(DeviceNode *node, size_t n) { - size_t i; +void device_node_array_free(DeviceNode *nodes, size_t n) { + assert(nodes || n == 0); - for (i = 0; i < n; i++) - free(node[i].path); + FOREACH_ARRAY(node, nodes, n) + free(node->path); - free(node); + free(nodes); } Settings* settings_free(Settings *s) { diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 49802d6fdf..5d49e05064 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -4651,6 +4651,7 @@ static int merge_settings(Settings *settings, const char *path) { device_node_array_free(arg_extra_nodes, arg_n_extra_nodes); arg_extra_nodes = TAKE_PTR(settings->extra_nodes); arg_n_extra_nodes = settings->n_extra_nodes; + settings->n_extra_nodes = 0; return 0; } diff --git a/test/fuzz/fuzz-nspawn-oci/basic.json b/test/fuzz/fuzz-nspawn-oci/basic.json index f42739e03a..24bacf39c1 100644 --- a/test/fuzz/fuzz-nspawn-oci/basic.json +++ b/test/fuzz/fuzz-nspawn-oci/basic.json @@ -1,6 +1,8 @@ { "ociVersion": "1.0.0", + "hostname" : "foo", + "root": { "path": "rootfs", "readonly": true @@ -33,11 +35,42 @@ "cwd": "/tmp/src", - "rlimits": [ + "noNewPrivileges" : true, + "oomScoreAdj" : 20, + "capabilities" : { + "bounding" : [ + "CAP_AUDIT_WRITE", + "CAP_KILL", + "CAP_NET_BIND_SERVICE" + ], + "permitted" : [ + "CAP_AUDIT_WRITE", + "CAP_KILL", + "CAP_NET_BIND_SERVICE" + ], + "inheritable" : [ + "CAP_AUDIT_WRITE", + "CAP_KILL", + "CAP_NET_BIND_SERVICE" + ], + "effective" : [ + "CAP_AUDIT_WRITE", + "CAP_KILL" + ], + "ambient" : [ + "CAP_NET_BIND_SERVICE" + ] + }, + "rlimits" : [ { - "type": "RLIMIT_NOFILE", - "hard": 1020, - "soft": 1020 + "type" : "RLIMIT_NOFILE", + "soft" : 1024, + "hard" : 1024 + }, + { + "type" : "RLIMIT_RTPRIO", + "soft" : 5, + "hard" : 10 } ] }, @@ -110,32 +143,206 @@ } ], - "hooks": {}, - - "linux": { - "resources": { - "devices": [ + "linux" : { + "namespaces" : [ + { + "type" : "mount" + }, + { + "type" : "network", + "path" : "$NETNS" + }, + { + "type" : "pid" + }, + { + "type" : "uts" + } + ], + "uidMappings" : [ + { + "containerID" : 0, + "hostID" : 1000, + "size" : 100 + } + ], + "gidMappings" : [ + { + "containerID" : 0, + "hostID" : 1000, + "size" : 100 + } + ], + "devices" : [ + { + "type" : "c", + "path" : "/dev/zero", + "major" : 1, + "minor" : 5, + "fileMode" : 444 + }, + { + "type" : "b", + "path" : "$DEV", + "major" : 4, + "minor" : 2, + "fileMode" : 666, + "uid" : 0, + "gid" : 0 + } + ], + "resources" : { + "devices" : [ + { + "allow" : false, + "access" : "m" + }, + { + "allow" : true, + "type" : "b", + "major" : 4, + "minor" : 2, + "access" : "rwm" + } + ], + "memory" : { + "limit" : 134217728, + "reservation" : 33554432, + "swap" : 268435456 + }, + "cpu" : { + "shares" : 1024, + "quota" : 1000000, + "period" : 500000, + "cpus" : "0-7" + }, + "blockIO" : { + "weight" : 10, + "weightDevice" : [ + { + "major" : 4, + "minor" : 2, + "weight" : 500 + } + ], + "throttleReadBpsDevice" : [ + { + "major" : 4, + "minor" : 2, + "rate" : 500 + } + ], + "throttleWriteBpsDevice" : [ + { + "major" : 4, + "minor" : 2, + "rate" : 500 + } + ], + "throttleReadIOPSDevice" : [ + { + "major" : 4, + "minor" : 2, + "rate" : 500 + } + ], + "throttleWriteIOPSDevice" : [ + { + "major" : 4, + "minor" : 2, + "rate" : 500 + } + ] + }, + "pids" : { + "limit" : 1024 + } + }, + "sysctl" : { + "kernel.domainname" : "foo.bar", + "vm.swappiness" : "60" + }, + "seccomp" : { + "defaultAction" : "SCMP_ACT_ALLOW", + "architectures" : [ + "SCMP_ARCH_ARM", + "SCMP_ARCH_X86_64" + ], + "syscalls" : [ { - "allow": false, - "access": "rwm" + "names" : [ + "lchown", + "chmod" + ], + "action" : "SCMP_ACT_ERRNO", + "args" : [ + { + "index" : 0, + "value" : 1, + "op" : "SCMP_CMP_NE" + }, + { + "index" : 1, + "value" : 2, + "valueTwo" : 3, + "op" : "SCMP_CMP_MASKED_EQ" + } + ] } ] }, - "namespaces": [ + "rootfsPropagation" : "shared", + "maskedPaths" : [ + "/proc/kcore", + "/root/nonexistent" + ], + "readonlyPaths" : [ + "/proc/sys", + "/opt/readonly" + ] + }, + "hooks" : { + "prestart" : [ { - "type": "pid" + "path" : "/bin/sh", + "args" : [ + "-xec", + "echo $PRESTART_FOO >/prestart" + ], + "env" : [ + "PRESTART_FOO=prestart_bar", + "ALSO_FOO=also_bar" + ], + "timeout" : 666 }, { - "type": "ipc" - }, + "path" : "/bin/touch", + "args" : [ + "/tmp/also-prestart" + ] + } + ], + "poststart" : [ { - "type": "mount" + "path" : "/bin/sh", + "args" : [ + "touch", + "/poststart" + ] + } + ], + "poststop" : [ + { + "path" : "/bin/sh", + "args" : [ + "touch", + "/poststop" + ] } ] }, - - "annotations": { - "com.example.key1": "value1", - "com.example.key2": "value2" + "annotations" : { + "hello.world" : "1", + "foo" : "bar" } } diff --git a/test/units/testsuite-13.nspawn-oci.sh b/test/units/testsuite-13.nspawn-oci.sh new file mode 100755 index 0000000000..cbfdb18290 --- /dev/null +++ b/test/units/testsuite-13.nspawn-oci.sh @@ -0,0 +1,383 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +# shellcheck disable=SC2016 +set -eux +set -o pipefail + +export SYSTEMD_LOG_LEVEL=debug +export SYSTEMD_LOG_TARGET=journal +CREATE_BB_CONTAINER="/usr/lib/systemd/tests/testdata/create-busybox-container" + +# shellcheck disable=SC2317 +at_exit() { + set +e + + mountpoint -q /var/lib/machines && umount /var/lib/machines + [[ -n "${DEV:-}" ]] && rm -f "$DEV" + [[ -n "${NETNS:-}" ]] && umount "$NETNS" && rm -f "$NETNS" + [[ -n "${TMPDIR:-}" ]] && rm -fr "$TMPDIR" +} + +trap at_exit EXIT + +# Mount tmpfs over /var/lib/machines to not pollute the image +mkdir -p /var/lib/machines +mount -t tmpfs tmpfs /var/lib/machines + +# Setup a couple of dirs/devices for the OCI containers +DEV="$(mktemp -u /dev/oci-dev-XXX)" +mknod -m 666 "$DEV" b 42 42 +NETNS="$(mktemp /var/tmp/netns.XXX)" +mount --bind /proc/self/ns/net "$NETNS" +TMPDIR="$(mktemp -d)" +touch "$TMPDIR/hello" +OCI="$(mktemp -d /var/lib/machines/testsuite-13.oci-bundle.XXX)" +"$CREATE_BB_CONTAINER" "$OCI/rootfs" +mkdir -p "$OCI/rootfs/opt/var" +mkdir -p "$OCI/rootfs/opt/readonly" + +# Let's start with a simple config +cat >"$OCI/config.json" <<EOF +{ + "ociVersion" : "1.0.0", + "root" : { + "path" : "rootfs" + }, + "mounts" : [ + { + "destination" : "/root", + "type" : "tmpfs", + "source" : "tmpfs" + } + ] +} +EOF +systemd-nspawn --oci-bundle="$OCI" sh -xec 'mountpoint /root' + +# And now for something a bit more involved +# Notes: +# - the hooks are parsed & processed, but never executed +# - set sysctl's are parsed but never used? +# - same goes for arg_sysctl in nspawn.c +cat >"$OCI/config.json" <<EOF +{ + "ociVersion" : "1.0.0", + "hostname" : "my-oci-container", + "root" : { + "path" : "rootfs", + "readonly" : false + }, + "mounts" : [ + { + "destination" : "/root", + "type" : "tmpfs", + "source" : "tmpfs" + }, + { + "destination" : "/var", + "type" : "none", + "source" : "$TMPDIR", + "options" : ["rbind", "rw"] + } + ], + "process" : { + "terminal" : false, + "consoleSize" : { + "height" : 25, + "width" : 80 + }, + "user" : { + "uid" : 0, + "gid" : 0, + "additionalGids" : [5, 6] + }, + "env" : [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "FOO=bar" + ], + "cwd" : "/root", + "args" : [ + "sh", + "-xe", + "/entrypoint.sh" + ], + "noNewPrivileges" : true, + "oomScoreAdj" : 20, + "capabilities" : { + "bounding" : [ + "CAP_AUDIT_WRITE", + "CAP_KILL", + "CAP_NET_BIND_SERVICE" + ], + "permitted" : [ + "CAP_AUDIT_WRITE", + "CAP_KILL", + "CAP_NET_BIND_SERVICE" + ], + "inheritable" : [ + "CAP_AUDIT_WRITE", + "CAP_KILL", + "CAP_NET_BIND_SERVICE" + ], + "effective" : [ + "CAP_AUDIT_WRITE", + "CAP_KILL" + ], + "ambient" : [ + "CAP_NET_BIND_SERVICE" + ] + }, + "rlimits" : [ + { + "type" : "RLIMIT_NOFILE", + "soft" : 1024, + "hard" : 1024 + }, + { + "type" : "RLIMIT_RTPRIO", + "soft" : 5, + "hard" : 10 + } + ] + }, + "linux" : { + "namespaces" : [ + { + "type" : "mount" + }, + { + "type" : "network", + "path" : "$NETNS" + }, + { + "type" : "pid" + }, + { + "type" : "uts" + } + ], + "uidMappings" : [ + { + "containerID" : 0, + "hostID" : 1000, + "size" : 100 + } + ], + "gidMappings" : [ + { + "containerID" : 0, + "hostID" : 1000, + "size" : 100 + } + ], + "devices" : [ + { + "type" : "c", + "path" : "/dev/zero", + "major" : 1, + "minor" : 5, + "fileMode" : 444 + }, + { + "type" : "b", + "path" : "$DEV", + "major" : 4, + "minor" : 2, + "fileMode" : 666, + "uid" : 0, + "gid" : 0 + } + ], + "resources" : { + "devices" : [ + { + "allow" : false, + "access" : "m" + }, + { + "allow" : true, + "type" : "b", + "major" : 4, + "minor" : 2, + "access" : "rwm" + } + ], + "memory" : { + "limit" : 134217728, + "reservation" : 33554432, + "swap" : 268435456 + }, + "cpu" : { + "shares" : 1024, + "quota" : 1000000, + "period" : 500000, + "cpus" : "0-7" + }, + "blockIO" : { + "weight" : 10, + "weightDevice" : [ + { + "major" : 4, + "minor" : 2, + "weight" : 500 + } + ], + "throttleReadBpsDevice" : [ + { + "major" : 4, + "minor" : 2, + "rate" : 500 + } + ], + "throttleWriteBpsDevice" : [ + { + "major" : 4, + "minor" : 2, + "rate" : 500 + } + ], + "throttleReadIOPSDevice" : [ + { + "major" : 4, + "minor" : 2, + "rate" : 500 + } + ], + "throttleWriteIOPSDevice" : [ + { + "major" : 4, + "minor" : 2, + "rate" : 500 + } + ] + }, + "pids" : { + "limit" : 1024 + } + }, + "sysctl" : { + "kernel.domainname" : "foo.bar", + "vm.swappiness" : "60" + }, + "seccomp" : { + "defaultAction" : "SCMP_ACT_ALLOW", + "architectures" : [ + "SCMP_ARCH_ARM", + "SCMP_ARCH_X86_64" + ], + "syscalls" : [ + { + "names" : [ + "lchown", + "chmod" + ], + "action" : "SCMP_ACT_ERRNO", + "args" : [ + { + "index" : 0, + "value" : 1, + "op" : "SCMP_CMP_NE" + }, + { + "index" : 1, + "value" : 2, + "valueTwo" : 3, + "op" : "SCMP_CMP_MASKED_EQ" + } + ] + } + ] + }, + "rootfsPropagation" : "shared", + "maskedPaths" : [ + "/proc/kcore", + "/root/nonexistent" + ], + "readonlyPaths" : [ + "/proc/sys", + "/opt/readonly" + ] + }, + "hooks" : { + "prestart" : [ + { + "path" : "/bin/sh", + "args" : [ + "-xec", + "echo \$PRESTART_FOO >/prestart" + ], + "env" : [ + "PRESTART_FOO=prestart_bar", + "ALSO_FOO=also_bar" + ], + "timeout" : 666 + }, + { + "path" : "/bin/touch", + "args" : [ + "/tmp/also-prestart" + ] + } + ], + "poststart" : [ + { + "path" : "/bin/sh", + "args" : [ + "touch", + "/poststart" + ] + } + ], + "poststop" : [ + { + "path" : "/bin/sh", + "args" : [ + "touch", + "/poststop" + ] + } + ] + }, + "annotations" : { + "hello.world" : "1", + "foo" : "bar" + } +} +EOF +# Create a simple "entrypoint" script that validates that the container +# is created correctly according to the OCI config +cat >"$OCI/rootfs/entrypoint.sh" <<EOF +#!/bin/sh -e + +# Mounts +mountpoint /root +mountpoint /var +test -e /var/hello + +# Process +[[ "\$PWD" == /root ]] +[[ "\$FOO" == bar ]] + +# Process - rlimits +[[ "\$(ulimit -S -n)" -eq 1024 ]] +[[ "\$(ulimit -H -n)" -eq 1024 ]] +[[ "\$(ulimit -S -r)" -eq 5 ]] +[[ "\$(ulimit -H -r)" -eq 10 ]] +[[ "\$(hostname)" == my-oci-container ]] + +# Linux - devices +test -c /dev/zero +test -b "$DEV" +[[ "\$(stat -c '%t:%T' "$DEV")" == 4:2 ]] + +# Linux - maskedPaths +test -e /proc/kcore +cat /proc/kcore && exit 1 +test ! -e /root/nonexistent + +# Linux - readonlyPaths +touch /opt/readonly/foo && exit 1 + +exit 0 +EOF +systemd-nspawn --oci-bundle="$OCI" diff --git a/test/units/testsuite-13.nspawn.sh b/test/units/testsuite-13.nspawn.sh index 76ba143751..8f8daf05cc 100755 --- a/test/units/testsuite-13.nspawn.sh +++ b/test/units/testsuite-13.nspawn.sh @@ -46,7 +46,7 @@ mkdir -p /var/lib/machines mount -t tmpfs tmpfs /var/lib/machines testcase_sanity_check() { - local template root image oci uuid tmpdir + local template root image uuid tmpdir tmpdir="$(mktemp -d)" template="$(mktemp -d /tmp/nspawn-template.XXX)" @@ -59,24 +59,6 @@ testcase_sanity_check() { mount -o loop "$image" /mnt cp -r "$template"/* /mnt/ umount /mnt - # Create a simple OCI bundle - oci="$(mktemp -d /var/lib/machines/testsuite-13.oci-bundle.XXX)" - "$CREATE_BB_CONTAINER" "$oci/rootfs" - cat >"$oci/config.json" <<EOF -{ - "ociVersion" : "1.0.0", - "root" : { - "path" : "rootfs" - }, - "mounts" : [ - { - "destination" : "/root", - "type" : "tmpfs", - "source" : "tmpfs" - } - ] -} -EOF systemd-nspawn --help --no-pager systemd-nspawn --version @@ -101,7 +83,6 @@ EOF sh -xec 'touch /nope') test ! -e "$root/nope" systemd-nspawn --image="$image" sh -xec 'echo hello' - systemd-nspawn --oci-bundle="$oci" sh -xec 'mountpoint /root' # --volatile= touch "$root/usr/has-usr" |