def test_kubernetes_api_resources_get_short_name(
        kubernetes_api_resources_obj: KubernetesApiResources) -> None:
    """
    This test verifies that KubernetesApiResources.get_short_name() returns the correct value for a defined resource.

    :param kubernetes_api_resources_obj: The pre-loaded KubernetesApiResources fixture object for testing.
    """
    assert kubernetes_api_resources_obj.get_short_name("APIService") == ""
def test_kubernetes_api_resources_is_available_true(
        kubernetes_api_resources_obj: KubernetesApiResources) -> None:
    """
    This test verifies that KubernetesApiResources.is_available() correctly reports a defined resource as available.

    :param kubernetes_api_resources_obj: The pre-loaded KubernetesApiResources fixture object for testing.
    """
    assert kubernetes_api_resources_obj.is_available("APIService") is True
def test_kubernetes_api_resources_is_namespaced_missing(
        kubernetes_api_resources_obj: KubernetesApiResources) -> None:
    """
    This test verifies that KubernetesApiResources.is_namespaced() returns None for an undefined resource.

    :param kubernetes_api_resources_obj: The pre-loaded KubernetesApiResources fixture object for testing.
    """
    assert kubernetes_api_resources_obj.get_api_group("FooKind") is None
def test_kubernetes_api_resources_kind_as_dict_missing(
        kubernetes_api_resources_obj: KubernetesApiResources) -> None:
    """
    This test verifies that KubernetesApiResources.kind_as_dict() returns None for an undefined resource.

    :param kubernetes_api_resources_obj: The pre-loaded KubernetesApiResources fixture object for testing.
    """
    assert kubernetes_api_resources_obj.kind_as_dict("FooKind") is None
def test_kubernetes_api_resources_get_verbs_missing(
        kubernetes_api_resources_obj: KubernetesApiResources) -> None:
    """
    This test verifies that KubernetesApiResources.get_verbs() returns None when for an undefined resource.

    :param kubernetes_api_resources_obj: The pre-loaded KubernetesApiResources fixture object for testing.
    """
    assert kubernetes_api_resources_obj.get_verbs("FooKind") is None
def test_kubernetes_api_resources_is_namespaced(
        kubernetes_api_resources_obj: KubernetesApiResources) -> None:
    """
    This test verifies that KubernetesApiResources.is_namespaced() returns the correct value for a defined resource.

    :param kubernetes_api_resources_obj: The pre-loaded KubernetesApiResources fixture object for testing.
    """
    assert kubernetes_api_resources_obj.is_namespaced("APIService") is True
def test_kubernetes_api_resources_is_available_false(
        kubernetes_api_resources_obj: KubernetesApiResources) -> None:
    """
    This test verifies that KubernetesApiResources.is_available() correctly reports an undefined resource as not
    available.

    :param kubernetes_api_resources_obj: The pre-loaded KubernetesApiResources fixture object for testing.
    """
    assert kubernetes_api_resources_obj.is_available("FooKind") is False
def kubernetes_api_resources_obj() -> KubernetesApiResources:
    """
    This pytest fixture loads a KubernetesApiResources object representing the API resources as they might be returned
    from kubectl. With the "module" scope, this is only run once before the tests defined in this file are executed.

    :return: A KubernetesApiResources object loaded with Kubernetes API resource definitions for testing.
    """
    api_resources_dict: Dict = load_test_data(_API_RESOURCES_TEST_DATA_)
    return KubernetesApiResources(api_resources_dict)
def test_kubernetes_api_resources_get_api_group(
        kubernetes_api_resources_obj: KubernetesApiResources) -> None:
    """
    This test verifies that KubernetesApiResources.get_api_group() returns the correct API group for a defined
    resource.

    :param kubernetes_api_resources_obj: The pre-loaded KubernetesApiResources fixture object for testing.
    """
    assert kubernetes_api_resources_obj.get_api_group(
        "APIService") == "apiregistration.k8s.io"
