diff options
Diffstat (limited to '')
-rw-r--r-- | collectors/cgroups.plugin/Makefile.am | 21 | ||||
-rw-r--r-- | collectors/cgroups.plugin/Makefile.in (renamed from charts.d/Makefile.in) | 160 | ||||
-rw-r--r-- | collectors/cgroups.plugin/README.md | 187 | ||||
-rw-r--r--[-rwxr-xr-x] | collectors/cgroups.plugin/cgroup-name.sh (renamed from plugins.d/cgroup-name.sh) | 35 | ||||
-rwxr-xr-x | collectors/cgroups.plugin/cgroup-name.sh.in | 196 | ||||
-rwxr-xr-x | collectors/cgroups.plugin/cgroup-network-helper.sh (renamed from plugins.d/cgroup-network-helper.sh) | 29 | ||||
-rw-r--r-- | collectors/cgroups.plugin/cgroup-network.c (renamed from src/cgroup-network.c) | 97 | ||||
-rw-r--r-- | collectors/cgroups.plugin/sys_fs_cgroup.c (renamed from src/sys_fs_cgroup.c) | 340 | ||||
-rw-r--r-- | collectors/cgroups.plugin/sys_fs_cgroup.h | 31 |
9 files changed, 785 insertions, 311 deletions
diff --git a/collectors/cgroups.plugin/Makefile.am b/collectors/cgroups.plugin/Makefile.am new file mode 100644 index 000000000..eb3214ab2 --- /dev/null +++ b/collectors/cgroups.plugin/Makefile.am @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: GPL-3.0-or-later + +AUTOMAKE_OPTIONS = subdir-objects +MAINTAINERCLEANFILES = $(srcdir)/Makefile.in + +CLEANFILES = \ + cgroup-name.sh \ + $(NULL) + +include $(top_srcdir)/build/subst.inc +SUFFIXES = .in + +dist_plugins_SCRIPTS = \ + cgroup-name.sh \ + cgroup-network-helper.sh \ + $(NULL) + +dist_noinst_DATA = \ + cgroup-name.sh.in \ + README.md \ + $(NULL) diff --git a/charts.d/Makefile.in b/collectors/cgroups.plugin/Makefile.in index ebd1af2be..49c3c9834 100644 --- a/charts.d/Makefile.in +++ b/collectors/cgroups.plugin/Makefile.in @@ -14,6 +14,8 @@ @SET_MAKE@ +# SPDX-License-Identifier: GPL-3.0-or-later + VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' @@ -79,18 +81,21 @@ PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ -subdir = charts.d -DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ - $(dist_charts_SCRIPTS) $(dist_charts_DATA) +DIST_COMMON = $(top_srcdir)/build/subst.inc $(srcdir)/Makefile.in \ + $(srcdir)/Makefile.am $(dist_plugins_SCRIPTS) \ + $(dist_noinst_DATA) +subdir = collectors/cgroups.plugin ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___atomic.m4 \ - $(top_srcdir)/m4/ax_c__generic.m4 $(top_srcdir)/m4/ax_c_lto.m4 \ - $(top_srcdir)/m4/ax_c_mallinfo.m4 \ - $(top_srcdir)/m4/ax_c_mallopt.m4 \ - $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/ax_gcc_func_attribute.m4 \ - $(top_srcdir)/m4/ax_pthread.m4 $(top_srcdir)/m4/jemalloc.m4 \ - $(top_srcdir)/m4/tcmalloc.m4 $(top_srcdir)/configure.ac +am__aclocal_m4_deps = $(top_srcdir)/build/m4/ax_c___atomic.m4 \ + $(top_srcdir)/build/m4/ax_c__generic.m4 \ + $(top_srcdir)/build/m4/ax_c_lto.m4 \ + $(top_srcdir)/build/m4/ax_c_mallinfo.m4 \ + $(top_srcdir)/build/m4/ax_c_mallopt.m4 \ + $(top_srcdir)/build/m4/ax_check_compile_flag.m4 \ + $(top_srcdir)/build/m4/ax_gcc_func_attribute.m4 \ + $(top_srcdir)/build/m4/ax_pthread.m4 \ + $(top_srcdir)/build/m4/jemalloc.m4 \ + $(top_srcdir)/build/m4/tcmalloc.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d @@ -124,8 +129,8 @@ am__uninstall_files_from_dir = { \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } -am__installdirs = "$(DESTDIR)$(chartsdir)" "$(DESTDIR)$(chartsdir)" -SCRIPTS = $(dist_charts_SCRIPTS) +am__installdirs = "$(DESTDIR)$(pluginsdir)" +SCRIPTS = $(dist_plugins_SCRIPTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false @@ -145,7 +150,7 @@ am__can_run_installinfo = \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac -DATA = $(dist_charts_DATA) +DATA = $(dist_noinst_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ @@ -245,6 +250,7 @@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ +build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ cachedir = @cachedir@ @@ -266,6 +272,7 @@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +libconfigdir = @libconfigdir@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ @@ -292,42 +299,28 @@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ varlibdir = @varlibdir@ webdir = @webdir@ - -# -# Copyright (C) 2015 Alon Bar-Lev <alon.barlev@gmail.com> -# +AUTOMAKE_OPTIONS = subdir-objects MAINTAINERCLEANFILES = $(srcdir)/Makefile.in -dist_charts_SCRIPTS = \ +CLEANFILES = \ + cgroup-name.sh \ + $(NULL) + +SUFFIXES = .in +dist_plugins_SCRIPTS = \ + cgroup-name.sh \ + cgroup-network-helper.sh \ $(NULL) -dist_charts_DATA = \ +dist_noinst_DATA = \ + cgroup-name.sh.in \ README.md \ - ap.chart.sh \ - apcupsd.chart.sh \ - apache.chart.sh \ - cpu_apps.chart.sh \ - cpufreq.chart.sh \ - example.chart.sh \ - exim.chart.sh \ - hddtemp.chart.sh \ - libreswan.chart.sh \ - load_average.chart.sh \ - mem_apps.chart.sh \ - mysql.chart.sh \ - nginx.chart.sh \ - nut.chart.sh \ - opensips.chart.sh \ - phpfpm.chart.sh \ - postfix.chart.sh \ - sensors.chart.sh \ - squid.chart.sh \ - tomcat.chart.sh \ $(NULL) all: all-am .SUFFIXES: -$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) +.SUFFIXES: .in +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/build/subst.inc $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ @@ -336,9 +329,9 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi exit 1;; \ esac; \ done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu charts.d/Makefile'; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu collectors/cgroups.plugin/Makefile'; \ $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --gnu charts.d/Makefile + $(AUTOMAKE) --gnu collectors/cgroups.plugin/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ @@ -348,6 +341,7 @@ Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; +$(top_srcdir)/build/subst.inc: $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh @@ -357,12 +351,12 @@ $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): -install-dist_chartsSCRIPTS: $(dist_charts_SCRIPTS) +install-dist_pluginsSCRIPTS: $(dist_plugins_SCRIPTS) @$(NORMAL_INSTALL) - @list='$(dist_charts_SCRIPTS)'; test -n "$(chartsdir)" || list=; \ + @list='$(dist_plugins_SCRIPTS)'; test -n "$(pluginsdir)" || list=; \ if test -n "$$list"; then \ - echo " $(MKDIR_P) '$(DESTDIR)$(chartsdir)'"; \ - $(MKDIR_P) "$(DESTDIR)$(chartsdir)" || exit 1; \ + echo " $(MKDIR_P) '$(DESTDIR)$(pluginsdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(pluginsdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ @@ -381,38 +375,17 @@ install-dist_chartsSCRIPTS: $(dist_charts_SCRIPTS) while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ - echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(chartsdir)$$dir'"; \ - $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(chartsdir)$$dir" || exit $$?; \ + echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(pluginsdir)$$dir'"; \ + $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(pluginsdir)$$dir" || exit $$?; \ } \ ; done -uninstall-dist_chartsSCRIPTS: +uninstall-dist_pluginsSCRIPTS: @$(NORMAL_UNINSTALL) - @list='$(dist_charts_SCRIPTS)'; test -n "$(chartsdir)" || exit 0; \ + @list='$(dist_plugins_SCRIPTS)'; test -n "$(pluginsdir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ - dir='$(DESTDIR)$(chartsdir)'; $(am__uninstall_files_from_dir) -install-dist_chartsDATA: $(dist_charts_DATA) - @$(NORMAL_INSTALL) - @list='$(dist_charts_DATA)'; test -n "$(chartsdir)" || list=; \ - if test -n "$$list"; then \ - echo " $(MKDIR_P) '$(DESTDIR)$(chartsdir)'"; \ - $(MKDIR_P) "$(DESTDIR)$(chartsdir)" || exit 1; \ - fi; \ - for p in $$list; do \ - if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ - echo "$$d$$p"; \ - done | $(am__base_list) | \ - while read files; do \ - echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(chartsdir)'"; \ - $(INSTALL_DATA) $$files "$(DESTDIR)$(chartsdir)" || exit $$?; \ - done - -uninstall-dist_chartsDATA: - @$(NORMAL_UNINSTALL) - @list='$(dist_charts_DATA)'; test -n "$(chartsdir)" || list=; \ - files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ - dir='$(DESTDIR)$(chartsdir)'; $(am__uninstall_files_from_dir) + dir='$(DESTDIR)$(pluginsdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: @@ -454,7 +427,7 @@ check-am: all-am check: check-am all-am: Makefile $(SCRIPTS) $(DATA) installdirs: - for dir in "$(DESTDIR)$(chartsdir)" "$(DESTDIR)$(chartsdir)"; do \ + for dir in "$(DESTDIR)$(pluginsdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am @@ -479,6 +452,7 @@ install-strip: mostlyclean-generic: clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) @@ -508,7 +482,7 @@ info: info-am info-am: -install-data-am: install-dist_chartsDATA install-dist_chartsSCRIPTS +install-data-am: install-dist_pluginsSCRIPTS install-dvi: install-dvi-am @@ -552,23 +526,37 @@ ps: ps-am ps-am: -uninstall-am: uninstall-dist_chartsDATA uninstall-dist_chartsSCRIPTS +uninstall-am: uninstall-dist_pluginsSCRIPTS .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic cscopelist-am \ ctags-am distclean distclean-generic distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ - install-data-am install-dist_chartsDATA \ - install-dist_chartsSCRIPTS install-dvi install-dvi-am \ - install-exec install-exec-am install-html install-html-am \ - install-info install-info-am install-man install-pdf \ - install-pdf-am install-ps install-ps-am install-strip \ - installcheck installcheck-am installdirs maintainer-clean \ - maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ - pdf-am ps ps-am tags-am uninstall uninstall-am \ - uninstall-dist_chartsDATA uninstall-dist_chartsSCRIPTS - + install-data-am install-dist_pluginsSCRIPTS install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic pdf pdf-am ps ps-am tags-am uninstall \ + uninstall-am uninstall-dist_pluginsSCRIPTS + +.in: + if sed \ + -e 's#[@]localstatedir_POST@#$(localstatedir)#g' \ + -e 's#[@]sbindir_POST@#$(sbindir)#g' \ + -e 's#[@]sysconfdir_POST@#$(sysconfdir)#g' \ + -e 's#[@]pythondir_POST@#$(pythondir)#g' \ + -e 's#[@]configdir_POST@#$(configdir)#g' \ + -e 's#[@]libconfigdir_POST@#$(libconfigdir)#g' \ + -e 's#[@]cachedir_POST@#$(cachedir)#g' \ + $< > $@.tmp; then \ + mv "$@.tmp" "$@"; \ + else \ + rm -f "$@.tmp"; \ + false; \ + fi # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. diff --git a/collectors/cgroups.plugin/README.md b/collectors/cgroups.plugin/README.md new file mode 100644 index 000000000..e78aa0440 --- /dev/null +++ b/collectors/cgroups.plugin/README.md @@ -0,0 +1,187 @@ +# cgroups.plugin + +You can monitor containers and virtual machines using **cgroups**. + +cgroups (or control groups), are a Linux kernel feature that provides accounting and resource usage limiting for processes. When cgroups are bundled with namespaces (i.e. isolation), they form what we usually call **containers**. + +cgroups are hierarchical, meaning that cgroups can contain child cgroups, which can contain more cgroups, etc. All accounting is reported (and resource usage limits are applied) also in a hierarchical way. + +To visualize cgroup metrics netdata provides configuration for cherry picking the cgroups of interest. By default (without any configuration) netdata should pick **systemd services**, all kinds of **containers** (lxc, docker, etc) and **virtual machines** spawn by managers that register them with cgroups (qemu, libvirt, etc). + +## configuring netdata for cgroups + +For each cgroup available in the system, netdata provides this configuration: + +``` +[plugin:cgroups] + enable cgroup XXX = yes | no +``` + +But it also provides a few patterns to provide a sane default (`yes` or `no`). + +Below we see, how this works. + +### how netdata finds the available cgroups + +Linux exposes resource usage reporting and provides dynamic configuration for cgroups, using virtual files (usually) under `/sys/fs/cgroup`. netdata reads `/proc/self/mountinfo` to detect the exact mount point of cgroups. netdata also allows manual configuration of this mount point, using these settings: + +``` +[plugin:cgroups] + check for new cgroups every = 10 + path to /sys/fs/cgroup/cpuacct = /sys/fs/cgroup/cpuacct + path to /sys/fs/cgroup/blkio = /sys/fs/cgroup/blkio + path to /sys/fs/cgroup/memory = /sys/fs/cgroup/memory + path to /sys/fs/cgroup/devices = /sys/fs/cgroup/devices +``` + +netdata rescans these directories for added or removed cgroups every `check for new cgroups every` seconds. + +### hierarchical search for cgroups + +Since cgroups are hierarchical, for each of the directories shown above, netdata walks through the subdirectories recursively searching for cgroups (each subdirectory is another cgroup). + +For each of the directories found, netdata provides a configuration variable: + +``` +[plugin:cgroups] + search for cgroups under PATH = yes | no +``` + +To provide a sane default for this setting, netdata uses the following pattern list (patterns starting with `!` give a negative match and their order is important: the first matching a path will be used): + +``` +[plugin:cgroups] + search for cgroups in subpaths matching = !*/init.scope !*-qemu !/init.scope !/system !/systemd !/user !/user.slice * +``` + +So, we disable checking for **child cgroups** in systemd internal cgroups ([systemd services are monitored by netdata](https://github.com/netdata/netdata/wiki/monitoring-systemd-services)), user cgroups (normally used for desktop and remote user sessions), qemu virtual machines (child cgroups of virtual machines) and `init.scope`. All others are enabled. + + +### enabled cgroups + +To check if the cgroup is enabled, netdata uses this setting: + +``` +[plugin:cgroups] + enable cgroup NAME = yes | no +``` + +To provide a sane default, netdata uses the following pattern list (it checks the pattern against the path of the cgroup): + +``` +[plugin:cgroups] + enable by default cgroups matching = !*/init.scope *.scope !*/vcpu* !*/emulator !*.mount !*.partition !*.service !*.slice !*.swap !*.user !/ !/docker !/libvirt !/lxc !/lxc/*/ns !/lxc/*/ns/* !/machine !/qemu !/system !/systemd !/user * +``` + +The above provides the default `yes` or `no` setting for the cgroup. However, there is an additional step. In many cases the cgroups found in the `/sys/fs/cgroup` hierarchy are just random numbers and in many cases these numbers are ephemeral: they change across reboots or sessions. + +So, we need to somehow map the paths of the cgroups to names, to provide consistent netdata configuration (i.e. there is no point to say `enable cgroup 1234 = yes | no`, if `1234` is a random number that changes over time - we need a name for the cgroup first, so that `enable cgroup NAME = yes | no` will be consistent). + +For this mapping netdata provides 2 configuration options: + +``` +[plugin:cgroups] + run script to rename cgroups matching = *.scope *docker* *lxc* *qemu* !/ !*.mount !*.partition !*.service !*.slice !*.swap !*.user * + script to get cgroup names = /usr/libexec/netdata/plugins.d/cgroup-name.sh +``` + +The whole point for the additional pattern list, is to limit the number of times the script will be called. Without this pattern list, the script might be called thousands of times, depending on the number of cgroups available in the system. + +The above pattern list is matched against the path of the cgroup. For matched cgroups, netdata calls the script [cgroup-name.sh](https://github.com/netdata/netdata/blob/master/collectors/cgroups.plugin/cgroup-name.sh.in) to get its name. This script queries `docker`, or applies heuristics to find give a name for the cgroup. + +## Monitoring systemd services + +netdata monitors **systemd services**. Example: + +![image](https://cloud.githubusercontent.com/assets/2662304/21964372/20cd7b84-db53-11e6-98a2-b9c986b082c0.png) + +Support per distribution: + +system|systemd services<br/>charts shown|`tree`<br/>`/sys/fs/cgroup`|comments +:-------:|:-------:|:-------:|:------------ +Arch Linux|YES| | +Gentoo|NO| |can be enabled, see below +Ubuntu 16.04 LTS|YES| | +Ubuntu 16.10|YES|[here](http://pastebin.com/PiWbQEXy)| +Fedora 25|YES|[here](http://pastebin.com/ax0373wF)| +Debian 8|NO| |can be enabled, see below +AMI|NO|[here](http://pastebin.com/FrxmptjL)|not a systemd system +Centos 7.3.1611|NO|[here](http://pastebin.com/SpzgezAg)|can be enabled, see below + +#### how to enable cgroup accounting on systemd systems that is by default disabled + +You can verify there is no accounting enabled, by running `systemd-cgtop`. The program will show only resources for cgroup ` / `, but all services will show nothing. + +To enable cgroup accounting, execute this: + +```sh +sed -e 's|^#Default\(.*\)Accounting=.*$|Default\1Accounting=yes|g' /etc/systemd/system.conf >/tmp/system.conf +``` + +To see the changes it made, run this: + +``` +# diff /etc/systemd/system.conf /tmp/system.conf +40,44c40,44 +< #DefaultCPUAccounting=no +< #DefaultIOAccounting=no +< #DefaultBlockIOAccounting=no +< #DefaultMemoryAccounting=no +< #DefaultTasksAccounting=yes +--- +> DefaultCPUAccounting=yes +> DefaultIOAccounting=yes +> DefaultBlockIOAccounting=yes +> DefaultMemoryAccounting=yes +> DefaultTasksAccounting=yes +``` + +If you are happy with the changes, run: + +```sh +# copy the file to the right location +sudo cp /tmp/system.conf /etc/systemd/system.conf + +# restart systemd to take it into account +sudo systemctl daemon-reexec +``` + +(`systemctl daemon-reload` does not reload the configuration of the server - so you have to execute `systemctl daemon-reexec`). + +Now, when you run `systemd-cgtop`, services will start reporting usage (if it does not, restart a service - any service - to wake it up). Refresh your netdata dashboard, and you will have the charts too. + +In case memory accounting is missing, you will need to enable it at your kernel, by appending the following kernel boot options and rebooting: + +``` +cgroup_enable=memory swapaccount=1 +``` + +You can add the above, directly at the `linux` line in your `/boot/grub/grub.cfg` or appending them to the `GRUB_CMDLINE_LINUX` in `/etc/default/grub` (in which case you will have to run `update-grub` before rebooting). On DigitalOcean debian images you may have to set it at `/etc/default/grub.d/50-cloudimg-settings.cfg`. + +--- + +## Monitoring ephemeral containers + +netdata monitors containers automatically when it is installed at the host, or when it is installed in a container that has access to the `/proc` and `/sys` filesystems of the host. + +netdata prior to v1.6 had 2 issues when such containers were monitored: + +1. network interface alarms where triggering when containers were stopped + +2. charts were never cleaned up, so after some time dozens of containers were showing up on the dashboard, and they were occupying memory. + + +### the current netdata + +network interfaces and cgroups (containers) are now self-cleaned. + +So, when a network interface or container stops, netdata might log a few errors in error.log complaining about files it cannot find, but immediately: + +1. it will detect this is a removed container or network interface +2. it will freeze/pause all alarms for them +3. it will mark their charts as obsolete +4. obsolete charts are not be offered on new dashboard sessions (so hit F5 and the charts are gone) +5. existing dashboard sessions will continue to see them, but of course they will not refresh +6. obsolete charts will be removed from memory, 1 hour after the last user viewed them (configurable with `[global].cleanup obsolete charts after seconds = 3600` (at netdata.conf). +7. when obsolete charts are removed from memory they are also deleted from disk (configurable with `[global].delete obsolete charts files = yes`) + diff --git a/plugins.d/cgroup-name.sh b/collectors/cgroups.plugin/cgroup-name.sh index 3c8ad7205..6bf8b8b03 100755..100644 --- a/plugins.d/cgroup-name.sh +++ b/collectors/cgroups.plugin/cgroup-name.sh @@ -3,7 +3,7 @@ # netdata # real-time performance and health monitoring, done right! # (C) 2016 Costa Tsaousis <costa@tsaousis.gr> -# GPL v3+ +# SPDX-License-Identifier: GPL-3.0-or-later # # Script to find a better name for cgroups # @@ -51,8 +51,10 @@ debug() { # ----------------------------------------------------------------------------- -[ -z "${NETDATA_CONFIG_DIR}" ] && NETDATA_CONFIG_DIR="$(dirname "${0}")/../../../../etc/netdata" -CONFIG="${NETDATA_CONFIG_DIR}/cgroups-names.conf" +[ -z "${NETDATA_USER_CONFIG_DIR}" ] && NETDATA_USER_CONFIG_DIR="/usr/local/etc/netdata" +[ -z "${NETDATA_STOCK_CONFIG_DIR}" ] && NETDATA_STOCK_CONFIG_DIR="/usr/local/lib/netdata/conf.d" + +DOCKER_HOST="${DOCKER_HOST:=/var/run/docker.sock}" CGROUP="${1}" NAME= @@ -63,16 +65,21 @@ if [ -z "${CGROUP}" ] fatal "called without a cgroup name. Nothing to do." fi -if [ -f "${CONFIG}" ] +for CONFIG in "${NETDATA_USER_CONFIG_DIR}/cgroups-names.conf" "${NETDATA_STOCK_CONFIG_DIR}/cgroups-names.conf" +do + if [ -f "${CONFIG}" ] then - NAME="$(grep "^${CGROUP} " "${CONFIG}" | sed "s/[[:space:]]\+/ /g" | cut -d ' ' -f 2)" - if [ -z "${NAME}" ] - then - info "cannot find cgroup '${CGROUP}' in '${CONFIG}'." + NAME="$(grep "^${CGROUP} " "${CONFIG}" | sed "s/[[:space:]]\+/ /g" | cut -d ' ' -f 2)" + if [ -z "${NAME}" ] + then + info "cannot find cgroup '${CGROUP}' in '${CONFIG}'." + else + break + fi + #else + # info "configuration file '${CONFIG}' is not available." fi -#else -# info "configuration file '${CONFIG}' is not available." -fi +done function docker_get_name_classic { local id="${1}" @@ -83,13 +90,13 @@ function docker_get_name_classic { function docker_get_name_api { local id="${1}" - if [ ! -S "/var/run/docker.sock" ] + if [ ! -S "${DOCKER_HOST}" ] then - warning "Can't find /var/run/docker.sock" + warning "Can't find ${DOCKER_HOST}" return 1 fi info "Running API command: /containers/${id}/json" - JSON=$(echo -e "GET /containers/${id}/json HTTP/1.0\r\n" | nc -U /var/run/docker.sock | grep '^{.*') + JSON=$(echo -e "GET /containers/${id}/json HTTP/1.0\r\n" | nc -U ${DOCKER_HOST} | grep '^{.*') NAME=$(echo $JSON | jq -r .Name,.Config.Hostname | grep -v null | head -n1 | sed 's|^/||') return 0 } diff --git a/collectors/cgroups.plugin/cgroup-name.sh.in b/collectors/cgroups.plugin/cgroup-name.sh.in new file mode 100755 index 000000000..53696a4bf --- /dev/null +++ b/collectors/cgroups.plugin/cgroup-name.sh.in @@ -0,0 +1,196 @@ +#!/usr/bin/env bash + +# netdata +# real-time performance and health monitoring, done right! +# (C) 2016 Costa Tsaousis <costa@tsaousis.gr> +# SPDX-License-Identifier: GPL-3.0-or-later +# +# Script to find a better name for cgroups +# + +export PATH="${PATH}:/sbin:/usr/sbin:/usr/local/sbin" +export LC_ALL=C + +# ----------------------------------------------------------------------------- + +PROGRAM_NAME="$(basename "${0}")" + +logdate() { + date "+%Y-%m-%d %H:%M:%S" +} + +log() { + local status="${1}" + shift + + echo >&2 "$(logdate): ${PROGRAM_NAME}: ${status}: ${*}" + +} + +warning() { + log WARNING "${@}" +} + +error() { + log ERROR "${@}" +} + +info() { + log INFO "${@}" +} + +fatal() { + log FATAL "${@}" + exit 1 +} + +debug=0 +debug() { + [ $debug -eq 1 ] && log DEBUG "${@}" +} + +# ----------------------------------------------------------------------------- + +[ -z "${NETDATA_USER_CONFIG_DIR}" ] && NETDATA_USER_CONFIG_DIR="@configdir_POST@" +[ -z "${NETDATA_STOCK_CONFIG_DIR}" ] && NETDATA_STOCK_CONFIG_DIR="@libconfigdir_POST@" + +DOCKER_HOST="${DOCKER_HOST:=/var/run/docker.sock}" +CGROUP="${1}" +NAME= + +# ----------------------------------------------------------------------------- + +if [ -z "${CGROUP}" ] + then + fatal "called without a cgroup name. Nothing to do." +fi + +for CONFIG in "${NETDATA_USER_CONFIG_DIR}/cgroups-names.conf" "${NETDATA_STOCK_CONFIG_DIR}/cgroups-names.conf" +do + if [ -f "${CONFIG}" ] + then + NAME="$(grep "^${CGROUP} " "${CONFIG}" | sed "s/[[:space:]]\+/ /g" | cut -d ' ' -f 2)" + if [ -z "${NAME}" ] + then + info "cannot find cgroup '${CGROUP}' in '${CONFIG}'." + else + break + fi + #else + # info "configuration file '${CONFIG}' is not available." + fi +done + +function docker_get_name_classic { + local id="${1}" + info "Running command: docker ps --filter=id=\"${id}\" --format=\"{{.Names}}\"" + NAME="$( docker ps --filter=id="${id}" --format="{{.Names}}" )" + return 0 +} + +function docker_get_name_api { + local id="${1}" + if [ ! -S "${DOCKER_HOST}" ] + then + warning "Can't find ${DOCKER_HOST}" + return 1 + fi + info "Running API command: /containers/${id}/json" + JSON=$(echo -e "GET /containers/${id}/json HTTP/1.0\r\n" | nc -U ${DOCKER_HOST} | grep '^{.*') + NAME=$(echo $JSON | jq -r .Name,.Config.Hostname | grep -v null | head -n1 | sed 's|^/||') + return 0 +} + +function docker_get_name { + local id="${1}" + if hash docker 2>/dev/null + then + docker_get_name_classic "${id}" + else + docker_get_name_api "${id}" || docker_get_name_classic "${id}" + fi + if [ -z "${NAME}" ] + then + warning "cannot find the name of docker container '${id}'" + NAME="${id:0:12}" + else + info "docker container '${id}' is named '${NAME}'" + fi +} + +if [ -z "${NAME}" ] + then + if [[ "${CGROUP}" =~ ^.*docker[-_/\.][a-fA-F0-9]+[-_\.]?.*$ ]] + then + # docker containers + + DOCKERID="$( echo "${CGROUP}" | sed "s|^.*docker[-_/]\([a-fA-F0-9]\+\)[-_\.]\?.*$|\1|" )" + # echo "DOCKERID=${DOCKERID}" + + if [ ! -z "${DOCKERID}" -a \( ${#DOCKERID} -eq 64 -o ${#DOCKERID} -eq 12 \) ] + then + docker_get_name "${DOCKERID}" + else + error "a docker id cannot be extracted from docker cgroup '${CGROUP}'." + fi + elif [[ "${CGROUP}" =~ ^.*kubepods[_/].*[_/]pod[a-fA-F0-9-]+[_/][a-fA-F0-9]+$ ]] + then + # kubernetes + + DOCKERID="$( echo "${CGROUP}" | sed "s|^.*kubepods[_/].*[_/]pod[a-fA-F0-9-]\+[_/]\([a-fA-F0-9]\+\)$|\1|" )" + # echo "DOCKERID=${DOCKERID}" + + if [ ! -z "${DOCKERID}" -a \( ${#DOCKERID} -eq 64 -o ${#DOCKERID} -eq 12 \) ] + then + docker_get_name "${DOCKERID}" + else + error "a docker id cannot be extracted from kubernetes cgroup '${CGROUP}'." + fi + elif [[ "${CGROUP}" =~ machine.slice[_/].*\.service ]] + then + # systemd-nspawn + + NAME="$(echo ${CGROUP} | sed 's/.*machine.slice[_\/]\(.*\)\.service/\1/g')" + + elif [[ "${CGROUP}" =~ machine.slice_machine.*-qemu ]] + then + # libvirtd / qemu virtual machines + + # NAME="$(echo ${CGROUP} | sed 's/machine.slice_machine.*-qemu//; s/\/x2d//; s/\/x2d/\-/g; s/\.scope//g')" + NAME="qemu_$(echo ${CGROUP} | sed 's/machine.slice_machine.*-qemu//; s/\/x2d[[:digit:]]*//; s/\/x2d//g; s/\.scope//g')" + + elif [[ "${CGROUP}" =~ machine_.*\.libvirt-qemu ]] + then + # libvirtd / qemu virtual machines + NAME="qemu_$(echo ${CGROUP} | sed 's/^machine_//; s/\.libvirt-qemu$//; s/-/_/;')" + + elif [[ "${CGROUP}" =~ qemu.slice_([0-9]+).scope && -d /etc/pve ]] + then + # Proxmox VMs + + FILENAME="/etc/pve/qemu-server/${BASH_REMATCH[1]}.conf" + if [[ -f $FILENAME && -r $FILENAME ]] + then + NAME="qemu_$(grep -e '^name: ' "/etc/pve/qemu-server/${BASH_REMATCH[1]}.conf" | head -1 | sed -rn 's|\s*name\s*:\s*(.*)?$|\1|p')" + else + error "proxmox config file missing ${FILENAME} or netdata does not have read access. Please ensure netdata is a member of www-data group." + fi + elif [[ "${CGROUP}" =~ lxc_([0-9]+) && -d /etc/pve ]] + then + # Proxmox Containers (LXC) + + FILENAME="/etc/pve/lxc/${BASH_REMATCH[1]}.conf" + if [[ -f ${FILENAME} && -r ${FILENAME} ]] + then + NAME=$(grep -e '^hostname: ' /etc/pve/lxc/${BASH_REMATCH[1]}.conf | head -1 | sed -rn 's|\s*hostname\s*:\s*(.*)?$|\1|p') + else + error "proxmox config file missing ${FILENAME} or netdata does not have read access. Please ensure netdata is a member of www-data group." + fi + fi + + [ -z "${NAME}" ] && NAME="${CGROUP}" + [ ${#NAME} -gt 100 ] && NAME="${NAME:0:100}" +fi + +info "cgroup '${CGROUP}' is called '${NAME}'" +echo "${NAME}" diff --git a/plugins.d/cgroup-network-helper.sh b/collectors/cgroups.plugin/cgroup-network-helper.sh index f07059986..666f02fc8 100755 --- a/plugins.d/cgroup-network-helper.sh +++ b/collectors/cgroups.plugin/cgroup-network-helper.sh @@ -1,10 +1,11 @@ #!/usr/bin/env bash +# shellcheck disable=SC1117 # cgroup-network-helper.sh # detect container and virtual machine interfaces # # (C) 2017 Costa Tsaousis -# GPL v3+ +# SPDX-License-Identifier: GPL-3.0-or-later # # This script is called as root (by cgroup-network), with either a pid, or a cgroup path. # It tries to find all the network interfaces that belong to the same cgroup. @@ -23,6 +24,7 @@ # ----------------------------------------------------------------------------- # the system path is cleared by cgroup-network +# shellcheck source=/dev/null [ -f /etc/profile ] && source /etc/profile export LC_ALL=C @@ -66,7 +68,7 @@ debug() { # ----------------------------------------------------------------------------- # check for BASH v4+ (required for associative arrays) -[ $(( ${BASH_VERSINFO[0]} )) -lt 4 ] && \ +[ $(( BASH_VERSINFO[0] )) -lt 4 ] && \ fatal "BASH version 4 or later is required (this is ${BASH_VERSION})." # ----------------------------------------------------------------------------- @@ -86,7 +88,7 @@ do shift done -if [ -z "${pid}" -a -z "${cgroup}" ] +if [ -z "${pid}" ] && [ -z "${cgroup}" ] then fatal "Either --pid or --cgroup is required" fi @@ -103,7 +105,7 @@ set_source() { # cgroup-network can detect veth interfaces by itself (written in C). # If you seek for a shell version of what it does, check this: -# https://github.com/firehol/netdata/issues/474#issuecomment-317866709 +# https://github.com/netdata/netdata/issues/474#issuecomment-317866709 # ----------------------------------------------------------------------------- @@ -115,7 +117,7 @@ proc_pid_fdinfo_iff() { debug "Searching for tun/tap interfaces for pid ${p}..." set_source "fdinfo" - grep ^iff:.* "${NETDATA_HOST_PREFIX}/proc/${p}/fdinfo"/* 2>/dev/null | cut -f 2 + grep "^iff:.*" "${NETDATA_HOST_PREFIX}/proc/${p}/fdinfo"/* 2>/dev/null | cut -f 2 } find_tun_tap_interfaces_for_cgroup() { @@ -128,7 +130,7 @@ find_tun_tap_interfaces_for_cgroup() { local p for p in $(< "${c}/emulator/cgroup.procs" ) do - proc_pid_fdinfo_iff ${p} + proc_pid_fdinfo_iff "${p}" done fi } @@ -154,11 +156,14 @@ virsh_find_all_interfaces_for_cgroup() { local c="${1}" # the cgroup path # the virsh command - local virsh="$(which virsh 2>/dev/null || command -v virsh 2>/dev/null)" + local virsh + # shellcheck disable=SC2230 + virsh="$(which virsh 2>/dev/null || command -v virsh 2>/dev/null)" if [ ! -z "${virsh}" ] then - local d="$(virsh_cgroup_to_domain_name "${c}")" + local d + d="$(virsh_cgroup_to_domain_name "${c}")" if [ ! -z "${d}" ] then @@ -167,7 +172,7 @@ virsh_find_all_interfaces_for_cgroup() { # match only 'network' interfaces from virsh output set_source "virsh" - "${virsh}" -r domiflist ${d} |\ + "${virsh}" -r domiflist "${d}" |\ sed -n \ -e "s|^\([^[:space:]]\+\)[[:space:]]\+network[[:space:]]\+\([^[:space:]]\+\)[[:space:]]\+[^[:space:]]\+[[:space:]]\+[^[:space:]]\+$|\1 \1_\2|p" \ -e "s|^\([^[:space:]]\+\)[[:space:]]\+bridge[[:space:]]\+\([^[:space:]]\+\)[[:space:]]\+[^[:space:]]\+[[:space:]]\+[^[:space:]]\+$|\1 \1_\2|p" @@ -188,7 +193,7 @@ find_all_interfaces_of_pid_or_cgroup() { then # we have been called with a pid - proc_pid_fdinfo_iff ${p} + proc_pid_fdinfo_iff "${p}" elif [ ! -z "${c}" ] then @@ -219,6 +224,7 @@ declare -A devs=() # store all interfaces found in the associative array # this will also give the unique devices, as seen by the host last_src= +# shellcheck disable=SC2162 while read host_device guest_device do [ -z "${host_device}" ] && continue @@ -231,8 +237,9 @@ do # when we run in debug, show the source debug "Found host device '${host_device}', guest device '${guest_device}', detected via '${last_src}'" - [ -z "${devs[${host_device}]}" -o "${devs[${host_device}]}" = "${host_device}" ] && \ + if [ -z "${devs[${host_device}]}" ] || [ "${devs[${host_device}]}" = "${host_device}" ]; then devs[${host_device}]="${guest_device}" + fi done < <( find_all_interfaces_of_pid_or_cgroup "${pid}" "${cgroup}" ) diff --git a/src/cgroup-network.c b/collectors/cgroups.plugin/cgroup-network.c index 0e2d5163a..0cf2a2633 100644 --- a/src/cgroup-network.c +++ b/collectors/cgroups.plugin/cgroup-network.c @@ -1,5 +1,6 @@ -#include "common.h" -#include <libgen.h> +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "libnetdata/libnetdata.h" #ifdef HAVE_SETNS #ifndef _GNU_SOURCE @@ -8,8 +9,6 @@ #include <sched.h> #endif -char *host_prefix = ""; - char environment_variable2[FILENAME_MAX + 50] = ""; char *environment[] = { "PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin", @@ -19,14 +18,28 @@ char *environment[] = { // ---------------------------------------------------------------------------- -// callback required by fatal() +// callback required by fatal() void netdata_cleanup_and_exit(int ret) { exit(ret); } -void health_reload(void) {}; -void rrdhost_save_all(void) {}; +// callbacks required by popen() +void signals_block(void) {}; +void signals_unblock(void) {}; +void signals_reset(void) {}; + +// callback required by eval() +int health_variable_lookup(const char *variable, uint32_t hash, struct rrdcalc *rc, calculated_number *result) { + (void)variable; + (void)hash; + (void)rc; + (void)result; + return 0; +}; + +// required by get_system_cpus() +char *netdata_configured_host_prefix = ""; // ---------------------------------------------------------------------------- @@ -41,8 +54,10 @@ struct iface { }; unsigned int read_iface_iflink(const char *prefix, const char *iface) { + if(!prefix) prefix = ""; + char filename[FILENAME_MAX + 1]; - snprintfz(filename, FILENAME_MAX, "%s/sys/class/net/%s/iflink", prefix?prefix:"", iface); + snprintfz(filename, FILENAME_MAX, "%s/sys/class/net/%s/iflink", prefix, iface); unsigned long long iflink = 0; int ret = read_single_number_file(filename, &iflink); @@ -52,8 +67,10 @@ unsigned int read_iface_iflink(const char *prefix, const char *iface) { } unsigned int read_iface_ifindex(const char *prefix, const char *iface) { + if(!prefix) prefix = ""; + char filename[FILENAME_MAX + 1]; - snprintfz(filename, FILENAME_MAX, "%s/sys/class/net/%s/ifindex", prefix?prefix:"", iface); + snprintfz(filename, FILENAME_MAX, "%s/sys/class/net/%s/ifindex", prefix, iface); unsigned long long ifindex = 0; int ret = read_single_number_file(filename, &ifindex); @@ -63,10 +80,12 @@ unsigned int read_iface_ifindex(const char *prefix, const char *iface) { } struct iface *read_proc_net_dev(const char *prefix) { + if(!prefix) prefix = ""; + procfile *ff = NULL; char filename[FILENAME_MAX + 1]; - snprintfz(filename, FILENAME_MAX, "%s%s", prefix?prefix:"", "/proc/net/dev"); + snprintfz(filename, FILENAME_MAX, "%s%s", prefix, (*prefix)?"/proc/1/net/dev":"/proc/net/dev"); ff = procfile_open(filename, " \t,:|", PROCFILE_FLAG_DEFAULT); if(unlikely(!ff)) { error("Cannot open file '%s'", filename); @@ -163,12 +182,14 @@ static void continue_as_child(void) { } int proc_pid_fd(const char *prefix, const char *ns, pid_t pid) { + if(!prefix) prefix = ""; + char filename[FILENAME_MAX + 1]; - snprintfz(filename, FILENAME_MAX, "%s/proc/%d/%s", prefix?prefix:"", (int)pid, ns); + snprintfz(filename, FILENAME_MAX, "%s/proc/%d/%s", prefix, (int)pid, ns); int fd = open(filename, O_RDONLY); if(fd == -1) - error("Cannot open file '%s'", filename); + error("Cannot open proc_pid_fd() file '%s'", filename); return fd; } @@ -193,6 +214,8 @@ static struct ns { }; int switch_namespace(const char *prefix, pid_t pid) { + if(!prefix) prefix = ""; + #ifdef HAVE_SETNS int i; @@ -207,8 +230,8 @@ int switch_namespace(const char *prefix, pid_t pid) { // 2 passes - found it at nsenter source code // this is related CLONE_NEWUSER functionality - // FIXME: this code cannot switch user namespace - // Fortunately, we don't need it. + // This code cannot switch user namespace (it can all the other namespaces) + // Fortunately, we don't need to switch user namespaces. int pass, errors = 0; for(pass = 0; pass < 2 ;pass++) { @@ -272,9 +295,15 @@ int switch_namespace(const char *prefix, pid_t pid) { } pid_t read_pid_from_cgroup_file(const char *filename) { - FILE *fp = fopen(filename, "r"); + int fd = open(filename, procfile_open_flags); + if(fd == -1) { + error("Cannot open pid_from_cgroup() file '%s'.", filename); + return 0; + } + + FILE *fp = fdopen(fd, "r"); if(!fp) { - error("Cannot read file '%s'.", filename); + error("Cannot upgrade fd to fp for file '%s'.", filename); return 0; } @@ -387,14 +416,13 @@ int send_devices(void) { // since it switches namespaces, so after this call, everything is different! void detect_veth_interfaces(pid_t pid) { - struct iface *host, *cgroup, *h, *c; - const char *prefix = getenv("NETDATA_HOST_PREFIX"); + struct iface *host = NULL, *cgroup = NULL, *h, *c; - host = read_proc_net_dev(prefix); + host = read_proc_net_dev(netdata_configured_host_prefix); if(!host) { errno = 0; error("cannot read host interface list."); - return; + goto cleanup; } if(!eligible_ifaces(host)) { @@ -403,7 +431,7 @@ void detect_veth_interfaces(pid_t pid) { goto cleanup; } - if(switch_namespace(prefix, pid)) { + if(switch_namespace(netdata_configured_host_prefix, pid)) { errno = 0; error("cannot switch to the namespace of pid %u", (unsigned int) pid); goto cleanup; @@ -433,6 +461,7 @@ void detect_veth_interfaces(pid_t pid) { } cleanup: + free_host_ifaces(cgroup); free_host_ifaces(host); } @@ -444,17 +473,18 @@ void call_the_helper(pid_t pid, const char *cgroup) { if(setresuid(0, 0, 0) == -1) error("setresuid(0, 0, 0) failed."); - char buffer[CGROUP_NETWORK_INTERFACE_MAX_LINE + 1]; + char command[CGROUP_NETWORK_INTERFACE_MAX_LINE + 1]; if(cgroup) - snprintfz(buffer, CGROUP_NETWORK_INTERFACE_MAX_LINE, "exec " PLUGINS_DIR "/cgroup-network-helper.sh --cgroup '%s'", cgroup); + snprintfz(command, CGROUP_NETWORK_INTERFACE_MAX_LINE, "exec " PLUGINS_DIR "/cgroup-network-helper.sh --cgroup '%s'", cgroup); else - snprintfz(buffer, CGROUP_NETWORK_INTERFACE_MAX_LINE, "exec " PLUGINS_DIR "/cgroup-network-helper.sh --pid %d", pid); + snprintfz(command, CGROUP_NETWORK_INTERFACE_MAX_LINE, "exec " PLUGINS_DIR "/cgroup-network-helper.sh --pid %d", pid); - info("running: %s", buffer); + info("running: %s", command); pid_t cgroup_pid; - FILE *fp = mypopene(buffer, &cgroup_pid, environment); + FILE *fp = mypopene(command, &cgroup_pid, environment); if(fp) { + char buffer[CGROUP_NETWORK_INTERFACE_MAX_LINE + 1]; char *s; while((s = fgets(buffer, CGROUP_NETWORK_INTERFACE_MAX_LINE, fp))) { trim(s); @@ -475,7 +505,7 @@ void call_the_helper(pid_t pid, const char *cgroup) { mypclose(fp, cgroup_pid); } else - error("cannot execute cgroup-network helper script: %s", buffer); + error("cannot execute cgroup-network helper script: %s", command); } int is_valid_path_symbol(char c) { @@ -588,22 +618,23 @@ int main(int argc, char **argv) { program_version = VERSION; error_log_syslog = 0; + // since cgroup-network runs as root, prevent it from opening symbolic links + procfile_open_flags = O_RDONLY|O_NOFOLLOW; // ------------------------------------------------------------------------ // make sure NETDATA_HOST_PREFIX is safe - host_prefix = getenv("NETDATA_HOST_PREFIX"); - if(!host_prefix || !*host_prefix) - host_prefix = ""; + netdata_configured_host_prefix = getenv("NETDATA_HOST_PREFIX"); + if(verify_netdata_host_prefix() == -1) exit(1); - if(host_prefix[0] != '\0' && verify_path(host_prefix) == -1) - fatal("invalid NETDATA_HOST_PREFIX '%s'", host_prefix); + if(netdata_configured_host_prefix[0] != '\0' && verify_path(netdata_configured_host_prefix) == -1) + fatal("invalid NETDATA_HOST_PREFIX '%s'", netdata_configured_host_prefix); // ------------------------------------------------------------------------ // build a safe environment for our script // the first environment variable is a fixed PATH= - snprintfz(environment_variable2, sizeof(environment_variable2) - 1, "NETDATA_HOST_PREFIX=%s", host_prefix); + snprintfz(environment_variable2, sizeof(environment_variable2) - 1, "NETDATA_HOST_PREFIX=%s", netdata_configured_host_prefix); // ------------------------------------------------------------------------ diff --git a/src/sys_fs_cgroup.c b/collectors/cgroups.plugin/sys_fs_cgroup.c index f6e613c4b..9c0fd7f43 100644 --- a/src/sys_fs_cgroup.c +++ b/collectors/cgroups.plugin/sys_fs_cgroup.c @@ -1,11 +1,14 @@ -#include "common.h" +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "sys_fs_cgroup.h" + +#define PLUGIN_CGROUPS_NAME "cgroups.plugin" +#define PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME "systemd" +#define PLUGIN_CGROUPS_MODULE_CGROUPS_NAME "/sys/fs/cgroup" // ---------------------------------------------------------------------------- // cgroup globals -#define CHART_PRIORITY_SYSTEMD_SERVICES 19000 -#define CHART_PRIORITY_CONTAINERS 40000 - static long system_page_size = 4096; // system will be queried via sysconf() in configuration() static int cgroup_enable_cpuacct_stat = CONFIG_BOOLEAN_AUTO; @@ -71,7 +74,7 @@ void read_cgroup_plugin_configuration() { if(cgroup_update_every < localhost->rrd_update_every) cgroup_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 * cgroup_update_every); + cgroup_check_for_new_every = (int)config_get_number("plugin:cgroups", "check for new cgroups every", (long long)cgroup_check_for_new_every * (long long)cgroup_update_every); if(cgroup_check_for_new_every < cgroup_update_every) cgroup_check_for_new_every = cgroup_update_every; @@ -751,53 +754,55 @@ static inline void read_cgroup_network_interfaces(struct cgroup *cg) { debug(D_CGROUP, "looking for the network interfaces of cgroup '%s' with chart id '%s' and title '%s'", cg->id, cg->chart_id, cg->chart_title); pid_t cgroup_pid; - char buffer[CGROUP_NETWORK_INTERFACE_MAX_LINE + 1]; + char command[CGROUP_NETWORK_INTERFACE_MAX_LINE + 1]; - snprintfz(buffer, CGROUP_NETWORK_INTERFACE_MAX_LINE, "exec %s --cgroup '%s%s'", cgroups_network_interface_script, cgroup_cpuacct_base, cg->id); + snprintfz(command, CGROUP_NETWORK_INTERFACE_MAX_LINE, "exec %s --cgroup '%s%s'", cgroups_network_interface_script, cgroup_cpuacct_base, cg->id); - debug(D_CGROUP, "executing command '%s' for cgroup '%s'", buffer, cg->id); - FILE *fp = mypopen(buffer, &cgroup_pid); - if(fp) { - char *s; - while((s = fgets(buffer, CGROUP_NETWORK_INTERFACE_MAX_LINE, fp))) { - trim(s); + debug(D_CGROUP, "executing command '%s' for cgroup '%s'", command, cg->id); + FILE *fp = mypopen(command, &cgroup_pid); + if(!fp) { + error("CGROUP: cannot popen(\"%s\", \"r\").", command); + return; + } - if(*s && *s != '\n') { - char *t = s; - while(*t && *t != ' ') t++; - if(*t == ' ') { - *t = '\0'; - t++; - } + char *s; + char buffer[CGROUP_NETWORK_INTERFACE_MAX_LINE + 1]; + 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(!*s) { - error("CGROUP: empty host interface returned by script"); - continue; - } + if(!*s) { + error("CGROUP: empty host interface returned by script"); + continue; + } - if(!*t) { - error("CGROUP: empty guest interface returned by script"); - continue; - } + if(!*t) { + error("CGROUP: empty guest interface returned by script"); + continue; + } - struct cgroup_network_interface *i = callocz(1, sizeof(struct cgroup_network_interface)); - i->host_device = strdupz(s); - i->container_device = strdupz(t); - i->next = cg->interfaces; - cg->interfaces = i; + struct cgroup_network_interface *i = callocz(1, sizeof(struct cgroup_network_interface)); + i->host_device = strdupz(s); + i->container_device = strdupz(t); + i->next = cg->interfaces; + cg->interfaces = i; - info("CGROUP: cgroup '%s' has network interface '%s' as '%s'", cg->id, i->host_device, i->container_device); + info("CGROUP: cgroup '%s' has network interface '%s' as '%s'", cg->id, i->host_device, i->container_device); - // register a device rename to proc_net_dev.c - netdev_rename_device_add(i->host_device, i->container_device, cg->chart_id); - } + // register a device rename to proc_net_dev.c + netdev_rename_device_add(i->host_device, i->container_device, cg->chart_id); } - - mypclose(fp, cgroup_pid); - // debug(D_CGROUP, "closed command for cgroup '%s'", cg->id); } - else - error("CGROUP: cannot popen(\"%s\", \"r\").", buffer); + + mypclose(fp, cgroup_pid); + // debug(D_CGROUP, "closed command for cgroup '%s'", cg->id); } static inline void free_cgroup_network_interfaces(struct cgroup *cg) { @@ -845,14 +850,15 @@ static inline void cgroup_get_chart_name(struct cgroup *cg) { debug(D_CGROUP, "looking for the name of cgroup '%s' with chart id '%s' and title '%s'", cg->id, cg->chart_id, cg->chart_title); pid_t cgroup_pid; - char buffer[CGROUP_CHARTID_LINE_MAX + 1]; + char command[CGROUP_CHARTID_LINE_MAX + 1]; - snprintfz(buffer, CGROUP_CHARTID_LINE_MAX, "exec %s '%s' '%s'", cgroups_rename_script, cg->chart_id, cg->id); + snprintfz(command, CGROUP_CHARTID_LINE_MAX, "exec %s '%s' '%s'", cgroups_rename_script, cg->chart_id, cg->id); - debug(D_CGROUP, "executing command \"%s\" for cgroup '%s'", buffer, cg->id); - FILE *fp = mypopen(buffer, &cgroup_pid); + debug(D_CGROUP, "executing command \"%s\" for cgroup '%s'", command, cg->id); + FILE *fp = mypopen(command, &cgroup_pid); if(fp) { - // debug(D_CGROUP, "reading from command '%s' for cgroup '%s'", buffer, cg->id); + // debug(D_CGROUP, "reading from command '%s' for cgroup '%s'", command, cg->id); + char buffer[CGROUP_CHARTID_LINE_MAX + 1]; char *s = fgets(buffer, CGROUP_CHARTID_LINE_MAX, fp); // debug(D_CGROUP, "closing command for cgroup '%s'", cg->id); mypclose(fp, cgroup_pid); @@ -872,7 +878,7 @@ static inline void cgroup_get_chart_name(struct cgroup *cg) { } } else - error("CGROUP: cannot popen(\"%s\", \"r\").", buffer); + error("CGROUP: cannot popen(\"%s\", \"r\").", command); } static inline struct cgroup *cgroup_add(const char *id) { @@ -1460,9 +1466,9 @@ void update_systemd_services_charts( , "services.cpu" , title , "%" - , "cgroup" - , "systemd" - , CHART_PRIORITY_SYSTEMD_SERVICES + , PLUGIN_CGROUPS_NAME + , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME + , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD , update_every , RRDSET_TYPE_STACKED ); @@ -1484,9 +1490,9 @@ void update_systemd_services_charts( , (cgroup_used_memory_without_cache) ? "Systemd Services Used Memory without Cache" : "Systemd Services Used Memory" , "MB" - , "cgroup" - , "systemd" - , CHART_PRIORITY_SYSTEMD_SERVICES + 10 + , PLUGIN_CGROUPS_NAME + , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME + , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 10 , update_every , RRDSET_TYPE_STACKED ); @@ -1507,9 +1513,9 @@ void update_systemd_services_charts( , "services.mem_rss" , "Systemd Services RSS Memory" , "MB" - , "cgroup" - , "systemd" - , CHART_PRIORITY_SYSTEMD_SERVICES + 20 + , PLUGIN_CGROUPS_NAME + , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME + , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 20 , update_every , RRDSET_TYPE_STACKED ); @@ -1528,9 +1534,9 @@ void update_systemd_services_charts( , "services.mem_mapped" , "Systemd Services Mapped Memory" , "MB" - , "cgroup" - , "systemd" - , CHART_PRIORITY_SYSTEMD_SERVICES + 30 + , PLUGIN_CGROUPS_NAME + , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME + , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 30 , update_every , RRDSET_TYPE_STACKED ); @@ -1549,9 +1555,9 @@ void update_systemd_services_charts( , "services.mem_cache" , "Systemd Services Cache Memory" , "MB" - , "cgroup" - , "systemd" - , CHART_PRIORITY_SYSTEMD_SERVICES + 40 + , PLUGIN_CGROUPS_NAME + , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME + , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 40 , update_every , RRDSET_TYPE_STACKED ); @@ -1570,9 +1576,9 @@ void update_systemd_services_charts( , "services.mem_writeback" , "Systemd Services Writeback Memory" , "MB" - , "cgroup" - , "systemd" - , CHART_PRIORITY_SYSTEMD_SERVICES + 50 + , PLUGIN_CGROUPS_NAME + , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME + , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 50 , update_every , RRDSET_TYPE_STACKED ); @@ -1591,9 +1597,9 @@ void update_systemd_services_charts( , "services.mem_pgfault" , "Systemd Services Memory Minor Page Faults" , "MB/s" - , "cgroup" - , "systemd" - , CHART_PRIORITY_SYSTEMD_SERVICES + 60 + , PLUGIN_CGROUPS_NAME + , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME + , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 60 , update_every , RRDSET_TYPE_STACKED ); @@ -1611,9 +1617,9 @@ void update_systemd_services_charts( , "services.mem_pgmajfault" , "Systemd Services Memory Major Page Faults" , "MB/s" - , "cgroup" - , "systemd" - , CHART_PRIORITY_SYSTEMD_SERVICES + 70 + , PLUGIN_CGROUPS_NAME + , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME + , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 70 , update_every , RRDSET_TYPE_STACKED ); @@ -1632,9 +1638,9 @@ void update_systemd_services_charts( , "services.mem_pgpgin" , "Systemd Services Memory Charging Activity" , "MB/s" - , "cgroup" - , "systemd" - , CHART_PRIORITY_SYSTEMD_SERVICES + 80 + , PLUGIN_CGROUPS_NAME + , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME + , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 80 , update_every , RRDSET_TYPE_STACKED ); @@ -1653,9 +1659,9 @@ void update_systemd_services_charts( , "services.mem_pgpgout" , "Systemd Services Memory Uncharging Activity" , "MB/s" - , "cgroup" - , "systemd" - , CHART_PRIORITY_SYSTEMD_SERVICES + 90 + , PLUGIN_CGROUPS_NAME + , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME + , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 90 , update_every , RRDSET_TYPE_STACKED ); @@ -1676,9 +1682,9 @@ void update_systemd_services_charts( , "services.mem_failcnt" , "Systemd Services Memory Limit Failures" , "MB" - , "cgroup" - , "systemd" - , CHART_PRIORITY_SYSTEMD_SERVICES + 110 + , PLUGIN_CGROUPS_NAME + , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME + , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 110 , update_every , RRDSET_TYPE_STACKED ); @@ -1699,9 +1705,9 @@ void update_systemd_services_charts( , "services.swap_usage" , "Systemd Services Swap Memory Used" , "MB" - , "cgroup" - , "systemd" - , CHART_PRIORITY_SYSTEMD_SERVICES + 100 + , PLUGIN_CGROUPS_NAME + , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME + , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 100 , update_every , RRDSET_TYPE_STACKED ); @@ -1722,9 +1728,9 @@ void update_systemd_services_charts( , "services.io_read" , "Systemd Services Disk Read Bandwidth" , "KB/s" - , "cgroup" - , "systemd" - , CHART_PRIORITY_SYSTEMD_SERVICES + 120 + , PLUGIN_CGROUPS_NAME + , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME + , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 120 , update_every , RRDSET_TYPE_STACKED ); @@ -1743,9 +1749,9 @@ void update_systemd_services_charts( , "services.io_write" , "Systemd Services Disk Write Bandwidth" , "KB/s" - , "cgroup" - , "systemd" - , CHART_PRIORITY_SYSTEMD_SERVICES + 130 + , PLUGIN_CGROUPS_NAME + , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME + , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 130 , update_every , RRDSET_TYPE_STACKED ); @@ -1766,9 +1772,9 @@ void update_systemd_services_charts( , "services.io_ops_read" , "Systemd Services Disk Read Operations" , "operations/s" - , "cgroup" - , "systemd" - , CHART_PRIORITY_SYSTEMD_SERVICES + 140 + , PLUGIN_CGROUPS_NAME + , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME + , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 140 , update_every , RRDSET_TYPE_STACKED ); @@ -1787,9 +1793,9 @@ void update_systemd_services_charts( , "services.io_ops_write" , "Systemd Services Disk Write Operations" , "operations/s" - , "cgroup" - , "systemd" - , CHART_PRIORITY_SYSTEMD_SERVICES + 150 + , PLUGIN_CGROUPS_NAME + , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME + , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 150 , update_every , RRDSET_TYPE_STACKED ); @@ -1810,9 +1816,9 @@ void update_systemd_services_charts( , "services.throttle_io_read" , "Systemd Services Throttle Disk Read Bandwidth" , "KB/s" - , "cgroup" - , "systemd" - , CHART_PRIORITY_SYSTEMD_SERVICES + 160 + , PLUGIN_CGROUPS_NAME + , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME + , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 160 , update_every , RRDSET_TYPE_STACKED ); @@ -1831,9 +1837,9 @@ void update_systemd_services_charts( , "services.throttle_io_write" , "Systemd Services Throttle Disk Write Bandwidth" , "KB/s" - , "cgroup" - , "systemd" - , CHART_PRIORITY_SYSTEMD_SERVICES + 170 + , PLUGIN_CGROUPS_NAME + , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME + , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 170 , update_every , RRDSET_TYPE_STACKED ); @@ -1854,9 +1860,9 @@ void update_systemd_services_charts( , "services.throttle_io_ops_read" , "Systemd Services Throttle Disk Read Operations" , "operations/s" - , "cgroup" - , "systemd" - , CHART_PRIORITY_SYSTEMD_SERVICES + 180 + , PLUGIN_CGROUPS_NAME + , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME + , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 180 , update_every , RRDSET_TYPE_STACKED ); @@ -1875,9 +1881,9 @@ void update_systemd_services_charts( , "services.throttle_io_ops_write" , "Systemd Services Throttle Disk Write Operations" , "operations/s" - , "cgroup" - , "systemd" - , CHART_PRIORITY_SYSTEMD_SERVICES + 190 + , PLUGIN_CGROUPS_NAME + , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME + , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 190 , update_every , RRDSET_TYPE_STACKED ); @@ -1898,9 +1904,9 @@ void update_systemd_services_charts( , "services.queued_io_ops_read" , "Systemd Services Queued Disk Read Operations" , "operations/s" - , "cgroup" - , "systemd" - , CHART_PRIORITY_SYSTEMD_SERVICES + 200 + , PLUGIN_CGROUPS_NAME + , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME + , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 200 , update_every , RRDSET_TYPE_STACKED ); @@ -1919,9 +1925,9 @@ void update_systemd_services_charts( , "services.queued_io_ops_write" , "Systemd Services Queued Disk Write Operations" , "operations/s" - , "cgroup" - , "systemd" - , CHART_PRIORITY_SYSTEMD_SERVICES + 210 + , PLUGIN_CGROUPS_NAME + , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME + , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 210 , update_every , RRDSET_TYPE_STACKED ); @@ -1942,9 +1948,9 @@ void update_systemd_services_charts( , "services.merged_io_ops_read" , "Systemd Services Merged Disk Read Operations" , "operations/s" - , "cgroup" - , "systemd" - , CHART_PRIORITY_SYSTEMD_SERVICES + 220 + , PLUGIN_CGROUPS_NAME + , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME + , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 220 , update_every , RRDSET_TYPE_STACKED ); @@ -1963,9 +1969,9 @@ void update_systemd_services_charts( , "services.merged_io_ops_write" , "Systemd Services Merged Disk Write Operations" , "operations/s" - , "cgroup" - , "systemd" - , CHART_PRIORITY_SYSTEMD_SERVICES + 230 + , PLUGIN_CGROUPS_NAME + , PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME + , NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 230 , update_every , RRDSET_TYPE_STACKED ); @@ -1983,7 +1989,7 @@ void update_systemd_services_charts( if(likely(do_cpu && cg->cpuacct_stat.updated)) { if(unlikely(!cg->rd_cpu)) - cg->rd_cpu = rrddim_add(st_cpu, cg->chart_id, cg->chart_title, 100, hz, RRD_ALGORITHM_INCREMENTAL); + cg->rd_cpu = rrddim_add(st_cpu, cg->chart_id, cg->chart_title, 100, system_hz, RRD_ALGORITHM_INCREMENTAL); rrddim_set_by_pointer(st_cpu, cg->rd_cpu, cg->cpuacct_stat.user + cg->cpuacct_stat.system); } @@ -2245,15 +2251,15 @@ void update_cgroup_charts(int update_every) { , "cgroup.cpu" , title , "%" - , "cgroup" - , "default" - , CHART_PRIORITY_CONTAINERS + , PLUGIN_CGROUPS_NAME + , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME + , NETDATA_CHART_PRIO_CGROUPS_CONTAINERS , update_every , RRDSET_TYPE_STACKED ); - rrddim_add(cg->st_cpu, "user", NULL, 100, hz, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(cg->st_cpu, "system", NULL, 100, hz, RRD_ALGORITHM_INCREMENTAL); + rrddim_add(cg->st_cpu, "user", NULL, 100, system_hz, RRD_ALGORITHM_INCREMENTAL); + rrddim_add(cg->st_cpu, "system", NULL, 100, system_hz, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(cg->st_cpu); @@ -2278,9 +2284,9 @@ void update_cgroup_charts(int update_every) { , "cgroup.cpu_per_core" , title , "%" - , "cgroup" - , "default" - , CHART_PRIORITY_CONTAINERS + 100 + , PLUGIN_CGROUPS_NAME + , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME + , NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 100 , update_every , RRDSET_TYPE_STACKED ); @@ -2312,9 +2318,9 @@ void update_cgroup_charts(int update_every) { , "cgroup.mem" , title , "MB" - , "cgroup" - , "default" - , CHART_PRIORITY_CONTAINERS + 210 + , PLUGIN_CGROUPS_NAME + , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME + , NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 210 , update_every , RRDSET_TYPE_STACKED ); @@ -2332,7 +2338,7 @@ void update_cgroup_charts(int update_every) { rrdset_next(cg->st_mem); rrddim_set(cg->st_mem, "cache", cg->memory.cache); - rrddim_set(cg->st_mem, "rss", cg->memory.rss); + rrddim_set(cg->st_mem, "rss", (cg->memory.rss > cg->memory.rss_huge)?(cg->memory.rss - cg->memory.rss_huge):0); if(cg->memory.detailed_has_swap) rrddim_set(cg->st_mem, "swap", cg->memory.swap); @@ -2352,9 +2358,9 @@ void update_cgroup_charts(int update_every) { , "cgroup.writeback" , title , "MB" - , "cgroup" - , "default" - , CHART_PRIORITY_CONTAINERS + 300 + , PLUGIN_CGROUPS_NAME + , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME + , NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 300 , update_every , RRDSET_TYPE_AREA ); @@ -2384,9 +2390,9 @@ void update_cgroup_charts(int update_every) { , "cgroup.mem_activity" , title , "MB/s" - , "cgroup" - , "default" - , CHART_PRIORITY_CONTAINERS + 400 + , PLUGIN_CGROUPS_NAME + , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME + , NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 400 , update_every , RRDSET_TYPE_LINE ); @@ -2412,9 +2418,9 @@ void update_cgroup_charts(int update_every) { , "cgroup.pgfaults" , title , "MB/s" - , "cgroup" - , "default" - , CHART_PRIORITY_CONTAINERS + 500 + , PLUGIN_CGROUPS_NAME + , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME + , NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 500 , update_every , RRDSET_TYPE_LINE ); @@ -2442,9 +2448,9 @@ void update_cgroup_charts(int update_every) { , "cgroup.mem_usage" , title , "MB" - , "cgroup" - , "default" - , CHART_PRIORITY_CONTAINERS + 200 + , PLUGIN_CGROUPS_NAME + , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME + , NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 200 , update_every , RRDSET_TYPE_STACKED ); @@ -2472,9 +2478,9 @@ void update_cgroup_charts(int update_every) { , "cgroup.mem_failcnt" , title , "count" - , "cgroup" - , "default" - , CHART_PRIORITY_CONTAINERS + 250 + , PLUGIN_CGROUPS_NAME + , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME + , NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 250 , update_every , RRDSET_TYPE_LINE ); @@ -2500,9 +2506,9 @@ void update_cgroup_charts(int update_every) { , "cgroup.io" , title , "KB/s" - , "cgroup" - , "default" - , CHART_PRIORITY_CONTAINERS + 1200 + , PLUGIN_CGROUPS_NAME + , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME + , NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 1200 , update_every , RRDSET_TYPE_AREA ); @@ -2530,9 +2536,9 @@ void update_cgroup_charts(int update_every) { , "cgroup.serviced_ops" , title , "operations/s" - , "cgroup" - , "default" - , CHART_PRIORITY_CONTAINERS + 1200 + , PLUGIN_CGROUPS_NAME + , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME + , NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 1200 , update_every , RRDSET_TYPE_LINE ); @@ -2560,9 +2566,9 @@ void update_cgroup_charts(int update_every) { , "cgroup.throttle_io" , title , "KB/s" - , "cgroup" - , "default" - , CHART_PRIORITY_CONTAINERS + 1200 + , PLUGIN_CGROUPS_NAME + , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME + , NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 1200 , update_every , RRDSET_TYPE_AREA ); @@ -2590,9 +2596,9 @@ void update_cgroup_charts(int update_every) { , "cgroup.throttle_serviced_ops" , title , "operations/s" - , "cgroup" - , "default" - , CHART_PRIORITY_CONTAINERS + 1200 + , PLUGIN_CGROUPS_NAME + , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME + , NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 1200 , update_every , RRDSET_TYPE_LINE ); @@ -2620,9 +2626,9 @@ void update_cgroup_charts(int update_every) { , "cgroup.queued_ops" , title , "operations" - , "cgroup" - , "default" - , CHART_PRIORITY_CONTAINERS + 2000 + , PLUGIN_CGROUPS_NAME + , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME + , NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 2000 , update_every , RRDSET_TYPE_LINE ); @@ -2650,9 +2656,9 @@ void update_cgroup_charts(int update_every) { , "cgroup.merged_ops" , title , "operations/s" - , "cgroup" - , "default" - , CHART_PRIORITY_CONTAINERS + 2100 + , PLUGIN_CGROUPS_NAME + , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME + , NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 2100 , update_every , RRDSET_TYPE_LINE ); @@ -2741,7 +2747,7 @@ void *cgroups_main(void *ptr) { , NULL , "NetData CGroups Plugin CPU usage" , "milliseconds/s" - , "cgroup" + , PLUGIN_CGROUPS_NAME , "stats" , 132000 , cgroup_update_every diff --git a/collectors/cgroups.plugin/sys_fs_cgroup.h b/collectors/cgroups.plugin/sys_fs_cgroup.h new file mode 100644 index 000000000..09ce5e3fb --- /dev/null +++ b/collectors/cgroups.plugin/sys_fs_cgroup.h @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef NETDATA_SYS_FS_CGROUP_H +#define NETDATA_SYS_FS_CGROUP_H 1 + +#include "../../daemon/common.h" + +#if (TARGET_OS == OS_LINUX) + +#define NETDATA_PLUGIN_HOOK_LINUX_CGROUPS \ + { \ + .name = "PLUGIN[cgroups]", \ + .config_section = CONFIG_SECTION_PLUGINS, \ + .config_name = "cgroups", \ + .enabled = 1, \ + .thread = NULL, \ + .init_routine = NULL, \ + .start_routine = cgroups_main \ + }, + +extern void *cgroups_main(void *ptr); + +#include "../proc.plugin/plugin_proc.h" + +#else // (TARGET_OS == OS_LINUX) + +#define NETDATA_PLUGIN_HOOK_LINUX_CGROUPS + +#endif // (TARGET_OS == OS_LINUX) + +#endif //NETDATA_SYS_FS_CGROUP_H |