Compare commits

...

6 Commits

Author SHA1 Message Date
Federico Giovanardi 18d03694bf
Merge 9d58f3b81e into 4a346b779a 2024-11-25 20:34:07 +09:00
Daan De Meyer 4a346b779a test: Dump coredumps from journal in the integration test wrapper
Fixes #35277
2024-11-25 19:12:11 +09:00
Yu Watanabe 0e42004f3e networkd-test.py: disable IPv6AcceptRA= if not necessary
To speed up the test. Otherwise, it takes about few seconds interfaces
to enter the configured state. And may networkd-wait-online timeouts.
2024-11-25 10:07:26 +00:00
Luca Boccassi 6fd3496cfd test: mask tmpfiles.d file shipped by selinux policy package in containers
This tmpfiles.d wants to write to sysfs, which is read-only in containers,
so systemd-tmpfiles --create fails in TEST-22-TMPFILES when ran in nspawn
if the selinux policy package is instealled. Mask it, as it's not our
config file, we don't need it in the test.
2024-11-25 15:25:55 +09:00
Daan De Meyer bb486fe9df mkosi: Use shared extra tree between initrd and main image
Let's share more between initrd and main system and use a shared
extra tree to achieve that.
2024-11-25 15:09:58 +09:00
Federico Giovanardi 9d58f3b81e udev: add option to trigger parent devices despite filters
This commit add the `-i` option to `udevadm trigger` that force it to
match parent devices even if they're excluded from filters.
The rationale is that some embedded devices have a huge number of
platform devices ( ~ 4k for MX8 ) they are there because they're defined
in the device tree but there isn't any action or udev rules associated
with them.

So at boot a significant time is spend triggering and processing rules
for devices that don't produce any effect and we would like to filter
them by calling:

```
udevadm trigger --type=device --action=add -s block -s tty
```

instead of the normal

```
udevadm trigger --type=device --action=add
```

so we can use filter to filter out only subsystems for we we know that
we have rules in place that do something useful.

On the other side action / rules are not triggered until the parent is
triggered ( which is part of another subsystem), so the additional option
will allows udev to complete the coldplug with only the devices we care.

Example on iMX8:

.Without the new option
```
root@dev:~# udevadm trigger --dry-run  -s block --action=add -v
/sys/devices/platform/bus@5b000000/5b010000.mmc/mmc_host/mmc0/mmc0:0001/block/mmcblk0
/sys/devices/platform/bus@5b000000/5b010000.mmc/mmc_host/mmc0/mmc0:0001/block/mmcblk0/mmcblk0boot0
/sys/devices/platform/bus@5b000000/5b010000.mmc/mmc_host/mmc0/mmc0:0001/block/mmcblk0/mmcblk0boot1
/sys/devices/platform/bus@5b000000/5b010000.mmc/mmc_host/mmc0/mmc0:0001/block/mmcblk0/mmcblk0p1
/sys/devices/platform/bus@5b000000/5b010000.mmc/mmc_host/mmc0/mmc0:0001/block/mmcblk0/mmcblk0p2
/sys/devices/platform/bus@5b000000/5b010000.mmc/mmc_host/mmc0/mmc0:0001/block/mmcblk0/mmcblk0p3
/sys/devices/platform/bus@5b000000/5b010000.mmc/mmc_host/mmc0/mmc0:0001/block/mmcblk0/mmcblk0p4
```

