From daaca7fc2953019f93515c5d11093b30812203ad Mon Sep 17 00:00:00 2001 From: Henning Jacobs Date: Sun, 12 May 2019 15:42:16 +0200 Subject: [PATCH] Ingress application (#80) * find application via ingress backend/service * doc string --- deploy/rbac.yaml | 3 ++- kube_resource_report/report.py | 41 ++++++++++++++++++++++++++++++++-- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/deploy/rbac.yaml b/deploy/rbac.yaml index 35279e7..24c52c1 100644 --- a/deploy/rbac.yaml +++ b/deploy/rbac.yaml @@ -10,8 +10,9 @@ metadata: name: kube-resource-report rules: - apiGroups: [""] - resources: ["nodes", "pods", "namespaces"] + resources: ["nodes", "pods", "namespaces", "services"] verbs: + - get - list - apiGroups: ["extensions"] resources: ["ingresses"] diff --git a/kube_resource_report/report.py b/kube_resource_report/report.py index 84f25a8..8914447 100755 --- a/kube_resource_report/report.py +++ b/kube_resource_report/report.py @@ -19,7 +19,7 @@ from jinja2 import Environment, FileSystemLoader, select_autoescape import pykube -from pykube import Namespace, Pod, Node, Ingress +from pykube import Namespace, Pod, Node, Ingress, Service, ObjectDoesNotExist from pykube.objects import APIObject, NamespacedAPIObject from kube_resource_report import cluster_discovery, pricing, filters, __version__ @@ -161,6 +161,38 @@ def get_pod_usage(cluster, pods: dict): logger.exception("Failed to get pod usage metrics") +def find_backend_application(client, ingress, rule): + ''' + The Ingress object might not have a "application" label, so let's try to find the application by looking at the backend service and its pods + ''' + paths = rule.get('http', {}).get('paths', []) + selectors = [] + for path in paths: + service_name = path.get('backend', {}).get('serviceName') + if service_name: + try: + service = Service.objects(client, namespace=ingress.namespace).get(name=service_name) + except ObjectDoesNotExist: + logger.debug(f'Referenced service does not exist: {ingress.namespace}/{service_name}') + else: + selector = service.obj['spec'].get('selector', {}) + selectors.append(selector) + application = get_application_from_labels(selector) + if application: + return application + # we still haven't found the application, let's look up pods by label selectors + for selector in selectors: + application_candidates = set() + for pod in Pod.objects(client).filter(namespace=ingress.namespace, selector=selector): + application = get_application_from_labels(pod.labels) + if application: + application_candidates.add(application) + + if len(application_candidates) == 1: + return application_candidates.pop() + return '' + + def query_cluster( cluster, executor, system_namespaces, additional_cost_per_cluster, no_ingress_status, node_label ): @@ -308,7 +340,12 @@ def query_cluster( application = get_application_from_labels(_ingress.labels) for rule in _ingress.obj["spec"].get("rules", []): host = rule.get('host', '') - ingress = [_ingress.namespace, _ingress.name, application, host, 0] + if not application: + # find the application by getting labels from pods + backend_application = find_backend_application(cluster.client, _ingress, rule) + else: + backend_application = None + ingress = [_ingress.namespace, _ingress.name, application or backend_application, host, 0] if host and not no_ingress_status: try: future = futures_by_host[host]