mirror of
https://github.com/systemd/systemd
synced 2024-07-21 10:17:21 +00:00
Merge pull request #27684 from mrc0mmand/more-nspawn-tests
test: further extend systemd-nspawn coverage
This commit is contained in:
commit
ec0bd9611a
|
@ -638,7 +638,7 @@ int mount_all(const char *dest,
|
|||
|
||||
r = chase(mount_table[k].where, dest, CHASE_NONEXISTENT|CHASE_PREFIX_ROOT, &where, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to resolve %s/%s: %m", dest, mount_table[k].where);
|
||||
return log_error_errno(r, "Failed to resolve %s%s: %m", strempty(dest), mount_table[k].where);
|
||||
|
||||
/* Skip this entry if it is not a remount. */
|
||||
if (mount_table[k].what) {
|
||||
|
@ -697,7 +697,7 @@ int mount_all(const char *dest,
|
|||
* for those. */
|
||||
r = chase(mount_table[k].what, dest, CHASE_PREFIX_ROOT, &prefixed, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to resolve %s/%s: %m", dest, mount_table[k].what);
|
||||
return log_error_errno(r, "Failed to resolve %s%s: %m", strempty(dest), mount_table[k].what);
|
||||
}
|
||||
|
||||
r = mount_verbose_full(
|
||||
|
|
|
@ -752,38 +752,48 @@ int remove_veth_links(const char *primary, char **pairs) {
|
|||
}
|
||||
|
||||
static int network_iface_pair_parse(const char* iftype, char ***l, const char *p, const char* ifprefix) {
|
||||
_cleanup_free_ char *a = NULL, *b = NULL;
|
||||
int r;
|
||||
|
||||
r = extract_first_word(&p, &a, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to extract first word in %s parameter: %m", iftype);
|
||||
if (r == 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Short read while reading %s parameter: %m", iftype);
|
||||
if (!ifname_valid(a))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s, interface name not valid: %s", iftype, a);
|
||||
for (;;) {
|
||||
_cleanup_free_ char *word = NULL, *a = NULL, *b = NULL;
|
||||
const char *interface;
|
||||
|
||||
if (isempty(p)) {
|
||||
if (ifprefix)
|
||||
b = strjoin(ifprefix, a);
|
||||
else
|
||||
b = strdup(a);
|
||||
} else
|
||||
b = strdup(p);
|
||||
if (!b)
|
||||
return log_oom();
|
||||
r = extract_first_word(&p, &word, NULL, 0);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse interface name: %m");
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
if (!ifname_valid(b))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s, interface name not valid: %s", iftype, b);
|
||||
interface = word;
|
||||
r = extract_first_word(&interface, &a, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to extract first word in %s parameter: %m", iftype);
|
||||
if (r == 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Short read while reading %s parameter: %m", iftype);
|
||||
if (!ifname_valid(a))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s, interface name not valid: %s", iftype, a);
|
||||
|
||||
r = strv_push_pair(l, a, b);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
if (isempty(interface)) {
|
||||
if (ifprefix)
|
||||
b = strjoin(ifprefix, a);
|
||||
else
|
||||
b = strdup(a);
|
||||
} else
|
||||
b = strdup(interface);
|
||||
if (!b)
|
||||
return log_oom();
|
||||
|
||||
if (!ifname_valid(b))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s, interface name not valid: %s", iftype, b);
|
||||
|
||||
r = strv_consume_pair(l, TAKE_PTR(a), TAKE_PTR(b));
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
a = b = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -90,7 +90,7 @@ static int oci_unsupported(const char *name, JsonVariant *v, JsonDispatchFlags f
|
|||
}
|
||||
|
||||
static int oci_terminal(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
|
||||
Settings *s = userdata;
|
||||
Settings *s = ASSERT_PTR(userdata);
|
||||
|
||||
/* If not specified, or set to true, we'll default to either an interactive or a read-only
|
||||
* console. If specified as false, we'll forcibly move to "pipe" mode though. */
|
||||
|
@ -115,6 +115,7 @@ static int oci_console_dimension(const char *name, JsonVariant *variant, JsonDis
|
|||
}
|
||||
|
||||
static int oci_console_size(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
|
||||
Settings *s = ASSERT_PTR(userdata);
|
||||
|
||||
static const JsonDispatch table[] = {
|
||||
{ "height", JSON_VARIANT_UNSIGNED, oci_console_dimension, offsetof(Settings, console_height), JSON_MANDATORY },
|
||||
|
@ -122,7 +123,7 @@ static int oci_console_size(const char *name, JsonVariant *v, JsonDispatchFlags
|
|||
{}
|
||||
};
|
||||
|
||||
return json_dispatch(v, table, oci_unexpected, flags, userdata);
|
||||
return json_dispatch(v, table, oci_unexpected, flags, s);
|
||||
}
|
||||
|
||||
static int oci_absolute_path(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
|
||||
|
@ -186,9 +187,8 @@ static int oci_args(const char *name, JsonVariant *v, JsonDispatchFlags flags, v
|
|||
|
||||
static int oci_rlimit_type(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
|
||||
const char *z;
|
||||
int t, *type = userdata;
|
||||
|
||||
assert_se(type);
|
||||
int *type = ASSERT_PTR(userdata);
|
||||
int t;
|
||||
|
||||
z = startswith(json_variant_string(v), "RLIMIT_");
|
||||
if (!z)
|
||||
|
@ -206,7 +206,8 @@ static int oci_rlimit_type(const char *name, JsonVariant *v, JsonDispatchFlags f
|
|||
}
|
||||
|
||||
static int oci_rlimit_value(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
|
||||
rlim_t z, *value = ASSERT_PTR(userdata);
|
||||
rlim_t *value = ASSERT_PTR(userdata);
|
||||
rlim_t z;
|
||||
|
||||
if (json_variant_is_negative(v))
|
||||
z = RLIM_INFINITY;
|
||||
|
@ -227,7 +228,6 @@ static int oci_rlimit_value(const char *name, JsonVariant *v, JsonDispatchFlags
|
|||
}
|
||||
|
||||
static int oci_rlimits(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
|
||||
|
||||
Settings *s = ASSERT_PTR(userdata);
|
||||
JsonVariant *e;
|
||||
int r;
|
||||
|
@ -276,7 +276,8 @@ static int oci_rlimits(const char *name, JsonVariant *v, JsonDispatchFlags flags
|
|||
}
|
||||
|
||||
static int oci_capability_array(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
|
||||
uint64_t *mask = userdata, m = 0;
|
||||
uint64_t *mask = ASSERT_PTR(userdata);
|
||||
uint64_t m = 0;
|
||||
JsonVariant *e;
|
||||
|
||||
JSON_VARIANT_ARRAY_FOREACH(e, v) {
|
||||
|
@ -347,10 +348,10 @@ static int oci_oom_score_adj(const char *name, JsonVariant *v, JsonDispatchFlags
|
|||
}
|
||||
|
||||
static int oci_uid_gid(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
|
||||
uid_t *uid = userdata, u;
|
||||
uid_t *uid = ASSERT_PTR(userdata);
|
||||
uid_t u;
|
||||
uint64_t k;
|
||||
|
||||
assert(uid);
|
||||
assert_cc(sizeof(uid_t) == sizeof(gid_t));
|
||||
|
||||
k = json_variant_unsigned(v);
|
||||
|
@ -395,6 +396,7 @@ static int oci_supplementary_gids(const char *name, JsonVariant *v, JsonDispatch
|
|||
}
|
||||
|
||||
static int oci_user(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
|
||||
|
||||
static const JsonDispatch table[] = {
|
||||
{ "uid", JSON_VARIANT_UNSIGNED, oci_uid_gid, offsetof(Settings, uid), JSON_MANDATORY },
|
||||
{ "gid", JSON_VARIANT_UNSIGNED, oci_uid_gid, offsetof(Settings, gid), JSON_MANDATORY },
|
||||
|
@ -427,7 +429,7 @@ static int oci_process(const char *name, JsonVariant *v, JsonDispatchFlags flags
|
|||
}
|
||||
|
||||
static int oci_root(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
|
||||
Settings *s = userdata;
|
||||
Settings *s = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
static const JsonDispatch table[] = {
|
||||
|
@ -511,13 +513,15 @@ typedef struct oci_mount_data {
|
|||
char **options;
|
||||
} oci_mount_data;
|
||||
|
||||
static void cleanup_oci_mount_data(oci_mount_data *data) {
|
||||
static void oci_mount_data_done(oci_mount_data *data) {
|
||||
free(data->destination);
|
||||
free(data->source);
|
||||
strv_free(data->options);
|
||||
free(data->type);
|
||||
strv_free(data->options);
|
||||
}
|
||||
|
||||
DEFINE_TRIVIAL_DESTRUCTOR(oci_mount_data_donep, oci_mount_data, oci_mount_data_done);
|
||||
|
||||
static int oci_mounts(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
|
||||
Settings *s = ASSERT_PTR(userdata);
|
||||
JsonVariant *e;
|
||||
|
@ -533,8 +537,8 @@ static int oci_mounts(const char *name, JsonVariant *v, JsonDispatchFlags flags,
|
|||
};
|
||||
|
||||
_cleanup_free_ char *joined_options = NULL;
|
||||
_cleanup_(oci_mount_data_donep) oci_mount_data data = {};
|
||||
CustomMount *m;
|
||||
_cleanup_(cleanup_oci_mount_data) oci_mount_data data = {};
|
||||
|
||||
r = json_dispatch(e, table, oci_unexpected, flags, &data);
|
||||
if (r < 0)
|
||||
|
@ -610,20 +614,27 @@ static int oci_namespace_type(const char *name, JsonVariant *v, JsonDispatchFlag
|
|||
return 0;
|
||||
}
|
||||
|
||||
struct namespace_data {
|
||||
unsigned long type;
|
||||
char *path;
|
||||
};
|
||||
|
||||
static void namespace_data_done(struct namespace_data *p) {
|
||||
assert(p);
|
||||
|
||||
free(p->path);
|
||||
}
|
||||
|
||||
DEFINE_TRIVIAL_DESTRUCTOR(namespace_data_donep, struct namespace_data, namespace_data_done);
|
||||
|
||||
static int oci_namespaces(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
|
||||
Settings *s = userdata;
|
||||
Settings *s = ASSERT_PTR(userdata);
|
||||
unsigned long n = 0;
|
||||
JsonVariant *e;
|
||||
int r;
|
||||
|
||||
assert_se(s);
|
||||
|
||||
JSON_VARIANT_ARRAY_FOREACH(e, v) {
|
||||
|
||||
struct namespace_data {
|
||||
unsigned long type;
|
||||
char *path;
|
||||
} data = {};
|
||||
_cleanup_(namespace_data_donep) struct namespace_data data = {};
|
||||
|
||||
static const JsonDispatch table[] = {
|
||||
{ "type", JSON_VARIANT_STRING, oci_namespace_type, offsetof(struct namespace_data, type), JSON_MANDATORY },
|
||||
|
@ -632,26 +643,19 @@ static int oci_namespaces(const char *name, JsonVariant *v, JsonDispatchFlags fl
|
|||
};
|
||||
|
||||
r = json_dispatch(e, table, oci_unexpected, flags, &data);
|
||||
if (r < 0) {
|
||||
free(data.path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (data.path) {
|
||||
if (data.type != CLONE_NEWNET) {
|
||||
free(data.path);
|
||||
if (data.type != CLONE_NEWNET)
|
||||
return json_log(e, flags, SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||||
"Specifying namespace path for non-network namespace is not supported.");
|
||||
}
|
||||
|
||||
if (s->network_namespace_path) {
|
||||
free(data.path);
|
||||
if (s->network_namespace_path)
|
||||
return json_log(e, flags, SYNTHETIC_ERRNO(EINVAL),
|
||||
"Network namespace path specified more than once, refusing.");
|
||||
}
|
||||
|
||||
free(s->network_namespace_path);
|
||||
s->network_namespace_path = data.path;
|
||||
free_and_replace(s->network_namespace_path, data.path);
|
||||
}
|
||||
|
||||
if (FLAGS_SET(n, data.type))
|
||||
|
@ -675,10 +679,10 @@ static int oci_namespaces(const char *name, JsonVariant *v, JsonDispatchFlags fl
|
|||
}
|
||||
|
||||
static int oci_uid_gid_range(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
|
||||
uid_t *uid = userdata, u;
|
||||
uid_t *uid = ASSERT_PTR(userdata);
|
||||
uid_t u;
|
||||
uint64_t k;
|
||||
|
||||
assert(uid);
|
||||
assert_cc(sizeof(uid_t) == sizeof(gid_t));
|
||||
|
||||
/* This is very much like oci_uid_gid(), except the checks are a bit different, as this is a UID range rather
|
||||
|
@ -777,11 +781,9 @@ static int oci_device_type(const char *name, JsonVariant *v, JsonDispatchFlags f
|
|||
}
|
||||
|
||||
static int oci_device_major(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
|
||||
unsigned *u = userdata;
|
||||
unsigned *u = ASSERT_PTR(userdata);
|
||||
uint64_t k;
|
||||
|
||||
assert_se(u);
|
||||
|
||||
k = json_variant_unsigned(v);
|
||||
if (!DEVICE_MAJOR_VALID(k))
|
||||
return json_log(v, flags, SYNTHETIC_ERRNO(ERANGE),
|
||||
|
@ -792,11 +794,9 @@ static int oci_device_major(const char *name, JsonVariant *v, JsonDispatchFlags
|
|||
}
|
||||
|
||||
static int oci_device_minor(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
|
||||
unsigned *u = userdata;
|
||||
unsigned *u = ASSERT_PTR(userdata);
|
||||
uint64_t k;
|
||||
|
||||
assert_se(u);
|
||||
|
||||
k = json_variant_unsigned(v);
|
||||
if (!DEVICE_MINOR_VALID(k))
|
||||
return json_log(v, flags, SYNTHETIC_ERRNO(ERANGE),
|
||||
|
@ -807,11 +807,10 @@ static int oci_device_minor(const char *name, JsonVariant *v, JsonDispatchFlags
|
|||
}
|
||||
|
||||
static int oci_device_file_mode(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
|
||||
mode_t *mode = userdata, m;
|
||||
mode_t *mode = ASSERT_PTR(userdata);
|
||||
mode_t m;
|
||||
uint64_t k;
|
||||
|
||||
assert(mode);
|
||||
|
||||
k = json_variant_unsigned(v);
|
||||
m = (mode_t) k;
|
||||
|
||||
|
@ -931,7 +930,7 @@ static int oci_cgroups_path(const char *name, JsonVariant *v, JsonDispatchFlags
|
|||
}
|
||||
|
||||
static int oci_cgroup_device_type(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
|
||||
mode_t *mode = userdata;
|
||||
mode_t *mode = ASSERT_PTR(userdata);
|
||||
const char *n;
|
||||
|
||||
assert_se(n = json_variant_string(v));
|
||||
|
@ -958,7 +957,7 @@ struct device_data {
|
|||
};
|
||||
|
||||
static int oci_cgroup_device_access(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
|
||||
struct device_data *d = userdata;
|
||||
struct device_data *d = ASSERT_PTR(userdata);
|
||||
bool r = false, w = false, m = false;
|
||||
const char *s;
|
||||
size_t i;
|
||||
|
@ -984,7 +983,6 @@ static int oci_cgroup_device_access(const char *name, JsonVariant *v, JsonDispat
|
|||
}
|
||||
|
||||
static int oci_cgroup_devices(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
|
||||
|
||||
_cleanup_free_ struct device_data *list = NULL;
|
||||
Settings *s = ASSERT_PTR(userdata);
|
||||
size_t n_list = 0, i;
|
||||
|
@ -1187,7 +1185,7 @@ static int oci_cgroup_memory(const char *name, JsonVariant *v, JsonDispatchFlags
|
|||
{}
|
||||
};
|
||||
|
||||
Settings *s = userdata;
|
||||
Settings *s = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
r = json_dispatch(v, table, oci_unexpected, flags, &data);
|
||||
|
@ -1303,7 +1301,7 @@ static int oci_cgroup_cpu(const char *name, JsonVariant *v, JsonDispatchFlags fl
|
|||
.period = UINT64_MAX,
|
||||
};
|
||||
|
||||
Settings *s = userdata;
|
||||
Settings *s = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
r = json_dispatch(v, table, oci_unexpected, flags, &data);
|
||||
|
@ -1741,13 +1739,15 @@ struct syscall_rule {
|
|||
size_t n_arguments;
|
||||
};
|
||||
|
||||
static void syscall_rule_free(struct syscall_rule *rule) {
|
||||
static void syscall_rule_done(struct syscall_rule *rule) {
|
||||
assert(rule);
|
||||
|
||||
strv_free(rule->names);
|
||||
free(rule->arguments);
|
||||
};
|
||||
|
||||
DEFINE_TRIVIAL_DESTRUCTOR(syscall_rule_donep, struct syscall_rule, syscall_rule_done);
|
||||
|
||||
static int oci_seccomp_action(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
|
||||
uint32_t *action = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
@ -1831,18 +1831,17 @@ static int oci_seccomp_syscalls(const char *name, JsonVariant *v, JsonDispatchFl
|
|||
{ "args", JSON_VARIANT_ARRAY, oci_seccomp_args, 0, 0 },
|
||||
{}
|
||||
};
|
||||
struct syscall_rule rule = {
|
||||
_cleanup_(syscall_rule_donep) struct syscall_rule rule = {
|
||||
.action = UINT32_MAX,
|
||||
};
|
||||
|
||||
r = json_dispatch(e, table, oci_unexpected, flags, &rule);
|
||||
if (r < 0)
|
||||
goto fail_rule;
|
||||
return r;
|
||||
|
||||
if (strv_isempty(rule.names)) {
|
||||
json_log(e, flags, 0, "System call name list is empty.");
|
||||
r = -EINVAL;
|
||||
goto fail_rule;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
STRV_FOREACH(i, rule.names) {
|
||||
|
@ -1856,15 +1855,8 @@ static int oci_seccomp_syscalls(const char *name, JsonVariant *v, JsonDispatchFl
|
|||
|
||||
r = seccomp_rule_add_array(sc, rule.action, nr, rule.n_arguments, rule.arguments);
|
||||
if (r < 0)
|
||||
goto fail_rule;
|
||||
return r;
|
||||
}
|
||||
|
||||
syscall_rule_free(&rule);
|
||||
continue;
|
||||
|
||||
fail_rule:
|
||||
syscall_rule_free(&rule);
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -2031,7 +2023,7 @@ static int oci_linux(const char *name, JsonVariant *v, JsonDispatchFlags flags,
|
|||
}
|
||||
|
||||
static int oci_hook_timeout(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
|
||||
usec_t *u = userdata;
|
||||
usec_t *u = ASSERT_PTR(userdata);
|
||||
uint64_t k;
|
||||
|
||||
k = json_variant_unsigned(v);
|
||||
|
|
|
@ -30,7 +30,8 @@ test_append_files() {
|
|||
seq \
|
||||
sleep \
|
||||
stat \
|
||||
touch
|
||||
touch \
|
||||
true
|
||||
|
||||
cp /etc/os-release "$container/usr/lib/os-release"
|
||||
cat >"$container/sbin/init" <<EOF
|
||||
|
|
|
@ -214,6 +214,7 @@ BASICTOOLS=(
|
|||
script
|
||||
sed
|
||||
seq
|
||||
setfacl
|
||||
setfattr
|
||||
setfont
|
||||
setpriv
|
||||
|
@ -886,8 +887,8 @@ INNER_EOF
|
|||
# Let's make one to prevent unexpected "<bin> not found" issues in the future
|
||||
export PATH="/sbin:/bin:/usr/sbin:/usr/bin"
|
||||
|
||||
mount -t proc proc /proc
|
||||
mount -t sysfs sysfs /sys
|
||||
mountpoint -q /proc || mount -t proc proc /proc
|
||||
mountpoint -q /sys || mount -t sysfs sysfs /sys
|
||||
mount -o remount,rw /
|
||||
|
||||
DEFAULT_ENVIRONMENT="\$DEFAULT_ENVIRONMENT ASAN_RT_PATH=$ASAN_RT_PATH"
|
||||
|
@ -961,7 +962,7 @@ install_fs_tools() {
|
|||
install_modules() {
|
||||
dinfo "Install modules"
|
||||
|
||||
instmods dummy vfat veth
|
||||
instmods bridge dummy ipvlan macvlan vfat veth
|
||||
instmods loop =block
|
||||
instmods nls_ascii =nls
|
||||
instmods overlay =overlayfs
|
||||
|
@ -2655,13 +2656,14 @@ inst_binary() {
|
|||
|
||||
# Same as above, but we need to wrap certain libraries unconditionally
|
||||
#
|
||||
# chown, getent, login, su, useradd, userdel - dlopen() (not only) systemd's PAM modules
|
||||
# chown, getent, login, setfacl, su, useradd, userdel
|
||||
# - dlopen() (not only) systemd's PAM modules
|
||||
# ls, mkfs.*, mksquashfs, mkswap, setpriv, stat
|
||||
# - pull in nss_systemd with certain options (like ls -l) when
|
||||
# nsswitch.conf uses [SUCCESS=merge] (like on Arch Linux)
|
||||
# - pull in nss_systemd with certain options (like ls -l) when
|
||||
# nsswitch.conf uses [SUCCESS=merge] (like on Arch Linux)
|
||||
# delv, dig - pull in nss_resolve if `resolve` is in nsswitch.conf
|
||||
# tar - called by machinectl in TEST-25
|
||||
bin_rx='/(chown|delv|dig|getent|login|ls|mkfs\.[a-z0-9]+|mksquashfs|mkswap|setpriv|stat|su|tar|useradd|userdel)$'
|
||||
bin_rx='/(chown|delv|dig|getent|login|ls|mkfs\.[a-z0-9]+|mksquashfs|mkswap|setfacl|setpriv|stat|su|tar|useradd|userdel)$'
|
||||
if get_bool "$IS_BUILT_WITH_ASAN" && [[ "$bin" =~ $bin_rx ]]; then
|
||||
wrap_binary=1
|
||||
fi
|
||||
|
|
|
@ -15,6 +15,7 @@ at_exit() {
|
|||
machinectl status long-running >/dev/null && machinectl kill --signal=KILL long-running
|
||||
mountpoint -q /var/lib/machines && timeout 10 sh -c "while ! umount /var/lib/machines; do sleep .5; done"
|
||||
[[ -n "${NSPAWN_FRAGMENT:-}" ]] && rm -f "/etc/systemd/nspawn/$NSPAWN_FRAGMENT" "/var/lib/machines/$NSPAWN_FRAGMENT"
|
||||
rm -f /run/systemd/nspawn/*.nspawn
|
||||
}
|
||||
|
||||
trap at_exit EXIT
|
||||
|
|
|
@ -18,6 +18,7 @@ at_exit() {
|
|||
[[ -n "${DEV:-}" ]] && rm -f "$DEV"
|
||||
[[ -n "${NETNS:-}" ]] && umount "$NETNS" && rm -f "$NETNS"
|
||||
[[ -n "${TMPDIR:-}" ]] && rm -fr "$TMPDIR"
|
||||
rm -f /run/systemd/nspawn/*.nspawn
|
||||
}
|
||||
|
||||
trap at_exit EXIT
|
||||
|
@ -382,4 +383,84 @@ touch /opt/readonly/foo && exit 1
|
|||
|
||||
exit 0
|
||||
EOF
|
||||
systemd-nspawn --oci-bundle="$OCI"
|
||||
timeout 30 systemd-nspawn --oci-bundle="$OCI"
|
||||
|
||||
# Test a couple of invalid configs
|
||||
INVALID_SNIPPETS=(
|
||||
# Invalid object
|
||||
'"foo" : { }'
|
||||
'"process" : { "foo" : [ ] }'
|
||||
# Non-absolute mount
|
||||
'"mounts" : [ { "destination" : "foo", "type" : "tmpfs", "source" : "tmpfs" } ]'
|
||||
# Invalid rlimit
|
||||
'"process" : { "rlimits" : [ { "type" : "RLIMIT_FOO", "soft" : 0, "hard" : 0 } ] }'
|
||||
# rlimit without RLIMIT_ prefix
|
||||
'"process" : { "rlimits" : [ { "type" : "CORE", "soft" : 0, "hard" : 0 } ] }'
|
||||
# Invalid env assignment
|
||||
'"process" : { "env" : [ "foo" ] }'
|
||||
'"process" : { "env" : [ "foo=bar", 1 ] }'
|
||||
# Invalid process args
|
||||
'"process" : { "args" : [ ] }'
|
||||
'"process" : { "args" : [ "" ] }'
|
||||
'"process" : { "args" : [ "foo", 1 ] }'
|
||||
# Invalid capabilities
|
||||
'"process" : { "capabilities" : { "bounding" : [ 1 ] } }'
|
||||
'"process" : { "capabilities" : { "bounding" : [ "FOO_BAR" ] } }'
|
||||
# Unsupported option (without JSON_PERMISSIVE)
|
||||
'"linux" : { "resources" : { "cpu" : { "realtimeRuntime" : 1 } } }'
|
||||
# Invalid namespace
|
||||
'"linux" : { "namespaces" : [ { "type" : "foo" } ] }'
|
||||
# Namespace path for a non-network namespace
|
||||
'"linux" : { "namespaces" : [ { "type" : "user", "path" : "/foo/bar" } ] }'
|
||||
# Duplicate namespace
|
||||
'"linux" : { "namespaces" : [ { "type" : "ipc" }, { "type" : "ipc" } ] }'
|
||||
# Invalid device type
|
||||
'"linux" : { "devices" : [ { "type" : "foo", "path" : "/dev/foo" } ] }'
|
||||
# Invalid cgroups path
|
||||
'"linux" : { "cgroupsPath" : "/foo/bar/baz" }'
|
||||
'"linux" : { "cgroupsPath" : "foo/bar/baz" }'
|
||||
# Invalid sysctl assignments
|
||||
'"linux" : { "sysctl" : { "vm.swappiness" : 60 } }'
|
||||
'"linux" : { "sysctl" : { "foo..bar" : "baz" } }'
|
||||
# Invalid seccomp assignments
|
||||
'"linux" : { "seccomp" : { } }'
|
||||
'"linux" : { "seccomp" : { "defaultAction" : 1 } }'
|
||||
'"linux" : { "seccomp" : { "defaultAction" : "foo" } }'
|
||||
'"linux" : { "seccomp" : { "defaultAction" : "SCMP_ACT_ALLOW", "syscalls" : [ { "action" : "SCMP_ACT_ERRNO", "names" : [ ] } ] } }'
|
||||
# Invalid masked paths
|
||||
'"linux" : { "maskedPaths" : [ "/foo", 1 ] }'
|
||||
'"linux" : { "maskedPaths" : [ "/foo", "bar" ] }'
|
||||
# Invalid read-only paths
|
||||
'"linux" : { "readonlyPaths" : [ "/foo", 1 ] }'
|
||||
'"linux" : { "readonlyPaths" : [ "/foo", "bar" ] }'
|
||||
# Invalid hooks
|
||||
'"hooks" : { "prestart" : [ { "path" : "/bin/sh", "timeout" : 0 } ] }'
|
||||
# Invalid annotations
|
||||
'"annotations" : { "" : "bar" }'
|
||||
'"annotations" : { "foo" : 1 }'
|
||||
)
|
||||
|
||||
for snippet in "${INVALID_SNIPPETS[@]}"; do
|
||||
: "Snippet: $snippet"
|
||||
cat >"$OCI/config.json" <<EOF
|
||||
{
|
||||
"ociVersion" : "1.0.0",
|
||||
"root" : {
|
||||
"path" : "rootfs"
|
||||
},
|
||||
$snippet
|
||||
}
|
||||
EOF
|
||||
(! systemd-nspawn --oci-bundle="$OCI" sh -c 'echo hello')
|
||||
done
|
||||
|
||||
# Invalid OCI bundle version
|
||||
cat >"$OCI/config.json" <<EOF
|
||||
{
|
||||
"ociVersion" : "6.6.6",
|
||||
"root" : {
|
||||
"path" : "rootfs"
|
||||
}
|
||||
}
|
||||
EOF
|
||||
(! systemd-nspawn --oci-bundle="$OCI" sh -c 'echo hello')
|
||||
|
|
|
@ -1,6 +1,25 @@
|
|||
#!/usr/bin/env bash
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
# shellcheck disable=SC2016
|
||||
#
|
||||
# Notes on coverage: when collecting coverage we need the $BUILD_DIR present
|
||||
# and writable in the container as well. To do this in the least intrusive way,
|
||||
# two things are going on in the background (only when built with -Db_coverage=true):
|
||||
# 1) the systemd-nspawn@.service is copied to /etc/systemd/system/ with
|
||||
# --bind=$BUILD_DIR appended to the ExecStart= line
|
||||
# 2) each create_dummy_container() call also creates an .nspawn file in /run/systemd/nspawn/
|
||||
# with the last fragment from the path used as a name
|
||||
#
|
||||
# The first change is quite self-contained and applies only to containers run
|
||||
# with machinectl. The second one might cause some unexpected side-effects, namely:
|
||||
# - nspawn config (setting) files don't support dropins, so tests that test
|
||||
# the config files might need some tweaking (as seen below with
|
||||
# the $COVERAGE_BUILD_DIR shenanigans) since they overwrite the .nspawn file
|
||||
# - also a note - if /etc/systemd/nspawn/cont-name.nspawn exists, it takes
|
||||
# precedence and /run/systemd/nspawn/cont-name.nspawn won't be read even
|
||||
# if it exists
|
||||
# - in some cases we don't create a test container using create_dummy_container(),
|
||||
# so in that case an explicit call to coverage_create_nspawn_dropin() is needed
|
||||
set -eux
|
||||
set -o pipefail
|
||||
|
||||
|
@ -14,6 +33,7 @@ at_exit() {
|
|||
set +e
|
||||
|
||||
mountpoint -q /var/lib/machines && umount /var/lib/machines
|
||||
rm -f /run/systemd/nspawn/*.nspawn
|
||||
}
|
||||
|
||||
trap at_exit EXIT
|
||||
|
@ -47,7 +67,7 @@ fi
|
|||
mkdir -p /var/lib/machines
|
||||
mount -t tmpfs tmpfs /var/lib/machines
|
||||
|
||||
testcase_sanity_check() {
|
||||
testcase_sanity() {
|
||||
local template root image uuid tmpdir
|
||||
|
||||
tmpdir="$(mktemp -d)"
|
||||
|
@ -67,6 +87,7 @@ testcase_sanity_check() {
|
|||
|
||||
# --template=
|
||||
root="$(mktemp -u -d /var/lib/machines/testsuite-13.sanity.XXX)"
|
||||
coverage_create_nspawn_dropin "$root"
|
||||
(! systemd-nspawn --directory="$root" bash -xec 'echo hello')
|
||||
# Initialize $root from $template (the $root directory must not exist, hence
|
||||
# the `mktemp -u` above)
|
||||
|
@ -213,6 +234,20 @@ EOF
|
|||
test ! -e "$tmpdir/3/nope"
|
||||
rm -fr "$tmpdir"
|
||||
|
||||
# --port (sanity only)
|
||||
systemd-nspawn --network-veth --directory="$root" --port=80 --port=90 true
|
||||
systemd-nspawn --network-veth --directory="$root" --port=80:8080 true
|
||||
systemd-nspawn --network-veth --directory="$root" --port=tcp:80 true
|
||||
systemd-nspawn --network-veth --directory="$root" --port=tcp:80:8080 true
|
||||
systemd-nspawn --network-veth --directory="$root" --port=udp:80 true
|
||||
systemd-nspawn --network-veth --directory="$root" --port=udp:80:8080 --port=tcp:80:8080 true
|
||||
(! systemd-nspawn --network-veth --directory="$root" --port= true)
|
||||
(! systemd-nspawn --network-veth --directory="$root" --port=-1 true)
|
||||
(! systemd-nspawn --network-veth --directory="$root" --port=: true)
|
||||
(! systemd-nspawn --network-veth --directory="$root" --port=icmp:80:8080 true)
|
||||
(! systemd-nspawn --network-veth --directory="$root" --port=tcp::8080 true)
|
||||
(! systemd-nspawn --network-veth --directory="$root" --port=8080: true)
|
||||
|
||||
# Assorted tests
|
||||
systemd-nspawn --directory="$root" --suppress-sync=yes bash -xec 'echo hello'
|
||||
systemd-nspawn --capability=help
|
||||
|
@ -263,7 +298,208 @@ EOF
|
|||
(! systemd-nspawn --rlimit==)
|
||||
}
|
||||
|
||||
testcase_check_bind_tmp_path() {
|
||||
nspawn_settings_cleanup() {
|
||||
for dev in sd-host-only sd-shared{1,2} sd-macvlan{1,2} sd-ipvlan{1,2}; do
|
||||
ip link del "$dev" || :
|
||||
done
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
testcase_nspawn_settings() {
|
||||
local root container dev private_users
|
||||
|
||||
mkdir -p /run/systemd/nspawn
|
||||
root="$(mktemp -d /var/lib/machines/testsuite-13.nspawn-settings.XXX)"
|
||||
container="$(basename "$root")"
|
||||
create_dummy_container "$root"
|
||||
rm -f "/etc/systemd/nspawn/$container.nspawn"
|
||||
mkdir -p "$root/tmp" "$root"/opt/{tmp,inaccessible,also-inaccessible}
|
||||
|
||||
for dev in sd-host-only sd-shared{1,2} sd-macvlan{1,2} sd-ipvlan{1,2}; do
|
||||
ip link add "$dev" type dummy
|
||||
done
|
||||
udevadm settle
|
||||
ip link
|
||||
trap nspawn_settings_cleanup RETURN
|
||||
|
||||
# Let's start with one huge config to test as much as we can at once
|
||||
cat >"/run/systemd/nspawn/$container.nspawn" <<EOF
|
||||
[Exec]
|
||||
Boot=no
|
||||
Ephemeral=no
|
||||
ProcessTwo=no
|
||||
Parameters=bash /entrypoint.sh "foo bar" 'bar baz'
|
||||
Environment=FOO=bar
|
||||
Environment=BAZ="hello world"
|
||||
User=root
|
||||
WorkingDirectory=/tmp
|
||||
Capability=CAP_BLOCK_SUSPEND CAP_BPF CAP_CHOWN
|
||||
DropCapability=CAP_AUDIT_CONTROL CAP_AUDIT_WRITE
|
||||
AmbientCapability=CAP_BPF CAP_CHOWN
|
||||
NoNewPrivileges=no
|
||||
MachineID=f28f129b51874b1280a89421ec4b4ad4
|
||||
PrivateUsers=no
|
||||
NotifyReady=no
|
||||
SystemCallFilter=@basic-io @chown
|
||||
SystemCallFilter=~ @clock
|
||||
LimitNOFILE=1024:2048
|
||||
LimitRTPRIO=8:16
|
||||
OOMScoreAdjust=32
|
||||
CPUAffinity=0,0-5,1-5
|
||||
Hostname=nspawn-settings
|
||||
ResolvConf=copy-host
|
||||
Timezone=delete
|
||||
LinkJournal=no
|
||||
SuppressSync=no
|
||||
|
||||
[Files]
|
||||
ReadOnly=no
|
||||
Volatile=no
|
||||
TemporaryFileSystem=/tmp
|
||||
TemporaryFileSystem=/opt/tmp
|
||||
Inaccessible=/opt/inaccessible
|
||||
Inaccessible=/opt/also-inaccessible
|
||||
PrivateUsersOwnership=auto
|
||||
Overlay=+/var::/var
|
||||
${COVERAGE_BUILD_DIR:+"Bind=$COVERAGE_BUILD_DIR"}
|
||||
|
||||
[Network]
|
||||
Private=yes
|
||||
VirtualEthernet=yes
|
||||
VirtualEthernetExtra=my-fancy-veth1
|
||||
VirtualEthernetExtra=fancy-veth2:my-fancy-veth2
|
||||
Interface=sd-shared1 sd-shared2:sd-shared2
|
||||
MACVLAN=sd-macvlan1 sd-macvlan2:my-macvlan2
|
||||
IPVLAN=sd-ipvlan1 sd-ipvlan2:my-ipvlan2
|
||||
Zone=sd-zone0
|
||||
Port=80
|
||||
Port=81:8181
|
||||
Port=tcp:60
|
||||
Port=udp:60:61
|
||||
EOF
|
||||
cat >"$root/entrypoint.sh" <<\EOF
|
||||
#!/bin/bash -ex
|
||||
|
||||
[[ "$1" == "foo bar" ]]
|
||||
[[ "$2" == "bar baz" ]]
|
||||
|
||||
[[ "$USER" == root ]]
|
||||
[[ "$FOO" == bar ]]
|
||||
[[ "$BAZ" == "hello world" ]]
|
||||
[[ "$PWD" == /tmp ]]
|
||||
[[ "$(</etc/machine-id)" == f28f129b51874b1280a89421ec4b4ad4 ]]
|
||||
[[ "$(ulimit -S -n)" -eq 1024 ]]
|
||||
[[ "$(ulimit -H -n)" -eq 2048 ]]
|
||||
[[ "$(ulimit -S -r)" -eq 8 ]]
|
||||
[[ "$(ulimit -H -r)" -eq 16 ]]
|
||||
[[ "$(</proc/self/oom_score_adj)" -eq 32 ]]
|
||||
[[ "$(hostname)" == nspawn-settings ]]
|
||||
[[ -e /etc/resolv.conf ]]
|
||||
[[ ! -e /etc/localtime ]]
|
||||
|
||||
mountpoint /tmp
|
||||
touch /tmp/foo
|
||||
mountpoint /opt/tmp
|
||||
touch /opt/tmp/foo
|
||||
touch /opt/inaccessible/foo && exit 1
|
||||
touch /opt/also-inaccessible/foo && exit 1
|
||||
mountpoint /var
|
||||
|
||||
ip link
|
||||
ip link | grep host-only && exit 1
|
||||
ip link | grep host0@
|
||||
ip link | grep my-fancy-veth1@
|
||||
ip link | grep my-fancy-veth2@
|
||||
ip link | grep sd-shared1
|
||||
ip link | grep sd-shared2
|
||||
ip link | grep mv-sd-macvlan1@
|
||||
ip link | grep my-macvlan2@
|
||||
ip link | grep iv-sd-ipvlan1@
|
||||
ip link | grep my-ipvlan2@
|
||||
EOF
|
||||
timeout 30 systemd-nspawn --directory="$root"
|
||||
|
||||
# And now for stuff that needs to run separately
|
||||
#
|
||||
# Note on the condition below: since our container tree is owned by root,
|
||||
# both "yes" and "identity" private users settings will behave the same
|
||||
# as PrivateUsers=0:65535, which makes BindUser= fail as the UID already
|
||||
# exists there, so skip setting it in such case
|
||||
for private_users in "131072:65536" yes identity pick; do
|
||||
cat >"/run/systemd/nspawn/$container.nspawn" <<EOF
|
||||
[Exec]
|
||||
Hostname=private-users
|
||||
PrivateUsers=$private_users
|
||||
|
||||
[Files]
|
||||
PrivateUsersOwnership=auto
|
||||
BindUser=
|
||||
$([[ "$private_users" =~ (yes|identity) ]] || echo "BindUser=testuser")
|
||||
${COVERAGE_BUILD_DIR:+"Bind=$COVERAGE_BUILD_DIR"}
|
||||
EOF
|
||||
cat "/run/systemd/nspawn/$container.nspawn"
|
||||
chown -R root:root "$root"
|
||||
systemd-nspawn --directory="$root" bash -xec '[[ "$(hostname)" == private-users ]]'
|
||||
done
|
||||
|
||||
rm -fr "$root" "/run/systemd/nspawn/$container.nspawn"
|
||||
}
|
||||
|
||||
bind_user_cleanup() {
|
||||
userdel --force --remove nspawn-bind-user-1
|
||||
userdel --force --remove nspawn-bind-user-2
|
||||
}
|
||||
|
||||
testcase_bind_user() {
|
||||
local root
|
||||
|
||||
root="$(mktemp -d /var/lib/machines/testsuite-13.bind-user.XXX)"
|
||||
create_dummy_container "$root"
|
||||
useradd --create-home --user-group nspawn-bind-user-1
|
||||
useradd --create-home --user-group nspawn-bind-user-2
|
||||
trap bind_user_cleanup RETURN
|
||||
touch /home/nspawn-bind-user-1/foo
|
||||
touch /home/nspawn-bind-user-2/bar
|
||||
# Add a couple of POSIX ACLs to test the patch-uid stuff
|
||||
mkdir -p "$root/opt"
|
||||
setfacl -R -m 'd:u:nspawn-bind-user-1:rwX' -m 'u:nspawn-bind-user-1:rwX' "$root/opt"
|
||||
setfacl -R -m 'd:g:nspawn-bind-user-1:rwX' -m 'g:nspawn-bind-user-1:rwX' "$root/opt"
|
||||
|
||||
systemd-nspawn --directory="$root" \
|
||||
--private-users=pick \
|
||||
--bind-user=nspawn-bind-user-1 \
|
||||
bash -xec 'test -e /run/host/home/nspawn-bind-user-1/foo'
|
||||
|
||||
systemd-nspawn --directory="$root" \
|
||||
--private-users=pick \
|
||||
--private-users-ownership=chown \
|
||||
--bind-user=nspawn-bind-user-1 \
|
||||
--bind-user=nspawn-bind-user-2 \
|
||||
bash -xec 'test -e /run/host/home/nspawn-bind-user-1/foo; test -e /run/host/home/nspawn-bind-user-2/bar'
|
||||
chown -R root:root "$root"
|
||||
|
||||
# User/group name collision
|
||||
echo "nspawn-bind-user-2:x:1000:1000:nspawn-bind-user-2:/home/nspawn-bind-user-2:/bin/bash" >"$root/etc/passwd"
|
||||
(! systemd-nspawn --directory="$root" \
|
||||
--private-users=pick \
|
||||
--bind-user=nspawn-bind-user-1 \
|
||||
--bind-user=nspawn-bind-user-2 \
|
||||
true)
|
||||
rm -f "$root/etc/passwd"
|
||||
|
||||
echo "nspawn-bind-user-2:x:1000:" >"$root/etc/group"
|
||||
(! systemd-nspawn --directory="$root" \
|
||||
--private-users=pick \
|
||||
--bind-user=nspawn-bind-user-1 \
|
||||
--bind-user=nspawn-bind-user-2 \
|
||||
true)
|
||||
rm -f "$root/etc/group"
|
||||
|
||||
rm -fr "$root"
|
||||
}
|
||||
|
||||
testcase_bind_tmp_path() {
|
||||
# https://github.com/systemd/systemd/issues/4789
|
||||
local root
|
||||
|
||||
|
@ -278,7 +514,7 @@ testcase_check_bind_tmp_path() {
|
|||
rm -fr "$root" /tmp/bind
|
||||
}
|
||||
|
||||
testcase_check_norbind() {
|
||||
testcase_norbind() {
|
||||
# https://github.com/systemd/systemd/issues/13170
|
||||
local root
|
||||
|
||||
|
@ -298,14 +534,14 @@ testcase_check_norbind() {
|
|||
rm -fr "$root" /tmp/binddir/
|
||||
}
|
||||
|
||||
check_rootidmap_cleanup() {
|
||||
rootidmap_cleanup() {
|
||||
local dir="${1:?}"
|
||||
|
||||
mountpoint -q "$dir/bind" && umount "$dir/bind"
|
||||
rm -fr "$dir"
|
||||
}
|
||||
|
||||
testcase_check_rootidmap() {
|
||||
testcase_rootidmap() {
|
||||
local root cmd permissions
|
||||
local owner=1000
|
||||
|
||||
|
@ -315,7 +551,7 @@ testcase_check_rootidmap() {
|
|||
dd if=/dev/zero of=/tmp/rootidmap/ext4.img bs=4k count=2048
|
||||
mkfs.ext4 /tmp/rootidmap/ext4.img
|
||||
mount /tmp/rootidmap/ext4.img /tmp/rootidmap/bind
|
||||
trap "check_rootidmap_cleanup /tmp/rootidmap/" RETURN
|
||||
trap "rootidmap_cleanup /tmp/rootidmap/" RETURN
|
||||
|
||||
touch /tmp/rootidmap/bind/file
|
||||
chown -R "$owner:$owner" /tmp/rootidmap/bind
|
||||
|
@ -342,7 +578,7 @@ testcase_check_rootidmap() {
|
|||
fi
|
||||
}
|
||||
|
||||
testcase_check_notification_socket() {
|
||||
testcase_notification_socket() {
|
||||
# https://github.com/systemd/systemd/issues/4944
|
||||
local root
|
||||
local cmd='echo a | nc -U -u -w 1 /run/host/notify'
|
||||
|
@ -352,12 +588,14 @@ testcase_check_notification_socket() {
|
|||
|
||||
systemd-nspawn --register=no --directory="$root" bash -x -c "$cmd"
|
||||
systemd-nspawn --register=no --directory="$root" -U bash -x -c "$cmd"
|
||||
|
||||
rm -fr "$root"
|
||||
}
|
||||
|
||||
testcase_check_os_release() {
|
||||
testcase_os_release() {
|
||||
local root entrypoint os_release_source
|
||||
|
||||
root="$(mktemp -d /var/lib/machines/testsuite-13.check-os-release.XXX)"
|
||||
root="$(mktemp -d /var/lib/machines/testsuite-13.os-release.XXX)"
|
||||
create_dummy_container "$root"
|
||||
entrypoint="$root/entrypoint.sh"
|
||||
cat >"$entrypoint" <<\EOF
|
||||
|
@ -395,11 +633,11 @@ EOF
|
|||
rm -fr "$root"
|
||||
}
|
||||
|
||||
testcase_check_machinectl_bind() {
|
||||
testcase_machinectl_bind() {
|
||||
local service_path service_name root container_name ec
|
||||
local cmd='for i in $(seq 1 20); do if test -f /tmp/marker; then exit 0; fi; sleep .5; done; exit 1;'
|
||||
|
||||
root="$(mktemp -d /var/lib/machines/testsuite-13.check-machinectl-bind.XXX)"
|
||||
root="$(mktemp -d /var/lib/machines/testsuite-13.machinectl-bind.XXX)"
|
||||
create_dummy_container "$root"
|
||||
container_name="$(basename "$root")"
|
||||
|
||||
|
@ -425,7 +663,7 @@ EOF
|
|||
return "$ec"
|
||||
}
|
||||
|
||||
testcase_check_selinux() {
|
||||
testcase_selinux() {
|
||||
# Basic test coverage to avoid issues like https://github.com/systemd/systemd/issues/19976
|
||||
if ! command -v selinuxenabled >/dev/null || ! selinuxenabled; then
|
||||
echo >&2 "SELinux is not enabled, skipping SELinux-related tests"
|
||||
|
@ -434,7 +672,7 @@ testcase_check_selinux() {
|
|||
|
||||
local root
|
||||
|
||||
root="$(mktemp -d /var/lib/machines/testsuite-13.check-selinux.XXX)"
|
||||
root="$(mktemp -d /var/lib/machines/testsuite-13.selinux.XXX)"
|
||||
create_dummy_container "$root"
|
||||
chcon -R -t container_t "$root"
|
||||
|
||||
|
@ -447,17 +685,19 @@ testcase_check_selinux() {
|
|||
rm -fr "$root"
|
||||
}
|
||||
|
||||
testcase_check_ephemeral_config() {
|
||||
testcase_ephemeral_config() {
|
||||
# https://github.com/systemd/systemd/issues/13297
|
||||
local root container_name
|
||||
|
||||
root="$(mktemp -d /var/lib/machines/testsuite-13.check-ephemeral-config.XXX)"
|
||||
root="$(mktemp -d /var/lib/machines/testsuite-13.ephemeral-config.XXX)"
|
||||
create_dummy_container "$root"
|
||||
container_name="${root##*/}"
|
||||
container_name="$(basename "$root")"
|
||||
|
||||
mkdir -p /run/systemd/nspawn/
|
||||
rm -f "/etc/systemd/nspawn/$container_name.nspawn"
|
||||
cat >"/run/systemd/nspawn/$container_name.nspawn" <<EOF
|
||||
[Files]
|
||||
${COVERAGE_BUILD_DIR:+"Bind=$COVERAGE_BUILD_DIR"}
|
||||
BindReadOnly=/tmp/ephemeral-config
|
||||
EOF
|
||||
touch /tmp/ephemeral-config
|
||||
|
@ -473,7 +713,7 @@ EOF
|
|||
--machine=foobar \
|
||||
bash -x -c "! test -f /tmp/ephemeral-config"
|
||||
|
||||
rm -fr "$root" "/run/systemd/nspawn/$container_name"
|
||||
rm -fr "$root" "/run/systemd/nspawn/$container_name.nspawn"
|
||||
}
|
||||
|
||||
matrix_run_one() {
|
||||
|
|
|
@ -81,6 +81,23 @@ runas() {
|
|||
XDG_RUNTIME_DIR=/run/user/"$(id -u "$userid")" setpriv --reuid="$userid" --init-groups "$@"
|
||||
}
|
||||
|
||||
coverage_create_nspawn_dropin() {
|
||||
# If we're collecting coverage, bind mount the $BUILD_DIR into the nspawn
|
||||
# container so gcov can update the counters. This is mostly for standalone
|
||||
# containers, as machinectl stuff is handled by overriding the systemd-nspawn@.service
|
||||
# (see test/test-functions:install_systemd())
|
||||
local root="${1:?}"
|
||||
local container
|
||||
|
||||
if [[ -z "${COVERAGE_BUILD_DIR:-}" ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
container="$(basename "$root")"
|
||||
mkdir -p "/run/systemd/nspawn"
|
||||
echo -ne "[Files]\nBind=$COVERAGE_BUILD_DIR\n" >"/run/systemd/nspawn/${container:?}.nspawn"
|
||||
}
|
||||
|
||||
create_dummy_container() {
|
||||
local root="${1:?}"
|
||||
|
||||
|
@ -91,4 +108,5 @@ create_dummy_container() {
|
|||
|
||||
mkdir -p "$root"
|
||||
cp -a /testsuite-13-container-template/* "$root"
|
||||
coverage_create_nspawn_dropin "$root"
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue