Compare commits

...

22 Commits

Author SHA1 Message Date
Zbigniew Jędrzejewski-Szmek 583e509c4c
Merge 0e54562082 into 0e44a351ea 2024-11-25 00:14:26 +00:00
Daan De Meyer 0e44a351ea mkosi: Make sure mkosi.clangd always runs on the host
If the editor that invokes mkosi.clangd is a flatpak, let's make sure
that mkosi is run on the host and not in the flatpak sandbox since it
won't be installed there.
2024-11-25 00:21:10 +01:00
Luca Boccassi 94eacb9329
Various mkosi and integration test fixes (#35336) 2024-11-24 18:10:03 +00:00
Daan De Meyer f458a60391 test: Lint integration-test-wrapper.py 2024-11-24 16:47:20 +01:00
Daan De Meyer ceca7c5005 test: Fix typing errors in integration-test-wrapper.py 2024-11-24 16:47:20 +01:00
Daan De Meyer 4f969b20b0 test: Format integration-test-wrapper.py 2024-11-24 16:47:20 +01:00
Daan De Meyer d6047d9fb5 ukify: Fix typing error 2024-11-24 16:47:20 +01:00
Daan De Meyer a2aacbfad5 Move mypy.ini and ruff.toml to top level
This allows reusing them for integration-test-wrapper.py as well.
2024-11-24 16:47:20 +01:00
Daan De Meyer 6d2fd490cf integration-test-wrapper: Remove unneeded format strings 2024-11-24 16:47:20 +01:00
Daan De Meyer c859b310ed mkosi: Add github CLI to tools 2024-11-24 16:47:20 +01:00
Daan De Meyer 51cd3dec2a mkosi: Add dnf and dnf5 to sanitizer workaround list 2024-11-24 16:47:20 +01:00
Daan De Meyer fdc4706850 mkosi: Install clangd everywhere 2024-11-24 16:47:20 +01:00
Daan De Meyer 506403f561 mkosi: Use bash to execute command -v
command is only an executable on Fedora due to a downstream patch,
on Arch for example it's only a builtin so we have to use bash to
execute command -v to get proper results on Arch.
2024-11-24 16:47:18 +01:00
Daan De Meyer 6fd5df6005 mkosi: Add shellcheck to tools 2024-11-24 16:47:04 +01:00
Daan De Meyer a197604af4 mkosi: update to latest 2024-11-24 16:47:04 +01:00
Vito Caputo 4f3df8c1bb NEWS: add blurb thanking Nick Owens
Nick's largely responsible for nerd-sniping me into fixing #34516
and did most of the testing.
2024-11-24 16:31:27 +09:00
白一百 8c18851e7e
hwdb: add entry for Chuwi Hi10 X1 (#35331)
https://www.chuwi.com/product/items/chuwi-hi10-x1.html
Rotated -90 degrees in the Z axis.
2024-11-24 16:30:33 +09:00
Yu Watanabe 5b2926d941 curl-util: do not configure new io event source when the event loop is already dead
Similar to c5ecf09494, but for io event source.

Fixes #35322.
2024-11-23 22:49:57 +01:00
Ani Sinha 4b356c90dc measure: add 'dtbauto' option in help message
'dtbauto' command line was missing from the help string. Add it.
2024-11-23 12:43:34 +00:00
Léane GRASSER f28e16d14e po: Translated using Weblate (French)
Currently translated at 100.0% (257 of 257 strings)

Co-authored-by: Léane GRASSER <leane.grasser@proton.me>
Translate-URL: https://translate.fedoraproject.org/projects/systemd/main/fr/
Translation: systemd/main
2024-11-23 20:49:18 +09:00
Zbigniew Jędrzejewski-Szmek 0e54562082 logind: define flags enum for manager_is_inhibited()
The most common case of block=true, ignore_inactive=false is mapped to flags=0.

For https://github.com/systemd/systemd/issues/34091.
2024-11-20 13:23:12 +01:00
Zbigniew Jędrzejewski-Szmek 03af199aaf logind: drop one duplicate param in manager_is_inhibited()
In the review in https://github.com/systemd/systemd/pull/30307#pullrequestreview-2255002732
removal of the excessive boolean parameters was requested. We don't need
a separate boolean param here, since we always pass true with a uid and
false otherwise.
2024-11-20 09:44:01 +01:00
26 changed files with 169 additions and 106 deletions

View File

@ -37,7 +37,7 @@ jobs:
VALIDATE_GITHUB_ACTIONS: true VALIDATE_GITHUB_ACTIONS: true
- name: Check that tabs are not used in Python code - name: Check that tabs are not used in Python code
run: sh -c '! git grep -P "\\t" -- src/ukify/ukify.py' run: sh -c '! git grep -P "\\t" -- src/ukify/ukify.py test/integration-test-wrapper.py'
- name: Install ruff and mypy - name: Install ruff and mypy
run: | run: |
@ -47,14 +47,14 @@ jobs:
- name: Run mypy - name: Run mypy
run: | run: |
python3 -m mypy --version python3 -m mypy --version
python3 -m mypy src/ukify/ukify.py python3 -m mypy src/ukify/ukify.py test/integration-test-wrapper.py
- name: Run ruff check - name: Run ruff check
run: | run: |
ruff --version ruff --version
ruff check src/ukify/ukify.py ruff check src/ukify/ukify.py test/integration-test-wrapper.py
- name: Run ruff format - name: Run ruff format
run: | run: |
ruff --version ruff --version
ruff format --check src/ukify/ukify.py ruff format --check src/ukify/ukify.py test/integration-test-wrapper.py

View File

@ -105,7 +105,7 @@ jobs:
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- uses: systemd/mkosi@8976a0abb19221e65300222f2d33067970cca0f1 - uses: systemd/mkosi@0825cca8084674ec8fa27502134b1bc601f79e0c
# Freeing up disk space with rm -rf can take multiple minutes. Since we don't need the extra free space # Freeing up disk space with rm -rf can take multiple minutes. Since we don't need the extra free space
# immediately, we remove the files in the background. However, we first move them to a different location # immediately, we remove the files in the background. However, we first move them to a different location

3
NEWS
View File

@ -764,6 +764,9 @@ CHANGES WITH 257 in spe:
other cases EnterNamespace= might be an suitable approach to acquire other cases EnterNamespace= might be an suitable approach to acquire
symbolized backtraces.) symbolized backtraces.)
Special thanks to Nick Owens for bringing attention to and testing
fixes for issue #34516.
Contributions from: 12paper, A. Wilcox, Abderrahim Kitouni, Contributions from: 12paper, A. Wilcox, Abderrahim Kitouni,
Adrian Vovk, Alain Greppin, Allison Karlitskaya, Alyssa Ross, Adrian Vovk, Alain Greppin, Allison Karlitskaya, Alyssa Ross,
Anders Jonsson, Andika Triwidada, Andres Beltran, Anouk Ceyssens, Anders Jonsson, Andika Triwidada, Andres Beltran, Anouk Ceyssens,

