diff --git a/python/src/mas/cli/aiservice/install/app.py b/python/src/mas/cli/aiservice/install/app.py
index 4389da5a50a..41ab26ccc8c 100644
--- a/python/src/mas/cli/aiservice/install/app.py
+++ b/python/src/mas/cli/aiservice/install/app.py
@@ -124,14 +124,29 @@ def configAibroker(self):
self.configOperationMode()
+ @logMethodCall
+ def chooseInstallFlavour(self) -> None:
+ self.printH1("Choose Install Mode")
+ self.printDescription([
+ "There are two flavours of the interactive install to choose from: Simplified and Advanced. The simplified option will present fewer dialogs, but you lose the ability to configure the following aspects of the installation:",
+ " - Configure certificate issuer",
+ ])
+ self.showAdvancedOptions = self.yesOrNo("Show advanced installation options")
+
@logMethodCall
def interactiveMode(self, simplified: bool, advanced: bool) -> None:
# Interactive mode
self.interactiveMode = True
+ if simplified:
+ self.showAdvancedOptions = False
+ elif advanced:
+ self.showAdvancedOptions = True
+ else:
+ self.chooseInstallFlavour()
+
self.storageClassProvider = "custom"
self.slsLicenseFileLocal = None
- self.showAdvancedOptions = True
# Catalog
self.configCatalog()
@@ -150,7 +165,7 @@ def interactiveMode(self, simplified: bool, advanced: bool) -> None:
self.configCertManager()
self.configAibroker()
if self.devMode:
- self.configAppChannel("aibroker")
+ self.configAppChannel()
self.aiServiceSettings()
self.aiServiceTenantSettings()
@@ -505,6 +520,7 @@ def setupApprovals(self, namespace: str) -> None:
logger.debug(f"Approval workflow for {approval['id']} will be enabled during install ({approval['maxRetries']} / {approval['retryDelay']}s / {approval['ignoreFailure']})")
self.initializeApprovalConfigMap(namespace, approval['id'], True, approval['maxRetries'], approval['retryDelay'], approval['ignoreFailure'])
+ @logMethodCall
def aiServiceSettings(self) -> None:
self.printH1("AI Service Settings")
@@ -537,6 +553,18 @@ def aiServiceSettings(self) -> None:
self.promptForString("Storage tenants bucket", "aiservice_s3_tenants_bucket")
self.promptForString("Storage templates bucket", "aiservice_s3_templates_bucket")
+ # Configure Certificate Issuer
+ self.configCertIssuer()
+
+ @logMethodCall
+ def configCertIssuer(self):
+ if self.showAdvancedOptions:
+ self.printH1("Configure Certificate Issuer")
+ configureCertIssuer = self.yesOrNo('Configure certificate issuer')
+ if configureCertIssuer:
+ self.promptForString("Certificate issuer name", "aiservice_certificate_issuer")
+
+ @logMethodCall
def aiServiceTenantSettings(self) -> None:
self.printH1("AI Service Tenant Settings")
self.printDescription([
@@ -829,7 +857,7 @@ def configDRO(self) -> None:
self.promptForString("IBM Data Reporter Operator (DRO) Namespace", "dro_namespace", default="redhat-marketplace")
@logMethodCall
- def configAppChannel(self, appId):
+ def configAppChannel(self):
self.params["aiservice_channel"] = prompt(HTML('Custom channel for AI Service '))
@logMethodCall
diff --git a/python/src/mas/cli/aiservice/install/argBuilder.py b/python/src/mas/cli/aiservice/install/argBuilder.py
index 92c7e677245..c24b43ec763 100644
--- a/python/src/mas/cli/aiservice/install/argBuilder.py
+++ b/python/src/mas/cli/aiservice/install/argBuilder.py
@@ -103,6 +103,11 @@ def buildCommand(self) -> str:
# AI Service Advanced Settings
# -----------------------------------------------------------------------------
+
+ # Certificate Issuer
+ if self.getParam('aiservice_certificate_issuer') != "":
+ command += f" --aiservice-certificate-issuer \"{self.getParam('aiservice_certificate_issuer')}\"{newline}"
+
if self.getParam('aiservice_s3_accesskey') != "":
command += f" --s3-accesskey \"{self.getParam('aiservice_s3_accesskey')}\"{newline}"
if self.getParam('aiservice_s3_secretkey') != "":
diff --git a/python/src/mas/cli/aiservice/install/argParser.py b/python/src/mas/cli/aiservice/install/argParser.py
index e99a07b33a7..883a958be79 100644
--- a/python/src/mas/cli/aiservice/install/argParser.py
+++ b/python/src/mas/cli/aiservice/install/argParser.py
@@ -401,6 +401,12 @@ def isValidFile(parser, arg) -> str:
default="non-production",
help="Environment type (default: non-production)"
)
+aiServiceArgGroup.add_argument(
+ "--aiservice-certificate-issuer",
+ dest="aiservice_certificate_issuer",
+ required=False,
+ help="Provide the name of the Issuer to configure AI Service to issue certificates",
+)
# IBM Db2 Universal Operator
diff --git a/python/src/mas/cli/aiservice/install/params.py b/python/src/mas/cli/aiservice/install/params.py
index 7b6aa428971..39047dc267d 100644
--- a/python/src/mas/cli/aiservice/install/params.py
+++ b/python/src/mas/cli/aiservice/install/params.py
@@ -97,4 +97,7 @@
"rsl_token",
"rsl_ca_crt",
"environment_type",
+
+ # Certificate Issuer
+ "aiservice_certificate_issuer",
]
diff --git a/python/src/mas/cli/aiservice/install/summarizer.py b/python/src/mas/cli/aiservice/install/summarizer.py
index b560e3d4892..f09d24be3e8 100644
--- a/python/src/mas/cli/aiservice/install/summarizer.py
+++ b/python/src/mas/cli/aiservice/install/summarizer.py
@@ -47,6 +47,9 @@ def aiServiceSummary(self) -> None:
self.printParamSummary("Instance ID", "aiservice_instance_id")
self.printParamSummary("Environment Type", "environment_type")
+ if "aiservice_certificate_issuer" in self.params:
+ self.printParamSummary("Certificate Issuer", "aiservice_certificate_issuer")
+
self.printH2("AI Service Tenant Entitlement")
self.printParamSummary("Entitlement Type", "tenant_entitlement_type")
self.printParamSummary("Start Date", "tenant_entitlement_start_date")
diff --git a/python/src/mas/cli/install/app.py b/python/src/mas/cli/install/app.py
index 856e003a8ef..306af5024ff 100644
--- a/python/src/mas/cli/install/app.py
+++ b/python/src/mas/cli/install/app.py
@@ -1026,6 +1026,17 @@ def aiServiceSettings(self) -> None:
self.promptForString("Storage tenants bucket", "aiservice_s3_tenants_bucket")
self.promptForString("Storage templates bucket", "aiservice_s3_templates_bucket")
+ # Configure Certificate Issuer
+ self.configAIServiceCertIssuer()
+
+ @logMethodCall
+ def configAIServiceCertIssuer(self):
+ if self.showAdvancedOptions:
+ self.printH1("Configure Certificate Issuer")
+ configureCertIssuer = self.yesOrNo('Configure certificate issuer')
+ if configureCertIssuer:
+ self.promptForString("Certificate issuer name", "aiservice_certificate_issuer")
+
@logMethodCall
def aiServiceTenantSettings(self) -> None:
if self.installAIService:
diff --git a/python/src/mas/cli/install/argBuilder.py b/python/src/mas/cli/install/argBuilder.py
index ecc367916e1..71ddb0002c8 100644
--- a/python/src/mas/cli/install/argBuilder.py
+++ b/python/src/mas/cli/install/argBuilder.py
@@ -312,6 +312,11 @@ def buildCommand(self) -> str:
command += f" --aiservice-instance-id \"{self.getParam('aiservice_instance_id')}\"{newline}"
if self.getParam('aiservice_channel') != "":
command += f" --aiservice-channel \"{self.getParam('aiservice_channel')}\"{newline}"
+
+ # Certificate Issuer for AI Service
+ if self.getParam('aiservice_certificate_issuer') != "":
+ command += f" --aiservice-certificate-issuer \"{self.getParam('aiservice_certificate_issuer')}\"{newline}"
+
if self.getParam('aiservice_s3_accesskey') != "" and self.getParam('minio_root_user') == "":
command += f" --s3-accesskey \"{self.getParam('aiservice_s3_accesskey')}\"{newline}"
if self.getParam('aiservice_s3_secretkey') != "" and self.getParam('minio_root_user') == "":
diff --git a/python/src/mas/cli/install/argParser.py b/python/src/mas/cli/install/argParser.py
index 6cf8d0aa104..48990e1c932 100644
--- a/python/src/mas/cli/install/argParser.py
+++ b/python/src/mas/cli/install/argParser.py
@@ -767,11 +767,11 @@ def isValidFile(parser: argparse.ArgumentParser, arg: str) -> str:
# S3 Storage
# -----------------------------------------------------------------------------
-s3ArgGroup = installArgParser.add_argument_group(
+aiServiceS3ArgGroup = installArgParser.add_argument_group(
"S3 Storage",
"Configure S3-compatible object storage for AI Service including Minio installation or external S3 connection details (host, port, SSL, credentials, bucket, and region)."
)
-s3ArgGroup.add_argument(
+aiServiceS3ArgGroup.add_argument(
"--install-minio",
dest="install_minio_aiservice",
required=False,
@@ -782,13 +782,13 @@ def isValidFile(parser: argparse.ArgumentParser, arg: str) -> str:
# S3 - Minio
# -----------------------------------------------------------------------------
-s3ArgGroup.add_argument(
+aiServiceS3ArgGroup.add_argument(
"--minio-root-user",
dest="minio_root_user",
required=False,
help="Root user for minio"
)
-s3ArgGroup.add_argument(
+aiServiceS3ArgGroup.add_argument(
"--minio-root-password",
dest="minio_root_password",
required=False,
@@ -797,43 +797,43 @@ def isValidFile(parser: argparse.ArgumentParser, arg: str) -> str:
# S3 - External Connection
# -----------------------------------------------------------------------------
-s3ArgGroup.add_argument(
+aiServiceS3ArgGroup.add_argument(
"--s3-host",
dest="aiservice_s3_host",
required=False,
help="Hostname or IP address of the S3 storage service"
)
-s3ArgGroup.add_argument(
+aiServiceS3ArgGroup.add_argument(
"--s3-port",
dest="aiservice_s3_port",
required=False,
help="Port number for the S3 storage service"
)
-s3ArgGroup.add_argument(
+aiServiceS3ArgGroup.add_argument(
"--s3-ssl",
dest="aiservice_s3_ssl",
required=False,
help="Enable or disable SSL for S3 connection (true/false)"
)
-s3ArgGroup.add_argument(
+aiServiceS3ArgGroup.add_argument(
"--s3-accesskey",
dest="aiservice_s3_accesskey",
required=False,
help="Access key for authenticating with the S3 storage service"
)
-s3ArgGroup.add_argument(
+aiServiceS3ArgGroup.add_argument(
"--s3-secretkey",
dest="aiservice_s3_secretkey",
required=False,
help="Secret key for authenticating with the S3 storage service"
)
-s3ArgGroup.add_argument(
+aiServiceS3ArgGroup.add_argument(
"--s3-region",
dest="aiservice_s3_region",
required=False,
help="Region for the S3 storage service"
)
-s3ArgGroup.add_argument(
+aiServiceS3ArgGroup.add_argument(
"--s3-bucket-prefix",
dest="aiservice_s3_bucket_prefix",
required=False,
@@ -842,14 +842,14 @@ def isValidFile(parser: argparse.ArgumentParser, arg: str) -> str:
# S3 - Bucket Naming
# -----------------------------------------------------------------------------
-s3ArgGroup.add_argument(
+aiServiceS3ArgGroup.add_argument(
"--s3-tenants-bucket",
dest="aiservice_s3_tenants_bucket",
required=False,
default="km-tenants",
help="Name of the S3 bucket for tenants storage"
)
-s3ArgGroup.add_argument(
+aiServiceS3ArgGroup.add_argument(
"--s3-templates-bucket",
dest="aiservice_s3_templates_bucket",
required=False,
@@ -859,125 +859,132 @@ def isValidFile(parser: argparse.ArgumentParser, arg: str) -> str:
# Watsonx
# -----------------------------------------------------------------------------
-watsonxArgGroup = installArgParser.add_argument_group(
+aiServiceWatsonxArgGroup = installArgParser.add_argument_group(
"Watsonx",
"Configure IBM Watsonx integration for AI Service including API key, instance ID, project ID, and service URL."
)
-watsonxArgGroup.add_argument(
+aiServiceWatsonxArgGroup.add_argument(
"--watsonxai-apikey",
dest="aiservice_watsonxai_apikey",
required=False,
help="API key for WatsonX"
)
-watsonxArgGroup.add_argument(
+aiServiceWatsonxArgGroup.add_argument(
"--watsonxai-url",
dest="aiservice_watsonxai_url",
required=False,
help="URL endpoint for WatsonX"
)
-watsonxArgGroup.add_argument(
+aiServiceWatsonxArgGroup.add_argument(
"--watsonxai-project-id",
dest="aiservice_watsonxai_project_id",
required=False,
help="Project ID for WatsonX"
)
-watsonxArgGroup.add_argument(
+aiServiceWatsonxArgGroup.add_argument(
"--watsonx-action",
dest="aiservice_watsonx_action",
required=False,
help="Action to perform with WatsonX (install/remove)"
)
-watsonxArgGroup.add_argument(
+aiServiceWatsonxArgGroup.add_argument(
"--watsonxai-ca-crt",
dest="aiservice_watsonxai_ca_crt",
required=False,
help="CA certificate for WatsonX AI (PEM format, optional, only if using self-signed certs)"
)
-watsonxArgGroup.add_argument(
+aiServiceWatsonxArgGroup.add_argument(
"--watsonxai-deployment-id",
dest="aiservice_watsonxai_deployment_id",
required=False,
help="WatsonX deployment ID"
)
-watsonxArgGroup.add_argument(
+aiServiceWatsonxArgGroup.add_argument(
"--watsonxai-space-id",
dest="aiservice_watsonxai_space_id",
required=False,
help="WatsonX space ID"
)
-watsonxArgGroup.add_argument(
+aiServiceWatsonxArgGroup.add_argument(
"--watsonxai-instance-id",
dest="aiservice_watsonxai_instance_id",
required=False,
help="WatsonX instance ID"
)
-watsonxArgGroup.add_argument(
+aiServiceWatsonxArgGroup.add_argument(
"--watsonxai-username",
dest="aiservice_watsonxai_username",
required=False,
help="WatsonX username"
)
-watsonxArgGroup.add_argument(
+aiServiceWatsonxArgGroup.add_argument(
"--watsonxai-version",
dest="aiservice_watsonxai_version",
required=False,
help="WatsonX version"
)
-watsonxArgGroup.add_argument(
+aiServiceWatsonxArgGroup.add_argument(
"--watsonxai-onprem",
dest="aiservice_watsonxai_on_prem",
required=False,
help="WatsonX deployed on prem"
)
-# AI Service
+# AI Service Tenant
# -----------------------------------------------------------------------------
-aiServiceArgGroup = installArgParser.add_argument_group("Maximo AI Service")
+aiServiceTenantArgGroup = installArgParser.add_argument_group("Maximo AI Service Tenant")
-aiServiceArgGroup.add_argument(
+aiServiceTenantArgGroup.add_argument(
"--tenant-entitlement-type",
dest="tenant_entitlement_type",
required=False,
default="standard",
help="Entitlement type for AI Service tenant"
)
-aiServiceArgGroup.add_argument(
+aiServiceTenantArgGroup.add_argument(
"--tenant-entitlement-start-date",
dest="tenant_entitlement_start_date",
required=False,
help="Start date for AI Service tenant"
)
-aiServiceArgGroup.add_argument(
+aiServiceTenantArgGroup.add_argument(
"--tenant-entitlement-end-date",
dest="tenant_entitlement_end_date",
required=False,
help="End date for AI Service tenant"
)
-aiServiceArgGroup.add_argument(
+aiServiceTenantArgGroup.add_argument(
"--rsl-url",
dest="rsl_url",
required=False,
help="rsl url"
)
-aiServiceArgGroup.add_argument(
+aiServiceTenantArgGroup.add_argument(
"--rsl-org-id",
dest="rsl_org_id",
required=False,
help="org id for rsl"
)
-aiServiceArgGroup.add_argument(
+aiServiceTenantArgGroup.add_argument(
"--rsl-token",
dest="rsl_token",
required=False,
help="token for rsl"
)
-aiServiceArgGroup.add_argument(
+aiServiceTenantArgGroup.add_argument(
"--rsl-ca-crt",
dest="rsl_ca_crt",
required=False,
help="CA certificate for RSL API (PEM format, optional, only if using self-signed certs)"
)
+
+# AI Service Configuration
+# -----------------------------------------------------------------------------
+aiServiceArgGroup = installArgParser.add_argument_group(
+ "Maximo AI Service",
+ "Maximo AI Service configuration such as certificate Issuer, environment type"
+)
aiServiceArgGroup.add_argument(
"--environment-type",
dest="environment_type",
@@ -985,6 +992,12 @@ def isValidFile(parser: argparse.ArgumentParser, arg: str) -> str:
default="non-production",
help="Environment type (default: non-production)"
)
+aiServiceArgGroup.add_argument(
+ "--aiservice-certificate-issuer",
+ dest="aiservice_certificate_issuer",
+ required=False,
+ help="Provide the name of the Issuer to configure AI Service to issue certificates",
+)
# IBM Cloud Pak for Data
# -----------------------------------------------------------------------------
diff --git a/python/src/mas/cli/install/params.py b/python/src/mas/cli/install/params.py
index 2e34c5720f1..bf6b89aefc9 100644
--- a/python/src/mas/cli/install/params.py
+++ b/python/src/mas/cli/install/params.py
@@ -204,5 +204,8 @@
"rsl_org_id",
"rsl_token",
"rsl_ca_crt",
- "environment_type"
+ "environment_type",
+
+ # Certificate Issuer
+ "aiservice_certificate_issuer"
]
diff --git a/python/src/mas/cli/install/summarizer.py b/python/src/mas/cli/install/summarizer.py
index a881f6e9d51..ee295044c9f 100644
--- a/python/src/mas/cli/install/summarizer.py
+++ b/python/src/mas/cli/install/summarizer.py
@@ -238,6 +238,9 @@ def aiServiceSummary(self) -> None:
self.printParamSummary("Instance ID", "aiservice_instance_id")
self.printParamSummary("Environment Type", "environment_type")
+ if "aiservice_certificate_issuer" in self.params:
+ self.printParamSummary("Certificate Issuer", "aiservice_certificate_issuer")
+
self.printH2("AI Service Tenant Entitlement")
self.printParamSummary("Entitlement Type", "tenant_entitlement_type")
self.printParamSummary("Start Date", "tenant_entitlement_start_date")
diff --git a/python/test/aiservice/install/test_app.py b/python/test/aiservice/install/test_app.py
index 71e2d61dcf6..cd0c3748ebe 100644
--- a/python/test/aiservice/install/test_app.py
+++ b/python/test/aiservice/install/test_app.py
@@ -109,7 +109,7 @@ def test_install_noninteractive(tmpdir):
'--skip-pre-check'])
-def test_install_interactive(tmpdir):
+def test_install_interactive_advanced(tmpdir):
tmpdir.join('authorized_entitlement.lic').write('testLicense')
tmpdir.join('mongodb-system.yaml').write('#')
tmpdir.join('cert.crt').write('#')
@@ -161,6 +161,132 @@ def set_mixin_prompt_input(**kwargs):
message = str(kwargs['message'])
if re.match('.*Proceed with this cluster?.*', message):
return 'y'
+ if re.match('.*Show advanced installation options?.*', message):
+ return 'y'
+ if re.match('.*Do you accept the license terms?.*', message):
+ return 'y'
+ if re.match('.*ReadWriteOnce (RWO) storage class.*', message):
+ return 'nfs-client'
+ if re.match('.*ReadWriteMany (RWX) storage class.*', message):
+ return 'nfs-client'
+ if re.match('.*SLS Mode.*', message):
+ return '1'
+ if re.match('.*License file.*', message):
+ return f'{tmpdir}/authorized_entitlement.lic'
+ if re.match('.*Instance ID.*', message):
+ return 'apmdevops'
+ if re.match('.*Operational Mode.*', message):
+ return '1'
+ if re.match('.*Install Minio.*', message):
+ return 'y'
+ if re.match('.*minio root username.*', message):
+ return 'username'
+ if re.match('.*minio root password.*', message):
+ return 'password'
+ if re.match('.*Configure certificate issuer?.*', message):
+ return 'y'
+ if re.match('.*Certificate issuer name.*', message):
+ return 'cert-issuer'
+ if re.match('.*RSL url.*', message):
+ return 'https://rls.maximo.test.ibm.com'
+ if re.match('.*ORG Id of RSL.*', message):
+ return 'rslOrgId'
+ if re.match('.*Token for RSL.*', message):
+ return 'rslToken'
+ if re.match('.*Watsonxai machine learning url.*', message):
+ return 'watsonxUrl'
+ if re.match('.*Does the RSL API use a self-signed certificate.*', message):
+ return 'n'
+ if re.match('.*Does the Watsonxai AI use a self-signed certificate.*', message):
+ return 'n'
+ if re.match('.*Create MongoDb cluster.*', message):
+ return 'n'
+ if re.match('.*Select Local configuration directory.*', message):
+ return str(tmpdir)
+ if re.match('.*MongoDb Username.*', message):
+ return 'mongodbUser'
+ if re.match('.*MongoDb Password.*', message):
+ return 'mongodbPassword'
+ if re.match('.*Path to certificate file.*', message):
+ return f'{tmpdir}/cert.crt'
+ if re.match(".*System mongodb configuration file 'mongodb-system.yaml' already exists", message):
+ return 'n'
+ if re.match(".*Proceed with these settings.*", message):
+ return 'y'
+ if re.match(".*Wait for PVCs to bind.*", message):
+ return 'n'
+ mixins_prompt.side_effect = set_mixin_prompt_input
+
+ def set_app_prompt_input(**kwargs):
+ message = str(kwargs['message'])
+ if re.match('.*ReadWriteOnce (RWO) storage class.*', message):
+ return 'nfs-client'
+ if re.match('.*ReadWriteMany (RWX) storage class.*', message):
+ return 'nfs-client'
+ app_prompt.side_effect = set_app_prompt_input
+
+ storage_class = MagicMock()
+ get_storage_classes.return_value = [storage_class]
+ storage_class.metadata = MagicMock()
+ storage_class.metadata.name = 'nfs-client'
+ app = AiServiceInstallApp()
+ app.install(argv=[])
+
+
+def test_install_interactive_simplified(tmpdir):
+ tmpdir.join('authorized_entitlement.lic').write('testLicense')
+ tmpdir.join('mongodb-system.yaml').write('#')
+ tmpdir.join('cert.crt').write('#')
+ with mock.patch('mas.cli.cli.config'):
+ dynamic_client = MagicMock(DynamicClient)
+ resources = MagicMock()
+ dynamic_client.resources = resources
+ routes_api = MagicMock()
+ catalog_api = MagicMock()
+ crd_api = MagicMock()
+ namespace_api = MagicMock()
+ cluster_role_binding_api = MagicMock()
+ pvc_api = MagicMock()
+ secret_api = MagicMock()
+ storage_class_api = MagicMock()
+ license_api = MagicMock()
+ resource_apis = {'CatalogSource': catalog_api, 'Route': routes_api, 'CustomResourceDefinition': crd_api, 'Namespace': namespace_api,
+ 'ClusterRoleBinding': cluster_role_binding_api, 'PersistentVolumeClaim': pvc_api, 'Secret': secret_api,
+ 'StorageClass': storage_class_api, 'LicenseService': license_api}
+ resources.get.side_effect = lambda **kwargs: resource_apis.get(kwargs['kind'], None)
+ route = MagicMock()
+ route.spec = MagicMock()
+ route.spec.host = 'maximo.ibm.com'
+ route.spec.displayName = supportedCatalogs['amd64'][1]
+ routes_api.get.return_value = route
+ catalog_api.get.side_effect = NotFoundError(ApiException(status='404'))
+ with (
+ mock.patch('mas.cli.cli.DynamicClient') as dynamic_client_class,
+ mock.patch('mas.cli.cli.getNodes') as get_nodes,
+ mock.patch('mas.cli.cli.isAirgapInstall') as is_airgap_install,
+ mock.patch('mas.cli.aiservice.install.app.getCurrentCatalog') as get_current_catalog,
+ mock.patch('mas.cli.aiservice.install.app.installOpenShiftPipelines'),
+ mock.patch('mas.cli.aiservice.install.app.updateTektonDefinitions'),
+ mock.patch('mas.cli.aiservice.install.app.prepareAiServicePipelinesNamespace'),
+ mock.patch('mas.cli.aiservice.install.app.launchInstallPipeline') as launch_ai_service_install_pipeline,
+ mock.patch('mas.cli.cli.isSNO') as is_sno,
+ mock.patch('mas.cli.displayMixins.prompt') as mixins_prompt,
+ mock.patch('mas.cli.aiservice.install.app.prompt') as app_prompt,
+ mock.patch('mas.cli.aiservice.install.app.getStorageClasses') as get_storage_classes
+ ):
+ dynamic_client_class.return_value = dynamic_client
+ get_nodes.return_value = [{'status': {'nodeInfo': {'architecture': 'amd64'}}}]
+ is_airgap_install.return_value = False
+ get_current_catalog.return_value = {'catalogId': supportedCatalogs['amd64'][1]}
+ launch_ai_service_install_pipeline.return_value = 'https://pipeline.test.maximo.ibm.com'
+ is_sno.return_value = False
+
+ def set_mixin_prompt_input(**kwargs):
+ message = str(kwargs['message'])
+ if re.match('.*Proceed with this cluster?.*', message):
+ return 'y'
+ if re.match('.*Show advanced installation options?.*', message):
+ return 'n'
if re.match('.*Do you accept the license terms?.*', message):
return 'y'
if re.match('.*ReadWriteOnce (RWO) storage class.*', message):
@@ -171,10 +297,16 @@ def set_mixin_prompt_input(**kwargs):
return '1'
if re.match('.*License file.*', message):
return f'{tmpdir}/authorized_entitlement.lic'
+ if re.match('.*Instance ID.*', message):
+ return 'apmdevops'
if re.match('.*Operational Mode.*', message):
return '1'
if re.match('.*Install Minio.*', message):
return 'y'
+ if re.match('.*minio root username.*', message):
+ return 'username'
+ if re.match('.*minio root password.*', message):
+ return 'password'
if re.match('.*RSL url.*', message):
return 'https://rls.maximo.test.ibm.com'
if re.match('.*ORG Id of RSL.*', message):
diff --git a/tekton/src/params/install-aiservice.yml.j2 b/tekton/src/params/install-aiservice.yml.j2
index 54815d4810b..9e57c1f76de 100644
--- a/tekton/src/params/install-aiservice.yml.j2
+++ b/tekton/src/params/install-aiservice.yml.j2
@@ -155,3 +155,9 @@
description: token for RSL
default: ""
+# MAS Application Configuration - IBM Maximo AI Service - Certificate Issuer
+# -----------------------------------------------------------------------------
+- name: aiservice_certificate_issuer
+ type: string
+ description: Name of the Issuer to configure AI Service to issue certificates
+ default: ""
diff --git a/tekton/src/pipelines/taskdefs/aiservice/aiservice.yml.j2 b/tekton/src/pipelines/taskdefs/aiservice/aiservice.yml.j2
index 7a9b88f710a..f9c3f9ddab0 100644
--- a/tekton/src/pipelines/taskdefs/aiservice/aiservice.yml.j2
+++ b/tekton/src/pipelines/taskdefs/aiservice/aiservice.yml.j2
@@ -87,6 +87,9 @@
- name: environment_type
value: $(params.environment_type)
+ - name: aiservice_certificate_issuer
+ value: $(params.aiservice_certificate_issuer)
+
taskRef:
name: mas-devops-aiservice
kind: Task
diff --git a/tekton/src/tasks/aiservice/aiservice.yml.j2 b/tekton/src/tasks/aiservice/aiservice.yml.j2
index 0732ebf4989..62dc2977e23 100644
--- a/tekton/src/tasks/aiservice/aiservice.yml.j2
+++ b/tekton/src/tasks/aiservice/aiservice.yml.j2
@@ -152,6 +152,10 @@ spec:
- name: rsl_token
type: string
+ # Certificate Issuer
+ - name: aiservice_certificate_issuer
+ type: string
+
stepTemplate:
env:
{{ lookup('template', task_src_dir ~ '/common/cli-env.yml.j2') | indent(6) }}
@@ -249,6 +253,10 @@ spec:
- name: RSL_TOKEN
value: $(params.rsl_token)
+ # Certificate Issuer
+ - name: AISERVICE_CERTIFICATE_ISSUER
+ value: $(params.aiservice_certificate_issuer)
+
steps:
- name: aiservice
command: