mirror of
https://github.com/opencontainers/runc.git
synced 2026-02-05 18:45:28 +01:00
As per - https://github.com/opencontainers/runtime-spec/pull/1253 - https://github.com/opencontainers/runtime-spec/pull/1261 CPU affinity can be set in two ways: 1. When creating/starting a container, in config.json's Process.ExecCPUAffinity, which is when applied to all execs. 2. When running an exec, in process.json's CPUAffinity, which applied to a given exec and overrides the value from (1). Add some basic tests. Note that older kernels (RHEL8, Ubuntu 20.04) change CPU affinity of a process to that of a container's cgroup, as soon as it is moved to that cgroup, while newer kernels (Ubuntu 24.04, Fedora 41) don't do that. Because of the above, - it's impossible to really test initial CPU affinity without adding debug logging to libcontainer/nsenter; - for older kernels, there can be a brief moment when exec's affinity is different than either initial or final affinity being set; - exec's final CPU affinity, if not specified, can be different depending on the kernel, therefore we don't test it. Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
89 lines
1.7 KiB
C
89 lines
1.7 KiB
C
#define _GNU_SOURCE
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include "log.h"
|
|
#include "getenv.h"
|
|
|
|
static const char *level_str[] = { "panic", "fatal", "error", "warning", "info", "debug", "trace" };
|
|
|
|
int logfd = -1;
|
|
static int loglevel = DEBUG;
|
|
|
|
extern char *escape_json_string(char *str);
|
|
void setup_logpipe(void)
|
|
{
|
|
int i;
|
|
|
|
i = getenv_int("_LIBCONTAINER_LOGPIPE");
|
|
if (i < 0) {
|
|
/* We are not runc init, or log pipe was not provided. */
|
|
return;
|
|
}
|
|
logfd = i;
|
|
|
|
i = getenv_int("_LIBCONTAINER_LOGLEVEL");
|
|
if (i < 0)
|
|
return;
|
|
loglevel = i;
|
|
}
|
|
|
|
bool log_enabled_for(int level)
|
|
{
|
|
return (logfd >= 0 && level <= loglevel);
|
|
}
|
|
|
|
/* Defined in nsexec.c */
|
|
extern int current_stage;
|
|
|
|
void write_log(int level, const char *format, ...)
|
|
{
|
|
char *message = NULL, *stage = NULL, *json = NULL;
|
|
va_list args;
|
|
int ret;
|
|
|
|
if (!log_enabled_for(level))
|
|
return;
|
|
|
|
va_start(args, format);
|
|
ret = vasprintf(&message, format, args);
|
|
va_end(args);
|
|
if (ret < 0) {
|
|
message = NULL;
|
|
goto out;
|
|
}
|
|
|
|
message = escape_json_string(message);
|
|
|
|
if (current_stage < 0) {
|
|
stage = strdup("nsexec");
|
|
if (stage == NULL)
|
|
goto out;
|
|
} else {
|
|
ret = asprintf(&stage, "nsexec-%d", current_stage);
|
|
if (ret < 0) {
|
|
stage = NULL;
|
|
goto out;
|
|
}
|
|
}
|
|
ret = asprintf(&json, "{\"level\":\"%s\", \"msg\": \"%s[%d]: %s\"}\n",
|
|
level_str[level], stage, getpid(), message);
|
|
if (ret < 0) {
|
|
json = NULL;
|
|
goto out;
|
|
}
|
|
|
|
/* This logging is on a best-effort basis. In case of a short or failed
|
|
* write there is nothing we can do, so just ignore write() errors.
|
|
*/
|
|
ssize_t __attribute__((unused)) __res = write(logfd, json, ret);
|
|
|
|
out:
|
|
free(message);
|
|
free(stage);
|
|
free(json);
|
|
}
|