View File

@ -295,6 +295,10 @@ sensor:modalias:acpi:MXC6655*:dmi:*:svnCHUWIInnovationAndTechnology*:pnHi10X:*
sensor:modalias:acpi:KIOX000A*:dmi:*:svnCHUWIInnovationAndTechnology*:pnHi10X:* sensor:modalias:acpi:KIOX000A*:dmi:*:svnCHUWIInnovationAndTechnology*:pnHi10X:*
ACCEL_MOUNT_MATRIX=0, -1, 0; -1, 0, 0; 0, 0, 1 ACCEL_MOUNT_MATRIX=0, -1, 0; -1, 0, 0; 0, 0, 1
# Chuwi Hi10 X1
sensor:modalias:acpi:NSA2513*:dmi:*:svnCHUWIInnovationAndTechnology*:pnHi10X1:*
ACCEL_MOUNT_MATRIX=0, 1, 0; -1, 0, 0; 0, 0, 1
# Chuwi Hi10 Go # Chuwi Hi10 Go
sensor:modalias:acpi:MXC6655*:dmi:*:svnCHUWIINNOVATIONLIMITED:pnHi10Go:* sensor:modalias:acpi:MXC6655*:dmi:*:svnCHUWIINNOVATIONLIMITED:pnHi10Go:*
ACCEL_MOUNT_MATRIX=-1, 0, 0; 0,-1, 0; 0, 0, 1 ACCEL_MOUNT_MATRIX=-1, 0, 0; 0,-1, 0; 0, 0, 1

View File

