Example #1
0
def generate_metrics(namespaces):

    metrics = []

    if not namespaces:
        print("No namespaces specified, watching all namespaces\n")
        v1_namespaces = dyn_client.resources.get(api_version='v1', kind='Namespace')
        namespaces = [namespace.metadata.name for namespace in v1_namespaces.get(
            label_selector=pelorus.get_prod_label()).items]
    else:
        print("Watching namespaces: %s\n" % (namespaces))

    for namespace in namespaces:
        v1_replicationcontrollers = dyn_client.resources.get(api_version='v1', kind='ReplicationController')
        replicationcontrollers = v1_replicationcontrollers.get(namespace=namespace,
                                                               label_selector=pelorus.get_app_label())

        for rc in replicationcontrollers.items:
            images = [image_sha(c.image) for c in rc.spec.template.spec.containers]

            # Since a commit will be built into a particular image and there could be multiple
            # containers (images) per pod, we will push one metric per image/container in the
            # pod template
            for i in images:
                if i is not None:
                    metric = DeployTimeMetric(rc.metadata.name, namespace)
                    metric.labels = rc.metadata.labels
                    metric.deploy_time = rc.metadata.creationTimestamp
                    metric.image_sha = i
                    metrics.append(metric)

    return metrics
Example #2
0
    def generate_metrics(self) -> Iterable[CommitMetric]:
        """Method called by the collect to create a list of metrics to publish"""
        # This will loop and look at OCP builds (calls get_git_commit_time)
        if not self._namespaces:
            logging.info("No namespaces specified, watching all namespaces")
            v1_namespaces = self._kube_client.resources.get(
                api_version="v1", kind="Namespace"
            )
            self._namespaces = [
                namespace.metadata.name for namespace in v1_namespaces.get().items
            ]
        else:
            logging.info("Watching namespaces: %s" % (self._namespaces))

        # Initialize metrics list
        metrics = []
        for namespace in self._namespaces:
            # Initialized variables
            builds = []
            apps = []
            builds_by_app = {}
            app_label = pelorus.get_app_label()
            logging.debug(
                "Searching for builds with label: %s in namespace: %s"
                % (app_label, namespace)
            )

            v1_builds = self._kube_client.resources.get(
                api_version="build.openshift.io/v1", kind="Build"
            )
            # only use builds that have the app label
            builds = v1_builds.get(namespace=namespace, label_selector=app_label)

            # use a jsonpath expression to find all values for the app label
            jsonpath_str = (
                "$['items'][*]['metadata']['labels']['" + str(app_label) + "']"
            )
            jsonpath_expr = parse(jsonpath_str)

            found = jsonpath_expr.find(builds)

            apps = [match.value for match in found]

            if not apps:
                continue
            # remove duplicates
            apps = list(dict.fromkeys(apps))
            builds_by_app = {}

            for app in apps:
                builds_by_app[app] = list(
                    filter(lambda b: b.metadata.labels[app_label] == app, builds.items)
                )

            metrics += self.get_metrics_from_apps(builds_by_app, namespace)

        return metrics
Example #3
0
    def generate_commit_metrics_list(self, namespaces):

        if not namespaces:
            logging.info("No namespaces specified, watching all namespaces")
            v1_namespaces = dyn_client.resources.get(api_version='v1',
                                                     kind='Namespace')
            namespaces = [
                namespace.metadata.name
                for namespace in v1_namespaces.get().items
            ]
        else:
            logging.info("Watching namespaces: %s" % (namespaces))

        # Initialize metrics list
        metrics = []
        for namespace in namespaces:
            # Initialized variables
            builds = []
            apps = []
            builds_by_app = {}
            app_label = pelorus.get_app_label()
            logging.info(
                "Searching for builds with label: %s in namespace: %s" %
                (app_label, namespace))

            v1_builds = dyn_client.resources.get(
                api_version='build.openshift.io/v1', kind='Build')
            # only use builds that have the app label
            builds = v1_builds.get(namespace=namespace,
                                   label_selector=app_label)

            # use a jsonpath expression to find all values for the app label
            jsonpath_str = "$['items'][*]['metadata']['labels']['" + str(
                app_label) + "']"
            jsonpath_expr = parse(jsonpath_str)

            found = jsonpath_expr.find(builds)

            apps = [match.value for match in found]

            if not apps:
                continue
            # remove duplicates
            apps = list(dict.fromkeys(apps))
            builds_by_app = {}

            for app in apps:
                builds_by_app[app] = list(
                    filter(lambda b: b.metadata.labels[app_label] == app,
                           builds.items))

            metrics += self.get_metrics_from_apps(builds_by_app, namespace)

        return metrics
