vmspawn,journal-remote: add journal forwarding disk usage options
Add options to vmspawn to configure journal-remote disk usage limits when forwarding journal entries from the VM. These are passed through as --max-use=, --keep-free=, --max-file-size=, and --max-files= command-line arguments to systemd-journal-remote. Add --max-use=, --keep-free=, --max-file-size=, and --max-files= command-line options to systemd-journal-remote to allow overriding the corresponding settings from the configuration file. Add $SYSTEMD_JOURNAL_REMOTE_CONFIG_FILE environment variable support to systemd-journal-remote. When set, the specified file is used instead of the default configuration file and drop-in directories. When set to the empty string or /dev/null, configuration file parsing is skipped entirely. vmspawn sets this to /dev/null in the child process to avoid inheriting the host's journal-remote configuration. Make fork_notify() argv parameter optional. When NULL is passed, fork_notify() returns 0 in the child (with $NOTIFY_SOCKET set) and lets the caller run custom code before exec. Returns 1 in the parent. This allows vmspawn to set environment variables in the child without polluting the parent process. Co-developed-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
committed by
Daan De Meyer
parent
fcff958319
commit
012d87c1fc
@@ -679,6 +679,11 @@ SYSTEMD_HOME_DEBUG_SUFFIX=foo \
|
|||||||
string format. Overrides the default maximum allowed size for a file-descriptor
|
string format. Overrides the default maximum allowed size for a file-descriptor
|
||||||
based input record to be stored in the journal.
|
based input record to be stored in the journal.
|
||||||
|
|
||||||
|
* `$SYSTEMD_JOURNAL_REMOTE_CONFIG_FILE` – path to a configuration file for
|
||||||
|
`systemd-journal-remote`. When set, the specified file is used instead of the
|
||||||
|
default configuration file and drop-in directories. If set to the empty string
|
||||||
|
or `/dev/null`, configuration file parsing is skipped entirely.
|
||||||
|
|
||||||
* `$SYSTEMD_CATALOG` – path to the compiled catalog database file to use for
|
* `$SYSTEMD_CATALOG` – path to the compiled catalog database file to use for
|
||||||
`journalctl -x`, `journalctl --update-catalog`, `journalctl --list-catalog`
|
`journalctl -x`, `journalctl --update-catalog`, `journalctl --list-catalog`
|
||||||
and related calls.
|
and related calls.
|
||||||
|
|||||||
@@ -333,6 +333,19 @@
|
|||||||
<xi:include href="version-info.xml" xpointer="v239"/></listitem>
|
<xi:include href="version-info.xml" xpointer="v239"/></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>--max-use=</option></term>
|
||||||
|
<term><option>--keep-free=</option></term>
|
||||||
|
<term><option>--max-file-size=</option></term>
|
||||||
|
<term><option>--max-files=</option></term>
|
||||||
|
|
||||||
|
<listitem><para>These options override the corresponding settings from the configuration file
|
||||||
|
(see <citerefentry><refentrytitle>journal-remote.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
|
||||||
|
See that page for the descriptions of these options.</para>
|
||||||
|
|
||||||
|
<xi:include href="version-info.xml" xpointer="v261"/></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<xi:include href="standard-options.xml" xpointer="help" />
|
<xi:include href="standard-options.xml" xpointer="help" />
|
||||||
<xi:include href="standard-options.xml" xpointer="version" />
|
<xi:include href="standard-options.xml" xpointer="version" />
|
||||||
</variablelist>
|
</variablelist>
|
||||||
|
|||||||
@@ -668,6 +668,21 @@
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>--forward-journal-max-use=<replaceable>BYTES</replaceable></option></term>
|
||||||
|
<term><option>--forward-journal-keep-free=<replaceable>BYTES</replaceable></option></term>
|
||||||
|
<term><option>--forward-journal-max-file-size=<replaceable>BYTES</replaceable></option></term>
|
||||||
|
<term><option>--forward-journal-max-files=<replaceable>N</replaceable></option></term>
|
||||||
|
|
||||||
|
<listitem><para>These options configure the corresponding settings of
|
||||||
|
<citerefentry><refentrytitle>systemd-journal-remote</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||||
|
when forwarding journal entries from the VM. See
|
||||||
|
<citerefentry><refentrytitle>journal-remote.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
|
||||||
|
for the descriptions of these settings.</para>
|
||||||
|
|
||||||
|
<xi:include href="version-info.xml" xpointer="v261"/></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><option>--pass-ssh-key=<replaceable>BOOL</replaceable></option></term>
|
<term><option>--pass-ssh-key=<replaceable>BOOL</replaceable></option></term>
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ _systemd_vmspawn() {
|
|||||||
[BIND]='--bind --bind-ro'
|
[BIND]='--bind --bind-ro'
|
||||||
[SSH_KEY]='--ssh-key'
|
[SSH_KEY]='--ssh-key'
|
||||||
[CONSOLE]='--console'
|
[CONSOLE]='--console'
|
||||||
[ARG]='--cpus --ram --vsock-cid -M --machine --uuid --private-users --background --set-credential --load-credential'
|
[ARG]='--cpus --ram --vsock-cid -M --machine --uuid --private-users --background --set-credential --load-credential --forward-journal-max-use --forward-journal-keep-free --forward-journal-max-file-size --forward-journal-max-files'
|
||||||
[IMAGE_FORMAT]='--image-format'
|
[IMAGE_FORMAT]='--image-format'
|
||||||
[IMAGE_DISK_TYPE]='--image-disk-type'
|
[IMAGE_DISK_TYPE]='--image-disk-type'
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
#include "parse-argument.h"
|
#include "parse-argument.h"
|
||||||
#include "parse-helpers.h"
|
#include "parse-helpers.h"
|
||||||
#include "parse-util.h"
|
#include "parse-util.h"
|
||||||
|
#include "path-util.h"
|
||||||
#include "pretty-print.h"
|
#include "pretty-print.h"
|
||||||
#include "process-util.h"
|
#include "process-util.h"
|
||||||
#include "socket-netlink.h"
|
#include "socket-netlink.h"
|
||||||
@@ -829,6 +830,22 @@ static int parse_config(void) {
|
|||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const char *config_file = secure_getenv("SYSTEMD_JOURNAL_REMOTE_CONFIG_FILE");
|
||||||
|
if (config_file) {
|
||||||
|
if (isempty(config_file) || path_equal(config_file, "/dev/null"))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return config_parse(
|
||||||
|
/* unit= */ NULL,
|
||||||
|
config_file,
|
||||||
|
/* f= */ NULL,
|
||||||
|
"Remote\0",
|
||||||
|
config_item_table_lookup, items,
|
||||||
|
CONFIG_PARSE_WARN,
|
||||||
|
/* userdata= */ NULL,
|
||||||
|
/* ret_stat= */ NULL);
|
||||||
|
}
|
||||||
|
|
||||||
return config_parse_standard_file_with_dropins(
|
return config_parse_standard_file_with_dropins(
|
||||||
"systemd/journal-remote.conf",
|
"systemd/journal-remote.conf",
|
||||||
"Remote\0",
|
"Remote\0",
|
||||||
@@ -1004,6 +1021,30 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Option --gnutls-log= is not available.");
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Option --gnutls-log= is not available.");
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
OPTION_LONG("max-use", "BYTES", "Maximum disk space to use"):
|
||||||
|
r = parse_size(arg, 1024, &arg_max_use);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to parse --max-use= value: %s", arg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
OPTION_LONG("keep-free", "BYTES", "Minimum disk space to keep free"):
|
||||||
|
r = parse_size(arg, 1024, &arg_keep_free);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to parse --keep-free= value: %s", arg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
OPTION_LONG("max-file-size", "BYTES", "Maximum size of individual journal files"):
|
||||||
|
r = parse_size(arg, 1024, &arg_max_size);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to parse --max-file-size= value: %s", arg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
OPTION_LONG("max-files", "N", "Maximum number of journal files to keep"):
|
||||||
|
r = safe_atou64(arg, &arg_n_max_files);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to parse --max-files= value: %s", arg);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
arg_files = strv_copy(option_parser_get_args(&state));
|
arg_files = strv_copy(option_parser_get_args(&state));
|
||||||
|
|||||||
@@ -90,7 +90,6 @@ static int on_child_notify(sd_event_source *s, int fd, uint32_t revents, void *u
|
|||||||
int fork_notify(char * const *argv, PidRef *ret_pidref) {
|
int fork_notify(char * const *argv, PidRef *ret_pidref) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(!strv_isempty(argv));
|
|
||||||
assert(ret_pidref);
|
assert(ret_pidref);
|
||||||
|
|
||||||
if (!is_main_thread())
|
if (!is_main_thread())
|
||||||
@@ -119,7 +118,7 @@ int fork_notify(char * const *argv, PidRef *ret_pidref) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (DEBUG_LOGGING) {
|
if (DEBUG_LOGGING && argv) {
|
||||||
_cleanup_free_ char *l = quote_command_line(argv, SHELL_ESCAPE_EMPTY);
|
_cleanup_free_ char *l = quote_command_line(argv, SHELL_ESCAPE_EMPTY);
|
||||||
log_debug("Invoking '%s' as child.", strnull(l));
|
log_debug("Invoking '%s' as child.", strnull(l));
|
||||||
}
|
}
|
||||||
@@ -141,6 +140,11 @@ int fork_notify(char * const *argv, PidRef *ret_pidref) {
|
|||||||
_exit(EXIT_MEMORY);
|
_exit(EXIT_MEMORY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!argv) {
|
||||||
|
*ret_pidref = TAKE_PIDREF(child);
|
||||||
|
return 0; /* Let the caller run custom code in the child */
|
||||||
|
}
|
||||||
|
|
||||||
r = invoke_callout_binary(argv[0], argv);
|
r = invoke_callout_binary(argv[0], argv);
|
||||||
log_debug_errno(r, "Failed to invoke %s: %m", argv[0]);
|
log_debug_errno(r, "Failed to invoke %s: %m", argv[0]);
|
||||||
_exit(EXIT_EXEC);
|
_exit(EXIT_EXEC);
|
||||||
@@ -164,7 +168,7 @@ int fork_notify(char * const *argv, PidRef *ret_pidref) {
|
|||||||
|
|
||||||
*ret_pidref = TAKE_PIDREF(child);
|
*ret_pidref = TAKE_PIDREF(child);
|
||||||
|
|
||||||
return 0;
|
return 1; /* In the parent */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fork_notify_terminate_internal(PidRef *pidref) {
|
static void fork_notify_terminate_internal(PidRef *pidref) {
|
||||||
|
|||||||
+65
-1
@@ -34,6 +34,7 @@
|
|||||||
#include "escape.h"
|
#include "escape.h"
|
||||||
#include "ether-addr-util.h"
|
#include "ether-addr-util.h"
|
||||||
#include "event-util.h"
|
#include "event-util.h"
|
||||||
|
#include "exit-status.h"
|
||||||
#include "extract-word.h"
|
#include "extract-word.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "fileio.h"
|
#include "fileio.h"
|
||||||
@@ -159,6 +160,10 @@ static bool arg_firmware_describe = false;
|
|||||||
static Set *arg_firmware_features_include = NULL;
|
static Set *arg_firmware_features_include = NULL;
|
||||||
static Set *arg_firmware_features_exclude = NULL;
|
static Set *arg_firmware_features_exclude = NULL;
|
||||||
static char *arg_forward_journal = NULL;
|
static char *arg_forward_journal = NULL;
|
||||||
|
static uint64_t arg_forward_journal_max_use = UINT64_MAX;
|
||||||
|
static uint64_t arg_forward_journal_keep_free = UINT64_MAX;
|
||||||
|
static uint64_t arg_forward_journal_max_file_size = UINT64_MAX;
|
||||||
|
static uint64_t arg_forward_journal_max_files = UINT64_MAX;
|
||||||
static int arg_register = -1;
|
static int arg_register = -1;
|
||||||
static bool arg_keep_unit = false;
|
static bool arg_keep_unit = false;
|
||||||
static sd_id128_t arg_uuid = {};
|
static sd_id128_t arg_uuid = {};
|
||||||
@@ -844,6 +849,30 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
return r;
|
return r;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
OPTION_LONG("forward-journal-max-use", "BYTES", "Maximum disk space for forwarded journal"):
|
||||||
|
r = parse_size(arg, 1024, &arg_forward_journal_max_use);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to parse --forward-journal-max-use= value: %s", optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
OPTION_LONG("forward-journal-keep-free", "BYTES", "Minimum disk space to keep free"):
|
||||||
|
r = parse_size(arg, 1024, &arg_forward_journal_keep_free);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to parse --forward-journal-keep-free= value: %s", optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
OPTION_LONG("forward-journal-max-file-size", "BYTES", "Maximum size of individual journal files"):
|
||||||
|
r = parse_size(arg, 1024, &arg_forward_journal_max_file_size);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to parse --forward-journal-max-file-size= value: %s", optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
OPTION_LONG("forward-journal-max-files", "N", "Maximum number of journal files to keep"):
|
||||||
|
r = safe_atou64(arg, &arg_forward_journal_max_files);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to parse --forward-journal-max-files= value: %s", optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
OPTION_LONG("pass-ssh-key", "BOOL", "Create an SSH key to access the VM"):
|
OPTION_LONG("pass-ssh-key", "BOOL", "Create an SSH key to access the VM"):
|
||||||
r = parse_boolean_argument("--pass-ssh-key=", arg, &arg_pass_ssh_key);
|
r = parse_boolean_argument("--pass-ssh-key=", arg, &arg_pass_ssh_key);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@@ -923,6 +952,12 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
if (arg_ram_slots > 0 && arg_ram_max == 0)
|
if (arg_ram_slots > 0 && arg_ram_max == 0)
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Memory hotplug slots require a maximum RAM size");
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Memory hotplug slots require a maximum RAM size");
|
||||||
|
|
||||||
|
if ((arg_forward_journal_max_use != UINT64_MAX ||
|
||||||
|
arg_forward_journal_keep_free != UINT64_MAX ||
|
||||||
|
arg_forward_journal_max_file_size != UINT64_MAX ||
|
||||||
|
arg_forward_journal_max_files != UINT64_MAX) && !arg_forward_journal)
|
||||||
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--forward-journal-max-use=/--forward-journal-keep-free=/--forward-journal-max-file-size=/--forward-journal-max-files= require --forward-journal=.");
|
||||||
|
|
||||||
if (arg_ephemeral && arg_extra_drives.n_drives > 0)
|
if (arg_ephemeral && arg_extra_drives.n_drives > 0)
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot use --ephemeral with --extra-drive=");
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot use --ephemeral with --extra-drive=");
|
||||||
|
|
||||||
@@ -1628,9 +1663,38 @@ static int start_systemd_journal_remote(
|
|||||||
if (!argv)
|
if (!argv)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
r = fork_notify(argv, ret_pidref);
|
if (arg_forward_journal_max_use != UINT64_MAX &&
|
||||||
|
strv_extendf(&argv, "--max-use=%" PRIu64, arg_forward_journal_max_use) < 0)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
if (arg_forward_journal_keep_free != UINT64_MAX &&
|
||||||
|
strv_extendf(&argv, "--keep-free=%" PRIu64, arg_forward_journal_keep_free) < 0)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
if (arg_forward_journal_max_file_size != UINT64_MAX &&
|
||||||
|
strv_extendf(&argv, "--max-file-size=%" PRIu64, arg_forward_journal_max_file_size) < 0)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
if (arg_forward_journal_max_files != UINT64_MAX &&
|
||||||
|
strv_extendf(&argv, "--max-files=%" PRIu64, arg_forward_journal_max_files) < 0)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
r = fork_notify(/* argv= */ NULL, ret_pidref);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
if (r == 0) {
|
||||||
|
/* In the child */
|
||||||
|
if (setenv("SYSTEMD_JOURNAL_REMOTE_CONFIG_FILE",
|
||||||
|
"/dev/null",
|
||||||
|
/* overwrite= */ true) < 0) {
|
||||||
|
log_debug_errno(errno, "Failed to set $SYSTEMD_JOURNAL_REMOTE_CONFIG_FILE: %m");
|
||||||
|
_exit(EXIT_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
|
r = invoke_callout_binary(argv[0], argv);
|
||||||
|
log_error_errno(r, "Failed to invoke %s: %m", argv[0]);
|
||||||
|
_exit(EXIT_EXEC);
|
||||||
|
}
|
||||||
|
|
||||||
if (ret_listen_address)
|
if (ret_listen_address)
|
||||||
*ret_listen_address = TAKE_PTR(listen_address);
|
*ret_listen_address = TAKE_PTR(listen_address);
|
||||||
|
|||||||
Reference in New Issue
Block a user