diff options
Diffstat (limited to 'src/collectors/cgroups.plugin')
-rw-r--r-- | src/collectors/cgroups.plugin/README.md | 9 | ||||
-rw-r--r-- | src/collectors/cgroups.plugin/cgroup-discovery.c | 6 | ||||
-rw-r--r-- | src/collectors/cgroups.plugin/cgroup-internals.h | 8 | ||||
-rwxr-xr-x | src/collectors/cgroups.plugin/cgroup-name.sh.in | 4 | ||||
-rw-r--r-- | src/collectors/cgroups.plugin/cgroup-network.c | 257 | ||||
-rw-r--r-- | src/collectors/cgroups.plugin/cgroup-top.c | 4 | ||||
-rw-r--r-- | src/collectors/cgroups.plugin/sys_fs_cgroup.c | 37 |
7 files changed, 199 insertions, 126 deletions
diff --git a/src/collectors/cgroups.plugin/README.md b/src/collectors/cgroups.plugin/README.md index efa868bfb..dc58973af 100644 --- a/src/collectors/cgroups.plugin/README.md +++ b/src/collectors/cgroups.plugin/README.md @@ -1,12 +1,3 @@ -<!-- -title: "Monitor Cgroups (cgroups.plugin)" -custom_edit_url: "https://github.com/netdata/netdata/edit/master/src/collectors/cgroups.plugin/README.md" -sidebar_label: "Monitor Cgroups" -learn_status: "Published" -learn_topic_type: "References" -learn_rel_path: "Integrations/Monitor/Virtualized environments/Containers" ---> - # Monitor Cgroups (cgroups.plugin) You can monitor containers and virtual machines using **cgroups**. diff --git a/src/collectors/cgroups.plugin/cgroup-discovery.c b/src/collectors/cgroups.plugin/cgroup-discovery.c index d880f8a71..5d3027a47 100644 --- a/src/collectors/cgroups.plugin/cgroup-discovery.c +++ b/src/collectors/cgroups.plugin/cgroup-discovery.c @@ -23,7 +23,7 @@ struct cgroup *discovered_cgroup_root = NULL; char cgroup_chart_id_prefix[] = "cgroup_"; char services_chart_id_prefix[] = "systemd_"; -char *cgroups_rename_script = NULL; +const char *cgroups_rename_script = NULL; // Shared memory with information from detected cgroups netdata_ebpf_cgroup_shm_t shm_cgroup_ebpf = {NULL, NULL}; @@ -188,7 +188,7 @@ static inline void discovery_rename_cgroup(struct cgroup *cg) { } char buffer[CGROUP_CHARTID_LINE_MAX + 1]; - char *new_name = fgets(buffer, CGROUP_CHARTID_LINE_MAX, instance->child_stdout_fp); + char *new_name = fgets(buffer, CGROUP_CHARTID_LINE_MAX, spawn_popen_stdout(instance)); int exit_code = spawn_popen_wait(instance); switch (exit_code) { @@ -1101,7 +1101,7 @@ static inline void read_cgroup_network_interfaces(struct cgroup *cg) { char *s; char buffer[CGROUP_NETWORK_INTERFACE_MAX_LINE + 1]; - while((s = fgets(buffer, CGROUP_NETWORK_INTERFACE_MAX_LINE, instance->child_stdout_fp))) { + while((s = fgets(buffer, CGROUP_NETWORK_INTERFACE_MAX_LINE, spawn_popen_stdout(instance)))) { trim(s); if(*s && *s != '\n') { diff --git a/src/collectors/cgroups.plugin/cgroup-internals.h b/src/collectors/cgroups.plugin/cgroup-internals.h index e0d53dc93..cdb5837bd 100644 --- a/src/collectors/cgroups.plugin/cgroup-internals.h +++ b/src/collectors/cgroups.plugin/cgroup-internals.h @@ -273,7 +273,7 @@ struct discovery_thread { extern struct discovery_thread discovery_thread; -extern char *cgroups_rename_script; +extern const char *cgroups_rename_script; extern char cgroup_chart_id_prefix[]; extern char services_chart_id_prefix[]; extern uv_mutex_t cgroup_root_mutex; @@ -313,7 +313,7 @@ extern SIMPLE_PATTERN *enabled_cgroup_renames; extern SIMPLE_PATTERN *systemd_services_cgroups; extern SIMPLE_PATTERN *entrypoint_parent_process_comm; -extern char *cgroups_network_interface_script; +extern const char *cgroups_network_interface_script; extern int cgroups_check; @@ -394,8 +394,8 @@ static inline char *cgroup_chart_type(char *buffer, struct cgroup *cg) { #define RRDFUNCTIONS_CGTOP_HELP "View running containers" #define RRDFUNCTIONS_SYSTEMD_SERVICES_HELP "View systemd services" -int cgroup_function_cgroup_top(BUFFER *wb, const char *function); -int cgroup_function_systemd_top(BUFFER *wb, const char *function); +int cgroup_function_cgroup_top(BUFFER *wb, const char *function, BUFFER *payload, const char *source); +int cgroup_function_systemd_top(BUFFER *wb, const char *function, BUFFER *payload, const char *source); void cgroup_netdev_link_init(void); const DICTIONARY_ITEM *cgroup_netdev_get(struct cgroup *cg); diff --git a/src/collectors/cgroups.plugin/cgroup-name.sh.in b/src/collectors/cgroups.plugin/cgroup-name.sh.in index 0f8b63256..18755b622 100755 --- a/src/collectors/cgroups.plugin/cgroup-name.sh.in +++ b/src/collectors/cgroups.plugin/cgroup-name.sh.in @@ -155,7 +155,7 @@ function docker_like_get_name_api() { info "Running API command: curl \"${host}${path}\"" JSON=$(curl -sS "${host}${path}") fi - if OUTPUT=$(echo "${JSON}" | jq -r '.Config.Env[],"CONT_NAME=\(.Name)","IMAGE_NAME=\(.Config.Image)"') && [ -n "$OUTPUT" ]; then + if OUTPUT=$(echo "${JSON}" | jq -r '.Config.Env[]?,"CONT_NAME=\(.Name)","IMAGE_NAME=\(.Config.Image)"') && [ -n "$OUTPUT" ]; then parse_docker_like_inspect_output "$OUTPUT" fi return 0 @@ -610,7 +610,7 @@ function podman_validate_id() { DOCKER_HOST="${DOCKER_HOST:=/var/run/docker.sock}" PODMAN_HOST="${PODMAN_HOST:=/run/podman/podman.sock}" CGROUP_PATH="${1}" # the path as it is (e.g. '/docker/efcf4c409') -CGROUP="${2}" # the modified path (e.g. 'docker_efcf4c409') +CGROUP="${2//\//_}" # the modified path (e.g. 'docker_efcf4c409') EXIT_SUCCESS=0 EXIT_RETRY=2 EXIT_DISABLE=3 diff --git a/src/collectors/cgroups.plugin/cgroup-network.c b/src/collectors/cgroups.plugin/cgroup-network.c index 4cb5cbabe..d64b31288 100644 --- a/src/collectors/cgroups.plugin/cgroup-network.c +++ b/src/collectors/cgroups.plugin/cgroup-network.c @@ -3,6 +3,8 @@ #include "libnetdata/libnetdata.h" #include "libnetdata/required_dummies.h" +SPAWN_SERVER *spawn_server = NULL; + char env_netdata_host_prefix[FILENAME_MAX + 50] = ""; char env_netdata_log_method[FILENAME_MAX + 50] = ""; char env_netdata_log_format[FILENAME_MAX + 50] = ""; @@ -42,7 +44,7 @@ unsigned int read_iface_iflink(const char *prefix, const char *iface) { unsigned long long iflink = 0; int ret = read_single_number_file(filename, &iflink); - if(ret) collector_error("Cannot read '%s'.", filename); + if(ret) nd_log(NDLS_COLLECTORS, NDLP_ERR, "Cannot read '%s'.", filename); return (unsigned int)iflink; } @@ -55,7 +57,7 @@ unsigned int read_iface_ifindex(const char *prefix, const char *iface) { unsigned long long ifindex = 0; int ret = read_single_number_file(filename, &ifindex); - if(ret) collector_error("Cannot read '%s'.", filename); + if(ret) nd_log(NDLS_COLLECTORS, NDLP_ERR, "Cannot read '%s'.", filename); return (unsigned int)ifindex; } @@ -68,19 +70,15 @@ struct iface *read_proc_net_dev(const char *scope __maybe_unused, const char *pr snprintfz(filename, FILENAME_MAX, "%s%s", prefix, (*prefix)?"/proc/1/net/dev":"/proc/net/dev"); -#ifdef NETDATA_INTERNAL_CHECKS - collector_info("parsing '%s'", filename); -#endif - ff = procfile_open(filename, " \t,:|", PROCFILE_FLAG_DEFAULT); if(unlikely(!ff)) { - collector_error("Cannot open file '%s'", filename); + nd_log(NDLS_COLLECTORS, NDLP_ERR, "Cannot open file '%s'", filename); return NULL; } ff = procfile_readall(ff); if(unlikely(!ff)) { - collector_error("Cannot read file '%s'", filename); + nd_log(NDLS_COLLECTORS, NDLP_ERR, "Cannot read file '%s'", filename); return NULL; } @@ -97,9 +95,7 @@ struct iface *read_proc_net_dev(const char *scope __maybe_unused, const char *pr t->next = root; root = t; -#ifdef NETDATA_INTERNAL_CHECKS - collector_info("added %s interface '%s', ifindex %u, iflink %u", scope, t->device, t->ifindex, t->iflink); -#endif + nd_log(NDLS_COLLECTORS, NDLP_DEBUG, "added %s interface '%s', ifindex %u, iflink %u", scope, t->device, t->ifindex, t->iflink); } procfile_close(ff); @@ -143,13 +139,18 @@ static void continue_as_child(void) { int status; pid_t ret; - if (child < 0) - collector_error("fork() failed"); + if (child < 0) { + nd_log(NDLS_COLLECTORS, NDLP_ERR, "fork() failed"); + exit(1); + } - /* Only the child returns */ - if (child == 0) + if (child == 0) { + // the child returns + gettid_uncached(); return; + } + // here is the parent for (;;) { ret = waitpid(child, &status, WUNTRACED); if ((ret == child) && (WIFSTOPPED(status))) { @@ -159,9 +160,36 @@ static void continue_as_child(void) { } else { break; } + tinysleep(); } /* Return the child's exit code if possible */ + +#ifdef __SANITIZE_ADDRESS__ + /* + * With sanitization, exiting leads to an infinite loop (100% cpu) here: + * + * #0 0x00007ffff690ea8b in sched_yield () from /usr/lib/libc.so.6 + * #1 0x00007ffff792c4a6 in __sanitizer::StopTheWorld (callback=<optimized out>, argument=<optimized out>) at /usr/src/debug/gcc/gcc/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp:457 + * #2 0x00007ffff793f6f9 in __lsan::LockStuffAndStopTheWorldCallback (info=<optimized out>, size=<optimized out>, data=0x7fffffffde20) at /usr/src/debug/gcc/gcc/libsanitizer/lsan/lsan_common_linux.cpp:127 + * #3 0x00007ffff6977909 in dl_iterate_phdr () from /usr/lib/libc.so.6 + * #4 0x00007ffff793fb24 in __lsan::LockStuffAndStopTheWorld (callback=callback@entry=0x7ffff793d9d0 <__lsan::CheckForLeaksCallback(__sanitizer::SuspendedThreadsList const&, void*)>, argument=argument@entry=0x7fffffffdea0) + * at /usr/src/debug/gcc/gcc/libsanitizer/lsan/lsan_common_linux.cpp:142 + * #5 0x00007ffff793c965 in __lsan::CheckForLeaks () at /usr/src/debug/gcc/gcc/libsanitizer/lsan/lsan_common.cpp:778 + * #6 0x00007ffff793cc68 in __lsan::DoLeakCheck () at /usr/src/debug/gcc/gcc/libsanitizer/lsan/lsan_common.cpp:821 + * #7 0x00007ffff684e340 in __cxa_finalize () from /usr/lib/libc.so.6 + * #8 0x00007ffff7838c58 in __do_global_dtors_aux () from /usr/lib/libasan.so.8 + * #9 0x00007fffffffdfe0 in ?? () + * + * Probably is something related to switching name spaces. + * So, we kill -9 self. + * + */ + + nd_log(NDLS_COLLECTORS, NDLP_DEBUG, "sanitizers detected, killing myself to avoid lockup"); + kill(getpid(), SIGKILL); +#endif + if (WIFEXITED(status)) { exit(WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { @@ -179,7 +207,7 @@ int proc_pid_fd(const char *prefix, const char *ns, pid_t pid) { int fd = open(filename, O_RDONLY | O_CLOEXEC); if(fd == -1) - collector_error("Cannot open proc_pid_fd() file '%s'", filename); + nd_log(NDLS_COLLECTORS, NDLP_ERR, "Cannot open proc_pid_fd() file '%s'", filename); return fd; } @@ -203,10 +231,8 @@ static struct ns { { .nstype = 0, .fd = -1, .status = -1, .name = NULL, .path = NULL } }; -int switch_namespace(const char *prefix, pid_t pid) { - +static int switch_namespace(const char *prefix, pid_t pid) { #ifdef HAVE_SETNS - int i; for(i = 0; all_ns[i].name ; i++) all_ns[i].fd = proc_pid_fd(prefix, all_ns[i].path, pid); @@ -229,7 +255,9 @@ int switch_namespace(const char *prefix, pid_t pid) { if(setns(all_ns[i].fd, all_ns[i].nstype) == -1) { if(pass == 1) { all_ns[i].status = 0; - collector_error("Cannot switch to %s namespace of pid %d", all_ns[i].name, (int) pid); + nd_log(NDLS_COLLECTORS, NDLP_ERR, + "Cannot switch to %s namespace of pid %d", + all_ns[i].name, (int) pid); } } else @@ -238,21 +266,22 @@ int switch_namespace(const char *prefix, pid_t pid) { } } + gettid_uncached(); setgroups(0, NULL); if(root_fd != -1) { if(fchdir(root_fd) < 0) - collector_error("Cannot fchdir() to pid %d root directory", (int)pid); + nd_log(NDLS_COLLECTORS, NDLP_ERR, "Cannot fchdir() to pid %d root directory", (int)pid); if(chroot(".") < 0) - collector_error("Cannot chroot() to pid %d root directory", (int)pid); + nd_log(NDLS_COLLECTORS, NDLP_ERR, "Cannot chroot() to pid %d root directory", (int)pid); close(root_fd); } if(cwd_fd != -1) { if(fchdir(cwd_fd) < 0) - collector_error("Cannot fchdir() to pid %d current working directory", (int)pid); + nd_log(NDLS_COLLECTORS, NDLP_ERR, "Cannot fchdir() to pid %d current working directory", (int)pid); close(cwd_fd); } @@ -276,9 +305,8 @@ int switch_namespace(const char *prefix, pid_t pid) { #else errno = ENOSYS; - collector_error("setns() is missing on this system."); + nd_log(NDLS_COLLECTORS, NDLP_ERR, "setns() is missing on this system."); return 1; - #endif } @@ -286,13 +314,13 @@ pid_t read_pid_from_cgroup_file(const char *filename) { int fd = open(filename, procfile_open_flags); if(fd == -1) { if (errno != ENOENT) - collector_error("Cannot open pid_from_cgroup() file '%s'.", filename); + nd_log(NDLS_COLLECTORS, NDLP_ERR, "Cannot open pid_from_cgroup() file '%s'.", filename); return 0; } FILE *fp = fdopen(fd, "r"); if(!fp) { - collector_error("Cannot upgrade fd to fp for file '%s'.", filename); + nd_log(NDLS_COLLECTORS, NDLP_ERR, "Cannot upgrade fd to fp for file '%s'.", filename); return 0; } @@ -307,9 +335,8 @@ pid_t read_pid_from_cgroup_file(const char *filename) { fclose(fp); -#ifdef NETDATA_INTERNAL_CHECKS - if(pid > 0) collector_info("found pid %d on file '%s'", pid, filename); -#endif + if(pid > 0) + nd_log(NDLS_COLLECTORS, NDLP_DEBUG, "found pid %d on file '%s'", pid, filename); return pid; } @@ -331,7 +358,7 @@ pid_t read_pid_from_cgroup(const char *path) { DIR *dir = opendir(path); if (!dir) { - collector_error("cannot read directory '%s'", path); + nd_log(NDLS_COLLECTORS, NDLP_ERR, "cannot read directory '%s'", path); return 0; } @@ -368,9 +395,8 @@ struct found_device { } *detected_devices = NULL; void add_device(const char *host, const char *guest) { -#ifdef NETDATA_INTERNAL_CHECKS - collector_info("adding device with host '%s', guest '%s'", host, guest); -#endif + errno_clear(); + nd_log(NDLS_COLLECTORS, NDLP_DEBUG, "adding device with host '%s', guest '%s'", host, guest); uint32_t hash = simple_hash(host); @@ -422,36 +448,34 @@ void detect_veth_interfaces(pid_t pid) { host = read_proc_net_dev("host", netdata_configured_host_prefix); if(!host) { errno_clear(); - collector_error("cannot read host interface list."); + nd_log(NDLS_COLLECTORS, NDLP_WARNING, "no host interface list."); goto cleanup; } if(!eligible_ifaces(host)) { errno_clear(); - collector_info("there are no double-linked host interfaces available."); + nd_log(NDLS_COLLECTORS, NDLP_WARNING, "no double-linked host interfaces available."); goto cleanup; } if(switch_namespace(netdata_configured_host_prefix, pid)) { errno_clear(); - collector_error("cannot switch to the namespace of pid %u", (unsigned int) pid); + nd_log(NDLS_COLLECTORS, NDLP_ERR, "cannot switch to the namespace of pid %u", (unsigned int) pid); goto cleanup; } -#ifdef NETDATA_INTERNAL_CHECKS - collector_info("switched to namespaces of pid %d", pid); -#endif + nd_log(NDLS_COLLECTORS, NDLP_DEBUG, "switched to namespaces of pid %d", pid); cgroup = read_proc_net_dev("cgroup", NULL); if(!cgroup) { errno_clear(); - collector_error("cannot read cgroup interface list."); + nd_log(NDLS_COLLECTORS, NDLP_ERR, "cannot read cgroup interface list."); goto cleanup; } if(!eligible_ifaces(cgroup)) { errno_clear(); - collector_error("there are not double-linked cgroup interfaces available."); + nd_log(NDLS_COLLECTORS, NDLP_ERR, "there are not double-linked cgroup interfaces available."); goto cleanup; } @@ -478,66 +502,113 @@ void detect_veth_interfaces(pid_t pid) { if(iface_is_eligible(h)) { for (c = cgroup; c; c = c->next) { if(iface_is_eligible(c) && h->ifindex == c->iflink && h->iflink == c->ifindex) { - add_device(h->device, c->device); + printf("%s %s\n", h->device, c->device); + // add_device(h->device, c->device); } } } } + printf("EXIT DONE\n"); + fflush(stdout); + cleanup: free_host_ifaces(cgroup); free_host_ifaces(host); } +struct send_to_spawned_process { + pid_t pid; + char host_prefix[FILENAME_MAX]; +}; + + +static int spawn_callback(SPAWN_REQUEST *request) { + const struct send_to_spawned_process *d = request->data; + detect_veth_interfaces(d->pid); + return 0; +} + +#define CGROUP_NETWORK_INTERFACE_MAX_LINE 2048 +static void read_from_spawned(SPAWN_INSTANCE *si, const char *name __maybe_unused) { + char buffer[CGROUP_NETWORK_INTERFACE_MAX_LINE + 1]; + char *s; + FILE *fp = fdopen(spawn_server_instance_read_fd(si), "r"); + while((s = fgets(buffer, CGROUP_NETWORK_INTERFACE_MAX_LINE, fp))) { + trim(s); + + if(*s && *s != '\n') { + char *t = s; + while(*t && *t != ' ') t++; + if(*t == ' ') { + *t = '\0'; + t++; + } + + if(strcmp(s, "EXIT") == 0) + break; + + if(!*s || !*t) continue; + add_device(s, t); + } + } + fclose(fp); + spawn_server_instance_read_fd_unset(si); + spawn_server_exec_kill(spawn_server, si); +} + +void detect_veth_interfaces_spawn(pid_t pid) { + struct send_to_spawned_process d = { + .pid = pid, + }; + strncpyz(d.host_prefix, netdata_configured_host_prefix, sizeof(d.host_prefix) - 1); + SPAWN_INSTANCE *si = spawn_server_exec(spawn_server, STDERR_FILENO, 0, NULL, &d, sizeof(d), SPAWN_INSTANCE_TYPE_CALLBACK); + if(si) + read_from_spawned(si, "switch namespace callback"); + else + nd_log(NDLS_COLLECTORS, NDLP_ERR, "cgroup-network cannot spawn switch namespace callback"); +} + // ---------------------------------------------------------------------------- // call the external helper #define CGROUP_NETWORK_INTERFACE_MAX_LINE 2048 void call_the_helper(pid_t pid, const char *cgroup) { - if(setresuid(0, 0, 0) == -1) - collector_error("setresuid(0, 0, 0) failed."); - char command[CGROUP_NETWORK_INTERFACE_MAX_LINE + 1]; if(cgroup) snprintfz(command, CGROUP_NETWORK_INTERFACE_MAX_LINE, "exec " PLUGINS_DIR "/cgroup-network-helper.sh --cgroup '%s'", cgroup); else snprintfz(command, CGROUP_NETWORK_INTERFACE_MAX_LINE, "exec " PLUGINS_DIR "/cgroup-network-helper.sh --pid %d", pid); - collector_info("running: %s", command); + nd_log(NDLS_COLLECTORS, NDLP_DEBUG, "running: %s", command); - POPEN_INSTANCE *pi; + SPAWN_INSTANCE *si; - if(cgroup) - pi = spawn_popen_run_variadic(PLUGINS_DIR "/cgroup-network-helper.sh", "--cgroup", cgroup, NULL); + if(cgroup) { + const char *argv[] = { + PLUGINS_DIR "/cgroup-network-helper.sh", + "--cgroup", + cgroup, + NULL, + }; + si = spawn_server_exec(spawn_server, nd_log_collectors_fd(), 0, argv, NULL, 0, SPAWN_INSTANCE_TYPE_EXEC); + } else { char buffer[100]; snprintfz(buffer, sizeof(buffer) - 1, "%d", pid); - pi = spawn_popen_run_variadic(PLUGINS_DIR "/cgroup-network-helper.sh", "--pid", buffer, NULL); + const char *argv[] = { + PLUGINS_DIR "/cgroup-network-helper.sh", + "--pid", + buffer, + NULL, + }; + si = spawn_server_exec(spawn_server, nd_log_collectors_fd(), 0, argv, NULL, 0, SPAWN_INSTANCE_TYPE_EXEC); } - if(pi) { - char buffer[CGROUP_NETWORK_INTERFACE_MAX_LINE + 1]; - char *s; - while((s = fgets(buffer, CGROUP_NETWORK_INTERFACE_MAX_LINE, pi->child_stdout_fp))) { - trim(s); - - if(*s && *s != '\n') { - char *t = s; - while(*t && *t != ' ') t++; - if(*t == ' ') { - *t = '\0'; - t++; - } - - if(!*s || !*t) continue; - add_device(s, t); - } - } - - spawn_popen_kill(pi); - } + if(si) + read_from_spawned(si, command); else - collector_error("cannot execute cgroup-network helper script: %s", command); + nd_log(NDLS_COLLECTORS, NDLP_ERR, "cannot execute cgroup-network helper script: %s", command); } int is_valid_path_symbol(char c) { @@ -568,33 +639,33 @@ int verify_path(const char *path) { const char *s = path; while((c = *s++)) { if(!( isalnum(c) || is_valid_path_symbol(c) )) { - collector_error("invalid character in path '%s'", path); + nd_log(NDLS_COLLECTORS, NDLP_ERR, "invalid character in path '%s'", path); return -1; } } if(strstr(path, "\\") && !strstr(path, "\\x")) { - collector_error("invalid escape sequence in path '%s'", path); + nd_log(NDLS_COLLECTORS, NDLP_ERR, "invalid escape sequence in path '%s'", path); return 1; } if(strstr(path, "/../")) { - collector_error("invalid parent path sequence detected in '%s'", path); + nd_log(NDLS_COLLECTORS, NDLP_ERR, "invalid parent path sequence detected in '%s'", path); return 1; } if(path[0] != '/') { - collector_error("only absolute path names are supported - invalid path '%s'", path); + nd_log(NDLS_COLLECTORS, NDLP_ERR, "only absolute path names are supported - invalid path '%s'", path); return -1; } if (stat(path, &sb) == -1) { - collector_error("cannot stat() path '%s'", path); + nd_log(NDLS_COLLECTORS, NDLP_ERR, "cannot stat() path '%s'", path); return -1; } if((sb.st_mode & S_IFMT) != S_IFDIR) { - collector_error("path '%s' is not a directory", path); + nd_log(NDLS_COLLECTORS, NDLP_ERR, "path '%s' is not a directory", path); return -1; } @@ -616,10 +687,10 @@ char *fix_path_variable(void) { char *s = strsep(&ptr, ":"); if(s && *s) { if(verify_path(s) == -1) { - collector_error("the PATH variable includes an invalid path '%s' - removed it.", s); + nd_log(NDLS_COLLECTORS, NDLP_ERR, "the PATH variable includes an invalid path '%s' - removed it.", s); } else { - collector_info("the PATH variable includes a valid path '%s'.", s); + nd_log(NDLS_COLLECTORS, NDLP_DEBUG, "the PATH variable includes a valid path '%s'.", s); if(added) strcat(safe_path, ":"); strcat(safe_path, s); added++; @@ -627,8 +698,8 @@ char *fix_path_variable(void) { } } - collector_info("unsafe PATH: '%s'.", path); - collector_info(" safe PATH: '%s'.", safe_path); + nd_log(NDLS_COLLECTORS, NDLP_DEBUG, "unsafe PATH: '%s'.", path); + nd_log(NDLS_COLLECTORS, NDLP_DEBUG, " safe PATH: '%s'.", safe_path); freez(p); return safe_path; @@ -643,11 +714,14 @@ void usage(void) { exit(1); } -int main(int argc, char **argv) { +int main(int argc, const char **argv) { pid_t pid = 0; - clocks_init(); + if (setresuid(0, 0, 0) == -1) + collector_error("setresuid(0, 0, 0) failed."); + nd_log_initialize_for_external_plugins("cgroup-network"); + spawn_server = spawn_server_create(SPAWN_SERVER_OPTION_EXEC | SPAWN_SERVER_OPTION_CALLBACK, NULL, spawn_callback, argc, argv); // since cgroup-network runs as root, prevent it from opening symbolic links procfile_open_flags = O_RDONLY|O_NOFOLLOW; @@ -700,16 +774,16 @@ int main(int argc, char **argv) { if(pid <= 0) { errno_clear(); - collector_error("Invalid pid %d given", (int) pid); + nd_log(NDLS_COLLECTORS, NDLP_ERR, "Invalid pid %d given", (int) pid); return 2; } if(helper) call_the_helper(pid, NULL); } else if(!strcmp(argv[arg], "--cgroup")) { - char *cgroup = argv[arg+1]; + const char *cgroup = argv[arg+1]; if(verify_path(cgroup) == -1) { - collector_error("cgroup '%s' does not exist or is not valid.", cgroup); + nd_log(NDLS_COLLECTORS, NDLP_ERR, "cgroup '%s' does not exist or is not valid.", cgroup); return 1; } @@ -718,16 +792,19 @@ int main(int argc, char **argv) { if(pid <= 0 && !detected_devices) { errno_clear(); - collector_error("Cannot find a cgroup PID from cgroup '%s'", cgroup); + nd_log(NDLS_COLLECTORS, NDLP_ERR, "Cannot find a cgroup PID from cgroup '%s'", cgroup); } } else usage(); if(pid > 0) - detect_veth_interfaces(pid); + detect_veth_interfaces_spawn(pid); int found = send_devices(); + + spawn_server_destroy(spawn_server); + if(found <= 0) return 1; return 0; } diff --git a/src/collectors/cgroups.plugin/cgroup-top.c b/src/collectors/cgroups.plugin/cgroup-top.c index aa413dad1..7b98502b5 100644 --- a/src/collectors/cgroups.plugin/cgroup-top.c +++ b/src/collectors/cgroups.plugin/cgroup-top.c @@ -98,7 +98,7 @@ void cgroup_netdev_get_bandwidth(struct cgroup *cg, NETDATA_DOUBLE *received, NE *sent = t->sent[slot]; } -int cgroup_function_cgroup_top(BUFFER *wb, const char *function __maybe_unused) { +int cgroup_function_cgroup_top(BUFFER *wb, const char *function __maybe_unused, BUFFER *payload __maybe_unused, const char *source __maybe_unused) { buffer_flush(wb); wb->content_type = CT_APPLICATION_JSON; buffer_json_initialize(wb, "\"", "\"", 0, true, BUFFER_JSON_OPTIONS_DEFAULT); @@ -341,7 +341,7 @@ int cgroup_function_cgroup_top(BUFFER *wb, const char *function __maybe_unused) return HTTP_RESP_OK; } -int cgroup_function_systemd_top(BUFFER *wb, const char *function __maybe_unused) { +int cgroup_function_systemd_top(BUFFER *wb, const char *function __maybe_unused, BUFFER *payload __maybe_unused, const char *source __maybe_unused) { buffer_flush(wb); wb->content_type = CT_APPLICATION_JSON; buffer_json_initialize(wb, "\"", "\"", 0, true, BUFFER_JSON_OPTIONS_DEFAULT); diff --git a/src/collectors/cgroups.plugin/sys_fs_cgroup.c b/src/collectors/cgroups.plugin/sys_fs_cgroup.c index 5fdefa863..d41575fa6 100644 --- a/src/collectors/cgroups.plugin/sys_fs_cgroup.c +++ b/src/collectors/cgroups.plugin/sys_fs_cgroup.c @@ -39,7 +39,7 @@ SIMPLE_PATTERN *search_cgroup_paths = NULL; SIMPLE_PATTERN *enabled_cgroup_renames = NULL; SIMPLE_PATTERN *systemd_services_cgroups = NULL; SIMPLE_PATTERN *entrypoint_parent_process_comm = NULL; -char *cgroups_network_interface_script = NULL; +const char *cgroups_network_interface_script = NULL; int cgroups_check = 0; uint32_t Read_hash = 0; uint32_t Write_hash = 0; @@ -82,7 +82,7 @@ static enum cgroups_systemd_setting cgroups_detect_systemd(const char *exec) return retval; struct pollfd pfd; - pfd.fd = spawn_server_instance_read_fd(pi->si); + pfd.fd = spawn_popen_read_fd(pi); pfd.events = POLLIN; int timeout = 3000; // milliseconds @@ -93,7 +93,7 @@ static enum cgroups_systemd_setting cgroups_detect_systemd(const char *exec) } else if (ret == 0) { collector_info("Cannot get the output of \"%s\" within timeout (%d ms)", exec, timeout); } else { - while (fgets(buf, MAXSIZE_PROC_CMDLINE, pi->child_stdout_fp) != NULL) { + while (fgets(buf, MAXSIZE_PROC_CMDLINE, spawn_popen_stdout(pi)) != NULL) { if ((begin = strstr(buf, SYSTEMD_HIERARCHY_STRING))) { end = begin = begin + strlen(SYSTEMD_HIERARCHY_STRING); if (!*begin) @@ -153,18 +153,18 @@ static enum cgroups_type cgroups_try_detect_version() int cgroups2_available = 0; // 1. check if cgroups2 available on system at all - POPEN_INSTANCE *instance = spawn_popen_run("grep cgroup /proc/filesystems"); - if(!instance) { + POPEN_INSTANCE *pi = spawn_popen_run("grep cgroup /proc/filesystems"); + if(!pi) { collector_error("cannot run 'grep cgroup /proc/filesystems'"); return CGROUPS_AUTODETECT_FAIL; } - while (fgets(buf, MAXSIZE_PROC_CMDLINE, instance->child_stdout_fp) != NULL) { + while (fgets(buf, MAXSIZE_PROC_CMDLINE, spawn_popen_stdout(pi)) != NULL) { if (strstr(buf, "cgroup2")) { cgroups2_available = 1; break; } } - if(spawn_popen_wait(instance) != 0) + if(spawn_popen_wait(pi) != 0) return CGROUPS_AUTODETECT_FAIL; if(!cgroups2_available) @@ -229,13 +229,17 @@ void read_cgroup_plugin_configuration() { throttled_time_hash = simple_hash("throttled_time"); throttled_usec_hash = simple_hash("throttled_usec"); - cgroup_update_every = (int)config_get_number("plugin:cgroups", "update every", localhost->rrd_update_every); - if(cgroup_update_every < localhost->rrd_update_every) + cgroup_update_every = (int)config_get_duration_seconds("plugin:cgroups", "update every", localhost->rrd_update_every); + if(cgroup_update_every < localhost->rrd_update_every) { cgroup_update_every = localhost->rrd_update_every; + config_set_duration_seconds("plugin:cgroups", "update every", localhost->rrd_update_every); + } - cgroup_check_for_new_every = (int)config_get_number("plugin:cgroups", "check for new cgroups every", cgroup_check_for_new_every); - if(cgroup_check_for_new_every < cgroup_update_every) + cgroup_check_for_new_every = (int)config_get_duration_seconds("plugin:cgroups", "check for new cgroups every", cgroup_check_for_new_every); + if(cgroup_check_for_new_every < cgroup_update_every) { cgroup_check_for_new_every = cgroup_update_every; + config_set_duration_seconds("plugin:cgroups", "check for new cgroups every", cgroup_check_for_new_every); + } cgroup_use_unified_cgroups = config_get_boolean_ondemand("plugin:cgroups", "use unified cgroups", CONFIG_BOOLEAN_AUTO); if (cgroup_use_unified_cgroups == CONFIG_BOOLEAN_AUTO) @@ -1401,24 +1405,25 @@ void *cgroups_main(void *ptr) { cgroup_netdev_link_init(); rrd_function_add_inline(localhost, NULL, "containers-vms", 10, - RRDFUNCTIONS_PRIORITY_DEFAULT / 2, RRDFUNCTIONS_CGTOP_HELP, + RRDFUNCTIONS_PRIORITY_DEFAULT / 2, RRDFUNCTIONS_VERSION_DEFAULT, + RRDFUNCTIONS_CGTOP_HELP, "top", HTTP_ACCESS_ANONYMOUS_DATA, cgroup_function_cgroup_top); rrd_function_add_inline(localhost, NULL, "systemd-services", 10, - RRDFUNCTIONS_PRIORITY_DEFAULT / 3, RRDFUNCTIONS_SYSTEMD_SERVICES_HELP, + RRDFUNCTIONS_PRIORITY_DEFAULT / 3, RRDFUNCTIONS_VERSION_DEFAULT, + RRDFUNCTIONS_SYSTEMD_SERVICES_HELP, "top", HTTP_ACCESS_ANONYMOUS_DATA, cgroup_function_systemd_top); heartbeat_t hb; - heartbeat_init(&hb); - usec_t step = cgroup_update_every * USEC_PER_SEC; + heartbeat_init(&hb, cgroup_update_every * USEC_PER_SEC); usec_t find_every = cgroup_check_for_new_every * USEC_PER_SEC, find_dt = 0; while(service_running(SERVICE_COLLECTORS)) { worker_is_idle(); - usec_t hb_dt = heartbeat_next(&hb, step); + usec_t hb_dt = heartbeat_next(&hb); if (unlikely(!service_running(SERVICE_COLLECTORS))) break; |