From 0be85595ab36f337ca3d64ab707aa4ebf6757efe Mon Sep 17 00:00:00 2001 From: Bhautik Vala Date: Wed, 23 Sep 2026 18:47:11 +0530 Subject: [PATCH 1/3] [patch] Create secret for storing entitlement and artifactory token and remove it from param --- src/mas/devops/tekton.py | 126 +++++++++++++++++- .../pipelinerun-aiservice-upgrade.yml.j2 | 15 --- .../templates/pipelinerun-backup.yml.j2 | 10 -- .../templates/pipelinerun-install.yml.j2 | 13 -- .../templates/pipelinerun-restore.yml.j2 | 14 -- .../templates/pipelinerun-update.yml.j2 | 13 -- .../templates/pipelinerun-upgrade.yml.j2 | 14 -- 7 files changed, 121 insertions(+), 84 deletions(-) diff --git a/src/mas/devops/tekton.py b/src/mas/devops/tekton.py index cb91ed80..39d89fdc 100644 --- a/src/mas/devops/tekton.py +++ b/src/mas/devops/tekton.py @@ -843,17 +843,28 @@ def prepareAiServicePipelinesNamespace( logger.info(f"Storage class {storageClass} uses volumeBindingMode={volumeBindingMode}, skipping PVC bind wait") -def prepareRestoreSecrets(dynClient: DynamicClient, namespace: str, restoreConfigs: dict = None): +def prepareRestoreSecrets( + dynClient: DynamicClient, + namespace: str, + restoreConfigs: dict = None, + ibm_entitlement_key: str = None, + artifactory_token: str = None, + artifactory_username: str = None, +): """ Create or update secret required for MAS Restore pipeline. - Creates secret in the specified namespace: + Creates secrets in the specified namespace: - pipeline-restore-configs + - mas-devops-credentials (only when credentials are provided) Parameters: dynClient (DynamicClient): OpenShift Dynamic Client namespace (str): The namespace to create secrets in restoreConfigs (dict, optional): configuration data for restore. Defaults to None (empty secret). + ibm_entitlement_key (str, optional): IBM entitlement key for registry access. Defaults to None. + artifactory_token (str, optional): Artifactory token for dev catalog access. Defaults to None. + artifactory_username (str, optional): Artifactory username for dev catalog access. Defaults to None. Returns: None @@ -880,6 +891,37 @@ def prepareRestoreSecrets(dynClient: DynamicClient, namespace: str, restoreConfi } secretsAPI.create(body=restoreConfigs, namespace=namespace) + # 2. Secret/mas-devops-credentials + # ------------------------------------------------------------------------- + credentials_data = {} + + if ibm_entitlement_key: + credentials_data["IBM_ENTITLEMENT_KEY"] = base64.b64encode(ibm_entitlement_key.encode()).decode() + + if artifactory_token: + credentials_data["ARTIFACTORY_TOKEN"] = base64.b64encode(artifactory_token.encode()).decode() + + if artifactory_username: + credentials_data["ARTIFACTORY_USERNAME"] = base64.b64encode(artifactory_username.encode()).decode() + + if credentials_data: + try: + secretsAPI.delete(name="mas-devops-credentials", namespace=namespace) + except NotFoundError: + pass + + secretsAPI.create( + body={ + "apiVersion": "v1", + "kind": "Secret", + "type": "Opaque", + "metadata": {"name": "mas-devops-credentials"}, + "data": credentials_data, + }, + namespace=namespace, + ) + logger.info(f"Created mas-devops-credentials secret in namespace {namespace}") + def prepareInstallSecrets( dynClient: DynamicClient, @@ -893,13 +935,17 @@ def prepareInstallSecrets( aiserviceConfig: str = None, db2LicenseFile: dict | None = None, facilitiesProperties: dict | None = None, + ibm_entitlement_key: str = None, + artifactory_token: str = None, + artifactory_username: str = None, ) -> None: """ Create or update secrets required for MAS installation pipelines. - Creates secrets in the specified namespace: mas-devops-slack, pipeline-additional-configs, - pipeline-sls-entitlement, pipeline-certificates, pipeline-pod-templates, pipeline-aiservice-config, - pipeline-db2-license, and pipeline-facilities-properties. + Creates secrets in the specified namespace: mas-devops-slack, mas-devops-credentials, + pipeline-additional-configs, pipeline-sls-entitlement, pipeline-certificates, + pipeline-pod-templates, pipeline-aiservice-config, pipeline-db2-license, and + pipeline-facilities-properties. Parameters: dynClient (DynamicClient): OpenShift Dynamic Client @@ -913,6 +959,9 @@ def prepareInstallSecrets( slack_channel (str, optional): Slack channel ID for notifications. Defaults to None. aiserviceConfig (str, optional): AI Service tenant config data. Defaults to None (empty secret). facilitiesProperties (dict, optional): Facilities properties file content. Defaults to None (empty secret). + ibm_entitlement_key (str, optional): IBM entitlement key for registry access. Defaults to None. + artifactory_token (str, optional): Artifactory token for dev catalog access. Defaults to None. + artifactory_username (str, optional): Artifactory username for dev catalog access. Defaults to None. Returns: None @@ -959,6 +1008,40 @@ def prepareInstallSecrets( secretsAPI.create(body=mas_devops_secret, namespace=namespace) logger.info(f"Created mas-devops-slack secret with MAS_INSTANCE_ID={instance_id} in namespace {namespace}") + # 1. Secret/mas-devops-credentials + # ------------------------------------------------------------------------- + # New secret holding registry credentials sourced from secret instead of pipeline params. + # Only created when at least one credential is provided — all keys are optional. + if instance_id: + credentials_data = {} + + if ibm_entitlement_key: + credentials_data["IBM_ENTITLEMENT_KEY"] = base64.b64encode(ibm_entitlement_key.encode()).decode() + + if artifactory_token: + credentials_data["ARTIFACTORY_TOKEN"] = base64.b64encode(artifactory_token.encode()).decode() + + if artifactory_username: + credentials_data["ARTIFACTORY_USERNAME"] = base64.b64encode(artifactory_username.encode()).decode() + + if credentials_data: + try: + secretsAPI.delete(name="mas-devops-credentials", namespace=namespace) + except NotFoundError: + pass + + secretsAPI.create( + body={ + "apiVersion": "v1", + "kind": "Secret", + "type": "Opaque", + "metadata": {"name": "mas-devops-credentials"}, + "data": credentials_data, + }, + namespace=namespace, + ) + logger.info(f"Created mas-devops-credentials secret in namespace {namespace}") + # 1. Secret/pipeline-additional-configs # ------------------------------------------------------------------------- # Must exist, but can be empty @@ -1074,17 +1157,22 @@ def prepareUpdateSecrets( slack_token: str = None, slack_channel: str = None, db2LicenseFile: dict | None = None, + artifactory_token: str = None, + artifactory_username: str = None, ) -> None: """ Create or update mas-devops-slack secret in mas-pipelines namespace for update pipeline. Creates the slack secret in mas-pipelines namespace if it exists and slack credentials are provided. + Also creates mas-devops-credentials secret if artifactory credentials are provided. Parameters: dynClient (DynamicClient): OpenShift Dynamic Client slack_token (str, optional): Slack bot token for notifications. Defaults to None. slack_channel (str, optional): Slack channel ID for notifications. Defaults to None. db2LicenseFile (dict, optional): Db2 license file content. Defaults to None (empty secret). + artifactory_token (str, optional): Artifactory token for dev catalog access. Defaults to None. + artifactory_username (str, optional): Artifactory username for dev catalog access. Defaults to None. Returns: None @@ -1152,6 +1240,34 @@ def prepareUpdateSecrets( secretsAPI.create(body=mas_devops_secret, namespace=namespace) logger.info(f"Created mas-devops-slack secret in namespace {namespace}") + # Create mas-devops-credentials if artifactory credentials are provided + # Note: update pipeline does not use ibm_entitlement_key (skipped via skip_entitlement_key_flag) + credentials_data = {} + + if artifactory_token: + credentials_data["ARTIFACTORY_TOKEN"] = base64.b64encode(artifactory_token.encode()).decode() + + if artifactory_username: + credentials_data["ARTIFACTORY_USERNAME"] = base64.b64encode(artifactory_username.encode()).decode() + + if credentials_data: + try: + secretsAPI.delete(name="mas-devops-credentials", namespace=namespace) + except NotFoundError: + pass + + secretsAPI.create( + body={ + "apiVersion": "v1", + "kind": "Secret", + "type": "Opaque", + "metadata": {"name": "mas-devops-credentials"}, + "data": credentials_data, + }, + namespace=namespace, + ) + logger.info(f"Created mas-devops-credentials secret in namespace {namespace}") + def testCLI() -> None: pass diff --git a/src/mas/devops/templates/pipelinerun-aiservice-upgrade.yml.j2 b/src/mas/devops/templates/pipelinerun-aiservice-upgrade.yml.j2 index 4b5bc70c..b5463320 100644 --- a/src/mas/devops/templates/pipelinerun-aiservice-upgrade.yml.j2 +++ b/src/mas/devops/templates/pipelinerun-aiservice-upgrade.yml.j2 @@ -22,27 +22,12 @@ spec: - name: aiservice_channel value: "{{ aiservice_channel }}" - # IBM Entitlement Key - # ------------------------------------------------------------------------- - - name: ibm_entitlement_key - value: "{{ ibm_entitlement_key }}" - {%- if skip_pre_check is defined and skip_pre_check != "" %} # Skip pre-check # ------------------------------------------------------------------------- - name: skip_pre_check value: "{{ skip_pre_check }}" {%- endif %} -{%- if artifactory_username is defined and artifactory_username != "" %} - - # Enable development catalogs - # ------------------------------------------------------------------------- - - name: artifactory_username - value: "{{ artifactory_username }}" - - name: artifactory_token - value: "{{ artifactory_token }}" -{%- endif %} - workspaces: # The generated configuration files # ------------------------------------------------------------------------- diff --git a/src/mas/devops/templates/pipelinerun-backup.yml.j2 b/src/mas/devops/templates/pipelinerun-backup.yml.j2 index d5386710..e57d57fb 100644 --- a/src/mas/devops/templates/pipelinerun-backup.yml.j2 +++ b/src/mas/devops/templates/pipelinerun-backup.yml.j2 @@ -74,16 +74,6 @@ spec: value: "{{ cert_manager_provider }}" {% endif %} - # Development Build Support - {% if artifactory_username is defined and artifactory_username != "" %} - - name: artifactory_username - value: "{{ artifactory_username }}" - {% endif %} - {% if artifactory_token is defined and artifactory_token != "" %} - - name: artifactory_token - value: "{{ artifactory_token }}" - {% endif %} - # Upload Configuration {% if upload_backup is defined and upload_backup != "" %} - name: upload_backup diff --git a/src/mas/devops/templates/pipelinerun-install.yml.j2 b/src/mas/devops/templates/pipelinerun-install.yml.j2 index ca6dd277..666308b6 100644 --- a/src/mas/devops/templates/pipelinerun-install.yml.j2 +++ b/src/mas/devops/templates/pipelinerun-install.yml.j2 @@ -19,10 +19,6 @@ spec: pipeline: "0" params: - # IBM Entitlement Key - # ------------------------------------------------------------------------- - - name: ibm_entitlement_key - value: "{{ ibm_entitlement_key }}" {%- if skip_pre_check is defined and skip_pre_check != "" %} # Pipeline config @@ -44,15 +40,6 @@ spec: - name: ocp_ingress_tls_secret_name value: "{{ ocp_ingress_tls_secret_name }}" {%- endif %} -{%- if artifactory_username is defined and artifactory_username != "" %} - - # Enable development catalogs - # ------------------------------------------------------------------------- - - name: artifactory_username - value: "{{ artifactory_username }}" - - name: artifactory_token - value: "{{ artifactory_token }}" -{%- endif %} {%- if ibmcloud_apikey is defined and ibmcloud_resourcegroup != "" %} # IBM Cloud diff --git a/src/mas/devops/templates/pipelinerun-restore.yml.j2 b/src/mas/devops/templates/pipelinerun-restore.yml.j2 index bf5ae6fa..d57c8f38 100644 --- a/src/mas/devops/templates/pipelinerun-restore.yml.j2 +++ b/src/mas/devops/templates/pipelinerun-restore.yml.j2 @@ -99,10 +99,6 @@ spec: - name: dro_contact_lastname value: "{{ dro_contact_lastname }}" {% endif %} - {% if ibm_entitlement_key is defined and ibm_entitlement_key != "" %} - - name: ibm_entitlement_key - value: "{{ ibm_entitlement_key }}" - {% endif %} {% if dro_namespace is defined and dro_namespace != "" %} - name: dro_namespace value: "{{ dro_namespace }}" @@ -148,16 +144,6 @@ spec: value: "{{ cert_manager_provider }}" {% endif %} - # Development Build Support - {% if artifactory_username is defined and artifactory_username != "" %} - - name: artifactory_username - value: "{{ artifactory_username }}" - {% endif %} - {% if artifactory_token is defined and artifactory_token != "" %} - - name: artifactory_token - value: "{{ artifactory_token }}" - {% endif %} - # Download Configuration {% if backup_archive_name is defined and backup_archive_name != "" %} - name: backup_archive_name diff --git a/src/mas/devops/templates/pipelinerun-update.yml.j2 b/src/mas/devops/templates/pipelinerun-update.yml.j2 index 1370379e..4222a9d8 100644 --- a/src/mas/devops/templates/pipelinerun-update.yml.j2 +++ b/src/mas/devops/templates/pipelinerun-update.yml.j2 @@ -28,19 +28,6 @@ spec: - name: mas_catalog_version value: "{{ mas_catalog_version }}" -{%- if ibm_entitlement_key is defined and ibm_entitlement_key != "" %} - # TODO: What even uses this, nothing in the update pipeline should be using this - - name: ibm_entitlement_key - value: "{{ ibm_entitlement_key }}" -{%- endif %} -{%- if artifactory_username is defined and artifactory_username != "" %} - # Enable development catalogs - # ------------------------------------------------------------------------- - - name: artifactory_username - value: "{{ artifactory_username }}" - - name: artifactory_token - value: "{{ artifactory_token }}" -{%- endif %} {%- if skip_pre_check is defined and skip_pre_check != "" %} # Skip pre-check # ------------------------------------------------------------------------- diff --git a/src/mas/devops/templates/pipelinerun-upgrade.yml.j2 b/src/mas/devops/templates/pipelinerun-upgrade.yml.j2 index 86cf6726..4549d0ab 100644 --- a/src/mas/devops/templates/pipelinerun-upgrade.yml.j2 +++ b/src/mas/devops/templates/pipelinerun-upgrade.yml.j2 @@ -30,26 +30,12 @@ spec: - name: mas_channel value: "{{ mas_channel }}" - # IBM Entitlement Key - # ------------------------------------------------------------------------- - - name: ibm_entitlement_key - value: "{{ ibm_entitlement_key }}" - {%- if skip_pre_check is defined and skip_pre_check != "" %} # Skip pre-check # ------------------------------------------------------------------------- - name: skip_pre_check value: "{{ skip_pre_check }}" {%- endif %} -{%- if artifactory_username is defined and artifactory_username != "" %} - - # Enable development catalogs - # ------------------------------------------------------------------------- - - name: artifactory_username - value: "{{ artifactory_username }}" - - name: artifactory_token - value: "{{ artifactory_token }}" -{%- endif %} {%- if db2_action_system == "install" or db2_action_manage == "install" %} # Dependencies - Db2 - Actions From f761732a7257920d299a711d591d3656d184d26e Mon Sep 17 00:00:00 2001 From: Bhautik Vala Date: Thu, 24 Sep 2026 11:31:02 +0530 Subject: [PATCH 2/3] [patch] Use separate secret name for registry creds for install,update,backup etc --- src/mas/devops/tekton.py | 43 ++++++++++++------- .../pipelinerun-aiservice-upgrade.yml.j2 | 5 +++ .../templates/pipelinerun-backup.yml.j2 | 5 +++ .../templates/pipelinerun-install.yml.j2 | 9 ++++ .../templates/pipelinerun-restore.yml.j2 | 5 +++ .../templates/pipelinerun-update.yml.j2 | 5 +++ .../templates/pipelinerun-upgrade.yml.j2 | 5 +++ 7 files changed, 61 insertions(+), 16 deletions(-) diff --git a/src/mas/devops/tekton.py b/src/mas/devops/tekton.py index 39d89fdc..2eeb1ea0 100644 --- a/src/mas/devops/tekton.py +++ b/src/mas/devops/tekton.py @@ -850,13 +850,14 @@ def prepareRestoreSecrets( ibm_entitlement_key: str = None, artifactory_token: str = None, artifactory_username: str = None, + registry_secret_name: str = "mas-restore-secrets", ): """ Create or update secret required for MAS Restore pipeline. Creates secrets in the specified namespace: - pipeline-restore-configs - - mas-devops-credentials (only when credentials are provided) + - {registry_secret_name} (only when credentials are provided) Parameters: dynClient (DynamicClient): OpenShift Dynamic Client @@ -865,6 +866,7 @@ def prepareRestoreSecrets( ibm_entitlement_key (str, optional): IBM entitlement key for registry access. Defaults to None. artifactory_token (str, optional): Artifactory token for dev catalog access. Defaults to None. artifactory_username (str, optional): Artifactory username for dev catalog access. Defaults to None. + registry_secret_name (str, optional): Name of the per-pipeline registry credentials secret. Defaults to "mas-restore-secrets". Returns: None @@ -891,7 +893,7 @@ def prepareRestoreSecrets( } secretsAPI.create(body=restoreConfigs, namespace=namespace) - # 2. Secret/mas-devops-credentials + # 2. Secret/{registry_secret_name} # ------------------------------------------------------------------------- credentials_data = {} @@ -906,7 +908,7 @@ def prepareRestoreSecrets( if credentials_data: try: - secretsAPI.delete(name="mas-devops-credentials", namespace=namespace) + secretsAPI.delete(name=registry_secret_name, namespace=namespace) except NotFoundError: pass @@ -915,12 +917,12 @@ def prepareRestoreSecrets( "apiVersion": "v1", "kind": "Secret", "type": "Opaque", - "metadata": {"name": "mas-devops-credentials"}, + "metadata": {"name": registry_secret_name}, "data": credentials_data, }, namespace=namespace, ) - logger.info(f"Created mas-devops-credentials secret in namespace {namespace}") + logger.info(f"Created {registry_secret_name} secret in namespace {namespace}") def prepareInstallSecrets( @@ -938,11 +940,12 @@ def prepareInstallSecrets( ibm_entitlement_key: str = None, artifactory_token: str = None, artifactory_username: str = None, + registry_secret_name: str = None, ) -> None: """ Create or update secrets required for MAS installation pipelines. - Creates secrets in the specified namespace: mas-devops-slack, mas-devops-credentials, + Creates secrets in the specified namespace: mas-devops-slack, {registry_secret_name}, pipeline-additional-configs, pipeline-sls-entitlement, pipeline-certificates, pipeline-pod-templates, pipeline-aiservice-config, pipeline-db2-license, and pipeline-facilities-properties. @@ -1008,11 +1011,17 @@ def prepareInstallSecrets( secretsAPI.create(body=mas_devops_secret, namespace=namespace) logger.info(f"Created mas-devops-slack secret with MAS_INSTANCE_ID={instance_id} in namespace {namespace}") - # 1. Secret/mas-devops-credentials + # 1. Secret/{registry_secret_name} # ------------------------------------------------------------------------- - # New secret holding registry credentials sourced from secret instead of pipeline params. + # Per-pipeline secret holding registry credentials sourced from secret instead of pipeline params. # Only created when at least one credential is provided — all keys are optional. + # Secret name is derived from namespace prefix if not explicitly provided: + # mas-{id}-pipelines → mas-install-secrets + # aiservice-{id}-pipelines → mas-aiservice-install-secrets if instance_id: + if registry_secret_name is None: + registry_secret_name = "mas-aiservice-install-secrets" if namespace.startswith("aiservice-") else "mas-install-secrets" + credentials_data = {} if ibm_entitlement_key: @@ -1026,7 +1035,7 @@ def prepareInstallSecrets( if credentials_data: try: - secretsAPI.delete(name="mas-devops-credentials", namespace=namespace) + secretsAPI.delete(name=registry_secret_name, namespace=namespace) except NotFoundError: pass @@ -1035,12 +1044,12 @@ def prepareInstallSecrets( "apiVersion": "v1", "kind": "Secret", "type": "Opaque", - "metadata": {"name": "mas-devops-credentials"}, + "metadata": {"name": registry_secret_name}, "data": credentials_data, }, namespace=namespace, ) - logger.info(f"Created mas-devops-credentials secret in namespace {namespace}") + logger.info(f"Created {registry_secret_name} secret in namespace {namespace}") # 1. Secret/pipeline-additional-configs # ------------------------------------------------------------------------- @@ -1159,12 +1168,13 @@ def prepareUpdateSecrets( db2LicenseFile: dict | None = None, artifactory_token: str = None, artifactory_username: str = None, + registry_secret_name: str = "mas-update-secrets", ) -> None: """ Create or update mas-devops-slack secret in mas-pipelines namespace for update pipeline. Creates the slack secret in mas-pipelines namespace if it exists and slack credentials are provided. - Also creates mas-devops-credentials secret if artifactory credentials are provided. + Also creates {registry_secret_name} secret if artifactory credentials are provided. Parameters: dynClient (DynamicClient): OpenShift Dynamic Client @@ -1173,6 +1183,7 @@ def prepareUpdateSecrets( db2LicenseFile (dict, optional): Db2 license file content. Defaults to None (empty secret). artifactory_token (str, optional): Artifactory token for dev catalog access. Defaults to None. artifactory_username (str, optional): Artifactory username for dev catalog access. Defaults to None. + registry_secret_name (str, optional): Name of the per-pipeline registry credentials secret. Defaults to "mas-update-secrets". Returns: None @@ -1240,7 +1251,7 @@ def prepareUpdateSecrets( secretsAPI.create(body=mas_devops_secret, namespace=namespace) logger.info(f"Created mas-devops-slack secret in namespace {namespace}") - # Create mas-devops-credentials if artifactory credentials are provided + # Create {registry_secret_name} if artifactory credentials are provided # Note: update pipeline does not use ibm_entitlement_key (skipped via skip_entitlement_key_flag) credentials_data = {} @@ -1252,7 +1263,7 @@ def prepareUpdateSecrets( if credentials_data: try: - secretsAPI.delete(name="mas-devops-credentials", namespace=namespace) + secretsAPI.delete(name=registry_secret_name, namespace=namespace) except NotFoundError: pass @@ -1261,12 +1272,12 @@ def prepareUpdateSecrets( "apiVersion": "v1", "kind": "Secret", "type": "Opaque", - "metadata": {"name": "mas-devops-credentials"}, + "metadata": {"name": registry_secret_name}, "data": credentials_data, }, namespace=namespace, ) - logger.info(f"Created mas-devops-credentials secret in namespace {namespace}") + logger.info(f"Created {registry_secret_name} secret in namespace {namespace}") def testCLI() -> None: diff --git a/src/mas/devops/templates/pipelinerun-aiservice-upgrade.yml.j2 b/src/mas/devops/templates/pipelinerun-aiservice-upgrade.yml.j2 index b5463320..d340ce8d 100644 --- a/src/mas/devops/templates/pipelinerun-aiservice-upgrade.yml.j2 +++ b/src/mas/devops/templates/pipelinerun-aiservice-upgrade.yml.j2 @@ -15,6 +15,11 @@ spec: pipeline: "0" params: + # Registry Credentials Secret + # ------------------------------------------------------------------------- + - name: pipeline_registry_secret_name + value: "mas-aiservice-upgrade-secrets" + # Target AI Service Instance # ------------------------------------------------------------------------- - name: aiservice_instance_id diff --git a/src/mas/devops/templates/pipelinerun-backup.yml.j2 b/src/mas/devops/templates/pipelinerun-backup.yml.j2 index e57d57fb..3019ef70 100644 --- a/src/mas/devops/templates/pipelinerun-backup.yml.j2 +++ b/src/mas/devops/templates/pipelinerun-backup.yml.j2 @@ -17,6 +17,11 @@ spec: persistentVolumeClaim: claimName: backup-pvc params: + # Registry Credentials Secret + # ------------------------------------------------------------------------- + - name: pipeline_registry_secret_name + value: "mas-backup-secrets" + # Common Parameters - name: image_pull_policy value: IfNotPresent diff --git a/src/mas/devops/templates/pipelinerun-install.yml.j2 b/src/mas/devops/templates/pipelinerun-install.yml.j2 index 666308b6..eb422e8e 100644 --- a/src/mas/devops/templates/pipelinerun-install.yml.j2 +++ b/src/mas/devops/templates/pipelinerun-install.yml.j2 @@ -19,6 +19,15 @@ spec: pipeline: "0" params: + # Registry Credentials Secret + # ------------------------------------------------------------------------- + - name: pipeline_registry_secret_name +{%- if mas_instance_id is defined and mas_instance_id != "" %} + value: "mas-install-secrets" +{%- else %} + value: "mas-aiservice-install-secrets" +{%- endif %} + {%- if skip_pre_check is defined and skip_pre_check != "" %} # Pipeline config diff --git a/src/mas/devops/templates/pipelinerun-restore.yml.j2 b/src/mas/devops/templates/pipelinerun-restore.yml.j2 index d57c8f38..10654533 100644 --- a/src/mas/devops/templates/pipelinerun-restore.yml.j2 +++ b/src/mas/devops/templates/pipelinerun-restore.yml.j2 @@ -20,6 +20,11 @@ spec: secret: secretName: pipeline-restore-configs params: + # Registry Credentials Secret + # ------------------------------------------------------------------------- + - name: pipeline_registry_secret_name + value: "mas-restore-secrets" + # Common Parameters - name: image_pull_policy value: IfNotPresent diff --git a/src/mas/devops/templates/pipelinerun-update.yml.j2 b/src/mas/devops/templates/pipelinerun-update.yml.j2 index 4222a9d8..2886d644 100644 --- a/src/mas/devops/templates/pipelinerun-update.yml.j2 +++ b/src/mas/devops/templates/pipelinerun-update.yml.j2 @@ -15,6 +15,11 @@ spec: pipeline: "0" params: + # Registry Credentials Secret + # ------------------------------------------------------------------------- + - name: pipeline_registry_secret_name + value: "mas-update-secrets" + {%- if image_pull_policy is defined and image_pull_policy != "" %} # Image Pull Policy diff --git a/src/mas/devops/templates/pipelinerun-upgrade.yml.j2 b/src/mas/devops/templates/pipelinerun-upgrade.yml.j2 index 4549d0ab..24a36e4c 100644 --- a/src/mas/devops/templates/pipelinerun-upgrade.yml.j2 +++ b/src/mas/devops/templates/pipelinerun-upgrade.yml.j2 @@ -15,6 +15,11 @@ spec: pipeline: "0" params: + # Registry Credentials Secret + # ------------------------------------------------------------------------- + - name: pipeline_registry_secret_name + value: "mas-upgrade-secrets" + {%- if image_pull_policy is defined and image_pull_policy != "" %} # Image Pull Policy From 2b8ff4ff5fe8d908338261552823e369997583f5 Mon Sep 17 00:00:00 2001 From: Bhautik Vala Date: Mon, 5 Oct 2026 12:13:49 +0530 Subject: [PATCH 3/3] [patch] Add missing secret creation functions --- src/mas/devops/tekton.py | 180 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 180 insertions(+) diff --git a/src/mas/devops/tekton.py b/src/mas/devops/tekton.py index 2eeb1ea0..bd14871b 100644 --- a/src/mas/devops/tekton.py +++ b/src/mas/devops/tekton.py @@ -1280,6 +1280,67 @@ def prepareUpdateSecrets( logger.info(f"Created {registry_secret_name} secret in namespace {namespace}") +def prepareUpgradeSecrets( + dynClient: DynamicClient, + namespace: str, + ibm_entitlement_key: str = None, + artifactory_token: str = None, + artifactory_username: str = None, + registry_secret_name: str = "mas-upgrade-secrets", +) -> None: + """ + Create the registry credentials secret required for the MAS Upgrade pipeline. + + Upgrade tasks pull images from ICR (ibm_entitlement_key) and optionally from + Artifactory (artifactory_token / artifactory_username). Credentials are written + into a named OCP Secret so they are never visible as plaintext PipelineRun params. + + Only keys with non-empty values are written to the secret. + The secret is skipped entirely if no credentials are provided. + + Parameters: + dynClient (DynamicClient): OpenShift Dynamic Client + namespace (str): The pipeline namespace (mas-{instanceId}-pipelines) + ibm_entitlement_key (str, optional): IBM entitlement key for ICR image pulls. Defaults to None. + artifactory_token (str, optional): Artifactory token for dev catalog access. Defaults to None. + artifactory_username (str, optional): Artifactory username for dev catalog access. Defaults to None. + registry_secret_name (str, optional): Name of the secret to create. Defaults to "mas-upgrade-secrets". + + Returns: + None + """ + secretsAPI = dynClient.resources.get(api_version="v1", kind="Secret") + + credentials_data = {} + + if ibm_entitlement_key: + credentials_data["IBM_ENTITLEMENT_KEY"] = base64.b64encode(ibm_entitlement_key.encode()).decode() + + if artifactory_token: + credentials_data["ARTIFACTORY_TOKEN"] = base64.b64encode(artifactory_token.encode()).decode() + + if artifactory_username: + credentials_data["ARTIFACTORY_USERNAME"] = base64.b64encode(artifactory_username.encode()).decode() + + if credentials_data: + try: + secretsAPI.delete(name=registry_secret_name, namespace=namespace) + except NotFoundError: + pass + + secretsAPI.create( + body={ + "apiVersion": "v1", + "kind": "Secret", + "type": "Opaque", + "metadata": {"name": registry_secret_name}, + "data": credentials_data, + }, + namespace=namespace, + ) + logger.info(f"Created {registry_secret_name} secret in namespace {namespace}") + + def testCLI() -> None: pass # echo -n "Testing availability of $CLI_IMAGE in cluster ..." @@ -1490,6 +1551,63 @@ def launchUpdatePipeline(dynClient: DynamicClient, params: dict) -> str: return pipelineURL +def prepareBackupSecrets( + dynClient: DynamicClient, + namespace: str, + artifactory_token: str = None, + artifactory_username: str = None, + registry_secret_name: str = "mas-backup-secrets", +) -> None: + """ + Create the registry credentials secret required for the MAS Backup pipeline. + + Backup tasks do not use ibm_entitlement_key (no image pulls from ICR), but may + use Artifactory credentials to upload backup archives to an Artifactory repository. + Credentials are written into a named OCP Secret so they are never visible as + plaintext PipelineRun params. + + Only keys with non-empty values are written to the secret. + The secret is skipped entirely if no credentials are provided. + + Parameters: + dynClient (DynamicClient): OpenShift Dynamic Client + namespace (str): The pipeline namespace (mas-{instanceId}-pipelines) + artifactory_token (str, optional): Artifactory token for archive upload. Defaults to None. + artifactory_username (str, optional): Artifactory username for archive upload. Defaults to None. + registry_secret_name (str, optional): Name of the secret to create. Defaults to "mas-backup-secrets". + + Returns: + None + """ + secretsAPI = dynClient.resources.get(api_version="v1", kind="Secret") + + credentials_data = {} + + if artifactory_token: + credentials_data["ARTIFACTORY_TOKEN"] = base64.b64encode(artifactory_token.encode()).decode() + + if artifactory_username: + credentials_data["ARTIFACTORY_USERNAME"] = base64.b64encode(artifactory_username.encode()).decode() + + if credentials_data: + try: + secretsAPI.delete(name=registry_secret_name, namespace=namespace) + except NotFoundError: + pass + + secretsAPI.create( + body={ + "apiVersion": "v1", + "kind": "Secret", + "type": "Opaque", + "metadata": {"name": registry_secret_name}, + "data": credentials_data, + }, + namespace=namespace, + ) + logger.info(f"Created {registry_secret_name} secret in namespace {namespace}") + + def launchBackupPipeline(dynClient: DynamicClient, params: dict) -> str: """ Create a PipelineRun to backup a MAS instance. @@ -1577,6 +1695,68 @@ def launchAiServiceUpgradePipeline( return pipelineURL +def prepareAiServiceUpgradeSecrets( + dynClient: DynamicClient, + namespace: str, + ibm_entitlement_key: str = None, + artifactory_token: str = None, + artifactory_username: str = None, + registry_secret_name: str = "mas-aiservice-upgrade-secrets", +) -> None: + """ + Create the registry credentials secret required for the AI Service Upgrade pipeline. + + The aiservice_upgrade Ansible role uses ibm_entitlement_key (ICR image pulls) and + optionally artifactory_token / artifactory_username (dev catalog access). + Credentials are written into a named OCP Secret so they are never visible as + plaintext PipelineRun params. + + Only keys with non-empty values are written to the secret. + The secret is skipped entirely if no credentials are provided. + + Parameters: + dynClient (DynamicClient): OpenShift Dynamic Client + namespace (str): The pipeline namespace (aiservice-{instanceId}-pipelines) + ibm_entitlement_key (str, optional): IBM entitlement key for ICR image pulls. Defaults to None. + artifactory_token (str, optional): Artifactory token for dev catalog access. Defaults to None. + artifactory_username (str, optional): Artifactory username for dev catalog access. Defaults to None. + registry_secret_name (str, optional): Name of the secret to create. Defaults to "mas-aiservice-upgrade-secrets". + + Returns: + None + """ + secretsAPI = dynClient.resources.get(api_version="v1", kind="Secret") + + credentials_data = {} + + if ibm_entitlement_key: + credentials_data["IBM_ENTITLEMENT_KEY"] = base64.b64encode(ibm_entitlement_key.encode()).decode() + + if artifactory_token: + credentials_data["ARTIFACTORY_TOKEN"] = base64.b64encode(artifactory_token.encode()).decode() + + if artifactory_username: + credentials_data["ARTIFACTORY_USERNAME"] = base64.b64encode(artifactory_username.encode()).decode() + + if credentials_data: + try: + secretsAPI.delete(name=registry_secret_name, namespace=namespace) + except NotFoundError: + pass + + secretsAPI.create( + body={ + "apiVersion": "v1", + "kind": "Secret", + "type": "Opaque", + "metadata": {"name": registry_secret_name}, + "data": credentials_data, + }, + namespace=namespace, + ) + logger.info(f"Created {registry_secret_name} secret in namespace {namespace}") + + def prepareInstallRBAC(dynClient: DynamicClient, namespace: str, instanceId: str, installRBACDir: str) -> None: """ Apply the minimal install RBAC bundle for a MAS instance.