@ -1,12 +1,18 @@
#!/bin/bash #!/bin/bash
# SPDX-License-Identifier: LGPL-2.1-or-later # SPDX-License-Identifier: LGPL-2.1-or-later
MKOSI_CONFIG="$(mkosi --json summary | jq -r .Images[-1])" if command -v flatpak-spawn >/dev/null; then
SPAWN=(flatpak-spawn --host)
else
SPAWN=()
fi
MKOSI_CONFIG="$("${SPAWN[@]}" --host mkosi --json summary | jq -r .Images[-1])"
DISTRIBUTION="$(jq -r .Distribution <<< "$MKOSI_CONFIG")" DISTRIBUTION="$(jq -r .Distribution <<< "$MKOSI_CONFIG")"
RELEASE="$(jq -r .Release <<< "$MKOSI_CONFIG")" RELEASE="$(jq -r .Release <<< "$MKOSI_CONFIG")"
ARCH="$(jq -r .Architecture <<< "$MKOSI_CONFIG")" ARCH="$(jq -r .Architecture <<< "$MKOSI_CONFIG")"
exec mkosi \ exec "${SPAWN[@]}" mkosi \
--incremental=strict \ --incremental=strict \
--build-sources-ephemeral=no \ --build-sources-ephemeral=no \
--format=none \ --format=none \

View File

@ -6,10 +6,12 @@ ToolsTreeDistribution=arch
[Build] [Build]
ToolsTreePackages= ToolsTreePackages=
cryptsetup cryptsetup
github-cli
libcap libcap
libmicrohttpd libmicrohttpd
python-jinja python-jinja
python-pytest python-pytest
ruff ruff
shellcheck
tpm2-tss tpm2-tss
util-linux-libs util-linux-libs

View File

@ -16,3 +16,4 @@ ToolsTreePackages=
tpm2-tss-devel tpm2-tss-devel
python3-jinja2 python3-jinja2
python3-pytest python3-pytest
shellcheck

View File

@ -6,6 +6,7 @@ ToolsTreeDistribution=|ubuntu
[Build] [Build]
ToolsTreePackages= ToolsTreePackages=
gh
libblkid-dev libblkid-dev
libcap-dev libcap-dev
libcryptsetup-dev libcryptsetup-dev
@ -16,3 +17,4 @@ ToolsTreePackages=
libtss2-dev libtss2-dev
python3-jinja2 python3-jinja2
python3-pytest python3-pytest
shellcheck

View File

@ -5,4 +5,5 @@ ToolsTreeDistribution=fedora
[Build] [Build]
ToolsTreePackages= ToolsTreePackages=
gh
ruff ruff

View File

@ -5,6 +5,7 @@ ToolsTreeDistribution=opensuse
[Build] [Build]
ToolsTreePackages= ToolsTreePackages=
gh
pkgconfig(blkid) pkgconfig(blkid)
pkgconfig(libcap) pkgconfig(libcap)
pkgconfig(libcryptsetup) pkgconfig(libcryptsetup)
@ -16,3 +17,4 @@ ToolsTreePackages=
tss2-devel tss2-devel
python3-jinja2 python3-jinja2
python3-pytest python3-pytest
ShellCheck

View File

@ -13,6 +13,7 @@ Environment=
[Content] [Content]
Packages= Packages=
clang-devel
compiler-rt compiler-rt
gdb gdb
git-core git-core

View File

@ -15,6 +15,7 @@ Environment=
[Content] [Content]
Packages= Packages=
apt apt
clangd
erofs-utils erofs-utils
git-core git-core
libclang-rt-dev libclang-rt-dev

View File

@ -12,6 +12,7 @@ Environment=
[Content] [Content]
Packages= Packages=
clang
diffutils diffutils
erofs-utils erofs-utils
gcc-c++ gcc-c++

View File

@ -57,6 +57,8 @@ wrap=(
delv delv
dhcpd dhcpd
dig dig
dnf
dnf5
dmsetup dmsetup
dnsmasq dnsmasq
findmnt findmnt
@ -93,7 +95,7 @@ wrap=(
) )
for bin in "${wrap[@]}"; do for bin in "${wrap[@]}"; do
if ! mkosi-chroot command -v "$bin" >/dev/null; then if ! mkosi-chroot bash -c "command -v $bin" >/dev/null; then
continue continue
fi fi
@ -103,7 +105,7 @@ for bin in "${wrap[@]}"; do
enable_lsan=0 enable_lsan=0
fi fi
target="$(mkosi-chroot command -v "$bin")" target="$(mkosi-chroot bash -c "command -v $bin")"
mv "$BUILDROOT/$target" "$BUILDROOT/$target.orig" mv "$BUILDROOT/$target" "$BUILDROOT/$target.orig"

View File

