OpenShift
Description
This connector monitors Red Hat OpenShift Container Platform and OKD 4.x clusters through the API server REST API (cluster version and updates, cluster operators, operators installed by OLM with their updates, nodes with their CPU and memory usage, Deployments and StatefulSets with their desired, available, ready, current and updated pods, DaemonSets with their scheduled, misscheduled and ready nodes, HorizontalPodAutoscalers with their minimum, maximum, current and desired pods, PersistentVolumeClaims with their phase, requested and provisioned storage, PersistentVolumes with their phase and capacity, namespaces (projects) with their phase, Jobs with their active, failed and succeeded pods (by default the Jobs without succeeded pod, see the jobFieldSelector variable), CronJobs with their running Jobs, Services with their ready, serving and terminating endpoints and their load balancer ingress points, pods with their phase and CPU and memory usage (by default the pods not Succeeded, see the podFieldSelector and podLabelSelector variables) and their containers with their state, restarts, readiness, resources and CPU utilization, machine config pools, CPU, memory, storage and object count quotas of cluster resource quotas and project resource quotas). The bearer token of a ServiceAccount bound to the cluster-reader ClusterRole must be provided as the HTTP password.
container kubernetes linux openshift
This connector requires the Enterprise edition of MetricsHub.
Target
Typical platforms: Red Hat OpenShift, OKD
Operating systems: Linux, other
This connector is not available for the local host (it is applicable to remote hosts only).
Prerequisites
Leverages: OpenShift API server REST API
Technology and protocols: HTTP
Variables:
podFieldSelector: Field selector of the pods monitored by openshift_pod and openshift_container (Kubernetes field selector syntax, for example status.phase!=Succeeded,metadata.namespace!=openshift-monitoring). The default leaves out the pods that completed successfully (the pods of finished Jobs); set it empty to monitor every pod. (default:status.phase!=Succeeded)podLabelSelector: Label selector of the pods monitored by openshift_pod and openshift_container, also applied to their resource metrics (Kubernetes label selector syntax, for example app.kubernetes.io/part-of=shop; the value goes into the request URL as it is, so write a space as +, for example environment+in+(production,qa)). Empty by default (every pod selected by podFieldSelector).jobFieldSelector: Field selector of the Jobs monitored by openshift_job (Kubernetes field selector syntax; the API only supports status.successful, metadata.name and metadata.namespace on Jobs). The default keeps the Jobs that have no succeeded pod (running, failed or not started), leaving out the completed Jobs that every CronJob run creates; set it empty to monitor every Job. (default:status.successful=0)
Examples
CLI
metricshub HOSTNAME -t linux -c +OpenShift --https --http-port 443 -u USERNAME
metricshub.yaml
resourceGroups:
<RESOURCE_GROUP>:
resources:
<HOSTNAME-ID>:
attributes:
host.name: <HOSTNAME> # Change with actual host name
host.type: linux
connectors: [ +OpenShift ] # Optional, to load only this connector
protocols:
http:
https: true
port: 443 # or probably something else
username: <USERNAME> # Change with actual credentials
password: <PASSWORD> # Encrypted using metricshub-encrypt
additionalConnectors:
OpenShift: # Unique ID. Use 'uses' if different from the original connector ID
uses: OpenShift # Optional - Original ID if not in key
force: true # Optional (default: true); false for auto-detection only
variables:
podFieldSelector: <VALUE> # Replace with desired value.
podLabelSelector: <VALUE> # Replace with desired value.
jobFieldSelector: <VALUE> # Replace with desired value.
Connector Activation Criteria
The OpenShift connector will be automatically activated, and its status will be reported as OK if all the below criteria are met:
- The HTTP Request below to the managed host succeeds:
- get
/version - The response body contains:
gitVersion(regex)
- get
- The HTTP Request below to the managed host succeeds:
- get
/apis/config.openshift.io/v1/clusterversions/version - Request Header:
${file::httpHeader.txt} - The entire response (header + body) contains:
200(regex)
- get
Metrics
| Type | Collected Metrics | Specific Attributes |
|---|---|---|
| openshift_appliedclusterresourcequota | openshift.appliedclusterquota.cpu.limit.hardopenshift.appliedclusterquota.cpu.limit.usedopenshift.appliedclusterquota.cpu.request.hardopenshift.appliedclusterquota.cpu.request.usedopenshift.appliedclusterquota.ephemeral_storage.limit.hardopenshift.appliedclusterquota.ephemeral_storage.limit.usedopenshift.appliedclusterquota.ephemeral_storage.request.hardopenshift.appliedclusterquota.ephemeral_storage.request.usedopenshift.appliedclusterquota.memory.limit.hardopenshift.appliedclusterquota.memory.limit.usedopenshift.appliedclusterquota.memory.request.hardopenshift.appliedclusterquota.memory.request.usedopenshift.appliedclusterquota.object_count.hard{k8s.resourcequota.resource_name="configmaps"}openshift.appliedclusterquota.object_count.hard{k8s.resourcequota.resource_name="count/pods"}openshift.appliedclusterquota.object_count.hard{k8s.resourcequota.resource_name="pods"}openshift.appliedclusterquota.object_count.hard{k8s.resourcequota.resource_name="replicationcontrollers"}openshift.appliedclusterquota.object_count.hard{k8s.resourcequota.resource_name="resourcequotas"}openshift.appliedclusterquota.object_count.hard{k8s.resourcequota.resource_name="secrets"}openshift.appliedclusterquota.object_count.hard{k8s.resourcequota.resource_name="services"}openshift.appliedclusterquota.object_count.hard{k8s.resourcequota.resource_name="services.loadbalancers"}openshift.appliedclusterquota.object_count.hard{k8s.resourcequota.resource_name="services.nodeports"}openshift.appliedclusterquota.object_count.used{k8s.resourcequota.resource_name="configmaps"}openshift.appliedclusterquota.object_count.used{k8s.resourcequota.resource_name="count/pods"}openshift.appliedclusterquota.object_count.used{k8s.resourcequota.resource_name="pods"}openshift.appliedclusterquota.object_count.used{k8s.resourcequota.resource_name="replicationcontrollers"}openshift.appliedclusterquota.object_count.used{k8s.resourcequota.resource_name="resourcequotas"}openshift.appliedclusterquota.object_count.used{k8s.resourcequota.resource_name="secrets"}openshift.appliedclusterquota.object_count.used{k8s.resourcequota.resource_name="services"}openshift.appliedclusterquota.object_count.used{k8s.resourcequota.resource_name="services.loadbalancers"}openshift.appliedclusterquota.object_count.used{k8s.resourcequota.resource_name="services.nodeports"}openshift.appliedclusterquota.persistentvolumeclaim_count.hardopenshift.appliedclusterquota.persistentvolumeclaim_count.usedopenshift.appliedclusterquota.storage.request.hardopenshift.appliedclusterquota.storage.request.used | idk8s.namespace.namenameopenshift.clusterquota.nameopenshift.clusterquota.uid |
| openshift_cluster | openshift.clusterversion.status{state="degraded|failed|ok"}openshift.clusterversion.update.available | channelcontrol_plane_topologydesired_versionidk8s.cluster.namek8s.cluster.uidnameplatformversion |
| openshift_clusteroperator | openshift.clusteroperator.status{state="degraded|failed|ok"} | idnameversion |
| openshift_clusterresourcequota | openshift.clusterquota.cpu.limit.hardopenshift.clusterquota.cpu.limit.usedopenshift.clusterquota.cpu.request.hardopenshift.clusterquota.cpu.request.usedopenshift.clusterquota.ephemeral_storage.limit.hardopenshift.clusterquota.ephemeral_storage.limit.usedopenshift.clusterquota.ephemeral_storage.request.hardopenshift.clusterquota.ephemeral_storage.request.usedopenshift.clusterquota.memory.limit.hardopenshift.clusterquota.memory.limit.usedopenshift.clusterquota.memory.request.hardopenshift.clusterquota.memory.request.usedopenshift.clusterquota.object_count.hard{k8s.resourcequota.resource_name="configmaps"}openshift.clusterquota.object_count.hard{k8s.resourcequota.resource_name="count/pods"}openshift.clusterquota.object_count.hard{k8s.resourcequota.resource_name="pods"}openshift.clusterquota.object_count.hard{k8s.resourcequota.resource_name="replicationcontrollers"}openshift.clusterquota.object_count.hard{k8s.resourcequota.resource_name="resourcequotas"}openshift.clusterquota.object_count.hard{k8s.resourcequota.resource_name="secrets"}openshift.clusterquota.object_count.hard{k8s.resourcequota.resource_name="services"}openshift.clusterquota.object_count.hard{k8s.resourcequota.resource_name="services.loadbalancers"}openshift.clusterquota.object_count.hard{k8s.resourcequota.resource_name="services.nodeports"}openshift.clusterquota.object_count.used{k8s.resourcequota.resource_name="configmaps"}openshift.clusterquota.object_count.used{k8s.resourcequota.resource_name="count/pods"}openshift.clusterquota.object_count.used{k8s.resourcequota.resource_name="pods"}openshift.clusterquota.object_count.used{k8s.resourcequota.resource_name="replicationcontrollers"}openshift.clusterquota.object_count.used{k8s.resourcequota.resource_name="resourcequotas"}openshift.clusterquota.object_count.used{k8s.resourcequota.resource_name="secrets"}openshift.clusterquota.object_count.used{k8s.resourcequota.resource_name="services"}openshift.clusterquota.object_count.used{k8s.resourcequota.resource_name="services.loadbalancers"}openshift.clusterquota.object_count.used{k8s.resourcequota.resource_name="services.nodeports"}openshift.clusterquota.persistentvolumeclaim_count.hardopenshift.clusterquota.persistentvolumeclaim_count.usedopenshift.clusterquota.storage.request.hardopenshift.clusterquota.storage.request.used | idnameopenshift.clusterquota.nameopenshift.clusterquota.uid |
| openshift_container | k8s.container.cpu.limit.desiredk8s.container.cpu.limit.utilizationk8s.container.cpu.request.desiredk8s.container.cpu.request.utilizationk8s.container.memory.limit.desiredk8s.container.memory.request.desiredk8s.container.readyk8s.container.restart.countk8s.container.status.reason{state="Completed|ContainerCannotRun|ContainerCreating|CrashLoopBackOff|CreateContainerConfigError|ErrImagePull|Error|ImagePullBackOff|OOMKilled"}k8s.container.status.state{state="running|terminated|waiting"} | idk8s.container.namek8s.container.status.last_terminated_reasonk8s.namespace.namek8s.pod.namek8s.pod.uidname |
| openshift_cronjob | k8s.cronjob.job.active | idk8s.cronjob.namek8s.cronjob.uidk8s.namespace.namename |
| openshift_daemonset | k8s.daemonset.node.current_scheduledk8s.daemonset.node.desired_scheduledk8s.daemonset.node.misscheduledk8s.daemonset.node.ready | idk8s.daemonset.namek8s.daemonset.uidk8s.namespace.namename |
| openshift_deployment | k8s.deployment.pod.availablek8s.deployment.pod.desired | idk8s.deployment.namek8s.deployment.uidk8s.namespace.namename |
| openshift_hpa | k8s.hpa.pod.currentk8s.hpa.pod.desiredk8s.hpa.pod.maxk8s.hpa.pod.min | idk8s.hpa.namek8s.hpa.scaletargetref.api_versionk8s.hpa.scaletargetref.kindk8s.hpa.scaletargetref.namek8s.hpa.uidk8s.namespace.namename |
| openshift_job | k8s.job.pod.activek8s.job.pod.desired_successfulk8s.job.pod.failedk8s.job.pod.max_parallelk8s.job.pod.successful | idk8s.job.namek8s.job.uidk8s.namespace.namename |
| openshift_machineconfigpool | openshift.machineconfigpool.machine.countopenshift.machineconfigpool.machine.degradedopenshift.machineconfigpool.machine.readyopenshift.machineconfigpool.machine.unavailableopenshift.machineconfigpool.machine.updatedopenshift.machineconfigpool.status{state="degraded|failed|ok"} | idname |
| openshift_namespace | k8s.namespace.phase{state="active|terminating"} | idk8s.namespace.namek8s.namespace.uidname |
| openshift_node | k8s.node.condition.status{k8s.node.condition.type="DiskPressure", k8s.node.condition.status="false"}k8s.node.condition.status{k8s.node.condition.type="DiskPressure", k8s.node.condition.status="true"}k8s.node.condition.status{k8s.node.condition.type="DiskPressure", k8s.node.condition.status="unknown"}k8s.node.condition.status{k8s.node.condition.type="MemoryPressure", k8s.node.condition.status="false"}k8s.node.condition.status{k8s.node.condition.type="MemoryPressure", k8s.node.condition.status="true"}k8s.node.condition.status{k8s.node.condition.type="MemoryPressure", k8s.node.condition.status="unknown"}k8s.node.condition.status{k8s.node.condition.type="NetworkUnavailable", k8s.node.condition.status="false"}k8s.node.condition.status{k8s.node.condition.type="NetworkUnavailable", k8s.node.condition.status="true"}k8s.node.condition.status{k8s.node.condition.type="NetworkUnavailable", k8s.node.condition.status="unknown"}k8s.node.condition.status{k8s.node.condition.type="PIDPressure", k8s.node.condition.status="false"}k8s.node.condition.status{k8s.node.condition.type="PIDPressure", k8s.node.condition.status="true"}k8s.node.condition.status{k8s.node.condition.type="PIDPressure", k8s.node.condition.status="unknown"}k8s.node.condition.status{k8s.node.condition.type="Ready", k8s.node.condition.status="false"}k8s.node.condition.status{k8s.node.condition.type="Ready", k8s.node.condition.status="true"}k8s.node.condition.status{k8s.node.condition.type="Ready", k8s.node.condition.status="unknown"}k8s.node.cpu.allocatablek8s.node.cpu.usagek8s.node.ephemeral_storage.allocatablek8s.node.memory.allocatablek8s.node.memory.working_setk8s.node.pod.allocatablemetricshub.host.observed | container.runtime.descriptionhost.archhost.nameidk8s.cluster.namek8s.node.namek8s.node.uidkernel_versionkubelet_versionnameos.descriptionroles |
| openshift_operator | openshift.operator.status{state="degraded|failed|ok"}openshift.operator.update.available | idk8s.namespace.namemanaged_namespacesnameproviderversion |
| openshift_persistentvolume | k8s.persistentvolume.status.phase{state="Available|Bound|Failed|Pending|Released"}k8s.persistentvolume.storage.capacity | idk8s.persistentvolume.namek8s.persistentvolume.uidk8s.storageclass.namename |
| openshift_persistentvolumeclaim | k8s.persistentvolumeclaim.status.phase{state="Bound|Lost|Pending"}k8s.persistentvolumeclaim.storage.capacityk8s.persistentvolumeclaim.storage.request | idk8s.namespace.namek8s.persistentvolumeclaim.namek8s.persistentvolumeclaim.uidk8s.storageclass.namename |
| openshift_pod | k8s.pod.cpu.usagek8s.pod.memory.working_setk8s.pod.status.phase{state="Failed|Pending|Running|Succeeded|Unknown"}k8s.pod.status.reason{state="Evicted|NodeAffinity|NodeLost|Shutdown|UnexpectedAdmissionError"} | idk8s.namespace.namek8s.node.namek8s.pod.namek8s.pod.uidname |
| openshift_resourcequota | k8s.resourcequota.cpu.limit.hardk8s.resourcequota.cpu.limit.usedk8s.resourcequota.cpu.request.hardk8s.resourcequota.cpu.request.usedk8s.resourcequota.ephemeral_storage.limit.hardk8s.resourcequota.ephemeral_storage.limit.usedk8s.resourcequota.ephemeral_storage.request.hardk8s.resourcequota.ephemeral_storage.request.usedk8s.resourcequota.memory.limit.hardk8s.resourcequota.memory.limit.usedk8s.resourcequota.memory.request.hardk8s.resourcequota.memory.request.usedk8s.resourcequota.object_count.hard{k8s.resourcequota.resource_name="configmaps"}k8s.resourcequota.object_count.hard{k8s.resourcequota.resource_name="count/pods"}k8s.resourcequota.object_count.hard{k8s.resourcequota.resource_name="pods"}k8s.resourcequota.object_count.hard{k8s.resourcequota.resource_name="replicationcontrollers"}k8s.resourcequota.object_count.hard{k8s.resourcequota.resource_name="resourcequotas"}k8s.resourcequota.object_count.hard{k8s.resourcequota.resource_name="secrets"}k8s.resourcequota.object_count.hard{k8s.resourcequota.resource_name="services"}k8s.resourcequota.object_count.hard{k8s.resourcequota.resource_name="services.loadbalancers"}k8s.resourcequota.object_count.hard{k8s.resourcequota.resource_name="services.nodeports"}k8s.resourcequota.object_count.used{k8s.resourcequota.resource_name="configmaps"}k8s.resourcequota.object_count.used{k8s.resourcequota.resource_name="count/pods"}k8s.resourcequota.object_count.used{k8s.resourcequota.resource_name="pods"}k8s.resourcequota.object_count.used{k8s.resourcequota.resource_name="replicationcontrollers"}k8s.resourcequota.object_count.used{k8s.resourcequota.resource_name="resourcequotas"}k8s.resourcequota.object_count.used{k8s.resourcequota.resource_name="secrets"}k8s.resourcequota.object_count.used{k8s.resourcequota.resource_name="services"}k8s.resourcequota.object_count.used{k8s.resourcequota.resource_name="services.loadbalancers"}k8s.resourcequota.object_count.used{k8s.resourcequota.resource_name="services.nodeports"}k8s.resourcequota.persistentvolumeclaim_count.hardk8s.resourcequota.persistentvolumeclaim_count.usedk8s.resourcequota.storage.request.hardk8s.resourcequota.storage.request.used | idk8s.namespace.namek8s.resourcequota.namek8s.resourcequota.uidname |
| openshift_service | k8s.service.endpoint.count{k8s.service.endpoint.condition="ready", k8s.service.endpoint.address_type="FQDN"}k8s.service.endpoint.count{k8s.service.endpoint.condition="ready", k8s.service.endpoint.address_type="IPv4"}k8s.service.endpoint.count{k8s.service.endpoint.condition="ready", k8s.service.endpoint.address_type="IPv6"}k8s.service.endpoint.count{k8s.service.endpoint.condition="serving", k8s.service.endpoint.address_type="FQDN"}k8s.service.endpoint.count{k8s.service.endpoint.condition="serving", k8s.service.endpoint.address_type="IPv4"}k8s.service.endpoint.count{k8s.service.endpoint.condition="serving", k8s.service.endpoint.address_type="IPv6"}k8s.service.endpoint.count{k8s.service.endpoint.condition="terminating", k8s.service.endpoint.address_type="FQDN"}k8s.service.endpoint.count{k8s.service.endpoint.condition="terminating", k8s.service.endpoint.address_type="IPv4"}k8s.service.endpoint.count{k8s.service.endpoint.condition="terminating", k8s.service.endpoint.address_type="IPv6"}k8s.service.load_balancer.ingress.count | idk8s.namespace.namek8s.service.namek8s.service.typek8s.service.uidname |
| openshift_statefulset | k8s.statefulset.pod.currentk8s.statefulset.pod.desiredk8s.statefulset.pod.readyk8s.statefulset.pod.updated | idk8s.namespace.namek8s.statefulset.namek8s.statefulset.uidname |