Skip to content
Permalink
Browse files

8918 Inventory Kubernetes ingresses

This adds entries under the Kubernetes.Ingress node of the
software inventory.  The load balancers, the backends,
and the hosts are listed.

This patch further modifies `check_mk_rbac.yaml` to list ingresses.

This closes CMK-2752.

Change-Id: Id243c446253df3b4a74369edb9e6a16ea3b5c69b
  • Loading branch information...
Synss committed Sep 25, 2019
1 parent 6168b5d commit e7af498879ebb98022c19460e841e9b222f65c3b
@@ -0,0 +1,15 @@
Title: Inventory Kubernetes ingresses
Level: 1
Component: checks
Compatible: incomp
Edition: cre
Version: 1.7.0i1
Date: 1569489519
Class: feature

This adds entries under the Kubernetes.Ingress node of the
software inventory. The load balancers, the backends,
and the hosts are listed.

<b>Note</b> Users must apply the new version of
check_mk_rbac.yml to access the ingresses.
@@ -525,6 +525,7 @@
".software.applications.kubernetes.roles:*.role" : {"title": _("Name")},
".software.applications.kubernetes.roles:*.namespace" : {"title": _("Namespace")},
".software.applications.kubernetes.nodes:*.name" : {"title": _("Name")},
".software.applications.kubernetes.ingresses:": {"title": _("Ingress")},
".software.applications.kubernetes.pod_container:*.name": {"title": _("Name")},
".software.applications.kubernetes.pod_container:*.image": {"title": _("Image")},
".software.applications.kubernetes.pod_container:*.image_pull_policy": {"title": _("Image pull policy")},
@@ -154,6 +154,7 @@ def _valuespec_special_agents_kubernetes():
ListChoice(choices=[
("nodes", _("Nodes")),
("services", _("Services")),
("ingresses", _("Ingresses")),
("deployments", _("Deployments")),
("pods", _("Pods")),
("endpoints", _("Endpoints")),
@@ -164,6 +165,7 @@ def _valuespec_special_agents_kubernetes():
default_value=[
"nodes",
"endpoints",
"ingresses",
],
allow_empty=False,
title=_("Retrieve information about..."))),
@@ -34,7 +34,8 @@
)

import argparse
from collections import OrderedDict, MutableSequence
from collections import OrderedDict, MutableSequence, defaultdict
import contextlib
import functools
import itertools
import json
@@ -56,6 +57,15 @@
import cmk.utils.password_store


@contextlib.contextmanager
def suppress(*exc):
# This is contextlib.suppress from Python 3.2
try:
yield
except exc:
pass


class PathPrefixAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
if not values:
@@ -357,6 +367,53 @@ def replicas(self):
}


class Ingress(Metadata):
def __init__(self, ingress):
super(Ingress, self).__init__(ingress.metadata)
self._backends = [] # list of (path, service_name, service_port)
self._hosts = defaultdict(list) # secret -> list of hosts
self._load_balancers = []

spec = ingress.spec
if spec:
if spec.backend:
self._backends.append(
("(default)", spec.backend.service_name, spec.backend.service_port))
for rule in spec.rules if spec.rules else ():
if rule.http:
for path in rule.http.paths:
path_ = {
(True, True): rule.host + path.path,
(True, False): rule.host,
(False, True): path.path,
(False, False): "/"
}[(rule.host is not None, path.path is not None)]
self._backends.append(
(path_, path.backend.service_name, path.backend.service_port))
for tls in spec.tls if spec.tls else ():
self._hosts[tls.secret_name if tls.secret_name else ""].extend(
tls.hosts if tls.hosts else ())

status = ingress.status
if status:
with suppress(AttributeError):
# Anything along the path to status..ingress is optional (aka may be None).
self._load_balancers.extend([{
"hostname": _.hostname if _.hostname else "",
"ip": _.ip if _.ip else "",
} for _ in status.load_balancer.ingress])

@property
def info(self):
return {
self.name: {
"backends": self._backends,
"hosts": self._hosts,
"load_balancers": self._load_balancers,
}
}


class Pod(Metadata):
def __init__(self, pod):
# type: (client.V1Pod) -> None
@@ -863,6 +920,11 @@ def replicas(self):
return {deployment.name: deployment.replicas for deployment in self}


class IngressList(K8sList[Ingress]):
def infos(self):
return {ingress.name: ingress.info for ingress in self}


