Module: check_mk
Branch: master
Commit: 7ba060d879c831ff55facb505a4bbdf1e5b066a1
URL:
http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=7ba060d879c831…
Author: Óscar Nájera <on(a)mathias-kettner.de>
Date: Fri Jan 11 15:08:02 2019 +0100
Kubernetes special agent extension for custom metrics
CMK-1475
Change-Id: I875d82889495f276f6c9f2258b200f9dbd6ef71a
---
cmk/special_agents/agent_kubernetes.py | 87 ++++++++++++++++++++++++++++++++++
1 file changed, 87 insertions(+)
diff --git a/cmk/special_agents/agent_kubernetes.py
b/cmk/special_agents/agent_kubernetes.py
index 47124ee..5efe7a0 100644
--- a/cmk/special_agents/agent_kubernetes.py
+++ b/cmk/special_agents/agent_kubernetes.py
@@ -48,6 +48,7 @@ from typing import ( # pylint: disable=unused-import
)
from kubernetes import client
+from kubernetes.client.rest import ApiException
import cmk.utils.profile
import cmk.utils.password_store
@@ -492,6 +493,31 @@ class RoleList(ListLike[Role]):
}
+class Metric(object):
+ def __init__(self, metric):
+ self.from_object = metric['describedObject']
+ self.metrics = {metric['metricName']: metric.get('value')}
+
+ def __add__(self, other):
+ assert self.from_object == other.from_object
+ self.metrics.update(other.metrics)
+ return self
+
+ def __str__(self):
+ return str(self.__dict__)
+
+ def __repr__(self):
+ return str(self.__dict__)
+
+
+class MetricList(ListLike[Metric]):
+ def __add__(self, other):
+ return MetricList([a + b for a, b in zip(self, other)])
+
+ def list_metrics(self):
+ return [item.__dict__ for item in self]
+
+
class Group(object):
"""
A group of elements where an element is e.g. a piggyback host.
@@ -591,6 +617,8 @@ class ApiData(object):
storage_api = client.StorageV1Api(api_client)
rbac_authorization_api = client.RbacAuthorizationV1Api(api_client)
+ self.custom_api = client.CustomObjectsApi(api_client)
+
logging.debug('Retrieving data')
storage_classes = storage_api.list_storage_class()
namespaces = core_api.list_namespace()
@@ -615,6 +643,56 @@ class ApiData(object):
map(PersistentVolumeClaim, pvcs.items))
self.pods = PodList(map(Pod, pods.items))
+ pods_custom_metrics = {
+ "memory": ['memory_rss', 'memory_swap',
'memory_usage_bytes', 'memory_max_usage_bytes'],
+ "fs": ['fs_inodes', 'fs_reads',
'fs_writes', 'fs_limit_bytes', 'fs_usage_bytes'],
+ "cpu": ['cpu_system', 'cpu_user',
'cpu_usage']
+ }
+
+ self.pods_Metrics = dict() # type: Dict[str, Dict[str, List]]
+ for metric_group, metrics in pods_custom_metrics.items():
+ self.pods_Metrics[metric_group] = self.get_namespaced_group_metric(metrics)
+
+ def get_namespaced_group_metric(self, metrics):
+ # type: (List[str]) -> Dict[str, List]
+ queries = [self.get_namespaced_custom_pod_metric(metric) for metric in metrics]
+
+ grouped_metrics = {} # type: Dict[str, List]
+ for response in queries:
+ for namespace in response:
+ grouped_metrics.setdefault(namespace, []).append(response[namespace])
+
+ for namespace in grouped_metrics:
+ grouped_metrics[namespace] = reduce(operator.add,
+
grouped_metrics[namespace]).list_metrics()
+
+ return grouped_metrics
+
+ def get_namespaced_custom_pod_metric(self, metric):
+ # type: (str) -> Dict
+
+ logging.debug('Query Custom Metrics Endpoint: %s', metric)
+ custom_metric = {}
+ for namespace in self.namespaces:
+ try:
+ data = map(
+ Metric,
+ self.custom_api.get_namespaced_custom_object(
+ 'custom.metrics.k8s.io',
+ 'v1beta1',
+ namespace.name,
+ 'pods/*',
+ metric,
+ )['items'])
+ custom_metric[namespace.name] = MetricList(data)
+ except ApiException as err:
+ if err.status == 404:
+ logging.info('Data unavailable. No pods in namespace %s',
namespace.name)
+ else:
+ raise err
+
+ return custom_metric
+
def cluster_sections(self):
# type: () -> str
logging.info('Output cluster sections')
@@ -643,6 +721,14 @@ class ApiData(object):
g.join('k8s_conditions', self.nodes.conditions())
return '\n'.join(g.output())
+ def custom_metrics_section(self):
+ # type: () -> str
+ logging.info('Output pods custom metrics')
+ e = Element()
+ for c_metric in self.pods_Metrics:
+ e.get('k8s_pods_%s' % c_metric).insert(self.pods_Metrics[c_metric])
+ return '\n'.join(e.output())
+
def get_api_client(arguments):
# type: (argparse.Namespace) -> client.ApiClient
@@ -682,6 +768,7 @@ def main(args=None):
api_data = ApiData(api_client)
print(api_data.cluster_sections())
print(api_data.node_sections())
+ print(api_data.custom_metrics_section())
except Exception as e:
if arguments.debug:
raise