Merge pull request #28082 from mrc0mmand/more-journal-remote-tests
test: add a couple of tests for systemd-journal-{remote,upload}
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
#include "main-func.h"
|
||||
#include "memory-util.h"
|
||||
#include "parse-argument.h"
|
||||
#include "parse-helpers.h"
|
||||
#include "pretty-print.h"
|
||||
#include "process-util.h"
|
||||
#include "rlimit-util.h"
|
||||
@@ -369,8 +370,8 @@ static int setup_microhttpd_server(RemoteServer *s,
|
||||
const char *cert,
|
||||
const char *trust) {
|
||||
struct MHD_OptionItem opts[] = {
|
||||
{ MHD_OPTION_NOTIFY_COMPLETED, (intptr_t) request_meta_free},
|
||||
{ MHD_OPTION_EXTERNAL_LOGGER, (intptr_t) microhttpd_logger},
|
||||
{ MHD_OPTION_NOTIFY_COMPLETED, (intptr_t) request_meta_free},
|
||||
{ MHD_OPTION_LISTEN_SOCKET, fd},
|
||||
{ MHD_OPTION_CONNECTION_MEMORY_LIMIT, 128*1024},
|
||||
{ MHD_OPTION_END},
|
||||
@@ -385,9 +386,9 @@ static int setup_microhttpd_server(RemoteServer *s,
|
||||
MHD_USE_EPOLL |
|
||||
MHD_USE_ITC;
|
||||
|
||||
_cleanup_(MHDDaemonWrapper_freep) MHDDaemonWrapper *d = NULL;
|
||||
const union MHD_DaemonInfo *info;
|
||||
int r, epoll_fd;
|
||||
MHDDaemonWrapper *d;
|
||||
|
||||
assert(fd >= 0);
|
||||
|
||||
@@ -435,75 +436,49 @@ static int setup_microhttpd_server(RemoteServer *s,
|
||||
request_handler, NULL,
|
||||
MHD_OPTION_ARRAY, opts,
|
||||
MHD_OPTION_END);
|
||||
if (!d->daemon) {
|
||||
log_error("Failed to start μhttp daemon");
|
||||
r = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
if (!d->daemon)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to start μhttp daemon");
|
||||
|
||||
log_debug("Started MHD %s daemon on fd:%d (wrapper @ %p)",
|
||||
key ? "HTTPS" : "HTTP", fd, d);
|
||||
|
||||
info = MHD_get_daemon_info(d->daemon, MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY);
|
||||
if (!info) {
|
||||
log_error("μhttp returned NULL daemon info");
|
||||
r = -EOPNOTSUPP;
|
||||
goto error;
|
||||
}
|
||||
if (!info)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "μhttp returned NULL daemon info");
|
||||
|
||||
epoll_fd = info->listen_fd;
|
||||
if (epoll_fd < 0) {
|
||||
log_error("μhttp epoll fd is invalid");
|
||||
r = -EUCLEAN;
|
||||
goto error;
|
||||
}
|
||||
if (epoll_fd < 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EUCLEAN), "μhttp epoll fd is invalid");
|
||||
|
||||
r = sd_event_add_io(s->events, &d->io_event,
|
||||
epoll_fd, EPOLLIN,
|
||||
dispatch_http_event, d);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to add event callback: %m");
|
||||
goto error;
|
||||
}
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to add event callback: %m");
|
||||
|
||||
r = sd_event_source_set_description(d->io_event, "io_event");
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to set source name: %m");
|
||||
goto error;
|
||||
}
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set source name: %m");
|
||||
|
||||
r = sd_event_add_time(s->events, &d->timer_event,
|
||||
CLOCK_MONOTONIC, UINT64_MAX, 0,
|
||||
null_timer_event_handler, d);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to add timer_event: %m");
|
||||
goto error;
|
||||
}
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to add timer_event: %m");
|
||||
|
||||
r = sd_event_source_set_description(d->timer_event, "timer_event");
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to set source name: %m");
|
||||
goto error;
|
||||
}
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set source name: %m");
|
||||
|
||||
r = hashmap_ensure_put(&s->daemons, &uint64_hash_ops, &d->fd, d);
|
||||
if (r == -ENOMEM) {
|
||||
log_oom();
|
||||
goto error;
|
||||
}
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to add daemon to hashmap: %m");
|
||||
goto error;
|
||||
}
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to add daemon to hashmap: %m");
|
||||
|
||||
TAKE_PTR(d);
|
||||
s->active++;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
MHD_stop_daemon(d->daemon);
|
||||
free(d->daemon);
|
||||
free(d);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int setup_microhttpd_socket(RemoteServer *s,
|
||||
@@ -762,7 +737,7 @@ static int parse_config(void) {
|
||||
{ "Remote", "SplitMode", config_parse_write_split_mode, 0, &arg_split_mode },
|
||||
{ "Remote", "ServerKeyFile", config_parse_path, 0, &arg_key },
|
||||
{ "Remote", "ServerCertificateFile", config_parse_path, 0, &arg_cert },
|
||||
{ "Remote", "TrustedCertificateFile", config_parse_path, 0, &arg_trust },
|
||||
{ "Remote", "TrustedCertificateFile", config_parse_path_or_ignore, 0, &arg_trust },
|
||||
{ "Remote", "MaxUse", config_parse_iec_uint64, 0, &arg_max_use },
|
||||
{ "Remote", "MaxFileSize", config_parse_iec_uint64, 0, &arg_max_size },
|
||||
{ "Remote", "MaxFiles", config_parse_uint64, 0, &arg_n_max_files },
|
||||
@@ -866,7 +841,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
case ARG_URL:
|
||||
if (arg_url)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"cannot currently set more than one --url");
|
||||
"Cannot currently set more than one --url=");
|
||||
|
||||
arg_url = optarg;
|
||||
break;
|
||||
@@ -874,7 +849,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
case ARG_GETTER:
|
||||
if (arg_getter)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"cannot currently use --getter more than once");
|
||||
"Cannot currently use --getter= more than once");
|
||||
|
||||
arg_getter = optarg;
|
||||
break;
|
||||
@@ -882,7 +857,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
case ARG_LISTEN_RAW:
|
||||
if (arg_listen_raw)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"cannot currently use --listen-raw more than once");
|
||||
"Cannot currently use --listen-raw= more than once");
|
||||
|
||||
arg_listen_raw = optarg;
|
||||
break;
|
||||
@@ -890,7 +865,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
case ARG_LISTEN_HTTP:
|
||||
if (arg_listen_http || http_socket >= 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"cannot currently use --listen-http more than once");
|
||||
"Cannot currently use --listen-http= more than once");
|
||||
|
||||
r = negative_fd(optarg);
|
||||
if (r >= 0)
|
||||
@@ -902,7 +877,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
case ARG_LISTEN_HTTPS:
|
||||
if (arg_listen_https || https_socket >= 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"cannot currently use --listen-https more than once");
|
||||
"Cannot currently use --listen-https= more than once");
|
||||
|
||||
r = negative_fd(optarg);
|
||||
if (r >= 0)
|
||||
@@ -936,27 +911,23 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
|
||||
case ARG_TRUST:
|
||||
#if HAVE_GNUTLS
|
||||
if (arg_trust || arg_trust_all)
|
||||
if (arg_trust)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Confusing trusted CA configuration");
|
||||
"Cannot use --trust more= than once");
|
||||
|
||||
if (streq(optarg, "all"))
|
||||
arg_trust_all = true;
|
||||
else {
|
||||
arg_trust = strdup(optarg);
|
||||
if (!arg_trust)
|
||||
return log_oom();
|
||||
}
|
||||
arg_trust = strdup(optarg);
|
||||
if (!arg_trust)
|
||||
return log_oom();
|
||||
#else
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Option --trust is not available.");
|
||||
"Option --trust= is not available.");
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
if (arg_output)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"cannot use --output/-o more than once");
|
||||
"Cannot use --output=/-o more than once");
|
||||
|
||||
r = parse_path_argument(optarg, /* suppress_root = */ false, &arg_output);
|
||||
if (r < 0)
|
||||
@@ -1000,7 +971,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
break;
|
||||
#else
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Option --gnutls-log is not available.");
|
||||
"Option --gnutls-log= is not available.");
|
||||
#endif
|
||||
|
||||
case '?':
|
||||
@@ -1020,12 +991,12 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
|| sd_listen_fds(false) > 0;
|
||||
if (type_a && type_b)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Cannot use file input or --getter with "
|
||||
"--arg-listen-... or socket activation.");
|
||||
"Cannot use file input or --getter= with "
|
||||
"--listen-...= or socket activation.");
|
||||
if (type_a) {
|
||||
if (!arg_output)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Option --output must be specified with file input or --getter.");
|
||||
"Option --output= must be specified with file input or --getter=.");
|
||||
|
||||
if (!IN_SET(arg_split_mode, JOURNAL_WRITE_SPLIT_NONE, _JOURNAL_WRITE_SPLIT_INVALID))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
@@ -1051,6 +1022,11 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"For SplitMode=host, output must be a directory.");
|
||||
|
||||
if (STRPTR_IN_SET(arg_trust, "-", "all")) {
|
||||
arg_trust_all = true;
|
||||
arg_trust = mfree(arg_trust);
|
||||
}
|
||||
|
||||
log_debug("Full config: SplitMode=%s Key=%s Cert=%s Trust=%s",
|
||||
journal_write_split_mode_to_string(arg_split_mode),
|
||||
strna(arg_key),
|
||||
@@ -1096,7 +1072,7 @@ static int load_certificates(char **key, char **cert, char **trust) {
|
||||
|
||||
if ((arg_listen_raw || arg_listen_http) && *trust)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Option --trust makes all non-HTTPS connections untrusted.");
|
||||
"Option --trust= makes all non-HTTPS connections untrusted.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "macro.h"
|
||||
#include "managed-journal-file.h"
|
||||
#include "parse-util.h"
|
||||
#include "parse-helpers.h"
|
||||
#include "process-util.h"
|
||||
#include "socket-util.h"
|
||||
#include "stdio-util.h"
|
||||
@@ -30,11 +31,28 @@
|
||||
|
||||
#define filename_escape(s) xescape((s), "/ ")
|
||||
|
||||
#if HAVE_MICROHTTPD
|
||||
MHDDaemonWrapper *MHDDaemonWrapper_free(MHDDaemonWrapper *d) {
|
||||
if (!d)
|
||||
return NULL;
|
||||
|
||||
if (d->daemon)
|
||||
MHD_stop_daemon(d->daemon);
|
||||
sd_event_source_unref(d->io_event);
|
||||
sd_event_source_unref(d->timer_event);
|
||||
|
||||
return mfree(d);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int open_output(RemoteServer *s, Writer *w, const char* host) {
|
||||
_cleanup_free_ char *_filename = NULL;
|
||||
const char *filename;
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
assert(w);
|
||||
|
||||
switch (s->split_mode) {
|
||||
case JOURNAL_WRITE_SPLIT_NONE:
|
||||
filename = s->output;
|
||||
@@ -104,6 +122,9 @@ int journal_remote_get_writer(RemoteServer *s, const char *host, Writer **writer
|
||||
const void *key;
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
assert(writer);
|
||||
|
||||
switch (s->split_mode) {
|
||||
case JOURNAL_WRITE_SPLIT_NONE:
|
||||
key = "one and only";
|
||||
@@ -172,6 +193,7 @@ static int get_source_for_fd(RemoteServer *s,
|
||||
|
||||
/* This takes ownership of name, but only on success. */
|
||||
|
||||
assert(s);
|
||||
assert(fd >= 0);
|
||||
assert(source);
|
||||
|
||||
@@ -275,10 +297,11 @@ int journal_remote_add_source(RemoteServer *s, int fd, char* name, bool own_name
|
||||
}
|
||||
|
||||
int journal_remote_add_raw_socket(RemoteServer *s, int fd) {
|
||||
int r;
|
||||
_unused_ _cleanup_close_ int fd_ = fd;
|
||||
char name[STRLEN("raw-socket-") + DECIMAL_STR_MAX(int) + 1];
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
assert(fd >= 0);
|
||||
|
||||
r = sd_event_add_io(s->events, &s->listen_event,
|
||||
@@ -293,7 +316,7 @@ int journal_remote_add_raw_socket(RemoteServer *s, int fd) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
fd_ = -EBADF;
|
||||
TAKE_FD(fd_);
|
||||
s->active++;
|
||||
return 0;
|
||||
}
|
||||
@@ -338,18 +361,12 @@ int journal_remote_server_init(
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if HAVE_MICROHTTPD
|
||||
static void MHDDaemonWrapper_free(MHDDaemonWrapper *d) {
|
||||
MHD_stop_daemon(d->daemon);
|
||||
sd_event_source_unref(d->io_event);
|
||||
sd_event_source_unref(d->timer_event);
|
||||
free(d);
|
||||
}
|
||||
#endif
|
||||
|
||||
void journal_remote_server_destroy(RemoteServer *s) {
|
||||
size_t i;
|
||||
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
#if HAVE_MICROHTTPD
|
||||
hashmap_free_with_destructor(s->daemons, MHDDaemonWrapper_free);
|
||||
#endif
|
||||
@@ -389,6 +406,7 @@ int journal_remote_handle_raw_source(
|
||||
* 0 if data is currently exhausted, negative on error.
|
||||
*/
|
||||
|
||||
assert(s);
|
||||
assert(fd >= 0 && fd < (ssize_t) MALLOC_ELEMENTSOF(s->sources));
|
||||
source = s->sources[fd];
|
||||
assert(source->importer.fd == fd);
|
||||
@@ -424,9 +442,11 @@ int journal_remote_handle_raw_source(
|
||||
|
||||
static int dispatch_raw_source_until_block(sd_event_source *event,
|
||||
void *userdata) {
|
||||
RemoteSource *source = userdata;
|
||||
RemoteSource *source = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
assert(event);
|
||||
|
||||
/* Make sure event stays around even if source is destroyed */
|
||||
sd_event_source_ref(event);
|
||||
|
||||
@@ -449,7 +469,7 @@ static int dispatch_raw_source_event(sd_event_source *event,
|
||||
int fd,
|
||||
uint32_t revents,
|
||||
void *userdata) {
|
||||
RemoteSource *source = userdata;
|
||||
RemoteSource *source = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
assert(source->event);
|
||||
@@ -471,7 +491,7 @@ static int dispatch_raw_source_event(sd_event_source *event,
|
||||
|
||||
static int dispatch_blocking_source_event(sd_event_source *event,
|
||||
void *userdata) {
|
||||
RemoteSource *source = userdata;
|
||||
RemoteSource *source = ASSERT_PTR(userdata);
|
||||
|
||||
return journal_remote_handle_raw_source(event, source->importer.fd, EPOLLIN, journal_remote_server_global);
|
||||
}
|
||||
@@ -485,6 +505,9 @@ static int accept_connection(
|
||||
_cleanup_close_ int fd2 = -EBADF;
|
||||
int r;
|
||||
|
||||
assert(addr);
|
||||
assert(hostname);
|
||||
|
||||
log_debug("Accepting new %s connection on fd:%d", type, fd);
|
||||
fd2 = accept4(fd, &addr->sockaddr.sa, &addr->size, SOCK_NONBLOCK|SOCK_CLOEXEC);
|
||||
if (fd2 < 0) {
|
||||
@@ -530,7 +553,7 @@ static int dispatch_raw_connection_event(
|
||||
uint32_t revents,
|
||||
void *userdata) {
|
||||
|
||||
RemoteServer *s = userdata;
|
||||
RemoteServer *s = ASSERT_PTR(userdata);
|
||||
int fd2;
|
||||
SocketAddress addr = {
|
||||
.size = sizeof(union sockaddr_union),
|
||||
|
||||
@@ -20,6 +20,9 @@ struct MHDDaemonWrapper {
|
||||
sd_event_source *io_event;
|
||||
sd_event_source *timer_event;
|
||||
};
|
||||
|
||||
MHDDaemonWrapper *MHDDaemonWrapper_free(MHDDaemonWrapper *d);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(MHDDaemonWrapper*, MHDDaemonWrapper_free);
|
||||
#endif
|
||||
|
||||
struct RemoteServer {
|
||||
|
||||
@@ -518,45 +518,6 @@ static int perform_upload(Uploader *u) {
|
||||
return update_cursor_state(u);
|
||||
}
|
||||
|
||||
static int config_parse_path_or_ignore(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
_cleanup_free_ char *n = NULL;
|
||||
bool fatal = ltype;
|
||||
char **s = ASSERT_PTR(data);
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
|
||||
if (isempty(rvalue))
|
||||
goto finalize;
|
||||
|
||||
n = strdup(rvalue);
|
||||
if (!n)
|
||||
return log_oom();
|
||||
|
||||
if (streq(n, "-"))
|
||||
goto finalize;
|
||||
|
||||
r = path_simplify_and_warn(n, PATH_CHECK_ABSOLUTE | (fatal ? PATH_CHECK_FATAL : 0), unit, filename, line, lvalue);
|
||||
if (r < 0)
|
||||
return fatal ? -ENOEXEC : 0;
|
||||
|
||||
finalize:
|
||||
return free_and_replace(*s, n);
|
||||
}
|
||||
|
||||
static int parse_config(void) {
|
||||
const ConfigTableItem items[] = {
|
||||
{ "Upload", "URL", config_parse_string, CONFIG_PARSE_STRING_SAFE, &arg_url },
|
||||
@@ -663,7 +624,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
case 'u':
|
||||
if (arg_url)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"cannot use more than one --url");
|
||||
"Cannot use more than one --url=");
|
||||
|
||||
arg_url = optarg;
|
||||
break;
|
||||
@@ -671,7 +632,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
case ARG_KEY:
|
||||
if (arg_key)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"cannot use more than one --key");
|
||||
"Cannot use more than one --key=");
|
||||
|
||||
arg_key = optarg;
|
||||
break;
|
||||
@@ -679,7 +640,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
case ARG_CERT:
|
||||
if (arg_cert)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"cannot use more than one --cert");
|
||||
"Cannot use more than one --cert=");
|
||||
|
||||
arg_cert = optarg;
|
||||
break;
|
||||
@@ -687,7 +648,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
case ARG_TRUST:
|
||||
if (arg_trust)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"cannot use more than one --trust");
|
||||
"Cannot use more than one --trust=");
|
||||
|
||||
arg_trust = optarg;
|
||||
break;
|
||||
@@ -707,7 +668,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
case 'M':
|
||||
if (arg_machine)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"cannot use more than one --machine/-M");
|
||||
"Cannot use more than one --machine=/-M");
|
||||
|
||||
arg_machine = optarg;
|
||||
break;
|
||||
@@ -715,7 +676,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
case 'D':
|
||||
if (arg_directory)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"cannot use more than one --directory/-D");
|
||||
"Cannot use more than one --directory=/-D");
|
||||
|
||||
arg_directory = optarg;
|
||||
break;
|
||||
@@ -729,7 +690,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
case ARG_CURSOR:
|
||||
if (arg_cursor)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"cannot use more than one --cursor/--after-cursor");
|
||||
"Cannot use more than one --cursor=/--after-cursor=");
|
||||
|
||||
arg_cursor = optarg;
|
||||
break;
|
||||
@@ -737,7 +698,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
case ARG_AFTER_CURSOR:
|
||||
if (arg_cursor)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"cannot use more than one --cursor/--after-cursor");
|
||||
"Cannot use more than one --cursor=/--after-cursor=");
|
||||
|
||||
arg_cursor = optarg;
|
||||
arg_after_cursor = true;
|
||||
@@ -770,11 +731,11 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
|
||||
if (!arg_url)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Required --url/-u option missing.");
|
||||
"Required --url=/-u option missing.");
|
||||
|
||||
if (!!arg_key != !!arg_cert)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Options --key and --cert must be used together.");
|
||||
"Options --key= and --cert= must be used together.");
|
||||
|
||||
if (optind < argc && (arg_directory || arg_file || arg_machine || arg_journal_type))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
|
||||
@@ -196,3 +196,42 @@ int parse_socket_bind_item(
|
||||
*port_min = mn;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_path_or_ignore(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
_cleanup_free_ char *n = NULL;
|
||||
bool fatal = ltype;
|
||||
char **s = ASSERT_PTR(data);
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
|
||||
if (isempty(rvalue))
|
||||
goto finalize;
|
||||
|
||||
n = strdup(rvalue);
|
||||
if (!n)
|
||||
return log_oom();
|
||||
|
||||
if (streq(n, "-"))
|
||||
goto finalize;
|
||||
|
||||
r = path_simplify_and_warn(n, PATH_CHECK_ABSOLUTE | (fatal ? PATH_CHECK_FATAL : 0), unit, filename, line, lvalue);
|
||||
if (r < 0)
|
||||
return fatal ? -ENOEXEC : 0;
|
||||
|
||||
finalize:
|
||||
return free_and_replace(*s, n);
|
||||
}
|
||||
|
||||
@@ -23,3 +23,15 @@ int parse_socket_bind_item(
|
||||
int *ip_protocol,
|
||||
uint16_t *nr_ports,
|
||||
uint16_t *port_min);
|
||||
|
||||
int config_parse_path_or_ignore(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata);
|
||||
|
||||
@@ -6,3 +6,4 @@
|
||||
# (at your option) any later version.
|
||||
|
||||
u systemd-journal-remote - "systemd Journal Remote"
|
||||
u systemd-journal-upload - "systemd Journal Upload"
|
||||
|
||||
@@ -57,7 +57,13 @@ curl -Lfs --header "Accept: text/event-stream" http://localhost:19531/entries |
|
||||
# Same thing as journalctl --output=export
|
||||
mkdir /tmp/remote-journal
|
||||
curl -Lfs --header "Accept: application/vnd.fdo.journal" http://localhost:19531/entries | \
|
||||
/usr/lib/systemd/systemd-journal-remote -o /tmp/remote-journal/system.journal --split-mode=none -
|
||||
/usr/lib/systemd/systemd-journal-remote --output=/tmp/remote-journal/system.journal --split-mode=none -
|
||||
journalctl --directory=/tmp/remote-journal -t "$TEST_TAG" --grep "$TEST_MESSAGE"
|
||||
rm -rf /tmp/remote-journal/*
|
||||
# Let's do the same thing again, but let systemd-journal-remote spawn curl itself
|
||||
/usr/lib/systemd/systemd-journal-remote --url=http://localhost:19531/entries \
|
||||
--output=/tmp/remote-journal/system.journal \
|
||||
--split-mode=none
|
||||
journalctl --directory=/tmp/remote-journal -t "$TEST_TAG" --grep "$TEST_MESSAGE"
|
||||
rm -rf /tmp/remote-journal
|
||||
|
||||
|
||||
Executable
+216
@@ -0,0 +1,216 @@
|
||||
#!/usr/bin/env bash
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
# shellcheck disable=SC2016
|
||||
set -eux
|
||||
set -o pipefail
|
||||
|
||||
if [[ ! -x /usr/lib/systemd/systemd-journal-remote || ! -x /usr/lib/systemd/systemd-journal-upload ]]; then
|
||||
echo "Built without systemd-journal-remote/upload support, skipping the test"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if ! command -v openssl >/dev/null; then
|
||||
echo "openssl command not available, skipping the tests"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
at_exit() {
|
||||
set +e
|
||||
|
||||
systemctl stop systemd-journal-upload
|
||||
systemctl stop systemd-journal-remote.{socket,service}
|
||||
# Remove any remote journals on exit, so we don't try to export them together
|
||||
# with the local journals, causing a mess
|
||||
rm -rf /var/log/journal/remote
|
||||
}
|
||||
|
||||
trap at_exit EXIT
|
||||
|
||||
TEST_MESSAGE="-= This is a test message $RANDOM =-"
|
||||
TEST_TAG="$(systemd-id128 new)"
|
||||
|
||||
echo "$TEST_MESSAGE" | systemd-cat -t "$TEST_TAG"
|
||||
journalctl --sync
|
||||
|
||||
/usr/lib/systemd/systemd-journal-remote --version
|
||||
/usr/lib/systemd/systemd-journal-remote --help
|
||||
/usr/lib/systemd/systemd-journal-upload --version
|
||||
/usr/lib/systemd/systemd-journal-upload --help
|
||||
|
||||
# Generate a self-signed certificate for systemd-journal-remote
|
||||
#
|
||||
# Note: older OpenSSL requires a config file with some extra options, unfortunately
|
||||
# Note2: /run here is used on purpose, since the systemd-journal-remote service uses PrivateTmp=yes
|
||||
mkdir -p /run/systemd/journal-remote-tls
|
||||
cat >/tmp/openssl.conf <<EOF
|
||||
[ req ]
|
||||
prompt = no
|
||||
distinguished_name = req_distinguished_name
|
||||
|
||||
[ req_distinguished_name ]
|
||||
C = CZ
|
||||
L = Brno
|
||||
O = Foo
|
||||
OU = Bar
|
||||
CN = localhost
|
||||
EOF
|
||||
openssl req -x509 -nodes -newkey rsa:2048 -sha256 -days 7 \
|
||||
-config /tmp/openssl.conf \
|
||||
-keyout /run/systemd/journal-remote-tls/key.pem \
|
||||
-out /run/systemd/journal-remote-tls/cert.pem
|
||||
chown -R systemd-journal-remote /run/systemd/journal-remote-tls
|
||||
|
||||
# Configure journal-upload to upload journals to journal-remote without client certificates
|
||||
mkdir -p /run/systemd/journal-{remote,upload}.conf.d
|
||||
cat >/run/systemd/journal-remote.conf.d/99-test.conf <<EOF
|
||||
[Remote]
|
||||
SplitMode=host
|
||||
ServerKeyFile=/run/systemd/journal-remote-tls/key.pem
|
||||
ServerCertificateFile=/run/systemd/journal-remote-tls/cert.pem
|
||||
TrustedCertificateFile=-
|
||||
EOF
|
||||
cat >/run/systemd/journal-upload.conf.d/99-test.conf <<EOF
|
||||
[Upload]
|
||||
URL=https://localhost:19532
|
||||
ServerKeyFile=-
|
||||
ServerCertificateFile=-
|
||||
TrustedCertificateFile=-
|
||||
EOF
|
||||
systemd-analyze cat-config systemd/journal-remote.conf
|
||||
systemd-analyze cat-config systemd/journal-upload.conf
|
||||
|
||||
systemctl restart systemd-journal-remote.socket
|
||||
systemctl restart systemd-journal-upload
|
||||
timeout 15 bash -xec 'while ! systemctl -q is-active systemd-journal-remote.service; do sleep 1; done'
|
||||
systemctl status systemd-journal-{remote,upload}
|
||||
|
||||
# It may take a bit until the whole journal is transferred
|
||||
timeout 30 bash -xec "while ! journalctl --directory=/var/log/journal/remote --identifier='$TEST_TAG' --grep='$TEST_MESSAGE'; do sleep 1; done"
|
||||
|
||||
systemctl stop systemd-journal-upload
|
||||
systemctl stop systemd-journal-remote.{socket,service}
|
||||
rm -rf /var/log/journal/remote/*
|
||||
|
||||
# Now let's do the same, but with a full PKI setup
|
||||
#
|
||||
# journal-upload keeps the cursor of the last uploaded message, so let's send a fresh one
|
||||
echo "$TEST_MESSAGE" | systemd-cat -t "$TEST_TAG"
|
||||
journalctl --sync
|
||||
|
||||
mkdir /run/systemd/remote-pki
|
||||
cat >/run/systemd/remote-pki/ca.conf <<EOF
|
||||
[ req ]
|
||||
prompt = no
|
||||
distinguished_name = req_distinguished_name
|
||||
|
||||
[ req_distinguished_name ]
|
||||
C = CZ
|
||||
L = Brno
|
||||
O = Foo
|
||||
OU = Bar
|
||||
CN = Test CA
|
||||
EOF
|
||||
cat >/run/systemd/remote-pki/client.conf <<EOF
|
||||
[ req ]
|
||||
prompt = no
|
||||
distinguished_name = req_distinguished_name
|
||||
|
||||
[ req_distinguished_name ]
|
||||
C = CZ
|
||||
L = Brno
|
||||
O = Foo
|
||||
OU = Bar
|
||||
CN = Test Client
|
||||
EOF
|
||||
cat >/run/systemd/remote-pki/server.conf <<EOF
|
||||
[ req ]
|
||||
prompt = no
|
||||
distinguished_name = req_distinguished_name
|
||||
|
||||
[ req_distinguished_name ]
|
||||
C = CZ
|
||||
L = Brno
|
||||
O = Foo
|
||||
OU = Bar
|
||||
CN = localhost
|
||||
EOF
|
||||
# Generate a dummy CA
|
||||
openssl req -x509 -nodes -newkey rsa:2048 -sha256 -days 7 \
|
||||
-config /run/systemd/remote-pki/ca.conf \
|
||||
-keyout /run/systemd/remote-pki/ca.key \
|
||||
-out /run/systemd/remote-pki/ca.crt
|
||||
echo 01 >/run/systemd/remote-pki/ca.srl
|
||||
# Generate a client key and signing request
|
||||
openssl req -nodes -newkey rsa:2048 -sha256 \
|
||||
-config /run/systemd/remote-pki/client.conf \
|
||||
-keyout /run/systemd/remote-pki/client.key \
|
||||
-out /run/systemd/remote-pki/client.csr
|
||||
# Sign the request with the CA key
|
||||
openssl x509 -req -days 7 \
|
||||
-in /run/systemd/remote-pki/client.csr \
|
||||
-CA /run/systemd/remote-pki/ca.crt \
|
||||
-CAkey /run/systemd/remote-pki/ca.key \
|
||||
-out /run/systemd/remote-pki/client.crt
|
||||
# And do the same for the server
|
||||
openssl req -nodes -newkey rsa:2048 -sha256 \
|
||||
-config /run/systemd/remote-pki/server.conf \
|
||||
-keyout /run/systemd/remote-pki/server.key \
|
||||
-out /run/systemd/remote-pki/server.csr
|
||||
openssl x509 -req -days 7 \
|
||||
-in /run/systemd/remote-pki/server.csr \
|
||||
-CA /run/systemd/remote-pki/ca.crt \
|
||||
-CAkey /run/systemd/remote-pki/ca.key \
|
||||
-out /run/systemd/remote-pki/server.crt
|
||||
setfacl -R -m "u:systemd-journal-remote:rwX" /run/systemd/remote-pki
|
||||
setfacl -R -m "u:systemd-journal-upload:rwX" /run/systemd/remote-pki
|
||||
|
||||
# Reconfigure journal-upload/journal remote with the new keys
|
||||
cat >/run/systemd/journal-remote.conf.d/99-test.conf <<EOF
|
||||
[Remote]
|
||||
SplitMode=host
|
||||
ServerKeyFile=/run/systemd/remote-pki/server.key
|
||||
ServerCertificateFile=/run/systemd/remote-pki/server.crt
|
||||
TrustedCertificateFile=/run/systemd/remote-pki/ca.crt
|
||||
EOF
|
||||
cat >/run/systemd/journal-upload.conf.d/99-test.conf <<EOF
|
||||
[Upload]
|
||||
URL=https://localhost:19532
|
||||
ServerKeyFile=/run/systemd/remote-pki/client.key
|
||||
ServerCertificateFile=/run/systemd/remote-pki/client.crt
|
||||
TrustedCertificateFile=/run/systemd/remote-pki/ca.crt
|
||||
EOF
|
||||
systemd-analyze cat-config systemd/journal-remote.conf
|
||||
systemd-analyze cat-config systemd/journal-upload.conf
|
||||
|
||||
systemctl restart systemd-journal-remote.socket
|
||||
systemctl restart systemd-journal-upload
|
||||
timeout 15 bash -xec 'while ! systemctl -q is-active systemd-journal-remote.service; do sleep 1; done'
|
||||
systemctl status systemd-journal-{remote,upload}
|
||||
|
||||
# It may take a bit until the whole journal is transferred
|
||||
timeout 30 bash -xec "while ! journalctl --directory=/var/log/journal/remote --identifier='$TEST_TAG' --grep='$TEST_MESSAGE'; do sleep 1; done"
|
||||
|
||||
systemctl stop systemd-journal-upload
|
||||
systemctl stop systemd-journal-remote.{socket,service}
|
||||
|
||||
# Let's test if journal-remote refuses connection from journal-upload with invalid client certs
|
||||
#
|
||||
# We should end up with something like this:
|
||||
# systemd-journal-remote[726]: Client is not authorized
|
||||
# systemd-journal-upload[738]: Upload to https://localhost:19532/upload failed with code 401:
|
||||
# systemd[1]: systemd-journal-upload.service: Main process exited, code=exited, status=1/FAILURE
|
||||
# systemd[1]: systemd-journal-upload.service: Failed with result 'exit-code'.
|
||||
#
|
||||
cat >/run/systemd/journal-upload.conf.d/99-test.conf <<EOF
|
||||
[Upload]
|
||||
URL=https://localhost:19532
|
||||
ServerKeyFile=/run/systemd/journal-remote-tls/key.pem
|
||||
ServerCertificateFile=/run/systemd/journal-remote-tls/cert.pem
|
||||
TrustedCertificateFile=/run/systemd/remote-pki/ca.crt
|
||||
EOF
|
||||
systemd-analyze cat-config systemd/journal-upload.conf
|
||||
setfacl -R -m "u:systemd-journal-upload:rwX" /run/systemd/journal-remote-tls
|
||||
|
||||
systemctl restart systemd-journal-upload
|
||||
timeout 10 bash -xec 'while [[ "$(systemctl show -P ActiveState systemd-journal-upload)" != failed ]]; do sleep 1; done'
|
||||
(! systemctl status systemd-journal-upload)
|
||||
Reference in New Issue
Block a user