diff --git a/.secrets.baseline b/.secrets.baseline
index 0558ebcec90..4140ca9ce69 100644
--- a/.secrets.baseline
+++ b/.secrets.baseline
@@ -122,7 +122,7 @@
"hashed_secret": "b60d121b438a380c343d5ec3c2037564b82ffef3",
"is_secret": false,
"is_verified": false,
- "line_number": 186,
+ "line_number": 211,
"type": "Secret Keyword",
"verified_result": null
}
diff --git a/docs/guides/aiservice-install.md b/docs/guides/aiservice-install.md
new file mode 100644
index 00000000000..a4af98dfaca
--- /dev/null
+++ b/docs/guides/aiservice-install.md
@@ -0,0 +1,307 @@
+AI Service Installation
+===============================================================================
+Usage
+-------------------------------------------------------------------------------
+For full usage information run `mas aiservice-install --help`
+
+The `mas aiservice-install` command is specifically designed for standalone installation of AI Service version 9.1.x or above. This command provides a streamlined installation process focused solely on AI Service and its dependencies.
+
+!!! note "AI Service Installation Options"
+ - **Standalone Installation (9.1.x+)**: Use `mas aiservice-install` for dedicated AI Service installation
+ - **Integrated Installation**: AI Service can also be installed alongside MAS applications using `mas install` command
+
+Preparation
+-------------------------------------------------------------------------------
+### IBM Entitlement Key
+Access [Container Software Library](https://myibm.ibm.com/products-services/containerlibrary) using your IBMId to obtain your entitlement key.
+
+### MAS License File
+Access [IBM License Key Center](https://licensing.flexnetoperations.com/), on the **Get Keys** menu select **IBM AppPoint Suites**. Select `IBM MAXIMO APPLICATION SUITE AppPOINT LIC` and on the next page fill in the information as below:
+
+| Field | Content |
+| ---------------- | ----------------------------------------------------------------------------- |
+| Number of Keys | How many AppPoints to assign to the license file |
+| Host ID Type | Set to **Ethernet Address** |
+| Host ID | Enter any 12 digit hexadecimal string |
+| Hostname | Set to the hostname of your OCP instance, but this can be any value really. |
+| Port | Set to **27000** |
+
+The other values can be left at their defaults. Finally, click **Generate** and download the license file to your home directory as `entitlement.lic`.
+
+!!! note
+ The license file is only required if IBM Suite License Service (SLS) has not been previously installed in your cluster. If SLS is already configured, you can skip the license file configuration.
+
+### OpenShift Cluster
+You should already have a target OpenShift cluster ready to install AI Service into. If you do not already have one then refer to the [OpenShift Container Platform installation overview](https://docs.openshift.com/container-platform/4.15/installing/index.html).
+
+The CLI also supports OpenShift provisioning in many hyperscaler providers:
+
+- [AWS](../commands/provision-rosa.md)
+- [IBM Cloud](../commands/provision-roks.md)
+- [IBM DevIT FYRE (Internal)](../commands/provision-fyre.md)
+
+### Operator Catalog Selection
+If you have not already determined the catalog version for your installation, refer to the information in the [Operator Catalog](../catalogs/index.md) topic, or contact IBM Support for guidance.
+
+
+Interactive Install
+-------------------------------------------------------------------------------
+Run the `mas aiservice-install` command and follow the interactive prompts. Mount your home directory to access the license file when needed.
+
+```bash
+docker run -ti --rm -v ~:/mnt/home quay.io/ibmmas/cli:@@CLI_LATEST_VERSION@@ mas aiservice-install
+```
+
+The interactive install will guide you through the following steps:
+
+
+
+
+ If you are not already connected to an OpenShift cluster you will be prompted to provide the server URL & token to make a new connection. If you are already connected to a cluster you will be given the option to change to another cluster.
+ You will be presented with a table of available catalogs with information about the different releases of MAS available in each.
+ Confirm that you accept the IBM Maximo Application Suite license terms.
+
+
+ AI Service requires both a `ReadWriteMany` and a `ReadWriteOnce` capable storage class to be available in the cluster. The installer has the ability to recognize certain storage class providers and will default to the most appropriate storage class in these cases:
+
+ - IBMCloud Storage (ibmc-block-gold & ibmc-file-gold-gid)
+ - OpenShift Container Storage (ocs-storagecluster-ceph-rbd & ocs-storagecluster-cephfs)
+ - External OpenShift Container Storage (ocs-external-storagecluster-ceph-rbd & ocs-external-storagecluster-cephfs)
+ - NFS Client (nfs-client)
+ - Azure Managed Storage (managed-premium & azurefiles-premium)
+ - AWS Storage (gp3-cs & efs)
+
+ The names in brackets represent the `ReadWriteOnce` and `ReadWriteMany` class that will be used. Even when a recognized storage provider is detected you will be provided with the option to select your own storage classes if you wish.
+
+
+ Provide the location of your license file (e.g., `/mnt/home/entitlement.lic`), contact information, and IBM entitlement key. If you have set the IBM_ENTITLEMENT_KEY environment variable, this field will be pre-filled.
+ Note: This step is only required if IBM Suite License Service (SLS) has not been previously installed in your cluster.
+
+
+ Provide the configuration details for your AI Service instance:
+
+ - Instance ID: Unique identifier for your AI Service instance
+ - Channel: AI Service version channel (e.g., 9.1.x)
+ - S3 Storage Configuration: Configure object storage for AI Service data
+ - Database Configuration: Set up database connection for AI Service
+ - RSL Configuration: Configure Red Hat Service Locator integration
+ - Tenant Configuration: Set up AI Service tenant(s)
+ - Operational Mode: Choose between production or non-production mode
+
+
+
+ Choose how to configure AI Service dependencies:
+
+ - IBM Suite License Service (SLS): Install new instance or use existing SLS
+ - Database (Db2): Install in-cluster Db2 or provide connection to existing database
+ - IBM Data Reporter Operator (DRO): Install DRO or provide alternative configuration
+ - MinIO: Configure object storage for AI Service
+
+ For each dependency, you can choose to install it automatically or provide connection details to an existing instance.
+
+
+ Before the install 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.
+
+
+
+
+
+Non-Interactive Install
+-------------------------------------------------------------------------------
+The following command demonstrates a complete AI Service installation with all configuration options. This command will launch the MAS CLI container image, login to your OpenShift Cluster and start the AI Service installation without triggering any prompts.
+
+```bash
+IBM_ENTITLEMENT_KEY=your_entitlement_key_here
+
+docker run -e IBM_ENTITLEMENT_KEY -ti --rm -v ~:/mnt/home quay.io/ibmmas/cli:@@CLI_LATEST_VERSION@@ bash -c "
+ oc login --token=sha256~xxxx --server=https://xxx &&
+ mas aiservice-install \
+ --mas-catalog-version @@MAS_LATEST_CATALOG@@ \
+ --ibm-entitlement-key \${IBM_ENTITLEMENT_KEY} \
+ --aiservice-instance-id aiservice1 \
+ --aiservice-channel 9.1.x \
+ \
+ --storage-class-rwo nfs-client \
+ --storage-class-rwx nfs-client \
+ --storage-pipeline nfs-client \
+ --storage-accessmode ReadWriteMany \
+ \
+ --license-file /mnt/home/entitlement.lic \
+ --uds-email admin@example.com \
+ --uds-firstname John \
+ --uds-lastname Doe \
+ \
+ --dro-namespace redhat-marketplace \
+ --mongodb-namespace mongoce \
+ \
+ --s3-tenants-bucket km-tenants \
+ --s3-templates-bucket km-templates \
+ \
+ --odh-model-deployment-type serverless \
+ \
+ --watsonxai-apikey your_watsonx_api_key \
+ --watsonxai-url https://us-south.ml.cloud.ibm.com \
+ --watsonxai-project-id your_project_id \
+ \
+ --install-minio
+ --minio-root-user minio \
+ --minio-root-password minio123 \
+ \
+ --tenant-entitlement-type standard \
+ --tenant-entitlement-start-date 2025-01-01 \
+ --tenant-entitlement-end-date 2026-01-01 \
+ \
+ --rsl-url http://your-rsl-host:3001/api/v3/vector/query \
+ --rsl-org-id your_org_id \
+ --rsl-token 'Bearer your_rsl_token' \
+ \
+ --accept-license --no-confirm
+"
+```
+
+### Core Parameters
+
+| Parameter | Description | Required | Example |
+|-----------|-------------|----------|---------|
+| `--mas-catalog-version` | MAS operator catalog version | Yes | `v9-250902-amd64` |
+| `--aiservice-instance-id` | Unique identifier for AI Service instance | Yes | `aiservice1` |
+| `--aiservice-channel` | AI Service version channel | Yes | `9.1.x` |
+| `--ibm-entitlement-key` | IBM Container Registry entitlement key | Yes | `$IBM_ENTITLEMENT_KEY` |
+
+### Storage Configuration
+
+| Parameter | Description | Required | Example |
+|-----------|-------------|----------|---------|
+| `--storage-class-rwo` | ReadWriteOnce storage class | Yes | `nfs-client` |
+| `--storage-class-rwx` | ReadWriteMany storage class | Yes | `nfs-client` |
+| `--storage-pipeline` | Storage class for pipeline workloads | Yes | `nfs-client` |
+| `--storage-accessmode` | Storage access mode | Yes | `ReadWriteMany` |
+
+### License and Contact Information
+
+| Parameter | Description | Required | Example |
+|-----------|-------------|----------|---------|
+| `--license-file` | Path to MAS license file (required if SLS not installed) | Conditional | `/mnt/home/entitlement.lic` |
+| `--uds-email` | Contact email address | Yes | `admin@example.com` |
+| `--uds-firstname` | Contact first name | Yes | `John` |
+| `--uds-lastname` | Contact last name | Yes | `Doe` |
+
+### Dependency Configuration
+
+| Parameter | Description | Required | Example |
+|-----------|-------------|----------|---------|
+| `--dro-namespace` | IBM Data Reporter Operator namespace | Optional | `redhat-marketplace` |
+| `--mongodb-namespace` | MongoDB namespace (for SLS) | Optional | `mongoce` |
+
+### S3 Storage Configuration
+
+| Parameter | Description | Required | Example |
+|-----------|-------------|----------|---------|
+| `--s3-accesskey` | S3 access key | Yes | `minio` |
+| `--s3-secretkey` | S3 secret key | Yes | `minio123` |
+| `--s3-host` | S3 service host | Yes | `minio-service.minio.svc.cluster.local` |
+| `--s3-port` | S3 service port | Yes | `9000` |
+| `--s3-ssl` | Enable SSL for S3 connection | Yes | `false` |
+| `--s3-region` | S3 region | Yes | `none` |
+| `--s3-bucket-prefix` | Prefix for S3 buckets | Yes | `s3-` |
+| `--s3-tenants-bucket` | S3 bucket for tenant data | Yes | `km-tenants` |
+| `--s3-templates-bucket` | S3 bucket for templates | Yes | `km-templates` |
+
+### OpenDataHub Configuration
+
+| Parameter | Description | Required | Example |
+|-----------|-------------|----------|---------|
+| `--odh-model-deployment-type` | Model deployment type (serverless/raw) | Yes | `serverless` |
+
+### Watson AI Configuration
+
+| Parameter | Description | Required | Example |
+|-----------|-------------|----------|---------|
+| `--watsonxai-apikey` | Watson AI API key | Optional | `your_api_key` |
+| `--watsonxai-url` | Watson AI service URL | Optional | `https://us-south.ml.cloud.ibm.com` |
+| `--watsonxai-project-id` | Watson AI project ID | Optional | `your_project_id` |
+
+### MinIO Configuration
+
+| Parameter | Description | Required | Example |
+|-----------|-------------|----------|---------|
+| `--minio-root-user` | MinIO root username | Yes | `minio` |
+| `--minio-root-password` | MinIO root password | Yes | `minio123` |
+
+### Tenant Configuration
+
+| Parameter | Description | Required | Example |
+|-----------|-------------|----------|---------|
+| `--tenant-entitlement-type` | Tenant entitlement type | Yes | `standard` |
+| `--tenant-entitlement-start-date` | Entitlement start date (YYYY-MM-DD) | Yes | `2025-01-01` |
+| `--tenant-entitlement-end-date` | Entitlement end date (YYYY-MM-DD) | Yes | `2026-01-01` |
+
+### RSL (Red Hat Service Locator) Configuration
+
+| Parameter | Description | Required | Example |
+|-----------|-------------|----------|---------|
+| `--rsl-url` | RSL service URL | Optional | `http://host:3001/api/v3/vector/query` |
+| `--rsl-org-id` | RSL organization ID | Optional | `your_org_id` |
+| `--rsl-token` | RSL authentication token | Optional | `Bearer your_token` |
+
+### Additional Options
+
+| Parameter | Description | Required |
+|-----------|-------------|----------|
+| `--accept-license` | Accept license terms | Yes |
+| `--no-confirm` | Skip confirmation prompts | Optional |
+
+
+Dependencies
+-------------------------------------------------------------------------------
+The AI Service installation automatically handles the following dependencies:
+
+### Required Dependencies
+- **IBM Suite License Service (SLS)**: Manages licensing for AI Service. Automatically installed if not present, or can use existing SLS instance.
+- **IBM Data Reporter Operator (DRO)**: Handles data reporting and metrics
+- **Red Hat Certificate Manager**: Manages TLS certificates
+- **MinIO**: Provides S3-compatible object storage for AI Service data
+- **Db2**: Database for AI Service metadata and configuration
+
+### Optional Dependencies
+- **MongoDB Community Edition**: Only required if installing SLS for the first time
+
+
+More Information
+-------------------------------------------------------------------------------
+The AI Service installation is designed to work on any OCP cluster, but has been specifically tested in these environments:
+
+- IBMCloud ROKS
+- Microsoft Azure
+- AWS ROSA
+- IBM DevIT FYRE (internal)
+
+The engine that performs all tasks is written in Ansible. The code is open source and available in [ibm-mas/ansible-devops](https://github.com/ibm-mas/ansible-devops), and the collection is also available to install directly from [Ansible Galaxy](https://galaxy.ansible.com/ibm/mas_devops).
+
+The installation is performed inside your RedHat OpenShift cluster utilizing [OpenShift Pipelines](https://cloud.redhat.com/learn/topics/ci-cd):
+
+> OpenShift Pipelines is a Kubernetes-native CI/CD solution based on Tekton. It builds on Tekton to provide a CI/CD experience through tight integration with OpenShift and Red Hat developer tools. OpenShift Pipelines is designed to run each step of the CI/CD pipeline in its own container, allowing each step to scale independently to meet the demands of the pipeline.
+
+
+Integration with Maximo Manage
+-------------------------------------------------------------------------------
+After installing AI Service, you can bind it to Maximo Manage to enable AI capabilities:
+
+**During Manage Installation:**
+
+When installing Manage alongside AI Service using `mas install`:
+
+- **Installing AI Service with Manage** (using `--aiservice-channel`):
+ - The binding is configured automatically with default "user" tenant
+ - No additional parameters needed
+ - Any `--manage-aiservice-instance-id` or `--manage-aiservice-tenant-id` parameters will be ignored
+
+- **Using Existing AI Service** (not using `--aiservice-channel`):
+ - **Interactive Mode**: You will be prompted to select the AI Service instance and tenant
+ - **Non-Interactive Mode**: Use `--manage-aiservice-instance-id` and `--manage-aiservice-tenant-id` parameters
+
+**Post-Installation:**
+
+You can configure the AI Service binding through the Maximo Manage UI.
+
+For more information on integrating AI Service with Manage, see the [Installation Guide](install.md#application-configuration).
\ No newline at end of file
diff --git a/docs/guides/install-aiservice.md b/docs/guides/install-aiservice.md
deleted file mode 100644
index 1ba9f2e7899..00000000000
--- a/docs/guides/install-aiservice.md
+++ /dev/null
@@ -1,148 +0,0 @@
-Installation
-===============================================================================
-Usage
--------------------------------------------------------------------------------
-For full usage information run `mas aiservice-install --help`
-`mas aiservice-install` is specifically built for installation of Aiservice 9.1.x or above.
-
-For installation of Aiservice 9.0.x have to use `mas install` command.
-
-Preparation
--------------------------------------------------------------------------------
-### IBM Entitlement Key
-Access [Container Software Library](https://myibm.ibm.com/products-services/containerlibrary) using your IBMId to obtain your entitlement key.
-
-### MAS License File
-Access [IBM License Key Center](https://licensing.flexnetoperations.com/), on the **Get Keys** menu select **IBM AppPoint Suites**. Select `IBM MAXIMO APPLICATION SUITE AppPOINT LIC` and on the next page fill in the information as below:
-
-| Field | Content |
-| ---------------- | ----------------------------------------------------------------------------- |
-| Number of Keys | How many AppPoints to assign to the license file |
-| Host ID Type | Set to **Ethernet Address** |
-| Host ID | Enter any 12 digit hexadecimal string |
-| Hostname | Set to the hostname of your OCP instance, but this can be any value really. |
-| Port | Set to **27000** |
-
-
-The other values can be left at their defaults. Finally, click **Generate** and download the license file to your home directory as `entitlement.lic`.
-
-!!! note
- For more information about how to access the IBM License Key Center review the [getting started documentation](https://www.ibm.com/support/pages/system/files/inline-files/GettingStartedEnglish_2020.pdf) available from the IBM support website.
-
-### OpenShift Cluster
-You should already have a target OpenShift cluster ready to install Maximo Application suite into. If you do not already have one then refer to the [OpenShift Container Platform installation overview](https://docs.openshift.com/container-platform/4.15/installing/index.html).
-
-The CLI also supports OpenShift provisioning in many hyperscaler providers:
-
-- [AWS](../commands/provision-rosa.md)
-- [IBM Cloud](../commands/provision-roks.md)
-- [IBM DevIT FYRE (Internal)](../commands/provision-fyre.md)
-
-
-### Operator Catalog Selection
-If you have not already determined the catalog version for your installation, refer to the information in the [Operator Catalog](../catalogs/index.md) topic, or contact IBM Support for guidance.
-
-
-Interactive Install
--------------------------------------------------------------------------------
-Regardless of whether you are running a connected or disconnected installation, simply run the `mas aiservice-install` command and follow the prompts, the basic structure of the interactive flow is described below.
-
-We will need the `entitlement.lic` file to perform the installation so we will mount your home directory into the running container. When prompted you will be able to set license file to `/mnt/home/entitlement.lic` - This is a prerequisite step, required only when `sls` has not been installed previously.
-
-```bash
-docker run -ti --rm -v ~:/mnt/home quay.io/ibmmas/cli:@@CLI_LATEST_VERSION@@ mas aiservice-install
-```
-
-The interactive install will guide you through a series of questioned designed to help you arrive at the best configuration for your scenario, it can be broken down as below:
-
-
-
-
- If you are not already connected to an OpenShift cluster you will be prompted to provide the server URL & token to make a new connection. If you are already connected to a cluster you will be given the option to change to another cluster
- You will be presented with a table of available catalogs with information about the different releases of MAS
- Confirm that you accept the IBM Maximo Application Suite license terms
-
-
- MAS requires both a `ReadWriteMany` and a `ReadWriteOnce` capable storage class to be available in the cluster. The installer has the ability to recognize certain storage class providers and will default to the most appropriate storage class in these cases:
-
- - IBMCloud Storage (ibmc-block-gold & ibmc-file-gold-gid)
- - OpenShift Container Storage (ocs-storagecluster-ceph-rbd & ocs-storagecluster-cephfs)
- - External OpenShift Container Storage (ocs-external-storagecluster-ceph-rbd & ocs-external-storagecluster-cephfs)
- - NFS Client (nfs-client)
- - Azure Managed Storage (managed-premium & azurefiles-premium)
- - AWS Storage (gp3-cs & efs)
-
- The names in brackets represent the `ReadWriteOnce` and `ReadWriteMany` class that will be used, in the case of NFS the same storage class will be used for both `ReadWriteOnce` and `ReadWriteMany` volumes. Even when a recognized storage provider is detected you will be provided with the option to select your own storages classes if you wish.
- When selecting your own storage classes you will be presented with a list of those available and must select both a `ReadWriteMany` and a `ReadWriteOnce` storage class. Unfortunately there is no way for the install to verify that the storage class selected actually supports the appropriate access mode, refer to the documentation from the storage class provider to determine whether your storage class supports `ReadWriteOnce` and/or `ReadWriteMany`.
-
-
- Provide the location of your license file, contact information, and IBM entitlement key (if you have set the IBM_ENTITLEMENT_KEY environment variable then this field will be pre-filled with that value already).
-
-
- Provide the basic information about your Aiservice instance:
-
- - Instance ID
- - Configure s3 storage, DB, RSL and tenant
- - Choose to install SLS, DB2, or DRO as a dependency, or opt out and provide alternative information including connection URL and token.
- - Operational Mode (production or non-production)
-
-
-
- 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.
-
-
-
-
-
-Non-Interactive Install
--------------------------------------------------------------------------------
-The following command will launch the MAS CLI container image, login to your OpenShift Cluster and start the install of MAS without triggering any prompts. This is how we install MAS in development hundreds of times every single week.
-
-```bash
-IBM_ENTITLEMENT_KEY=xxx
-
-docker run -e IBM_ENTITLEMENT_KEY -e SUPERUSER_PASSWORD -ti --rm -v ~:/mnt/home quay.io/ibmmas/cli:@@CLI_LATEST_VERSION@@ bash -c "
- oc login --token=sha256~xxxx --server=https://xxx &&
- mas aiservice-install \
- --mas-catalog-version @@MAS_LATEST_CATALOG@@ \
- --aiservice-instance-id aib1 \
- --aiservice-channel 9.1.x \
- \
- --ibm-entitlement-key '${IBM_ENTITLEMENT_KEY}' \
- --license-file /mnt/home/entitlement.lic \
- --contact-email myemail@email.com \
- --contact-firstname John \
- --contact-lastname Barnes \
- \
- --storage-rwo ibmc-block-gold \
- --storage-rwx ibmc-file-gold-gid \
- --storage-pipeline ibmc-file-gold-gid \
- --storage-accessmode ReadWriteMany \
- \
- --accept-license --no-confirm
-```
-
-More Information
--------------------------------------------------------------------------------
-The install is designed to work on any OCP cluster, but has been specifically tested in these environments:
-
-- IBMCloud ROKS
-- IBM DevIT FYRE (internal)
-
-The engine that performs all tasks is written in Ansible, you can directly use the same automation outside of this CLI if you wish. The code is open source and available in [ibm-mas/ansible-devops](https://github.com/ibm-mas/ansible-devops), the collection is also available to install directly from [Ansible Galaxy](https://galaxy.ansible.com/ibm/mas_devops), the install supports the following actions:
-
-- IBM Maximo Operator Catalog installation
-- Required dependency installation:
- - MongoDb (Community Edition) - only needed when want to install SLS.
- - IBM Suite License Service (installed instance of SLS also can be used).
- - IBM Data Reporter Operator
- - Red Hat Certificate Manager
- - Minio
- - db2
-- Aiservice installation
-
-
-
-The installation is performed inside your RedHat OpenShift cluster utilizing [Openshift Pipelines](https://cloud.redhat.com/learn/topics/ci-cd)
-
-> OpenShift Pipelines is a Kubernetes-native CI/CD solution based on Tekton. It builds on Tekton to provide a CI/CD experience through tight integration with OpenShift and Red Hat developer tools. OpenShift Pipelines is designed to run each step of the CI/CD pipeline in its own container, allowing each step to scale independently to meet the demands of the pipeline.
diff --git a/docs/guides/install.md b/docs/guides/install.md
index 932ca855dda..c762fbc1430 100644
--- a/docs/guides/install.md
+++ b/docs/guides/install.md
@@ -99,6 +99,12 @@ Interactive Install
-------------------------------------------------------------------------------
Regardless of whether you are running a connected or disconnected installation, simply run the `mas install` command and follow the prompts, the basic structure of the interactive flow is described below. We will need the `entitlement.lic` file to perform the installation so we will mount your home directory into the running container. When prompted you will be able to set license file to `/mnt/home/entitlement.lic`
+!!! note "NEW: AI Service Installation Options"
+ **NEW UPDATE:** AI Service can now be installed in two ways:
+
+ - **Integrated Installation**: AI Service is now available as an option during the MAS installation process using the `mas install` command. You can select AI Service along with other MAS applications during the interactive application selection step or you can run Non-interactive command as well.
+ - **Standalone Installation**: For standalone AI Service installation, use the dedicated `mas aiservice-install` command to install AI Service independently of the main MAS installation.
+
```bash
docker run -ti --rm -v ~:/mnt/home quay.io/ibmmas/cli:@@CLI_LATEST_VERSION@@ mas install
```
@@ -155,10 +161,29 @@ The interactive install will guide you through a series of questioned designed t
Monitor is only available for install if IoT is selected
Assist and Predict are only available for install if Monitor is selected
From MAS 9.1 onwards, Assist will be rebranded as Collaborate in the MAS UI. It will still appear as Assist in the MAS CLI and within the OpenShift Cluster, but from the MAS UI it will appear as Collaborate.
+ NEW UPDATE: AI Service is now available as an installation option during the application selection step.
Some Maximo applications support additional configuration, you will be taken through the configuration options for each application that you chose to install.
+ NEW UPDATE: Maximo Manage - AI Service Binding
+ NEW UPDATE: When installing Maximo Manage, you can optionally bind it to an AI Service Tenant. This integration enables AI capabilities within Manage through the AI Config Application.
+
+ - Installing AI Service with Manage: If you select AI Service during the application selection step (using
--aiservice-channel), the binding is configured automatically:
+
+ - A default tenant ID "user" is automatically created and bound to Manage
+ - The AI Service instance being installed is automatically used for the binding
+ - No additional configuration is required - the binding parameters are set automatically
+ - Important: When AI Service is being installed, any
--manage-aiservice-instance-id or --manage-aiservice-tenant-id parameters provided will be ignored, as the binding is automatically configured
+
+
+ - Using Existing AI Service: If AI Service is already installed in your cluster (not using
--aiservice-channel), you can bind Manage to an existing AI Service tenant:
+
+ - Interactive Mode: You will be prompted to select from available AI Service instances and tenants
+ - Non-Interactive Mode: Use
--manage-aiservice-instance-id and --manage-aiservice-tenant-id parameters to specify the binding
+
+
+
The install supports the automatic provision of in-cluster MongoDb and Db2 databases for use with Maximo Application Suite, you may also choose to bring your own (BYO) by providing the necessary configuration files (which the installer will also help you create).
diff --git a/docs/index.md b/docs/index.md
index b3adcbde5ed..371518a991c 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -47,6 +47,7 @@ Not all functions supported in the container image are available in the standalo
| CLI Function | Image | Binary |
| ---------------------------------------------------------- | :------: | :------: |
| [install](guides/install.md) | ✓ | ✓ |
+| [aiservice-install](guides/aiservice-install.md) | ✓ | ✓ |
| [update](commands/update.md) | ✓ | ✓ |
| [upgrade](commands/upgrade.md) | ✓ | ✓ |
| [uninstall](commands/uninstall.md) | ✓ | ✓ |
diff --git a/image/cli/mascli/functions/internal/save_config b/image/cli/mascli/functions/internal/save_config
index 2df46042ed7..3c47ac7bf9c 100644
--- a/image/cli/mascli/functions/internal/save_config
+++ b/image/cli/mascli/functions/internal/save_config
@@ -208,11 +208,11 @@ export MAS_APP_SETTINGS_DB2_SCHEMA=$MAS_APP_SETTINGS_DB2_SCHEMA
export MAS_APP_SETTINGS_TABLESPACE=$MAS_APP_SETTINGS_TABLESPACE
export MAS_APP_SETTINGS_INDEXSPACE=$MAS_APP_SETTINGS_INDEXSPACE
-export MAS_APP_SETTINGS_CRYPTO_KEY=$MAS_APP_SETTINGS_CRYPTO_KEY
-export MAS_APP_SETTINGS_CRYPTOX_KEY=$MAS_APP_SETTINGS_CRYPTOX_KEY
-export MAS_APP_SETTINGS_OLD_CRYPTO_KEY=$MAS_APP_SETTINGS_OLD_CRYPTO_KEY
-export MAS_APP_SETTINGS_OLD_CRYPTOX_KEY=$MAS_APP_SETTINGS_OLD_CRYPTOX_KEY
-export MAS_APP_SETTINGS_OVERRIDE_ENCRYPTION_SECRETS_FLAG=$MAS_APP_SETTINGS_OVERRIDE_ENCRYPTION_SECRETS_FLAG
+export MAS_MANAGE_ENCRYPTIONSECRET_CRYPTO_KEY=$MAS_MANAGE_ENCRYPTIONSECRET_CRYPTO_KEY
+export MAS_MANAGE_ENCRYPTIONSECRET_CRYPTOX_KEY=$MAS_MANAGE_ENCRYPTIONSECRET_CRYPTOX_KEY
+export MAS_MANAGE_ENCRYPTIONSECRET_OLD_CRYPTO_KEY=$MAS_MANAGE_ENCRYPTIONSECRET_OLD_CRYPTO_KEY
+export MAS_MANAGE_ENCRYPTIONSECRET_OLD_CRYPTOX_KEY=$MAS_MANAGE_ENCRYPTIONSECRET_OLD_CRYPTOX_KEY
+export MAS_MANAGE_WS_DB_ENCRYPTIONSECRET=$MAS_MANAGE_WS_DB_ENCRYPTIONSECRET
export MAS_APP_SETTINGS_SERVER_BUNDLES_SIZE=$MAS_APP_SETTINGS_SERVER_BUNDLES_SIZE
diff --git a/python/src/mas/cli/aiservice/install/argBuilder.py b/python/src/mas/cli/aiservice/install/argBuilder.py
index 0cd16daf2e8..d259e867ab3 100644
--- a/python/src/mas/cli/aiservice/install/argBuilder.py
+++ b/python/src/mas/cli/aiservice/install/argBuilder.py
@@ -35,7 +35,7 @@ def buildCommand(self) -> str:
command += f" --ibm-entitlement-key $IBM_ENTITLEMENT_KEY{newline}"
- # Aibroker Instance Id
+ # AI Service Instance Id
command += f" --aiservice-instance-id \"{self.getParam('aiservice_instance_id')}\"{newline}"
# MAS Advanced Configuration
@@ -87,8 +87,8 @@ def buildCommand(self) -> str:
# Approvals
# -----------------------------------------------------------------------------
- if self.getParam('approval_aibroker') != "":
- command += f" --approval-aibroker \"{self.getParam('approval_aibroker')}\"{newline}"
+ if self.getParam('approval_aiservice') != "":
+ command += f" --approval-aiservice \"{self.getParam('approval_aiservice')}\"{newline}"
# More Options
# -----------------------------------------------------------------------------
diff --git a/python/src/mas/cli/install/app.py b/python/src/mas/cli/install/app.py
index 6d1e2126d1f..4e6ae41882b 100644
--- a/python/src/mas/cli/install/app.py
+++ b/python/src/mas/cli/install/app.py
@@ -13,6 +13,8 @@
import logging.handlers
from sys import exit
from os import path, getenv
+from datetime import datetime
+from dateutil.relativedelta import relativedelta
import re
import calendar
@@ -41,7 +43,8 @@
TimeoutFormatValidator,
StorageClassValidator,
JsonValidator,
- OptimizerInstallPlanValidator
+ OptimizerInstallPlanValidator,
+ BucketPrefixValidator
)
from mas.devops.ocp import (
@@ -193,6 +196,7 @@ def processCatalogChoice(self) -> list:
"Predict": "mas_predict_version",
"Inspection": "mas_visualinspection_version",
"Facilities": "mas_facilities_version",
+ "AI Service": "aiservice_version",
}
else:
applications = {
@@ -214,7 +218,7 @@ def processCatalogChoice(self) -> list:
# Add 9.1-feature channel based off 9.0 to those apps that have not onboarded yet
if key in self.chosenCatalog:
tempChosenCatalog = self.chosenCatalog[key].copy()
- if '9.1.x-feature' not in tempChosenCatalog:
+ if '9.1.x-feature' not in tempChosenCatalog and '9.0.x' 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)})
@@ -491,6 +495,12 @@ def configOperationMode(self):
" 2. Non-Production"
])
self.operationalMode = self.promptForInt("Operational Mode", default=1, min=1, max=2)
+ if self.operationalMode == 1:
+ self.setParam("environment_type", "production")
+ self.setParam("aiservice_odh_model_deployment_type", "raw")
+ else:
+ self.setParam("environment_type", "non-production")
+ self.setParam("aiservice_odh_model_deployment_type", "serverless")
@logMethodCall
def configRoutingMode(self):
@@ -706,6 +716,12 @@ def configApps(self):
self.configAppChannel("facilities")
else:
self.installFacilities = False
+ # TODO: May be have to change this condition if Manage 9.0 is not supporting AI Cofig Application
+ # AI Service is only installable on Manage 9.x as AI Config Application is not supported on Manage 8.x
+ if not self.getParam("mas_app_channel_manage").startswith("8."):
+ self.installAIService = self.yesOrNo("Install AI Service")
+ if self.installAIService:
+ self.configAIService()
@logMethodCall
def configAppChannel(self, appId):
@@ -875,6 +891,148 @@ def facilitiesSettings(self) -> None:
self.generateFacilitiesCfg(destination=facilitiesConfigsPath)
self.setParam("mas_ws_facilities_config_file", "/workspace/configs/facilities-configs.yaml")
+ @logMethodCall
+ def configAIService(self):
+ self.printH1("Configure AI Service Instance")
+ self.printDescription([
+ "Instance ID restrictions:",
+ " - Must be 3-12 characters long",
+ " - Must only use lowercase letters, numbers, and hypen (-) symbol",
+ " - Must start with a lowercase letter",
+ " - Must end with a lowercase letter or a number"
+ ])
+
+ # Install Db2 for AI Service
+ self.setParam("db2_action_aiservice", "install")
+
+ self.promptForString("Instance ID", "aiservice_instance_id", validator=InstanceIDFormatValidator())
+ self.params["aiservice_channel"] = prompt(HTML('Custom channel for AI Service '))
+
+ @logMethodCall
+ def aiServiceSettings(self) -> None:
+ if self.installAIService:
+ self.printH1("AI Service Settings")
+
+ # Ask about MinIO installation FIRST (moved from aiServiceDependencies)
+ self.printH2("Storage Configuration")
+ self.printDescription(["AI Service requires object storage for pipelines, tenants, and templates. You can either install MinIO in-cluster or connect to external storage."])
+
+ if self.yesOrNo("Install Minio"):
+ # Only ask for MinIO credentials
+ self.promptForString("minio root username", "minio_root_user")
+ self.promptForString("minio root password", "minio_root_password", isPassword=True)
+
+ # Auto-set MinIO storage defaults (same as non-interactive mode)
+ self._setMinioStorageDefaults()
+ else:
+ # Ask for external storage configuration
+ self.printDescription(["Configure your external object storage (S3-compatible) connection details:"])
+ self.promptForString("Storage access key", "aiservice_s3_accesskey")
+ self.promptForString("Storage secret key", "aiservice_s3_secretkey", isPassword=True)
+ self.promptForString("Storage host", "aiservice_s3_host")
+ self.promptForString("Storage port", "aiservice_s3_port")
+ self.promptForString("Storage ssl", "aiservice_s3_ssl")
+ self.promptForString("Storage region", "aiservice_s3_region")
+ self.printDescription([
+ "",
+ "Storage bucket prefix restrictions:",
+ " - Must be 1-4 characters long"
+ ])
+ self.promptForString("Storage bucket prefix", "aiservice_s3_bucket_prefix", validator=BucketPrefixValidator())
+ self.promptForString("Storage tenants bucket", "aiservice_s3_tenants_bucket")
+ self.promptForString("Storage templates bucket", "aiservice_s3_templates_bucket")
+
+ @logMethodCall
+ def aiServiceTenantSettings(self) -> None:
+ if self.installAIService:
+ self.printH1("AI Service Tenant Settings")
+ self.printDescription([
+ "AI Service will reserve AppPoints for a fixed period of time based on the values you enter:"
+ ])
+
+ today = datetime.today()
+ oneyear = datetime.today() + relativedelta(years=1)
+ self.setParam("tenant_entitlement_type", "standard")
+ self.setParam("tenant_entitlement_start_date", today.strftime('%Y-%m-%d'))
+ self.promptForString("Entitlement end date (YYYY-MM-DD)", "tenant_entitlement_end_date", default=oneyear.strftime('%Y-%m-%d'))
+
+ @logMethodCall
+ def _setMinioStorageDefaults(self) -> None:
+ """
+ Set MinIO storage defaults when MinIO is being installed in-cluster.
+ This mirrors the logic from non-interactive mode.
+ """
+ # self.setParam("aiservice_s3_provider", "minio")
+ self.setParam("aiservice_s3_accesskey", self.getParam("minio_root_user"))
+ self.setParam("aiservice_s3_secretkey", self.getParam("minio_root_password"))
+ self.setParam("aiservice_s3_host", "minio-service.minio.svc.cluster.local")
+ self.setParam("aiservice_s3_port", "9000")
+ self.setParam("aiservice_s3_ssl", "false")
+ self.setParam("aiservice_s3_region", "none")
+ self.setParam("aiservice_s3_bucket_prefix", "s3-")
+
+ # Set default bucket names
+ self.setParam("aiservice_s3_tenants_bucket", "km-tenants")
+ self.setParam("aiservice_s3_templates_bucket", "km-templates")
+
+ @logMethodCall
+ def aiServiceIntegrations(self) -> None:
+ if self.installAIService:
+ self.printH1("WatsonX Integration")
+ self.printDescription([
+ "This CLI section configures the integration between the AI Service and IBM watsonx.ai. AI Service",
+ "uses watsonx for model deployment and inferencing.",
+ "",
+ "The WatsonX API key must be a **platform API key** associated with a user that has at least:",
+ "- **Editor permission** for the project",
+ "- **Viewer permission** for the space",
+ "You can generate this key by following IBM's documentation: https://www.ibm.com/docs/en/watsonx/w-and-w/2.2.0?topic=tutorials-generating-api-keys#api-keys__platform__title__1",
+ "",
+ "The endpoint URL is your WatsonX Machine Learning service URL. It can be found in the watsonx.ai",
+ "documentation: https://cloud.ibm.com/apidocs/watsonx-ai-cp/watsonx-ai-cp-2.2.0#endpoint-url",
+ "",
+ "The project ID refers to your specific watsonx.ai project where your ML models and assets are stored.",
+ "",
+ "Optional identifiers:",
+ " - DeploymentId: ID of the model deployment in a **dedicated watsonx runtime**",
+ " (e.g., granite-3-2-8b-instruct deployed in your dedicated runtime).",
+ " - SpaceId: ID of the **watsonx deployment space** where deployments are managed.",
+ "Provide these only if you already have them; otherwise AI Service can proceed with defaults/workflows",
+ "that do not require pre-existing deployment/space identifiers.",
+ "",
+ ])
+ self.promptForString("Watsonxai api key", "aiservice_watsonxai_apikey", isPassword=True)
+ watsonxUrl = self.promptForString("Watsonxai machine learning url", "aiservice_watsonxai_url")
+ self.promptForString("Watsonxai project id", "aiservice_watsonxai_project_id")
+ if self.yesOrNo("Does the Watsonxai AI use a self-signed certificate"):
+ self.promptForString("Watsonxai CA certificate (PEM format)", "aiservice_watsonxai_ca_crt")
+ self.promptForString("Watsonxai Deployment ID (optional)", "aiservice_watsonxai_deployment_id")
+ self.promptForString("Watsonxai Space ID (optional)", "aiservice_watsonxai_space_id")
+ if ".ibm.com" not in watsonxUrl:
+ self.promptForString("Watsonxai Instance ID (optional)", "aiservice_watsonxai_instance_id")
+ self.promptForString("Watsonxai Username (optional)", "aiservice_watsonxai_username")
+ self.promptForString("Watsonxai Version (optional)", "aiservice_watsonxai_version")
+
+ self.printH1("RSL Integration")
+ self.printDescription([
+ "RSL (Reliable Strategy Library) connects to strategic asset management via STRATEGIZEAPI.",
+ "",
+ "RSL URL: https://api.rsl-service.suite.maximo.com (standard for all customers)",
+ "Org ID: Get from MAS Manage > System Properties > 'mxe.rs.rslorgid'",
+ "Token: Use your IBM entitlement key (same as MAS installation)",
+ "",
+ "Note: Future versions will auto-configure these from MAS Manage.",
+ ""
+ ])
+ self.promptForString("RSL url", "rsl_url")
+ self.promptForString("ORG Id of RSL", "rsl_org_id")
+ rslToken = self.promptForString("Token for RSL", isPassword=True)
+ if not rslToken.startswith("Bearer "):
+ rslToken = "Bearer " + rslToken
+ self.setParam("rsl_token", rslToken)
+ if self.yesOrNo("Does the RSL API use a self-signed certificate?"):
+ self.promptForString("RSL CA certificate (PEM format)", "rsl_ca_crt")
+
@logMethodCall
def chooseInstallFlavour(self) -> None:
self.printH1("Choose Install Mode")
@@ -938,6 +1096,10 @@ def interactiveMode(self, simplified: bool, advanced: bool) -> None:
self.assistSettings()
self.facilitiesSettings()
+ self.aiServiceSettings()
+ self.aiServiceTenantSettings()
+ self.aiServiceIntegrations()
+
# Dependencies
self.configMongoDb()
self.configDb2()
@@ -969,6 +1131,7 @@ def nonInteractiveMode(self) -> None:
self.deployCP4D = False
self.db2SetAffinity = False
self.db2SetTolerations = False
+ self.installAIService = False
self.slsLicenseFileLocal = None
self.approvals = {
@@ -980,7 +1143,8 @@ def nonInteractiveMode(self) -> None:
"approval_optimizer": {"id": "app-cfg-optimizer"}, # After Optimizer workspace has been configured
"approval_predict": {"id": "app-cfg-predict"}, # After Predict workspace has been configured
"approval_visualinspection": {"id": "app-cfg-visualinspection"}, # After Visual Inspection workspace has been configured
- "approval_facilities": {"id": "app-cfg-facilities"}, # After Facilities workspace has been configuredĀ
+ "approval_facilities": {"id": "app-cfg-facilities"}, # After Facilities workspace has been configured
+ "approval_aiservice": {"id": "aiservice"} # After AI Service Tenant has been configuredĀ
}
self.configGrafana()
@@ -1017,9 +1181,13 @@ def nonInteractiveMode(self) -> None:
elif key == "non_prod":
if not value:
self.operationalMode = 1
+ self.setParam("environment_type", "production")
+ self.setParam("aiservice_odh_model_deployment_type", "raw")
else:
self.operationalMode = 2
self.setParam("mas_annotations", "mas.ibm.com/operationalMode=nonproduction")
+ self.setParam("environment_type", "non-production")
+ self.setParam("aiservice_odh_model_deployment_type", "serverless")
elif key == "additional_configs":
self.localConfigDir = value
@@ -1074,6 +1242,23 @@ def nonInteractiveMode(self) -> None:
if value is not None and value != "":
self.setParam("mas_app_channel_facilities", value)
self.installFacilities = True
+ elif key == "aiservice_channel":
+ if value is not None and value != "":
+ self.setParam("aiservice_channel", value)
+ # Install Db2 for AI Service
+ self.setParam("db2_action_aiservice", "install")
+ self.installAIService = True
+ # Set manage - bind - AI Service params same as provided AI Service's params
+ self.setParam("manage_bind_aiservice_instance_id", vars(self.args).get("aiservice_instance_id"))
+ self.setParam("manage_bind_aiservice_tenant_id", "user")
+ elif key == "manage_bind_aiservice_instance_id":
+ # only set if AI Service not being installed
+ if not vars(self.args).get("aiservice_instance_id") and value is not None and value != "":
+ self.setParam("manage_bind_aiservice_instance_id", value)
+ elif key == "manage_bind_aiservice_tenant_id":
+ # only set if AI Service not being installed
+ if not vars(self.args).get("aiservice_instance_id") and value is not None and value != "":
+ self.setParam("manage_bind_aiservice_tenant_id", value)
# Manage advanced settings that need extra processing
elif key == "mas_app_settings_server_bundle_size":
@@ -1148,6 +1333,54 @@ def nonInteractiveMode(self) -> None:
elif key == "enable_ipv6":
self.setParam("enable_ipv6", True)
+ elif key == "install_minio_aiservice":
+ if vars(self.args).get("aiservice_instance_id"):
+ incompatibleWithMinioInstall = [
+ "aiservice_s3_accesskey",
+ "aiservice_s3_secretkey",
+ "aiservice_s3_host",
+ "aiservice_s3_port",
+ "aiservice_s3_ssl",
+ "aiservice_s3_bucket_prefix",
+ "aiservice_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}")
+
+ # Extra validation: minio_root_password must be at least 8 characters
+ minio_pass = vars(self.args)["minio_root_password"]
+ if len(minio_pass) < 8:
+ self.fatalError("minio_root_password must be at least 8 characters long")
+
+ # self.setParam("aiservice_s3_provider", "minio")
+
+ self.setParam("aiservice_s3_accesskey", self.args.minio_root_user)
+ self.setParam("aiservice_s3_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_s3_host", "minio-service.minio.svc.cluster.local")
+ self.setParam("aiservice_s3_port", "9000")
+ self.setParam("aiservice_s3_ssl", "false")
+ self.setParam("aiservice_s3_region", "none")
+ self.setParam("aiservice_s3_bucket_prefix", "s3-")
+ else:
+ self.fatalError(f"Unsupported value for --install-minio: {value}")
+
+ elif key == "aiservice_s3_bucket_prefix":
+ if len(value) == 0 or len(value) > 4:
+ self.fatalError(f"Unsupported value for --s3-bucket-prefix(Must be 1-4 characters long): {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 8bd261e6d17..535d9420baf 100644
--- a/python/src/mas/cli/install/argBuilder.py
+++ b/python/src/mas/cli/install/argBuilder.py
@@ -38,13 +38,13 @@ def buildCommand(self) -> str:
if self.getParam('mas_app_settings_customization_archive_password') != "":
command += "export CUSTOMIZATION_PASSWORD=x\n"
- if self.getParam('mas_app_settings_crypto_key') != "":
+ if self.getParam('mas_manage_encryptionsecret_crypto_key') != "":
command += "export CRYPTO_KEY=x\n"
- if self.getParam('mas_app_settings_cryptox_key') != "":
+ if self.getParam('mas_manage_encryptionsecret_cryptox_key') != "":
command += "export CRYPTOX_KEY=x\n"
- if self.getParam('mas_app_settings_old_crypto_key') != "":
+ if self.getParam('mas_manage_encryptionsecret_old_crypto_key') != "":
command += "export OLD_CRYPTO_KEY=x\n"
- if self.getParam('mas_app_settings_old_cryptox_key') != "":
+ if self.getParam('mas_manage_encryptionsecret_old_cryptox_key') != "":
command += "export OLD_CRYTPOX_KEY=x\n"
command += f"mas install --mas-catalog-version {self.getParam('mas_catalog_version')}"
@@ -191,6 +191,8 @@ def buildCommand(self) -> str:
command += f" --visualinspection-channel \"{self.getParam('mas_app_channel_visualinspection')}\"{newline}"
if self.installFacilities:
command += f" --facilities-channel \"{self.getParam('mas_app_channel_facilities')}\"{newline}"
+ if self.installAIService:
+ command += f" --aiservice-channel \"{self.getParam('aiservice_channel')}\"{newline}"
# Arcgis
# -----------------------------------------------------------------------------
@@ -227,16 +229,16 @@ def buildCommand(self) -> str:
if self.getParam('mas_app_settings_db2_schema') != "":
command += f" --manage-db-schema \"{self.getParam('mas_app_settings_db2_schema')}\"{newline}"
- if self.getParam('mas_app_settings_crypto_key') != "":
+ if self.getParam('mas_manage_encryptionsecret_crypto_key') != "":
command += f" --manage-crypto-key $CRYPTO_KEY{newline}"
- if self.getParam('mas_app_settings_cryptox_key') != "":
+ if self.getParam('mas_manage_encryptionsecret_cryptox_key') != "":
command += f" --manage-cryptox-key $CRYPTOX_KEY{newline}"
- if self.getParam('mas_app_settings_old_crypto_key') != "":
+ if self.getParam('mas_manage_encryptionsecret_old_crypto_key') != "":
command += f" --manage-old-crypto-key $OLD_CRYPTO_KEY{newline}"
- if self.getParam('mas_app_settings_old_cryptox_key') != "":
+ if self.getParam('mas_manage_encryptionsecret_old_cryptox_key') != "":
command += f" --manage-old-cryptox-key $OLD_CRYPTOX_KEY{newline}"
- if self.getParam('mas_app_settings_override_encryption_secrets_flag') == "true":
- command += f" --manage-override-encryption-secrets \"{newline}"
+ if self.getParam('mas_manage_ws_db_encryptionsecret') != "":
+ command += f" --manage-encryption-secret-name \"{self.getParam('mas_manage_ws_db_encryptionsecret')}\"{newline}"
if self.getParam('mas_app_settings_base_lang') != "":
command += f" --manage-base-language \"{self.getParam('mas_app_settings_base_lang')}\"{newline}"
@@ -258,6 +260,11 @@ def buildCommand(self) -> str:
if self.getParam('mas_appws_upgrade_type') == "true":
command += f" --manage-upgrade-type \"{self.getParam('mas_appws_upgrade_type')}\"{newline}"
+ if self.getParam('manage_bind_aiservice_instance_id') != "":
+ command += f" --manage-aiservice-instance-id \"{self.getParam('manage_bind_aiservice_instance_id')}\"{newline}"
+ if self.getParam('manage_bind_aiservice_tenant_id') != "":
+ command += f" --manage-aiservice-tenant-id \"{self.getParam('manage_bind_aiservice_tenant_id')}\"{newline}"
+
# Facilities Advanced Settings
# -----------------------------------------------------------------------------
# TODO: Fix type for storage sizes and max conn pool size
@@ -297,6 +304,80 @@ def buildCommand(self) -> str:
if self.getParam('mas_ws_facilities_storage_userfiles_size') != "":
command += f" --facilities-userfiles-storage-size \"{self.getParam('mas_ws_facilities_storage_userfiles_size')}\"{newline}"
+ # AI Service Advanced Settings
+ # -----------------------------------------------------------------------------
+ if self.installAIService:
+ if self.getParam('aiservice_instance_id') != "":
+ 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}"
+ 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') == "":
+ command += f" --s3-secretkey \"{self.getParam('aiservice_s3_secretkey')}\"{newline}"
+ if self.getParam('aiservice_s3_host') != "" and self.getParam('minio_root_user') == "":
+ command += f" --s3-host \"{self.getParam('aiservice_s3_host')}\"{newline}"
+ if self.getParam('aiservice_s3_port') != "" and self.getParam('minio_root_user') == "":
+ command += f" --s3-port \"{self.getParam('aiservice_s3_port')}\"{newline}"
+ if self.getParam('aiservice_s3_ssl') != "" and self.getParam('minio_root_user') == "":
+ command += f" --s3-ssl \"{self.getParam('aiservice_s3_ssl')}\"{newline}"
+ if self.getParam('aiservice_s3_region') != "" and self.getParam('minio_root_user') == "":
+ command += f" --s3-region \"{self.getParam('aiservice_s3_region')}\"{newline}"
+ if self.getParam('aiservice_s3_bucket_prefix') != "" and self.getParam('minio_root_user') == "":
+ command += f" --s3-bucket-prefix \"{self.getParam('aiservice_s3_bucket_prefix')}\"{newline}"
+ if self.getParam('aiservice_s3_tenants_bucket') != "":
+ command += f" --s3-tenants-bucket \"{self.getParam('aiservice_s3_tenants_bucket')}\"{newline}"
+ if self.getParam('aiservice_s3_templates_bucket') != "":
+ command += f" --s3-templates-bucket \"{self.getParam('aiservice_s3_templates_bucket')}\"{newline}"
+
+ if self.getParam('aiservice_odh_model_deployment_type') != "":
+ command += f" --odh-model-deployment-type \"{self.getParam('aiservice_odh_model_deployment_type')}\"{newline}"
+
+ if self.getParam('aiservice_watsonxai_apikey') != "":
+ command += f" --watsonxai-apikey \"{self.getParam('aiservice_watsonxai_apikey')}\"{newline}"
+ if self.getParam('aiservice_watsonxai_url') != "":
+ command += f" --watsonxai-url \"{self.getParam('aiservice_watsonxai_url')}\"{newline}"
+ if self.getParam('aiservice_watsonxai_project_id') != "":
+ command += f" --watsonxai-project-id \"{self.getParam('aiservice_watsonxai_project_id')}\"{newline}"
+ if self.getParam('aiservice_watsonx_action') != "":
+ command += f" --watsonx-action \"{self.getParam('aiservice_watsonx_action')}\"{newline}"
+ if self.getParam('aiservice_watsonxai_ca_crt') != "":
+ command += f" --watsonxai-ca-crt \"{self.getParam('aiservice_watsonxai_ca_crt')}\"{newline}"
+ if self.getParam('aiservice_watsonxai_deployment_id') != "":
+ command += f" --watsonxai-deployment-id \"{self.getParam('aiservice_watsonxai_deployment_id')}\"{newline}"
+ if self.getParam('aiservice_watsonxai_space_id') != "":
+ command += f" --watsonxai-space-id \"{self.getParam('aiservice_watsonxai_space_id')}\"{newline}"
+ if self.getParam('aiservice_watsonxai_instance_id') != "":
+ command += f" --watsonxai-instance-id \"{self.getParam('aiservice_watsonxai_instance_id')}\"{newline}"
+ if self.getParam('aiservice_watsonxai_username') != "":
+ command += f" --watsonxai-username \"{self.getParam('aiservice_watsonxai_username')}\"{newline}"
+ if self.getParam('aiservice_watsonxai_version') != "":
+ command += f" --watsonxai-version \"{self.getParam('aiservice_watsonxai_version')}\"{newline}"
+ if self.getParam('aiservice_watsonxai_on_prem') != "":
+ command += f" --watsonxai-onprem \"{self.getParam('aiservice_watsonxai_on_prem')}\"{newline}"
+
+ if self.getParam('minio_root_user') != "":
+ command += f" --install-minio {newline}"
+ command += f" --minio-root-user \"{self.getParam('minio_root_user')}\"{newline}"
+ if self.getParam('minio_root_password') != "":
+ command += f" --minio-root-password \"{self.getParam('minio_root_password')}\"{newline}"
+
+ if self.getParam('tenant_entitlement_type') != "":
+ command += f" --tenant-entitlement-type \"{self.getParam('tenant_entitlement_type')}\"{newline}"
+ if self.getParam('tenant_entitlement_start_date') != "":
+ command += f" --tenant-entitlement-start-date \"{self.getParam('tenant_entitlement_start_date')}\"{newline}"
+ if self.getParam('tenant_entitlement_end_date') != "":
+ command += f" --tenant-entitlement-end-date \"{self.getParam('tenant_entitlement_end_date')}\"{newline}"
+
+ if self.getParam('rsl_url') != "":
+ command += f" --rsl-url \"{self.getParam('rsl_url')}\"{newline}"
+ if self.getParam('rsl_org_id') != "":
+ command += f" --rsl-org-id \"{self.getParam('rsl_org_id')}\"{newline}"
+ if self.getParam('rsl_token') != "":
+ command += f" --rsl-token \"{self.getParam('rsl_token')}\"{newline}"
+ if self.getParam('rsl_ca_crt') != "":
+ command += f" --rsl-ca-crt \"{self.getParam('rsl_ca_crt')}\"{newline}"
+
# IBM Cloud Pak for Data
# -----------------------------------------------------------------------------
if self.getParam('cpd_product_version') != "":
@@ -453,6 +534,8 @@ def buildCommand(self) -> str:
command += f" --approval-visualinspection \"{self.getParam('approval_visualinspection')}\"{newline}"
if self.getParam('approval_facilities') != "":
command += f" --approval-facilities \"{self.getParam('approval_facilities')}\"{newline}"
+ if self.getParam('approval_aiservice') != "":
+ command += f" --approval-aiservice \"{self.getParam('approval_aiservice')}\"{newline}"
# More Options
# -----------------------------------------------------------------------------
diff --git a/python/src/mas/cli/install/argParser.py b/python/src/mas/cli/install/argParser.py
index a839f5618fb..365d96b2305 100644
--- a/python/src/mas/cli/install/argParser.py
+++ b/python/src/mas/cli/install/argParser.py
@@ -77,6 +77,12 @@ def isValidFile(parser, arg) -> str:
required=False,
help="Subscription channel for the Core Platform"
)
+masArgGroup.add_argument(
+ "--aiservice-instance-id",
+ required=False,
+ help="AI Service Instance ID"
+)
+
# MAS Special characters
# -----------------------------------------------------------------------------
masSpecialCharacters = installArgParser.add_argument_group("Mas Special Characters")
@@ -422,6 +428,11 @@ def isValidFile(parser, arg) -> str:
required=False,
help="Subscription channel for Maximo Real Estate and Facilities"
)
+masAppsArgGroup.add_argument(
+ "--aiservice-channel",
+ required=False,
+ help="Subscription channel for Maximo AI Service"
+)
# Arcgis
# -----------------------------------------------------------------------------
@@ -545,35 +556,33 @@ def isValidFile(parser, arg) -> str:
manageArgGroup.add_argument(
"--manage-crypto-key",
- dest="mas_app_settings_crypto_key",
+ dest="mas_manage_encryptionsecret_crypto_key",
required=False,
help="Customize Manage database encryption keys"
)
manageArgGroup.add_argument(
"--manage-cryptox-key",
- dest="mas_app_settings_cryptox_key",
+ dest="mas_manage_encryptionsecret_cryptox_key",
required=False,
help="Customize Manage database encryption keys"
)
manageArgGroup.add_argument(
"--manage-old-crypto-key",
- dest="mas_app_settings_old_crypto_key",
+ dest="mas_manage_encryptionsecret_old_crypto_key",
required=False,
help="Customize Manage database encryption keys"
)
manageArgGroup.add_argument(
"--manage-old-cryptox-key",
- dest="mas_app_settings_old_cryptox_key",
+ dest="mas_manage_encryptionsecret_old_cryptox_key",
required=False,
help="Customize Manage database encryption keys"
)
manageArgGroup.add_argument(
- "--manage-override-encryption-secrets",
- dest="mas_app_settings_override_encryption_secrets_flag",
+ "--manage-encryption-secret-name",
+ dest="mas_manage_ws_db_encryptionsecret",
required=False,
- help="Override any existing Manage database encryption keys. A backup of the original secret holding existing encryption keys is taken prior overriding it with the new defined keys",
- action="store_const",
- const="true"
+ help="Name of the Manage database encryption secret"
)
manageArgGroup.add_argument(
@@ -621,6 +630,19 @@ def isValidFile(parser, arg) -> str:
choices=["cr", "db"]
)
+manageArgGroup.add_argument(
+ "--manage-aiservice-instance-id",
+ dest="manage_bind_aiservice_instance_id",
+ required=False,
+ help="AI Service Instance ID to bind with Manage"
+)
+manageArgGroup.add_argument(
+ "--manage-aiservice-tenant-id",
+ dest="manage_bind_aiservice_tenant_id",
+ required=False,
+ help="AI Service Tenant ID to bind with Manage"
+)
+
# Facilities Advanced Settings
# TODO: Fix type for storage sizes and max conn pool size
facilitiesArgGroup = installArgParser.add_argument_group("Facilities Advanced Configuration")
@@ -708,6 +730,233 @@ def isValidFile(parser, arg) -> str:
help="Defines the user files storage size",
)
+# ODH
+# -----------------------------------------------------------------------------
+odhArgGroup = installArgParser.add_argument_group("Opendatahub")
+
+odhArgGroup.add_argument(
+ "--odh-model-deployment-type",
+ dest="aiservice_odh_model_deployment_type",
+ required=False,
+ default="raw",
+ help="Model deployment type for ODH"
+)
+
+# S3 - General
+# -----------------------------------------------------------------------------
+s3ArgGroup = installArgParser.add_argument_group("S3 Storage")
+s3ArgGroup.add_argument(
+ "--install-minio",
+ dest="install_minio_aiservice",
+ required=False,
+ help="Install Minio and configure it as the S3 provider for AI Service",
+ action="store_const",
+ const="true"
+)
+
+# S3 - Minio
+# -----------------------------------------------------------------------------
+s3ArgGroup.add_argument(
+ "--minio-root-user",
+ dest="minio_root_user",
+ required=False,
+ help="Root user for minio"
+)
+s3ArgGroup.add_argument(
+ "--minio-root-password",
+ dest="minio_root_password",
+ required=False,
+ help="Password for minio root user"
+)
+
+# S3 - External Connection
+# -----------------------------------------------------------------------------
+s3ArgGroup.add_argument(
+ "--s3-host",
+ dest="aiservice_s3_host",
+ required=False,
+ help="Hostname or IP address of the S3 storage service"
+)
+s3ArgGroup.add_argument(
+ "--s3-port",
+ dest="aiservice_s3_port",
+ required=False,
+ help="Port number for the S3 storage service"
+)
+s3ArgGroup.add_argument(
+ "--s3-ssl",
+ dest="aiservice_s3_ssl",
+ required=False,
+ help="Enable or disable SSL for S3 connection (true/false)"
+)
+s3ArgGroup.add_argument(
+ "--s3-accesskey",
+ dest="aiservice_s3_accesskey",
+ required=False,
+ help="Access key for authenticating with the S3 storage service"
+)
+s3ArgGroup.add_argument(
+ "--s3-secretkey",
+ dest="aiservice_s3_secretkey",
+ required=False,
+ help="Secret key for authenticating with the S3 storage service"
+)
+s3ArgGroup.add_argument(
+ "--s3-region",
+ dest="aiservice_s3_region",
+ required=False,
+ help="Region for the S3 storage service"
+)
+s3ArgGroup.add_argument(
+ "--s3-bucket-prefix",
+ dest="aiservice_s3_bucket_prefix",
+ required=False,
+ help="Bucket prefix configured with S3 storage service"
+)
+
+# S3 - Bucket Naming
+# -----------------------------------------------------------------------------
+s3ArgGroup.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(
+ "--s3-templates-bucket",
+ dest="aiservice_s3_templates_bucket",
+ required=False,
+ default="km-templates",
+ help="Name of the S3 bucket for templates storage"
+)
+
+# Watsonx
+# -----------------------------------------------------------------------------
+watsonxArgGroup = installArgParser.add_argument_group("Watsonx")
+
+watsonxArgGroup.add_argument(
+ "--watsonxai-apikey",
+ dest="aiservice_watsonxai_apikey",
+ required=False,
+ help="API key for WatsonX"
+)
+watsonxArgGroup.add_argument(
+ "--watsonxai-url",
+ dest="aiservice_watsonxai_url",
+ required=False,
+ help="URL endpoint for WatsonX"
+)
+watsonxArgGroup.add_argument(
+ "--watsonxai-project-id",
+ dest="aiservice_watsonxai_project_id",
+ required=False,
+ help="Project ID for WatsonX"
+)
+watsonxArgGroup.add_argument(
+ "--watsonx-action",
+ dest="aiservice_watsonx_action",
+ required=False,
+ help="Action to perform with WatsonX (install/remove)"
+)
+watsonxArgGroup.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(
+ "--watsonxai-deployment-id",
+ dest="aiservice_watsonxai_deployment_id",
+ required=False,
+ help="WatsonX deployment ID"
+)
+watsonxArgGroup.add_argument(
+ "--watsonxai-space-id",
+ dest="aiservice_watsonxai_space_id",
+ required=False,
+ help="WatsonX space ID"
+)
+watsonxArgGroup.add_argument(
+ "--watsonxai-instance-id",
+ dest="aiservice_watsonxai_instance_id",
+ required=False,
+ help="WatsonX instance ID"
+)
+watsonxArgGroup.add_argument(
+ "--watsonxai-username",
+ dest="aiservice_watsonxai_username",
+ required=False,
+ help="WatsonX username"
+)
+watsonxArgGroup.add_argument(
+ "--watsonxai-version",
+ dest="aiservice_watsonxai_version",
+ required=False,
+ help="WatsonX version"
+)
+watsonxArgGroup.add_argument(
+ "--watsonxai-onprem",
+ dest="aiservice_watsonxai_on_prem",
+ required=False,
+ help="WatsonX deployed on prem"
+)
+
+# AI Service
+# -----------------------------------------------------------------------------
+aiServiceArgGroup = installArgParser.add_argument_group("Maximo AI Service")
+
+aiServiceArgGroup.add_argument(
+ "--tenant-entitlement-type",
+ dest="tenant_entitlement_type",
+ required=False,
+ default="standard",
+ help="Entitlement type for AI Service tenant"
+)
+aiServiceArgGroup.add_argument(
+ "--tenant-entitlement-start-date",
+ dest="tenant_entitlement_start_date",
+ required=False,
+ help="Start date for AI Service tenant"
+)
+aiServiceArgGroup.add_argument(
+ "--tenant-entitlement-end-date",
+ dest="tenant_entitlement_end_date",
+ required=False,
+ help="End date for AI Service tenant"
+)
+aiServiceArgGroup.add_argument(
+ "--rsl-url",
+ dest="rsl_url",
+ required=False,
+ help="rsl url"
+)
+aiServiceArgGroup.add_argument(
+ "--rsl-org-id",
+ dest="rsl_org_id",
+ required=False,
+ help="org id for rsl"
+)
+aiServiceArgGroup.add_argument(
+ "--rsl-token",
+ dest="rsl_token",
+ required=False,
+ help="token for rsl"
+)
+aiServiceArgGroup.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)"
+)
+aiServiceArgGroup.add_argument(
+ "--environment-type",
+ dest="environment_type",
+ required=False,
+ default="non-production",
+ help="Environment type (default: non-production)"
+)
+
# IBM Cloud Pak for Data
# -----------------------------------------------------------------------------
cpdAppsArgGroup = installArgParser.add_argument_group("IBM Cloud Pak for Data")
@@ -1108,7 +1357,11 @@ def isValidFile(parser, arg) -> str:
default="",
help="Require approval after the Maximo Real Estate and Facilities workspace has been configured"
)
-
+approvalsGroup.add_argument(
+ "--approval-aiservice",
+ default="",
+ help="Require approval after the AI Service has been configured"
+)
# More Options
# -----------------------------------------------------------------------------
diff --git a/python/src/mas/cli/install/params.py b/python/src/mas/cli/install/params.py
index c68d322a449..8a3144b2942 100644
--- a/python/src/mas/cli/install/params.py
+++ b/python/src/mas/cli/install/params.py
@@ -49,11 +49,11 @@
"mas_app_settings_tablespace",
"mas_app_settings_indexspace",
"mas_app_settings_db2_schema",
- "mas_app_settings_crypto_key",
- "mas_app_settings_cryptox_key",
- "mas_app_settings_old_crypto_key",
- "mas_app_settings_old_cryptox_key",
- "mas_app_settings_override_encryption_secrets_flag",
+ "mas_manage_encryptionsecret_crypto_key",
+ "mas_manage_encryptionsecret_cryptox_key",
+ "mas_manage_encryptionsecret_old_crypto_key",
+ "mas_manage_encryptionsecret_old_cryptox_key",
+ "mas_manage_ws_db_encryptionsecret",
"mas_app_settings_server_timezone",
"mas_appws_bindings_jdbc_manage",
"mas_appws_components",
@@ -167,5 +167,45 @@
"mas_ws_facilities_dwfagents",
"mas_ws_facilities_db_maxconnpoolsize",
# Special chars
- "mas_special_characters"
+ "mas_special_characters",
+ # ODH
+ "aiservice_odh_model_deployment_type",
+ # AI Service
+ "aiservice_s3_accesskey",
+ "aiservice_s3_secretkey",
+ "aiservice_s3_host",
+ "aiservice_s3_port",
+ "aiservice_s3_ssl",
+ "aiservice_s3_region",
+ "aiservice_s3_bucket_prefix",
+ "aiservice_s3_tenants_bucket",
+ "aiservice_s3_templates_bucket",
+
+ "aiservice_watsonxai_apikey",
+ "aiservice_watsonxai_url",
+ "aiservice_watsonxai_project_id",
+ "aiservice_watsonx_action",
+ "aiservice_watsonxai_ca_crt",
+ "aiservice_watsonxai_deployment_id",
+ "aiservice_watsonxai_space_id",
+ "aiservice_watsonxai_instance_id",
+ "aiservice_watsonxai_username",
+ "aiservice_watsonxai_version",
+ "aiservice_watsonxai_on_prem",
+ "aiservice_instance_id",
+ "aiservice_watsonxai_instance_id",
+ "aiservice_watsonxai_verify",
+
+ "minio_root_user",
+ "minio_root_password",
+
+ "tenant_entitlement_type",
+ "tenant_entitlement_start_date",
+ "tenant_entitlement_end_date",
+
+ "rsl_url",
+ "rsl_org_id",
+ "rsl_token",
+ "rsl_ca_crt",
+ "environment_type"
]
diff --git a/python/src/mas/cli/install/settings/manageSettings.py b/python/src/mas/cli/install/settings/manageSettings.py
index e3291bf0f98..0f853f5edaa 100644
--- a/python/src/mas/cli/install/settings/manageSettings.py
+++ b/python/src/mas/cli/install/settings/manageSettings.py
@@ -10,6 +10,11 @@
from prompt_toolkit.completion import WordCompleter
from mas.cli.validators import LanguageValidator
+from mas.devops.aiservice import listAiServiceTenantInstances, listAiServiceInstances
+from openshift.dynamic.exceptions import ResourceNotFoundError
+from ...validators import AiserviceTeanantIDValidator
+from prompt_toolkit import print_formatted_text, HTML
+
import logging
logger = logging.getLogger(__name__)
@@ -53,6 +58,7 @@ def manageSettings(self) -> None:
self.manageSettingsJMS()
self.manageSettingsDatabase()
self.manageSettingsCustomizationArchive()
+ self.manageSettingsAiService()
self.manageSettingsOther()
self.manageStorageAndAccessMode()
@@ -148,11 +154,11 @@ def manageSettingsDatabase(self) -> None:
self.promptForString("Indexspace", "mas_app_settings_indexspace", default="MAXINDEX")
if self.yesOrNo("Customize database encryption settings"):
- self.promptForString("MXE_SECURITY_CRYPTO_KEY", "mas_app_settings_crypto_key")
- self.promptForString("MXE_SECURITY_CRYPTOX_KEY", "mas_app_settings_cryptox_key")
- self.promptForString("MXE_SECURITY_OLD_CRYPTO_KEY", "mas_app_settings_old_crypto_key")
- self.promptForString("MXE_SECURITY_OLD_CRYPTOX_KEY", "mas_app_settings_old_cryptox_key")
- self.yesOrNo("Override database encryption secrets with provided keys", "mas_app_settings_override_encryption_secrets_flag")
+ self.promptForString("MXE_SECURITY_CRYPTO_KEY", "mas_manage_encryptionsecret_crypto_key")
+ self.promptForString("MXE_SECURITY_CRYPTOX_KEY", "mas_manage_encryptionsecret_cryptox_key")
+ self.promptForString("MXE_SECURITY_OLD_CRYPTO_KEY", "mas_manage_encryptionsecret_old_crypto_key")
+ self.promptForString("MXE_SECURITY_OLD_CRYPTOX_KEY", "mas_manage_encryptionsecret_old_cryptox_key")
+ self.promptForString("Encryption secret name", "mas_manage_ws_db_encryptionsecret")
def manageSettingsServerBundleConfig(self) -> None:
if not self.isManageFoundation:
@@ -279,3 +285,50 @@ def manageSettingsOther(self) -> None:
self.manageSettingsTimezone()
self.manageSettingsLanguages()
self.manageSettingsCP4D()
+
+ def manageSettingsAiService(self) -> None:
+ try:
+ aiserviceTenantInstances = listAiServiceTenantInstances(self.dynamicClient)
+ aiserviceInstances = listAiServiceInstances(self.dynamicClient)
+ except ResourceNotFoundError:
+ aiserviceTenantInstances = []
+ aiserviceInstances = []
+
+ if self.installAIService:
+ # if aiservice is being installed along with manage, add default tenant instance
+ aiserviceTenantInstances.append("user")
+ # Set aiservice instance id from the provided aiservice_instance_id parameter
+ if self.getParam("aiservice_instance_id"):
+ self.setParam("manage_bind_aiservice_instance_id", self.getParam("aiservice_instance_id"))
+ elif len(aiserviceTenantInstances) == 0 or len(aiserviceInstances) == 0:
+ return
+ else:
+ # Set aiservice instance id from the first instance fetched from cluster
+ self.setParam("manage_bind_aiservice_instance_id", aiserviceInstances[0]['metadata']['name'])
+
+ self.printH2(f"Maximo {self.manageAppName} Settings - AI Service Tenant Configuration")
+
+ self.printDescription([
+ "Select an AI Service Tenant ID to bind with Manage:",
+ " - The selected AI Service Tenant will be used in Manage AI Config Application"
+ ])
+
+ if self.installAIService:
+ self.printDescription([
+ " - As AI Service is being installed along with Manage, a default Tenant ID 'user' is available in the list below"
+ ])
+ # Show only default 'user' tenant when AI Service is being installed
+ aiserviceTenantOptions = ["user"]
+ print_formatted_text(HTML("- user (default)"))
+ else:
+ # Show all available tenants from cluster
+ aiserviceTenantOptions = []
+ for aiserviceTenant in aiserviceTenantInstances:
+ print_formatted_text(HTML(f"- {aiserviceTenant['metadata']['name'].split('-')[-1]}"))
+ aiserviceTenantOptions.append(aiserviceTenant['metadata']['name'].split('-')[-1])
+
+ aiserviceTenantCompleter = WordCompleter(aiserviceTenantOptions)
+ print()
+
+ aiserviceTenantInstanceId = self.promptForString('Enter AI Service Tenant ID to bind with Manage: ', completer=aiserviceTenantCompleter, validator=AiserviceTeanantIDValidator(self.getParam("manage_bind_aiservice_instance_id"), self.installAIService))
+ self.setParam("manage_bind_aiservice_tenant_id", aiserviceTenantInstanceId)
diff --git a/python/src/mas/cli/install/summarizer.py b/python/src/mas/cli/install/summarizer.py
index 515cf9eb6f1..6612acb0858 100644
--- a/python/src/mas/cli/install/summarizer.py
+++ b/python/src/mas/cli/install/summarizer.py
@@ -164,7 +164,7 @@ def inspectionSummary(self) -> None:
def manageSummary(self) -> None:
if self.installManage:
self.printSummary(f"{'Manage foundation' if self.getParam('mas_appws_components') == '' else 'Manage'}", self.params["mas_app_channel_manage"])
- if self.getParam("mas_appws_components") == "":
+ if self.getParam("mas_appws_components") != "":
print_formatted_text(HTML(" + Components"))
self.printSummary(" + ACM", "Enabled" if "acm=" in self.getParam("mas_appws_components") else "Disabled")
self.printSummary(" + Aviation", "Enabled" if "aviation=" in self.getParam("mas_appws_components") else "Disabled")
@@ -199,6 +199,11 @@ def manageSummary(self) -> None:
self.printParamSummary(" + Schema", "mas_app_settings_db2_schema")
self.printParamSummary(" + Tablespace", "mas_app_settings_tablespace")
self.printParamSummary(" + Indexspace", "mas_app_settings_indexspace")
+
+ if self.getParam("manage_bind_aiservice_tenant_id") != "":
+ print_formatted_text(HTML(" + AI Service Binding (for Manage)"))
+ self.printParamSummary(" + Bound AI Service Instance ID", "manage_bind_aiservice_instance_id")
+ self.printParamSummary(" + Bound AI Service Tenant ID", "manage_bind_aiservice_tenant_id")
else:
self.printSummary("Manage", "Do Not Install")
@@ -226,6 +231,39 @@ def facilitiesSummary(self) -> None:
else:
self.printSummary("Facilities", "Do Not Install")
+ def aiServiceSummary(self) -> None:
+ if self.installAIService:
+ self.printH2("AI Service")
+ self.printParamSummary("Release", "aiservice_channel")
+ self.printParamSummary("Instance ID", "aiservice_instance_id")
+ self.printParamSummary("Environment Type", "environment_type")
+
+ self.printH2("AI Service Tenant Entitlement")
+ self.printParamSummary("Entitlement Type", "tenant_entitlement_type")
+ self.printParamSummary("Start Date", "tenant_entitlement_start_date")
+ self.printParamSummary("End Date", "tenant_entitlement_end_date")
+
+ 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") != "":
+ self.printParamSummary("Minio Root Username", "minio_root_user")
+ print()
+ self.printParamSummary("Host", "aiservice_s3_host")
+ self.printParamSummary("Port", "aiservice_s3_port")
+ self.printParamSummary("SSL Enabled", "aiservice_s3_ssl")
+ self.printParamSummary("Region", "aiservice_s3_region")
+ self.printParamSummary("Bucket Prefix", "aiservice_s3_bucket_prefix")
+ self.printParamSummary("Templates Bucket Name", "aiservice_s3_templates_bucket")
+ self.printParamSummary("Tenants Bucket Name", "aiservice_s3_tenants_bucket")
+
+ self.printH2("IBM WatsonX")
+ self.printParamSummary("URL", "aiservice_watsonxai_url")
+ self.printParamSummary("Project ID", "aiservice_watsonxai_project_id")
+
+ self.printH2("RSL")
+ self.printParamSummary("URL", "rsl_url")
+ self.printParamSummary("Organization ID", "rsl_org_id")
+
def db2Summary(self) -> None:
if self.getParam("db2_action_system") == "install" or self.getParam("db2_action_manage") == "install":
self.printH2("IBM Db2 Univeral Operator Configuration")
@@ -382,6 +420,7 @@ def displayInstallSummary(self) -> None:
self.assistSummary()
self.inspectionSummary()
self.facilitiesSummary()
+ self.aiServiceSummary()
# Application Dependencies
self.mongoSummary()
diff --git a/python/src/mas/cli/validators.py b/python/src/mas/cli/validators.py
index 8a3644a6117..446349b63b0 100644
--- a/python/src/mas/cli/validators.py
+++ b/python/src/mas/cli/validators.py
@@ -21,7 +21,7 @@
from mas.devops.ocp import getStorageClass
from mas.devops.mas import verifyMasInstance
-from mas.devops.aiservice import verifyAiServiceInstance
+from mas.devops.aiservice import verifyAiServiceInstance, verifyAiServiceTenantInstance
import logging
@@ -100,6 +100,31 @@ def validate(self, document):
raise ValidationError(message='Not a valid AI Service instance ID on this cluster', cursor_position=len(instanceId))
+class AiserviceTeanantIDValidator(Validator):
+ def __init__(self, manage_bind_aiservice_instance_id, install_aiservice=False):
+ """
+ Initialize validator with AI Service instance ID and installation flag
+ """
+ self.manage_bind_aiservice_instance_id = manage_bind_aiservice_instance_id
+ self.install_aiservice = install_aiservice
+
+ def validate(self, document):
+ """
+ Validate that a AI Service tenant ID exists on the target cluster
+ """
+ tenantId = document.text
+
+ # If AI Service is being installed and tenant is 'user', skip cluster verification
+ if self.install_aiservice and tenantId == "user":
+ return
+
+ dynClient = dynamic.DynamicClient(
+ api_client.ApiClient(configuration=config.load_kube_config())
+ )
+ if not verifyAiServiceTenantInstance(dynClient, self.manage_bind_aiservice_instance_id, tenantId):
+ raise ValidationError(message='Not a valid AI Service tenant ID on this cluster', cursor_position=len(tenantId))
+
+
class StorageClassValidator(Validator):
def validate(self, document):
"""
diff --git a/tekton/src/params/install-aiservice.yml.j2 b/tekton/src/params/install-aiservice.yml.j2
index 147ada8b2c7..61bf980eaef 100644
--- a/tekton/src/params/install-aiservice.yml.j2
+++ b/tekton/src/params/install-aiservice.yml.j2
@@ -4,6 +4,14 @@
type: string
description: AI Service instance id
default: ""
+- name: manage_bind_aiservice_instance_id
+ type: string
+ description: AI Service Instance ID to bind with Manage
+ default: ""
+- name: manage_bind_aiservice_tenant_id
+ type: string
+ description: AI Service Tenant ID to bind with Manage
+ default: ""
- name: aiservice_channel
type: string
description: Default channel for IBM Maximo AI Service
diff --git a/tekton/src/params/install.yml.j2 b/tekton/src/params/install.yml.j2
index 6d70af079e3..364e1c54c08 100644
--- a/tekton/src/params/install.yml.j2
+++ b/tekton/src/params/install.yml.j2
@@ -619,25 +619,25 @@
type: string
description: Password to authenticate into Manage custom archive url (if required)
default: ""
-- name: mas_app_settings_crypto_key
+- name: mas_manage_encryptionsecret_crypto_key
type: string
description: Manage database encryption key for MXE_SECURITY_CRYPTO_KEY
default: ""
-- name: mas_app_settings_cryptox_key
+- name: mas_manage_encryptionsecret_cryptox_key
type: string
description: Manage database encryption key for MXE_SECURITY_CRYPTOX_KEY
default: ""
-- name: mas_app_settings_old_crypto_key
+- name: mas_manage_encryptionsecret_old_crypto_key
type: string
description: Manage database encryption key for MXE_SECURITY_OLD_CRYPTO_KEY
default: ""
-- name: mas_app_settings_old_cryptox_key
+- name: mas_manage_encryptionsecret_old_cryptox_key
type: string
description: Manage database encryption key for MXE_SECURITY_OLD_CRYPTOX_KEY
default: ""
-- name: mas_app_settings_override_encryption_secrets_flag
+- name: mas_manage_ws_db_encryptionsecret
type: string
- description: Defines if Manage database encryption secret should be overriden with new values provided
+ description: Name of the Manage database encryption secret
default: ""
- name: mas_app_settings_default_jms
type: string
diff --git a/tekton/src/pipelines/taskdefs/apps/manage-app.yml.j2 b/tekton/src/pipelines/taskdefs/apps/manage-app.yml.j2
index 78bff895f46..67e5b053ed7 100644
--- a/tekton/src/pipelines/taskdefs/apps/manage-app.yml.j2
+++ b/tekton/src/pipelines/taskdefs/apps/manage-app.yml.j2
@@ -9,6 +9,12 @@
value: $(params.mas_instance_id)
- name: mas_app_id
value: manage
+ - name: aiservice_instance_id
+ value: $(params.aiservice_instance_id)
+ - name: manage_bind_aiservice_instance_id
+ value: $(params.manage_bind_aiservice_instance_id)
+ - name: manage_bind_aiservice_tenant_id
+ value: $(params.manage_bind_aiservice_tenant_id)
- name: artifactory_username
value: $(params.artifactory_username)
- name: artifactory_token
@@ -70,16 +76,16 @@
value: $(params.mas_app_settings_customization_archive_username)
- name: mas_app_settings_customization_archive_password
value: $(params.mas_app_settings_customization_archive_password)
- - name: mas_app_settings_crypto_key
- value: $(params.mas_app_settings_crypto_key)
- - name: mas_app_settings_cryptox_key
- value: $(params.mas_app_settings_cryptox_key)
- - name: mas_app_settings_old_crypto_key
- value: $(params.mas_app_settings_old_crypto_key)
- - name: mas_app_settings_old_cryptox_key
- value: $(params.mas_app_settings_old_cryptox_key)
- - name: mas_app_settings_override_encryption_secrets_flag
- value: $(params.mas_app_settings_override_encryption_secrets_flag)
+ - name: mas_manage_encryptionsecret_crypto_key
+ value: $(params.mas_manage_encryptionsecret_crypto_key)
+ - name: mas_manage_encryptionsecret_cryptox_key
+ value: $(params.mas_manage_encryptionsecret_cryptox_key)
+ - name: mas_manage_encryptionsecret_old_crypto_key
+ value: $(params.mas_manage_encryptionsecret_old_crypto_key)
+ - name: mas_manage_encryptionsecret_old_cryptox_key
+ value: $(params.mas_manage_encryptionsecret_old_cryptox_key)
+ - name: mas_manage_ws_db_encryptionsecret
+ value: $(params.mas_manage_ws_db_encryptionsecret)
- name: mas_app_settings_default_jms
value: $(params.mas_app_settings_default_jms)
- name: mas_manage_attachment_configuration_mode
diff --git a/tekton/src/tasks/aiservice/aiservice.yml.j2 b/tekton/src/tasks/aiservice/aiservice.yml.j2
index 315b2ec2fe9..0732ebf4989 100644
--- a/tekton/src/tasks/aiservice/aiservice.yml.j2
+++ b/tekton/src/tasks/aiservice/aiservice.yml.j2
@@ -21,7 +21,7 @@ spec:
- name: ibm_entitlement_key
type: string
- # MAS Details
+ # AI Service Details
- name: aiservice_instance_id
type: string
description: AI Service Instance ID
@@ -166,7 +166,7 @@ spec:
- name: IBM_ENTITLEMENT_KEY
value: $(params.ibm_entitlement_key)
- # MAS Details
+ # AI Service Details
- name: AISERVICE_INSTANCE_ID
value: $(params.aiservice_instance_id)
- name: AISERVICE_CHANNEL
diff --git a/tekton/src/tasks/suite-app-install.yml.j2 b/tekton/src/tasks/suite-app-install.yml.j2
index 893a9739f3e..9ef1b26d85b 100644
--- a/tekton/src/tasks/suite-app-install.yml.j2
+++ b/tekton/src/tasks/suite-app-install.yml.j2
@@ -18,6 +18,16 @@ spec:
- name: mas_app_id
type: string
description: Maximo Applicaiton Suite Application Id
+
+ - name: manage_bind_aiservice_instance_id
+ type: string
+ description: AI Service Instance ID to bind with Manage
+ default: ""
+
+ - name: manage_bind_aiservice_tenant_id
+ type: string
+ description: AI Service Tenant ID to bind with Manage
+ default: ""
# Custom Label Support
- name: custom_labels
@@ -184,25 +194,25 @@ spec:
type: string
description: Password to authenticate into Manage custom archive url (if required)
default: ""
- - name: mas_app_settings_crypto_key
+ - name: mas_manage_encryptionsecret_crypto_key
type: string
description: Manage database encryption key for MXE_SECURITY_CRYPTO_KEY
default: ""
- - name: mas_app_settings_cryptox_key
+ - name: mas_manage_encryptionsecret_cryptox_key
type: string
description: Manage database encryption key for MXE_SECURITY_CRYPTOX_KEY
default: ""
- - name: mas_app_settings_old_crypto_key
+ - name: mas_manage_encryptionsecret_old_crypto_key
type: string
description: Manage database encryption key for MXE_SECURITY_OLD_CRYPTO_KEY
default: ""
- - name: mas_app_settings_old_cryptox_key
+ - name: mas_manage_encryptionsecret_old_cryptox_key
type: string
description: Manage database encryption key for MXE_SECURITY_OLD_CRYPTOX_KEY
default: ""
- - name: mas_app_settings_override_encryption_secrets_flag
+ - name: mas_manage_ws_db_encryptionsecret
type: string
- description: Defines if Manage database encryption secret should be overriden with new values provided
+ description: Name of the Manage database encryption secret
default: ""
- name: mas_app_settings_default_jms
type: string
@@ -392,6 +402,12 @@ spec:
- name: MAS_CONFIG_DIR
value: /workspace/configs
+ # AI Service Details for Manage binding
+ - name: AISERVICE_INSTANCE_ID
+ value: $(params.manage_bind_aiservice_instance_id)
+ - name: AISERVICE_TENANT_ID
+ value: $(params.manage_bind_aiservice_tenant_id)
+
# CPD Version
- name: CPD_PRODUCT_VERSION
value: $(params.cpd_product_version)
@@ -449,16 +465,16 @@ spec:
value: $(params.mas_app_settings_customization_archive_username)
- name: MAS_APP_SETTINGS_CUSTOMIZATION_ARCHIVE_PASSWORD
value: $(params.mas_app_settings_customization_archive_password)
- - name: MAS_APP_SETTINGS_CRYPTO_KEY
- value: $(params.mas_app_settings_crypto_key)
- - name: MAS_APP_SETTINGS_CRYPTOX_KEY
- value: $(params.mas_app_settings_cryptox_key)
- - name: MAS_APP_SETTINGS_OLD_CRYPTO_KEY
- value: $(params.mas_app_settings_old_crypto_key)
- - name: MAS_APP_SETTINGS_OLD_CRYPTOX_KEY
- value: $(params.mas_app_settings_old_cryptox_key)
- - name: MAS_APP_SETTINGS_OVERRIDE_ENCRYPTION_SECRETS_FLAG
- value: $(params.mas_app_settings_override_encryption_secrets_flag)
+ - name: MAS_MANAGE_ENCRYPTIONSECRET_CRYPTO_KEY
+ value: $(params.mas_manage_encryptionsecret_crypto_key)
+ - name: MAS_MANAGE_ENCRYPTIONSECRET_CRYPTOX_KEY
+ value: $(params.mas_manage_encryptionsecret_cryptox_key)
+ - name: MAS_MANAGE_ENCRYPTIONSECRET_OLD_CRYPTO_KEY
+ value: $(params.mas_manage_encryptionsecret_old_crypto_key)
+ - name: MAS_MANAGE_ENCRYPTIONSECRET_OLD_CRYPTOX_KEY
+ value: $(params.mas_manage_encryptionsecret_old_cryptox_key)
+ - name: MAS_MANAGE_WS_DB_ENCRYPTIONSECRET
+ value: $(params.mas_manage_ws_db_encryptionsecret)
- name: MAS_APP_SETTINGS_DEFAULT_JMS
value: $(params.mas_app_settings_default_jms)
- name: MAS_POD_TEMPLATES_DIR