def test_kubernetes_api_resources_get_verbs(
        kubernetes_api_resources_obj: KubernetesApiResources) -> None:
    """
    This test verifies that KubernetesApiResources.get_verbs() returns the correct value for a defined resource.

    :param kubernetes_api_resources_obj: The pre-loaded KubernetesApiResources fixture object for testing.
    """
    assert kubernetes_api_resources_obj.get_verbs("APIService") == [
        "create", "delete", "deletecollection", "get", "list", "patch",
        "update", "watch"
    ]
def test_kubernetes_api_resources_as_dict(
        kubernetes_api_resources_obj: KubernetesApiResources) -> None:
    """
    This test verifies that KubernetesApiResources.as_dict() returns the correct dictionary.

    :param kubernetes_api_resources_obj: The pre-loaded KubernetesApiResources fixture object for testing.
    """
    # convert the object to a dict
    converted_api_resources: Dict = kubernetes_api_resources_obj.as_dict()

    # make sure a dict was returned, it's the correct length, and has the expected keys
    assert isinstance(converted_api_resources, dict)
    assert len(converted_api_resources) == 1
    assert "APIService" in converted_api_resources
Exemple #12
0
    def api_resources(self,
                      ignore_errors: bool = False) -> KubernetesApiResources:
        # check for ingress simulation to determine which API resources should be returned
        if self.ingress_simulator == self.IngressSimulator.NONE:
            api_resources_data: Dict = KubectlTest._load_response_data(
                _API_RESOURCES_NO_INGRESS_DATA_)
        elif self.ingress_simulator == self.IngressSimulator.NGINX_ONLY:
            api_resources_data: Dict = KubectlTest._load_response_data(
                _API_RESOURCES_NGINX_ONLY_DATA_)
        elif self.ingress_simulator == self.IngressSimulator.ISTIO_ONLY:
            api_resources_data: Dict = KubectlTest._load_response_data(
                _API_RESOURCES_ISTIO_ONLY_DATA_)
        else:
            api_resources_data: Dict = KubectlTest._load_response_data(
                _API_RESOURCES_BOTH_INGRESS_DATA_)

        return KubernetesApiResources(api_resources_data)
def test_kubernetes_api_resources_kind_as_dict(
        kubernetes_api_resources_obj: KubernetesApiResources) -> None:
    """
    This test verifies that KubernetesApiResources.kind_as_dict() returns the correct dictionary for a defined resource.

    :param kubernetes_api_resources_obj: The pre-loaded KubernetesApiResources fixture object for testing.
    """
    # get a single kind as a dict
    details: Dict = kubernetes_api_resources_obj.kind_as_dict("APIService")

    # verify that a dict was returned, it's the correct length, and has the expected keys
    assert isinstance(details, dict)
    assert len(details) == 5
    assert KubernetesApiResources.Keys.API_GROUP in details
    assert KubernetesApiResources.Keys.NAME in details
    assert KubernetesApiResources.Keys.NAMESPACED in details
    assert KubernetesApiResources.Keys.SHORT_NAME in details
    assert KubernetesApiResources.Keys.VERBS in details
