diff --git a/docs/certificatesigningrequest-metrics.md b/docs/certificatesigningrequest-metrics.md index 5f506579d5..ca52fae725 100644 --- a/docs/certificatesigningrequest-metrics.md +++ b/docs/certificatesigningrequest-metrics.md @@ -2,6 +2,7 @@ | Metric name| Metric type | Labels/tags | Status | | ---------- | ----------- | ----------- | ----------- | +| kube_certificatesigningrequest_annotations | Gauge | `certificatesigningrequest`=<certificatesigningrequest-name>
`signer_name`=<certificatesigningrequest-signer-name>| EXPERIMENTAL | | kube_certificatesigningrequest_created| Gauge | `certificatesigningrequest`=<certificatesigningrequest-name>
`signer_name`=<certificatesigningrequest-signer-name>| STABLE | | kube_certificatesigningrequest_condition | Gauge | `certificatesigningrequest`=<certificatesigningrequest-name>
`signer_name`=<certificatesigningrequest-signer-name>
`condition`=<approved\|denied> | STABLE | | kube_certificatesigningrequest_labels | Gauge | `certificatesigningrequest`=<certificatesigningrequest-name>
`signer_name`=<certificatesigningrequest-signer-name>| STABLE | diff --git a/docs/cli-arguments.md b/docs/cli-arguments.md index f56bdfb4ca..cb71f327d3 100644 --- a/docs/cli-arguments.md +++ b/docs/cli-arguments.md @@ -25,37 +25,38 @@ spec: ```txt $ kube-state-metrics -h Usage of ./kube-state-metrics: - --add_dir_header If true, adds the file directory to the header of the log messages - --alsologtostderr log to standard error as well as files - --apiserver string The URL of the apiserver to use as a master - --enable-gzip-encoding Gzip responses when requested by clients via 'Accept-Encoding: gzip' header. - -h, --help Print Help text - --host string Host to expose metrics on. (default "::") - --kubeconfig string Absolute path to the kubeconfig file - --log_backtrace_at traceLocation when logging hits line file:N, emit a stack trace (default :0) - --log_dir string If non-empty, write log files in this directory - --log_file string If non-empty, use this log file - --log_file_max_size uint Defines the maximum size a log file can grow to. Unit is megabytes. If the value is 0, the maximum file size is unlimited. (default 1800) - --logtostderr log to standard error instead of files (default true) - --metric-allowlist string Comma-separated list of metrics to be exposed. This list comprises of exact metric names and/or regex patterns. The allowlist and denylist are mutually exclusive. - --metric-denylist string Comma-separated list of metrics not to be enabled. This list comprises of exact metric names and/or regex patterns. The allowlist and denylist are mutually exclusive. - --metric-labels-allowlist string Comma-separated list of additional Kubernetes label keys that will be used in the resource' labels metric. By default the metric contains only name and namespace labels. To include additional labels provide a list of resource names in their plural form and Kubernetes label keys you would like to allow for them (Example: '=namespaces=[k8s-label-1,k8s-label-n,...],pods=[app],...)'. A single '*' can be provided per resource instead to allow any labels, but that has severe performance implications (Example: '=pods=[*]'). - --namespaces string Comma-separated list of namespaces to be enabled. Defaults to "" - --one_output If true, only write logs to their native severity level (vs also writing to each lower severity level) - --pod string Name of the pod that contains the kube-state-metrics container. When set, it is expected that --pod and --pod-namespace are both set. Most likely this should be passed via the downward API. This is used for auto-detecting sharding. If set, this has preference over statically configured sharding. This is experimental, it may be removed without notice. - --pod-namespace string Name of the namespace of the pod specified by --pod. When set, it is expected that --pod and --pod-namespace are both set. Most likely this should be passed via the downward API. This is used for auto-detecting sharding. If set, this has preference over statically configured sharding. This is experimental, it may be removed without notice. - --port int Port to expose metrics on. (default 8080) - --resources string Comma-separated list of Resources to be enabled. Defaults to "certificatesigningrequests,configmaps,cronjobs,daemonsets,deployments,endpoints,horizontalpodautoscalers,ingresses,jobs,leases,limitranges,mutatingwebhookconfigurations,namespaces,networkpolicies,nodes,persistentvolumeclaims,persistentvolumes,poddisruptionbudgets,pods,replicasets,replicationcontrollers,resourcequotas,secrets,services,statefulsets,storageclasses,validatingwebhookconfigurations,volumeattachments" - --shard int32 The instances shard nominal (zero indexed) within the total number of shards. (default 0) - --skip_headers If true, avoid header prefixes in the log messages - --skip_log_headers If true, avoid headers when opening log files - --stderrthreshold severity logs at or above this threshold go to stderr (default 2) - --telemetry-host string Host to expose kube-state-metrics self metrics on. (default "::") - --telemetry-port int Port to expose kube-state-metrics self metrics on. (default 8081) - --tls-config string Path to the TLS configuration file - --total-shards int The total number of shards. Sharding is disabled when total shards is set to 1. (default 1) - --use-apiserver-cache Sets resourceVersion=0 for ListWatch requests, using cached resources from the apiserver instead of an etcd quorum read. - -v, --v Level number for the log level verbosity - --version kube-state-metrics build version information - --vmodule moduleSpec comma-separated list of pattern=N settings for file-filtered logging + --add_dir_header If true, adds the file directory to the header of the log messages + --alsologtostderr log to standard error as well as files + --apiserver string The URL of the apiserver to use as a master + --enable-gzip-encoding Gzip responses when requested by clients via 'Accept-Encoding: gzip' header. + -h, --help Print Help text + --host string Host to expose metrics on. (default "::") + --kubeconfig string Absolute path to the kubeconfig file + --log_backtrace_at traceLocation when logging hits line file:N, emit a stack trace (default :0) + --log_dir string If non-empty, write log files in this directory + --log_file string If non-empty, use this log file + --log_file_max_size uint Defines the maximum size a log file can grow to. Unit is megabytes. If the value is 0, the maximum file size is unlimited. (default 1800) + --logtostderr log to standard error instead of files (default true) + --metric-allowlist string Comma-separated list of metrics to be exposed. This list comprises of exact metric names and/or regex patterns. The allowlist and denylist are mutually exclusive. + --metric-annotations-allowlist string Comma-separated list of Kubernetes annotations keys that will be used in the resource' labels metric. By default the metric contains only name and namespace labels. To include additional annotations provide a list of resource names in their plural form and Kubernetes annotation keys you would like to allow for them (Example: '=namespaces=[kubernetes.io/team,...],pods=[kubernetes.io/team],...)'. A single '*' can be provided per resource instead to allow any annotations, but that has severe performance implications (Example: '=pods=[*]'). + --metric-denylist string Comma-separated list of metrics not to be enabled. This list comprises of exact metric names and/or regex patterns. The allowlist and denylist are mutually exclusive. + --metric-labels-allowlist string Comma-separated list of additional Kubernetes label keys that will be used in the resource' labels metric. By default the metric contains only name and namespace labels. To include additional labels provide a list of resource names in their plural form and Kubernetes label keys you would like to allow for them (Example: '=namespaces=[k8s-label-1,k8s-label-n,...],pods=[app],...)'. A single '*' can be provided per resource instead to allow any labels, but that has severe performance implications (Example: '=pods=[*]'). + --namespaces string Comma-separated list of namespaces to be enabled. Defaults to "" + --one_output If true, only write logs to their native severity level (vs also writing to each lower severity level) + --pod string Name of the pod that contains the kube-state-metrics container. When set, it is expected that --pod and --pod-namespace are both set. Most likely this should be passed via the downward API. This is used for auto-detecting sharding. If set, this has preference over statically configured sharding. This is experimental, it may be removed without notice. + --pod-namespace string Name of the namespace of the pod specified by --pod. When set, it is expected that --pod and --pod-namespace are both set. Most likely this should be passed via the downward API. This is used for auto-detecting sharding. If set, this has preference over statically configured sharding. This is experimental, it may be removed without notice. + --port int Port to expose metrics on. (default 8080) + --resources string Comma-separated list of Resources to be enabled. Defaults to "certificatesigningrequests,configmaps,cronjobs,daemonsets,deployments,endpoints,horizontalpodautoscalers,ingresses,jobs,leases,limitranges,mutatingwebhookconfigurations,namespaces,networkpolicies,nodes,persistentvolumeclaims,persistentvolumes,poddisruptionbudgets,pods,replicasets,replicationcontrollers,resourcequotas,secrets,services,statefulsets,storageclasses,validatingwebhookconfigurations,volumeattachments" + --shard int32 The instances shard nominal (zero indexed) within the total number of shards. (default 0) + --skip_headers If true, avoid header prefixes in the log messages + --skip_log_headers If true, avoid headers when opening log files + --stderrthreshold severity logs at or above this threshold go to stderr (default 2) + --telemetry-host string Host to expose kube-state-metrics self metrics on. (default "::") + --telemetry-port int Port to expose kube-state-metrics self metrics on. (default 8081) + --tls-config string Path to the TLS configuration file + --total-shards int The total number of shards. Sharding is disabled when total shards is set to 1. (default 1) + --use-apiserver-cache Sets resourceVersion=0 for ListWatch requests, using cached resources from the apiserver instead of an etcd quorum read. + -v, --v Level number for the log level verbosity + --version kube-state-metrics build version information + --vmodule moduleSpec comma-separated list of pattern=N settings for file-filtered logging ``` diff --git a/docs/cronjob-metrics.md b/docs/cronjob-metrics.md index 60c76549e2..56269bb9fe 100644 --- a/docs/cronjob-metrics.md +++ b/docs/cronjob-metrics.md @@ -2,6 +2,7 @@ | Metric name| Metric type | Labels/tags | Status | | ---------- | ----------- | ----------- | ----------- | +| kube_cronjob_annotations | Gauge | `cronjob`=<cronjob-name>
`namespace`=<cronjob-namespace>
`annotation_CRONJOB_ANNOTATION`=<CRONJOB_ANNOTATION> | EXPERIMENTAL | kube_cronjob_info | Gauge | `cronjob`=<cronjob-name>
`namespace`=<cronjob-namespace>
`schedule`=<schedule>
`concurrency_policy`=<concurrency-policy> | STABLE | kube_cronjob_labels | Gauge | `cronjob`=<cronjob-name>
`namespace`=<cronjob-namespace>
`label_CRONJOB_LABEL`=<CRONJOB_LABEL> | STABLE | kube_cronjob_created | Gauge | `cronjob`=<cronjob-name>
`namespace`=<cronjob-namespace> | STABLE diff --git a/docs/daemonset-metrics.md b/docs/daemonset-metrics.md index d95f63101f..9a49b21158 100644 --- a/docs/daemonset-metrics.md +++ b/docs/daemonset-metrics.md @@ -2,6 +2,7 @@ | Metric name| Metric type | Labels/tags | Status | | ---------- | ----------- | ----------- | ----------- | +| kube_daemonset_annotations | Gauge | `daemonset`=<daemonset-name>
`namespace`=<daemonset-namespace>
`annotation_DAEMONSET_ANNOTATION`=<DAEMONSET_ANNOTATION> | EXPERIMENTAL | | kube_daemonset_created | Gauge | `daemonset`=<daemonset-name>
`namespace`=<daemonset-namespace> | STABLE | | kube_daemonset_status_current_number_scheduled | Gauge | `daemonset`=<daemonset-name>
`namespace`=<daemonset-namespace> | STABLE | | kube_daemonset_status_desired_number_scheduled | Gauge | `daemonset`=<daemonset-name>
`namespace`=<daemonset-namespace> | STABLE | diff --git a/docs/deployment-metrics.md b/docs/deployment-metrics.md index 9176f620b7..fee17e7e1f 100644 --- a/docs/deployment-metrics.md +++ b/docs/deployment-metrics.md @@ -2,6 +2,7 @@ | Metric name| Metric type | Labels/tags | Status | | ---------- | ----------- | ----------- | ----------- | +| kube_deployment_annotations | Gauge | `deployment`=<deployment-name>
`namespace`=<deployment-namespace>
`annotation_DEPLOYMENT_ANNOTATION`=<DEPLOYMENT_ANNOTATION> | EXPERIMENTAL | | kube_deployment_status_replicas | Gauge | `deployment`=<deployment-name>
`namespace`=<deployment-namespace> | STABLE | | kube_deployment_status_replicas_ready | Gauge | `deployment`=<deployment-name>
`namespace`=<deployment-namespace> | EXPERIMENTAL | | kube_deployment_status_replicas_available | Gauge | `deployment`=<deployment-name>
`namespace`=<deployment-namespace> | STABLE | diff --git a/docs/endpoint-metrics.md b/docs/endpoint-metrics.md index 2e0b416030..d17211e008 100644 --- a/docs/endpoint-metrics.md +++ b/docs/endpoint-metrics.md @@ -2,6 +2,7 @@ | Metric name| Metric type | Labels/tags | Status | | ---------- | ----------- | ----------- | ----------- | +| kube_endpoint_annotations | Gauge | `endpoint`=<endpoint-name>
`namespace`=<endpoint-namespace>
`annotation_ENDPOINT_ANNOTATION`=<ENDPOINT_ANNOTATION> | EXPERIMENTAL | | kube_endpoint_address_not_ready | Gauge | `endpoint`=<endpoint-name>
`namespace`=<endpoint-namespace> | STABLE | | kube_endpoint_address_available | Gauge | `endpoint`=<endpoint-name>
`namespace`=<endpoint-namespace> | STABLE | | kube_endpoint_info | Gauge | `endpoint`=<endpoint-name>
`namespace`=<endpoint-namespace> | STABLE | diff --git a/docs/horizontalpodautoscaler-metrics.md b/docs/horizontalpodautoscaler-metrics.md index 5c603598ff..518f34ab58 100644 --- a/docs/horizontalpodautoscaler-metrics.md +++ b/docs/horizontalpodautoscaler-metrics.md @@ -2,6 +2,7 @@ | Metric name | Metric type | Labels/tags | Status | | -------------------------------- | ----------- | ------------------------------------------------------------- | ------ | +| kube_horizontalpodautoscaler_annotations | Gauge | `horizontalpodautoscaler`=<hpa-name>
`namespace`=<hpa-namespace> | EXPERIMENTAL | | kube_horizontalpodautoscaler_labels | Gauge | `horizontalpodautoscaler`=<hpa-name>
`namespace`=<hpa-namespace> | STABLE | | kube_horizontalpodautoscaler_metadata_generation | Gauge | `horizontalpodautoscaler`=<hpa-name>
`namespace`=<hpa-namespace> | STABLE | | kube_horizontalpodautoscaler_spec_max_replicas | Gauge | `horizontalpodautoscaler`=<hpa-name>
`namespace`=<hpa-namespace> | STABLE | diff --git a/docs/ingress-metrics.md b/docs/ingress-metrics.md index cfd9643d6a..4af1c20a9f 100644 --- a/docs/ingress-metrics.md +++ b/docs/ingress-metrics.md @@ -2,6 +2,7 @@ | Metric name| Metric type | Labels/tags | Status | | ---------- | ----------- | ----------- | ----------- | +| kube_ingress_annotations | Gauge | `ingress`=<ingress-name>
`namespace`=<ingress-namespace>
`annotation_INGRESS_ANNOTATION`=<ANNOTATION_LABEL> | EXPERIMENTAL | | kube_ingress_info | Gauge | `ingress`=<ingress-name>
`namespace`=<ingress-namespace> | STABLE | | kube_ingress_labels | Gauge | `ingress`=<ingress-name>
`namespace`=<ingress-namespace>
`label_INGRESS_LABEL`=<INGRESS_LABEL> | STABLE | | kube_ingress_created | Gauge | `ingress`=<ingress-name>
`namespace`=<ingress-namespace> | STABLE | diff --git a/docs/job-metrics.md b/docs/job-metrics.md index d0ec58ce60..6d82a882d3 100644 --- a/docs/job-metrics.md +++ b/docs/job-metrics.md @@ -2,6 +2,7 @@ | Metric name| Metric type | Labels/tags | Status | | ---------- | ----------- | ----------- | ----------- | +| kube_job_annotations | Gauge | `job_name`=<job-name>
`namespace`=<job-namespace>
`annotation_JOB_ANNOTATION`=<JOB_ANNOTATION> | EXPERIMENTAL | | kube_job_info | Gauge | `job_name`=<job-name>
`namespace`=<job-namespace> | STABLE | | kube_job_labels | Gauge | `job_name`=<job-name>
`namespace`=<job-namespace>
`label_JOB_LABEL`=<JOB_LABEL> | STABLE | | kube_job_owner | Gauge | `job_name`=<job-name>
`namespace`=<job-namespace>
`owner_kind`=<owner kind>
`owner_name`=<owner name>
`owner_is_controller`=<whether owner is controller> | STABLE | diff --git a/docs/namespace-metrics.md b/docs/namespace-metrics.md index 3241d48de2..5bea8fa8d3 100644 --- a/docs/namespace-metrics.md +++ b/docs/namespace-metrics.md @@ -2,6 +2,7 @@ | Metric name| Metric type | Labels/tags | Status | | ---------- | ----------- | ----------- | ----------- | +| kube_namespace_annotations | Gauge | `namespace`=<namespace-name>
`label_NS_ANNOTATION`=<NS_ANNOTATION> | EXPERIMENTAL | | kube_namespace_created | Gauge | `namespace`=<namespace-name> | STABLE | | kube_namespace_labels | Gauge | `namespace`=<namespace-name>
`label_NS_LABEL`=<NS_LABEL> | STABLE | | kube_namespace_status_condition | Gauge | `namespace`=<namespace-name>
`condition`=<NamespaceDeletionDiscoveryFailure\|NamespaceDeletionContentFailure\|NamespaceDeletionGroupVersionParsingFailure>
`status`=<true\|false\|unknown> | EXPERIMENTAL | diff --git a/docs/networkpolicy-metrics.md b/docs/networkpolicy-metrics.md index 2a023d46c7..c5fa1f64f0 100644 --- a/docs/networkpolicy-metrics.md +++ b/docs/networkpolicy-metrics.md @@ -3,6 +3,7 @@ | Metric name | Metric type | Labels/tags | Status | | ------------------------------------- | ----------- | ------------------------------------------------------------------------------ | ------------ | +| kube_networkpolicy_annotations | Gauge | `namespace`=<namespace name> `networkpolicy`=<networkpolicy name> | EXPERIMENTAL | | kube_networkpolicy_created | Gauge | `namespace`=<namespace name> `networkpolicy`=<networkpolicy name> | EXPERIMENTAL | | kube_networkpolicy_labels | Gauge | `namespace`=<namespace name> `networkpolicy`=<networkpolicy name> | EXPERIMENTAL | | kube_networkpolicy_spec_egress_rules | Gauge | `namespace`=<namespace name> `networkpolicy`=<networkpolicy name> | EXPERIMENTAL | diff --git a/docs/node-metrics.md b/docs/node-metrics.md index 8b89ac9ba9..a0f1d7b430 100644 --- a/docs/node-metrics.md +++ b/docs/node-metrics.md @@ -2,6 +2,7 @@ | Metric name| Metric type | Description | Unit (where applicable) | Labels/tags | Status | | ---------- | ----------- | ----------- | ----------------------- | ----------- | ------ | +| kube_node_annotations | Gauge | Kubernetes annotations converted to Prometheus labels | | `node`=<node-address>
`annotation_NODE_ANNOTATION`=<NODE_ANNOTATION> | EXPERIMENTAL | | kube_node_info | Gauge | Information about a cluster node| |`node`=<node-address>
`kernel_version`=<kernel-version>
`os_image`=<os-image-name>
`container_runtime_version`=<container-runtime-and-version-combination>
`kubelet_version`=<kubelet-version>
`kubeproxy_version`=<kubeproxy-version>
`pod_cidr`=<pod-cidr>
`provider_id`=<provider-id>
`system_uuid`=<system-uuid>
`internal_ip`=<internal-ip> | STABLE | | kube_node_labels | Gauge | Kubernetes labels converted to Prometheus labels | | `node`=<node-address>
`label_NODE_LABEL`=<NODE_LABEL> | STABLE | | kube_node_role | Gauge | The role of a cluster node | | `node`=<node-address>
`role`=<NODE_ROLE> | EXPERIMENTAL | diff --git a/docs/persistentvolume-metrics.md b/docs/persistentvolume-metrics.md index 18624cf76a..241d7ebe83 100644 --- a/docs/persistentvolume-metrics.md +++ b/docs/persistentvolume-metrics.md @@ -2,6 +2,7 @@ | Metric name| Metric type | Labels/tags | Status | | ---------- | ----------- | ----------- | ----------- | +| kube_persistentvolume_annotations | Gauge | `persistentvolume`=<persistentvolume-name>
`annotation_PERSISTENTVOLUME_ANNOTATION`=<PERSISTENTVOLUME_ANNOTATION> | EXPERIMENTAL | | kube_persistentvolume_capacity_bytes | Gauge | `persistentvolume`=<pv-name> | STABLE | | kube_persistentvolume_status_phase | Gauge | `persistentvolume`=<pv-name>
`phase`=<Bound\|Failed\|Pending\|Available\|Released>| STABLE | | kube_persistentvolume_claim_ref | Gauge | `persistentvolume`=<pv-name>
`claim_namespace`=<>
`name`=<> | STABLE | diff --git a/docs/persistentvolumeclaim-metrics.md b/docs/persistentvolumeclaim-metrics.md index 40025b2ca2..7c786e351b 100644 --- a/docs/persistentvolumeclaim-metrics.md +++ b/docs/persistentvolumeclaim-metrics.md @@ -2,6 +2,7 @@ | Metric name| Metric type | Labels/tags | Status | | ---------- | ----------- | ----------- | ----------- | +| kube_persistentvolumeclaim_annotations | Gauge | `persistentvolumeclaim`=<persistentvolumeclaim-name>
`namespace`=<persistentvolumeclaim-namespace>
`annotation_PERSISTENTVOLUMECLAIM_ANNOTATION`=<PERSISTENTVOLUMECLAIM_ANNOATION> | EXPERIMENTAL | | kube_persistentvolumeclaim_access_mode | Gauge | `access_mode`=<persistentvolumeclaim-access-mode>
`namespace`=<persistentvolumeclaim-namespace>
`persistentvolumeclaim`=<persistentvolumeclaim-name> | STABLE | | kube_persistentvolumeclaim_info | Gauge | `namespace`=<persistentvolumeclaim-namespace>
`persistentvolumeclaim`=<persistentvolumeclaim-name>
`storageclass`=<persistentvolumeclaim-storageclassname>
`volumename`=<volumename> | STABLE | | kube_persistentvolumeclaim_labels | Gauge | `persistentvolumeclaim`=<persistentvolumeclaim-name>
`namespace`=<persistentvolumeclaim-namespace>
`label_PERSISTENTVOLUMECLAIM_LABEL`=<PERSISTENTVOLUMECLAIM_LABEL> | STABLE | diff --git a/docs/pod-metrics.md b/docs/pod-metrics.md index 1d1db19d0d..424506bb1d 100644 --- a/docs/pod-metrics.md +++ b/docs/pod-metrics.md @@ -2,6 +2,7 @@ | Metric name| Metric type | Description | Unit (where applicable) | Labels/tags | Status | | ---------- | ----------- | ----------- | ----------------------- | ----------- | ------ | +| kube_pod_annotations | Gauge | Kubernetes annotations converted to Prometheus labels | | `pod`=<pod-name>
`namespace`=<pod-namespace>
`annotation_POD_ANNOTATION`=<POD_ANNOTATION>
`uid`=<pod-uid> | EXPERIMENTAL | | kube_pod_info | Gauge | Information about pod | | `pod`=<pod-name>
`namespace`=<pod-namespace>
`host_ip`=<host-ip>
`pod_ip`=<pod-ip>
`node`=<node-name>
`created_by_kind`=<created_by_kind>
`created_by_name`=<created_by_name>
`uid`=<pod-uid>
`priority_class`=<priority_class>
`host_network`=<host_network>| STABLE | | kube_pod_start_time | Gauge | Start time in unix timestamp for a pod | seconds | `pod`=<pod-name>
`namespace`=<pod-namespace>
`uid`=<pod-uid> | STABLE | | kube_pod_completion_time | Gauge | Completion time in unix timestamp for a pod | seconds | `pod`=<pod-name>
`namespace`=<pod-namespace>
`uid`=<pod-uid> | STABLE | diff --git a/docs/replicaset-metrics.md b/docs/replicaset-metrics.md index ab2e3d16f0..d4bb9c38d0 100644 --- a/docs/replicaset-metrics.md +++ b/docs/replicaset-metrics.md @@ -2,6 +2,7 @@ | Metric name| Metric type | Labels/tags | Status | | ---------- | ----------- | ----------- | ----------- | +| kube_replicaset_annotations | Gauge | `replicaset`=<replicaset-name>
`namespace`=<replicaset-namespace>
`annotation_REPLICASET_ANNOTATION`=<REPLICASET_ANNOTATION> | EXPERIMENTAL | | kube_replicaset_status_replicas | Gauge | `replicaset`=<replicaset-name>
`namespace`=<replicaset-namespace> | STABLE | | kube_replicaset_status_fully_labeled_replicas | Gauge | `replicaset`=<replicaset-name>
`namespace`=<replicaset-namespace> | STABLE | | kube_replicaset_status_ready_replicas | Gauge | `replicaset`=<replicaset-name>
`namespace`=<replicaset-namespace> | STABLE | diff --git a/docs/secret-metrics.md b/docs/secret-metrics.md index 780df876de..b5c4beeed6 100644 --- a/docs/secret-metrics.md +++ b/docs/secret-metrics.md @@ -2,6 +2,7 @@ | Metric name| Metric type | Labels/tags | Status | | ---------- | ----------- | ----------- | ----------- | +| kube_secret_annotations | Gauge | `secret`=<secret-name>
`namespace`=<secret-namespace>
`annotations_SECRET_ANNOTATION`=<SECRET_ANNOTATION> | EXPERIMENTAL | | kube_secret_info | Gauge | `secret`=<secret-name>
`namespace`=<secret-namespace> | STABLE | | kube_secret_type | Gauge | `secret`=<secret-name>
`namespace`=<secret-namespace>
`type`=<secret-type> | STABLE | | kube_secret_labels | Gauge | `secret`=<secret-name>
`namespace`=<secret-namespace>
`label_SECRET_LABEL`=<SECRET_LABEL> | STABLE | diff --git a/docs/service-metrics.md b/docs/service-metrics.md index fa2044e657..80207584c6 100644 --- a/docs/service-metrics.md +++ b/docs/service-metrics.md @@ -2,6 +2,7 @@ | Metric name| Metric type | Description | Unit (where applicable) | Labels/tags | Status | | ---------- | ----------- | ----------- | ----------------------- | ----------- | ------ | +| kube_service_annotations | Gauge | Kubernetes annotations converted to Prometheus labels | |`service`=<service-name>
`namespace`=<service-namespace>
`annotation_SERVICE_ANNOTATION`=<SERVICE_ANNOTATION> | EXPERIMENTAL | | kube_service_info | Gauge | Information about service | |`service`=<service-name>
`namespace`=<service-namespace>
`cluster_ip`=<service cluster ip>
`external_name`=<service external name>
`load_balancer_ip`=<service load balancer ip> | STABLE | | kube_service_labels | Gauge | Kubernetes labels converted to Prometheus labels | |`service`=<service-name>
`namespace`=<service-namespace>
`label_SERVICE_LABEL`=<SERVICE_LABEL> | STABLE | | kube_service_created | Gauge | Unix creation timestamp | seconds |`service`=<service-name>
`namespace`=<service-namespace> | STABLE | diff --git a/docs/statefulset-metrics.md b/docs/statefulset-metrics.md index aff9327517..fae40311c3 100644 --- a/docs/statefulset-metrics.md +++ b/docs/statefulset-metrics.md @@ -2,6 +2,7 @@ | Metric name| Metric type | Labels/tags | Status | | ---------- | ----------- | ----------- | ----------- | +| kube_statefulset_annotations | Gauge | `statefulset`=<statefulset-name>
`namespace`=<statefulset-namespace>
`annotation_STATEFULSET_ANNOTATION`=<STATEFULSET_ANNOTATION> | EXPERIMENTAL | | kube_statefulset_status_replicas | Gauge | `statefulset`=<statefulset-name>
`namespace`=<statefulset-namespace> | STABLE | | kube_statefulset_status_replicas_current | Gauge | `statefulset`=<statefulset-name>
`namespace`=<statefulset-namespace> | STABLE | | kube_statefulset_status_replicas_ready | Gauge | `statefulset`=<statefulset-name>
`namespace`=<statefulset-namespace> | STABLE | diff --git a/docs/storageclass-metrics.md b/docs/storageclass-metrics.md index 184a92fa48..d5f4088fb8 100644 --- a/docs/storageclass-metrics.md +++ b/docs/storageclass-metrics.md @@ -2,6 +2,7 @@ | Metric name| Metric type | Labels/tags | Status | | ---------- | ----------- | ----------- | ----------- | +| kube_storageclass_annotations | Gauge | `storageclass`=<storageclass-name>
`annotation_STORAGECLASS_ANNOTATION`=<STORAGECLASS_ANNOTATION> | EXPERIMENTAL | | kube_storageclass_info | Gauge | `storageclass`=<storageclass-name>
`provisioner`=<storageclass-provisioner>
`reclaim_policy`=<storageclass-reclaimPolicy>
`volume_binding_mode`=<storageclass-volumeBindingMode> | STABLE | | kube_storageclass_labels | Gauge | `storageclass`=<storageclass-name>
`label_STORAGECLASS_LABEL`=<STORAGECLASS_LABEL> | STABLE | | kube_storageclass_created | Gauge | `storageclass`=<storageclass-name> | STABLE | diff --git a/docs/verticalpodautoscaler-metrics.md b/docs/verticalpodautoscaler-metrics.md index 143d671e78..3077c2395c 100644 --- a/docs/verticalpodautoscaler-metrics.md +++ b/docs/verticalpodautoscaler-metrics.md @@ -2,6 +2,7 @@ | Metric name | Metric type | Labels/tags | Status | | -------------------------------- | ----------- | ------------------------------------------------------------- | ------ | +| kube_verticalpodautoscaler_annotations | Gauge | `annotation_app`=<foo>
`namespace`=<namespace>
`target_api_version`=<api version>
`target_kind`=<target kind>
`target_name`=<target name>
`verticalpodautoscaler`=<vertical pod autoscaler name> | EXPERIMENTAL | | kube_verticalpodautoscaler_spec_resourcepolicy_container_policies_minallowed | Gauge | `container`=<container name>
`namespace`=<namespace>
`resource`=<cpu memory>
`target_api_version`=<api version>
`target_kind`=<target kind>
`target_name`=<target name>
`unit`=<core byte>
`verticalpodautoscaler`=<vertical pod autoscaler name> | EXPERIMENTAL | | kube_verticalpodautoscaler_spec_resourcepolicy_container_policies_maxallowed | Gauge | `container`=<container name>
`namespace`=<namespace>
`resource`=<cpu memory>
`target_api_version`=<api version>
`target_kind`=<target kind>
`target_name`=<target name>
`unit`=<core byte>
`verticalpodautoscaler`=<vertical pod autoscaler name> | EXPERIMENTAL | | kube_verticalpodautoscaler_status_recommendation_containerrecommendations_lowerbound | Gauge | `container`=<container name>
`namespace`=<namespace>
`resource`=<cpu memory>
`target_api_version`=<api version>
`target_kind`=<target kind>
`target_name`=<target name>
`unit`=<core byte>
`verticalpodautoscaler`=<vertical pod autoscaler name> | EXPERIMENTAL | diff --git a/internal/store/builder.go b/internal/store/builder.go index 317e17d680..9bc4a48d00 100644 --- a/internal/store/builder.go +++ b/internal/store/builder.go @@ -57,19 +57,20 @@ var _ ksmtypes.BuilderInterface = &Builder{} // Builder helps to build store. It follows the builder pattern // (https://en.wikipedia.org/wiki/Builder_pattern). type Builder struct { - kubeClient clientset.Interface - vpaClient vpaclientset.Interface - namespaces options.NamespaceList - ctx context.Context - enabledResources []string - allowDenyList ksmtypes.AllowDenyLister - listWatchMetrics *watch.ListWatchMetrics - shardingMetrics *sharding.Metrics - shard int32 - totalShards int - buildStoresFunc ksmtypes.BuildStoresFunc - allowLabelsList map[string][]string - useAPIServerCache bool + kubeClient clientset.Interface + vpaClient vpaclientset.Interface + namespaces options.NamespaceList + ctx context.Context + enabledResources []string + allowDenyList ksmtypes.AllowDenyLister + listWatchMetrics *watch.ListWatchMetrics + shardingMetrics *sharding.Metrics + shard int32 + totalShards int + buildStoresFunc ksmtypes.BuildStoresFunc + allowAnnotationsList map[string][]string + allowLabelsList map[string][]string + useAPIServerCache bool } // NewBuilder returns a new builder. @@ -148,6 +149,13 @@ func (b *Builder) DefaultGenerateStoresFunc() ksmtypes.BuildStoresFunc { return b.buildStores } +// WithAllowAnnotations configures which annotations can be returned for metrics +func (b *Builder) WithAllowAnnotations(annotations map[string][]string) { + if len(annotations) > 0 { + b.allowAnnotationsList = annotations + } +} + // WithAllowLabels configures which labels can be returned for metrics func (b *Builder) WithAllowLabels(labels map[string][]string) { if len(labels) > 0 { @@ -234,31 +242,31 @@ func (b *Builder) buildConfigMapStores() []*metricsstore.MetricsStore { } func (b *Builder) buildCronJobStores() []*metricsstore.MetricsStore { - return b.buildStoresFunc(cronJobMetricFamilies(b.allowLabelsList["cronjobs"]), &batchv1beta1.CronJob{}, createCronJobListWatch, b.useAPIServerCache) + return b.buildStoresFunc(cronJobMetricFamilies(b.allowAnnotationsList["cronjobs"], b.allowLabelsList["cronjobs"]), &batchv1beta1.CronJob{}, createCronJobListWatch, b.useAPIServerCache) } func (b *Builder) buildDaemonSetStores() []*metricsstore.MetricsStore { - return b.buildStoresFunc(daemonSetMetricFamilies(b.allowLabelsList["daemonsets"]), &appsv1.DaemonSet{}, createDaemonSetListWatch, b.useAPIServerCache) + return b.buildStoresFunc(daemonSetMetricFamilies(b.allowAnnotationsList["daemonsets"], b.allowLabelsList["daemonsets"]), &appsv1.DaemonSet{}, createDaemonSetListWatch, b.useAPIServerCache) } func (b *Builder) buildDeploymentStores() []*metricsstore.MetricsStore { - return b.buildStoresFunc(deploymentMetricFamilies(b.allowLabelsList["deployments"]), &appsv1.Deployment{}, createDeploymentListWatch, b.useAPIServerCache) + return b.buildStoresFunc(deploymentMetricFamilies(b.allowAnnotationsList["deployments"], b.allowLabelsList["deployments"]), &appsv1.Deployment{}, createDeploymentListWatch, b.useAPIServerCache) } func (b *Builder) buildEndpointsStores() []*metricsstore.MetricsStore { - return b.buildStoresFunc(endpointMetricFamilies(b.allowLabelsList["endpoints"]), &v1.Endpoints{}, createEndpointsListWatch, b.useAPIServerCache) + return b.buildStoresFunc(endpointMetricFamilies(b.allowAnnotationsList["endpoints"], b.allowLabelsList["endpoints"]), &v1.Endpoints{}, createEndpointsListWatch, b.useAPIServerCache) } func (b *Builder) buildHPAStores() []*metricsstore.MetricsStore { - return b.buildStoresFunc(hpaMetricFamilies(b.allowLabelsList["horizontalpodautoscalers"]), &autoscaling.HorizontalPodAutoscaler{}, createHPAListWatch, b.useAPIServerCache) + return b.buildStoresFunc(hpaMetricFamilies(b.allowAnnotationsList["horizontalpodautoscalers"], b.allowLabelsList["horizontalpodautoscalers"]), &autoscaling.HorizontalPodAutoscaler{}, createHPAListWatch, b.useAPIServerCache) } func (b *Builder) buildIngressStores() []*metricsstore.MetricsStore { - return b.buildStoresFunc(ingressMetricFamilies(b.allowLabelsList["ingresses"]), &networkingv1.Ingress{}, createIngressListWatch, b.useAPIServerCache) + return b.buildStoresFunc(ingressMetricFamilies(b.allowAnnotationsList["ingresses"], b.allowLabelsList["ingresses"]), &networkingv1.Ingress{}, createIngressListWatch, b.useAPIServerCache) } func (b *Builder) buildJobStores() []*metricsstore.MetricsStore { - return b.buildStoresFunc(jobMetricFamilies(b.allowLabelsList["jobs"]), &batchv1.Job{}, createJobListWatch, b.useAPIServerCache) + return b.buildStoresFunc(jobMetricFamilies(b.allowAnnotationsList["jobs"], b.allowLabelsList["jobs"]), &batchv1.Job{}, createJobListWatch, b.useAPIServerCache) } func (b *Builder) buildLimitRangeStores() []*metricsstore.MetricsStore { @@ -270,23 +278,23 @@ func (b *Builder) buildMutatingWebhookConfigurationStores() []*metricsstore.Metr } func (b *Builder) buildNamespaceStores() []*metricsstore.MetricsStore { - return b.buildStoresFunc(namespaceMetricFamilies(b.allowLabelsList["namespaces"]), &v1.Namespace{}, createNamespaceListWatch, b.useAPIServerCache) + return b.buildStoresFunc(namespaceMetricFamilies(b.allowAnnotationsList["namespaces"], b.allowLabelsList["namespaces"]), &v1.Namespace{}, createNamespaceListWatch, b.useAPIServerCache) } func (b *Builder) buildNetworkPolicyStores() []*metricsstore.MetricsStore { - return b.buildStoresFunc(networkPolicyMetricFamilies(b.allowLabelsList["networkpolicies"]), &networkingv1.NetworkPolicy{}, createNetworkPolicyListWatch, b.useAPIServerCache) + return b.buildStoresFunc(networkPolicyMetricFamilies(b.allowAnnotationsList["networkpolicies"], b.allowLabelsList["networkpolicies"]), &networkingv1.NetworkPolicy{}, createNetworkPolicyListWatch, b.useAPIServerCache) } func (b *Builder) buildNodeStores() []*metricsstore.MetricsStore { - return b.buildStoresFunc(nodeMetricFamilies(b.allowLabelsList["nodes"]), &v1.Node{}, createNodeListWatch, b.useAPIServerCache) + return b.buildStoresFunc(nodeMetricFamilies(b.allowAnnotationsList["nodes"], b.allowLabelsList["nodes"]), &v1.Node{}, createNodeListWatch, b.useAPIServerCache) } func (b *Builder) buildPersistentVolumeClaimStores() []*metricsstore.MetricsStore { - return b.buildStoresFunc(persistentVolumeClaimMetricFamilies(b.allowLabelsList["persistentvolumeclaims"]), &v1.PersistentVolumeClaim{}, createPersistentVolumeClaimListWatch, b.useAPIServerCache) + return b.buildStoresFunc(persistentVolumeClaimMetricFamilies(b.allowAnnotationsList["persistentvolumeclaims"], b.allowLabelsList["persistentvolumeclaims"]), &v1.PersistentVolumeClaim{}, createPersistentVolumeClaimListWatch, b.useAPIServerCache) } func (b *Builder) buildPersistentVolumeStores() []*metricsstore.MetricsStore { - return b.buildStoresFunc(persistentVolumeMetricFamilies(b.allowLabelsList["persistentvolumes"]), &v1.PersistentVolume{}, createPersistentVolumeListWatch, b.useAPIServerCache) + return b.buildStoresFunc(persistentVolumeMetricFamilies(b.allowAnnotationsList["persistentvolumes"], b.allowLabelsList["persistentvolumes"]), &v1.PersistentVolume{}, createPersistentVolumeListWatch, b.useAPIServerCache) } func (b *Builder) buildPodDisruptionBudgetStores() []*metricsstore.MetricsStore { @@ -294,7 +302,7 @@ func (b *Builder) buildPodDisruptionBudgetStores() []*metricsstore.MetricsStore } func (b *Builder) buildReplicaSetStores() []*metricsstore.MetricsStore { - return b.buildStoresFunc(replicaSetMetricFamilies(b.allowLabelsList["replicasets"]), &appsv1.ReplicaSet{}, createReplicaSetListWatch, b.useAPIServerCache) + return b.buildStoresFunc(replicaSetMetricFamilies(b.allowAnnotationsList["replicasets"], b.allowLabelsList["replicasets"]), &appsv1.ReplicaSet{}, createReplicaSetListWatch, b.useAPIServerCache) } func (b *Builder) buildReplicationControllerStores() []*metricsstore.MetricsStore { @@ -306,27 +314,27 @@ func (b *Builder) buildResourceQuotaStores() []*metricsstore.MetricsStore { } func (b *Builder) buildSecretStores() []*metricsstore.MetricsStore { - return b.buildStoresFunc(secretMetricFamilies(b.allowLabelsList["secrets"]), &v1.Secret{}, createSecretListWatch, b.useAPIServerCache) + return b.buildStoresFunc(secretMetricFamilies(b.allowAnnotationsList["secrets"], b.allowLabelsList["secrets"]), &v1.Secret{}, createSecretListWatch, b.useAPIServerCache) } func (b *Builder) buildServiceStores() []*metricsstore.MetricsStore { - return b.buildStoresFunc(serviceMetricFamilies(b.allowLabelsList["services"]), &v1.Service{}, createServiceListWatch, b.useAPIServerCache) + return b.buildStoresFunc(serviceMetricFamilies(b.allowAnnotationsList["services"], b.allowLabelsList["services"]), &v1.Service{}, createServiceListWatch, b.useAPIServerCache) } func (b *Builder) buildStatefulSetStores() []*metricsstore.MetricsStore { - return b.buildStoresFunc(statefulSetMetricFamilies(b.allowLabelsList["statefulsets"]), &appsv1.StatefulSet{}, createStatefulSetListWatch, b.useAPIServerCache) + return b.buildStoresFunc(statefulSetMetricFamilies(b.allowAnnotationsList["statefulsets"], b.allowLabelsList["statefulsets"]), &appsv1.StatefulSet{}, createStatefulSetListWatch, b.useAPIServerCache) } func (b *Builder) buildStorageClassStores() []*metricsstore.MetricsStore { - return b.buildStoresFunc(storageClassMetricFamilies(b.allowLabelsList["storageclasses"]), &storagev1.StorageClass{}, createStorageClassListWatch, b.useAPIServerCache) + return b.buildStoresFunc(storageClassMetricFamilies(b.allowAnnotationsList["storageclasses"], b.allowLabelsList["storageclasses"]), &storagev1.StorageClass{}, createStorageClassListWatch, b.useAPIServerCache) } func (b *Builder) buildPodStores() []*metricsstore.MetricsStore { - return b.buildStoresFunc(podMetricFamilies(b.allowLabelsList["pods"]), &v1.Pod{}, createPodListWatch, b.useAPIServerCache) + return b.buildStoresFunc(podMetricFamilies(b.allowAnnotationsList["pods"], b.allowLabelsList["pods"]), &v1.Pod{}, createPodListWatch, b.useAPIServerCache) } func (b *Builder) buildCsrStores() []*metricsstore.MetricsStore { - return b.buildStoresFunc(csrMetricFamilies(b.allowLabelsList["certificatesigningrequests"]), &certv1.CertificateSigningRequest{}, createCSRListWatch, b.useAPIServerCache) + return b.buildStoresFunc(csrMetricFamilies(b.allowAnnotationsList["certificatesigningrequests"], b.allowLabelsList["certificatesigningrequests"]), &certv1.CertificateSigningRequest{}, createCSRListWatch, b.useAPIServerCache) } func (b *Builder) buildValidatingWebhookConfigurationStores() []*metricsstore.MetricsStore { @@ -338,7 +346,7 @@ func (b *Builder) buildVolumeAttachmentStores() []*metricsstore.MetricsStore { } func (b *Builder) buildVPAStores() []*metricsstore.MetricsStore { - return b.buildStoresFunc(vpaMetricFamilies(b.allowLabelsList["verticalpodautoscalers"]), &vpaautoscaling.VerticalPodAutoscaler{}, createVPAListWatchFunc(b.vpaClient), b.useAPIServerCache) + return b.buildStoresFunc(vpaMetricFamilies(b.allowAnnotationsList["verticalpodautoscalers"], b.allowLabelsList["verticalpodautoscalers"]), &vpaautoscaling.VerticalPodAutoscaler{}, createVPAListWatchFunc(b.vpaClient), b.useAPIServerCache) } func (b *Builder) buildLeasesStores() []*metricsstore.MetricsStore { diff --git a/internal/store/certificatesigningrequest.go b/internal/store/certificatesigningrequest.go index ac3331ecaf..523d218b46 100644 --- a/internal/store/certificatesigningrequest.go +++ b/internal/store/certificatesigningrequest.go @@ -31,20 +31,40 @@ import ( ) var ( + descCSRAnnotationsName = "kube_certificatesigningrequest_annotations" + descCSRAnnotationsHelp = "Kubernetes annotations converted to Prometheus labels." descCSRLabelsName = "kube_certificatesigningrequest_labels" descCSRLabelsHelp = "Kubernetes labels converted to Prometheus labels." descCSRLabelsDefaultLabels = []string{"certificatesigningrequest", "signer_name"} ) -func csrMetricFamilies(allowLabelsList []string) []generator.FamilyGenerator { +func csrMetricFamilies(allowAnnotationsList, allowLabelsList []string) []generator.FamilyGenerator { return []generator.FamilyGenerator{ + *generator.NewFamilyGenerator( + descCSRAnnotationsName, + descCSRAnnotationsHelp, + metric.Gauge, + "", + wrapCSRFunc(func(j *certv1.CertificateSigningRequest) *metric.Family { + annotationKeys, annotationValues := createPrometheusLabelKeysValues("annotation", j.Annotations, allowAnnotationsList) + return &metric.Family{ + Metrics: []*metric.Metric{ + { + LabelKeys: annotationKeys, + LabelValues: annotationValues, + Value: 1, + }, + }, + } + }), + ), *generator.NewFamilyGenerator( descCSRLabelsName, descCSRLabelsHelp, metric.Gauge, "", wrapCSRFunc(func(j *certv1.CertificateSigningRequest) *metric.Family { - labelKeys, labelValues := createLabelKeysValues(j.Labels, allowLabelsList) + labelKeys, labelValues := createPrometheusLabelKeysValues("label", j.Labels, allowLabelsList) return &metric.Family{ Metrics: []*metric.Metric{ { diff --git a/internal/store/certificatesigningrequest_test.go b/internal/store/certificatesigningrequest_test.go index 5f5f3a81ab..4849b87363 100644 --- a/internal/store/certificatesigningrequest_test.go +++ b/internal/store/certificatesigningrequest_test.go @@ -227,8 +227,8 @@ func TestCsrStore(t *testing.T) { }, } for i, c := range cases { - c.Func = generator.ComposeMetricGenFuncs(csrMetricFamilies(nil)) - c.Headers = generator.ExtractMetricFamilyHeaders(csrMetricFamilies(nil)) + c.Func = generator.ComposeMetricGenFuncs(csrMetricFamilies(nil, nil)) + c.Headers = generator.ExtractMetricFamilyHeaders(csrMetricFamilies(nil, nil)) if err := c.run(); err != nil { t.Errorf("unexpected error when collecting result in %vth run:\n%s", i, err) } diff --git a/internal/store/cronjob.go b/internal/store/cronjob.go index 5698e4ea5b..636bc48032 100644 --- a/internal/store/cronjob.go +++ b/internal/store/cronjob.go @@ -34,20 +34,40 @@ import ( ) var ( + descCronJobAnnotationsName = "kube_cronjob_annotations" + descCronJobAnnotationsHelp = "Kubernetes annotations converted to Prometheus labels." descCronJobLabelsName = "kube_cronjob_labels" descCronJobLabelsHelp = "Kubernetes labels converted to Prometheus labels." descCronJobLabelsDefaultLabels = []string{"namespace", "cronjob"} ) -func cronJobMetricFamilies(allowLabelsList []string) []generator.FamilyGenerator { +func cronJobMetricFamilies(allowAnnotationsList, allowLabelsList []string) []generator.FamilyGenerator { return []generator.FamilyGenerator{ + *generator.NewFamilyGenerator( + descCronJobAnnotationsName, + descCronJobAnnotationsHelp, + metric.Gauge, + "", + wrapCronJobFunc(func(j *batchv1beta1.CronJob) *metric.Family { + annotationKeys, annotationValues := createPrometheusLabelKeysValues("label", j.Annotations, allowLabelsList) + return &metric.Family{ + Metrics: []*metric.Metric{ + { + LabelKeys: annotationKeys, + LabelValues: annotationValues, + Value: 1, + }, + }, + } + }), + ), *generator.NewFamilyGenerator( descCronJobLabelsName, descCronJobLabelsHelp, metric.Gauge, "", wrapCronJobFunc(func(j *batchv1beta1.CronJob) *metric.Family { - labelKeys, labelValues := createLabelKeysValues(j.Labels, allowLabelsList) + labelKeys, labelValues := createPrometheusLabelKeysValues("label", j.Labels, allowLabelsList) return &metric.Family{ Metrics: []*metric.Metric{ { diff --git a/internal/store/cronjob_test.go b/internal/store/cronjob_test.go index 22186382cc..ac41f8165f 100644 --- a/internal/store/cronjob_test.go +++ b/internal/store/cronjob_test.go @@ -281,8 +281,8 @@ func TestCronJobStore(t *testing.T) { }, } for i, c := range cases { - c.Func = generator.ComposeMetricGenFuncs(cronJobMetricFamilies(nil)) - c.Headers = generator.ExtractMetricFamilyHeaders(cronJobMetricFamilies(nil)) + c.Func = generator.ComposeMetricGenFuncs(cronJobMetricFamilies(nil, nil)) + c.Headers = generator.ExtractMetricFamilyHeaders(cronJobMetricFamilies(nil, nil)) if err := c.run(); err != nil { t.Errorf("unexpected collecting result in %vth run:\n%s", i, err) } diff --git a/internal/store/daemonset.go b/internal/store/daemonset.go index fc5886263b..07e3a38f1f 100644 --- a/internal/store/daemonset.go +++ b/internal/store/daemonset.go @@ -31,12 +31,14 @@ import ( ) var ( + descDaemonSetAnnotationsName = "kube_daemonset_annotations" + descDaemonSetAnnotationsHelp = "Kubernetes annotations converted to Prometheus labels." descDaemonSetLabelsName = "kube_daemonset_labels" descDaemonSetLabelsHelp = "Kubernetes labels converted to Prometheus labels." descDaemonSetLabelsDefaultLabels = []string{"namespace", "daemonset"} ) -func daemonSetMetricFamilies(allowLabelsList []string) []generator.FamilyGenerator { +func daemonSetMetricFamilies(allowAnnotationsList, allowLabelsList []string) []generator.FamilyGenerator { return []generator.FamilyGenerator{ *generator.NewFamilyGenerator( "kube_daemonset_created", @@ -210,13 +212,31 @@ func daemonSetMetricFamilies(allowLabelsList []string) []generator.FamilyGenerat } }), ), + *generator.NewFamilyGenerator( + descDaemonSetAnnotationsName, + descDaemonSetAnnotationsHelp, + metric.Gauge, + "", + wrapDaemonSetFunc(func(d *v1.DaemonSet) *metric.Family { + annotationKeys, annotationValues := createPrometheusLabelKeysValues("annotation", d.Annotations, allowLabelsList) + return &metric.Family{ + Metrics: []*metric.Metric{ + { + LabelKeys: annotationKeys, + LabelValues: annotationValues, + Value: 1, + }, + }, + } + }), + ), *generator.NewFamilyGenerator( descDaemonSetLabelsName, descDaemonSetLabelsHelp, metric.Gauge, "", wrapDaemonSetFunc(func(d *v1.DaemonSet) *metric.Family { - labelKeys, labelValues := createLabelKeysValues(d.Labels, allowLabelsList) + labelKeys, labelValues := createPrometheusLabelKeysValues("label", d.Labels, allowLabelsList) return &metric.Family{ Metrics: []*metric.Metric{ { diff --git a/internal/store/daemonset_test.go b/internal/store/daemonset_test.go index 20709f7ae6..5a9bb2faa0 100644 --- a/internal/store/daemonset_test.go +++ b/internal/store/daemonset_test.go @@ -222,8 +222,8 @@ func TestDaemonSetStore(t *testing.T) { }, } for i, c := range cases { - c.Func = generator.ComposeMetricGenFuncs(daemonSetMetricFamilies(nil)) - c.Headers = generator.ExtractMetricFamilyHeaders(daemonSetMetricFamilies(nil)) + c.Func = generator.ComposeMetricGenFuncs(daemonSetMetricFamilies(nil, nil)) + c.Headers = generator.ExtractMetricFamilyHeaders(daemonSetMetricFamilies(nil, nil)) if err := c.run(); err != nil { t.Errorf("unexpected collecting result in %vth run:\n%s", i, err) } diff --git a/internal/store/deployment.go b/internal/store/deployment.go index a6db137b3a..10fe07a13f 100644 --- a/internal/store/deployment.go +++ b/internal/store/deployment.go @@ -32,12 +32,14 @@ import ( ) var ( + descDeploymentAnnotationsName = "kube_deployment_annotations" + descDeploymentAnnotationsHelp = "Kubernetes annotations converted to Prometheus labels." descDeploymentLabelsName = "kube_deployment_labels" descDeploymentLabelsHelp = "Kubernetes labels converted to Prometheus labels." descDeploymentLabelsDefaultLabels = []string{"namespace", "deployment"} ) -func deploymentMetricFamilies(allowLabelsList []string) []generator.FamilyGenerator { +func deploymentMetricFamilies(allowAnnotationsList, allowLabelsList []string) []generator.FamilyGenerator { return []generator.FamilyGenerator{ *generator.NewFamilyGenerator( "kube_deployment_created", @@ -266,13 +268,31 @@ func deploymentMetricFamilies(allowLabelsList []string) []generator.FamilyGenera } }), ), + *generator.NewFamilyGenerator( + descDeploymentAnnotationsName, + descDeploymentAnnotationsHelp, + metric.Gauge, + "", + wrapDeploymentFunc(func(d *v1.Deployment) *metric.Family { + annotationKeys, annotationValues := createPrometheusLabelKeysValues("annotation", d.Annotations, allowAnnotationsList) + return &metric.Family{ + Metrics: []*metric.Metric{ + { + LabelKeys: annotationKeys, + LabelValues: annotationValues, + Value: 1, + }, + }, + } + }), + ), *generator.NewFamilyGenerator( descDeploymentLabelsName, descDeploymentLabelsHelp, metric.Gauge, "", wrapDeploymentFunc(func(d *v1.Deployment) *metric.Family { - labelKeys, labelValues := createLabelKeysValues(d.Labels, allowLabelsList) + labelKeys, labelValues := createPrometheusLabelKeysValues("label", d.Labels, allowLabelsList) return &metric.Family{ Metrics: []*metric.Metric{ { diff --git a/internal/store/deployment_test.go b/internal/store/deployment_test.go index b05d6b999a..093fc3cf6e 100644 --- a/internal/store/deployment_test.go +++ b/internal/store/deployment_test.go @@ -43,6 +43,8 @@ func TestDeploymentStore(t *testing.T) { // Fixed metadata on type and help text. We prepend this to every expected // output so we only have to modify a single place when doing adjustments. const metadata = ` + # HELP kube_deployment_annotations Kubernetes annotations converted to Prometheus labels. + # TYPE kube_deployment_annotations gauge # HELP kube_deployment_created Unix creation timestamp # TYPE kube_deployment_created gauge # HELP kube_deployment_metadata_generation Sequence number representing a specific generation of the desired state. @@ -74,11 +76,15 @@ func TestDeploymentStore(t *testing.T) { ` cases := []generateMetricsTestCase{ { + AllowAnnotationsList: []string{"company.io/team"}, Obj: &v1.Deployment{ ObjectMeta: metav1.ObjectMeta{ Name: "depl1", CreationTimestamp: metav1.Time{Time: time.Unix(1500000000, 0)}, Namespace: "ns1", + Annotations: map[string]string{ + "company.io/team": "my-brilliant-team", + }, Labels: map[string]string{ "app": "example1", }, @@ -107,6 +113,7 @@ func TestDeploymentStore(t *testing.T) { }, }, Want: metadata + ` + kube_deployment_annotations{annotation_company_io_team="my-brilliant-team",deployment="depl1",namespace="ns1"} 1 kube_deployment_created{deployment="depl1",namespace="ns1"} 1.5e+09 kube_deployment_labels{deployment="depl1",namespace="ns1"} 1 kube_deployment_metadata_generation{deployment="depl1",namespace="ns1"} 21 @@ -163,7 +170,8 @@ func TestDeploymentStore(t *testing.T) { }, }, Want: metadata + ` - kube_deployment_labels{deployment="depl2",namespace="ns2"} 1 + kube_deployment_annotations{deployment="depl2",namespace="ns2"} 1 + kube_deployment_labels{deployment="depl2",namespace="ns2"} 1 kube_deployment_metadata_generation{deployment="depl2",namespace="ns2"} 14 kube_deployment_spec_paused{deployment="depl2",namespace="ns2"} 1 kube_deployment_spec_replicas{deployment="depl2",namespace="ns2"} 5 @@ -189,8 +197,8 @@ func TestDeploymentStore(t *testing.T) { } for i, c := range cases { - c.Func = generator.ComposeMetricGenFuncs(deploymentMetricFamilies(nil)) - c.Headers = generator.ExtractMetricFamilyHeaders(deploymentMetricFamilies(nil)) + c.Func = generator.ComposeMetricGenFuncs(deploymentMetricFamilies(c.AllowAnnotationsList, nil)) + c.Headers = generator.ExtractMetricFamilyHeaders(deploymentMetricFamilies(c.AllowAnnotationsList, nil)) if err := c.run(); err != nil { t.Errorf("unexpected collecting result in %vth run:\n%s", i, err) } diff --git a/internal/store/endpoint.go b/internal/store/endpoint.go index f86ee654a0..7e56c3c516 100644 --- a/internal/store/endpoint.go +++ b/internal/store/endpoint.go @@ -31,12 +31,14 @@ import ( ) var ( + descEndpointAnnotationsName = "kube_endpoint_annotations" + descEndpointAnnotationsHelp = "Kubernetes annotations converted to Prometheus labels." descEndpointLabelsName = "kube_endpoint_labels" descEndpointLabelsHelp = "Kubernetes labels converted to Prometheus labels." descEndpointLabelsDefaultLabels = []string{"namespace", "endpoint"} ) -func endpointMetricFamilies(allowLabelsList []string) []generator.FamilyGenerator { +func endpointMetricFamilies(allowAnnotationsList, allowLabelsList []string) []generator.FamilyGenerator { return []generator.FamilyGenerator{ *generator.NewFamilyGenerator( "kube_endpoint_info", @@ -73,13 +75,31 @@ func endpointMetricFamilies(allowLabelsList []string) []generator.FamilyGenerato } }), ), + *generator.NewFamilyGenerator( + descEndpointAnnotationsName, + descEndpointAnnotationsHelp, + metric.Gauge, + "", + wrapEndpointFunc(func(e *v1.Endpoints) *metric.Family { + annotationKeys, annotationValues := createPrometheusLabelKeysValues("annotation", e.Annotations, allowAnnotationsList) + return &metric.Family{ + Metrics: []*metric.Metric{ + { + LabelKeys: annotationKeys, + LabelValues: annotationValues, + Value: 1, + }, + }, + } + }), + ), *generator.NewFamilyGenerator( descEndpointLabelsName, descEndpointLabelsHelp, metric.Gauge, "", wrapEndpointFunc(func(e *v1.Endpoints) *metric.Family { - labelKeys, labelValues := createLabelKeysValues(e.Labels, allowLabelsList) + labelKeys, labelValues := createPrometheusLabelKeysValues("label", e.Labels, allowLabelsList) return &metric.Family{ Metrics: []*metric.Metric{ { diff --git a/internal/store/endpoint_test.go b/internal/store/endpoint_test.go index b1033ff93f..26f3afc933 100644 --- a/internal/store/endpoint_test.go +++ b/internal/store/endpoint_test.go @@ -30,6 +30,8 @@ func TestEndpointStore(t *testing.T) { // Fixed metadata on type and help text. We prepend this to every expected // output so we only have to modify a single place when doing adjustments. const metadata = ` + # HELP kube_endpoint_annotations Kubernetes annotations converted to Prometheus labels. + # TYPE kube_endpoint_annotations gauge # HELP kube_endpoint_address_available Number of addresses available in endpoint. # TYPE kube_endpoint_address_available gauge # HELP kube_endpoint_address_not_ready Number of addresses not ready in endpoint @@ -84,6 +86,7 @@ func TestEndpointStore(t *testing.T) { }, }, Want: metadata + ` + kube_endpoint_annotations{endpoint="test-endpoint",namespace="default"} 1 kube_endpoint_address_available{endpoint="test-endpoint",namespace="default"} 6 kube_endpoint_address_not_ready{endpoint="test-endpoint",namespace="default"} 6 kube_endpoint_created{endpoint="test-endpoint",namespace="default"} 1.5e+09 @@ -93,8 +96,8 @@ func TestEndpointStore(t *testing.T) { }, } for i, c := range cases { - c.Func = generator.ComposeMetricGenFuncs(endpointMetricFamilies(nil)) - c.Headers = generator.ExtractMetricFamilyHeaders(endpointMetricFamilies(nil)) + c.Func = generator.ComposeMetricGenFuncs(endpointMetricFamilies(nil, nil)) + c.Headers = generator.ExtractMetricFamilyHeaders(endpointMetricFamilies(nil, nil)) if err := c.run(); err != nil { t.Errorf("unexpected collecting result in %vth run:\n%s", i, err) } @@ -109,6 +112,8 @@ func TestEndpointStoreWithLabels(t *testing.T) { # TYPE kube_endpoint_address_available gauge # HELP kube_endpoint_address_not_ready Number of addresses not ready in endpoint # TYPE kube_endpoint_address_not_ready gauge + # HELP kube_endpoint_annotations Kubernetes annotations converted to Prometheus labels. + # TYPE kube_endpoint_annotations gauge # HELP kube_endpoint_created Unix creation timestamp # TYPE kube_endpoint_created gauge # HELP kube_endpoint_info Information about endpoint. @@ -123,6 +128,9 @@ func TestEndpointStoreWithLabels(t *testing.T) { Name: "test-endpoint", CreationTimestamp: metav1.Time{Time: time.Unix(1500000000, 0)}, Namespace: "default", + Annotations: map[string]string{ + "app": "foobar", + }, Labels: map[string]string{ "app": "foobar", }, @@ -161,6 +169,7 @@ func TestEndpointStoreWithLabels(t *testing.T) { Want: metadata + ` kube_endpoint_address_available{endpoint="test-endpoint",namespace="default"} 6 kube_endpoint_address_not_ready{endpoint="test-endpoint",namespace="default"} 6 + kube_endpoint_annotations{endpoint="test-endpoint",annotation_app="foobar",namespace="default"} 1 kube_endpoint_created{endpoint="test-endpoint",namespace="default"} 1.5e+09 kube_endpoint_info{endpoint="test-endpoint",namespace="default"} 1 kube_endpoint_labels{endpoint="test-endpoint",label_app="foobar",namespace="default"} 1 @@ -168,11 +177,14 @@ func TestEndpointStoreWithLabels(t *testing.T) { }, } for i, c := range cases { + allowAnnotations := []string{ + "app", + } allowLabels := []string{ "app", } - c.Func = generator.ComposeMetricGenFuncs(endpointMetricFamilies(allowLabels)) - c.Headers = generator.ExtractMetricFamilyHeaders(endpointMetricFamilies(allowLabels)) + c.Func = generator.ComposeMetricGenFuncs(endpointMetricFamilies(allowAnnotations, allowLabels)) + c.Headers = generator.ExtractMetricFamilyHeaders(endpointMetricFamilies(allowAnnotations, allowLabels)) if err := c.run(); err != nil { t.Errorf("unexpected collecting result in %vth run:\n%s", i, err) } diff --git a/internal/store/horizontalpodautoscaler.go b/internal/store/horizontalpodautoscaler.go index 55af5bcfb0..26bdec00ed 100644 --- a/internal/store/horizontalpodautoscaler.go +++ b/internal/store/horizontalpodautoscaler.go @@ -45,6 +45,8 @@ func (m metricTargetType) String() string { } var ( + descHorizontalPodAutoscalerAnnotationsName = "kube_horizontalpodautoscaler_annotations" + descHorizontalPodAutoscalerAnnotationsHelp = "Kubernetes annotations converted to Prometheus labels." descHorizontalPodAutoscalerLabelsName = "kube_horizontalpodautoscaler_labels" descHorizontalPodAutoscalerLabelsHelp = "Kubernetes labels converted to Prometheus labels." descHorizontalPodAutoscalerLabelsDefaultLabels = []string{"namespace", "horizontalpodautoscaler"} @@ -52,7 +54,7 @@ var ( targetMetricLabels = []string{"metric_name", "metric_target_type"} ) -func hpaMetricFamilies(allowLabelsList []string) []generator.FamilyGenerator { +func hpaMetricFamilies(allowAnnotationsList, allowLabelsList []string) []generator.FamilyGenerator { return []generator.FamilyGenerator{ *generator.NewFamilyGenerator( "kube_horizontalpodautoscaler_metadata_generation", @@ -192,13 +194,31 @@ func hpaMetricFamilies(allowLabelsList []string) []generator.FamilyGenerator { } }), ), + *generator.NewFamilyGenerator( + descHorizontalPodAutoscalerAnnotationsName, + descHorizontalPodAutoscalerAnnotationsHelp, + metric.Gauge, + "", + wrapHPAFunc(func(a *autoscaling.HorizontalPodAutoscaler) *metric.Family { + annotationKeys, annotationValues := createPrometheusLabelKeysValues("annotation", a.Annotations, allowLabelsList) + return &metric.Family{ + Metrics: []*metric.Metric{ + { + LabelKeys: annotationKeys, + LabelValues: annotationValues, + Value: 1, + }, + }, + } + }), + ), *generator.NewFamilyGenerator( descHorizontalPodAutoscalerLabelsName, descHorizontalPodAutoscalerLabelsHelp, metric.Gauge, "", wrapHPAFunc(func(a *autoscaling.HorizontalPodAutoscaler) *metric.Family { - labelKeys, labelValues := createLabelKeysValues(a.Labels, allowLabelsList) + labelKeys, labelValues := createPrometheusLabelKeysValues("label", a.Labels, allowLabelsList) return &metric.Family{ Metrics: []*metric.Metric{ { diff --git a/internal/store/horizontalpodautoscaler_test.go b/internal/store/horizontalpodautoscaler_test.go index 09e20ba468..a26e849f7a 100644 --- a/internal/store/horizontalpodautoscaler_test.go +++ b/internal/store/horizontalpodautoscaler_test.go @@ -309,8 +309,8 @@ func TestHPAStore(t *testing.T) { }, } for i, c := range cases { - c.Func = generator.ComposeMetricGenFuncs(hpaMetricFamilies(nil)) - c.Headers = generator.ExtractMetricFamilyHeaders(hpaMetricFamilies(nil)) + c.Func = generator.ComposeMetricGenFuncs(hpaMetricFamilies(nil, nil)) + c.Headers = generator.ExtractMetricFamilyHeaders(hpaMetricFamilies(nil, nil)) if err := c.run(); err != nil { t.Errorf("unexpected collecting result in %vth run:\n%s", i, err) } diff --git a/internal/store/ingress.go b/internal/store/ingress.go index 85c0b001ee..c05f16f7ce 100644 --- a/internal/store/ingress.go +++ b/internal/store/ingress.go @@ -32,12 +32,14 @@ import ( ) var ( + descIngressAnnotationsName = "kube_ingress_annotations" + descIngressAnnotationsHelp = "Kubernetes annotations converted to Prometheus labels." descIngressLabelsName = "kube_ingress_labels" descIngressLabelsHelp = "Kubernetes labels converted to Prometheus labels." descIngressLabelsDefaultLabels = []string{"namespace", "ingress"} ) -func ingressMetricFamilies(allowLabelsList []string) []generator.FamilyGenerator { +func ingressMetricFamilies(allowAnnotationsList, allowLabelsList []string) []generator.FamilyGenerator { return []generator.FamilyGenerator{ *generator.NewFamilyGenerator( "kube_ingress_info", @@ -53,13 +55,31 @@ func ingressMetricFamilies(allowLabelsList []string) []generator.FamilyGenerator }} }), ), + *generator.NewFamilyGenerator( + descIngressAnnotationsName, + descIngressAnnotationsHelp, + metric.Gauge, + "", + wrapIngressFunc(func(i *networkingv1.Ingress) *metric.Family { + annotationKeys, annotationValues := createPrometheusLabelKeysValues("annotation", i.Annotations, allowLabelsList) + return &metric.Family{ + Metrics: []*metric.Metric{ + { + LabelKeys: annotationKeys, + LabelValues: annotationValues, + Value: 1, + }, + }} + + }), + ), *generator.NewFamilyGenerator( descIngressLabelsName, descIngressLabelsHelp, metric.Gauge, "", wrapIngressFunc(func(i *networkingv1.Ingress) *metric.Family { - labelKeys, labelValues := createLabelKeysValues(i.Labels, allowLabelsList) + labelKeys, labelValues := createPrometheusLabelKeysValues("label", i.Labels, allowLabelsList) return &metric.Family{ Metrics: []*metric.Metric{ { diff --git a/internal/store/ingress_test.go b/internal/store/ingress_test.go index 790c04807d..e4871943ab 100644 --- a/internal/store/ingress_test.go +++ b/internal/store/ingress_test.go @@ -169,8 +169,8 @@ func TestIngressStore(t *testing.T) { }, } for i, c := range cases { - c.Func = generator.ComposeMetricGenFuncs(ingressMetricFamilies(nil)) - c.Headers = generator.ExtractMetricFamilyHeaders(ingressMetricFamilies(nil)) + c.Func = generator.ComposeMetricGenFuncs(ingressMetricFamilies(nil, nil)) + c.Headers = generator.ExtractMetricFamilyHeaders(ingressMetricFamilies(nil, nil)) if err := c.run(); err != nil { t.Errorf("unexpected collecting result in %vth run:\n%s", i, err) } diff --git a/internal/store/job.go b/internal/store/job.go index 5cf2ab74b6..472954c41d 100644 --- a/internal/store/job.go +++ b/internal/store/job.go @@ -32,21 +32,41 @@ import ( ) var ( + descJobAnnotationsName = "kube_job_annotations" + descJobAnnotationsHelp = "Kubernetes annotations converted to Prometheus labels." descJobLabelsName = "kube_job_labels" descJobLabelsHelp = "Kubernetes labels converted to Prometheus labels." descJobLabelsDefaultLabels = []string{"namespace", "job_name"} jobFailureReasons = []string{"BackoffLimitExceeded", "DeadLineExceeded", "Evicted"} ) -func jobMetricFamilies(allowLabelsList []string) []generator.FamilyGenerator { +func jobMetricFamilies(allowAnnotationsList, allowLabelsList []string) []generator.FamilyGenerator { return []generator.FamilyGenerator{ + *generator.NewFamilyGenerator( + descJobAnnotationsName, + descJobAnnotationsHelp, + metric.Gauge, + "", + wrapJobFunc(func(j *v1batch.Job) *metric.Family { + annotationKeys, annotationValues := createPrometheusLabelKeysValues("annotation", j.Annotations, allowAnnotationsList) + return &metric.Family{ + Metrics: []*metric.Metric{ + { + LabelKeys: annotationKeys, + LabelValues: annotationValues, + Value: 1, + }, + }, + } + }), + ), *generator.NewFamilyGenerator( descJobLabelsName, descJobLabelsHelp, metric.Gauge, "", wrapJobFunc(func(j *v1batch.Job) *metric.Family { - labelKeys, labelValues := createLabelKeysValues(j.Labels, allowLabelsList) + labelKeys, labelValues := createPrometheusLabelKeysValues("label", j.Labels, allowLabelsList) return &metric.Family{ Metrics: []*metric.Metric{ { diff --git a/internal/store/job_test.go b/internal/store/job_test.go index c81de4f15a..3cfb68ef70 100644 --- a/internal/store/job_test.go +++ b/internal/store/job_test.go @@ -48,6 +48,8 @@ func TestJobStore(t *testing.T) { // Fixed metadata on type and help text. We prepend this to every expected // output so we only have to modify a single place when doing adjustments. const metadata = ` + # HELP kube_job_annotations Kubernetes annotations converted to Prometheus labels. + # TYPE kube_job_annotations gauge # HELP kube_job_created Unix creation timestamp # TYPE kube_job_created gauge # HELP kube_job_owner Information about the Job's owner. @@ -110,6 +112,7 @@ func TestJobStore(t *testing.T) { }, }, Want: metadata + ` + kube_job_annotations{job_name="RunningJob1",namespace="ns1"} 1 kube_job_owner{job_name="RunningJob1",namespace="ns1",owner_is_controller="true",owner_kind="CronJob",owner_name="cronjob-name"} 1 kube_job_created{job_name="RunningJob1",namespace="ns1"} 1.5e+09 kube_job_info{job_name="RunningJob1",namespace="ns1"} 1 @@ -150,6 +153,7 @@ func TestJobStore(t *testing.T) { }, }, Want: metadata + ` + kube_job_annotations{job_name="SuccessfulJob1",namespace="ns1"} 1 kube_job_owner{job_name="SuccessfulJob1",namespace="ns1",owner_is_controller="",owner_kind="",owner_name=""} 1 kube_job_complete{condition="false",job_name="SuccessfulJob1",namespace="ns1"} 0 kube_job_complete{condition="true",job_name="SuccessfulJob1",namespace="ns1"} 1 @@ -193,6 +197,7 @@ func TestJobStore(t *testing.T) { }, }, Want: metadata + ` + kube_job_annotations{job_name="FailedJob1",namespace="ns1"} 1 kube_job_owner{job_name="FailedJob1",namespace="ns1",owner_is_controller="",owner_kind="",owner_name=""} 1 kube_job_failed{condition="false",job_name="FailedJob1",namespace="ns1"} 0 kube_job_failed{condition="true",job_name="FailedJob1",namespace="ns1"} 1 @@ -242,6 +247,7 @@ func TestJobStore(t *testing.T) { kube_job_complete{condition="false",job_name="SuccessfulJob2NoActiveDeadlineSeconds",namespace="ns1"} 0 kube_job_complete{condition="true",job_name="SuccessfulJob2NoActiveDeadlineSeconds",namespace="ns1"} 1 + kube_job_annotations{job_name="SuccessfulJob2NoActiveDeadlineSeconds",namespace="ns1"} 1 kube_job_complete{condition="unknown",job_name="SuccessfulJob2NoActiveDeadlineSeconds",namespace="ns1"} 0 kube_job_info{job_name="SuccessfulJob2NoActiveDeadlineSeconds",namespace="ns1"} 1 kube_job_labels{job_name="SuccessfulJob2NoActiveDeadlineSeconds",namespace="ns1"} 1 @@ -256,8 +262,8 @@ func TestJobStore(t *testing.T) { }, } for i, c := range cases { - c.Func = generator.ComposeMetricGenFuncs(jobMetricFamilies(nil)) - c.Headers = generator.ExtractMetricFamilyHeaders(jobMetricFamilies(nil)) + c.Func = generator.ComposeMetricGenFuncs(jobMetricFamilies(nil, nil)) + c.Headers = generator.ExtractMetricFamilyHeaders(jobMetricFamilies(nil, nil)) if err := c.run(); err != nil { t.Errorf("unexpected collecting result in %vth run:\n%s", i, err) } diff --git a/internal/store/namespace.go b/internal/store/namespace.go index c1e994f543..aa6b5d5114 100644 --- a/internal/store/namespace.go +++ b/internal/store/namespace.go @@ -31,12 +31,14 @@ import ( ) var ( + descNamespaceAnnotationsName = "kube_namespace_annotations" + descNamespaceAnnotationsHelp = "Kubernetes annotations converted to Prometheus labels." descNamespaceLabelsName = "kube_namespace_labels" descNamespaceLabelsHelp = "Kubernetes labels converted to Prometheus labels." descNamespaceLabelsDefaultLabels = []string{"namespace"} ) -func namespaceMetricFamilies(allowLabelsList []string) []generator.FamilyGenerator { +func namespaceMetricFamilies(allowAnnotationsList, allowLabelsList []string) []generator.FamilyGenerator { return []generator.FamilyGenerator{ *generator.NewFamilyGenerator( "kube_namespace_created", @@ -56,13 +58,31 @@ func namespaceMetricFamilies(allowLabelsList []string) []generator.FamilyGenerat } }), ), + *generator.NewFamilyGenerator( + descNamespaceAnnotationsName, + descNamespaceAnnotationsHelp, + metric.Gauge, + "", + wrapNamespaceFunc(func(n *v1.Namespace) *metric.Family { + annotationKeys, annotationValues := createPrometheusLabelKeysValues("annotation", n.Annotations, allowAnnotationsList) + return &metric.Family{ + Metrics: []*metric.Metric{ + { + LabelKeys: annotationKeys, + LabelValues: annotationValues, + Value: 1, + }, + }, + } + }), + ), *generator.NewFamilyGenerator( descNamespaceLabelsName, descNamespaceLabelsHelp, metric.Gauge, "", wrapNamespaceFunc(func(n *v1.Namespace) *metric.Family { - labelKeys, labelValues := createLabelKeysValues(n.Labels, allowLabelsList) + labelKeys, labelValues := createPrometheusLabelKeysValues("label", n.Labels, allowLabelsList) return &metric.Family{ Metrics: []*metric.Metric{ { diff --git a/internal/store/namespace_test.go b/internal/store/namespace_test.go index 1849ff665e..f550ed0e1e 100644 --- a/internal/store/namespace_test.go +++ b/internal/store/namespace_test.go @@ -30,6 +30,8 @@ func TestNamespaceStore(t *testing.T) { // Fixed metadata on type and help text. We prepend this to every expected // output so we only have to modify a single place when doing adjustments. const metadata = ` + # HELP kube_namespace_annotations Kubernetes annotations converted to Prometheus labels. + # TYPE kube_namespace_annotations gauge # HELP kube_namespace_created Unix creation timestamp # TYPE kube_namespace_created gauge # HELP kube_namespace_labels Kubernetes labels converted to Prometheus labels. @@ -54,6 +56,7 @@ func TestNamespaceStore(t *testing.T) { }, }, Want: metadata + ` + kube_namespace_annotations{namespace="nsActiveTest"} 1 kube_namespace_labels{namespace="nsActiveTest"} 1 kube_namespace_status_phase{namespace="nsActiveTest",phase="Active"} 1 kube_namespace_status_phase{namespace="nsActiveTest",phase="Terminating"} 0 @@ -72,6 +75,7 @@ func TestNamespaceStore(t *testing.T) { }, }, Want: metadata + ` + kube_namespace_annotations{namespace="nsTerminateTest"} 1 kube_namespace_labels{namespace="nsTerminateTest"} 1 kube_namespace_status_phase{namespace="nsTerminateTest",phase="Active"} 0 kube_namespace_status_phase{namespace="nsTerminateTest",phase="Terminating"} 1 @@ -95,6 +99,7 @@ func TestNamespaceStore(t *testing.T) { }, }, Want: metadata + ` + kube_namespace_annotations{namespace="nsTerminateWithConditionTest"} 1 kube_namespace_labels{namespace="nsTerminateWithConditionTest"} 1 kube_namespace_status_phase{namespace="nsTerminateWithConditionTest",phase="Active"} 0 kube_namespace_status_phase{namespace="nsTerminateWithConditionTest",phase="Terminating"} 1 @@ -127,6 +132,7 @@ func TestNamespaceStore(t *testing.T) { }, }, Want: metadata + ` + kube_namespace_annotations{namespace="ns1"} 1 kube_namespace_created{namespace="ns1"} 1.5e+09 kube_namespace_labels{namespace="ns1"} 1 kube_namespace_status_phase{namespace="ns1",phase="Active"} 1 @@ -150,6 +156,7 @@ func TestNamespaceStore(t *testing.T) { }, }, Want: metadata + ` + kube_namespace_annotations{namespace="ns2"} 1 kube_namespace_labels{namespace="ns2"} 1 kube_namespace_status_phase{namespace="ns2",phase="Active"} 1 kube_namespace_status_phase{namespace="ns2",phase="Terminating"} 0 @@ -158,8 +165,8 @@ func TestNamespaceStore(t *testing.T) { } for i, c := range cases { - c.Func = generator.ComposeMetricGenFuncs(namespaceMetricFamilies(nil)) - c.Headers = generator.ExtractMetricFamilyHeaders(namespaceMetricFamilies(nil)) + c.Func = generator.ComposeMetricGenFuncs(namespaceMetricFamilies(nil, nil)) + c.Headers = generator.ExtractMetricFamilyHeaders(namespaceMetricFamilies(nil, nil)) if err := c.run(); err != nil { t.Errorf("unexpected collecting result in %vth run:\n%s", i, err) } diff --git a/internal/store/networkpolicy.go b/internal/store/networkpolicy.go index 96d095299b..7798b0d98e 100644 --- a/internal/store/networkpolicy.go +++ b/internal/store/networkpolicy.go @@ -31,10 +31,14 @@ import ( ) var ( + descNetworkPolicyAnnotationsName = "kube_networkpolicy_annotations" + descNetworkPolicyAnnotationsHelp = "Kubernetes annotations converted to Prometheus labels." + descNetworkPolicyLabelsName = "kube_networkpolicy_labels" + descNetworkPolicyLabelsHelp = "Kubernetes labels converted to Prometheus labels." descNetworkPolicyLabelsDefaultLabels = []string{"namespace", "networkpolicy"} ) -func networkPolicyMetricFamilies(allowLabelsList []string) []generator.FamilyGenerator { +func networkPolicyMetricFamilies(allowAnnotationsList, allowLabelsList []string) []generator.FamilyGenerator { return []generator.FamilyGenerator{ *generator.NewFamilyGenerator( "kube_networkpolicy_created", @@ -54,12 +58,30 @@ func networkPolicyMetricFamilies(allowLabelsList []string) []generator.FamilyGen }), ), *generator.NewFamilyGenerator( - "kube_networkpolicy_labels", - "Kubernetes labels converted to Prometheus labels", + descNetworkPolicyAnnotationsName, + descNetworkPolicyAnnotationsHelp, metric.Gauge, "", wrapNetworkPolicyFunc(func(n *networkingv1.NetworkPolicy) *metric.Family { - labelKeys, labelValues := createLabelKeysValues(n.Labels, allowLabelsList) + annotationKeys, annotationValues := createPrometheusLabelKeysValues("annotation", n.Annotations, allowAnnotationsList) + return &metric.Family{ + Metrics: []*metric.Metric{ + { + LabelKeys: annotationKeys, + LabelValues: annotationValues, + Value: 1, + }, + }, + } + }), + ), + *generator.NewFamilyGenerator( + descNetworkPolicyLabelsName, + descNetworkPolicyLabelsHelp, + metric.Gauge, + "", + wrapNetworkPolicyFunc(func(n *networkingv1.NetworkPolicy) *metric.Family { + labelKeys, labelValues := createPrometheusLabelKeysValues("label", n.Labels, allowLabelsList) return &metric.Family{ Metrics: []*metric.Metric{ { diff --git a/internal/store/networkpolicy_test.go b/internal/store/networkpolicy_test.go index 5a5ef2bb03..22b693c081 100644 --- a/internal/store/networkpolicy_test.go +++ b/internal/store/networkpolicy_test.go @@ -68,7 +68,7 @@ func TestNetworkPolicyStore(t *testing.T) { }, } for i, c := range cases { - c.Func = generator.ComposeMetricGenFuncs(networkPolicyMetricFamilies(nil)) + c.Func = generator.ComposeMetricGenFuncs(networkPolicyMetricFamilies(nil, nil)) if err := c.run(); err != nil { t.Errorf("unexpected collecting result in %dth run:\n%s", i, err) } diff --git a/internal/store/node.go b/internal/store/node.go index b183e28748..10593ba131 100644 --- a/internal/store/node.go +++ b/internal/store/node.go @@ -33,15 +33,18 @@ import ( ) var ( + descNodeAnnotationsName = "kube_node_annotations" + descNodeAnnotationsHelp = "Kubernetes annotations converted to Prometheus labels." descNodeLabelsName = "kube_node_labels" descNodeLabelsHelp = "Kubernetes labels converted to Prometheus labels." descNodeLabelsDefaultLabels = []string{"node"} ) -func nodeMetricFamilies(allowLabelsList []string) []generator.FamilyGenerator { +func nodeMetricFamilies(allowAnnotationsList, allowLabelsList []string) []generator.FamilyGenerator { return []generator.FamilyGenerator{ createNodeCreatedFamilyGenerator(), createNodeInfoFamilyGenerator(), + createNodeAnnotationsGenerator(allowAnnotationsList), createNodeLabelsGenerator(allowLabelsList), createNodeRoleFamilyGenerator(), createNodeSpecTaintFamilyGenerator(), @@ -125,6 +128,27 @@ func createNodeInfoFamilyGenerator() generator.FamilyGenerator { ) } +func createNodeAnnotationsGenerator(allowAnnotationsList []string) generator.FamilyGenerator { + return *generator.NewFamilyGenerator( + descNodeAnnotationsName, + descNodeAnnotationsHelp, + metric.Gauge, + "", + wrapNodeFunc(func(n *v1.Node) *metric.Family { + annotationKeys, annotationValues := createPrometheusLabelKeysValues("annotation", n.Annotations, allowAnnotationsList) + return &metric.Family{ + Metrics: []*metric.Metric{ + { + LabelKeys: annotationKeys, + LabelValues: annotationValues, + Value: 1, + }, + }, + } + }), + ) +} + func createNodeLabelsGenerator(allowLabelsList []string) generator.FamilyGenerator { return *generator.NewFamilyGenerator( descNodeLabelsName, @@ -132,7 +156,7 @@ func createNodeLabelsGenerator(allowLabelsList []string) generator.FamilyGenerat metric.Gauge, "", wrapNodeFunc(func(n *v1.Node) *metric.Family { - labelKeys, labelValues := createLabelKeysValues(n.Labels, allowLabelsList) + labelKeys, labelValues := createPrometheusLabelKeysValues("label", n.Labels, allowLabelsList) return &metric.Family{ Metrics: []*metric.Metric{ { diff --git a/internal/store/node_test.go b/internal/store/node_test.go index 4da58f475f..2490720d15 100644 --- a/internal/store/node_test.go +++ b/internal/store/node_test.go @@ -278,8 +278,8 @@ func TestNodeStore(t *testing.T) { }, } for i, c := range cases { - c.Func = generator.ComposeMetricGenFuncs(nodeMetricFamilies(nil)) - c.Headers = generator.ExtractMetricFamilyHeaders(nodeMetricFamilies(nil)) + c.Func = generator.ComposeMetricGenFuncs(nodeMetricFamilies(nil, nil)) + c.Headers = generator.ExtractMetricFamilyHeaders(nodeMetricFamilies(nil, nil)) if err := c.run(); err != nil { t.Errorf("unexpected collecting result in %vth run:\n%s", i, err) } diff --git a/internal/store/persistentvolume.go b/internal/store/persistentvolume.go index cfa74943de..1d5b7e8704 100644 --- a/internal/store/persistentvolume.go +++ b/internal/store/persistentvolume.go @@ -36,12 +36,14 @@ var ( descPersistentVolumeClaimRefHelp = "Information about the Persitant Volume Claim Reference." descPersistentVolumeClaimRefDefaultLabels = []string{"persistentvolume"} + descPersistentVolumeAnnotationsName = "kube_persistentvolume_annotations" + descPersistentVolumeAnnotationsHelp = "Kubernetes annotations converted to Prometheus labels." descPersistentVolumeLabelsName = "kube_persistentvolume_labels" descPersistentVolumeLabelsHelp = "Kubernetes labels converted to Prometheus labels." descPersistentVolumeLabelsDefaultLabels = []string{"persistentvolume"} ) -func persistentVolumeMetricFamilies(allowLabelsList []string) []generator.FamilyGenerator { +func persistentVolumeMetricFamilies(allowAnnotationsList, allowLabelsList []string) []generator.FamilyGenerator { return []generator.FamilyGenerator{ *generator.NewFamilyGenerator( descPersistentVolumeClaimRefName, @@ -73,13 +75,31 @@ func persistentVolumeMetricFamilies(allowLabelsList []string) []generator.Family } }), ), + *generator.NewFamilyGenerator( + descPersistentVolumeAnnotationsName, + descPersistentVolumeAnnotationsHelp, + metric.Gauge, + "", + wrapPersistentVolumeFunc(func(p *v1.PersistentVolume) *metric.Family { + annotationKeys, annotationValues := createPrometheusLabelKeysValues("annotation", p.Annotations, allowAnnotationsList) + return &metric.Family{ + Metrics: []*metric.Metric{ + { + LabelKeys: annotationKeys, + LabelValues: annotationValues, + Value: 1, + }, + }, + } + }), + ), *generator.NewFamilyGenerator( descPersistentVolumeLabelsName, descPersistentVolumeLabelsHelp, metric.Gauge, "", wrapPersistentVolumeFunc(func(p *v1.PersistentVolume) *metric.Family { - labelKeys, labelValues := createLabelKeysValues(p.Labels, allowLabelsList) + labelKeys, labelValues := createPrometheusLabelKeysValues("label", p.Labels, allowLabelsList) return &metric.Family{ Metrics: []*metric.Metric{ { diff --git a/internal/store/persistentvolume_test.go b/internal/store/persistentvolume_test.go index 82b40c62c9..c9b3e61f83 100644 --- a/internal/store/persistentvolume_test.go +++ b/internal/store/persistentvolume_test.go @@ -482,8 +482,8 @@ func TestPersistentVolumeStore(t *testing.T) { }, } for i, c := range cases { - c.Func = generator.ComposeMetricGenFuncs(persistentVolumeMetricFamilies(nil)) - c.Headers = generator.ExtractMetricFamilyHeaders(persistentVolumeMetricFamilies(nil)) + c.Func = generator.ComposeMetricGenFuncs(persistentVolumeMetricFamilies(nil, nil)) + c.Headers = generator.ExtractMetricFamilyHeaders(persistentVolumeMetricFamilies(nil, nil)) if err := c.run(); err != nil { t.Errorf("unexpected collecting result in %vth run:\n%s", i, err) } diff --git a/internal/store/persistentvolumeclaim.go b/internal/store/persistentvolumeclaim.go index e68928898c..c29920c831 100644 --- a/internal/store/persistentvolumeclaim.go +++ b/internal/store/persistentvolumeclaim.go @@ -31,12 +31,14 @@ import ( ) var ( + descPersistentVolumeClaimAnnotationsName = "kube_persistentvolumeclaim_annotations" + descPersistentVolumeClaimAnnotationsHelp = "Kubernetes annotations converted to Prometheus labels." descPersistentVolumeClaimLabelsName = "kube_persistentvolumeclaim_labels" descPersistentVolumeClaimLabelsHelp = "Kubernetes labels converted to Prometheus labels." descPersistentVolumeClaimLabelsDefaultLabels = []string{"namespace", "persistentvolumeclaim"} ) -func persistentVolumeClaimMetricFamilies(allowLabelsList []string) []generator.FamilyGenerator { +func persistentVolumeClaimMetricFamilies(allowAnnotationsList, allowLabelsList []string) []generator.FamilyGenerator { return []generator.FamilyGenerator{ *generator.NewFamilyGenerator( descPersistentVolumeClaimLabelsName, @@ -44,12 +46,12 @@ func persistentVolumeClaimMetricFamilies(allowLabelsList []string) []generator.F metric.Gauge, "", wrapPersistentVolumeClaimFunc(func(p *v1.PersistentVolumeClaim) *metric.Family { - labelKeys, labelValues := createLabelKeysValues(p.Labels, allowLabelsList) + annotationKeys, annotationValues := createPrometheusLabelKeysValues("annotation", p.Annotations, allowAnnotationsList) return &metric.Family{ Metrics: []*metric.Metric{ { - LabelKeys: labelKeys, - LabelValues: labelValues, + LabelKeys: annotationKeys, + LabelValues: annotationValues, Value: 1, }, }, diff --git a/internal/store/persistentvolumeclaim_test.go b/internal/store/persistentvolumeclaim_test.go index 7a87986553..f2369abb8d 100644 --- a/internal/store/persistentvolumeclaim_test.go +++ b/internal/store/persistentvolumeclaim_test.go @@ -183,8 +183,8 @@ func TestPersistentVolumeClaimStore(t *testing.T) { }, } for i, c := range cases { - c.Func = generator.ComposeMetricGenFuncs(persistentVolumeClaimMetricFamilies(nil)) - c.Headers = generator.ExtractMetricFamilyHeaders(persistentVolumeClaimMetricFamilies(nil)) + c.Func = generator.ComposeMetricGenFuncs(persistentVolumeClaimMetricFamilies(nil, nil)) + c.Headers = generator.ExtractMetricFamilyHeaders(persistentVolumeClaimMetricFamilies(nil, nil)) if err := c.run(); err != nil { t.Errorf("unexpected collecting result in %vth run:\n%s", i, err) } diff --git a/internal/store/pod.go b/internal/store/pod.go index e427478b14..48620a3dd5 100644 --- a/internal/store/pod.go +++ b/internal/store/pod.go @@ -37,7 +37,7 @@ var ( podStatusReasons = []string{"NodeLost", "Evicted", "UnexpectedAdmissionError"} ) -func podMetricFamilies(allowLabelsList []string) []generator.FamilyGenerator { +func podMetricFamilies(allowAnnotationsList, allowLabelsList []string) []generator.FamilyGenerator { return []generator.FamilyGenerator{ createPodCompletionTimeFamilyGenerator(), createPodContainerInfoFamilyGenerator(), @@ -74,6 +74,7 @@ func podMetricFamilies(allowLabelsList []string) []generator.FamilyGenerator { createPodInitContainerStatusTerminatedReasonFamilyGenerator(), createPodInitContainerStatusWaitingFamilyGenerator(), createPodInitContainerStatusWaitingReasonFamilyGenerator(), + createPodAnnotationsGenerator(allowAnnotationsList), createPodLabelsGenerator(allowLabelsList), createPodOverheadCPUCoresFamilyGenerator(), createPodOverheadMemoryBytesFamilyGenerator(), @@ -1131,6 +1132,26 @@ func createPodInitContainerStatusWaitingReasonFamilyGenerator() generator.Family ) } +func createPodAnnotationsGenerator(allowAnnotations []string) generator.FamilyGenerator { + return *generator.NewFamilyGenerator( + "kube_pod_annotations", + "Kubernetes annotations converted to Prometheus labels.", + metric.Gauge, + "", + wrapPodFunc(func(p *v1.Pod) *metric.Family { + annotationKeys, annotationValues := createPrometheusLabelKeysValues("annotation", p.Annotations, allowAnnotations) + m := metric.Metric{ + LabelKeys: annotationKeys, + LabelValues: annotationValues, + Value: 1, + } + return &metric.Family{ + Metrics: []*metric.Metric{&m}, + } + }), + ) +} + func createPodLabelsGenerator(allowLabelsList []string) generator.FamilyGenerator { return *generator.NewFamilyGenerator( "kube_pod_labels", @@ -1138,7 +1159,7 @@ func createPodLabelsGenerator(allowLabelsList []string) generator.FamilyGenerato metric.Gauge, "", wrapPodFunc(func(p *v1.Pod) *metric.Family { - labelKeys, labelValues := createLabelKeysValues(p.Labels, allowLabelsList) + labelKeys, labelValues := createPrometheusLabelKeysValues("label", p.Labels, allowLabelsList) m := metric.Metric{ LabelKeys: labelKeys, LabelValues: labelValues, diff --git a/internal/store/pod_test.go b/internal/store/pod_test.go index 7bd56196c9..1e7681bd84 100644 --- a/internal/store/pod_test.go +++ b/internal/store/pod_test.go @@ -1594,11 +1594,33 @@ func TestPodStore(t *testing.T) { "kube_pod_labels", }, }, + { + Obj: &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pod1", + Namespace: "ns1", + UID: "uid1", + Annotations: map[string]string{ + "app": "example", + }, + }, + Spec: v1.PodSpec{}, + }, + AllowAnnotationsList: []string{options.LabelWildcard}, + Want: ` + # HELP kube_pod_annotations Kubernetes annotations converted to Prometheus labels. + # TYPE kube_pod_annotations gauge + kube_pod_annotations{annotation_app="example",namespace="ns1",pod="pod1",uid="uid1"} 1 + `, + MetricNames: []string{ + "kube_pod_annotations", + }, + }, } for i, c := range cases { - c.Func = generator.ComposeMetricGenFuncs(podMetricFamilies(c.AllowLabelsList)) - c.Headers = generator.ExtractMetricFamilyHeaders(podMetricFamilies(c.AllowLabelsList)) + c.Func = generator.ComposeMetricGenFuncs(podMetricFamilies(c.AllowAnnotationsList, c.AllowLabelsList)) + c.Headers = generator.ExtractMetricFamilyHeaders(podMetricFamilies(c.AllowAnnotationsList, c.AllowLabelsList)) if err := c.run(); err != nil { t.Errorf("unexpected collecting result in %vth run:\n%s", i, err) } @@ -1608,7 +1630,7 @@ func TestPodStore(t *testing.T) { func BenchmarkPodStore(b *testing.B) { b.ReportAllocs() - f := generator.ComposeMetricGenFuncs(podMetricFamilies(nil)) + f := generator.ComposeMetricGenFuncs(podMetricFamilies(nil, nil)) pod := &v1.Pod{ ObjectMeta: metav1.ObjectMeta{ @@ -1670,7 +1692,7 @@ func BenchmarkPodStore(b *testing.B) { }, } - expectedFamilies := 50 + expectedFamilies := 51 for n := 0; n < b.N; n++ { families := f(pod) if len(families) != expectedFamilies { diff --git a/internal/store/replicaset.go b/internal/store/replicaset.go index 6c8a259365..027cd62772 100644 --- a/internal/store/replicaset.go +++ b/internal/store/replicaset.go @@ -33,11 +33,13 @@ import ( var ( descReplicaSetLabelsDefaultLabels = []string{"namespace", "replicaset"} + descReplicaSetAnnotationsName = "kube_replicaset_annotations" + descReplicaSetAnnotationsHelp = "Kubernetes annotations converted to Prometheus labels." descReplicaSetLabelsName = "kube_replicaset_labels" descReplicaSetLabelsHelp = "Kubernetes labels converted to Prometheus labels." ) -func replicaSetMetricFamilies(allowLabelsList []string) []generator.FamilyGenerator { +func replicaSetMetricFamilies(allowAnnotationsList, allowLabelsList []string) []generator.FamilyGenerator { return []generator.FamilyGenerator{ *generator.NewFamilyGenerator( "kube_replicaset_created", @@ -197,13 +199,31 @@ func replicaSetMetricFamilies(allowLabelsList []string) []generator.FamilyGenera } }), ), + *generator.NewFamilyGenerator( + descReplicaSetAnnotationsName, + descReplicaSetAnnotationsHelp, + metric.Gauge, + "", + wrapReplicaSetFunc(func(r *v1.ReplicaSet) *metric.Family { + annotationKeys, annotationValues := createPrometheusLabelKeysValues("annotation", r.Annotations, allowAnnotationsList) + return &metric.Family{ + Metrics: []*metric.Metric{ + { + LabelKeys: annotationKeys, + LabelValues: annotationValues, + Value: 1, + }, + }, + } + }), + ), *generator.NewFamilyGenerator( descReplicaSetLabelsName, descReplicaSetLabelsHelp, metric.Gauge, "", wrapReplicaSetFunc(func(r *v1.ReplicaSet) *metric.Family { - labelKeys, labelValues := createLabelKeysValues(r.Labels, allowLabelsList) + labelKeys, labelValues := createPrometheusLabelKeysValues("label", r.Labels, allowLabelsList) return &metric.Family{ Metrics: []*metric.Metric{ { diff --git a/internal/store/replicaset_test.go b/internal/store/replicaset_test.go index 3972fb8b25..7735c95308 100644 --- a/internal/store/replicaset_test.go +++ b/internal/store/replicaset_test.go @@ -36,9 +36,11 @@ func TestReplicaSetStore(t *testing.T) { // Fixed metadata on type and help text. We prepend this to every expected // output so we only have to modify a single place when doing adjustments. const metadata = ` + # HELP kube_replicaset_annotations Kubernetes annotations converted to Prometheus labels. + # TYPE kube_replicaset_annotations gauge # HELP kube_replicaset_created Unix creation timestamp # TYPE kube_replicaset_created gauge - # HELP kube_replicaset_metadata_generation Sequence number representing a specific generation of the desired state. + # HELP kube_replicaset_metadata_generation Sequence number representing a specific generation of the desired state. # TYPE kube_replicaset_metadata_generation gauge # HELP kube_replicaset_status_replicas The number of replicas per ReplicaSet. # TYPE kube_replicaset_status_replicas gauge @@ -85,6 +87,7 @@ func TestReplicaSetStore(t *testing.T) { }, }, Want: metadata + ` + kube_replicaset_annotations{replicaset="rs1",namespace="ns1"} 1 kube_replicaset_labels{replicaset="rs1",namespace="ns1"} 1 kube_replicaset_created{namespace="ns1",replicaset="rs1"} 1.5e+09 kube_replicaset_metadata_generation{namespace="ns1",replicaset="rs1"} 21 @@ -118,6 +121,7 @@ func TestReplicaSetStore(t *testing.T) { }, }, Want: metadata + ` + kube_replicaset_annotations{replicaset="rs2",namespace="ns2"} 1 kube_replicaset_labels{replicaset="rs2",namespace="ns2"} 1 kube_replicaset_metadata_generation{namespace="ns2",replicaset="rs2"} 14 kube_replicaset_status_replicas{namespace="ns2",replicaset="rs2"} 0 @@ -130,8 +134,8 @@ func TestReplicaSetStore(t *testing.T) { }, } for i, c := range cases { - c.Func = generator.ComposeMetricGenFuncs(replicaSetMetricFamilies(nil)) - c.Headers = generator.ExtractMetricFamilyHeaders(replicaSetMetricFamilies(nil)) + c.Func = generator.ComposeMetricGenFuncs(replicaSetMetricFamilies(nil, nil)) + c.Headers = generator.ExtractMetricFamilyHeaders(replicaSetMetricFamilies(nil, nil)) if err := c.run(); err != nil { t.Errorf("unexpected collecting result in %vth run:\n%s", i, err) } diff --git a/internal/store/secret.go b/internal/store/secret.go index 9b1599798e..f63290a1a0 100644 --- a/internal/store/secret.go +++ b/internal/store/secret.go @@ -31,12 +31,14 @@ import ( ) var ( + descSecretAnnotationsName = "kube_secret_annotations" + descSecretAnnotationsHelp = "Kubernetes annotations converted to Prometheus labels." descSecretLabelsName = "kube_secret_labels" descSecretLabelsHelp = "Kubernetes labels converted to Prometheus labels." descSecretLabelsDefaultLabels = []string{"namespace", "secret"} ) -func secretMetricFamilies(allowLabelsList []string) []generator.FamilyGenerator { +func secretMetricFamilies(allowAnnotationsList, allowLabelsList []string) []generator.FamilyGenerator { return []generator.FamilyGenerator{ *generator.NewFamilyGenerator( "kube_secret_info", @@ -70,13 +72,32 @@ func secretMetricFamilies(allowLabelsList []string) []generator.FamilyGenerator } }), ), + *generator.NewFamilyGenerator( + descSecretAnnotationsName, + descSecretAnnotationsHelp, + metric.Gauge, + "", + wrapSecretFunc(func(s *v1.Secret) *metric.Family { + annotationKeys, annotationValues := createPrometheusLabelKeysValues("annotation", s.Annotations, allowAnnotationsList) + return &metric.Family{ + Metrics: []*metric.Metric{ + { + LabelKeys: annotationKeys, + LabelValues: annotationValues, + Value: 1, + }, + }, + } + + }), + ), *generator.NewFamilyGenerator( descSecretLabelsName, descSecretLabelsHelp, metric.Gauge, "", wrapSecretFunc(func(s *v1.Secret) *metric.Family { - labelKeys, labelValues := createLabelKeysValues(s.Labels, allowLabelsList) + labelKeys, labelValues := createPrometheusLabelKeysValues("label", s.Labels, allowLabelsList) return &metric.Family{ Metrics: []*metric.Metric{ { diff --git a/internal/store/secret_test.go b/internal/store/secret_test.go index 052021ff72..96f88e1753 100644 --- a/internal/store/secret_test.go +++ b/internal/store/secret_test.go @@ -116,8 +116,8 @@ func TestSecretStore(t *testing.T) { }, } for i, c := range cases { - c.Func = generator.ComposeMetricGenFuncs(secretMetricFamilies(nil)) - c.Headers = generator.ExtractMetricFamilyHeaders(secretMetricFamilies(nil)) + c.Func = generator.ComposeMetricGenFuncs(secretMetricFamilies(nil, nil)) + c.Headers = generator.ExtractMetricFamilyHeaders(secretMetricFamilies(nil, nil)) if err := c.run(); err != nil { t.Errorf("unexpected collecting result in %vth run:\n%s", i, err) } diff --git a/internal/store/service.go b/internal/store/service.go index 15a1393a24..e382e89729 100644 --- a/internal/store/service.go +++ b/internal/store/service.go @@ -31,12 +31,14 @@ import ( ) var ( + descServiceAnnotationsName = "kube_service_annotations" + descServiceAnnotationsHelp = "Kubernetes annotations converted to Prometheus labels." descServiceLabelsName = "kube_service_labels" descServiceLabelsHelp = "Kubernetes labels converted to Prometheus labels." descServiceLabelsDefaultLabels = []string{"namespace", "service"} ) -func serviceMetricFamilies(allowLabelsList []string) []generator.FamilyGenerator { +func serviceMetricFamilies(allowAnnotationsList, allowLabelsList []string) []generator.FamilyGenerator { return []generator.FamilyGenerator{ *generator.NewFamilyGenerator( "kube_service_info", @@ -84,13 +86,28 @@ func serviceMetricFamilies(allowLabelsList []string) []generator.FamilyGenerator return &metric.Family{Metrics: []*metric.Metric{&m}} }), ), + *generator.NewFamilyGenerator( + descServiceAnnotationsName, + descServiceAnnotationsHelp, + metric.Gauge, + "", + wrapSvcFunc(func(s *v1.Service) *metric.Family { + annotationKeys, annotationValues := createPrometheusLabelKeysValues("annotation", s.Annotations, allowAnnotationsList) + m := metric.Metric{ + LabelKeys: annotationKeys, + LabelValues: annotationValues, + Value: 1, + } + return &metric.Family{Metrics: []*metric.Metric{&m}} + }), + ), *generator.NewFamilyGenerator( descServiceLabelsName, descServiceLabelsHelp, metric.Gauge, "", wrapSvcFunc(func(s *v1.Service) *metric.Family { - labelKeys, labelValues := createLabelKeysValues(s.Labels, allowLabelsList) + labelKeys, labelValues := createPrometheusLabelKeysValues("label", s.Labels, allowLabelsList) m := metric.Metric{ LabelKeys: labelKeys, LabelValues: labelValues, diff --git a/internal/store/service_test.go b/internal/store/service_test.go index b9545d7ad0..d6f0c1838f 100644 --- a/internal/store/service_test.go +++ b/internal/store/service_test.go @@ -30,6 +30,8 @@ func TestServiceStore(t *testing.T) { // Fixed metadata on type and help text. We prepend this to every expected // output so we only have to modify a single place when doing adjustments. const metadata = ` + # HELP kube_service_annotations Kubernetes annotations converted to Prometheus labels. + # TYPE kube_service_annotations gauge # HELP kube_service_info Information about service. # TYPE kube_service_info gauge # HELP kube_service_created Unix creation timestamp @@ -60,20 +62,24 @@ func TestServiceStore(t *testing.T) { }, }, Want: ` + # HELP kube_service_annotations Kubernetes annotations converted to Prometheus labels. # HELP kube_service_created Unix creation timestamp # HELP kube_service_info Information about service. # HELP kube_service_labels Kubernetes labels converted to Prometheus labels. # HELP kube_service_spec_type Type about service. + # TYPE kube_service_annotations gauge # TYPE kube_service_created gauge # TYPE kube_service_info gauge # TYPE kube_service_labels gauge # TYPE kube_service_spec_type gauge + kube_service_annotations{namespace="default",service="test-service1"} 1 kube_service_created{namespace="default",service="test-service1"} 1.5e+09 kube_service_info{cluster_ip="1.2.3.4",external_name="",load_balancer_ip="",namespace="default",service="test-service1"} 1 kube_service_labels{namespace="default",service="test-service1"} 1 kube_service_spec_type{namespace="default",service="test-service1",type="ClusterIP"} 1 `, MetricNames: []string{ + "kube_service_annotations", "kube_service_created", "kube_service_info", "kube_service_labels", @@ -97,6 +103,7 @@ func TestServiceStore(t *testing.T) { }, }, Want: metadata + ` + kube_service_annotations{namespace="default",service="test-service2"} 1 kube_service_created{namespace="default",service="test-service2"} 1.5e+09 kube_service_info{cluster_ip="1.2.3.5",external_name="",load_balancer_ip="",namespace="default",service="test-service2"} 1 kube_service_labels{namespace="default",service="test-service2"} 1 @@ -120,6 +127,7 @@ func TestServiceStore(t *testing.T) { }, }, Want: metadata + ` + kube_service_annotations{namespace="default",service="test-service3"} 1 kube_service_created{namespace="default",service="test-service3"} 1.5e+09 kube_service_info{cluster_ip="1.2.3.6",external_name="",load_balancer_ip="1.2.3.7",namespace="default",service="test-service3"} 1 kube_service_labels{namespace="default",service="test-service3"} 1 @@ -142,6 +150,7 @@ func TestServiceStore(t *testing.T) { }, }, Want: metadata + ` + kube_service_annotations{namespace="default",service="test-service4"} 1 kube_service_created{namespace="default",service="test-service4"} 1.5e+09 kube_service_info{cluster_ip="",external_name="www.example.com",load_balancer_ip="",namespace="default",service="test-service4"} 1 kube_service_labels{namespace="default",service="test-service4"} 1 @@ -173,6 +182,7 @@ func TestServiceStore(t *testing.T) { }, }, Want: metadata + ` + kube_service_annotations{namespace="default",service="test-service5"} 1 kube_service_created{namespace="default",service="test-service5"} 1.5e+09 kube_service_info{cluster_ip="",external_name="",load_balancer_ip="",namespace="default",service="test-service5"} 1 kube_service_labels{namespace="default",service="test-service5"} 1 @@ -199,6 +209,7 @@ func TestServiceStore(t *testing.T) { }, }, Want: metadata + ` + kube_service_annotations{namespace="default",service="test-service6"} 1 kube_service_created{namespace="default",service="test-service6"} 1.5e+09 kube_service_info{cluster_ip="",external_name="",load_balancer_ip="",namespace="default",service="test-service6"} 1 kube_service_labels{namespace="default",service="test-service6"} 1 @@ -209,8 +220,8 @@ func TestServiceStore(t *testing.T) { }, } for i, c := range cases { - c.Func = generator.ComposeMetricGenFuncs(serviceMetricFamilies(nil)) - c.Headers = generator.ExtractMetricFamilyHeaders(serviceMetricFamilies(nil)) + c.Func = generator.ComposeMetricGenFuncs(serviceMetricFamilies(nil, nil)) + c.Headers = generator.ExtractMetricFamilyHeaders(serviceMetricFamilies(nil, nil)) if err := c.run(); err != nil { t.Errorf("unexpected collecting result in %vth run:\n%s", i, err) } diff --git a/internal/store/statefulset.go b/internal/store/statefulset.go index 630b8f8263..5d4dfee0ad 100644 --- a/internal/store/statefulset.go +++ b/internal/store/statefulset.go @@ -31,12 +31,14 @@ import ( ) var ( + descStatefulSetAnnotationsName = "kube_statefulset_annotations" + descStatefulSetAnnotationsHelp = "Kubernetes annotations converted to Prometheus labels." descStatefulSetLabelsName = "kube_statefulset_labels" descStatefulSetLabelsHelp = "Kubernetes labels converted to Prometheus labels." descStatefulSetLabelsDefaultLabels = []string{"namespace", "statefulset"} ) -func statefulSetMetricFamilies(allowLabelsList []string) []generator.FamilyGenerator { +func statefulSetMetricFamilies(allowAnnotationsList, allowLabelsList []string) []generator.FamilyGenerator { return []generator.FamilyGenerator{ *generator.NewFamilyGenerator( "kube_statefulset_created", @@ -181,13 +183,31 @@ func statefulSetMetricFamilies(allowLabelsList []string) []generator.FamilyGener } }), ), + *generator.NewFamilyGenerator( + descStatefulSetAnnotationsName, + descStatefulSetAnnotationsHelp, + metric.Gauge, + "", + wrapStatefulSetFunc(func(s *v1.StatefulSet) *metric.Family { + annotationKeys, annotationValues := createPrometheusLabelKeysValues("annotation", s.Annotations, allowAnnotationsList) + return &metric.Family{ + Metrics: []*metric.Metric{ + { + LabelKeys: annotationKeys, + LabelValues: annotationValues, + Value: 1, + }, + }, + } + }), + ), *generator.NewFamilyGenerator( descStatefulSetLabelsName, descStatefulSetLabelsHelp, metric.Gauge, "", wrapStatefulSetFunc(func(s *v1.StatefulSet) *metric.Family { - labelKeys, labelValues := createLabelKeysValues(s.Labels, allowLabelsList) + labelKeys, labelValues := createPrometheusLabelKeysValues("label", s.Labels, allowLabelsList) return &metric.Family{ Metrics: []*metric.Metric{ { diff --git a/internal/store/statefulset_test.go b/internal/store/statefulset_test.go index a7a7b0842e..d5b65488eb 100644 --- a/internal/store/statefulset_test.go +++ b/internal/store/statefulset_test.go @@ -254,8 +254,8 @@ func TestStatefulSetStore(t *testing.T) { }, } for i, c := range cases { - c.Func = generator.ComposeMetricGenFuncs(statefulSetMetricFamilies(nil)) - c.Headers = generator.ExtractMetricFamilyHeaders(statefulSetMetricFamilies(nil)) + c.Func = generator.ComposeMetricGenFuncs(statefulSetMetricFamilies(nil, nil)) + c.Headers = generator.ExtractMetricFamilyHeaders(statefulSetMetricFamilies(nil, nil)) if err := c.run(); err != nil { t.Errorf("unexpected collecting result in %vth run:\n%s", i, err) } diff --git a/internal/store/storageclass.go b/internal/store/storageclass.go index f4c4538e44..4918e65e6d 100644 --- a/internal/store/storageclass.go +++ b/internal/store/storageclass.go @@ -29,6 +29,8 @@ import ( ) var ( + descStorageClassAnnotationsName = "kube_storageclass_annotations" + descStorageClassAnnotationsHelp = "Kubernetes annotations converted to Prometheus labels." descStorageClassLabelsName = "kube_storageclass_labels" descStorageClassLabelsHelp = "Kubernetes labels converted to Prometheus labels." descStorageClassLabelsDefaultLabels = []string{"storageclass"} @@ -36,7 +38,7 @@ var ( defaultVolumeBindingMode = storagev1.VolumeBindingImmediate ) -func storageClassMetricFamilies(allowLabelsList []string) []generator.FamilyGenerator { +func storageClassMetricFamilies(allowAnnotationsList, allowLabelsList []string) []generator.FamilyGenerator { return []generator.FamilyGenerator{ *generator.NewFamilyGenerator( "kube_storageclass_info", @@ -79,13 +81,31 @@ func storageClassMetricFamilies(allowLabelsList []string) []generator.FamilyGene } }), ), + *generator.NewFamilyGenerator( + descStorageClassAnnotationsName, + descStorageClassAnnotationsHelp, + metric.Gauge, + "", + wrapStorageClassFunc(func(s *storagev1.StorageClass) *metric.Family { + annotationKeys, annotationValues := createPrometheusLabelKeysValues("annotation", s.Annotations, allowAnnotationsList) + return &metric.Family{ + Metrics: []*metric.Metric{ + { + LabelKeys: annotationKeys, + LabelValues: annotationValues, + Value: 1, + }, + }, + } + }), + ), *generator.NewFamilyGenerator( descStorageClassLabelsName, descStorageClassLabelsHelp, metric.Gauge, "", wrapStorageClassFunc(func(s *storagev1.StorageClass) *metric.Family { - labelKeys, labelValues := createLabelKeysValues(s.Labels, allowLabelsList) + labelKeys, labelValues := createPrometheusLabelKeysValues("label", s.Labels, allowLabelsList) return &metric.Family{ Metrics: []*metric.Metric{ { diff --git a/internal/store/storageclass_test.go b/internal/store/storageclass_test.go index d3ee764fc8..c1f6866241 100644 --- a/internal/store/storageclass_test.go +++ b/internal/store/storageclass_test.go @@ -108,8 +108,8 @@ func TestStorageClassStore(t *testing.T) { }, } for i, c := range cases { - c.Func = generator.ComposeMetricGenFuncs(storageClassMetricFamilies(nil)) - c.Headers = generator.ExtractMetricFamilyHeaders(storageClassMetricFamilies(nil)) + c.Func = generator.ComposeMetricGenFuncs(storageClassMetricFamilies(nil, nil)) + c.Headers = generator.ExtractMetricFamilyHeaders(storageClassMetricFamilies(nil, nil)) if err := c.run(); err != nil { t.Errorf("unexpected collecting result in %vth run:\n%s", i, err) } diff --git a/internal/store/testutils.go b/internal/store/testutils.go index 86d3526cfb..fcebf167de 100644 --- a/internal/store/testutils.go +++ b/internal/store/testutils.go @@ -30,12 +30,13 @@ import ( ) type generateMetricsTestCase struct { - Obj interface{} - MetricNames []string - AllowLabelsList []string - Want string - Headers []string - Func func(interface{}) []metric.FamilyInterface + Obj interface{} + MetricNames []string + AllowAnnotationsList []string + AllowLabelsList []string + Want string + Headers []string + Func func(interface{}) []metric.FamilyInterface } func (testCase *generateMetricsTestCase) run() error { diff --git a/internal/store/utils.go b/internal/store/utils.go index e00205ea60..51c38ac19e 100644 --- a/internal/store/utils.go +++ b/internal/store/utils.go @@ -73,8 +73,8 @@ func addConditionMetrics(cs v1.ConditionStatus) []*metric.Metric { return ms } -func kubeLabelsToPrometheusLabels(labels map[string]string) ([]string, []string) { - return mapToPrometheusLabels(labels, "label") +func kubeMapToPrometheusLabels(prefix string, input map[string]string) ([]string, []string) { + return mapToPrometheusLabels(input, prefix) } func mapToPrometheusLabels(labels map[string]string, prefix string) ([]string, []string) { @@ -172,22 +172,23 @@ func isPrefixedNativeResource(name v1.ResourceName) bool { return strings.Contains(string(name), v1.ResourceDefaultNamespacePrefix) } -// createLabelKeysValues takes in passed kubernetes labels and allowed list in kubernetes label format -// it returns only those allowed labels that exist in the list converting them to Prometheus labels. -func createLabelKeysValues(allKubeLabels map[string]string, allowList []string) ([]string, []string) { - allowedKubeLabels := make(map[string]string) +// createPrometheusLabelKeysValues takes in passed kubernetes annotations/labels +// and associated allowed list in kubernetes label format. +// It returns only those allowed annotations/labels that exist in the list and converts them to Prometheus labels. +func createPrometheusLabelKeysValues(prefix string, allKubeData map[string]string, allowList []string) ([]string, []string) { + allowedKubeData := make(map[string]string) if len(allowList) > 0 { if allowList[0] == options.LabelWildcard { - return kubeLabelsToPrometheusLabels(allKubeLabels) + return kubeMapToPrometheusLabels(prefix, allKubeData) } for _, l := range allowList { - v, found := allKubeLabels[l] + v, found := allKubeData[l] if found { - allowedKubeLabels[l] = v + allowedKubeData[l] = v } } } - return kubeLabelsToPrometheusLabels(allowedKubeLabels) + return kubeMapToPrometheusLabels(prefix, allowedKubeData) } diff --git a/internal/store/utils_test.go b/internal/store/utils_test.go index 06e2cb4ac0..a2d914550c 100644 --- a/internal/store/utils_test.go +++ b/internal/store/utils_test.go @@ -246,7 +246,7 @@ func TestKubeLabelsToPrometheusLabels(t *testing.T) { for _, tc := range testCases { t.Run(fmt.Sprintf("kubelabels input=%v , expected prometheus keys=%v, expected prometheus values=%v", tc.kubeLabels, tc.expectKeys, tc.expectValues), func(t *testing.T) { - labelKeys, labelValues := kubeLabelsToPrometheusLabels(tc.kubeLabels) + labelKeys, labelValues := kubeMapToPrometheusLabels("label", tc.kubeLabels) if len(labelKeys) != len(tc.expectKeys) { t.Errorf("Got Prometheus label keys with len %d but expected %d", len(labelKeys), len(tc.expectKeys)) } diff --git a/internal/store/verticalpodautoscaler.go b/internal/store/verticalpodautoscaler.go index 3093a2c13b..90d3fe8daa 100644 --- a/internal/store/verticalpodautoscaler.go +++ b/internal/store/verticalpodautoscaler.go @@ -34,20 +34,40 @@ import ( ) var ( + descVerticalPodAutoscalerAnnotationsName = "kube_verticalpodautoscaler_annotations" + descVerticalPodAutoscalerAnnotationsHelp = "Kubernetes annotations converted to Prometheus labels." descVerticalPodAutoscalerLabelsName = "kube_verticalpodautoscaler_labels" descVerticalPodAutoscalerLabelsHelp = "Kubernetes labels converted to Prometheus labels." descVerticalPodAutoscalerLabelsDefaultLabels = []string{"namespace", "verticalpodautoscaler", "target_api_version", "target_kind", "target_name"} ) -func vpaMetricFamilies(allowLabelsList []string) []generator.FamilyGenerator { +func vpaMetricFamilies(allowAnnotationsList, allowLabelsList []string) []generator.FamilyGenerator { return []generator.FamilyGenerator{ + *generator.NewFamilyGenerator( + descVerticalPodAutoscalerAnnotationsName, + descVerticalPodAutoscalerAnnotationsHelp, + metric.Gauge, + "", + wrapVPAFunc(func(a *autoscaling.VerticalPodAutoscaler) *metric.Family { + annotationKeys, annotationValues := createPrometheusLabelKeysValues("annotation", a.Annotations, allowAnnotationsList) + return &metric.Family{ + Metrics: []*metric.Metric{ + { + LabelKeys: annotationKeys, + LabelValues: annotationValues, + Value: 1, + }, + }, + } + }), + ), *generator.NewFamilyGenerator( descVerticalPodAutoscalerLabelsName, descVerticalPodAutoscalerLabelsHelp, metric.Gauge, "", wrapVPAFunc(func(a *autoscaling.VerticalPodAutoscaler) *metric.Family { - labelKeys, labelValues := createLabelKeysValues(a.Labels, allowLabelsList) + labelKeys, labelValues := createPrometheusLabelKeysValues("label", a.Labels, allowLabelsList) return &metric.Family{ Metrics: []*metric.Metric{ { diff --git a/internal/store/verticalpodautoscaler_test.go b/internal/store/verticalpodautoscaler_test.go index f3be025bc9..481c689ff3 100644 --- a/internal/store/verticalpodautoscaler_test.go +++ b/internal/store/verticalpodautoscaler_test.go @@ -133,8 +133,8 @@ func TestVPAStore(t *testing.T) { }, } for i, c := range cases { - c.Func = generator.ComposeMetricGenFuncs(vpaMetricFamilies(nil)) - c.Headers = generator.ExtractMetricFamilyHeaders(vpaMetricFamilies(nil)) + c.Func = generator.ComposeMetricGenFuncs(vpaMetricFamilies(nil, nil)) + c.Headers = generator.ExtractMetricFamilyHeaders(vpaMetricFamilies(nil, nil)) if err := c.run(); err != nil { t.Errorf("unexpected collecting result in %vth run:\n%s", i, err) } diff --git a/internal/store/volumeattachment.go b/internal/store/volumeattachment.go index 228a8c2bb9..82cc3d45b9 100644 --- a/internal/store/volumeattachment.go +++ b/internal/store/volumeattachment.go @@ -42,7 +42,7 @@ var ( metric.Gauge, "", wrapVolumeAttachmentFunc(func(va *storagev1.VolumeAttachment) *metric.Family { - labelKeys, labelValues := kubeLabelsToPrometheusLabels(va.Labels) + labelKeys, labelValues := kubeMapToPrometheusLabels("label", va.Labels) return &metric.Family{ Metrics: []*metric.Metric{ { diff --git a/main.go b/main.go index b01621c97b..529f1e1b2d 100644 --- a/main.go +++ b/main.go @@ -151,6 +151,7 @@ func main() { storeBuilder.WithKubeClient(kubeClient) storeBuilder.WithVPAClient(vpaClient) storeBuilder.WithSharding(opts.Shard, opts.TotalShards) + storeBuilder.WithAllowAnnotations(opts.AnnotationsAllowList) storeBuilder.WithAllowLabels(opts.LabelsAllowList) ksmMetricsRegistry.MustRegister( diff --git a/main_test.go b/main_test.go index db2dc66a9c..743875aee1 100644 --- a/main_test.go +++ b/main_test.go @@ -75,6 +75,7 @@ func BenchmarkKubeStateMetrics(b *testing.B) { } builder.WithAllowDenyList(l) + builder.WithAllowAnnotations(map[string][]string{}) builder.WithAllowLabels(map[string][]string{}) // This test is not suitable to be compared in terms of time, as it includes @@ -165,7 +166,8 @@ func TestFullScrapeCycle(t *testing.T) { body, _ := io.ReadAll(resp.Body) - expected := `# HELP kube_pod_completion_time Completion time in unix timestamp for a pod. + expected := `# HELP kube_pod_annotations Kubernetes annotations converted to Prometheus labels. +# HELP kube_pod_completion_time Completion time in unix timestamp for a pod. # HELP kube_pod_container_info Information about a container in a pod. # HELP kube_pod_container_resource_limits The number of requested limit resource by a container. # HELP kube_pod_container_resource_requests The number of requested request resource by a container. @@ -215,6 +217,7 @@ func TestFullScrapeCycle(t *testing.T) { # HELP kube_pod_status_scheduled Describes the status of the scheduling process for the pod. # HELP kube_pod_status_scheduled_time Unix timestamp when pod moved into scheduled status # HELP kube_pod_status_unschedulable Describes the unschedulable status for the pod. +# TYPE kube_pod_annotations gauge # TYPE kube_pod_completion_time gauge # TYPE kube_pod_container_info gauge # TYPE kube_pod_container_resource_limits gauge @@ -265,6 +268,7 @@ func TestFullScrapeCycle(t *testing.T) { # TYPE kube_pod_status_scheduled gauge # TYPE kube_pod_status_scheduled_time gauge # TYPE kube_pod_status_unschedulable gauge +kube_pod_annotations{namespace="default",pod="pod0",uid="abc-0"} 1 kube_pod_container_info{namespace="default",pod="pod0",uid="abc-0",container="container2",image="k8s.gcr.io/hyperkube2",image_id="docker://sha256:bbb",container_id="docker://cd456"} 1 kube_pod_container_info{namespace="default",pod="pod0",uid="abc-0",container="container3",image="k8s.gcr.io/hyperkube3",image_id="docker://sha256:ccc",container_id="docker://ef789"} 1 kube_pod_container_resource_limits{namespace="default",pod="pod0",uid="abc-0",container="pod1_con1",node="node1",resource="cpu",unit="core"} 0.2 diff --git a/pkg/options/options.go b/pkg/options/options.go index c39ad25d51..09147e2e8d 100644 --- a/pkg/options/options.go +++ b/pkg/options/options.go @@ -28,24 +28,25 @@ import ( // Options are the configurable parameters for kube-state-metrics. type Options struct { - Apiserver string - Kubeconfig string - Help bool - Port int - Host string - TelemetryPort int - TelemetryHost string - TLSConfig string - Resources ResourceSet - Namespaces NamespaceList - Shard int32 - TotalShards int - Pod string - Namespace string - MetricDenylist MetricSet - MetricAllowlist MetricSet - Version bool - LabelsAllowList LabelsAllowList + Apiserver string + Kubeconfig string + Help bool + Port int + Host string + TelemetryPort int + TelemetryHost string + TLSConfig string + Resources ResourceSet + Namespaces NamespaceList + Shard int32 + TotalShards int + Pod string + Namespace string + MetricDenylist MetricSet + MetricAllowlist MetricSet + Version bool + AnnotationsAllowList LabelsAllowList + LabelsAllowList LabelsAllowList EnableGZIPEncoding bool @@ -57,10 +58,11 @@ type Options struct { // NewOptions returns a new instance of `Options`. func NewOptions() *Options { return &Options{ - Resources: ResourceSet{}, - MetricAllowlist: MetricSet{}, - MetricDenylist: MetricSet{}, - LabelsAllowList: LabelsAllowList{}, + Resources: ResourceSet{}, + MetricAllowlist: MetricSet{}, + MetricDenylist: MetricSet{}, + AnnotationsAllowList: LabelsAllowList{}, + LabelsAllowList: LabelsAllowList{}, } } @@ -93,6 +95,7 @@ func (o *Options) AddFlags() { o.flags.Var(&o.Namespaces, "namespaces", fmt.Sprintf("Comma-separated list of namespaces to be enabled. Defaults to %q", &DefaultNamespaces)) o.flags.Var(&o.MetricAllowlist, "metric-allowlist", "Comma-separated list of metrics to be exposed. This list comprises of exact metric names and/or regex patterns. The allowlist and denylist are mutually exclusive.") o.flags.Var(&o.MetricDenylist, "metric-denylist", "Comma-separated list of metrics not to be enabled. This list comprises of exact metric names and/or regex patterns. The allowlist and denylist are mutually exclusive.") + o.flags.Var(&o.AnnotationsAllowList, "metric-annotations-allowlist", "Comma-separated list of Kubernetes annotations keys that will be used in the resource' labels metric. By default the metric contains only name and namespace labels. To include additional annotations provide a list of resource names in their plural form and Kubernetes annotation keys you would like to allow for them (Example: '=namespaces=[kubernetes.io/team,...],pods=[kubernetes.io/team],...)'. A single '*' can be provided per resource instead to allow any annotations, but that has severe performance implications (Example: '=pods=[*]').") o.flags.Var(&o.LabelsAllowList, "metric-labels-allowlist", "Comma-separated list of additional Kubernetes label keys that will be used in the resource' labels metric. By default the metric contains only name and namespace labels. To include additional labels provide a list of resource names in their plural form and Kubernetes label keys you would like to allow for them (Example: '=namespaces=[k8s-label-1,k8s-label-n,...],pods=[app],...)'. A single '*' can be provided per resource instead to allow any labels, but that has severe performance implications (Example: '=pods=[*]').") o.flags.Int32Var(&o.Shard, "shard", int32(0), "The instances shard nominal (zero indexed) within the total number of shards. (default 0)") o.flags.IntVar(&o.TotalShards, "total-shards", 1, "The total number of shards. Sharding is disabled when total shards is set to 1.")