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
|
||||
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
|
||||
`journalctl -x`, `journalctl --update-catalog`, `journalctl --list-catalog`
|
||||
and related calls.
|
||||
|
||||
@@ -333,6 +333,19 @@
|
||||
<xi:include href="version-info.xml" xpointer="v239"/></listitem>
|
||||
</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="version" />
|
||||
</variablelist>
|
||||
|
||||
@@ -668,6 +668,21 @@
|
||||
</listitem>
|
||||
</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>
|
||||
<term><option>--pass-ssh-key=<replaceable>BOOL</replaceable></option></term>
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ _systemd_vmspawn() {
|
||||
[BIND]='--bind --bind-ro'
|
||||
[SSH_KEY]='--ssh-key'
|
||||
[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_DISK_TYPE]='--image-disk-type'
|
||||
)
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "parse-argument.h"
|
||||
#include "parse-helpers.h"
|
||||
#include "parse-util.h"
|
||||
#include "path-util.h"
|
||||
#include "pretty-print.h"
|
||||
#include "process-util.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(
|
||||
"systemd/journal-remote.conf",
|
||||
"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.");
|
||||
#endif
|
||||
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));
|
||||
|
||||
@@ -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 r;
|
||||
|
||||
assert(!strv_isempty(argv));
|
||||
assert(ret_pidref);
|
||||
|
||||
if (!is_main_thread())
|
||||
@@ -119,7 +118,7 @@ int fork_notify(char * const *argv, PidRef *ret_pidref) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (DEBUG_LOGGING) {
|
||||
if (DEBUG_LOGGING && argv) {
|
||||
_cleanup_free_ char *l = quote_command_line(argv, SHELL_ESCAPE_EMPTY);
|
||||
log_debug("Invoking '%s' as child.", strnull(l));
|
||||
}
|
||||
@@ -141,6 +140,11 @@ int fork_notify(char * const *argv, PidRef *ret_pidref) {
|
||||
_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);
|
||||
log_debug_errno(r, "Failed to invoke %s: %m", argv[0]);
|
||||
_exit(EXIT_EXEC);
|
||||
@@ -164,7 +168,7 @@ int fork_notify(char * const *argv, PidRef *ret_pidref) {
|
||||
|
||||
*ret_pidref = TAKE_PIDREF(child);
|
||||
|
||||
return 0;
|
||||
return 1; /* In the parent */
|
||||
}
|
||||
|
||||
static void fork_notify_terminate_internal(PidRef *pidref) {
|
||||
|
||||
+65
-1
@@ -34,6 +34,7 @@
|
||||
#include "escape.h"
|
||||
#include "ether-addr-util.h"
|
||||
#include "event-util.h"
|
||||
#include "exit-status.h"
|
||||
#include "extract-word.h"
|
||||
#include "fd-util.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_exclude = 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 bool arg_keep_unit = false;
|
||||
static sd_id128_t arg_uuid = {};
|
||||
@@ -844,6 +849,30 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
return r;
|
||||
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"):
|
||||
r = parse_boolean_argument("--pass-ssh-key=", arg, &arg_pass_ssh_key);
|
||||
if (r < 0)
|
||||
@@ -923,6 +952,12 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
if (arg_ram_slots > 0 && arg_ram_max == 0)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
*ret_listen_address = TAKE_PTR(listen_address);
|
||||
|
||||
Reference in New Issue
Block a user