summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIlya Mashchenko <ilya@netdata.cloud>2020-12-14 17:27:55 +0300
committerGitHub <noreply@github.com>2020-12-14 17:27:55 +0300
commit0f8175dd3060691394e263cdab01c8f940b1b5d3 (patch)
tree4b14cd6b7e6ba7797eeec4c74b4c4c35cdad4494
parent7bfa8c8eba72a109d940b1fa5c7acaed9cd7a52c (diff)
Kubernetes labels (#10107)
Co-authored-by: Markos Fountoulakis <markos.fountoulakis.senior@gmail.com> Co-authored-by: Vladimir Kobal <vlad@prokk.net>
-rw-r--r--CMakeLists.txt18
-rw-r--r--Makefile.am17
-rwxr-xr-xcollectors/cgroups.plugin/cgroup-name.sh.in407
-rw-r--r--collectors/cgroups.plugin/sys_fs_cgroup.c117
-rw-r--r--collectors/cgroups.plugin/sys_fs_cgroup.h2
-rw-r--r--collectors/cgroups.plugin/tests/test_cgroups_plugin.c110
-rw-r--r--collectors/cgroups.plugin/tests/test_cgroups_plugin.h16
-rw-r--r--collectors/cgroups.plugin/tests/test_doubles.c162
-rw-r--r--collectors/plugins.d/pluginsd_parser.c6
-rw-r--r--collectors/proc.plugin/plugin_proc.h3
-rw-r--r--collectors/proc.plugin/proc_net_dev.c30
-rw-r--r--daemon/commands.c6
-rw-r--r--database/rrd.h48
-rw-r--r--database/rrdcalc.c8
-rw-r--r--database/rrdcalctemplate.c6
-rw-r--r--database/rrdhost.c203
-rw-r--r--database/rrdlabels.c181
-rw-r--r--database/rrdset.c71
-rw-r--r--exporting/graphite/graphite.c6
-rw-r--r--exporting/json/json.c6
-rw-r--r--exporting/opentsdb/opentsdb.c12
-rw-r--r--exporting/prometheus/prometheus.c6
-rw-r--r--exporting/prometheus/remote_write/remote_write.c6
-rw-r--r--exporting/tests/exporting_fixtures.c16
-rw-r--r--health/health_log.c6
-rw-r--r--libnetdata/avl/avl.c16
-rw-r--r--libnetdata/avl/avl.h3
-rw-r--r--libnetdata/config/appconfig.c43
-rw-r--r--libnetdata/config/appconfig.h2
-rw-r--r--streaming/receiver.c2
-rw-r--r--streaming/rrdpush.c20
-rw-r--r--streaming/sender.c8
-rw-r--r--web/api/formatters/json_wrapper.c43
-rw-r--r--web/api/formatters/json_wrapper.h2
-rw-r--r--web/api/formatters/rrd2json.c25
-rw-r--r--web/api/formatters/rrd2json.h1
-rw-r--r--web/api/formatters/rrdset2json.c34
-rw-r--r--web/api/web_api_v1.c32
38 files changed, 1242 insertions, 458 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2d4ca19873..9d749691b9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -590,6 +590,7 @@ set(RRD_PLUGIN_FILES
database/rrddimvar.h
database/rrdfamily.c
database/rrdhost.c
+ database/rrdlabels.c
database/rrd.c
database/rrd.h
database/rrdset.c
@@ -1332,12 +1333,29 @@ endif()
target_link_libraries(valid_urls_testdriver libnetdata ${NETDATA_COMMON_LIBRARIES} ${CMOCKA_LIBRARIES})
# add_test(NAME test_valid_urls COMMAND valid_urls_testdriver)
+ set(CGROUPS_TEST_FILES
+ collectors/cgroups.plugin/tests/test_cgroups_plugin.c
+ collectors/cgroups.plugin/tests/test_cgroups_plugin.h
+ collectors/cgroups.plugin/tests/test_doubles.c
+ database/rrdlabels.c
+ database/rrd.h
+ )
+ add_executable(cgroups_testdriver ${CGROUPS_TEST_FILES} ${CGROUPS_PLUGIN_FILES})
+ target_link_options(
+ cgroups_testdriver
+ PRIVATE
+ -Wl,--wrap=add_label_to_list
+ )
+ target_link_libraries(cgroups_testdriver libnetdata ${NETDATA_COMMON_LIBRARIES} ${CMOCKA_LIBRARIES})
+ add_test(NAME test_cgroups COMMAND cgroups_testdriver)
+
set_target_properties(
str2ld_testdriver
storage_number_testdriver
exporting_engine_testdriver
web_api_testdriver
valid_urls_testdriver
+ cgroups_testdriver
PROPERTIES RUNTIME_OUTPUT_DIRECTORY tests
)
diff --git a/Makefile.am b/Makefile.am
index c7c2f8ab1c..333909e251 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -366,6 +366,7 @@ RRD_PLUGIN_FILES = \
database/rrddimvar.h \
database/rrdfamily.c \
database/rrdhost.c \
+ database/rrdlabels.c \
database/rrd.c \
database/rrd.h \
database/rrdset.c \
@@ -854,6 +855,7 @@ if ENABLE_UNITTESTS
exporting/tests/exporting_engine_testdriver \
web/api/tests/web_api_testdriver \
web/api/tests/valid_urls_testdriver \
+ collectors/cgroups_plugin/tests/cgroups_testdriver \
$(NULL)
TESTS = $(check_PROGRAMS)
@@ -1006,4 +1008,19 @@ if ENABLE_BACKEND_MONGODB
-Wl,--wrap=mongoc_collection_insert_many \
$(NULL)
endif
+
+ collectors_cgroups_plugin_tests_cgroups_testdriver_SOURCES = \
+ collectors/cgroups.plugin/tests/test_cgroups_plugin.c \
+ collectors/cgroups.plugin/tests/test_cgroups_plugin.h \
+ collectors/cgroups.plugin/tests/test_doubles.c \
+ $(CGROUPS_PLUGIN_FILES) \
+ database/rrdlabels.c \
+ database/rrd.h \
+ $(LIBNETDATA_FILES) \
+ $(NULL)
+ collectors_cgroups_plugin_tests_cgroups_testdriver_LDADD = $(NETDATA_COMMON_LIBS) $(TEST_LIBS)
+ collectors_cgroups_plugin_tests_cgroups_testdriver_LDFLAGS = \
+ -Wl,--wrap=add_label_to_list \
+ $(NULL)
+
endif
diff --git a/collectors/cgroups.plugin/cgroup-name.sh.in b/collectors/cgroups.plugin/cgroup-name.sh.in
index cd1b8a5880..19fbf3989d 100755
--- a/collectors/cgroups.plugin/cgroup-name.sh.in
+++ b/collectors/cgroups.plugin/cgroup-name.sh.in
@@ -17,63 +17,63 @@ export LC_ALL=C
PROGRAM_NAME="$(basename "${0}")"
logdate() {
- date "+%Y-%m-%d %H:%M:%S"
+ date "+%Y-%m-%d %H:%M:%S"
}
log() {
- local status="${1}"
- shift
+ local status="${1}"
+ shift
- echo >&2 "$(logdate): ${PROGRAM_NAME}: ${status}: ${*}"
+ echo >&2 "$(logdate): ${PROGRAM_NAME}: ${status}: ${*}"
}
warning() {
- log WARNING "${@}"
+ log WARNING "${@}"
}
error() {
- log ERROR "${@}"
+ log ERROR "${@}"
}
info() {
- log INFO "${@}"
+ log INFO "${@}"
}
fatal() {
- log FATAL "${@}"
- exit 1
+ log FATAL "${@}"
+ exit 1
}
function docker_like_get_name_command() {
- local command="${1}"
- local id="${2}"
- info "Running command: ${command} ps --filter=id=\"${id}\" --format=\"{{.Names}}\""
- NAME="$(${command} ps --filter=id="${id}" --format="{{.Names}}")"
- return 0
+ local command="${1}"
+ local id="${2}"
+ info "Running command: ${command} ps --filter=id=\"${id}\" --format=\"{{.Names}}\""
+ NAME="$(${command} ps --filter=id="${id}" --format="{{.Names}}")"
+ return 0
}
function docker_like_get_name_api() {
- local host_var="${1}"
- local host="${!host_var}"
- local path="/containers/${2}/json"
- if [ -z "${host}" ]; then
- warning "No ${host_var} is set"
- return 1
- fi
- if ! command -v jq >/dev/null 2>&1; then
- warning "Can't find jq command line tool. jq is required for netdata to retrieve container name using ${host} API, falling back to docker ps"
- return 1
- fi
- if [ -S "${host}" ]; then
- info "Running API command: curl --unix-socket \"${host}\" http://localhost${path}"
- JSON=$(curl -sS --unix-socket "${host}" "http://localhost${path}")
- else
- info "Running API command: curl \"${host}${path}\""
- JSON=$(curl -sS "${host}${path}")
- fi
- NAME=$(echo "${JSON}" | jq -r .Name,.Config.Hostname | grep -v null | head -n1 | sed 's|^/||')
- return 0
+ local host_var="${1}"
+ local host="${!host_var}"
+ local path="/containers/${2}/json"
+ if [ -z "${host}" ]; then
+ warning "No ${host_var} is set"
+ return 1
+ fi
+ if ! command -v jq > /dev/null 2>&1; then
+ warning "Can't find jq command line tool. jq is required for netdata to retrieve container name using ${host} API, falling back to docker ps"
+ return 1
+ fi
+ if [ -S "${host}" ]; then
+ info "Running API command: curl --unix-socket \"${host}\" http://localhost${path}"
+ JSON=$(curl -sS --unix-socket "${host}" "http://localhost${path}")
+ else
+ info "Running API command: curl \"${host}${path}\""
+ JSON=$(curl -sS "${host}${path}")
+ fi
+ NAME=$(echo "${JSON}" | jq -r .Name,.Config.Hostname | grep -v null | head -n1 | sed 's|^/||')
+ return 0
}
# get_lbl_val returns the value for the label with the given name.
@@ -99,6 +99,21 @@ function get_lbl_val() {
return 1
}
+function add_lbl_prefix() {
+ local orig_labels prefix
+ orig_labels="${1}"
+ prefix="${2}"
+
+ IFS=, read -ra labels <<< "$orig_labels"
+
+ local new_labels
+ for l in "${labels[@]}"; do
+ new_labels+="${prefix}${l},"
+ done
+
+ echo "${new_labels:0:-1}" # trim last ','
+}
+
# k8s_get_kubepod_name resolves */kubepods/* cgroup name.
# pod level cgroup name format: 'pod_<namespace>_<pod_name>'
# container level cgroup name format: 'cntr_<namespace>_<pod_name>_<container_name>'
@@ -122,11 +137,11 @@ function k8s_get_kubepod_name() {
#
# NOTE: cgroups plugin uses '_' to join dir names, so it is <parent>_<child>_<child>_...
- local funcname="${FUNCNAME[0]}"
+ local fn="${FUNCNAME[0]}"
local id="${1}"
if [[ ! $id =~ ^kubepods ]]; then
- warning "${funcname}: '${id}' is not kubepod cgroup."
+ warning "${fn}: '${id}' is not kubepod cgroup."
return 1
fi
@@ -160,72 +175,121 @@ function k8s_get_kubepod_name() {
fi
if [ -z "$pod_uid" ] && [ -z "$cntr_id" ]; then
- warning "${funcname}: can't extract pod_uid or container_id from the cgroup '$id'."
+ warning "${fn}: can't extract pod_uid or container_id from the cgroup '$id'."
return 1
fi
- [ -n "$pod_uid" ] && info "${funcname}: cgroup '$id' is a pod(uid:$pod_uid)"
- [ -n "$cntr_id" ] && info "${funcname}: cgroup '$id' is a container(id:$cntr_id)"
+ [ -n "$pod_uid" ] && info "${fn}: cgroup '$id' is a pod(uid:$pod_uid)"
+ [ -n "$cntr_id" ] && info "${fn}: cgroup '$id' is a container(id:$cntr_id)"
if ! command -v jq > /dev/null 2>&1; then
- warning "${funcname}: 'jq' command not available."
+ warning "${fn}: 'jq' command not available."
return 1
fi
+ local kube_system_ns
+ local tmp_kube_system_ns_file="${TMPDIR:-"/tmp/"}netdata-cgroups-kube-system-ns"
+ [ -f "$tmp_kube_system_ns_file" ] && kube_system_ns=$(cat "$tmp_kube_system_ns_file" 2> /dev/null)
+
local pods
if [ -n "${KUBERNETES_SERVICE_HOST}" ] && [ -n "${KUBERNETES_PORT_443_TCP_PORT}" ]; then
- local token header url
+ local token header host url
token="$(< /var/run/secrets/kubernetes.io/serviceaccount/token)"
header="Authorization: Bearer $token"
- url="https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_PORT_443_TCP_PORT/api/v1/pods"
+ host="$KUBERNETES_SERVICE_HOST:$KUBERNETES_PORT_443_TCP_PORT"
+
+ if [ -z "$kube_system_ns" ]; then
+ url="https://$host/api/v1/namespaces/kube-system"
+ # FIX: check HTTP response code
+ if ! kube_system_ns=$(curl -sSk -H "$header" "$url" 2>&1); then
+ warning "${fn}: error on curl '${url}': ${kube_system_ns}."
+ else
+ echo "$kube_system_ns" > "$tmp_kube_system_ns_file" 2> /dev/null
+ fi
+ fi
+
+ url="https://$host/api/v1/pods"
+ [ -n "$MY_NODE_NAME" ] && url+="?fieldSelector=spec.nodeName==$MY_NODE_NAME"
+ # FIX: check HTTP response code
if ! pods=$(curl -sSk -H "$header" "$url" 2>&1); then
- warning "${funcname}: error on curl '${url}': ${pods}."
+ warning "${fn}: error on curl '${url}': ${pods}."
return 1
fi
elif ps -C kubelet > /dev/null 2>&1 && command -v kubectl > /dev/null 2>&1; then
+ if [ -z "$kube_system_ns" ]; then
+ if ! kube_system_ns=$(kubectl get namespaces kube-system -o json 2>&1); then
+ warning "${fn}: error on 'kubectl': ${kube_system_ns}."
+ else
+ echo "$kube_system_ns" > "$tmp_kube_system_ns_file" 2> /dev/null
+ fi
+ fi
+
[[ -z ${KUBE_CONFIG+x} ]] && KUBE_CONFIG="/etc/kubernetes/admin.conf"
if ! pods=$(kubectl --kubeconfig="$KUBE_CONFIG" get pods --all-namespaces -o json 2>&1); then
- warning "${funcname}: error on 'kubectl': ${pods}."
+ warning "${fn}: error on 'kubectl': ${pods}."
return 1
fi
else
- warning "${funcname}: not inside the k8s cluster and 'kubectl' command not available."
+ warning "${fn}: not inside the k8s cluster and 'kubectl' command not available."
return 1
fi
+ local kube_system_uid
+ if [ -n "$kube_system_ns" ] && ! kube_system_uid=$(jq -r '.metadata.uid' <<< "$kube_system_ns" 2>&1); then
+ warning "${fn}: error on 'jq' parse kube_system_ns: ${kube_system_uid}."
+ fi
+
local jq_filter
- # 'namespace="<NAMESPACE>",pod_name="<NAME>",pod_uid="<UID>",container_name="<NAME>",container_ID="<ID>"'
- # wrong field value is 'null'
- jq_filter+='.items[] | '
- jq_filter+='"namespace=\"\(.metadata.namespace)\",pod_name=\"\(.metadata.name)\",pod_uid=\"\(.metadata.uid)\"" + '
- jq_filter+='(.status.containerStatuses[]? | '
- jq_filter+='",container_name=\"\(.name)\",container_id=\"\(.containerID)\""'
- jq_filter+=') | '
- jq_filter+='sub("docker://";"")'
+ jq_filter+='.items[] | "'
+ jq_filter+='namespace=\"\(.metadata.namespace)\",'
+ jq_filter+='pod_name=\"\(.metadata.name)\",'
+ jq_filter+='pod_uid=\"\(.metadata.uid)\",'
+ #jq_filter+='\(.metadata.labels | to_entries | map("pod_label_"+.key+"=\""+.value+"\"") | join(",") | if length > 0 then .+"," else . end)'
+ jq_filter+='\((.metadata.ownerReferences[]? | select(.controller==true) | "controller_kind=\""+.kind+"\",controller_name=\""+.name+"\",") // "")'
+ jq_filter+='node_name=\"\(.spec.nodeName)\",'
+ jq_filter+='" + '
+ jq_filter+='(.status.containerStatuses[]? | "'
+ jq_filter+='container_name=\"\(.name)\",'
+ jq_filter+='container_id=\"\(.containerID)\"'
+ jq_filter+='") | '
+ jq_filter+='sub("docker://";"")' # containerID: docker://a346da9bc0e3eaba6b295f64ac16e02f2190db2cef570835706a9e7a36e2c722
local containers
if ! containers=$(jq -r "${jq_filter}" <<< "$pods" 2>&1); then
- warning "${funcname}: error on 'jq' parse: ${containers}."
+ warning "${fn}: error on 'jq' parse pods: ${containers}."
return 1
fi
# available labels:
- # namespace, pod_name, pod_uid, container_name, container_id
+ # namespace, pod_name, pod_uid, container_name, container_id, node_name
local labels
if [ -n "$cntr_id" ]; then
if labels=$(grep "$cntr_id" <<< "$containers" 2> /dev/null); then
- name="cntr_$(get_lbl_val "$labels" namespace)_$(get_lbl_val "$labels" pod_name)_$(get_lbl_val "$labels" container_name)"
+ labels+=',kind="container"'
+ [ -n "$kube_system_uid" ] && [ "$kube_system_uid" != "null" ] && labels+=",cluster_id=\"$kube_system_uid\""
+ name="cntr"
+ name+="_$(get_lbl_val "$labels" namespace)"
+ name+="_$(get_lbl_val "$labels" pod_name)"
+ name+="_$(get_lbl_val "$labels" container_name)"
+ labels=$(add_lbl_prefix "$labels" "k8s_")
+ name+=" $labels"
fi
elif [ -n "$pod_uid" ]; then
if labels=$(grep "$pod_uid" -m 1 <<< "$containers" 2> /dev/null); then
- labels="${labels%%,cont*}"
- name="pod_$(get_lbl_val "$labels" namespace)_$(get_lbl_val "$labels" pod_name)"
+ labels="${labels%%,container_*}"
+ labels+=',kind="pod"'
+ [ -n "$kube_system_uid" ] && [ "$kube_system_uid" != "null" ] && labels+=",cluster_id=\"$kube_system_uid\""
+ name="pod"
+ name+="_$(get_lbl_val "$labels" namespace)"
+ name+="_$(get_lbl_val "$labels" pod_name)"
+ labels=$(add_lbl_prefix "$labels" "k8s_")
+ name+=" $labels"
fi
fi
# jq filter nonexistent field and nonexistent label value is 'null'
if [[ $name =~ _null(_|$) ]]; then
- warning "${funcname}: invalid name: $name (cgroup '$id')"
+ warning "${fn}: invalid name: $name (cgroup '$id')"
name=""
fi
@@ -235,69 +299,77 @@ function k8s_get_kubepod_name() {
}
function k8s_get_name() {
- local funcname="${FUNCNAME[0]}"
+ local fn="${FUNCNAME[0]}"
local id="${1}"
NAME=$(k8s_get_kubepod_name "$id")
if [ -z "${NAME}" ]; then
- warning "${funcname}: cannot find the name of cgroup with id '${id}'. Setting name to ${id} and disabling it."
+ warning "${fn}: cannot find the name of cgroup with id '${id}'. Setting name to ${id} and disabling it."
NAME="${id}"
NAME_NOT_FOUND=3
else
NAME="k8s_${NAME}"
- info "${funcname}: cgroup '${id}' has chart name '${NAME}'"
+
+ local name labels
+ name=${NAME%% *}
+ labels=${NAME#* }
+ if [ "$name" != "$labels" ]; then
+ info "${fn}: cgroup '${id}' has chart name '${name}', labels '${labels}"
+ else
+ info "${fn}: cgroup '${id}' has chart name '${NAME}'"
+ fi
fi
}
function docker_get_name() {
- local id="${1}"
- if hash docker 2>/dev/null; then
- docker_like_get_name_command docker "${id}"
- else
- docker_like_get_name_api DOCKER_HOST "${id}" || docker_like_get_name_command podman "${id}"
- fi
- if [ -z "${NAME}" ]; then
- warning "cannot find the name of docker container '${id}'"
- NAME_NOT_FOUND=2
- NAME="${id:0:12}"
- else
- info "docker container '${id}' is named '${NAME}'"
- fi
+ local id="${1}"
+ if hash docker 2> /dev/null; then
+ docker_like_get_name_command docker "${id}"
+ else
+ docker_like_get_name_api DOCKER_HOST "${id}" || docker_like_get_name_command podman "${id}"
+ fi
+ if [ -z "${NAME}" ]; then
+ warning "cannot find the name of docker container '${id}'"
+ NAME_NOT_FOUND=2
+ NAME="${id:0:12}"
+ else
+ info "docker container '${id}' is named '${NAME}'"
+ fi
}
function docker_validate_id() {
- local id="${1}"
- if [ -n "${id}" ] && { [ ${#id} -eq 64 ] || [ ${#id} -eq 12 ]; }; then
- docker_get_name "${id}"
- else
- error "a docker id cannot be extracted from docker cgroup '${CGROUP}'."
- fi
+ local id="${1}"
+ if [ -n "${id}" ] && { [ ${#id} -eq 64 ] || [ ${#id} -eq 12 ]; }; then
+ docker_get_name "${id}"
+ else
+ error "a docker id cannot be extracted from docker cgroup '${CGROUP}'."
+ fi
}
function podman_get_name() {
- local id="${1}"
-
- # for Podman, prefer using the API if we can, as netdata will not normally have access
- # to other users' containers, so they will not be visible when running `podman ps`
- docker_like_get_name_api PODMAN_HOST "${id}" || docker_like_get_name_command podman "${id}"
-
- if [ -z "${NAME}" ]; then
- warning "cannot find the name of podman container '${id}'"
- NAME_NOT_FOUND=2
- NAME="${id:0:12}"
- else
- info "podman container '${id}' is named '${NAME}'"
- fi
+ local id="${1}"
+
+ # for Podman, prefer using the API if we can, as netdata will not normally have access
+ # to other users' containers, so they will not be visible when running `podman ps`
+ docker_like_get_name_api PODMAN_HOST "${id}" || docker_like_get_name_command podman "${id}"
+
+ if [ -z "${NAME}" ]; then
+ warning "cannot find the name of podman container '${id}'"
+ NAME_NOT_FOUND=2
+ NAME="${id:0:12}"
+ else
+ info "podman container '${id}' is named '${NAME}'"
+ fi
}
function podman_validate_id() {
- local id="${1}"
- if [ -n "${id}" ] && [ ${#id} -eq 64 ]; then
- podman_get_name "${id}"
- else
- error "a podman id cannot be extracted from docker cgroup '${CGROUP}'."
- fi
+ local id="${1}"
+ if [ -n "${id}" ] && [ ${#id} -eq 64 ]; then
+ podman_get_name "${id}"
+ else
+ error "a podman id cannot be extracted from docker cgroup '${CGROUP}'."
+ fi
}
# -----------------------------------------------------------------------------
@@ -314,86 +386,85 @@ NAME=
# -----------------------------------------------------------------------------
if [ -z "${CGROUP}" ]; then
- fatal "called without a cgroup name. Nothing to do."
+ 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
+ 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
if [ -z "${NAME}" ]; then
- if [[ ${CGROUP} =~ ^.*kubepods.* ]]; then
- k8s_get_name "${CGROUP}"
- fi
+ if [[ ${CGROUP} =~ ^.*kubepods.* ]]; then
+ k8s_get_name "${CGROUP}"
+ fi
fi
if [ -z "${NAME}" ]; then
- if [[ ${CGROUP} =~ ^.*docker[-_/\.][a-fA-F0-9]+[-_\.]?.*$ ]]; then
- # docker containers
- #shellcheck disable=SC1117
- DOCKERID="$(echo "${CGROUP}" | sed "s|^.*docker[-_/]\([a-fA-F0-9]\+\)[-_\.]\?.*$|\1|")"
- docker_validate_id "${DOCKERID}"
- elif [[ ${CGROUP} =~ ^.*ecs[-_/\.][a-fA-F0-9]+[-_\.]?.*$ ]]; then
- # ECS
- #shellcheck disable=SC1117
- DOCKERID="$(echo "${CGROUP}" | sed "s|^.*ecs[-_/].*[-_/]\([a-fA-F0-9]\+\)[-_\.]\?.*$|\1|")"
- docker_validate_id "${DOCKERID}"
- elif [[ ${CGROUP} =~ ^.*libpod-[a-fA-F0-9]+.*$ ]]; then
- # Podman
- PODMANID="$(echo "${CGROUP}" | sed "s|^.*libpod-\([a-fA-F0-9]\+\).*$|\1|")"
- podman_validate_id "${PODMANID}"
-
- 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
- elif [[ ${CGROUP} =~ lxc.payload.* ]]; then
- # LXC 4.0
- NAME="$(echo "${CGROUP}" | sed 's/lxc\.payload\.\(.*\)/\1/g')"
- fi
-
- [ -z "${NAME}" ] && NAME="${CGROUP}"
- [ ${#NAME} -gt 100 ] && NAME="${NAME:0:100}"
+ if [[ ${CGROUP} =~ ^.*docker[-_/\.][a-fA-F0-9]+[-_\.]?.*$ ]]; then
+ # docker containers
+ #shellcheck disable=SC1117
+ DOCKERID="$(echo "${CGROUP}" | sed "s|^.*docker[-_/]\([a-fA-F0-9]\+\)[-_\.]\?.*$|\1|")"
+ docker_validate_id "${DOCKERID}"
+ elif [[ ${CGROUP} =~ ^.*ecs[-_/\.][a-fA-F0-9]+[-_\.]?.*$ ]]; then
+ # ECS
+ #shellcheck disable=SC1117
+ DOCKERID="$(echo "${CGROUP}" | sed "s|^.*ecs[-_/].*[-_/]\([a-fA-F0-9]\+\)[-_\.]\?.*$|\1|")"
+ docker_validate_id "${DOCKERID}"
+ elif [[ ${CGROUP} =~ ^.*libpod-[a-fA-F0-9]+.*$ ]]; then
+ # Podman
+ PODMANID="$(echo "${CGROUP}" | sed "s|^.*libpod-\([a-fA-F0-9]\+\).*$|\1|")"
+ podman_validate_id "${PODMANID}"
+
+ 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
+ elif [[ ${CGROUP} =~ lxc.payload.* ]]; then
+ # LXC 4.0
+ NAME="$(echo "${CGROUP}" | sed 's/lxc\.payload\.\(.*\)/\1/g')"
+ fi
+
+ [ -z "${NAME}" ] && NAME="${CGROUP}"
+ [ ${#NAME} -gt 100 ] && NAME="${NAME:0:100}"
fi
info "cgroup '${CGROUP}' is called '${NAME}'"
echo "${NAME}"
exit ${NAME_NOT_FOUND}
-
diff --git a/collectors/cgroups.plugin/sys_fs_cgroup.c b/collectors/cgroups.plugin/sys_fs_cgroup.c
index 75df8c6382..499124cb46 100644
--- a/collectors/cgroups.plugin/sys_fs_cgroup.c
+++ b/collectors/cgroups.plugin/sys_fs_cgroup.c
@@ -600,6 +600,8 @@ struct cgroup {
char *chart_title;
+ struct label *chart_labels;
+
struct cpuacct_stat cpuacct_stat;
struct cpuacct_usage cpuacct_usage;
@@ -1226,7 +1228,7 @@ static inline void read_cgroup_network_interfaces(struct cgroup *cg) {
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);
+ netdev_rename_device_add(i->host_device, i->container_device, cg->chart_id, cg->chart_labels);
}
}
@@ -1275,6 +1277,35 @@ static inline char *cgroup_chart_id_strdupz(const char *s) {
return r;
}
+char *parse_k8s_data(struct label **labels, char *data)
+{
+ char *name = mystrsep(&data, " ");
+
+ if (!data) {
+ return name;
+ }
+
+ while (data) {
+ char *key = mystrsep(&data, "=");
+
+ char *value;
+ if (data && *data == ',') {
+ value = "";