.With the new option
```
root@dev:~# udevadm trigger --dry-run -i -s block --action=add -v
/sys/devices/platform
/sys/devices/platform/bus@5b000000
/sys/devices/platform/bus@5b000000/5b010000.mmc
/sys/devices/platform/bus@5b000000/5b010000.mmc/mmc_host/mmc0
/sys/devices/platform/bus@5b000000/5b010000.mmc/mmc_host/mmc0/mmc0:0001
/sys/devices/platform/bus@5b000000/5b010000.mmc/mmc_host/mmc0/mmc0:0001/block/mmcblk0
/sys/devices/platform/bus@5b000000/5b010000.mmc/mmc_host/mmc0/mmc0:0001/block/mmcblk0/mmcblk0boot0
/sys/devices/platform/bus@5b000000/5b010000.mmc/mmc_host/mmc0/mmc0:0001/block/mmcblk0/mmcblk0boot1
/sys/devices/platform/bus@5b000000/5b010000.mmc/mmc_host/mmc0/mmc0:0001/block/mmcblk0/mmcblk0p1
/sys/devices/platform/bus@5b000000/5b010000.mmc/mmc_host/mmc0/mmc0:0001/block/mmcblk0/mmcblk0p2
/sys/devices/platform/bus@5b000000/5b010000.mmc/mmc_host/mmc0/mmc0:0001/block/mmcblk0/mmcblk0p3
/sys/devices/platform/bus@5b000000/5b010000.mmc/mmc_host/mmc0/mmc0:0001/block/mmcblk0/mmcblk0p4
```
Boot time reduction with this is place is ~ 1 second.
2024-11-21 09:00:51 +01:00
26 changed files with 217 additions and 62 deletions

View File

@ -577,6 +577,17 @@
<xi:include href="version-info.xml" xpointer="v251"/>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--include-parents</option></term>
<listitem>
<para>Trigger parent devices of found devices even if the parents
won't match the filter condition.
This is useful if we are interested to limit the coldplug activities to
some devices or subsystems.</para>
<xi:include href="version-info.xml" xpointer="v258"/>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-w</option></term>
<term><option>--settle</option></term>

View File

@ -38,9 +38,8 @@ SignExpectedPcr=yes
[Content]
ExtraTrees=
mkosi.extra.common
mkosi.crt:/usr/lib/verity.d/mkosi.crt # sysext verification key
mkosi.leak-sanitizer-suppressions:/usr/lib/systemd/leak-sanitizer-suppressions
mkosi.coredump-journal-storage.conf:/usr/lib/systemd/coredump.conf.d/10-coredump-journal-storage.conf
%O/minimal-0.root-%a.raw:/usr/share/minimal_0.raw
%O/minimal-0.root-%a-verity.raw:/usr/share/minimal_0.verity
%O/minimal-0.root-%a-verity-sig.raw:/usr/share/minimal_0.verity.sig

View File

@ -6,9 +6,7 @@ Include=
%D/mkosi.sanitizers
[Content]
ExtraTrees=
%D/mkosi.leak-sanitizer-suppressions:/usr/lib/systemd/leak-sanitizer-suppressions
%D/mkosi.coredump-journal-storage.conf:/usr/lib/systemd/coredump.conf.d/10-coredump-journal-storage.conf
ExtraTrees=%D/mkosi.extra.common
Packages=
findutils

View File

