diff --git a/.github/workflows/ci-validation.yml b/.github/workflows/ci-validation.yml index 357609c..583cad7 100644 --- a/.github/workflows/ci-validation.yml +++ b/.github/workflows/ci-validation.yml @@ -15,10 +15,10 @@ jobs: steps: - uses: actions/checkout@v2 - - name: Set up Python 3.6 + - name: Set up Python 3.8 uses: actions/setup-python@v2 with: - python-version: 3.6 + python-version: 3.8 - name: Install dependencies run: | python -m pip install --upgrade pip diff --git a/deployment_report/model/test/test_viya_deployment_report.py b/deployment_report/model/test/test_viya_deployment_report.py index ec28d22..84692ce 100644 --- a/deployment_report/model/test/test_viya_deployment_report.py +++ b/deployment_report/model/test/test_viya_deployment_report.py @@ -4,7 +4,7 @@ # ### Author: SAS Institute Inc. ### #################################################################### # ### -# Copyright (c) 2021, SAS Institute Inc., Cary, NC, USA. ### +# Copyright (c) 2022, SAS Institute Inc., Cary, NC, USA. ### # All Rights Reserved. ### # SPDX-License-Identifier: Apache-2.0 ### # ### @@ -252,7 +252,7 @@ def test_get_ingress_controller_none() -> None: report.gather_details(kubectl=KubectlTest(KubectlTest.IngressSimulator.NONE)) # check for expected attributes - assert report.get_ingress_controller() is None + assert report.get_ingress_controller() == SupportedIngress.Controllers.UNKNOWN def test_get_ingress_controller_unpopulated() -> None: diff --git a/deployment_report/model/utils/ingress_util.py b/deployment_report/model/utils/ingress_util.py index 7f1193b..039b9c7 100644 --- a/deployment_report/model/utils/ingress_util.py +++ b/deployment_report/model/utils/ingress_util.py @@ -4,7 +4,7 @@ # ### Author: SAS Institute Inc. ### #################################################################### # ### -# Copyright (c) 2021, SAS Institute Inc., Cary, NC, USA. ### +# Copyright (c) 2022, SAS Institute Inc., Cary, NC, USA. ### # All Rights Reserved. ### # SPDX-License-Identifier: Apache-2.0 ### # ### @@ -111,7 +111,7 @@ def ignorable_for_controller_if_unavailable(ingress_controller: Text, resource_t return False -def get_ingress_version(kubectl: KubectlInterface) -> Optional[Text]: +def get_ingress_version(kubectl: KubectlInterface, ingress_controller: Text) -> Optional[Text]: """ Retrieves ingress version used in the Kubernetes cluster @@ -119,52 +119,61 @@ def get_ingress_version(kubectl: KubectlInterface) -> Optional[Text]: :return: The ingress controller version used in the target cluster or Blank if it cannot be determined. """ + if not kubectl.ingress_ns: + return "" + version: Text = "" + getpod_cmd: AnyStr = "get pods -n " + kubectl.ingress_ns + \ " --field-selector=status.phase==Running" + \ " -o jsonpath=\"{.items[0].metadata.name}\"" - if kubectl.ingress_ns == SupportedIngress.Controllers.NS_NGINX: + if ingress_controller == SupportedIngress.Controllers.NGINX: podname: AnyStr = kubectl.do(getpod_cmd + " -l app.kubernetes.io/component=controller") - version_str: AnyStr = kubectl.do("exec -it " + podname.decode() + - " -n " + kubectl.ingress_ns + - " -- /nginx-ingress-controller --version") - version_list: List = version_str.decode().splitlines() - for v in version_list: - if _RELEASE_ in v: - version = ' '.join(v.split()) + version - elif _NGINX_VERSION_ in v: - version = version + ", " + v.split()[-1] - - elif kubectl.ingress_ns == SupportedIngress.Controllers.NS_ISTIO: + + if podname: + version_str: AnyStr = kubectl.do("exec -it " + podname.decode() + + " -n " + kubectl.ingress_ns + + " -- /nginx-ingress-controller --version") + version_list: List = version_str.decode().splitlines() + for v in version_list: + if _RELEASE_ in v: + version = ' '.join(v.split()) + version + elif _NGINX_VERSION_ in v: + version = version + ", " + v.split()[-1] + + elif ingress_controller == SupportedIngress.Controllers.ISTIO: podname: AnyStr = kubectl.do(getpod_cmd + " -l app=istiod") - version_str: AnyStr = kubectl.do("exec -it " + podname.decode() + - " -n " + kubectl.ingress_ns + - " -- pilot-discovery version --short") - version = version_str.decode() + if podname: + version_str: AnyStr = kubectl.do("exec -it " + podname.decode() + + " -n " + kubectl.ingress_ns + + " -- pilot-discovery version --short") + version = version_str.decode() - elif kubectl.ingress_ns == SupportedIngress.Controllers.NS_OPENSHIFT: + elif ingress_controller == SupportedIngress.Controllers.OPENSHIFT: podname: AnyStr = kubectl.do(getpod_cmd + " -l name=ingress-operator") - version_str: AnyStr = kubectl.do("get pod " + podname.decode() + - " -n " + kubectl.ingress_ns + - " -o jsonpath=\"{.spec.containers[].env[" + - "?(@.name=='RELEASE_VERSION')].value}\"") - version = version_str.decode() - - elif kubectl.ingress_ns == SupportedIngress.Controllers.NS_CONTOUR: + if podname: + version_str: AnyStr = kubectl.do("get pod " + podname.decode() + + " -n " + kubectl.ingress_ns + + " -o jsonpath=\"{.spec.containers[].env[" + + "?(@.name=='RELEASE_VERSION')].value}\"") + version = version_str.decode() + + elif ingress_controller == SupportedIngress.Controllers.CONTOUR: podname: AnyStr = kubectl.do(getpod_cmd + " -l app=envoy") - version_str: AnyStr = kubectl.do("get pod " + podname.decode() + - " -n " + kubectl.ingress_ns + - " -o jsonpath=\"{.spec.containers[*].image}\"") - version_list: List = version_str.decode().split(' ') - for v in version_list: - if version: - version = version + ", " + v.split("/")[-1].capitalize() - else: - version = v.split("/")[-1].capitalize() + if podname: + version_str: AnyStr = kubectl.do("get pod " + podname.decode() + + " -n " + kubectl.ingress_ns + + " -o jsonpath=\"{.spec.containers[*].image}\"") + version_list: List = version_str.decode().split(' ') + for v in version_list: + if version: + version = version + ", " + v.split("/")[-1].capitalize() + else: + version = v.split("/")[-1].capitalize() return version.strip() diff --git a/deployment_report/model/viya_deployment_report.py b/deployment_report/model/viya_deployment_report.py index 2a29977..0ff140f 100644 --- a/deployment_report/model/viya_deployment_report.py +++ b/deployment_report/model/viya_deployment_report.py @@ -4,7 +4,7 @@ # ### Author: SAS Institute Inc. ### #################################################################### # ### -# Copyright (c) 2021, SAS Institute Inc., Cary, NC, USA. ### +# Copyright (c) 2022, SAS Institute Inc., Cary, NC, USA. ### # All Rights Reserved. ### # SPDX-License-Identifier: Apache-2.0 ### # ### @@ -291,7 +291,13 @@ def gather_details(self, kubectl: KubectlInterface, ingress_controller == SupportedIngress.Controllers.OPENSHIFT or ingress_controller == SupportedIngress.Controllers.CONTOUR ): - ingress_version = ingress_util.get_ingress_version(kubectl) + if not kubectl.ingress_ns: + ingress_version = "N/A (No default ingress namespace was found)" + else: + ingress_version = ingress_util.get_ingress_version(kubectl=kubectl, + ingress_controller=ingress_controller) + else: + ingress_controller = SupportedIngress.Controllers.UNKNOWN # determine if any resource types for which caching was attempted were unavailable # if at least one is unavailable, a message will be displayed saying that components may not be complete diff --git a/viya_ark_library/k8s/sas_k8s_ingress.py b/viya_ark_library/k8s/sas_k8s_ingress.py index 2ab13a6..e0446d6 100644 --- a/viya_ark_library/k8s/sas_k8s_ingress.py +++ b/viya_ark_library/k8s/sas_k8s_ingress.py @@ -4,7 +4,7 @@ # ### Author: SAS Institute Inc. ### #################################################################### # ### -# Copyright (c) 2021, SAS Institute Inc., Cary, NC, USA. ### +# Copyright (c) 2022, SAS Institute Inc., Cary, NC, USA. ### # All Rights Reserved. ### # SPDX-License-Identifier: Apache-2.0 ### # ### @@ -27,6 +27,7 @@ class Controllers(object): ISTIO = "Istio" NGINX = "NGINX" OPENSHIFT = "OpenShift" + UNKNOWN = "Unknown" NS_CONTOUR = "projectcontour" NS_ISTIO = "istio-system" NS_NGINX = "ingress-nginx" diff --git a/viya_ark_library/k8s/sas_kubectl.py b/viya_ark_library/k8s/sas_kubectl.py index 981bf98..a74bde5 100644 --- a/viya_ark_library/k8s/sas_kubectl.py +++ b/viya_ark_library/k8s/sas_kubectl.py @@ -4,7 +4,7 @@ # ### Author: SAS Institute Inc. ### #################################################################### # ### -# Copyright (c) 2021, SAS Institute Inc., Cary, NC, USA. ### +# Copyright (c) 2022, SAS Institute Inc., Cary, NC, USA. ### # All Rights Reserved. ### # SPDX-License-Identifier: Apache-2.0 ### # ### @@ -30,7 +30,7 @@ _HEADER_VERBS_ = "VERBS" # constants values -_DO_MSG_ = "command_fail_ignored" +_NOTFOUND_ = "NotFound" class Kubectl(KubectlInterface): @@ -82,13 +82,7 @@ def __init__(self, executable: Text = "kubectl", namespace: Text = None, global_ self.ingress_ns = None # get ingress namespace - if ingress_namespace is not None: - ns: AnyStr = self.do("get namespace " + ingress_namespace, ignore_errors=True, warning=False) - if len(ns) > 0: - raise NamespaceNotFoundError( - f"The ingress namespace [{ingress_namespace}] was not found in the target environment.") - self.ingress_ns = ingress_namespace - else: + if not ingress_namespace: for x in range(len(existing_namespaces)): ns: AnyStr = existing_namespaces[x].get_name() if ( @@ -99,6 +93,13 @@ def __init__(self, executable: Text = "kubectl", namespace: Text = None, global_ ): self.ingress_ns = ns break + else: + ns: AnyStr = self.do("get namespace " + ingress_namespace, ignore_errors=True, warning=False) + if type(ns) is str and _NOTFOUND_ in ns: + raise NamespaceNotFoundError( + f"The ingress namespace [{ingress_namespace}] was not found in the target environment.") + else: + self.ingress_ns = ingress_namespace.lower() # loop over all existing namespaces and check for the given namespace for existing_namespace in existing_namespaces: @@ -177,7 +178,7 @@ def do(self, command: Text, ignore_errors: bool = False, success_rcs: Optional[L f"(rc: {rc} | stdout: {stdout} | stderr: {stderr})") else: if len(stdout) == 0: - stdout = _DO_MSG_ + stdout = stderr.decode() # return the stdout return stdout