Before the install actually starts you will be presented with a summary of all your choices and a non-interactive command that will allow you to repeat the same installation without going through all the prompts again.
-
+
@@ -105,8 +105,8 @@ docker run -e IBM_ENTITLEMENT_KEY -e SUPERUSER_PASSWORD -ti --rm -v ~:/mnt/home
oc login --token=sha256~xxxx --server=https://xxx &&
mas aiservice-install \
--mas-catalog-version @@MAS_LATEST_CATALOG@@ \
- --aibroker-instance-id aib1 \
- --aibroker-channel 9.1.x \
+ --aiservice-instance-id aib1 \
+ --aiservice-channel 9.1.x \
\
--ibm-entitlement-key '${IBM_ENTITLEMENT_KEY}' \
--license-file /mnt/home/entitlement.lic \
@@ -138,7 +138,6 @@ The engine that performs all tasks is written in Ansible, you can directly use t
- IBM Data Reporter Operator
- Red Hat Certificate Manager
- Minio
- - Mariadb
- db2
- Aiservice installation
diff --git a/image/cli/masfvt/fvt-aiservice.yml b/image/cli/masfvt/fvt-aiservice.yml
index 384fce4faee..aa8a73a6db3 100644
--- a/image/cli/masfvt/fvt-aiservice.yml
+++ b/image/cli/masfvt/fvt-aiservice.yml
@@ -5,10 +5,10 @@
# Image Pull Policy
image_pull_policy: "{{ lookup('env', 'IMAGE_PULL_POLICY') }}"
# MAS Details
- mas_app_channel_aibroker: "{{ lookup('env', 'MAS_APP_CHANNEL_AIBROKER') }}"
+ aiservice_channel: "{{ lookup('env', 'AISERVICE_CHANNEL') }}"
mas_workspace_id: "{{ lookup('env', 'MAS_WORKSPACE_ID') }}"
-
- aibroker_instance_id: "{{ lookup('env', 'AIBROKER_INSTANCE_ID') }}"
+
+ aiservice_instance_id: "{{ lookup('env', 'AISERVICE_INSTANCE_ID') }}"
# FVT Configuration
fvt_image_registry: "{{ lookup('env', 'FVT_IMAGE_REGISTRY') }}"
fvt_artifactory_username: "{{ lookup('env', 'FVT_ARTIFACTORY_USERNAME') }}"
@@ -18,7 +18,7 @@
# Pipeline Run Info
devops_build_number: "{{ lookup('env', 'DEVOPS_BUILD_NUMBER') | default('0', True) }}"
pipelinerun_name: "{{ lookup('env', 'PIPELINERUN_NAME') | default('mas-fvt-aibroker', True) }}-{{ devops_build_number }}"
- pipelinerun_namespace: "{{ lookup('env', 'PIPELINERUN_NAMESPACE') | default('mas-' ~ aibroker_instance_id ~ '-pipelines', True) }}"
+ pipelinerun_namespace: "{{ lookup('env', 'PIPELINERUN_NAMESPACE') | default('mas-' ~ aiservice_instance_id ~ '-pipelines', True) }}"
tasks:
- name: "Debug"
debug:
@@ -26,13 +26,13 @@
- "pipelinerun_name .................. {{ pipelinerun_name }}"
- "pipelinerun_namespace ............. {{ pipelinerun_namespace }}"
- ""
- - "mas_app_channel_aibroker ........... {{ mas_app_channel_aibroker }}"
- - "aibroker_instance_id ................... {{ aibroker_instance_id }}"
+ - "aiservice_channel ................. {{ aiservice_channel }}"
+ - "aiservice_instance_id ............. {{ aiservice_instance_id }}"
- ""
- "fvt_image_registry ................ {{ fvt_image_registry }}"
- "fvt_artifactory_username .......... {{ fvt_artifactory_username }}"
- "fvt_artifactory_token ............. {{ fvt_artifactory_token }}"
- - "fvt_digest_aibroker ................ {{ fvt_digest_aibroker }}"
+ - "fvt_digest_aibroker ............... {{ fvt_digest_aibroker }}"
- "ivt_digest_core ................... {{ ivt_digest_core }}"
- name: "Start fvt-aiservice pipeline"
diff --git a/image/cli/masfvt/templates/mas-fvt-aiservice.yml.j2 b/image/cli/masfvt/templates/mas-fvt-aiservice.yml.j2
index acf09e47abd..b0502969e6d 100644
--- a/image/cli/masfvt/templates/mas-fvt-aiservice.yml.j2
+++ b/image/cli/masfvt/templates/mas-fvt-aiservice.yml.j2
@@ -19,10 +19,10 @@ spec:
- name: image_pull_policy
value: "{{ image_pull_policy }}"
# MAS Info
- - name: mas_app_channel_aibroker
- value: "{{ mas_app_channel_aibroker }}"
+ - name: aiservice_channel
+ value: "{{ aiservice_channel }}"
- name: mas_instance_id
- value: "{{ aibroker_instance_id }}"
+ value: "{{ aiservice_instance_id }}"
- name: mas_workspace_id
value: "{{ mas_workspace_id }}"
# Registry
diff --git a/python/src/mas/cli/aiservice/install/app.py b/python/src/mas/cli/aiservice/install/app.py
index 4fb9b68ac76..12646a2118e 100644
--- a/python/src/mas/cli/aiservice/install/app.py
+++ b/python/src/mas/cli/aiservice/install/app.py
@@ -32,9 +32,9 @@
from ...install.catalogs import supportedCatalogs
-# AiService relies on SLS, which in turn depends on MongoDB.
+# AI Service relies on SLS, which in turn depends on MongoDB.
# SLS will utilize the shared MongoDB resource that would be used by MAS if it were deployed within the same OpenShift cluster.
-# AiService utilizes two distinct databases: DB2 is employed by the AiBroker component, while MariaDB supports OpenDataHub (ODH).
+# AI Service utilizes two distinct databases: DB2 is employed by the AiBroker component.
# By default, AiService will deploy DB2 within the same namespace as MAS (db2u), but it will be configured as a separate DB2 instance.
from ...install.settings.mongodbSettings import MongoDbSettingsMixin
@@ -56,10 +56,10 @@
from mas.devops.tekton import (
installOpenShiftPipelines,
updateTektonDefinitions,
- preparePipelinesNamespace,
+ prepareAiServicePipelinesNamespace,
prepareInstallSecrets,
testCLI,
- launchInstallPipelineForAiservice
+ launchAiServiceInstallPipeline
)
logger = logging.getLogger(__name__)
@@ -80,7 +80,7 @@ def processCatalogChoice(self) -> list:
self.catalogDigest = self.chosenCatalog["catalog_digest"]
self.catalogMongoDbVersion = self.chosenCatalog["mongo_extras_version_default"]
applications = {
- "Aibroker": "mas_aibroker_version",
+ "Aibroker": "aiservice_version",
}
self.catalogReleases = {}
@@ -96,9 +96,6 @@ def processCatalogChoice(self) -> list:
for application, key in applications.items():
# Add 9.1-feature channel based off 9.0 to those apps that have not onboarded yet
tempChosenCatalog = self.chosenCatalog[key].copy()
- if '9.1.x-feature' not in tempChosenCatalog:
- tempChosenCatalog.update({"9.1.x-feature": tempChosenCatalog["9.0.x"]})
-
self.catalogTable.append({"": application} | {key.replace(".x", ""): value for key, value in sorted(tempChosenCatalog.items(), reverse=True)})
if self.architecture == "s390x":
@@ -132,10 +129,10 @@ def configAibroker(self):
" - Must start with a lowercase letter",
" - Must end with a lowercase letter or a number"
])
- self.promptForString("Instance ID", "aibroker_instance_id", validator=InstanceIDFormatValidator())
+ self.promptForString("Instance ID", "aiservice_instance_id", validator=InstanceIDFormatValidator())
if self.slsMode == 2 and not self.getParam("sls_namespace"):
- self.setParam("sls_namespace", f"mas-{self.getParam('aibroker_instance_id')}-sls")
+ self.setParam("sls_namespace", f"mas-{self.getParam('aiservice_instance_id')}-sls")
self.configOperationMode()
@@ -145,18 +142,6 @@ def interactiveMode(self, simplified: bool, advanced: bool) -> None:
self.interactiveMode = True
self.storageClassProvider = "custom"
- self.installAssist = False
- self.installIoT = False
- self.installMonitor = False
- self.installManage = False
- self.installPredict = False
- self.installInspection = False
- self.installOptimizer = False
- self.installFacilities = False
- self.installAiBroker = True
- self.deployCP4D = False
- self.db2SetAffinity = False
- self.db2SetTolerations = False
self.slsLicenseFileLocal = None
if simplified:
@@ -185,7 +170,9 @@ def interactiveMode(self, simplified: bool, advanced: bool) -> None:
if self.devMode:
self.configAppChannel("aibroker")
- self.aibrokerSettings()
+ self.aiServiceSettings()
+ self.aiServiceTenantSettings()
+ self.aiServiceIntegrations()
# Dependencies
self.configMongoDb()
@@ -201,18 +188,6 @@ def nonInteractiveMode(self) -> None:
self.setParam("mongodb_action", "install")
self.storageClassProvider = "custom"
- self.installAssist = False
- self.installIoT = False
- self.installMonitor = False
- self.installManage = False
- self.installPredict = False
- self.installInspection = False
- self.installFacilities = False
- self.installOptimizer = False
- self.installAiBroker = True
- self.deployCP4D = False
- self.db2SetAffinity = False
- self.db2SetTolerations = False
self.slsLicenseFileLocal = None
self.approvals = {
@@ -233,6 +208,54 @@ def nonInteractiveMode(self) -> None:
if value is not None:
self.setParam(key, value)
+ elif key == "install_minio_aiservice":
+ incompatibleWithMinioInstall = [
+ "aiservice_storage_provider",
+ "aiservice_storage_accesskey",
+ "aiservice_storage_secretkey",
+ "aiservice_storage_host",
+ "aiservice_storage_port",
+ "aiservice_storage_ssl",
+ "aiservice_s3_endpoint_url",
+ "aiservice_storage_region",
+ "aiservice_tenant_s3_access_key",
+ "aiservice_tenant_s3_secret_key",
+ "aiservice_tenant_s3_endpoint_url",
+ "aiservice_tenant_s3_region"
+ ]
+ if value is None:
+ for uKey in incompatibleWithMinioInstall:
+ if vars(self.args)[uKey] is None:
+ self.fatalError(f"Parameter is required when --install-minio is not set: {uKey}")
+ elif value is not None and value == "true":
+ # If user is installing Minio in-cluster then we know how to connect to it already
+ for uKey in incompatibleWithMinioInstall:
+ if vars(self.args)[uKey] is not None:
+ self.fatalError(f"Unsupported parameter for --install-minio: {uKey}")
+ for rKey in ["minio_root_user", "minio_root_password"]:
+ if vars(self.args)[rKey] is None:
+ self.fatalError(f"Missing required parameter for --install-minio: {rKey}")
+
+ self.setParam("aiservice_storage_provider", "minio")
+
+ self.setParam("aiservice_storage_accesskey", self.args.minio_root_user)
+ self.setParam("aiservice_storage_secretkey", self.args.minio_root_password)
+
+ # TODO: Duplication -- we already have the URL, why do we need all the individual parts,
+ # especially when we don't need them for the tenant?
+ self.setParam("aiservice_storage_host", "minio-service.minio.svc.cluster.local")
+ self.setParam("aiservice_storage_port", "9000")
+ self.setParam("aiservice_storage_ssl", "false")
+ self.setParam("aiservice_s3_endpoint_url", "http://minio-service.minio.svc.cluster.local:9000")
+ self.setParam("aiservice_storage_region", "none")
+
+ self.setParam("aiservice_tenant_s3_access_key", self.args.minio_root_user)
+ self.setParam("aiservice_tenant_s3_secret_key", self.args.minio_root_password)
+ self.setParam("aiservice_tenant_s3_endpoint_url", "http://minio-service.minio.svc.cluster.local:9000")
+ self.setParam("aiservice_tenant_s3_region", "none")
+ else:
+ self.fatalError(f"Unsupported value for --install-minio: {value}")
+
elif key == "non_prod":
if not value:
self.operationalMode = 1
@@ -258,18 +281,10 @@ def nonInteractiveMode(self) -> None:
# We check for both None and "" values for the application channel parameters
# value = None means the parameter wasn't set at all
- # value = "" means the paramerter was explicitly set to "don't install this application"
- elif key == "aibroker_channel":
+ # value = "" means the parameter was explicitly set to "don't install this application"
+ elif key == "aiservice_channel":
if value is not None and value != "":
- self.setParam("mas_app_channel_aibroker", value)
- self.installAiBroker = True
-
- # Manage advanced settings that need extra processing
- elif key == "mas_app_settings_server_bundle_size":
- if value is not None:
- self.setParam(key, value)
- if value in ["jms", "snojms"]:
- self.setParam("mas_app_settings_persistent_volumes_flag", "true")
+ self.setParam("aiservice_channel", value)
# MongoDB
elif key == "mongodb_namespace":
@@ -284,7 +299,7 @@ def nonInteractiveMode(self) -> None:
self.setParam("sls_action", "install")
elif key == "dedicated_sls":
if value:
- self.setParam("sls_namespace", f"mas-{self.args.aibroker_instance_id}-sls")
+ self.setParam("sls_namespace", f"mas-{self.args.aiservice_instance_id}-sls")
# These settings are used by the CLI rather than passed to the PipelineRun
elif key == "storage_accessmode":
@@ -337,8 +352,7 @@ def nonInteractiveMode(self) -> None:
# License file is only optional for existing SLS instance
if self.slsLicenseFileLocal is None:
- if self.getParam("install_sls_aiservice") != "false":
- self.fatalError("--license-file must be set for new SLS install")
+ self.fatalError("--license-file must be set for new SLS install")
# Once we've processed the inputs, we should validate the catalog source & prompt to accept the license terms
if not self.devMode:
@@ -354,7 +368,7 @@ def install(self, argv):
# We use the presence of --mas-instance-id to determine whether
# the CLI is being started in interactive mode or not
- instanceId = args.aibroker_instance_id
+ instanceId = args.aiservice_instance_id
# Properties for arguments that control the behavior of the CLI
self.noConfirm = args.no_confirm
@@ -401,6 +415,9 @@ def install(self, argv):
# UDS install has not been supported since the January 2024 catalog update
self.setParam("uds_action", "install-dro")
+ # Install Db2 for AI Service
+ self.setParam("db2_action_aiservice", "install")
+
# User must either provide the configuration via numerous command line arguments, or the interactive prompts
if instanceId is None:
self.interactiveMode(simplified=args.simplified, advanced=args.advanced)
@@ -432,7 +449,7 @@ def install(self, argv):
self.createTektonFileWithDigest()
self.printH1("Launch Install")
- pipelinesNamespace = f"mas-{self.getParam('aibroker_instance_id')}-pipelines"
+ pipelinesNamespace = f"aiservice-{self.getParam('aiservice_instance_id')}-pipelines"
if not self.noConfirm:
self.printDescription(["If you are using storage classes that utilize 'WaitForFirstConsumer' binding mode choose 'No' at the prompt below"])
@@ -446,9 +463,9 @@ def install(self, argv):
with Halo(text=f'Preparing namespace ({pipelinesNamespace})', spinner=self.spinner) as h:
createNamespace(self.dynamicClient, pipelinesNamespace)
- preparePipelinesNamespace(
+ prepareAiServicePipelinesNamespace(
dynClient=self.dynamicClient,
- instanceId=self.getParam("aibroker_instance_id"),
+ instanceId=self.getParam("aiservice_instance_id"),
storageClass=self.pipelineStorageClass,
accessMode=self.pipelineStorageAccessMode,
waitForBind=wait,
@@ -456,7 +473,7 @@ def install(self, argv):
)
prepareInstallSecrets(
dynClient=self.dynamicClient,
- instanceId=self.getParam("aibroker_instance_id"),
+ namespace=pipelinesNamespace,
slsLicenseFile=self.slsLicenseFileSecret,
additionalConfigs=self.additionalConfigsSecret,
podTemplates=self.podTemplatesSecret,
@@ -475,13 +492,13 @@ def install(self, argv):
updateTektonDefinitions(pipelinesNamespace, self.tektonDefsPath)
h.stop_and_persist(symbol=self.successIcon, text=f"Latest Tekton definitions are installed (v{self.version})")
- with Halo(text=f"Submitting PipelineRun for {self.getParam('aibroker_instance_id')} install", spinner=self.spinner) as h:
- pipelineURL = launchInstallPipelineForAiservice(dynClient=self.dynamicClient, params=self.params)
+ with Halo(text=f"Submitting PipelineRun for {self.getParam('aiservice_instance_id')} install", spinner=self.spinner) as h:
+ pipelineURL = launchAiServiceInstallPipeline(dynClient=self.dynamicClient, params=self.params)
if pipelineURL is not None:
- h.stop_and_persist(symbol=self.successIcon, text=f"PipelineRun for {self.getParam('aibroker_instance_id')} install submitted")
+ h.stop_and_persist(symbol=self.successIcon, text=f"PipelineRun for {self.getParam('aiservice_instance_id')} install submitted")
print_formatted_text(HTML(f"\nView progress:\n