@ -58,7 +58,7 @@ _udevadm() {
--json --subsystem-match --subsystem-nomatch --attr-match --attr-nomatch --property-match
--tag-match --sysname-match --name-match --parent-match'
[TRIGGER_STANDALONE]='-v --verbose -n --dry-run -q --quiet -w --settle --wait-daemon --uuid
--initialized-match --initialized-nomatch'
--initialized-match --initialized-nomatch --include-parents'
[TRIGGER_ARG]='-t --type -c --action -s --subsystem-match -S --subsystem-nomatch
-a --attr-match -A --attr-nomatch -p --property-match
-g --tag-match -y --sysname-match --name-match -b --parent-match

View File

@ -38,6 +38,7 @@ _udevadm_trigger(){
'--tag-match=[Trigger events for devices with a matching tag.]:TAG' \
'--sysname-match=[Trigger events for devices with a matching sys device name.]:NAME' \
'--parent-match=[Trigger events for all children of a given device.]:NAME' \
'--include-parents[Also trigger parent devices of found devices.]' \
'--initialized-match[Trigger events for devices that are already initialized.]' \
'--initialized-nomatch[Trigger events for devices that are not initialized yet.]' \
'--uuid[Print synthetic uevent UUID.]' \

View File

@ -1058,3 +1058,8 @@ global:
sd_device_monitor_get_timeout;
sd_device_monitor_receive;
} LIBSYSTEMD_256;
LIBSYSTEMD_258 {
global:
sd_device_enumerator_add_all_parents;
} LIBSYSTEMD_257;

View File

@ -24,6 +24,17 @@ typedef enum DeviceEnumerationType {
_DEVICE_ENUMERATION_TYPE_INVALID = -EINVAL,
} DeviceEnumerationType;
typedef enum MatchFlag {
MATCH_NONE = 0,
MATCH_BASIC = 1u << 0,
MATCH_SYSNAME = 1u << 1,
MATCH_SUBSYSTEM = 1u << 2,
MATCH_PARENT = 1u << 3,
MATCH_TAG = 1u << 4,
MATCH_ALL = (1u << 5) - 1,
} MatchFlag;
struct sd_device_enumerator {
unsigned n_ref;
@ -46,6 +57,7 @@ struct sd_device_enumerator {
Set *match_tag;
Set *match_parent;
MatchInitializedType match_initialized;
MatchFlag parent_match_flags;
};
_public_ int sd_device_enumerator_new(sd_device_enumerator **ret) {
@ -61,6 +73,7 @@ _public_ int sd_device_enumerator_new(sd_device_enumerator **ret) {
.n_ref = 1,
.type = _DEVICE_ENUMERATION_TYPE_INVALID,
.match_initialized = MATCH_INITIALIZED_COMPAT,
.parent_match_flags = MATCH_ALL,
};
*ret = TAKE_PTR(enumerator);
@ -273,6 +286,15 @@ _public_ int sd_device_enumerator_allow_uninitialized(sd_device_enumerator *enum
return 1;
}
_public_ int sd_device_enumerator_add_all_parents(sd_device_enumerator *enumerator) {
assert_return(enumerator, -EINVAL);
enumerator->parent_match_flags = MATCH_NONE;
enumerator->scan_uptodate = false;
return 1;
}
int device_enumerator_add_match_is_initialized(sd_device_enumerator *enumerator, MatchInitializedType type) {
assert_return(enumerator, -EINVAL);
@ -567,15 +589,6 @@ static bool match_subsystem(sd_device_enumerator *enumerator, const char *subsys
return set_fnmatch(enumerator->match_subsystem, enumerator->nomatch_subsystem, subsystem);
}
typedef enum MatchFlag {
MATCH_SYSNAME = 1u << 0,
MATCH_SUBSYSTEM = 1u << 1,
MATCH_PARENT = 1u << 2,
MATCH_TAG = 1u << 3,
MATCH_ALL = (1u << 4) - 1,
} MatchFlag;
static int test_matches(
sd_device_enumerator *enumerator,
sd_device *device,
@ -618,18 +631,20 @@ static int test_matches(
!match_tag(enumerator, device))
return false;
r = match_initialized(enumerator, device);
if (r <= 0)
return r;
if (FLAGS_SET(flags, MATCH_BASIC)) {
r = match_initialized(enumerator, device);
if (r <= 0)
return r;
if (!match_property(enumerator->match_property, device, /* match_all = */ false))
return false;
if (!match_property(enumerator->match_property, device, /* match_all = */ false))
return false;
if (!match_property(enumerator->match_property_required, device, /* match_all = */ true))
return false;
if (!match_property(enumerator->match_property_required, device, /* match_all = */ true))
return false;
if (!device_match_sysattr(device, enumerator->match_sysattr, enumerator->nomatch_sysattr))
return false;
if (!device_match_sysattr(device, enumerator->match_sysattr, enumerator->nomatch_sysattr))
return false;
}
return true;
}
@ -743,7 +758,7 @@ static int enumerator_scan_dir_and_add_devices(
/* Also include all potentially matching parent devices in the enumeration. These are things
* like root busses e.g. /sys/devices/pci0000:00/ or /sys/devices/pnp0/, which ar not
* linked from /sys/class/ or /sys/bus/, hence pick them up explicitly here. */
k = enumerator_add_parent_devices(enumerator, device, MATCH_ALL);
k = enumerator_add_parent_devices(enumerator, device, enumerator->parent_match_flags);
if (k < 0)
r = k;
}

View File

@ -499,6 +499,41 @@ TEST(sd_device_enumerator_add_match_parent) {
}
}
TEST(sd_device_enumerator_add_all_parents) {
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
unsigned devices_count_with_parents = 0;
unsigned devices_count_without_parents = 0;
/* STEP 1: enumerate all block devices without all_parents() */
ASSERT_OK(sd_device_enumerator_new(&e));
ASSERT_OK(sd_device_enumerator_allow_uninitialized(e));
/* filter in only a subsystem */
ASSERT_OK(sd_device_enumerator_add_nomatch_sysname(e, "loop*"));
ASSERT_OK(sd_device_enumerator_add_match_subsystem(e, "block", true));
ASSERT_OK(sd_device_enumerator_add_match_property(e, "DEVTYPE", "partition"));
FOREACH_DEVICE(e, dev) {
ASSERT_TRUE(device_in_subsystem(dev, "block"));
ASSERT_TRUE(device_is_devtype(dev, "partition"));
devices_count_without_parents++;
}
log_debug("found %u devices", devices_count_without_parents);
/* STEP 2: enumerate again with all_parents() */
ASSERT_OK(sd_device_enumerator_add_all_parents(e) >= 0);
unsigned int not_filtered_parent_count = 0;
FOREACH_DEVICE(e, dev) {
if (!device_in_subsystem(dev, "block") || !device_is_devtype(dev,"partition"))
not_filtered_parent_count++;
devices_count_with_parents++;
}
log_debug("found %u devices out of %u that would have been excluded without all_parents()", not_filtered_parent_count,devices_count_with_parents);
ASSERT_EQ(devices_count_with_parents, devices_count_without_parents + not_filtered_parent_count);
}
TEST(sd_device_get_child) {
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
int r;

View File

@ -137,6 +137,7 @@ int sd_device_enumerator_add_nomatch_sysname(sd_device_enumerator *enumerator, c
int sd_device_enumerator_add_match_tag(sd_device_enumerator *enumerator, const char *tag);
int sd_device_enumerator_add_match_parent(sd_device_enumerator *enumerator, sd_device *parent);
int sd_device_enumerator_allow_uninitialized(sd_device_enumerator *enumerator);
int sd_device_enumerator_add_all_parents(sd_device_enumerator *enumerator);
/* device monitor */

View File

@ -266,6 +266,7 @@ static int help(void) {
" -y --sysname-match=NAME Trigger devices with this /sys path\n"
" --name-match=NAME Trigger devices with this /dev name\n"
" -b --parent-match=NAME Trigger devices with that parent device\n"
" --include-parents Trigger parent devices of found devices\n"
" --initialized-match Trigger devices that are already initialized\n"
" --initialized-nomatch Trigger devices that are not initialized yet\n"
" -w --settle Wait for the triggered events to complete\n"
@ -287,6 +288,7 @@ int trigger_main(int argc, char *argv[], void *userdata) {
ARG_PRIORITIZED_SUBSYSTEM,
ARG_INITIALIZED_MATCH,
ARG_INITIALIZED_NOMATCH,
ARG_INCLUDE_PARENTS,
};
static const struct option options[] = {
@ -304,6 +306,7 @@ int trigger_main(int argc, char *argv[], void *userdata) {
{ "sysname-match", required_argument, NULL, 'y' },
{ "name-match", required_argument, NULL, ARG_NAME },
{ "parent-match", required_argument, NULL, 'b' },
{ "include-parents", no_argument, NULL, ARG_INCLUDE_PARENTS },
{ "initialized-match", no_argument, NULL, ARG_INITIALIZED_MATCH },
{ "initialized-nomatch", no_argument, NULL, ARG_INITIALIZED_NOMATCH },
{ "settle", no_argument, NULL, 'w' },
@ -428,6 +431,11 @@ int trigger_main(int argc, char *argv[], void *userdata) {
return log_error_errno(r, "Failed to add parent match '%s': %m", optarg);
break;
}
case ARG_INCLUDE_PARENTS:
r = sd_device_enumerator_add_all_parents(e);
if (r < 0)
return log_error_errno(r, "Failed to always include all parents: %m");
break;
case 'w':
arg_settle = true;
break;

View File

@ -3,6 +3,7 @@
integration_tests += [
integration_test_template + {
'name' : fs.name(meson.current_source_dir()),
'coredump-exclude-regex' : '/(bash|python3.[0-9]+|systemd-executor)$',
'cmdline' : integration_test_template['cmdline'] + [
'''

View File

@ -4,6 +4,7 @@ integration_tests += [
integration_test_template + {
'name' : fs.name(meson.current_source_dir()),
'unit' : files('TEST-16-EXTEND-TIMEOUT.service'),
'coredump-exclude-regex' : '/(bash|sleep)$',
},
]

View File

@ -4,5 +4,6 @@ integration_tests += [
integration_test_template + {
'name' : fs.name(meson.current_source_dir()),
'vm' : true,
'coredump-exclude-regex' : '/(sleep|udevadm)$',
},
]

View File

@ -3,5 +3,6 @@
integration_tests += [
integration_test_template + {
'name' : fs.name(meson.current_source_dir()),
'coredump-exclude-regex' : '/(sleep|bash|systemd-notify)$',
},
]

View File

@ -4,5 +4,7 @@ integration_tests += [
integration_test_template + {
'name' : fs.name(meson.current_source_dir()),
'priority' : 10,
# TODO: Remove when https://github.com/systemd/systemd/issues/35335 is fixed.
'coredump-exclude-regex' : '/systemd-localed',
},
]

View File

@ -5,6 +5,7 @@ integration_tests += [
'name' : fs.name(meson.current_source_dir()),
'storage': 'persistent',
'vm' : true,
'coredump-exclude-regex' : '/(test-usr-dump|test-dump|bash)$',
},
]

View File

@ -6,6 +6,7 @@
import argparse
import json
import os
import re
import shlex
import subprocess
import sys
@ -32,6 +33,59 @@ ExecStart=false
"""
def process_coredumps(args: argparse.Namespace, journal_file: Path) -> bool:
# Collect executable paths of all coredumps and filter out the expected ones.
if args.coredump_exclude_regex:
exclude_regex = re.compile(args.coredump_exclude_regex)
else:
exclude_regex = None
result = subprocess.run(
[
args.mkosi,
'--directory', os.fspath(args.meson_source_dir),
'--extra-search-path', os.fspath(args.meson_build_dir),
'sandbox',
'coredumpctl',
'--file', journal_file,
'--json=short',
],
stdout=subprocess.PIPE,
text=True,
) # fmt: skip
# coredumpctl returns a non-zero exit status if there are no coredumps.
if result.returncode != 0:
return False
coredumps = json.loads(result.stdout)
coredumps = [
coredump for coredump in coredumps if not exclude_regex or not exclude_regex.search(coredump['exe'])
]
if not coredumps:
return False
subprocess.run(
[
args.mkosi,
'--directory', os.fspath(args.meson_source_dir),
'--extra-search-path', os.fspath(args.meson_build_dir),
'sandbox',
'coredumpctl',
'--file', journal_file,
'--no-pager',
'info',
*(coredump['exe'] for coredump in coredumps),
],
check=True,
) # fmt: skip
return True
def main() -> None:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--mkosi', required=True)
@ -44,6 +98,7 @@ def main() -> None:
parser.add_argument('--slow', action=argparse.BooleanOptionalAction)
parser.add_argument('--vm', action=argparse.BooleanOptionalAction)
parser.add_argument('--exit-code', required=True, type=int)
parser.add_argument('--coredump-exclude-regex', required=True)
parser.add_argument('mkosi_args', nargs='*')
args = parser.parse_args()
@ -114,7 +169,9 @@ def main() -> None:
"""
)
journal_file = None
journal_file = (args.meson_build_dir / (f'test/journal/{name}.journal')).absolute()
journal_file.unlink(missing_ok=True)
if not sys.stderr.isatty():
dropin += textwrap.dedent(
"""
@ -122,9 +179,6 @@ def main() -> None:
FailureAction=exit
"""
)
journal_file = (args.meson_build_dir / (f'test/journal/{name}.journal')).absolute()
journal_file.unlink(missing_ok=True)
elif not shell:
dropin += textwrap.dedent(
"""
@ -194,44 +248,42 @@ def main() -> None:
)
exit(77)
if journal_file and (
keep_journal == '0' or (result.returncode in (args.exit_code, 77) and keep_journal == 'fail')
coredumps = process_coredumps(args, journal_file)
if keep_journal == '0' or (
keep_journal == 'fail' and result.returncode in (args.exit_code, 77) and not coredumps
):
journal_file.unlink(missing_ok=True)
if shell or result.returncode in (args.exit_code, 77):
if shell or (result.returncode in (args.exit_code, 77) and not coredumps):
exit(0 if shell or result.returncode == args.exit_code else 77)
if journal_file:
ops = []
ops = []
if os.getenv('GITHUB_ACTIONS'):
id = os.environ['GITHUB_RUN_ID']
iteration = os.environ['GITHUB_RUN_ATTEMPT']
j = json.loads(
subprocess.run(
[
args.mkosi,
'--directory', os.fspath(args.meson_source_dir),
'--json',
'summary',
],
stdout=subprocess.PIPE,
text=True,
).stdout
) # fmt: skip
distribution = j['Images'][-1]['Distribution']
release = j['Images'][-1]['Release']
artifact = f'ci-mkosi-{id}-{iteration}-{distribution}-{release}-failed-test-journals'
ops += [f'gh run download {id} --name {artifact} -D ci/{artifact}']
journal_file = Path(f'ci/{artifact}/test/journal/{name}.journal')
if os.getenv('GITHUB_ACTIONS'):
id = os.environ['GITHUB_RUN_ID']
iteration = os.environ['GITHUB_RUN_ATTEMPT']
j = json.loads(
subprocess.run(
[
args.mkosi,
'--directory', os.fspath(args.meson_source_dir),
'--json',
'summary',
],
stdout=subprocess.PIPE,
text=True,
).stdout
) # fmt: skip
distribution = j['Images'][-1]['Distribution']
release = j['Images'][-1]['Release']
artifact = f'ci-mkosi-{id}-{iteration}-{distribution}-{release}-failed-test-journals'
ops += [f'gh run download {id} --name {artifact} -D ci/{artifact}']
journal_file = Path(f'ci/{artifact}/test/journal/{name}.journal')
ops += [f'journalctl --file {journal_file} --no-hostname -o short-monotonic -u {args.unit} -p info']
ops += [f'journalctl --file {journal_file} --no-hostname -o short-monotonic -u {args.unit} -p info']
print(
"Test failed, relevant logs can be viewed with: \n\n" f"{(' && '.join(ops))}\n",
file=sys.stderr,
)
print("Test failed, relevant logs can be viewed with: \n\n" f"{(' && '.join(ops))}\n", file=sys.stderr)
# 0 also means we failed so translate that to a non-zero exit code to mark the test as failed.
exit(result.returncode or 1)

View File

@ -297,6 +297,7 @@ integration_test_template = {
'qemu-args' : [],
'exit-code' : 123,
'vm' : false,
'coredump-exclude-regex' : '',
}
testdata_subdirs = [
'auxv',
@ -391,6 +392,7 @@ foreach integration_test : integration_tests
'--storage', integration_test['storage'],
'--firmware', integration_test['firmware'],
'--exit-code', integration_test['exit-code'].to_string(),
'--coredump-exclude-regex', integration_test['coredump-exclude-regex'],
]
if 'unit' in integration_test

View File

@ -248,6 +248,7 @@ Bridge=mybridge
[Match]
Name=mybridge
[Network]
IPv6AcceptRA=no
DNS=192.168.250.1
Address=192.168.250.33/24
Gateway=192.168.250.1
@ -540,6 +541,7 @@ MACAddress=12:34:56:78:9a:bc
[Match]
Name=dummy0
[Network]
IPv6AcceptRA=no
Address=192.168.42.100/24
DNS=192.168.42.1
Domains= ~company
@ -573,6 +575,7 @@ MACAddress=12:34:56:78:9a:bc
self.write_network('50-myvpn.network', '''[Match]
Name=dummy0
[Network]
IPv6AcceptRA=no
Address=192.168.42.100/24
DNS=192.168.42.1
Domains= ~company ~.
@ -927,6 +930,7 @@ cat <<EOF >/run/systemd/network/50-test.network
Name={ifr}
[Network]
IPv6AcceptRA=no
Address=192.168.5.1/24
{addr6}
DHCPServer=yes
@ -1006,6 +1010,7 @@ MACAddress=12:34:56:78:9a:bc
[Match]
Name=dummy0
[Network]
IPv6AcceptRA=no
Address=192.168.42.100/24
DNS=192.168.42.1
Domains= one two three four five six seven eight nine ten
@ -1035,6 +1040,7 @@ MACAddress=12:34:56:78:9a:bc
[Match]
Name=dummy0
[Network]
IPv6AcceptRA=no
Address=192.168.42.100/24
DNS=192.168.42.1
''')
@ -1107,7 +1113,12 @@ class MatchClientTest(unittest.TestCase, NetworkdTestingUtilities):
def test_basic_matching(self):
"""Verify the Name= line works throughout this class."""
self.add_veth_pair('test_if1', 'fake_if2')
self.write_network('50-test.network', "[Match]\nName=test_*\n[Network]")
self.write_network('50-test.network', '''\
[Match]
Name=test_*
[Network]
IPv6AcceptRA=no
''')
subprocess.check_call(['systemctl', 'start', 'systemd-networkd'])
self.assert_link_states(test_if1='managed', fake_if2='unmanaged')
@ -1118,11 +1129,13 @@ class MatchClientTest(unittest.TestCase, NetworkdTestingUtilities):
mac = '00:01:02:03:98:99'
self.add_veth_pair('test_veth', 'test_peer',
['addr', mac], ['addr', mac])
self.write_network('50-no-veth.network', """\
self.write_network('50-no-veth.network', '''\
[Match]
MACAddress={}
Name=!nonexistent *peer*
[Network]""".format(mac))
[Network]
IPv6AcceptRA=no
'''.format(mac))
subprocess.check_call(['systemctl', 'start', 'systemd-networkd'])
self.assert_link_states(test_veth='managed', test_peer='unmanaged')

View File

@ -6,6 +6,14 @@ set -o pipefail
# shellcheck source=test/units/test-control.sh
. "$(dirname "$0")"/test-control.sh
if systemd-detect-virt --quiet --container; then
# This comes from the selinux package and tries to write
# some files under sysfs, which will be read-only in a container,
# so mask it. It's not our tmpfiles.d file anyway.
mkdir -p /run/tmpfiles.d/
ln -s /dev/null /run/tmpfiles.d/selinux-policy.conf
fi
run_subtests
touch /testok