From 2a9a51f61490165e36f838cbee56374f225cd31a Mon Sep 17 00:00:00 2001 From: Josef Harte Date: Wed, 22 Jul 2026 16:01:26 +0100 Subject: [PATCH 1/6] add tenant operator param --- .secrets.baseline | 4 ++-- .../mascli/functions/gitops_aiservice_tenant | 18 ++++++++++++++- .../instance/ibm-aiservice-tenant.yaml.j2 | 5 +++++ python/src/mas/cli/aiservice/install/app.py | 7 ++++++ .../mas/cli/aiservice/install/argBuilder.py | 2 ++ .../mas/cli/aiservice/install/argParser.py | 7 ++++++ .../mas/cli/aiservice/install/summarizer.py | 3 +++ python/src/mas/cli/install/app.py | 9 ++++++++ python/src/mas/cli/install/argBuilder.py | 2 ++ python/src/mas/cli/install/argParser.py | 7 ++++++ .../cli/install/settings/additionalConfigs.py | 6 +++++ .../mas/cli/install/settings/aiSettings.py | 22 +++++++++++++++++++ python/src/mas/cli/install/summarizer.py | 6 +++++ tekton/src/params/install-aiservice.yml.j2 | 4 ++++ .../gitops-aiservice-tenant-pipeline.yml.j2 | 5 +++++ .../taskdefs/aiservice/aiservice.yml.j2 | 3 +++ tekton/src/tasks/aiservice/aiservice.yml.j2 | 6 +++++ .../gitops/gitops-aiservice-tenant.yml.j2 | 4 ++++ 18 files changed, 117 insertions(+), 3 deletions(-) diff --git a/.secrets.baseline b/.secrets.baseline index 31c40d1cfe8..f18c8ef4929 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -3,7 +3,7 @@ "files": "build/bin/config/oscap/ssg-rhel9-ds.xml|^.secrets.baseline$|^docs/catalogs/", "lines": null }, - "generated_at": "2026-07-21T06:40:25Z", + "generated_at": "2026-07-22T13:39:49Z", "plugins_used": [ { "name": "AWSKeyDetector" @@ -270,7 +270,7 @@ "hashed_secret": "b2817467154949a61f8e9ad31d1eeaf03221cbfa", "is_secret": false, "is_verified": false, - "line_number": 387, + "line_number": 392, "type": "Secret Keyword", "verified_result": null } diff --git a/image/cli/mascli/functions/gitops_aiservice_tenant b/image/cli/mascli/functions/gitops_aiservice_tenant index a3654bfc3d3..bf51085662b 100644 --- a/image/cli/mascli/functions/gitops_aiservice_tenant +++ b/image/cli/mascli/functions/gitops_aiservice_tenant @@ -28,7 +28,8 @@ ibm_aiservice_tenant(required): --aiservice-watsonxai-url ${COLOR_YELLOW}AISERVICE_WATSONXAI_URL${TEXT_RESET} Endpoint URL for Watsonx.ai --aiservice-watsonx-full ${COLOR_YELLOW}AISERVICE_WATSONX_FULL${TEXT_RESET} Full URL for Watsonx.ai including API key --tenant-scheduling-config-file ${COLOR_YELLOW}TENANT_SCHEDULING_CONFIG_FILE${TEXT_RESET} Path to tenant scheduling configuration file (tolerations and nodeSelector) - --enable-deprovisioning ${COLOR_YELLOW}AISERVICE_ENABLE_DEPROVISIONING${TEXT_RESET} When true, the tenant is deprovisioned when its AIServiceTenant CR is deleted + --tenant-operator-config-file ${COLOR_YELLOW}TENANT_OPERATOR_CONFIG_FILE${TEXT_RESET} Path to tenant operator configuration file + --enable-deprovisioning ${COLOR_YELLOW}AISERVICE_ENABLE_DEPROVISIONING${TEXT_RESET} When true, the tenant is deprovisioned when its AIServiceTenant CR is deleted AiService : --aiservice-namespace ${COLOR_YELLOW}AISERVICE_NAMESPACE${TEXT_RESET} The namespace where AI Service is deployed @@ -270,6 +271,10 @@ function gitops_aiservice_tenant_noninteractive() { --tenant-scheduling-config-yaml) export TENANT_SCHEDULING_CONFIG_YAML=$1 && shift ;; + + --tenant-operator-config-file) + export TENANT_OPERATOR_CONFIG_FILE=$1 && shift + ;; --enable-deprovisioning) export AISERVICE_ENABLE_DEPROVISIONING=$1 && shift @@ -424,6 +429,12 @@ else echo_reset_dim "Scheduling constraints (tolerations/nodeSelector) .............. ${COLOR_MAGENTA}Not Configured" fi + if [[ -n "$TENANT_OPERATOR_CONFIG_FILE" ]]; then + echo_reset_dim "Tenant operator configuration file .............. ${COLOR_MAGENTA}${TENANT_OPERATOR_CONFIG_FILE}" + else + echo_reset_dim "Tenant operator configuration file .............. ${COLOR_MAGENTA}Not set" + fi + echo_reset_dim "MAS ICR CP registry ............................................ ${COLOR_MAGENTA}${MAS_ICR_CP}" echo_reset_dim "MAS ICR CPOPEN registry ........................................ ${COLOR_MAGENTA}${MAS_ICR_CPOPEN}" @@ -517,6 +528,11 @@ fi export TENANT_SCHEDULING_CONFIG=$(yq eval '.' ${TENANT_SCHEDULING_CONFIG_YAML}) echo -e "\n - TENANT_SCHEDULING_CONFIG content .................. ${TENANT_SCHEDULING_CONFIG}" fi + + if [[ -n "$TENANT_OPERATOR_CONFIG_FILE" && -s "$TENANT_OPERATOR_CONFIG_FILE" ]]; then + export TENANT_OPERATOR_CONFIG=$(yq eval '.' ${TENANT_OPERATOR_CONFIG_FILE}) + echo -e "\n - TENANT_OPERATOR_CONFIG .................. ${TENANT_OPERATOR_CONFIG}" + fi # finally push them into the git repo diff --git a/image/cli/mascli/templates/gitops/appset-configs/cluster/instance/ibm-aiservice-tenant.yaml.j2 b/image/cli/mascli/templates/gitops/appset-configs/cluster/instance/ibm-aiservice-tenant.yaml.j2 index 668762eff77..fd11afca047 100644 --- a/image/cli/mascli/templates/gitops/appset-configs/cluster/instance/ibm-aiservice-tenant.yaml.j2 +++ b/image/cli/mascli/templates/gitops/appset-configs/cluster/instance/ibm-aiservice-tenant.yaml.j2 @@ -65,3 +65,8 @@ ibm_aiservice_tenant: tenant_scheduling_config: {{ TENANT_SCHEDULING_CONFIG | indent(4)}} {% endif %} + +{% if TENANT_OPERATOR_CONFIG is defined and TENANT_OPERATOR_CONFIG != '' %} + tenant_operator_config: + {{ TENANT_OPERATOR_CONFIG | indent(4)}} +{% endif %} diff --git a/python/src/mas/cli/aiservice/install/app.py b/python/src/mas/cli/aiservice/install/app.py index 2d9b5a486ee..83f9e23d05a 100644 --- a/python/src/mas/cli/aiservice/install/app.py +++ b/python/src/mas/cli/aiservice/install/app.py @@ -189,6 +189,7 @@ def nonInteractiveMode(self) -> None: self.db2LicenseFileLocal = None self.aiserviceTenantSchedulingConfigFileLocal = None + self.aiserviceTenantOperatorConfigFileLocal = None self.approvals = { "approval_aiservice": {"id": "aiservice"}, @@ -278,6 +279,10 @@ def nonInteractiveMode(self) -> None: if value is not None and value != "": self.aiserviceTenantSchedulingConfigFileLocal = value + elif key == "tenant_operator_config_file": + if value is not None and value != "": + self.aiserviceTenantOperatorConfigFileLocal = value + elif key == "db2_action_aiservice": # Check if external DB parameters are provided externalDbParams = ["aiservice_db_jdbc_url", "aiservice_db_username", "aiservice_db_password"] @@ -700,7 +705,9 @@ def aiServiceTenantSettings(self) -> None: self.promptForString("Entitlement end date (YYYY-MM-DD)", "tenant_entitlement_end_date", default=oneyear.strftime("%Y-%m-%d")) self.aiserviceTenantSchedulingConfigFileLocal = None + self.aiserviceTenantOperatorConfigFileLocal = None self.configSchedulingConstraints() + self.configTenantOperator() @logMethodCall def configSchedulingConstraints(self): diff --git a/python/src/mas/cli/aiservice/install/argBuilder.py b/python/src/mas/cli/aiservice/install/argBuilder.py index da1df2df697..1cf48546814 100644 --- a/python/src/mas/cli/aiservice/install/argBuilder.py +++ b/python/src/mas/cli/aiservice/install/argBuilder.py @@ -174,6 +174,8 @@ def buildCommand(self) -> str: command += f" --tenant-entitlement-end-date \"{self.getParam('tenant_entitlement_end_date')}\"{newline}" if self.aiserviceTenantSchedulingConfigFileLocal: command += f' --tenant-scheduling-config-file "{self.aiserviceTenantSchedulingConfigFileLocal}"{newline}' + if self.aiserviceTenantOperatorConfigFileLocal: + command += f' --tenant-operator-config-file "{self.aiserviceTenantOperatorConfigFileLocal}"{newline}' if self.getParam("rsl_ca_crt") != "": command += f" --rsl-ca-crt \"{self.getParam('rsl_ca_crt')}\"{newline}" diff --git a/python/src/mas/cli/aiservice/install/argParser.py b/python/src/mas/cli/aiservice/install/argParser.py index 65f9550d64a..3935d8f1942 100644 --- a/python/src/mas/cli/aiservice/install/argParser.py +++ b/python/src/mas/cli/aiservice/install/argParser.py @@ -222,6 +222,13 @@ def isValidFile(parser, arg) -> str: help="Path to the YAML file that contains the scheduling configuration for tenant", type=lambda x: isValidFile(aiServiceinstallArgParser, x), ) +aiserviceAdvancedArgGroup.add_argument( + "--tenant-operator-config-file", + dest="tenant_operator_config_file", + required=False, + help="Path to the YAML file that contains the tenant operator customization settings", + type=lambda x: isValidFile(aiServiceinstallArgParser, x), +) # Database Configuration diff --git a/python/src/mas/cli/aiservice/install/summarizer.py b/python/src/mas/cli/aiservice/install/summarizer.py index dc5c5018d49..93d8bd1e0bb 100644 --- a/python/src/mas/cli/aiservice/install/summarizer.py +++ b/python/src/mas/cli/aiservice/install/summarizer.py @@ -60,6 +60,9 @@ def aiServiceSummary(self) -> None: if self.aiserviceTenantSchedulingConfigFileLocal: self.printSummary("Scheduling configuration file", self.aiserviceTenantSchedulingConfigFileLocal) + if self.aiserviceTenantOperatorConfigFileLocal: + self.printSummary("Tenant operator configuration file", self.aiserviceTenantOperatorConfigFileLocal) + self.printH2("S3 Configuration") # self.printParamSummary("Storage provider", "aiservice_s3_provider") if self.getParam("minio_root_user") is not None and self.getParam("minio_root_user") != "": diff --git a/python/src/mas/cli/install/app.py b/python/src/mas/cli/install/app.py index 34fda116275..59041cc8aa4 100644 --- a/python/src/mas/cli/install/app.py +++ b/python/src/mas/cli/install/app.py @@ -1865,7 +1865,9 @@ def aiServiceTenantSettings(self) -> None: ) self.aiserviceTenantSchedulingConfigFileLocal = None + self.aiserviceTenantOperatorConfigFileLocal = None self.configSchedulingConstraints() + self.configTenantOperator() @logMethodCall def configSchedulingConstraints(self): @@ -1991,6 +1993,7 @@ def chooseInstallFlavour(self) -> None: " - Choose alternative Apache Kafka providers (default to Strimzi)", " - Customize Grafana storage settings", " - Customize Scheduling configuration for AI workloads(Training pipeline & Inference services) for AI Service tenant", + " - Customize AI Service tenant operator configuration", ] ) self.showAdvancedOptions = self.yesOrNo("Show advanced installation options") @@ -2004,6 +2007,7 @@ def interactiveMode(self, simplified: bool, advanced: bool) -> None: self.slsLicenseFileLocal = None self.db2LicenseFileLocal = None self.aiserviceTenantSchedulingConfigFileLocal = None + self.aiserviceTenantOperatorConfigFileLocal = None self.facilitiesPropertiesFileLocal = None if simplified: @@ -2097,6 +2101,7 @@ def nonInteractiveMode(self) -> None: self.slsLicenseFileLocal = None self.db2LicenseFileLocal = None self.aiserviceTenantSchedulingConfigFileLocal = None + self.aiserviceTenantOperatorConfigFileLocal = None self.facilitiesPropertiesFileLocal = None self.approvals: Dict[str, Dict[str, Any]] = { @@ -2452,6 +2457,10 @@ def nonInteractiveMode(self) -> None: if value is not None and value != "": self.aiserviceTenantSchedulingConfigFileLocal = value + elif key == "tenant_operator_config_file": + if value is not None and value != "": + self.aiserviceTenantOperatorConfigFileLocal = value + # Fail if there's any arguments we don't know how to handle else: print(f"Unknown option: {key} {value}") diff --git a/python/src/mas/cli/install/argBuilder.py b/python/src/mas/cli/install/argBuilder.py index 1b227ff9816..ff9463d884f 100644 --- a/python/src/mas/cli/install/argBuilder.py +++ b/python/src/mas/cli/install/argBuilder.py @@ -480,6 +480,8 @@ def buildCommand(self) -> str: command += f" --tenant-entitlement-end-date \"{self.getParam('tenant_entitlement_end_date')}\"{newline}" if self.aiserviceTenantSchedulingConfigFileLocal: command += f' --tenant-scheduling-config-file "{self.aiserviceTenantSchedulingConfigFileLocal}"{newline}' + if self.aiserviceTenantOperatorConfigFileLocal: + command += f' --tenant-operator-config-file "{self.aiserviceTenantOperatorConfigFileLocal}"{newline}' if self.getParam("rsl_ca_crt") != "": command += f" --rsl-ca-crt \"{self.getParam('rsl_ca_crt')}\"{newline}" diff --git a/python/src/mas/cli/install/argParser.py b/python/src/mas/cli/install/argParser.py index 173d1257d1e..bc0a5c6850c 100644 --- a/python/src/mas/cli/install/argParser.py +++ b/python/src/mas/cli/install/argParser.py @@ -1104,6 +1104,13 @@ def isValidFile(parser: argparse.ArgumentParser, arg: str) -> str: help="Path to the YAML file that contains the scheduling configuration for tenant", type=lambda x: isValidFile(installArgParser, x), ) +aiServiceArgGroup.add_argument( + "--tenant-operator-config-file", + dest="tenant_operator_config_file", + required=False, + help="Path to the YAML file that contains the tenant operator customization settings", + type=lambda x: isValidFile(installArgParser, x), +) # IBM Cloud Pak for Data # ----------------------------------------------------------------------------- diff --git a/python/src/mas/cli/install/settings/additionalConfigs.py b/python/src/mas/cli/install/settings/additionalConfigs.py index 96abce3fe2e..05f01a2de7f 100644 --- a/python/src/mas/cli/install/settings/additionalConfigs.py +++ b/python/src/mas/cli/install/settings/additionalConfigs.py @@ -38,6 +38,7 @@ class AdditionalConfigsMixin: manualCertsDir: str | None showAdvancedOptions: bool aiserviceTenantSchedulingConfigFileLocal: str | None + aiserviceTenantOperatorConfigFileLocal: str | None additionalConfigsSecret: Dict[str, Any] | None podTemplatesSecret: Dict[str, Any] | None slsLicenseFileSecret: Dict[str, Any] | None @@ -217,6 +218,11 @@ def aiserviceConfig(self) -> None: self.setParam("tenant_scheduling_config_file", f"/workspace/aiservice/{path.basename(self.aiserviceTenantSchedulingConfigFileLocal)}") self.aiserviceConfigSecret = self.addFilesToSecret(aiserviceConfigSecret, self.aiserviceTenantSchedulingConfigFileLocal, "yaml") + if self.aiserviceTenantOperatorConfigFileLocal: + aiserviceConfigSecret: dict[str, Any] = {"apiVersion": "v1", "kind": "Secret", "type": "Opaque", "metadata": {"name": "pipeline-aiservice-config"}} + self.setParam("tenant_operator_config_file", f"/workspace/aiservice/{path.basename(self.aiserviceTenantOperatorConfigFileLocal)}") + self.aiserviceConfigSecret = self.addFilesToSecret(aiserviceConfigSecret, self.aiserviceTenantOperatorConfigFileLocal, "yaml") + def db2LicenseFile(self) -> None: if self.db2LicenseFileLocal: db2LicenseFileSecret = {"apiVersion": "v1", "kind": "Secret", "type": "Opaque", "metadata": {"name": "pipeline-db2-license"}} diff --git a/python/src/mas/cli/install/settings/aiSettings.py b/python/src/mas/cli/install/settings/aiSettings.py index 86f09b19e56..4020e0129e2 100644 --- a/python/src/mas/cli/install/settings/aiSettings.py +++ b/python/src/mas/cli/install/settings/aiSettings.py @@ -11,6 +11,7 @@ from os import path from typing import TYPE_CHECKING, Dict, List, Any from prompt_toolkit import print_formatted_text +from mas.cli.cli import logMethodCall if TYPE_CHECKING: # Type hints for methods and attributes provided by other mixins @@ -29,6 +30,7 @@ class AiSettingsMixin: templatesDir: str dynamicClient: Any installAIService: bool + aiserviceTenantOperatorConfigFileLocal: str | None # Methods from BaseApp def setParam(self, param: str, value: str) -> None: ... @@ -55,6 +57,8 @@ def promptForString( completer: WordCompleter | None = None, ) -> str: ... + def promptForFile(self, message: str, mustExist: bool = True, default: str = "", envVar: str = "") -> str: ... + def promptForListSelect(self, message: str, options: List[str], param: str | None = None, default: int | None = None) -> str: ... # Methods from ConfigGeneratorMixin or InstallSettingsMixin @@ -142,3 +146,21 @@ def configAi(self) -> None: else: self.setParam("configure_aiassistant", "none") print_formatted_text("AiCfg configuration skipped") + + @logMethodCall + def configTenantOperator(self): + if self.showAdvancedOptions: + self.printH1("Tenant operator configuration customization") + self.printDescription( + content=[ + "The AI Service tenant operator deployment may be customized, for example, to adjust resource requests/limits", + "To customize the operator, create a YAML configuration file", + "The YAML file may contain any valid configuration for the 'spec.config' field in an OLM Subscription resource", + ] + ) + + configTenantOperator = self.yesOrNo("Customize the AI Service tenant operator deployment") + if configTenantOperator: + self.aiserviceTenantOperatorConfigFileLocal = self.promptForFile( + "Tenant operator configuration YAML file", mustExist=True, envVar="AISERVICE_TENANT_OPERATOR_CONFIG_FILE" + ) diff --git a/python/src/mas/cli/install/summarizer.py b/python/src/mas/cli/install/summarizer.py index 7c52392a1a0..b94c0c44f49 100644 --- a/python/src/mas/cli/install/summarizer.py +++ b/python/src/mas/cli/install/summarizer.py @@ -37,6 +37,7 @@ class InstallSummarizerMixin: localConfigDir: str | None slsLicenseFileLocal: str | None aiserviceTenantSchedulingConfigFileLocal: str | None + aiserviceTenantOperatorConfigFileLocal: str | None facilitiesPropertiesFileLocal: str | None deployCP4D: bool installAssist: bool @@ -412,6 +413,11 @@ def aiServiceSummary(self) -> None: "Scheduling configuration file", self.aiserviceTenantSchedulingConfigFileLocal, ) + if self.aiserviceTenantOperatorConfigFileLocal: + self.printSummary( + "Tenant operator configuration file", + self.aiserviceTenantOperatorConfigFileLocal, + ) self.printH2("S3 Configuration") # self.printParamSummary("Storage provider", "aiservice_s3_provider") diff --git a/tekton/src/params/install-aiservice.yml.j2 b/tekton/src/params/install-aiservice.yml.j2 index f99aaa077bb..b1d8eb65be1 100644 --- a/tekton/src/params/install-aiservice.yml.j2 +++ b/tekton/src/params/install-aiservice.yml.j2 @@ -104,6 +104,10 @@ type: string description: Path to YAML file that contains scheduling constraints for AI workloads for tenant default: "" +- name: tenant_operator_cfg_file + type: string + description: Path to YAML file that contains tenant operator customization settings + default: "" # MAS Application Configuration - IBM Maximo AI Service - Watstonx # ----------------------------------------------------------------------------- diff --git a/tekton/src/pipelines/gitops/gitops-aiservice-tenant-pipeline.yml.j2 b/tekton/src/pipelines/gitops/gitops-aiservice-tenant-pipeline.yml.j2 index 22f67a0487c..38b269d1239 100644 --- a/tekton/src/pipelines/gitops/gitops-aiservice-tenant-pipeline.yml.j2 +++ b/tekton/src/pipelines/gitops/gitops-aiservice-tenant-pipeline.yml.j2 @@ -97,6 +97,9 @@ spec: - name: tenant_scheduling_config_yaml type: string default: "" + - name: tenant_operator_config_yaml + type: string + default: "" # standalone sls - name: sls_service @@ -204,5 +207,7 @@ spec: value: $(params.tenant_entitlement_end_date) - name: tenant_scheduling_config_yaml value: $(params.tenant_scheduling_config_yaml) + - name: tenant_operator_config_yaml + value: $(params.tenant_operator_config_yaml) - name: sls_service value: $(params.sls_service) \ No newline at end of file diff --git a/tekton/src/pipelines/taskdefs/aiservice/aiservice.yml.j2 b/tekton/src/pipelines/taskdefs/aiservice/aiservice.yml.j2 index 1792cac2ece..c4f1d796344 100644 --- a/tekton/src/pipelines/taskdefs/aiservice/aiservice.yml.j2 +++ b/tekton/src/pipelines/taskdefs/aiservice/aiservice.yml.j2 @@ -95,6 +95,9 @@ - name: tenant_scheduling_cfg_file value: $(params.tenant_scheduling_cfg_file) + - name: tenant_operator_cfg_file + value: $(params.tenant_operator_cfg_file) + # Database Configuration - name: install_db2 value: $(params.install_db2) diff --git a/tekton/src/tasks/aiservice/aiservice.yml.j2 b/tekton/src/tasks/aiservice/aiservice.yml.j2 index 3f7ca841d14..1901701e30e 100644 --- a/tekton/src/tasks/aiservice/aiservice.yml.j2 +++ b/tekton/src/tasks/aiservice/aiservice.yml.j2 @@ -136,6 +136,9 @@ spec: - name: tenant_scheduling_cfg_file type: string + - name: tenant_operator_cfg_file + type: string + # RSL - name: rsl_ca_crt type: string @@ -266,6 +269,9 @@ spec: value: $(params.tenant_entitlement_end_date) - name: AISERVICE_TENANT_SCHEDULING_CONFIG_FILE value: $(params.tenant_scheduling_cfg_file) + + - name: AISERVICE_TENANT_OPERATOR_CONFIG_FILE + value: $(params.tenant_operator_cfg_file) # RSL - name: RSL_CA_CRT diff --git a/tekton/src/tasks/gitops/gitops-aiservice-tenant.yml.j2 b/tekton/src/tasks/gitops/gitops-aiservice-tenant.yml.j2 index fd04a82ac67..bd981473208 100644 --- a/tekton/src/tasks/gitops/gitops-aiservice-tenant.yml.j2 +++ b/tekton/src/tasks/gitops/gitops-aiservice-tenant.yml.j2 @@ -93,6 +93,8 @@ spec: type: string - name: tenant_scheduling_config_yaml type: string + - name: tenant_operator_config_yaml + type: string - name: sls_service type: string default: "" @@ -185,6 +187,8 @@ spec: value: $(params.tenant_entitlement_end_date) - name: TENANT_SCHEDULING_CONFIG_YAML value: $(params.tenant_scheduling_config_yaml) + - name: TENANT_OPERATOR_CONFIG_YAML + value: $(params.tenant_operator_config_yaml) - name: STANDALONE_SLS_SERVICE value: $(params.sls_service) - name: IS_GITOPS_FVT_ENV From 2a741c3b67bd1522a6aa8eae11c70b93b62f4d5e Mon Sep 17 00:00:00 2001 From: Josef Harte Date: Wed, 22 Jul 2026 17:49:28 +0100 Subject: [PATCH 2/6] fix tests --- python/tests/integration/aiservice_install/test_app.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/python/tests/integration/aiservice_install/test_app.py b/python/tests/integration/aiservice_install/test_app.py index ddb7c2d6137..a0ed47d25f5 100644 --- a/python/tests/integration/aiservice_install/test_app.py +++ b/python/tests/integration/aiservice_install/test_app.py @@ -26,6 +26,7 @@ def test_install_noninteractive(tmpdir): tmpdir.join("authorized_entitlement.lic").write("testLicense") tmpdir.join("aiservice-tenant-affinity-config.yaml").write("#") + tmpdir.join("aiservice-tenant-operator-config.yaml").write("#") with mock.patch("mas.cli.cli.config"): dynamic_client = MagicMock(DynamicClient) resources = MagicMock() @@ -154,6 +155,8 @@ def test_install_noninteractive(tmpdir): "2026-08-28", "--tenant-scheduling-config-file", f"{tmpdir}/aiservice-tenant-affinity-config.yaml", + "--tenant-operator-config-file", + f"{tmpdir}/aiservice-tenant-operator-config.yaml", "--rsl-ca-crt", "testRslCaCert", "--accept-license", @@ -166,6 +169,7 @@ def test_install_noninteractive(tmpdir): def test_install_interactive_advanced(tmpdir): tmpdir.join("authorized_entitlement.lic").write("testLicense") tmpdir.join("aiservice-tenant-affinity-config.yaml").write("#") + tmpdir.join("aiservice-tenant-operator-config.yaml").write("#") tmpdir.join("mongodb-system.yaml").write("#") tmpdir.join("cert.crt").write("#") with mock.patch("mas.cli.cli.config"): @@ -259,6 +263,10 @@ def set_mixin_prompt_input(**kwargs): return "y" if re.match(".*Scheduling configuration YAML file.*", message): return f"{tmpdir}/aiservice-tenant-affinity-config.yaml" + if re.match(".*Customize the AI Service tenant operator deployment.*", message): + return "y" + if re.match(".*Tenant operator configuration YAML file.*", message): + return f"{tmpdir}/aiservice-tenant-operator-config.yaml" if re.match(".*Watsonxai api key.*", message): return "testWxApiKey" if re.match(".*Watsonxai machine learning url.*", message): From 3cb6a15babbc57e70631df8d63fbf4a5216861cf Mon Sep 17 00:00:00 2001 From: Josef Harte Date: Fri, 31 Jul 2026 15:03:26 +0100 Subject: [PATCH 3/6] update var in Tekton --- .secrets.baseline | 2 +- .../gitops/gitops-aiservice-tenant-pipeline.yml.j2 | 6 +++--- tekton/src/tasks/gitops/gitops-aiservice-tenant.yml.j2 | 7 ++++--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/.secrets.baseline b/.secrets.baseline index f18c8ef4929..7bb4497fc00 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -3,7 +3,7 @@ "files": "build/bin/config/oscap/ssg-rhel9-ds.xml|^.secrets.baseline$|^docs/catalogs/", "lines": null }, - "generated_at": "2026-07-22T13:39:49Z", + "generated_at": "2026-07-31T14:03:18Z", "plugins_used": [ { "name": "AWSKeyDetector" diff --git a/tekton/src/pipelines/gitops/gitops-aiservice-tenant-pipeline.yml.j2 b/tekton/src/pipelines/gitops/gitops-aiservice-tenant-pipeline.yml.j2 index 38b269d1239..5b7d4225419 100644 --- a/tekton/src/pipelines/gitops/gitops-aiservice-tenant-pipeline.yml.j2 +++ b/tekton/src/pipelines/gitops/gitops-aiservice-tenant-pipeline.yml.j2 @@ -97,7 +97,7 @@ spec: - name: tenant_scheduling_config_yaml type: string default: "" - - name: tenant_operator_config_yaml + - name: tenant_operator_config type: string default: "" @@ -207,7 +207,7 @@ spec: value: $(params.tenant_entitlement_end_date) - name: tenant_scheduling_config_yaml value: $(params.tenant_scheduling_config_yaml) - - name: tenant_operator_config_yaml - value: $(params.tenant_operator_config_yaml) + - name: tenant_operator_config + value: $(params.tenant_operator_config) - name: sls_service value: $(params.sls_service) \ No newline at end of file diff --git a/tekton/src/tasks/gitops/gitops-aiservice-tenant.yml.j2 b/tekton/src/tasks/gitops/gitops-aiservice-tenant.yml.j2 index bd981473208..316eac06f7a 100644 --- a/tekton/src/tasks/gitops/gitops-aiservice-tenant.yml.j2 +++ b/tekton/src/tasks/gitops/gitops-aiservice-tenant.yml.j2 @@ -93,8 +93,9 @@ spec: type: string - name: tenant_scheduling_config_yaml type: string - - name: tenant_operator_config_yaml + - name: tenant_operator_config type: string + default: "" - name: sls_service type: string default: "" @@ -187,8 +188,8 @@ spec: value: $(params.tenant_entitlement_end_date) - name: TENANT_SCHEDULING_CONFIG_YAML value: $(params.tenant_scheduling_config_yaml) - - name: TENANT_OPERATOR_CONFIG_YAML - value: $(params.tenant_operator_config_yaml) + - name: TENANT_OPERATOR_CONFIG + value: $(params.tenant_operator_config) - name: STANDALONE_SLS_SERVICE value: $(params.sls_service) - name: IS_GITOPS_FVT_ENV From c94ab47cf39394d9c962e6d5a49070e26cdb3f83 Mon Sep 17 00:00:00 2001 From: Josef Harte Date: Tue, 4 Aug 2026 14:48:04 +0100 Subject: [PATCH 4/6] trigger ci From b43ce1f5d5c3ddef6e45beed23057c66b747d4f9 Mon Sep 17 00:00:00 2001 From: Josef Harte Date: Wed, 5 Aug 2026 10:27:13 +0100 Subject: [PATCH 5/6] fix secret re-init --- python/src/mas/cli/install/settings/additionalConfigs.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/python/src/mas/cli/install/settings/additionalConfigs.py b/python/src/mas/cli/install/settings/additionalConfigs.py index 05f01a2de7f..197bded9bb8 100644 --- a/python/src/mas/cli/install/settings/additionalConfigs.py +++ b/python/src/mas/cli/install/settings/additionalConfigs.py @@ -212,14 +212,13 @@ def slsLicenseFile(self) -> None: def aiserviceConfig(self) -> None: self.aiserviceConfigSecret = None + aiserviceConfigSecret: dict[str, Any] = {"apiVersion": "v1", "kind": "Secret", "type": "Opaque", "metadata": {"name": "pipeline-aiservice-config"}} if self.aiserviceTenantSchedulingConfigFileLocal: - aiserviceConfigSecret: dict[str, Any] = {"apiVersion": "v1", "kind": "Secret", "type": "Opaque", "metadata": {"name": "pipeline-aiservice-config"}} self.setParam("tenant_scheduling_config_file", f"/workspace/aiservice/{path.basename(self.aiserviceTenantSchedulingConfigFileLocal)}") self.aiserviceConfigSecret = self.addFilesToSecret(aiserviceConfigSecret, self.aiserviceTenantSchedulingConfigFileLocal, "yaml") if self.aiserviceTenantOperatorConfigFileLocal: - aiserviceConfigSecret: dict[str, Any] = {"apiVersion": "v1", "kind": "Secret", "type": "Opaque", "metadata": {"name": "pipeline-aiservice-config"}} self.setParam("tenant_operator_config_file", f"/workspace/aiservice/{path.basename(self.aiserviceTenantOperatorConfigFileLocal)}") self.aiserviceConfigSecret = self.addFilesToSecret(aiserviceConfigSecret, self.aiserviceTenantOperatorConfigFileLocal, "yaml") From 40f969ab5bd65c28efd5aee9964715c46d5f22c1 Mon Sep 17 00:00:00 2001 From: Josef Harte Date: Tue, 11 Aug 2026 09:44:50 +0100 Subject: [PATCH 6/6] trigger ci