summaryrefslogtreecommitdiffstats
path: root/collectors
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 /collectors
parent7bfa8c8eba72a109d940b1fa5c7acaed9cd7a52c (diff)
Kubernetes labels (#10107)
Co-authored-by: Markos Fountoulakis <markos.fountoulakis.senior@gmail.com> Co-authored-by: Vladimir Kobal <vlad@prokk.net>
Diffstat (limited to 'collectors')
-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
9 files changed, 666 insertions, 187 deletions
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 = "";
+ *data++ = '\0';
+ } else {
+ value = mystrsep(&data, ",");
+ }
+ value = strip_double_quotes(value, 1);
+
+ if (!key || *key == '\0' || !value || *value == '\0')
+ continue;
+
+ *labels = add_label_to_list(*labels, key, value, LABEL_SOURCE_KUBERNETES);
+ }
+
+ return name;
+}
+
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);
@@ -1305,12 +1336,19 @@ static inline void cgroup_get_chart_name(struct cgroup *cg) {
cg->enabled = 0;
}
- if(likely(cg->pending_renames < 2)) {
+ if (likely(cg->pending_renames < 2)) {
+ char *name = s;
+
+ if (!strncmp(s, "k8s_", 4)) {
+ free_label_list(cg->chart_labels);
+ name = parse_k8s_data(&cg->chart_labels, s);
+ }
+
freez(cg->chart_title);
- cg->chart_title = cgroup_title_strdupz(s);
+ cg->chart_title = cgroup_title_strdupz(name);
freez(cg->chart_id);
- cg->chart_id = cgroup_chart_id_strdupz(s);
+ cg->chart_id = cgroup_chart_id_strdupz(name);
cg->hash_chart = simple_hash(cg->chart_id);
}
}
@@ -1508,6 +1546,8 @@ static inline void cgroup_free(struct cgroup *cg) {
freez(cg->chart_id);
freez(cg->chart_title);
+ free_label_list(cg->chart_labels);
+
freez(cg);
cgroup_root_count--;
@@ -3022,6 +3062,9 @@ void update_cgroup_charts(int update_every) {
, update_every
, RRDSET_TYPE_STACKED
);
+
+ rrdset_update_labels(cg->st_cpu, cg->chart_labels);
+
if(!(cg->options & CGROUP_OPTIONS_IS_UNIFIED)) {
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);
@@ -3093,6 +3136,8 @@ void update_cgroup_charts(int update_every) {
, RRDSET_TYPE_LINE
);
+ rrdset_update_labels(cg->st_cpu_limit, cg->chart_labels);
+
if(!(cg->options & CGROUP_OPTIONS_IS_UNIFIED))
rrddim_add(cg->st_cpu_limit, "used", NULL, 1, system_hz, RRD_ALGORITHM_ABSOLUTE);
else
@@ -3146,6 +3191,8 @@ void update_cgroup_charts(int update_every) {
, RRDSET_TYPE_STACKED
);
+ rrdset_update_labels(cg->st_cpu_per_core, cg->chart_labels);
+
for(i = 0; i < cg->cpuacct_usage.cpus; i++) {
snprintfz(id, RRD_ID_LENGTH_MAX, "cpu%u", i);
rrddim_add(cg->st_cpu_per_core, id, NULL, 100, 1000000000, RRD_ALGORITHM_INCREMENTAL);
@@ -3179,6 +3226,9 @@ void update_cgroup_charts(int update_every) {
, update_every
, RRDSET_TYPE_STACKED
);
+
+ rrdset_update_labels(cg->st_mem, cg->chart_labels);
+
if(!(cg->options & CGROUP_OPTIONS_IS_UNIFIED)) {
rrddim_add(cg->st_mem, "cache", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
rrddim_add(cg->st_mem, "rss", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
@@ -3237,6 +3287,8 @@ void update_cgroup_charts(int update_every) {
, RRDSET_TYPE_AREA
);
+ rrdset_update_labels(cg->st_writeback, cg->chart_labels);
+
if(cg->memory.detailed_has_dirty)
rrddim_add(cg->st_writeback, "dirty", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
@@ -3270,6 +3322,8 @@ void update_cgroup_charts(int update_every) {
, RRDSET_TYPE_LINE
);
+ rrdset_update_labels(cg->st_mem_activity, cg->chart_labels);
+
rrddim_add(cg->st_mem_activity, "pgpgin", "in", system_page_size, 1024 * 1024, RRD_ALGORITHM_INCREMENTAL);
rrddim_add(cg->st_mem_activity, "pgpgout", "out", -system_page_size, 1024 * 1024, RRD_ALGORITHM_INCREMENTAL);
}
@@ -3299,6 +3353,8 @@ void update_cgroup_charts(int update_every) {
, RRDSET_TYPE_LINE
);
+ rrdset_update_labels(cg->st_pgfaults, cg->chart_labels);
+
rrddim_add(cg->st_pgfaults, "pgfault", NULL, system_page_size, 1024 * 1024, RRD_ALGORITHM_INCREMENTAL);
rrddim_add(cg->st_pgfaults, "pgmajfault", "swap", -system_page_size, 1024 * 1024, RRD_ALGORITHM_INCREMENTAL);
}
@@ -3329,6 +3385,8 @@ void update_cgroup_charts(int update_every) {
, RRDSET_TYPE_STACKED
);
+ rrdset_update_labels(cg->st_mem_usage, cg->chart_labels);
+
rrddim_add(cg->st_mem_usage, "ram", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
rrddim_add(cg->st_mem_usage, "swap", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
}
@@ -3390,6 +3448,8 @@ void update_cgroup_charts(int update_every) {
, RRDSET_TYPE_STACKED
);
+ rrdset_update_labels(cg->st_mem_usage_limit, cg->chart_labels);
+
rrddim_add(cg->st_mem_usage_limit, "available", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
rrddim_add(cg->st_mem_usage_limit, "used", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
}
@@ -3431,6 +3491,8 @@ void update_cgroup_charts(int update_every) {
, update_every
, RRDSET_TYPE_LINE
);
+
+ rrdset_update_labels(cg->st_mem_failcnt, cg->chart_labels);
rrddim_add(cg->st_mem_failcnt, "failures", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
@@ -3460,6 +3522,8 @@ void update_cgroup_charts(int update_every) {
, RRDSET_TYPE_AREA
);
+ rrdset_update_labels(cg->st_io, cg->chart_labels);
+
rrddim_add(cg->st_io, "read", NULL, 1, 1024, RRD_ALGORITHM_INCREMENTAL);
rrddim_add(cg->st_io, "write", NULL, -1, 1024, RRD_ALGORITHM_INCREMENTAL);
}
@@ -3490,6 +3554,8 @@ void update_cgroup_charts(int update_every) {
, RRDSET_TYPE_LINE
);
+ rrdset_update_labels(cg->st_serviced_ops, cg->chart_labels);
+
rrddim_add(cg->st_serviced_ops, "read", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
rrddim_add(cg->st_serviced_ops, "write", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
@@ -3519,6 +3585,8 @@ void update_cgroup_charts(int update_every) {
, update_every
, RRDSET_TYPE_AREA
);
+
+ rrdset_update_labels(cg->st_throttle_io, cg->chart_labels);
rrddim_add(cg->st_throttle_io, "read", NULL, 1, 1024, RRD_ALGORITHM_INCREMENTAL);
rrddim_add(cg->st_throttle_io, "write", NULL, -1, 1024, RRD_ALGORITHM_INCREMENTAL);
@@ -3549,6 +3617,8 @@ void update_cgroup_charts(int update_every) {
, update_every
, RRDSET_TYPE_LINE
);
+
+ rrdset_update_labels(cg->st_throttle_serviced_ops, cg->chart_labels);
rrddim_add(cg->st_throttle_serviced_ops, "read", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
rrddim_add(cg->st_throttle_serviced_ops, "write", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
@@ -3579,6 +3649,8 @@ void update_cgroup_charts(int update_every) {
, update_every
, RRDSET_TYPE_LINE
);
+
+ rrdset_update_labels(cg->st_queued_ops, cg->chart_labels);
rrddim_add(cg->st_queued_ops, "read", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
rrddim_add(cg->st_queued_ops, "write", NULL, -1, 1, RRD_ALGORITHM_ABSOLUTE);
@@ -3609,6 +3681,8 @@ void update_cgroup_charts(int update_every) {
, update_every
, RRDSET_TYPE_LINE
);
+
+ rrdset_update_labels(cg->st_merged_ops, cg->chart_labels);
rrddim_add(cg->st_merged_ops, "read", NULL, 1, 1024, RRD_ALGORITHM_INCREMENTAL);
rrddim_add(cg->st_merged_ops, "write", NULL, -1, 1024, RRD_ALGORITHM_INCREMENTAL);
@@ -3639,8 +3713,11 @@ void update_cgroup_charts(int update_every) {
, PLUGIN_CGROUPS_NAME
, PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
, cgroup_containers_chart_priority + 2200
- , update_every,
- RRDSET_TYPE_LINE);
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rrdset_update_labels(chart = res->some.st, cg->chart_labels);
res->some.rd10 = rrddim_add(chart, "some 10", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
res->some.rd60 = rrddim_add(chart, "some 60", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
@@ -3669,8 +3746,11 @@ void update_cgroup_charts(int update_every) {
, PLUGIN_CGROUPS_NAME
, PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
, cgroup_containers_chart_priority + 2300
- , update_every,
- RRDSET_TYPE_LINE);
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ rrdset_update_labels(chart = res->some.st, cg->chart_labels);
res->some.rd10 = rrddim_add(chart, "some 10", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
res->some.rd60 = rrddim_add(chart, "some 60", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
@@ -3698,8 +3778,11 @@ void update_cgroup_charts(int update_every) {
, PLUGIN_CGROUPS_NAME
, PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
, cgroup_containers_chart_