Module: check_mk
Branch: master
Commit: 0c7864b20bbf8dc2bcb7536c5787441ee492a24e
URL:
http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=0c7864b20bbf8d…
Author: Tom Baerwinkel <tb(a)mathias-kettner.de>
Date: Thu Mar 28 13:47:44 2019 +0100
agent_kubernetes, k8s_service_info: HW/SW inventory for services
Kubernetes services are now provided as piggyback data by the
agent_kubernetes. The inventory plugin k8s_service_info shows
some general information about a service in the HW/SW inventory.
Change-Id: If9f5e4e077d033ce914ed27ab780a0681778a9a6
---
cmk/gui/plugins/views/inventory.py | 6 +++
cmk/gui/plugins/wato/datasource_programs.py | 3 +-
cmk/special_agents/agent_kubernetes.py | 81 +++++++++++++++++++++++++++++
inventory/k8s_service_info | 41 +++++++++++++++
4 files changed, 130 insertions(+), 1 deletion(-)
diff --git a/cmk/gui/plugins/views/inventory.py b/cmk/gui/plugins/views/inventory.py
index 24edb67..8aa0629 100644
--- a/cmk/gui/plugins/views/inventory.py
+++ b/cmk/gui/plugins/views/inventory.py
@@ -1115,6 +1115,12 @@ inventory_displayhints.update({
".software.applications.kubernetes.pod_info.host_ip": {"title":
_("Host IP")},
".software.applications.kubernetes.pod_info.pod_ip": {"title":
_("Pod IP")},
".software.applications.kubernetes.pod_info.qos_class": {"title":
_("QOS class")},
+ ".software.applications.kubernetes.service_info.": {
+ "title": _("Service"),
+ },
+ ".software.applications.kubernetes.service_info.type": {"title":
_("Type")},
+ ".software.applications.kubernetes.service_info.cluster_ip":
{"title": _("Cluster IP")},
+ ".software.applications.kubernetes.service_info.load_balancer_ip":
{"title": _("Load Balancer IP")},
".software.applications.citrix.": {"title":
_("Citrix")},
".software.applications.citrix.controller.": {"title":
_("Controller")},
".software.applications.citrix.controller.controller_version": {
diff --git a/cmk/gui/plugins/wato/datasource_programs.py
b/cmk/gui/plugins/wato/datasource_programs.py
index a35b3d1..e74b0b6 100644
--- a/cmk/gui/plugins/wato/datasource_programs.py
+++ b/cmk/gui/plugins/wato/datasource_programs.py
@@ -150,8 +150,9 @@ class RulespecSpecialAgentsKubernetes(HostRulespec):
ListChoice(
choices=[
("nodes", _("Nodes")),
- ("pods", _("Pods")),
+ ("services", _("Services")),
("deployments", _("Deployments")),
+ ("pods", _("Pods")),
],
default_value=[
"nodes",
diff --git a/cmk/special_agents/agent_kubernetes.py
b/cmk/special_agents/agent_kubernetes.py
index c40ffb5..641cec6 100644
--- a/cmk/special_agents/agent_kubernetes.py
+++ b/cmk/special_agents/agent_kubernetes.py
@@ -251,6 +251,67 @@ class ComponentStatus(Metadata):
return [{'type': c.type, 'status': c.status} for c in
self._conditions]
+class Service(Metadata):
+ def __init__(self, service):
+ super(Service, self).__init__(service.metadata)
+
+ spec = service.spec
+ if spec:
+ # For details refer to:
+ #
https://github.com/kubernetes-client/python/blob/master/kubernetes/docs/V1S…
+
+ # type may be: ExternalName, ClusterIP, NodePort, and LoadBalancer
+ self._type = spec.type
+ self._selector = spec.selector if spec.selector else {}
+ # cluster_ip may be: None (headless service), "" (no IP), or a str
(valid IP)
+ self._cluster_ip = spec.cluster_ip
+ # only applies to type LoadBalancer
+ self._load_balancer_ip = spec.load_balancer_ip
+ self._ports = spec.ports if spec.ports else []
+ else:
+ self._type_ = None
+ self._selector = {}
+ self._cluster_ip = ""
+ self._load_balancer_ip = ""
+ self._ports = []
+
+ status = service.status
+ if status and status.load_balancer and status.load_balancer.ingress:
+ self._ingress = {
+ {
+ # for ingress points that are DNS based (typically AWS
load-balancers)
+ 'hostname': ingress.hostname,
+ # for ingress points that are IP based (typically GCE or OpenStack
load-balancers)
+ 'ip': ingress.ip
+ } for ingress in status.load_balancer.ingress
+ }
+
+ @property
+ def info(self):
+ return {
+ 'type': self._type,
+ 'selector': self._selector,
+ 'cluster_ip': self._cluster_ip,
+ 'load_balancer_ip': self._load_balancer_ip,
+ }
+
+ @property
+ def selector(self):
+ return self._selector
+
+ @property
+ def ports(self):
+ # port is the only field that is not optional
+ return {
+ port.port: {
+ 'name': port.name,
+ 'protocol': port.protocol,
+ 'target_port': port.target_port,
+ 'node_port': port.node_port,
+ } for port in self._ports
+ }
+
+
class Deployment(Metadata):
# TODO: include pods of the deployment?
def __init__(self, deployment):
@@ -543,6 +604,14 @@ class ComponentStatusList(K8sList[ComponentStatus]):
return {status.name: status.conditions for status in self if status.name}
+class ServiceList(K8sList[Service]):
+ def infos(self):
+ return {service.name: service.info for service in self}
+
+ def ports(self):
+ return {service.name: service.ports for service in self}
+
+
class DeploymentList(K8sList[Deployment]):
def replicas(self):
return {deployment.name: deployment.replicas for deployment in self}
@@ -804,6 +873,7 @@ class ApiData(object):
pvs = core_api.list_persistent_volume()
pvcs = core_api.list_persistent_volume_claim_for_all_namespaces()
pods = core_api.list_pod_for_all_namespaces()
+ services = core_api.list_service_for_all_namespaces()
deployments = apps_api.list_deployment_for_all_namespaces()
logging.debug('Assigning collected data')
@@ -818,6 +888,7 @@ class ApiData(object):
self.persistent_volume_claims = PersistentVolumeClaimList(
map(PersistentVolumeClaim, pvcs.items))
self.pods = PodList(map(Pod, pods.items))
+ self.services = ServiceList(map(Service, services.items))
self.deployments = DeploymentList(map(Deployment, deployments.items))
pods_custom_metrics = {
@@ -920,6 +991,14 @@ class ApiData(object):
g.join('k8s_pod_info', self.pods.info())
return '\n'.join(g.output())
+ def service_sections(self):
+ logging.info('Output service sections')
+ g = Group()
+ g.join('labels', self.services.labels())
+ g.join('k8s_service_info', self.services.infos())
+ g.join('k8s_service_ports', self.services.ports())
+ return '\n'.join(g.output())
+
def deployment_sections(self):
logging.info('Output node sections')
g = Group()
@@ -973,6 +1052,8 @@ def main(args=None):
print(api_data.pod_sections())
if 'deployments' in arguments.infos:
print(api_data.deployment_sections())
+ if 'services' in arguments.infos:
+ print(api_data.service_sections())
except Exception as e:
if arguments.debug:
raise
diff --git a/inventory/k8s_service_info b/inventory/k8s_service_info
new file mode 100644
index 0000000..e38639e
--- /dev/null
+++ b/inventory/k8s_service_info
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8; py-indent-offset: 4 -*-
+# +------------------------------------------------------------------+
+# | ____ _ _ __ __ _ __ |
+# | / ___| |__ ___ ___| | __ | \/ | |/ / |
+# | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
+# | | |___| | | | __/ (__| < | | | | . \ |
+# | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
+# | |
+# | Copyright Mathias Kettner 2019 mk(a)mathias-kettner.de |
+# +------------------------------------------------------------------+
+#
+# This file is part of Check_MK.
+# The official homepage is at
http://mathias-kettner.de/check_mk.
+#
+# check_mk is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation in version 2. check_mk is distributed
+# in the hope that it will be useful, but WITHOUT ANY WARRANTY; with-
+# out even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. See the GNU General Public License for more de-
+# tails. You should have received a copy of the GNU General Public
+# License along with GNU Make; see the file COPYING. If not, write
+# to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+# Boston, MA 02110-1301 USA.
+
+
+def inv_k8s_service_info(info, inventory_tree):
+ parsed = parse_k8s(info)
+
+ path = "software.applications.kubernetes.service_info."
+ inv_node = inventory_tree.get_dict(path)
+
+ for key, value in sorted(parsed.iteritems()):
+ inv_node[key] = value
+
+
+inv_info['k8s_service_info'] = {
+ 'inv_function': inv_k8s_service_info,
+ 'includes': ['k8s.include'],
+}
\ No newline at end of file