def test_kubernetes_api_resources_kind_as_dict_incomplete() -> None:
    """
    This test verifies that KubernetesApiResources.kind_as_dict() returns None when no resources are defined.
    """
    assert KubernetesApiResources(dict()).kind_as_dict("APIService") is None
    def gather_resource_details(kubectl: KubectlInterface,
                                gathered_resources: Dict,
                                api_resources: KubernetesApiResources,
                                resource_kind: Text,
                                is_owning_resource: bool = False) -> None:
        """
        Static method for gather details about resources in the target Kubernetes cluster.

        The method is called recursively and will gather details about any resources described in current resource's
        "ownerReferences", if defined. If all discovered resource kinds are listable, a complete ownership chain will be
        gathered.

        :param kubectl: The KubectlInterface object for issuing requests to the target Kubernetes cluster.
        :param gathered_resources: The dictionary where gathered resources will be stored.
        :param api_resources: The Kubectle.ApiResources object defining the API resources of the target Kubernetes
                              cluster.
        :param resource_kind: The 'kind' value of the resources to gather.
        :param is_owning_resource: INTERNAL PARAMETER - DO NOT PROVIDE A VALUE. A parameter set internally to note that
                                   the current resource is an owning resource for recursive calls.

        """
        # if an attempt has been made to gather this kind, return without moving forward #
        if resource_kind in gathered_resources:
            return

        # get the requested resources from the k8s API #
        resource_name: Text = api_resources.get_name(resource_kind)
        resources: List[KubernetesResource] = list()
        resource_available: bool = True
        if resource_name is not None:
            try:
                resources: Optional[
                    List[KubernetesResource]] = kubectl.get_resources(
                        api_resources.get_name(resource_kind))
            except CalledProcessError as e:
                if resource_kind == KubernetesResource.Kinds.POD:
                    # if a CalledProcessError is raised for pods, surface the error #
                    # if the resource kind is not "Pod", move forward without raising an error since #
                    # pods can still be reported #
                    raise e
                else:
                    # note that this resource was not available
                    resource_available = False

        # save the resources by kind #
        gathered_resources[resource_kind]: Dict = dict()

        # create a key to note whether this resource kind was available for listing: bool #
        gathered_resources[resource_kind][
            Keys.KindDetails.AVAILABLE]: bool = resource_available

        # create a key to define the number of resources of this kind returned by k8s: int #
        gathered_resources[resource_kind][Keys.KindDetails.COUNT]: int = len(
            resources)

        # create a key to hold the resources returned by k8s: dict #
        gathered_resources[resource_kind][ITEMS_KEY]: bool = dict()

        # store a unique list of kinds in any 'ownerReferences' definitions #
        owner_kinds: List = list()

        # loop over the resources returned #
        for resource in resources:
            # add the resource to its kind dictionary                                                             #
            # create a key set to the name of the resource, under which all resource details will be stored: dict #
            resource_details = gathered_resources[resource_kind][ITEMS_KEY][
                resource.get_name()] = dict()

            # create a key to hold extra details about the resource not provided in the resource definition: dict #
            resource_details[Keys.ResourceDetails.EXT_DICT]: Dict = dict()

            # create a key to hold the ext.relationships list, which defines the name and kind of resources #
            # related to this resource: list                                                                 #
            resource_relationship_list = resource_details[
                Keys.ResourceDetails.EXT_DICT][
                    Keys.ResourceDetails.Ext.RELATIONSHIPS_LIST] = list()

            # create a key under which the resource definition will be stored: KubernetesResource #
            resource_details[
                Keys.ResourceDetails.
                RESOURCE_DEFINITION]: KubernetesResource = resource

            # see if this resource defines any 'ownerReferences' #
            owner_references: List = resource.get_metadata_value(
                KubernetesResource.Keys.OWNER_REFERENCES)

            # if the resource does define 'ownerReferences', process them #
            if owner_references is not None:
                # iterate over the references #
                for owner_reference in owner_references:
                    # if the owner reference kind isn't in the owner_kinds list, add it #
                    if owner_reference[
                            KubernetesResource.Keys.KIND] not in owner_kinds:
                        owner_kinds.append(
                            owner_reference[KubernetesResource.Keys.KIND])

                    # add the owning object to the resource's relationships extension list #
                    relationship: Dict = ViyaDeploymentReportUtils._create_relationship_dict(
                        owner_reference[KubernetesResource.Keys.KIND],
                        owner_reference[KubernetesResource.Keys.NAME])

                    resource_relationship_list.append(relationship)
            elif owner_references is None and is_owning_resource:
                # if this resource doesn't have any owner references, but it does own resources, use it as the #
                # resource to determine a component name as this must be the resource furthest upstream        #
                # (i.e. a probable controller)                                                                 #
                component_name: Text = resource.get_name()

                # if a SAS component name is defined, use it instead
                if resource.get_annotation(
                        KubernetesResource.Keys.ANNOTATION_COMPONENT_NAME
                ) is not None:
                    component_name = resource.get_annotation(
                        KubernetesResource.Keys.ANNOTATION_COMPONENT_NAME)

                # define the component name value #
                resource_details[Keys.ResourceDetails.EXT_DICT][Keys.ResourceDetails.Ext.COMPONENT_NAME]: Text = \
                    component_name

        # if more kinds have been discovered, gather them as well #
        for owner_kind in owner_kinds:
            ViyaDeploymentReportUtils.gather_resource_details(
                kubectl,
                gathered_resources,
                api_resources,
                owner_kind,
                is_owning_resource=True)