@ -12,7 +12,7 @@ msgid ""
msgstr "" msgstr ""
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-11-06 14:42+0000\n" "POT-Creation-Date: 2024-11-06 14:42+0000\n"
"PO-Revision-Date: 2024-11-20 19:13+0000\n" "PO-Revision-Date: 2024-11-23 10:38+0000\n"
"Last-Translator: Léane GRASSER <leane.grasser@proton.me>\n" "Last-Translator: Léane GRASSER <leane.grasser@proton.me>\n"
"Language-Team: French <https://translate.fedoraproject.org/projects/systemd/" "Language-Team: French <https://translate.fedoraproject.org/projects/systemd/"
"main/fr/>\n" "main/fr/>\n"
@ -1258,7 +1258,7 @@ msgstr ""
#: src/sysupdate/org.freedesktop.sysupdate1.policy:75 #: src/sysupdate/org.freedesktop.sysupdate1.policy:75
msgid "Manage optional features" msgid "Manage optional features"
msgstr "Gérer les fonctionnalités en option" msgstr "Gérer les fonctionnalités facultatives"
#: src/sysupdate/org.freedesktop.sysupdate1.policy:76 #: src/sysupdate/org.freedesktop.sysupdate1.policy:76
msgid "Authentication is required to manage optional features" msgid "Authentication is required to manage optional features"

View File