class DaemonSetList(K8sList[DaemonSet]):
def info(self):
return {daemon_set.name: daemon_set.info for daemon_set in self}
@@ -1160,6 +1222,7 @@ def __init__(self, api_client):
jobs = batch_api.list_job_for_all_namespaces()
services = core_api.list_service_for_all_namespaces()
deployments = ext_api.list_deployment_for_all_namespaces()
ingresses = ext_api.list_ingress_for_all_namespaces()
daemon_sets = ext_api.list_daemon_set_for_all_namespaces()
stateful_sets = apps_api.list_stateful_set_for_all_namespaces()

@@ -1179,6 +1242,7 @@ def __init__(self, api_client):
self.jobs = JobList(map(Job, jobs.items))
self.services = ServiceList(map(Service, services.items))
self.deployments = DeploymentList(map(Deployment, deployments.items))
self.ingresses = IngressList(map(Ingress, ingresses.items))
self.daemon_sets = DaemonSetList(map(DaemonSet, daemon_sets.items))
self.stateful_sets = StatefulSetList(map(StatefulSet, stateful_sets.items))

@@ -1315,12 +1379,19 @@ def service_sections(self):
return '\n'.join(g.output(piggyback_prefix="service_"))

def deployment_sections(self):
logging.info('Output node sections')
logging.info('Output deployment sections')
g = PiggybackGroup()
g.join('labels', self.deployments.labels())
g.join('k8s_replicas', self.deployments.replicas())
return '\n'.join(g.output(piggyback_prefix="deployment_"))

def ingress_sections(self):
logging.info('Output ingress sections')
g = PiggybackGroup()
g.join('labels', self.ingresses.labels())
g.join('k8s_ingress_infos', self.ingresses.infos())
return '\n'.join(g.output(piggyback_prefix="ingress_"))

def daemon_set_sections(self):
logging.info('Daemon set sections')
g = PiggybackGroup()
@@ -1387,6 +1458,8 @@ def main(args=None):
print(api_data.job_sections())
if 'deployments' in arguments.infos:
print(api_data.deployment_sections())
if 'ingresses' in arguments.infos:
print(api_data.ingress_sections())
if 'services' in arguments.infos:
print(api_data.service_sections())
if 'daemon_sets' in arguments.infos:
@@ -46,6 +46,7 @@ rules:
- daemonsets
- deployments
- replicasets
- ingresses
verbs: ["get", "list"]
- apiGroups: ["apps"]
resources:
@@ -0,0 +1,60 @@
#!/usr/bin/env python
# -*- encoding: utf-8; py-indent-offset: 4 -*-
#!/usr/bin/env python
# -*- encoding: utf-8; py-indent-offset: 4 -*-
# +------------------------------------------------------------------+
# | ____ _ _ __ __ _ __ |
# | / ___| |__ ___ ___| | __ | \/ | |/ / |
# | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
# | | |___| | | | __/ (__| < | | | | . \ |
# | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
# | |
# | Copyright Mathias Kettner 2019 mk@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 _parse_hosts(hosts):
results = []
for secret_name, hosts_ in hosts.iteritems():
results.extend({"host": host, "secret_name": secret_name} for host in hosts_)
return results


def _parse_backends(backends):
return [{
"path": path,
"service_name": service_name,
"service_port": service_port,
} for path, service_name, service_port in backends]


def inv_k8s_ingresses(info, inventory_tree, status_data_tree):
parsed = parse_k8s(info)
path = "software.applications.kubernetes.ingresses.%s:"
for name, data in sorted(parsed.iteritems()):
inv_node = inventory_tree.get_dict(path % name)
inv_node.update({
'backends': _parse_backends(data['backends']),
'hosts': _parse_hosts(data['hosts']),
'load_balancers': data['load_balancers'],
})


inv_info['k8s_ingress_infos'] = {
'inv_function': inv_k8s_ingresses,
'includes': ['k8s.include'],
}
@@ -6090,6 +6090,7 @@ def test_registered_display_hints(load_plugins):
'.software.applications.kubernetes.assigned_pods:*.name',
'.software.applications.kubernetes.nodes:',
'.software.applications.kubernetes.nodes:*.name',
'.software.applications.kubernetes.ingresses:',
'.software.applications.kubernetes.pod_container:',
'.software.applications.kubernetes.pod_container:*.container_id',
'.software.applications.kubernetes.pod_container:*.image',

0 comments on commit e7af498

Please sign in to comment.
You can’t perform that action at this time.