def test_kubernetes_api_resources_is_namespaced_incomplete() -> None:
    """
    This test verifies that KubernetesApiResources.is_namespaced() returns None when no resources are defined.
    """
    assert KubernetesApiResources(dict()).is_namespaced("APIService") is None
def test_kubernetes_api_resources_is_available_incomplete() -> None:
    """
    This test verifies that KubernetesApiResources.is_available() correctly reports a resource as not available when
    no resources are defined.
    """
    assert KubernetesApiResources(dict()).is_available("APIService") is False
Exemple #18
0
    def api_resources(self,
                      ignore_errors: bool = False) -> KubernetesApiResources:
        # get the api-resources and convert the response into a list #
        api_resource_info: AnyStr = self.do("api-resources -o wide",
                                            ignore_errors)
        api_resource_lines: List = api_resource_info.decode().split("\n")
        api_resource_headers: Text = api_resource_lines[0]

        # get the index of all expected headers #
        name_index: int = api_resource_headers.index(_HEADER_NAME_)
        shortname_index: int = api_resource_headers.index(_HEADER_SHORTNAME_)
        apigroup_index: int = api_resource_headers.index(_HEADER_APIGROUP_)
        namespaced_index: int = api_resource_headers.index(_HEADER_NAMESPACED_)
        kind_index: int = api_resource_headers.index(_HEADER_KIND_)
        verbs_index: int = api_resource_headers.index(_HEADER_VERBS_)

        # set up the dictionary that will be returned #
        api_resources: Dict = dict()

        # iterate over all lines
        for api_resource_line in api_resource_lines[1:]:
            name: Text = ""
            shortname: Text = ""
            api_group: Text = ""
            namespaced_str: Text = ""
            kind: Text = ""
            verbs: List = list()

            # get the name value #
            for char in api_resource_line[name_index:]:
                if char != " ":
                    name = name + char
                else:
                    break

            # make sure a name was found #
            if name == "":
                continue

            # get the shortname value #
            for char in api_resource_line[shortname_index:]:
                if char != " ":
                    shortname = shortname + char
                else:
                    break

            # get the api group value #
            for char in api_resource_line[apigroup_index:]:
                if char != " ":
                    api_group = api_group + char
                else:
                    break

            # get the namespaced value #
            for char in api_resource_line[namespaced_index:]:
                if char != " ":
                    namespaced_str = namespaced_str + char
                else:
                    break

            # make namespaced a bool #
            namespaced: bool = bool(namespaced_str)

            # get the kind value
            for char in api_resource_line[kind_index:]:
                if char != " ":
                    kind = kind + char
                else:
                    break

            # get the verbs values #
            verb_str: Text = ""
            for char in api_resource_line[verbs_index:]:
                if char == "[":
                    pass
                elif char != "]":
                    verb_str = verb_str + char
                else:
                    break

            # convert verb_str to list #
            if " " in verb_str:
                # if there are multiple verbs split them into a list #
                verbs = verb_str.split()
            elif len(verb_str) > 0:
                # if there is only one, append it to the list #
                verbs.append(verb_str)

            api_resources[kind]: Dict = dict()
            api_resources[kind][KubernetesApiResources.Keys.NAME]: Text = name
            api_resources[kind][
                KubernetesApiResources.Keys.SHORT_NAME]: Text = shortname
            api_resources[kind][
                KubernetesApiResources.Keys.API_GROUP]: Text = api_group
            api_resources[kind][
                KubernetesApiResources.Keys.NAMESPACED]: bool = namespaced
            api_resources[kind][
                KubernetesApiResources.Keys.VERBS]: List = verbs

        return KubernetesApiResources(api_resources)
def test_kubernetes_api_resources_get_short_name_incomplete() -> None:
    """
    This test verifies that KubernetesApiResources.get_short_name() returns None when no resources are defined.
    """
    assert KubernetesApiResources(dict()).get_short_name("APIService") is None