@ -75,6 +75,10 @@ static int curl_glue_socket_callback(CURL *curl, curl_socket_t s, int action, vo
return 0; return 0;
} }
/* Don't configure io event source anymore when the event loop is dead already. */
if (g->event && sd_event_get_state(g->event) == SD_EVENT_FINISHED)
return 0;
r = hashmap_ensure_allocated(&g->ios, &trivial_hash_ops); r = hashmap_ensure_allocated(&g->ios, &trivial_hash_ops);
if (r < 0) { if (r < 0) {
log_oom(); log_oom();

View File

@ -234,7 +234,7 @@ static int handle_action_execute(
/* If the actual operation is inhibited, warn and fail */ /* If the actual operation is inhibited, warn and fail */
if (inhibit_what_is_valid(inhibit_operation) && if (inhibit_what_is_valid(inhibit_operation) &&
!ignore_inhibited && !ignore_inhibited &&
manager_is_inhibited(m, inhibit_operation, /* block= */ true, NULL, false, false, 0, &offending)) { manager_is_inhibited(m, inhibit_operation, NULL, /* flags= */ 0, UID_INVALID, &offending)) {
_cleanup_free_ char *comm = NULL, *u = NULL; _cleanup_free_ char *comm = NULL, *u = NULL;
(void) pidref_get_comm(&offending->pid, &comm); (void) pidref_get_comm(&offending->pid, &comm);
@ -372,7 +372,7 @@ int manager_handle_action(
/* If the key handling is inhibited, don't do anything */ /* If the key handling is inhibited, don't do anything */
if (inhibit_key > 0) { if (inhibit_key > 0) {
if (manager_is_inhibited(m, inhibit_key, /* block= */ true, NULL, true, false, 0, NULL)) { if (manager_is_inhibited(m, inhibit_key, NULL, MANAGER_IS_INHIBITED_IGNORE_INACTIVE, UID_INVALID, NULL)) {
log_debug("Refusing %s operation, %s is inhibited.", log_debug("Refusing %s operation, %s is inhibited.",
handle_action_to_string(handle), handle_action_to_string(handle),
inhibit_what_to_string(inhibit_key)); inhibit_what_to_string(inhibit_key));

View File

@ -411,7 +411,7 @@ int manager_get_idle_hint(Manager *m, dual_timestamp *t) {
assert(m); assert(m);
idle_hint = !manager_is_inhibited(m, INHIBIT_IDLE, /* block= */ true, t, false, false, 0, NULL); idle_hint = !manager_is_inhibited(m, INHIBIT_IDLE, t, /* flags= */ 0, UID_INVALID, NULL);
HASHMAP_FOREACH(s, m->sessions) { HASHMAP_FOREACH(s, m->sessions) {
dual_timestamp k; dual_timestamp k;

View File

@ -1931,7 +1931,12 @@ int manager_dispatch_delayed(Manager *manager, bool timeout) {
if (!manager->delayed_action || manager->action_job) if (!manager->delayed_action || manager->action_job)
return 0; return 0;
if (manager_is_inhibited(manager, manager->delayed_action->inhibit_what, /* block= */ false, NULL, false, false, 0, &offending)) { if (manager_is_inhibited(manager,
manager->delayed_action->inhibit_what,
NULL,
MANAGER_IS_INHIBITED_CHECK_DELAY,
UID_INVALID,
&offending)) {
_cleanup_free_ char *comm = NULL, *u = NULL; _cleanup_free_ char *comm = NULL, *u = NULL;
if (!timeout) if (!timeout)
@ -2033,7 +2038,7 @@ int bus_manager_shutdown_or_sleep_now_or_later(
delayed = delayed =
m->inhibit_delay_max > 0 && m->inhibit_delay_max > 0 &&
manager_is_inhibited(m, a->inhibit_what, /* block= */ false, NULL, false, false, 0, NULL); manager_is_inhibited(m, a->inhibit_what, NULL, MANAGER_IS_INHIBITED_CHECK_DELAY, UID_INVALID, NULL);
if (delayed) if (delayed)
/* Shutdown is delayed, keep in mind what we /* Shutdown is delayed, keep in mind what we
@ -2077,7 +2082,7 @@ static int verify_shutdown_creds(
return r; return r;
multiple_sessions = r > 0; multiple_sessions = r > 0;
blocked = manager_is_inhibited(m, a->inhibit_what, /* block= */ true, NULL, false, true, uid, &offending); blocked = manager_is_inhibited(m, a->inhibit_what, NULL, /* flags= */ 0, uid, &offending);
interactive = flags & SD_LOGIND_INTERACTIVE; interactive = flags & SD_LOGIND_INTERACTIVE;
if (multiple_sessions) { if (multiple_sessions) {
@ -2820,7 +2825,7 @@ static int method_can_shutdown_or_sleep(
return r; return r;
multiple_sessions = r > 0; multiple_sessions = r > 0;
blocked = manager_is_inhibited(m, a->inhibit_what, /* block= */ true, NULL, false, true, uid, NULL); blocked = manager_is_inhibited(m, a->inhibit_what, NULL, /* flags= */ 0, uid, NULL);
if (check_unit_state && a->target) { if (check_unit_state && a->target) {
_cleanup_free_ char *load_state = NULL; _cleanup_free_ char *load_state = NULL;

View File

@ -399,11 +399,9 @@ static int pidref_is_active_session(Manager *m, const PidRef *pid) {
bool manager_is_inhibited( bool manager_is_inhibited(
Manager *m, Manager *m,
InhibitWhat w, InhibitWhat w,
bool block,
dual_timestamp *since, dual_timestamp *since,
bool ignore_inactive, ManagerIsInhibitedFlags flags,
bool ignore_uid, uid_t uid_to_ignore,
uid_t uid,
Inhibitor **ret_offending) { Inhibitor **ret_offending) {
Inhibitor *i, *offending = NULL; Inhibitor *i, *offending = NULL;
@ -421,18 +419,19 @@ bool manager_is_inhibited(
if (!(i->what & w)) if (!(i->what & w))
continue; continue;
if ((block && !IN_SET(i->mode, INHIBIT_BLOCK, INHIBIT_BLOCK_WEAK)) || if ((flags & MANAGER_IS_INHIBITED_CHECK_DELAY) != (i->mode == INHIBIT_DELAY))
(!block && i->mode != INHIBIT_DELAY))
continue; continue;
if (ignore_inactive && pidref_is_active_session(m, &i->pid) <= 0) if ((flags & MANAGER_IS_INHIBITED_IGNORE_INACTIVE) &&
pidref_is_active_session(m, &i->pid) <= 0)
continue; continue;
if (i->mode == INHIBIT_BLOCK_WEAK && ignore_uid && i->uid == uid) if (i->mode == INHIBIT_BLOCK_WEAK &&
uid_is_valid(uid_to_ignore) &&
uid_to_ignore == i->uid)
continue; continue;
if (!inhibited || if (!inhibited || i->since.monotonic < ts.monotonic)
i->since.monotonic < ts.monotonic)
ts = i->since; ts = i->since;
inhibited = true; inhibited = true;

View File

@ -67,7 +67,20 @@ int inhibitor_create_fifo(Inhibitor *i);
bool inhibitor_is_orphan(Inhibitor *i); bool inhibitor_is_orphan(Inhibitor *i);
InhibitWhat manager_inhibit_what(Manager *m, InhibitMode mode); InhibitWhat manager_inhibit_what(Manager *m, InhibitMode mode);
bool manager_is_inhibited(Manager *m, InhibitWhat w, bool block, dual_timestamp *since, bool ignore_inactive, bool ignore_uid, uid_t uid, Inhibitor **offending);
typedef enum ManagerIsInhibitedFlags {
MANAGER_IS_INHIBITED_CHECK_DELAY = 1 << 0, /* When set, we only check delay inhibitors.
* Otherwise, we only check block inhibitors. */
MANAGER_IS_INHIBITED_IGNORE_INACTIVE = 1 << 1, /* When set, ignore inactive sessions. */
} ManagerIsInhibitedFlags;
bool manager_is_inhibited(
Manager *m,
InhibitWhat w,
dual_timestamp *since,
ManagerIsInhibitedFlags flags,
uid_t uid_to_ignore,
Inhibitor **ret_offending);
static inline bool inhibit_what_is_valid(InhibitWhat w) { static inline bool inhibit_what_is_valid(InhibitWhat w) {
return w > 0 && w < _INHIBIT_WHAT_MAX; return w > 0 && w < _INHIBIT_WHAT_MAX;

View File

@ -108,6 +108,7 @@ static int help(int argc, char *argv[], void *userdata) {
" --ucode=PATH Path to microcode image file %7$s .ucode\n" " --ucode=PATH Path to microcode image file %7$s .ucode\n"
" --splash=PATH Path to splash bitmap file %7$s .splash\n" " --splash=PATH Path to splash bitmap file %7$s .splash\n"
" --dtb=PATH Path to DeviceTree file %7$s .dtb\n" " --dtb=PATH Path to DeviceTree file %7$s .dtb\n"
" --dtbauto=PATH Path to DeviceTree file for auto selection %7$s .dtbauto\n"
" --uname=PATH Path to 'uname -r' file %7$s .uname\n" " --uname=PATH Path to 'uname -r' file %7$s .uname\n"
" --sbat=PATH Path to SBAT file %7$s .sbat\n" " --sbat=PATH Path to SBAT file %7$s .sbat\n"
" --pcrpkey=PATH Path to public key for PCR signatures %7$s .pcrpkey\n" " --pcrpkey=PATH Path to public key for PCR signatures %7$s .pcrpkey\n"

View File

@ -467,7 +467,7 @@ class SignTool:
raise NotImplementedError() raise NotImplementedError()
@staticmethod @staticmethod
def from_string(name) -> type['SignTool']: def from_string(name: str) -> type['SignTool']:
if name == 'pesign': if name == 'pesign':
return PeSign return PeSign
elif name == 'sbsign': elif name == 'sbsign':

View File

@ -1,8 +1,7 @@
#!/usr/bin/python3 #!/usr/bin/python3
# SPDX-License-Identifier: LGPL-2.1-or-later # SPDX-License-Identifier: LGPL-2.1-or-later
'''Test wrapper command for driving integration tests. """Test wrapper command for driving integration tests."""
'''
import argparse import argparse
import json import json
@ -13,7 +12,6 @@ import sys
import textwrap import textwrap
from pathlib import Path from pathlib import Path
EMERGENCY_EXIT_DROPIN = """\ EMERGENCY_EXIT_DROPIN = """\
[Unit] [Unit]
Wants=emergency-exit.service Wants=emergency-exit.service
@ -34,7 +32,7 @@ ExecStart=false
""" """
def main(): def main() -> None:
parser = argparse.ArgumentParser(description=__doc__) parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--mkosi', required=True) parser.add_argument('--mkosi', required=True)
parser.add_argument('--meson-source-dir', required=True, type=Path) parser.add_argument('--meson-source-dir', required=True, type=Path)
@ -46,34 +44,43 @@ def main():
parser.add_argument('--slow', action=argparse.BooleanOptionalAction) parser.add_argument('--slow', action=argparse.BooleanOptionalAction)
parser.add_argument('--vm', action=argparse.BooleanOptionalAction) parser.add_argument('--vm', action=argparse.BooleanOptionalAction)
parser.add_argument('--exit-code', required=True, type=int) parser.add_argument('--exit-code', required=True, type=int)
parser.add_argument('mkosi_args', nargs="*") parser.add_argument('mkosi_args', nargs='*')
args = parser.parse_args() args = parser.parse_args()
if not bool(int(os.getenv("SYSTEMD_INTEGRATION_TESTS", "0"))): if not bool(int(os.getenv('SYSTEMD_INTEGRATION_TESTS', '0'))):
print(f"SYSTEMD_INTEGRATION_TESTS=1 not found in environment, skipping {args.name}", file=sys.stderr) print(
f'SYSTEMD_INTEGRATION_TESTS=1 not found in environment, skipping {args.name}',
file=sys.stderr,
)
exit(77) exit(77)
if args.slow and not bool(int(os.getenv("SYSTEMD_SLOW_TESTS", "0"))): if args.slow and not bool(int(os.getenv('SYSTEMD_SLOW_TESTS', '0'))):
print(f"SYSTEMD_SLOW_TESTS=1 not found in environment, skipping {args.name}", file=sys.stderr) print(
f'SYSTEMD_SLOW_TESTS=1 not found in environment, skipping {args.name}',
file=sys.stderr,
)
exit(77) exit(77)
if args.vm and bool(int(os.getenv("TEST_NO_QEMU", "0"))): if args.vm and bool(int(os.getenv('TEST_NO_QEMU', '0'))):
print(f"TEST_NO_QEMU=1, skipping {args.name}", file=sys.stderr) print(f'TEST_NO_QEMU=1, skipping {args.name}', file=sys.stderr)
exit(77) exit(77)
for s in os.getenv("TEST_SKIP", "").split(): for s in os.getenv('TEST_SKIP', '').split():
if s in args.name: if s in args.name:
print(f"Skipping {args.name} due to TEST_SKIP", file=sys.stderr) print(f'Skipping {args.name} due to TEST_SKIP', file=sys.stderr)
exit(77) exit(77)
keep_journal = os.getenv("TEST_SAVE_JOURNAL", "fail") keep_journal = os.getenv('TEST_SAVE_JOURNAL', 'fail')
shell = bool(int(os.getenv("TEST_SHELL", "0"))) shell = bool(int(os.getenv('TEST_SHELL', '0')))
if shell and not sys.stderr.isatty(): if shell and not sys.stderr.isatty():
print(f"--interactive must be passed to meson test to use TEST_SHELL=1", file=sys.stderr) print(
'--interactive must be passed to meson test to use TEST_SHELL=1',
file=sys.stderr,
)
exit(1) exit(1)
name = args.name + (f"-{i}" if (i := os.getenv("MESON_TEST_ITERATION")) else "") name = args.name + (f'-{i}' if (i := os.getenv('MESON_TEST_ITERATION')) else '')
dropin = textwrap.dedent( dropin = textwrap.dedent(
"""\ """\
@ -84,14 +91,14 @@ def main():
if not shell: if not shell:
dropin += textwrap.dedent( dropin += textwrap.dedent(
f""" """
[Unit] [Unit]
SuccessAction=exit SuccessAction=exit
SuccessActionExitStatus=123 SuccessActionExitStatus=123
""" """
) )
if os.getenv("TEST_MATCH_SUBTEST"): if os.getenv('TEST_MATCH_SUBTEST'):
dropin += textwrap.dedent( dropin += textwrap.dedent(
f""" f"""
[Service] [Service]
@ -99,7 +106,7 @@ def main():
""" """
) )
if os.getenv("TEST_MATCH_TESTCASE"): if os.getenv('TEST_MATCH_TESTCASE'):
dropin += textwrap.dedent( dropin += textwrap.dedent(
f""" f"""
[Service] [Service]
@ -116,7 +123,7 @@ def main():
""" """
) )
journal_file = (args.meson_build_dir / (f"test/journal/{name}.journal")).absolute() journal_file = (args.meson_build_dir / (f'test/journal/{name}.journal')).absolute()
journal_file.unlink(missing_ok=True) journal_file.unlink(missing_ok=True)
elif not shell: elif not shell:
dropin += textwrap.dedent( dropin += textwrap.dedent(
@ -136,54 +143,60 @@ def main():
*(['--forward-journal', journal_file] if journal_file else []), *(['--forward-journal', journal_file] if journal_file else []),
*( *(
[ [
'--credential', '--credential', f'systemd.extra-unit.emergency-exit.service={shlex.quote(EMERGENCY_EXIT_SERVICE)}', # noqa: E501
f"systemd.extra-unit.emergency-exit.service={shlex.quote(EMERGENCY_EXIT_SERVICE)}", '--credential', f'systemd.unit-dropin.emergency.target={shlex.quote(EMERGENCY_EXIT_DROPIN)}',
'--credential',
f"systemd.unit-dropin.emergency.target={shlex.quote(EMERGENCY_EXIT_DROPIN)}",
] ]
if not sys.stderr.isatty() if not sys.stderr.isatty()
else [] else []
), ),
'--credential', '--credential', f'systemd.unit-dropin.{args.unit}={shlex.quote(dropin)}',
f"systemd.unit-dropin.{args.unit}={shlex.quote(dropin)}",
'--runtime-network=none', '--runtime-network=none',
'--runtime-scratch=no', '--runtime-scratch=no',
*args.mkosi_args, *args.mkosi_args,
'--qemu-firmware', args.firmware, '--qemu-firmware',
*(['--qemu-kvm', 'no'] if int(os.getenv("TEST_NO_KVM", "0")) else []), args.firmware,
*(['--qemu-kvm', 'no'] if int(os.getenv('TEST_NO_KVM', '0')) else []),
'--kernel-command-line-extra', '--kernel-command-line-extra',
' '.join([ ' '.join(
[
'systemd.hostname=H', 'systemd.hostname=H',
f"SYSTEMD_UNIT_PATH=/usr/lib/systemd/tests/testdata/{args.name}.units:/usr/lib/systemd/tests/testdata/units:", f'SYSTEMD_UNIT_PATH=/usr/lib/systemd/tests/testdata/{args.name}.units:/usr/lib/systemd/tests/testdata/units:',
*([f"systemd.unit={args.unit}"] if not shell else []), *([f'systemd.unit={args.unit}'] if not shell else []),
'systemd.mask=systemd-networkd-wait-online.service', 'systemd.mask=systemd-networkd-wait-online.service',
*( *(
[ [
"systemd.mask=serial-getty@.service", 'systemd.mask=serial-getty@.service',
"systemd.show_status=error", 'systemd.show_status=error',
"systemd.crash_shell=0", 'systemd.crash_shell=0',
"systemd.crash_action=poweroff", 'systemd.crash_action=poweroff',
] ]
if not sys.stderr.isatty() if not sys.stderr.isatty()
else [] else []
), ),
]), ]
),
'--credential', f"journal.storage={'persistent' if sys.stderr.isatty() else args.storage}", '--credential', f"journal.storage={'persistent' if sys.stderr.isatty() else args.storage}",
*(['--runtime-build-sources=no'] if not sys.stderr.isatty() else []), *(['--runtime-build-sources=no'] if not sys.stderr.isatty() else []),
'qemu' if args.vm or os.getuid() != 0 else 'boot', 'qemu' if args.vm or os.getuid() != 0 else 'boot',
] ] # fmt: skip
result = subprocess.run(cmd) result = subprocess.run(cmd)
# On Debian/Ubuntu we get a lot of random QEMU crashes. Retry once, and then skip if it fails again. # On Debian/Ubuntu we get a lot of random QEMU crashes. Retry once, and then skip if it fails again.
if args.vm and result.returncode == 247 and args.exit_code != 247: if args.vm and result.returncode == 247 and args.exit_code != 247:
if journal_file:
journal_file.unlink(missing_ok=True) journal_file.unlink(missing_ok=True)
result = subprocess.run(cmd) result = subprocess.run(cmd)
if args.vm and result.returncode == 247 and args.exit_code != 247: if args.vm and result.returncode == 247 and args.exit_code != 247:
print(f"Test {args.name} failed due to QEMU crash (error 247), ignoring", file=sys.stderr) print(
f'Test {args.name} failed due to QEMU crash (error 247), ignoring',
file=sys.stderr,
)
exit(77) exit(77)
if journal_file and (keep_journal == "0" or (result.returncode in (args.exit_code, 77) and keep_journal == "fail")): if journal_file and (
keep_journal == '0' or (result.returncode in (args.exit_code, 77) and keep_journal == 'fail')
):
journal_file.unlink(missing_ok=True) 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):
@ -192,31 +205,33 @@ def main():
if journal_file: if journal_file:
ops = [] ops = []
if os.getenv("GITHUB_ACTIONS"): if os.getenv('GITHUB_ACTIONS'):
id = os.environ["GITHUB_RUN_ID"] id = os.environ['GITHUB_RUN_ID']
iteration = os.environ["GITHUB_RUN_ATTEMPT"] iteration = os.environ['GITHUB_RUN_ATTEMPT']
j = json.loads( j = json.loads(
subprocess.run( subprocess.run(
[ [
args.mkosi, args.mkosi,
"--directory", os.fspath(args.meson_source_dir), '--directory', os.fspath(args.meson_source_dir),
"--json", '--json',
"summary", 'summary',
], ],
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
text=True, text=True,
).stdout ).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']
print(
"Test failed, relevant logs can be viewed with: \n\n" f"{(' && '.join(ops))}\n",
file=sys.stderr,
) )
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"]
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. # 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) exit(result.returncode or 1)