diff --git a/.gitignore b/.gitignore index e815b7f8..ed45b735 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ dist *.egg-info pandoc-*-amd64.deb pandoc-*-windows-x86_64.msi +pandoc-*-x86_64-macOS.pkg README.rst # Environments @@ -16,4 +17,4 @@ venv/ # Other kubectl.exe -/build +/build diff --git a/setup.py b/setup.py index 2ec5bc08..a0643b2f 100644 --- a/setup.py +++ b/setup.py @@ -55,12 +55,12 @@ def get_version(rel_path): description='Python for Maximo Application Suite Dev/Ops', long_description=long_description, install_requires=[ - 'pyyaml', # MIT License - 'openshift', # Apache Software License - 'kubernetes', # Apache Software License - 'kubeconfig', # BSD License - 'jinja2', # BSD License - 'jinja2-base64-filters' # MIT License + 'pyyaml', # MIT License + 'openshift', # Apache Software License + 'kubernetes', # Apache Software License + 'kubeconfig', # BSD License + 'jinja2', # BSD License + 'jinja2-base64-filters' # MIT License ], extras_require={ 'dev': [ diff --git a/src/mas/devops/ocp.py b/src/mas/devops/ocp.py index f195ccb6..fb717773 100644 --- a/src/mas/devops/ocp.py +++ b/src/mas/devops/ocp.py @@ -61,6 +61,22 @@ def connect(server: str, token: str, skipVerify: bool = False) -> bool: return True +def getNamespace(dynClient: DynamicClient, namespace: str) -> dict: + """ + Get a namespace + """ + namespaceAPI = dynClient.resources.get(api_version="v1", kind="Namespace") + + try: + ns = namespaceAPI.get(name=namespace) + logger.debug(f"Namespace {namespace} exists") + return ns + except NotFoundError: + logger.debug(f"Namespace {namespace} does not exist") + + return {} + + def createNamespace(dynClient: DynamicClient, namespace: str) -> bool: """ Create a namespace if it does not exist diff --git a/src/mas/devops/sls.py b/src/mas/devops/sls.py new file mode 100644 index 00000000..1aabc115 --- /dev/null +++ b/src/mas/devops/sls.py @@ -0,0 +1,46 @@ +# ***************************************************************************** +# Copyright (c) 2025 IBM Corporation and other Contributors. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# ***************************************************************************** + +import logging +from openshift.dynamic import DynamicClient +from openshift.dynamic.exceptions import NotFoundError, ResourceNotFoundError, UnauthorizedError + +logger = logging.getLogger(__name__) + + +def listSLSInstances(dynClient: DynamicClient) -> list: + """ + Get a list of SLS instances on the cluster + """ + try: + slsAPI = dynClient.resources.get(api_version="sls.ibm.com/v1", kind="LicenseService") + return slsAPI.get().to_dict()['items'] + except NotFoundError: + logger.info("There are no SLS instances installed on this cluster") + return [] + except ResourceNotFoundError: + logger.info("LicenseService CRD not found on cluster") + return [] + except UnauthorizedError: + logger.error("Error: Unable to verify SLS instances due to failed authorization: {e}") + return [] + + +def findSLSByNamespace(namespace: str, instances: list = None, dynClient: DynamicClient = None): + if not instances and not dynClient: + return False + + if not instances and dynClient: + instances = listSLSInstances(dynClient) + + for instance in instances: + if namespace in instance['metadata']['namespace']: + return True + return False diff --git a/src/mas/devops/tekton.py b/src/mas/devops/tekton.py index 8a84dd15..ed371301 100644 --- a/src/mas/devops/tekton.py +++ b/src/mas/devops/tekton.py @@ -148,7 +148,7 @@ def preparePipelinesNamespace(dynClient: DynamicClient, instanceId: str = None, sleep(15) -def prepareInstallSecrets(dynClient: DynamicClient, instanceId: str, slsLicenseFile: str, additionalConfigs: dict = None, certs: str = None, podTemplates: str = None) -> None: +def prepareInstallSecrets(dynClient: DynamicClient, instanceId: str, slsLicenseFile: str = None, additionalConfigs: dict = None, certs: str = None, podTemplates: str = None) -> None: namespace = f"mas-{instanceId}-pipelines" secretsAPI = dynClient.resources.get(api_version="v1", kind="Secret") @@ -178,10 +178,16 @@ def prepareInstallSecrets(dynClient: DynamicClient, instanceId: str, slsLicenseF except NotFoundError: pass - # TODO: Convert this to using secretsAPI.create() - result = kubectl.run(subcmd_args=['-n', namespace, 'create', 'secret', 'generic', 'pipeline-sls-entitlement', '--from-file', slsLicenseFile]) - for line in result.split("\n"): - logger.debug(line) + if slsLicenseFile is None: + slsLicenseFile = { + "apiVersion": "v1", + "kind": "Secret", + "type": "Opaque", + "metadata": { + "name": "pipeline-sls-entitlement" + } + } + secretsAPI.create(body=slsLicenseFile, namespace=namespace) # 3. Secret/pipeline-certificates # ------------------------------------------------------------------------- diff --git a/src/mas/devops/templates/pipelinerun-install.yml.j2 b/src/mas/devops/templates/pipelinerun-install.yml.j2 index 4ad87f44..324a45c1 100644 --- a/src/mas/devops/templates/pipelinerun-install.yml.j2 +++ b/src/mas/devops/templates/pipelinerun-install.yml.j2 @@ -284,8 +284,10 @@ spec: # ------------------------------------------------------------------------- - name: sls_channel value: '3.x' +{%- if sls_entitlement_file is defined and sls_entitlement_file != "" %} - name: sls_entitlement_file value: "{{ sls_entitlement_file }}" +{%- endif %} {%- if sls_namespace is defined and sls_namespace != "" %} - name: sls_namespace value: "{{ sls_namespace }}" @@ -298,6 +300,11 @@ spec: - name: sls_mongodb_cfg_file value: "{{ sls_mongodb_cfg_file }}" {%- endif %} +{%- if sls_action is defined and sls_action != "" %} + - name: sls_action + value: "{{ sls_action }}" +{%- endif %} + # Dependencies - UDS/DRO (Required) # -------------------------------------------------------------------------