Example #4
0
def get_replicas(
    dyn_client: DynamicClient, apiVersion: str, objectName: str
) -> dict[str, object]:
    """Process Replicas for given Api Version and Object type (ReplicaSet or ReplicationController)"""
    try:
        apiResource = dyn_client.resources.get(api_version=apiVersion, kind=objectName)
        replicationobjects = apiResource.get(label_selector=pelorus.get_app_label())
        return {
            f"{replica.metadata.namespace}/{replica.metadata.name}": replica
            for replica in replicationobjects.items
        }
    except ResourceNotFoundError:
        logging.debug(
            "API Object not found for version: %s object: %s", apiVersion, objectName
        )
    return {}
Example #5
0
def get_replicas(apiVersion, objectName):
    # Process Replicas for given Api Version and Object type (ReplicaSet or ReplicationController)
    replicas = {}
    try:
        apiResource = dyn_client.resources.get(api_version=apiVersion,
                                               kind=objectName)
        replicationobjects = apiResource.get(
            label_selector=pelorus.get_app_label())
        for replica in replicationobjects.items:
            replicas[replica.metadata.namespace + "/" +
                     replica.metadata.name] = replica
    except ResourceNotFoundError:
        logging.debug("API Object not found for version: %s object: %s",
                      apiVersion, objectName)
        pass
    return replicas
Example #6
0
def generate_metrics(
    namespaces: NamespaceSpec, dyn_client: DynamicClient
) -> Iterable[DeployTimeMetric]:
    visited_replicas = set()

    def already_seen(full_path: str) -> bool:
        return full_path in visited_replicas

    def mark_as_seen(full_path: str):
        visited_replicas.add(full_path)

    logging.info("generate_metrics: start")

    v1_pods = dyn_client.resources.get(api_version="v1", kind="Pod")
    log_namespaces(namespaces)

    def in_namespace(namespace: str) -> bool:
        return (not namespaces) or namespace in namespaces

    pods = v1_pods.get(
        label_selector=pelorus.get_app_label(), field_selector="status.phase=Running"
    ).items

    replicas_dict = (
        get_replicas(dyn_client, "v1", "ReplicationController")
        | get_replicas(dyn_client, "apps/v1", "ReplicaSet")
        | get_replicas(dyn_client, "extensions/v1beta1", "ReplicaSet")
    )

    for pod in pods:
        namespace = pod.metadata.namespace
        owner_refs = pod.metadata.ownerReferences
        if not in_namespace(namespace) or not owner_refs:
            continue

        logging.debug(
            "Getting Replicas for pod: %s in namespace: %s",
            pod.metadata.name,
            pod.metadata.namespace,
        )

        # Get deploytime from the owning controller of the pod.
        # We track all already-visited controllers to not duplicate metrics per-pod.
        for ref in owner_refs:
            full_path = f"{namespace}/{ref.name}"

            if ref.kind not in supported_replica_objects or already_seen(full_path):
                continue

            logging.debug(
                "Getting replica: %s, kind: %s, namespace: %s",
                ref.name,
                ref.kind,
                namespace,
            )

            if not (rc := replicas_dict.get(full_path)):
                continue

            mark_as_seen(full_path)
            images = (sha for c in pod.spec.containers if (sha := image_sha(c.image)))
Example #7
0
                ref.kind,
                namespace,
            )

            if not (rc := replicas_dict.get(full_path)):
                continue

            mark_as_seen(full_path)
            images = (sha for c in pod.spec.containers if (sha := image_sha(c.image)))

            # Since a commit will be built into a particular image and there could be multiple
            # containers (images) per pod, we will push one metric per image/container in the
            # pod template
            for sha in images:
                metric = DeployTimeMetric(
                    name=rc.metadata.labels[pelorus.get_app_label()],
                    namespace=namespace,
                    labels=rc.metadata.labels,
                    deploy_time=rc.metadata.creationTimestamp,
                    image_sha=sha,
                )
                yield metric


def get_replicas(
    dyn_client: DynamicClient, apiVersion: str, objectName: str
) -> dict[str, object]:
    """Process Replicas for given Api Version and Object type (ReplicaSet or ReplicationController)"""
    try:
        apiResource = dyn_client.resources.get(api_version=apiVersion, kind=objectName)
        replicationobjects = apiResource.get(label_selector=pelorus.get_app_label())
Example #8
0
 def get_app_name(self, issue):
     app_label = pelorus.get_app_label()
     for label in issue.fields.labels:
         if label.startswith("%s=" % app_label):
             return label.replace("%s=" % app_label, "")
     return "unknown"
Example #9
0
from random import randrange
from typing import Sequence
from unittest.mock import NonCallableMock

import pytest
from deploytime.app import DeployTimeMetric, generate_metrics, image_sha  # type: ignore
from openshift.dynamic import DynamicClient  # type: ignore
from openshift.dynamic.discovery import Discoverer  # type: ignore
from tests.openshift_mocks import *

import pelorus

# pylava:ignore=W0401

# region test constants
APP_LABEL = pelorus.get_app_label()

FOO_NS = "foo_ns"
BAR_NS = "bar_ns"
BAZ_NS = "baz_ns"

FOO_APP = "foo_app"
BAR_APP = "bar_app"

FOO_LABEL = "foo_label"
FOO_LABEL_VALUE = "test"

REPLICA_SET = "ReplicaSet"
REP_CONTROLLER = "ReplicationController"
UNKNOWN_OWNER_KIND = "UnknownOwnerKind"
Example #10
0
def generate_metrics(namespaces):

    metrics = []
    pods = []
    pod_replica_dict = {}

    logging.info("generate_metrics: start")

    v1_pods = dyn_client.resources.get(api_version='v1', kind='Pod')
    if not namespaces:
        logging.info("No namespaces specified, watching all namespaces")
    else:
        logging.info("Watching namespaces %s", namespaces)

    pods = v1_pods.get(label_selector=pelorus.get_app_label(),
                       field_selector='status.phase=Running').items

    replicas_dict = {}
    # Process ReplicationControllers for DeploymentConfigs
    replicas_dict = get_replicas('v1', 'ReplicationController')

    # Process ReplicaSets from apps/v1 api version for Deployments
    replicas_dict.update(get_replicas('apps/v1', 'ReplicaSet'))

    # Process ReplicaSets from extentions/v1beta1 api version for Deployments
    replicas_dict.update(get_replicas('extensions/v1beta1', 'ReplicaSet'))

    for pod in pods:
        if (not namespaces or
            (pod.metadata.namespace
             in namespaces)) and pod.metadata.ownerReferences:
            logging.debug("Getting Replicas for pod: %s in namespace: %s",
                          pod.metadata.name, pod.metadata.namespace)
            ownerRefs = pod.metadata.ownerReferences
            namespace = pod.metadata.namespace

            # use the replica controller/replicasets to get deploy timestame.  The ownerRef of pod is used to get
            # replicaiton controller.  A dictionary is used to handle dups when multiple pods are running.
            for ownerRef in ownerRefs:
                if (ownerRef.kind in supported_replica_objects
                        and not pod_replica_dict.get(namespace + "/" +
                                                     ownerRef.name)):

                    logging.debug(
                        "Getting replica: %s, kind: %s, namespace: %s",
                        ownerRef.name, ownerRef.kind, namespace)

                    if replicas_dict.get(namespace + "/" + ownerRef.name):
                        rc = replicas_dict.get(namespace + "/" + ownerRef.name)
                        pod_replica_dict[namespace + "/" +
                                         ownerRef.name] = "DONE"
                        images = [
                            image_sha(c.image) for c in pod.spec.containers
                        ]

                        # Since a commit will be built into a particular image and there could be multiple
                        # containers (images) per pod, we will push one metric per image/container in the
                        # pod template
                        for i in images:
                            if i is not None:
                                metric = DeployTimeMetric(
                                    rc.metadata.labels[
                                        pelorus.get_app_label()], namespace)
                                metric.labels = rc.metadata.labels
                                metric.deploy_time = rc.metadata.creationTimestamp
                                metric.image_sha = i
                                metric.namespace = namespace
                                metrics.append(metric)

    return metrics
Example #11
0
def test_get_app_label():
    assert pelorus.get_app_label() == pelorus.DEFAULT_APP_LABEL
    os.environ["APP_LABEL"] = "changed"
    assert pelorus.get_app_label() == "changed"
    os.unsetenv("APP_LABEL")