From 60b4c77127b60a150738f273c76a5924c42f267f Mon Sep 17 00:00:00 2001 From: Parveen Kumar Date: Mon, 5 Jan 2026 13:03:19 +0530 Subject: [PATCH 01/45] [minor] Support January Catalog Update --- .../devops/data/catalogs/v9-260129-amd64.yaml | 145 ++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 src/mas/devops/data/catalogs/v9-260129-amd64.yaml diff --git a/src/mas/devops/data/catalogs/v9-260129-amd64.yaml b/src/mas/devops/data/catalogs/v9-260129-amd64.yaml new file mode 100644 index 00000000..d85973db --- /dev/null +++ b/src/mas/devops/data/catalogs/v9-260129-amd64.yaml @@ -0,0 +1,145 @@ +--- +# Case bundle configuration for IBM Maximo Operator Catalog 251224 (AMD64) +# ----------------------------------------------------------------------------- +# In the future this won't be necessary as we'll be able to mirror from the +# catalog itself, but not everything in the catalog supports this yet (including MAS) +# so we need to use the CASE bundle mirror process still. + +catalog_digest: sha256:ecad371a50e030ce93ca00d73ef3b8b95f1305158800a077758c74ff4cf65623 + +ocp_compatibility: +- 4.16 +- 4.17 +- 4.18 +- 4.19 + +# Dependencies +# ----------------------------------------------------------------------------- +ibm_licensing_version: 4.2.17 # Operator version 4.2.14 (https://github.com/IBM/cloud-pak/tree/master/repo/case/ibm-licensing) +common_svcs_version: 4.13.0 # Operator version 4.13.0 (https://github.com/IBM/cloud-pak/tree/master/repo/case/ibm-cp-common-services) +common_svcs_version_1: 4.11.0 # Additional version 4.11.0 + +cp4d_platform_version: 5.2.0+20250709.170324 # Operator version 5.2.0 (https://github.com/IBM/cloud-pak/tree/master/repo/case/ibm-cp-datacore/) +ibm_zen_version: 6.2.0+20250530.152516.232 # For CPD5 ibm-zen has to be explicitily mirrored + +db2u_version: 7.3.1+20250821.161005.16793 # Operator version 110509.0.6 to find the version 7.3.1+20250821.161005.16793, search db2u-operator digest on repo (https://github.com/IBM/cloud-pak/tree/master/repo/case/ibm-db2uoperator) +events_version: 5.0.1 # Operator version 5.0.1 (https://github.com/IBM/cloud-pak/tree/master/repo/case/ibm-events-operator) +uds_version: 2.0.12 # Operator version 2.0.12 # sticking to 2.0.12 version # Please do Not Change +sls_version: 3.12.4 # Operator version 3.12.4 (https://github.ibm.com/maximoappsuite/ibm-sls/releases) +tsm_version: 1.7.2 # Operator version 1.7.2 (https://github.ibm.com/maximoappsuite/ibm-truststore-mgr/releases) +dd_version: 1.1.20 # Operator version 1.1.14 (https://github.ibm.com/maximoappsuite/ibm-data-dictionary/releases) +appconnect_version: 6.2.0 # Operator version 6.2.0 # sticking to 6.2.0 version # Please do Not Change +wsl_version: 11.0.0+20250521.202913.73 # used for wsl and wsl_runtimes unless wsl_runtimes_version also specified +wsl_runtimes_version: 11.0.0+20250515.090949.21 # cpd 5.1.3 uses version 10.3.0 of wsl runtimes but only 10.2.0 for wsl itself +wml_version: 11.0.0+20250530.193146.282 # Operator version 5.2.0 +postgress_version: 5.16.0+20250827.110911.2626 # ibm-cpd-cloud-native-postgresql-operator 5.2.0 cp4d + +ccs_build: 11.0.0+20250605.130237.468 # cpd 5.2.0 using ccs build +# datarefinery_build: +20240517.202103.146 + +spark_version: 11.0.0+20250604.163055.2097 # Operator version 5.2.0 +cognos_version: 28.0.0+20250515.175459.10054 # Operator version 25.0.0 +couchdb_version: 1.0.13 # Operator version 2.2.1 (1.0.13) sticking with 1.0.13 # (This is required for Assist 9.0, https://github.com/IBM/cloud-pak/blob/master/repo/case/ibm-couchdb/index.yaml) +# elasticsearch_version: 1.1.2667 # Operator version 1.1.2667 # used in cpd 5.1.3 only +opensearch_version: 1.1.2494 # Operator version 1.1.2494 + +# Maximo Application Suite +# ----------------------------------------------------------------------------- +mas_core_version: + 9.2.x-feature: 9.2.0-pre.stable_6976 # Updated + 9.1.x: 9.1.7 # Updated + 9.0.x: 9.0.18 # Updated + 8.10.x: 8.10.32 # Updated + 8.11.x: 8.11.29 # Updated +mas_assist_version: + 9.1.x: 9.1.6 # Updated + 9.0.x: 9.0.12 # Updated + 8.10.x: 8.7.8 # No Update + 8.11.x: 8.8.7 # No Update +mas_hputilities_version: + 9.1.x: "" # Not Supported + 9.0.x: "" # Not Supported + 8.10.x: 8.6.7 # No Update + 8.11.x: "" # Not Supported +mas_iot_version: + 9.1.x: 9.1.6 # Updated + 9.0.x: 9.0.15 # Updated + 8.10.x: 8.7.29 # Updated + 8.11.x: 8.8.25 # Updated +mas_manage_version: + 9.2.x-feature: 9.2.0-pre.stable_6856 # Updated + 9.1.x: 9.1.7 # Updated + 9.0.x: 9.0.20 # Updated + 8.10.x: 8.6.33 # Updated + 8.11.x: 8.7.27 # Updated +mas_monitor_version: + 9.1.x: 9.1.6 # Updated + 9.0.x: 9.0.16 # Updated + 8.10.x: 8.10.26 # Updated + 8.11.x: 8.11.24 # Updated +mas_optimizer_version: + 9.2.x-feature: 9.2.0-pre.stable_5162 # Updated + 9.1.x: 9.1.7 # Updated + 9.0.x: 9.0.16 # Updated + 8.10.x: 8.4.25 # Updated + 8.11.x: 8.5.24 # Updated +mas_predict_version: + 9.1.x: 9.1.4 # Updated + 9.0.x: 9.0.11 # Updated + 8.10.x: 8.8.12 # Updated + 8.11.x: 8.9.14 # Updated +mas_visualinspection_version: + 9.2.x-feature: 9.2.0-pre.stable_6198 # Updated + 9.1.x: 9.1.5 # Updated + 9.0.x: 9.0.15 # Updated + 8.10.x: 8.8.4 # No Update + 8.11.x: 8.9.18 # Updated +mas_facilities_version: + 9.1.x: 9.1.6 # Updated + 9.0.x: "" # Not Supported + 8.10.x: "" # Not Supported + 8.11.x: "" # Not Supported + + +# Maximo AI Service +# ------------------------------------------------------------------------------ +aiservice_version: + 9.2.x-feature: 9.2.0-pre.stable_6741 # Updated + 9.1.x: 9.1.10 # Updated + + +# Extra Images for UDS +# ------------------------------------------------------------------------------ +uds_extras_version: 1.5.0 + +# Extra Images for Mongo +# ------------------------------------------------------------------------------ +mongo_extras_version_default: 8.0.17 + +# Variables used to mirror additional mongo image versions +mongo_extras_version_4: 4.4.21 +mongo_extras_version_5: 5.0.23 +mongo_extras_version_6: 6.0.12 +mongo_extras_version_7: 7.0.23 +mongo_extras_version_8: 8.0.17 + +# Extra Images for Db2u +# ------------------------------------------------------------------------------ +db2u_extras_version: 1.0.6 # No Update +db2u_filter: db2 + +# Extra Images for IBM Watson Discovery +# ------------------------------------------------------------------------------ +#wd_extras_version: 1.0.4 + +# Extra Images for Amlen +# ------------------------------------------------------------------------------ +amlen_extras_version: 1.1.3 + +# Default Cloud Pak for Data version +# ------------------------------------------------------------------------------ +cpd_product_version_default: 5.2.0 + +manage_extras_913: 9.1.3 +minio_version: RELEASE.2025-06-13T11-33-47Z + From e924ed282d1d8b897f1b51db92be75e85303c1f7 Mon Sep 17 00:00:00 2001 From: jainyjoseph Date: Mon, 19 Jan 2026 10:40:38 +0530 Subject: [PATCH 02/45] [minor] Add db2_channel_default to control Db2 operator version via catalog metadata (#171) --- src/mas/devops/data/catalogs/v9-260129-amd64.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mas/devops/data/catalogs/v9-260129-amd64.yaml b/src/mas/devops/data/catalogs/v9-260129-amd64.yaml index d85973db..4be72295 100644 --- a/src/mas/devops/data/catalogs/v9-260129-amd64.yaml +++ b/src/mas/devops/data/catalogs/v9-260129-amd64.yaml @@ -23,6 +23,7 @@ cp4d_platform_version: 5.2.0+20250709.170324 # Operator version 5. ibm_zen_version: 6.2.0+20250530.152516.232 # For CPD5 ibm-zen has to be explicitily mirrored db2u_version: 7.3.1+20250821.161005.16793 # Operator version 110509.0.6 to find the version 7.3.1+20250821.161005.16793, search db2u-operator digest on repo (https://github.com/IBM/cloud-pak/tree/master/repo/case/ibm-db2uoperator) +db2_channel_default: v110509.0 # Default Channel version for db2u-operator events_version: 5.0.1 # Operator version 5.0.1 (https://github.com/IBM/cloud-pak/tree/master/repo/case/ibm-events-operator) uds_version: 2.0.12 # Operator version 2.0.12 # sticking to 2.0.12 version # Please do Not Change sls_version: 3.12.4 # Operator version 3.12.4 (https://github.ibm.com/maximoappsuite/ibm-sls/releases) From e10498d88d760b08669fa0fe85f17a6355b0d264 Mon Sep 17 00:00:00 2001 From: Parveen Kumar Date: Mon, 19 Jan 2026 15:07:17 +0530 Subject: [PATCH 03/45] [patch] jan release prep --- .../devops/data/catalogs/v9-260129-amd64.yaml | 76 +++++++++---------- .../devops/data/catalogs/v9-260129-s390x.yaml | 60 +++++++++++++++ .../data/catalogs/v9-290129-ppc64le.yaml | 60 +++++++++++++++ 3 files changed, 158 insertions(+), 38 deletions(-) create mode 100644 src/mas/devops/data/catalogs/v9-260129-s390x.yaml create mode 100644 src/mas/devops/data/catalogs/v9-290129-ppc64le.yaml diff --git a/src/mas/devops/data/catalogs/v9-260129-amd64.yaml b/src/mas/devops/data/catalogs/v9-260129-amd64.yaml index 4be72295..111bc9a9 100644 --- a/src/mas/devops/data/catalogs/v9-260129-amd64.yaml +++ b/src/mas/devops/data/catalogs/v9-260129-amd64.yaml @@ -1,11 +1,11 @@ --- -# Case bundle configuration for IBM Maximo Operator Catalog 251224 (AMD64) +# Case bundle configuration for IBM Maximo Operator Catalog 260129 (AMD64) # ----------------------------------------------------------------------------- # In the future this won't be necessary as we'll be able to mirror from the # catalog itself, but not everything in the catalog supports this yet (including MAS) # so we need to use the CASE bundle mirror process still. -catalog_digest: sha256:ecad371a50e030ce93ca00d73ef3b8b95f1305158800a077758c74ff4cf65623 +catalog_digest: sha256:62a3d0251fe682411f490e5f4b67fb4e6abc033c65025d36b3271d3e5fc5e57e ocp_compatibility: - 4.16 @@ -47,14 +47,14 @@ opensearch_version: 1.1.2494 # Operator version 1.1.2494 # Maximo Application Suite # ----------------------------------------------------------------------------- mas_core_version: - 9.2.x-feature: 9.2.0-pre.stable_6976 # Updated - 9.1.x: 9.1.7 # Updated - 9.0.x: 9.0.18 # Updated - 8.10.x: 8.10.32 # Updated - 8.11.x: 8.11.29 # Updated + 9.2.x-feature: 9.2.0-pre.stable_6976 # Need to update + 9.1.x: 9.1.7 # Need to update + 9.0.x: 9.0.18 # Need to update + 8.10.x: 8.10.32 # Need to update + 8.11.x: 8.11.29 # Need to update mas_assist_version: - 9.1.x: 9.1.6 # Updated - 9.0.x: 9.0.12 # Updated + 9.1.x: 9.1.6 # Need to update + 9.0.x: 9.0.12 # Need to update 8.10.x: 8.7.8 # No Update 8.11.x: 8.8.7 # No Update mas_hputilities_version: @@ -63,40 +63,40 @@ mas_hputilities_version: 8.10.x: 8.6.7 # No Update 8.11.x: "" # Not Supported mas_iot_version: - 9.1.x: 9.1.6 # Updated - 9.0.x: 9.0.15 # Updated - 8.10.x: 8.7.29 # Updated - 8.11.x: 8.8.25 # Updated + 9.1.x: 9.1.6 # Need to update + 9.0.x: 9.0.15 # Need to update + 8.10.x: 8.7.29 # Need to update + 8.11.x: 8.8.25 # Need to update mas_manage_version: - 9.2.x-feature: 9.2.0-pre.stable_6856 # Updated - 9.1.x: 9.1.7 # Updated - 9.0.x: 9.0.20 # Updated - 8.10.x: 8.6.33 # Updated - 8.11.x: 8.7.27 # Updated + 9.2.x-feature: 9.2.0-pre.stable_6856 # Need to update + 9.1.x: 9.1.7 # Need to update + 9.0.x: 9.0.20 # Need to update + 8.10.x: 8.6.33 # Need to update + 8.11.x: 8.7.27 # Need to update mas_monitor_version: - 9.1.x: 9.1.6 # Updated - 9.0.x: 9.0.16 # Updated - 8.10.x: 8.10.26 # Updated - 8.11.x: 8.11.24 # Updated + 9.1.x: 9.1.6 # Need to update + 9.0.x: 9.0.16 # Need to update + 8.10.x: 8.10.26 # Need to update + 8.11.x: 8.11.24 # Need to update mas_optimizer_version: - 9.2.x-feature: 9.2.0-pre.stable_5162 # Updated - 9.1.x: 9.1.7 # Updated - 9.0.x: 9.0.16 # Updated - 8.10.x: 8.4.25 # Updated - 8.11.x: 8.5.24 # Updated + 9.2.x-feature: 9.2.0-pre.stable_5162 # Need to update + 9.1.x: 9.1.7 # Need to update + 9.0.x: 9.0.16 # Need to update + 8.10.x: 8.4.25 # Need to update + 8.11.x: 8.5.24 # Need to update mas_predict_version: - 9.1.x: 9.1.4 # Updated - 9.0.x: 9.0.11 # Updated - 8.10.x: 8.8.12 # Updated - 8.11.x: 8.9.14 # Updated + 9.1.x: 9.1.4 # Need to update + 9.0.x: 9.0.11 # Need to update + 8.10.x: 8.8.12 # Need to update + 8.11.x: 8.9.14 # Need to update mas_visualinspection_version: - 9.2.x-feature: 9.2.0-pre.stable_6198 # Updated - 9.1.x: 9.1.5 # Updated - 9.0.x: 9.0.15 # Updated + 9.2.x-feature: 9.2.0-pre.stable_6198 # Need to update + 9.1.x: 9.1.5 # Need to update + 9.0.x: 9.0.15 # UpdNeed to updateated 8.10.x: 8.8.4 # No Update - 8.11.x: 8.9.18 # Updated + 8.11.x: 8.9.18 # Need to update mas_facilities_version: - 9.1.x: 9.1.6 # Updated + 9.1.x: 9.1.6 # Need to update 9.0.x: "" # Not Supported 8.10.x: "" # Not Supported 8.11.x: "" # Not Supported @@ -105,8 +105,8 @@ mas_facilities_version: # Maximo AI Service # ------------------------------------------------------------------------------ aiservice_version: - 9.2.x-feature: 9.2.0-pre.stable_6741 # Updated - 9.1.x: 9.1.10 # Updated + 9.2.x-feature: 9.2.0-pre.stable_6741 # Need to update + 9.1.x: 9.1.10 # Need to update # Extra Images for UDS diff --git a/src/mas/devops/data/catalogs/v9-260129-s390x.yaml b/src/mas/devops/data/catalogs/v9-260129-s390x.yaml new file mode 100644 index 00000000..2e27840c --- /dev/null +++ b/src/mas/devops/data/catalogs/v9-260129-s390x.yaml @@ -0,0 +1,60 @@ +--- +# Case bundle configuration for IBM Maximo Operator Catalog 260129 (Z) +# ----------------------------------------------------------------------------- +# In the future this won't be necessary as we'll be able to mirror from the +# catalog itself, but not everything in the catalog supports this yet (including MAS) +# so we need to use the CASE bundle mirror process still. + +catalog_digest: sha256:8209ebc3a2d50130307177b8b16e2bc91b6b3c6b3a4955bf0672333b918ffcb7 + +ocp_compatibility: +- 4.16 +- 4.17 +- 4.18 +- 4.19 + +uds_version: 2.0.12 # Operator version 2.0.12 # sticking to 2.0.12 version # Please do Not Change +sls_version: 3.12.4 # Operator version 3.12.4 (https://github.ibm.com/maximoappsuite/ibm-sls/releases) +tsm_version: 1.7.2 # Operator version 1.7.2 (https://github.ibm.com/maximoappsuite/ibm-truststore-mgr/releases) +db2u_version: 7.3.1+20250821.161005.16793 # Operator version 110509.0.2 to find the version 7.2.0, search CASE_VERSION in db2u, catalog.yaml into ibm-maximo-operator-catalog (https://github.com/IBM/cloud-pak/tree/master/repo/case/ibm-db2uoperator) + +# Maximo Application Suite +# ----------------------------------------------------------------------------- +mas_core_version: + 9.2.x-feature: 9.2.0-pre.stable_6976 # Need to update + 9.1.x: 9.1.7 # Need to update + 9.0.x: 9.0.18 # Need to update + 8.10.x: "" # Not Supported + 8.11.x: "" # Not Supported +mas_manage_version: + 9.2.x-feature: 9.2.0-pre.stable_6856 # Need to update + 9.1.x: 9.1.7 # Need to update + 9.0.x: 9.0.20 # Need to update + 8.10.x: "" # Not Supported + 8.11.x: "" # Not Supported + +# Extra Images for UDS +# ------------------------------------------------------------------------------ +uds_extras_version: 1.5.0 + +# Extra Images for Mongo +# ------------------------------------------------------------------------------ +mongo_extras_version_default: 8.0.17 + +# Variables used to mirror additional mongo image versions +mongo_extras_version_4: 4.4.21 +mongo_extras_version_5: 5.0.23 +mongo_extras_version_6: 6.0.12 +mongo_extras_version_7: 7.0.12 +mongo_extras_version_8: 8.0.17 + +editorial: + whats_new: + - title: '**MongoDb v8.0.17** support Running `mas update` will automatically upgrade existing MongoDbCommunity instances to MongoDb version v8.0.17 this requires MongoDb version to be on v7 or later.' + details: [] + - title: '**Security updates and bug fixes**' + details: + - IBM Maximo Application Suite Core Platform v9.0 and v9.1 + - IBM Maximo Manage v9.0 and v9.1 + - IBM Suite License Service v3.12 + known_issues: [] diff --git a/src/mas/devops/data/catalogs/v9-290129-ppc64le.yaml b/src/mas/devops/data/catalogs/v9-290129-ppc64le.yaml new file mode 100644 index 00000000..30b57d54 --- /dev/null +++ b/src/mas/devops/data/catalogs/v9-290129-ppc64le.yaml @@ -0,0 +1,60 @@ +--- +# Case bundle configuration for IBM Maximo Operator Catalog 260129 (PPC) +# ----------------------------------------------------------------------------- +# In the future this won't be necessary as we'll be able to mirror from the +# catalog itself, but not everything in the catalog supports this yet (including MAS) +# so we need to use the CASE bundle mirror process still. + +catalog_digest: sha256:26999b70b82c5363b2d24c9f6ecb2817de3c1492cdeebd816bc02422ac1d6fea + +ocp_compatibility: +- 4.16 +- 4.17 +- 4.18 +- 4.19 + +uds_version: 2.0.12 # Operator version 2.0.12 # sticking to 2.0.12 version # Please do Not Change +sls_version: 3.12.4 # Operator version 3.12.4 (https://github.ibm.com/maximoappsuite/ibm-sls/releases) +tsm_version: 1.7.2 # Operator version 1.7.2 (https://github.ibm.com/maximoappsuite/ibm-truststore-mgr/releases) +db2u_version: 7.3.1+20250821.161005.16793 # Operator version 110509.0.2 to find the version 7.2.0, search CASE_VERSION in db2u, catalog.yaml into ibm-maximo-operator-catalog (https://github.com/IBM/cloud-pak/tree/master/repo/case/ibm-db2uoperator) + +# Maximo Application Suite +# ----------------------------------------------------------------------------- +mas_core_version: + 9.2.x-feature: 9.2.0-pre.stable_6280 # Need to update + 9.1.x: 9.1.7 # Need to update + 9.0.x: 9.0.18 # Need to update + 8.10.x: "" # Not Supported + 8.11.x: "" # Not Supported +mas_manage_version: + 9.2.x-feature: 9.2.0-pre.stable_6856 # Need to update + 9.1.x: 9.1.7 # Need to update + 9.0.x: 9.0.20 # Need to update + 8.10.x: "" # Not Supported + 8.11.x: "" # Not Supported + +# Extra Images for UDS +# ------------------------------------------------------------------------------ +uds_extras_version: 1.5.0 + +# Extra Images for Mongo +# ------------------------------------------------------------------------------ +mongo_extras_version_default: 8.0.17 + +# Variables used to mirror additional mongo image versions +mongo_extras_version_4: 4.4.21 +mongo_extras_version_5: 5.0.23 +mongo_extras_version_6: 6.0.12 +mongo_extras_version_7: 7.0.12 +mongo_extras_version_8: 8.0.17 + +editorial: + whats_new: + - title: '**MongoDb v8.0.17** support Running `mas update` will automatically upgrade existing MongoDbCommunity instances to MongoDb version v8.0.17 this requires MongoDb version to be on v7 or later.' + details: [] + - title: '**Security updates and bug fixes**' + details: + - IBM Maximo Application Suite Core Platform v9.0 and v9.1 + - IBM Maximo Manage v9.0 and v9.1 + - IBM Suite License Service v3.12 + known_issues: [] From 3afcf87d83cfc385333895481e74470e3500e963 Mon Sep 17 00:00:00 2001 From: Anil Prajapati Date: Tue, 20 Jan 2026 11:01:45 +0530 Subject: [PATCH 04/45] [patch] update db2u version --- src/mas/devops/data/catalogs/v9-260129-amd64.yaml | 2 +- src/mas/devops/data/catalogs/v9-260129-s390x.yaml | 2 +- src/mas/devops/data/catalogs/v9-290129-ppc64le.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mas/devops/data/catalogs/v9-260129-amd64.yaml b/src/mas/devops/data/catalogs/v9-260129-amd64.yaml index 111bc9a9..417d6b92 100644 --- a/src/mas/devops/data/catalogs/v9-260129-amd64.yaml +++ b/src/mas/devops/data/catalogs/v9-260129-amd64.yaml @@ -22,7 +22,7 @@ common_svcs_version_1: 4.11.0 # Additional version 4.11.0 cp4d_platform_version: 5.2.0+20250709.170324 # Operator version 5.2.0 (https://github.com/IBM/cloud-pak/tree/master/repo/case/ibm-cp-datacore/) ibm_zen_version: 6.2.0+20250530.152516.232 # For CPD5 ibm-zen has to be explicitily mirrored -db2u_version: 7.3.1+20250821.161005.16793 # Operator version 110509.0.6 to find the version 7.3.1+20250821.161005.16793, search db2u-operator digest on repo (https://github.com/IBM/cloud-pak/tree/master/repo/case/ibm-db2uoperator) +db2u_version: 7.5.1+20251217.121408.18568 # Operator version 110509.0.7 to find the version 7.5.1+20251217.121408.18568, search db2u-operator digest on repo (https://github.com/IBM/cloud-pak/tree/master/repo/case/ibm-db2uoperator) db2_channel_default: v110509.0 # Default Channel version for db2u-operator events_version: 5.0.1 # Operator version 5.0.1 (https://github.com/IBM/cloud-pak/tree/master/repo/case/ibm-events-operator) uds_version: 2.0.12 # Operator version 2.0.12 # sticking to 2.0.12 version # Please do Not Change diff --git a/src/mas/devops/data/catalogs/v9-260129-s390x.yaml b/src/mas/devops/data/catalogs/v9-260129-s390x.yaml index 2e27840c..86a64289 100644 --- a/src/mas/devops/data/catalogs/v9-260129-s390x.yaml +++ b/src/mas/devops/data/catalogs/v9-260129-s390x.yaml @@ -16,7 +16,7 @@ ocp_compatibility: uds_version: 2.0.12 # Operator version 2.0.12 # sticking to 2.0.12 version # Please do Not Change sls_version: 3.12.4 # Operator version 3.12.4 (https://github.ibm.com/maximoappsuite/ibm-sls/releases) tsm_version: 1.7.2 # Operator version 1.7.2 (https://github.ibm.com/maximoappsuite/ibm-truststore-mgr/releases) -db2u_version: 7.3.1+20250821.161005.16793 # Operator version 110509.0.2 to find the version 7.2.0, search CASE_VERSION in db2u, catalog.yaml into ibm-maximo-operator-catalog (https://github.com/IBM/cloud-pak/tree/master/repo/case/ibm-db2uoperator) +db2u_version: 7.5.1+20251217.121408.18568 # Operator version 110509.0.7 to find the version 7.5.1+20251217.121408.18568, search db2u-operator digest on repo (https://github.com/IBM/cloud-pak/tree/master/repo/case/ibm-db2uoperator) # Maximo Application Suite # ----------------------------------------------------------------------------- diff --git a/src/mas/devops/data/catalogs/v9-290129-ppc64le.yaml b/src/mas/devops/data/catalogs/v9-290129-ppc64le.yaml index 30b57d54..888a37c3 100644 --- a/src/mas/devops/data/catalogs/v9-290129-ppc64le.yaml +++ b/src/mas/devops/data/catalogs/v9-290129-ppc64le.yaml @@ -16,7 +16,7 @@ ocp_compatibility: uds_version: 2.0.12 # Operator version 2.0.12 # sticking to 2.0.12 version # Please do Not Change sls_version: 3.12.4 # Operator version 3.12.4 (https://github.ibm.com/maximoappsuite/ibm-sls/releases) tsm_version: 1.7.2 # Operator version 1.7.2 (https://github.ibm.com/maximoappsuite/ibm-truststore-mgr/releases) -db2u_version: 7.3.1+20250821.161005.16793 # Operator version 110509.0.2 to find the version 7.2.0, search CASE_VERSION in db2u, catalog.yaml into ibm-maximo-operator-catalog (https://github.com/IBM/cloud-pak/tree/master/repo/case/ibm-db2uoperator) +db2u_version: 7.5.1+20251217.121408.18568 # Operator version 110509.0.7 to find the version 7.5.1+20251217.121408.18568, search db2u-operator digest on repo (https://github.com/IBM/cloud-pak/tree/master/repo/case/ibm-db2uoperator) # Maximo Application Suite # ----------------------------------------------------------------------------- From c1facb3e530f90614848c46172aca0f2d68bf347 Mon Sep 17 00:00:00 2001 From: Anil Prajapati Date: Wed, 21 Jan 2026 11:07:03 +0530 Subject: [PATCH 05/45] [patch] add elasticsearch_version --- src/mas/devops/data/catalogs/v9-260129-amd64.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mas/devops/data/catalogs/v9-260129-amd64.yaml b/src/mas/devops/data/catalogs/v9-260129-amd64.yaml index 417d6b92..380d82cb 100644 --- a/src/mas/devops/data/catalogs/v9-260129-amd64.yaml +++ b/src/mas/devops/data/catalogs/v9-260129-amd64.yaml @@ -41,7 +41,7 @@ ccs_build: 11.0.0+20250605.130237.468 # cpd 5.2.0 using ccs build spark_version: 11.0.0+20250604.163055.2097 # Operator version 5.2.0 cognos_version: 28.0.0+20250515.175459.10054 # Operator version 25.0.0 couchdb_version: 1.0.13 # Operator version 2.2.1 (1.0.13) sticking with 1.0.13 # (This is required for Assist 9.0, https://github.com/IBM/cloud-pak/blob/master/repo/case/ibm-couchdb/index.yaml) -# elasticsearch_version: 1.1.2667 # Operator version 1.1.2667 # used in cpd 5.1.3 only +elasticsearch_version: 1.1.2667 # Operator version 1.1.2667 # used in cpd 5.1.3 only opensearch_version: 1.1.2494 # Operator version 1.1.2494 # Maximo Application Suite From c499634fa87df9fd8613b68e5094a3ce50bf3c43 Mon Sep 17 00:00:00 2001 From: Parveen Kumar Date: Wed, 21 Jan 2026 14:09:50 +0530 Subject: [PATCH 06/45] [patch] updated latest app version of jan release --- .../devops/data/catalogs/v9-260129-amd64.yaml | 30 +++++++++---------- .../devops/data/catalogs/v9-260129-s390x.yaml | 2 +- .../data/catalogs/v9-290129-ppc64le.yaml | 2 +- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/mas/devops/data/catalogs/v9-260129-amd64.yaml b/src/mas/devops/data/catalogs/v9-260129-amd64.yaml index 380d82cb..5866f0ad 100644 --- a/src/mas/devops/data/catalogs/v9-260129-amd64.yaml +++ b/src/mas/devops/data/catalogs/v9-260129-amd64.yaml @@ -26,7 +26,7 @@ db2u_version: 7.5.1+20251217.121408.18568 # Operator version 110509.0.7 to fi db2_channel_default: v110509.0 # Default Channel version for db2u-operator events_version: 5.0.1 # Operator version 5.0.1 (https://github.com/IBM/cloud-pak/tree/master/repo/case/ibm-events-operator) uds_version: 2.0.12 # Operator version 2.0.12 # sticking to 2.0.12 version # Please do Not Change -sls_version: 3.12.4 # Operator version 3.12.4 (https://github.ibm.com/maximoappsuite/ibm-sls/releases) +sls_version: 3.12.5 # Operator version 3.12.5 (https://github.ibm.com/maximoappsuite/ibm-sls/releases) tsm_version: 1.7.2 # Operator version 1.7.2 (https://github.ibm.com/maximoappsuite/ibm-truststore-mgr/releases) dd_version: 1.1.20 # Operator version 1.1.14 (https://github.ibm.com/maximoappsuite/ibm-data-dictionary/releases) appconnect_version: 6.2.0 # Operator version 6.2.0 # sticking to 6.2.0 version # Please do Not Change @@ -53,8 +53,8 @@ mas_core_version: 8.10.x: 8.10.32 # Need to update 8.11.x: 8.11.29 # Need to update mas_assist_version: - 9.1.x: 9.1.6 # Need to update - 9.0.x: 9.0.12 # Need to update + 9.1.x: 9.1.7 # Updated + 9.0.x: 9.0.13 # Updated 8.10.x: 8.7.8 # No Update 8.11.x: 8.8.7 # No Update mas_hputilities_version: @@ -74,16 +74,16 @@ mas_manage_version: 8.10.x: 8.6.33 # Need to update 8.11.x: 8.7.27 # Need to update mas_monitor_version: - 9.1.x: 9.1.6 # Need to update - 9.0.x: 9.0.16 # Need to update - 8.10.x: 8.10.26 # Need to update - 8.11.x: 8.11.24 # Need to update + 9.1.x: 9.1.7 # Updated + 9.0.x: 9.0.17 # Updated + 8.10.x: 8.10.27 # Updated + 8.11.x: 8.11.25 # Updated mas_optimizer_version: - 9.2.x-feature: 9.2.0-pre.stable_5162 # Need to update - 9.1.x: 9.1.7 # Need to update - 9.0.x: 9.0.16 # Need to update - 8.10.x: 8.4.25 # Need to update - 8.11.x: 8.5.24 # Need to update + 9.2.x-feature: 9.2.0-pre.stable_5718-amd64 # Updated + 9.1.x: 9.1.8 # Updated + 9.0.x: 9.0.19 # Updated + 8.10.x: 8.4.26 # Updated + 8.11.x: 8.5.25 # Updated mas_predict_version: 9.1.x: 9.1.4 # Need to update 9.0.x: 9.0.11 # Need to update @@ -96,7 +96,7 @@ mas_visualinspection_version: 8.10.x: 8.8.4 # No Update 8.11.x: 8.9.18 # Need to update mas_facilities_version: - 9.1.x: 9.1.6 # Need to update + 9.1.x: 9.1.7 # Updated 9.0.x: "" # Not Supported 8.10.x: "" # Not Supported 8.11.x: "" # Not Supported @@ -105,8 +105,8 @@ mas_facilities_version: # Maximo AI Service # ------------------------------------------------------------------------------ aiservice_version: - 9.2.x-feature: 9.2.0-pre.stable_6741 # Need to update - 9.1.x: 9.1.10 # Need to update + 9.2.x-feature: 9.2.0-pre.stable_9768 # Updated + 9.1.x: 9.1.11 # Updated # Extra Images for UDS diff --git a/src/mas/devops/data/catalogs/v9-260129-s390x.yaml b/src/mas/devops/data/catalogs/v9-260129-s390x.yaml index 86a64289..6d9d2885 100644 --- a/src/mas/devops/data/catalogs/v9-260129-s390x.yaml +++ b/src/mas/devops/data/catalogs/v9-260129-s390x.yaml @@ -14,7 +14,7 @@ ocp_compatibility: - 4.19 uds_version: 2.0.12 # Operator version 2.0.12 # sticking to 2.0.12 version # Please do Not Change -sls_version: 3.12.4 # Operator version 3.12.4 (https://github.ibm.com/maximoappsuite/ibm-sls/releases) +sls_version: 3.12.5 # Operator version 3.12.5 (https://github.ibm.com/maximoappsuite/ibm-sls/releases) tsm_version: 1.7.2 # Operator version 1.7.2 (https://github.ibm.com/maximoappsuite/ibm-truststore-mgr/releases) db2u_version: 7.5.1+20251217.121408.18568 # Operator version 110509.0.7 to find the version 7.5.1+20251217.121408.18568, search db2u-operator digest on repo (https://github.com/IBM/cloud-pak/tree/master/repo/case/ibm-db2uoperator) diff --git a/src/mas/devops/data/catalogs/v9-290129-ppc64le.yaml b/src/mas/devops/data/catalogs/v9-290129-ppc64le.yaml index 888a37c3..b0efca97 100644 --- a/src/mas/devops/data/catalogs/v9-290129-ppc64le.yaml +++ b/src/mas/devops/data/catalogs/v9-290129-ppc64le.yaml @@ -14,7 +14,7 @@ ocp_compatibility: - 4.19 uds_version: 2.0.12 # Operator version 2.0.12 # sticking to 2.0.12 version # Please do Not Change -sls_version: 3.12.4 # Operator version 3.12.4 (https://github.ibm.com/maximoappsuite/ibm-sls/releases) +sls_version: 3.12.5 # Operator version 3.12.5 (https://github.ibm.com/maximoappsuite/ibm-sls/releases) tsm_version: 1.7.2 # Operator version 1.7.2 (https://github.ibm.com/maximoappsuite/ibm-truststore-mgr/releases) db2u_version: 7.5.1+20251217.121408.18568 # Operator version 110509.0.7 to find the version 7.5.1+20251217.121408.18568, search db2u-operator digest on repo (https://github.com/IBM/cloud-pak/tree/master/repo/case/ibm-db2uoperator) From d039af481f9e0d1843898c42816b5ca00c76fcb9 Mon Sep 17 00:00:00 2001 From: Parveen Kumar Date: Wed, 21 Jan 2026 15:09:31 +0530 Subject: [PATCH 07/45] [patch] update latest catalog digest --- src/mas/devops/data/catalogs/v9-260129-amd64.yaml | 2 +- src/mas/devops/data/catalogs/v9-260129-s390x.yaml | 2 +- src/mas/devops/data/catalogs/v9-290129-ppc64le.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mas/devops/data/catalogs/v9-260129-amd64.yaml b/src/mas/devops/data/catalogs/v9-260129-amd64.yaml index 5866f0ad..e9da43ff 100644 --- a/src/mas/devops/data/catalogs/v9-260129-amd64.yaml +++ b/src/mas/devops/data/catalogs/v9-260129-amd64.yaml @@ -5,7 +5,7 @@ # catalog itself, but not everything in the catalog supports this yet (including MAS) # so we need to use the CASE bundle mirror process still. -catalog_digest: sha256:62a3d0251fe682411f490e5f4b67fb4e6abc033c65025d36b3271d3e5fc5e57e +catalog_digest: sha256:4d370a19d522dc3536b8c2457dc459fc621887b66d750dc16cbb1c6bee307370 ocp_compatibility: - 4.16 diff --git a/src/mas/devops/data/catalogs/v9-260129-s390x.yaml b/src/mas/devops/data/catalogs/v9-260129-s390x.yaml index 6d9d2885..c7c87060 100644 --- a/src/mas/devops/data/catalogs/v9-260129-s390x.yaml +++ b/src/mas/devops/data/catalogs/v9-260129-s390x.yaml @@ -5,7 +5,7 @@ # catalog itself, but not everything in the catalog supports this yet (including MAS) # so we need to use the CASE bundle mirror process still. -catalog_digest: sha256:8209ebc3a2d50130307177b8b16e2bc91b6b3c6b3a4955bf0672333b918ffcb7 +catalog_digest: sha256:00fcfd02daf09da627be660db943bf0c5a63e57cc647782395def85b04bd3c7b ocp_compatibility: - 4.16 diff --git a/src/mas/devops/data/catalogs/v9-290129-ppc64le.yaml b/src/mas/devops/data/catalogs/v9-290129-ppc64le.yaml index b0efca97..334a5aa5 100644 --- a/src/mas/devops/data/catalogs/v9-290129-ppc64le.yaml +++ b/src/mas/devops/data/catalogs/v9-290129-ppc64le.yaml @@ -5,7 +5,7 @@ # catalog itself, but not everything in the catalog supports this yet (including MAS) # so we need to use the CASE bundle mirror process still. -catalog_digest: sha256:26999b70b82c5363b2d24c9f6ecb2817de3c1492cdeebd816bc02422ac1d6fea +catalog_digest: sha256:f5cf8dfbffc8d456946e3e44173cac88470bc1f93f8d6ed112f996dc76677d47 ocp_compatibility: - 4.16 From 06f60076090ee62b063562f22bbab98585852f7a Mon Sep 17 00:00:00 2001 From: Anil Prajapati Date: Thu, 22 Jan 2026 11:12:10 +0530 Subject: [PATCH 08/45] [patch] add catalog digest --- src/mas/devops/data/catalogs/v9-260129-amd64.yaml | 2 +- src/mas/devops/data/catalogs/v9-260129-s390x.yaml | 2 +- src/mas/devops/data/catalogs/v9-290129-ppc64le.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mas/devops/data/catalogs/v9-260129-amd64.yaml b/src/mas/devops/data/catalogs/v9-260129-amd64.yaml index e9da43ff..980b0979 100644 --- a/src/mas/devops/data/catalogs/v9-260129-amd64.yaml +++ b/src/mas/devops/data/catalogs/v9-260129-amd64.yaml @@ -5,7 +5,7 @@ # catalog itself, but not everything in the catalog supports this yet (including MAS) # so we need to use the CASE bundle mirror process still. -catalog_digest: sha256:4d370a19d522dc3536b8c2457dc459fc621887b66d750dc16cbb1c6bee307370 +catalog_digest: sha256:9a1d87b15420f66ac3f9c960452a68bbcf84eae049ab59ffd06d1c666368c8c8 ocp_compatibility: - 4.16 diff --git a/src/mas/devops/data/catalogs/v9-260129-s390x.yaml b/src/mas/devops/data/catalogs/v9-260129-s390x.yaml index c7c87060..86a56449 100644 --- a/src/mas/devops/data/catalogs/v9-260129-s390x.yaml +++ b/src/mas/devops/data/catalogs/v9-260129-s390x.yaml @@ -5,7 +5,7 @@ # catalog itself, but not everything in the catalog supports this yet (including MAS) # so we need to use the CASE bundle mirror process still. -catalog_digest: sha256:00fcfd02daf09da627be660db943bf0c5a63e57cc647782395def85b04bd3c7b +catalog_digest: sha256:971d4cede4d1ca670a9f77b58adc9f4bdab7108e7e22ee53966824be42b34ad0 ocp_compatibility: - 4.16 diff --git a/src/mas/devops/data/catalogs/v9-290129-ppc64le.yaml b/src/mas/devops/data/catalogs/v9-290129-ppc64le.yaml index 334a5aa5..dd32d25c 100644 --- a/src/mas/devops/data/catalogs/v9-290129-ppc64le.yaml +++ b/src/mas/devops/data/catalogs/v9-290129-ppc64le.yaml @@ -5,7 +5,7 @@ # catalog itself, but not everything in the catalog supports this yet (including MAS) # so we need to use the CASE bundle mirror process still. -catalog_digest: sha256:f5cf8dfbffc8d456946e3e44173cac88470bc1f93f8d6ed112f996dc76677d47 +catalog_digest: sha256:53f2218a5181b7c02326845f80f24ff6365c744bd633f75007c39bec3f0c584f ocp_compatibility: - 4.16 From 8c4e44edd0b134057f8bf6eb0f3c8e2bb695409b Mon Sep 17 00:00:00 2001 From: Parveen Kumar Date: Thu, 22 Jan 2026 12:22:30 +0530 Subject: [PATCH 09/45] [patch] update mas-core, iot and manage apps version --- .../devops/data/catalogs/v9-260129-amd64.yaml | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/mas/devops/data/catalogs/v9-260129-amd64.yaml b/src/mas/devops/data/catalogs/v9-260129-amd64.yaml index 980b0979..5837f19e 100644 --- a/src/mas/devops/data/catalogs/v9-260129-amd64.yaml +++ b/src/mas/devops/data/catalogs/v9-260129-amd64.yaml @@ -48,10 +48,10 @@ opensearch_version: 1.1.2494 # Operator version 1.1.2494 # ----------------------------------------------------------------------------- mas_core_version: 9.2.x-feature: 9.2.0-pre.stable_6976 # Need to update - 9.1.x: 9.1.7 # Need to update - 9.0.x: 9.0.18 # Need to update - 8.10.x: 8.10.32 # Need to update - 8.11.x: 8.11.29 # Need to update + 9.1.x: 9.1.8 # Updated + 9.0.x: 9.0.19 # Updated + 8.10.x: 8.10.33 # Updated + 8.11.x: 8.11.30 # Updated mas_assist_version: 9.1.x: 9.1.7 # Updated 9.0.x: 9.0.13 # Updated @@ -63,16 +63,16 @@ mas_hputilities_version: 8.10.x: 8.6.7 # No Update 8.11.x: "" # Not Supported mas_iot_version: - 9.1.x: 9.1.6 # Need to update - 9.0.x: 9.0.15 # Need to update - 8.10.x: 8.7.29 # Need to update - 8.11.x: 8.8.25 # Need to update + 9.1.x: 9.1.7 # Updated + 9.0.x: 9.0.16 # Updated + 8.10.x: 8.7.30 # Updated + 8.11.x: 8.8.26 # Updated mas_manage_version: 9.2.x-feature: 9.2.0-pre.stable_6856 # Need to update - 9.1.x: 9.1.7 # Need to update - 9.0.x: 9.0.20 # Need to update - 8.10.x: 8.6.33 # Need to update - 8.11.x: 8.7.27 # Need to update + 9.1.x: 9.1.8 # Updated + 9.0.x: 9.0.21 # Updated + 8.10.x: 8.6.34 # Updated + 8.11.x: 8.7.28 # Updated mas_monitor_version: 9.1.x: 9.1.7 # Updated 9.0.x: 9.0.17 # Updated From 744a18d4a2b5ae15ffe9b4900d4658f801dcbcb7 Mon Sep 17 00:00:00 2001 From: Parveen Kumar Date: Thu, 22 Jan 2026 12:28:28 +0530 Subject: [PATCH 10/45] [patch] update apps version --- src/mas/devops/data/catalogs/v9-260129-s390x.yaml | 8 ++++---- src/mas/devops/data/catalogs/v9-290129-ppc64le.yaml | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/mas/devops/data/catalogs/v9-260129-s390x.yaml b/src/mas/devops/data/catalogs/v9-260129-s390x.yaml index 86a56449..ddbd0390 100644 --- a/src/mas/devops/data/catalogs/v9-260129-s390x.yaml +++ b/src/mas/devops/data/catalogs/v9-260129-s390x.yaml @@ -22,14 +22,14 @@ db2u_version: 7.5.1+20251217.121408.18568 # Operator version 110509.0.7 to fi # ----------------------------------------------------------------------------- mas_core_version: 9.2.x-feature: 9.2.0-pre.stable_6976 # Need to update - 9.1.x: 9.1.7 # Need to update - 9.0.x: 9.0.18 # Need to update + 9.1.x: 9.1.8 # Updated + 9.0.x: 9.0.19 # Updated 8.10.x: "" # Not Supported 8.11.x: "" # Not Supported mas_manage_version: 9.2.x-feature: 9.2.0-pre.stable_6856 # Need to update - 9.1.x: 9.1.7 # Need to update - 9.0.x: 9.0.20 # Need to update + 9.1.x: 9.1.8 # Updated + 9.0.x: 9.0.21 # Updated 8.10.x: "" # Not Supported 8.11.x: "" # Not Supported diff --git a/src/mas/devops/data/catalogs/v9-290129-ppc64le.yaml b/src/mas/devops/data/catalogs/v9-290129-ppc64le.yaml index dd32d25c..f83eebec 100644 --- a/src/mas/devops/data/catalogs/v9-290129-ppc64le.yaml +++ b/src/mas/devops/data/catalogs/v9-290129-ppc64le.yaml @@ -22,14 +22,14 @@ db2u_version: 7.5.1+20251217.121408.18568 # Operator version 110509.0.7 to fi # ----------------------------------------------------------------------------- mas_core_version: 9.2.x-feature: 9.2.0-pre.stable_6280 # Need to update - 9.1.x: 9.1.7 # Need to update - 9.0.x: 9.0.18 # Need to update + 9.1.x: 9.1.8 # Updated + 9.0.x: 9.0.19 # Updated 8.10.x: "" # Not Supported 8.11.x: "" # Not Supported mas_manage_version: 9.2.x-feature: 9.2.0-pre.stable_6856 # Need to update - 9.1.x: 9.1.7 # Need to update - 9.0.x: 9.0.20 # Need to update + 9.1.x: 9.1.8 # Updated + 9.0.x: 9.0.21 # Updated 8.10.x: "" # Not Supported 8.11.x: "" # Not Supported From 5c47c3d62e171a3cae507030280a80ec76411939 Mon Sep 17 00:00:00 2001 From: Parveen Kumar Date: Tue, 27 Jan 2026 15:34:16 +0530 Subject: [PATCH 11/45] [patch] mas and manage fc, mvi and digest update --- src/mas/devops/data/catalogs/v9-260129-amd64.yaml | 14 +++++++------- src/mas/devops/data/catalogs/v9-260129-s390x.yaml | 6 +++--- .../devops/data/catalogs/v9-290129-ppc64le.yaml | 6 +++--- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/mas/devops/data/catalogs/v9-260129-amd64.yaml b/src/mas/devops/data/catalogs/v9-260129-amd64.yaml index 5837f19e..c79b8a71 100644 --- a/src/mas/devops/data/catalogs/v9-260129-amd64.yaml +++ b/src/mas/devops/data/catalogs/v9-260129-amd64.yaml @@ -5,7 +5,7 @@ # catalog itself, but not everything in the catalog supports this yet (including MAS) # so we need to use the CASE bundle mirror process still. -catalog_digest: sha256:9a1d87b15420f66ac3f9c960452a68bbcf84eae049ab59ffd06d1c666368c8c8 +catalog_digest: sha256:491a540becc02763812248c60357b0e58656b0c8cc5547fab661ceab57125556 ocp_compatibility: - 4.16 @@ -28,7 +28,7 @@ events_version: 5.0.1 # Operator version 5.0.1 (https://g uds_version: 2.0.12 # Operator version 2.0.12 # sticking to 2.0.12 version # Please do Not Change sls_version: 3.12.5 # Operator version 3.12.5 (https://github.ibm.com/maximoappsuite/ibm-sls/releases) tsm_version: 1.7.2 # Operator version 1.7.2 (https://github.ibm.com/maximoappsuite/ibm-truststore-mgr/releases) -dd_version: 1.1.20 # Operator version 1.1.14 (https://github.ibm.com/maximoappsuite/ibm-data-dictionary/releases) +dd_version: 1.1.21 # Operator version 1.1.21 (https://github.ibm.com/maximoappsuite/ibm-data-dictionary/releases) appconnect_version: 6.2.0 # Operator version 6.2.0 # sticking to 6.2.0 version # Please do Not Change wsl_version: 11.0.0+20250521.202913.73 # used for wsl and wsl_runtimes unless wsl_runtimes_version also specified wsl_runtimes_version: 11.0.0+20250515.090949.21 # cpd 5.1.3 uses version 10.3.0 of wsl runtimes but only 10.2.0 for wsl itself @@ -47,7 +47,7 @@ opensearch_version: 1.1.2494 # Operator version 1.1.2494 # Maximo Application Suite # ----------------------------------------------------------------------------- mas_core_version: - 9.2.x-feature: 9.2.0-pre.stable_6976 # Need to update + 9.2.x-feature: 9.2.0-pre.stable_9887 # Updated 9.1.x: 9.1.8 # Updated 9.0.x: 9.0.19 # Updated 8.10.x: 8.10.33 # Updated @@ -68,7 +68,7 @@ mas_iot_version: 8.10.x: 8.7.30 # Updated 8.11.x: 8.8.26 # Updated mas_manage_version: - 9.2.x-feature: 9.2.0-pre.stable_6856 # Need to update + 9.2.x-feature: 9.2.0-pre.stable_10282 # Updated 9.1.x: 9.1.8 # Updated 9.0.x: 9.0.21 # Updated 8.10.x: 8.6.34 # Updated @@ -91,10 +91,10 @@ mas_predict_version: 8.11.x: 8.9.14 # Need to update mas_visualinspection_version: 9.2.x-feature: 9.2.0-pre.stable_6198 # Need to update - 9.1.x: 9.1.5 # Need to update - 9.0.x: 9.0.15 # UpdNeed to updateated + 9.1.x: 9.1.7 # Updated + 9.0.x: 9.0.16 # Updated 8.10.x: 8.8.4 # No Update - 8.11.x: 8.9.18 # Need to update + 8.11.x: 8.9.19 # Updated mas_facilities_version: 9.1.x: 9.1.7 # Updated 9.0.x: "" # Not Supported diff --git a/src/mas/devops/data/catalogs/v9-260129-s390x.yaml b/src/mas/devops/data/catalogs/v9-260129-s390x.yaml index ddbd0390..5fffc29a 100644 --- a/src/mas/devops/data/catalogs/v9-260129-s390x.yaml +++ b/src/mas/devops/data/catalogs/v9-260129-s390x.yaml @@ -5,7 +5,7 @@ # catalog itself, but not everything in the catalog supports this yet (including MAS) # so we need to use the CASE bundle mirror process still. -catalog_digest: sha256:971d4cede4d1ca670a9f77b58adc9f4bdab7108e7e22ee53966824be42b34ad0 +catalog_digest: sha256:ae5472d4a8f6f9fe6140af1417b37965f35387a112f4ee9ced57606aa3fb5026 ocp_compatibility: - 4.16 @@ -21,13 +21,13 @@ db2u_version: 7.5.1+20251217.121408.18568 # Operator version 110509.0.7 to fi # Maximo Application Suite # ----------------------------------------------------------------------------- mas_core_version: - 9.2.x-feature: 9.2.0-pre.stable_6976 # Need to update + 9.2.x-feature: 9.2.0-pre.stable_9887 # Updated 9.1.x: 9.1.8 # Updated 9.0.x: 9.0.19 # Updated 8.10.x: "" # Not Supported 8.11.x: "" # Not Supported mas_manage_version: - 9.2.x-feature: 9.2.0-pre.stable_6856 # Need to update + 9.2.x-feature: 9.2.0-pre.stable_10282 # Updated 9.1.x: 9.1.8 # Updated 9.0.x: 9.0.21 # Updated 8.10.x: "" # Not Supported diff --git a/src/mas/devops/data/catalogs/v9-290129-ppc64le.yaml b/src/mas/devops/data/catalogs/v9-290129-ppc64le.yaml index f83eebec..79739528 100644 --- a/src/mas/devops/data/catalogs/v9-290129-ppc64le.yaml +++ b/src/mas/devops/data/catalogs/v9-290129-ppc64le.yaml @@ -5,7 +5,7 @@ # catalog itself, but not everything in the catalog supports this yet (including MAS) # so we need to use the CASE bundle mirror process still. -catalog_digest: sha256:53f2218a5181b7c02326845f80f24ff6365c744bd633f75007c39bec3f0c584f +catalog_digest: sha256:ff7857b5e1dcc8be7dd73cc7f9b869a46cb4d68f8c23de2299ead406a075a0eb ocp_compatibility: - 4.16 @@ -21,13 +21,13 @@ db2u_version: 7.5.1+20251217.121408.18568 # Operator version 110509.0.7 to fi # Maximo Application Suite # ----------------------------------------------------------------------------- mas_core_version: - 9.2.x-feature: 9.2.0-pre.stable_6280 # Need to update + 9.2.x-feature: 9.2.0-pre.stable_9887 # Updated 9.1.x: 9.1.8 # Updated 9.0.x: 9.0.19 # Updated 8.10.x: "" # Not Supported 8.11.x: "" # Not Supported mas_manage_version: - 9.2.x-feature: 9.2.0-pre.stable_6856 # Need to update + 9.2.x-feature: 9.2.0-pre.stable_10282 # Updated 9.1.x: 9.1.8 # Updated 9.0.x: 9.0.21 # Updated 8.10.x: "" # Not Supported From 66cd091f34c8c61b7c3ce09aad53bfffcf6eaf19 Mon Sep 17 00:00:00 2001 From: Parveen Kumar Date: Tue, 27 Jan 2026 22:42:28 +0530 Subject: [PATCH 12/45] [patch] update latest catalog digest --- src/mas/devops/data/catalogs/v9-260129-amd64.yaml | 4 ++-- src/mas/devops/data/catalogs/v9-260129-s390x.yaml | 2 +- src/mas/devops/data/catalogs/v9-290129-ppc64le.yaml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mas/devops/data/catalogs/v9-260129-amd64.yaml b/src/mas/devops/data/catalogs/v9-260129-amd64.yaml index c79b8a71..dc0376b5 100644 --- a/src/mas/devops/data/catalogs/v9-260129-amd64.yaml +++ b/src/mas/devops/data/catalogs/v9-260129-amd64.yaml @@ -5,7 +5,7 @@ # catalog itself, but not everything in the catalog supports this yet (including MAS) # so we need to use the CASE bundle mirror process still. -catalog_digest: sha256:491a540becc02763812248c60357b0e58656b0c8cc5547fab661ceab57125556 +catalog_digest: sha256:8e5e1245f70ec96b4c5f81d52e1e41d8efd015eeb1e0fd1c769b1866b174f7fe ocp_compatibility: - 4.16 @@ -79,7 +79,7 @@ mas_monitor_version: 8.10.x: 8.10.27 # Updated 8.11.x: 8.11.25 # Updated mas_optimizer_version: - 9.2.x-feature: 9.2.0-pre.stable_5718-amd64 # Updated + 9.2.x-feature: 9.2.0-pre.stable_9869-amd64 # Updated 9.1.x: 9.1.8 # Updated 9.0.x: 9.0.19 # Updated 8.10.x: 8.4.26 # Updated diff --git a/src/mas/devops/data/catalogs/v9-260129-s390x.yaml b/src/mas/devops/data/catalogs/v9-260129-s390x.yaml index 5fffc29a..b68df472 100644 --- a/src/mas/devops/data/catalogs/v9-260129-s390x.yaml +++ b/src/mas/devops/data/catalogs/v9-260129-s390x.yaml @@ -5,7 +5,7 @@ # catalog itself, but not everything in the catalog supports this yet (including MAS) # so we need to use the CASE bundle mirror process still. -catalog_digest: sha256:ae5472d4a8f6f9fe6140af1417b37965f35387a112f4ee9ced57606aa3fb5026 +catalog_digest: sha256:8628069464de6761e3d58304a6ffd2eb8c815ca54563d826983469e0e36b9ce5 ocp_compatibility: - 4.16 diff --git a/src/mas/devops/data/catalogs/v9-290129-ppc64le.yaml b/src/mas/devops/data/catalogs/v9-290129-ppc64le.yaml index 79739528..adcb2163 100644 --- a/src/mas/devops/data/catalogs/v9-290129-ppc64le.yaml +++ b/src/mas/devops/data/catalogs/v9-290129-ppc64le.yaml @@ -5,7 +5,7 @@ # catalog itself, but not everything in the catalog supports this yet (including MAS) # so we need to use the CASE bundle mirror process still. -catalog_digest: sha256:ff7857b5e1dcc8be7dd73cc7f9b869a46cb4d68f8c23de2299ead406a075a0eb +catalog_digest: sha256:20ebe4e08614f5eb34afebc92345368c87f81d21f9212baa78ea3725d2bc2f0b ocp_compatibility: - 4.16 From 33f3d8213cd83731b3fbab27e745e01547a5bffe Mon Sep 17 00:00:00 2001 From: Anil Prajapati Date: Wed, 28 Jan 2026 00:05:28 +0530 Subject: [PATCH 13/45] [patch] remove -amd64 form the optimizer 92-fc --- src/mas/devops/data/catalogs/v9-260129-amd64.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mas/devops/data/catalogs/v9-260129-amd64.yaml b/src/mas/devops/data/catalogs/v9-260129-amd64.yaml index dc0376b5..89b159fb 100644 --- a/src/mas/devops/data/catalogs/v9-260129-amd64.yaml +++ b/src/mas/devops/data/catalogs/v9-260129-amd64.yaml @@ -79,7 +79,7 @@ mas_monitor_version: 8.10.x: 8.10.27 # Updated 8.11.x: 8.11.25 # Updated mas_optimizer_version: - 9.2.x-feature: 9.2.0-pre.stable_9869-amd64 # Updated + 9.2.x-feature: 9.2.0-pre.stable_9869 # Updated 9.1.x: 9.1.8 # Updated 9.0.x: 9.0.19 # Updated 8.10.x: 8.4.26 # Updated From a1ce79e968ebd2c8e33b7c510484b3dc0d047bd9 Mon Sep 17 00:00:00 2001 From: Anil Prajapati Date: Wed, 28 Jan 2026 01:21:23 +0530 Subject: [PATCH 14/45] [patch] cli notification --- bin/mas-devops-notify-slack | 134 ++++++++++++++++++++++++++++++++++++ src/mas/devops/slack.py | 122 ++++++++++++++++++++++++++++++++ 2 files changed, 256 insertions(+) diff --git a/bin/mas-devops-notify-slack b/bin/mas-devops-notify-slack index 8750af3b..a11d700a 100755 --- a/bin/mas-devops-notify-slack +++ b/bin/mas-devops-notify-slack @@ -97,6 +97,133 @@ def notifyProvisionRoks(channels: list[str], rc: int, additionalMsg: str | None return response.data.get("ok", False) +def notifyAnsibleComplete(channels: list[str], rc: int, taskName: str, pipelineName: str, instanceId: str | None = None) -> bool: + """Send Slack notification about Ansible task completion status.""" + namespace = os.getenv("PIPELINE_NAMESPACE", "") + pipelineRunName = os.getenv("PIPELINERUN_NAME", "") + + if namespace == "" or pipelineRunName == "": + print("PIPELINE_NAMESPACE and PIPELINERUN_NAME env vars must be set") + sys.exit(1) + + # Check if this is the first task (no ConfigMap exists yet) + threadInfo = SlackUtil.getThreadConfigMap(namespace, pipelineRunName) + + if threadInfo is None: + # This is the first task - send pipeline started message + toolchainLink = _getToolchainLink() + instanceInfo = f"\nInstance ID: `{instanceId}`" if instanceId else "" + + message = [ + SlackUtil.buildHeader(f"🚀 MAS {pipelineName.title()} Pipeline Started"), + SlackUtil.buildSection(f"Pipeline Run: `{pipelineRunName}`{instanceInfo}\n{toolchainLink}") + ] + + response = SlackUtil.postMessageBlocks(channels[0], message) + + if response.data.get("ok", False): + threadId = response["ts"] + channelId = response["channel"] + + # Store thread information in ConfigMap + SlackUtil.createThreadConfigMap(namespace, pipelineRunName, channelId, threadId, pipelineName) + threadInfo = { + "threadId": threadId, + "channelId": channelId, + "pipelineName": pipelineName + } + else: + print("Failed to send initial Slack message") + return False + + # Send task completion message as thread reply + threadId = threadInfo.get("threadId") + channelId = threadInfo.get("channelId") + + if rc == 0: + emoji = "✅" + status = "Success" + else: + emoji = "❌" + status = "Failed" + + taskMessage = [ + SlackUtil.buildSection(f"{emoji} **{taskName}** - {status}") + ] + + if rc != 0: + taskMessage.append(SlackUtil.buildSection(f"Return Code: `{rc}`\nCheck logs for details")) + + response = SlackUtil.postMessageBlocks(channelId, taskMessage, threadId) + + if isinstance(response, list): + return all([res.data.get("ok", False) for res in response]) + return response.data.get("ok", False) + + +def notifyPipelineComplete(channels: list[str], rc: int, pipelineName: str, instanceId: str | None = None) -> bool: + """Send Slack notification about pipeline completion and cleanup ConfigMap.""" + namespace = os.getenv("PIPELINE_NAMESPACE", "") + pipelineRunName = os.getenv("PIPELINERUN_NAME", "") + + if namespace == "" or pipelineRunName == "": + print("PIPELINE_NAMESPACE and PIPELINERUN_NAME env vars must be set") + sys.exit(1) + + # Get thread information + threadInfo = SlackUtil.getThreadConfigMap(namespace, pipelineRunName) + + if threadInfo is None: + print("No thread information found - pipeline may not have started properly") + return False + + threadId = threadInfo.get("threadId") + channelId = threadInfo.get("channelId") + startTime = threadInfo.get("startTime") + + # Calculate duration if start time is available + durationText = "" + if startTime: + from datetime import datetime + try: + start = datetime.fromisoformat(startTime.replace("Z", "+00:00")) + end = datetime.utcnow() + duration = end - start + hours, remainder = divmod(int(duration.total_seconds()), 3600) + minutes, seconds = divmod(remainder, 60) + if hours > 0: + durationText = f"\nTotal Duration: {hours}h {minutes}m {seconds}s" + else: + durationText = f"\nTotal Duration: {minutes}m {seconds}s" + except: + pass + + instanceInfo = f"\nInstance ID: `{instanceId}`" if instanceId else "" + + if rc == 0: + emoji = "🎉" + status = "Completed Successfully" + additionalInfo = "\nAll tasks completed successfully" + else: + emoji = "💥" + status = "Failed" + additionalInfo = f"\nPipeline failed with return code: `{rc}`" + + message = [ + SlackUtil.buildHeader(f"{emoji} MAS {pipelineName.title()} Pipeline {status}"), + SlackUtil.buildSection(f"Pipeline Run: `{pipelineRunName}`{instanceInfo}{durationText}{additionalInfo}") + ] + + response = SlackUtil.postMessageBlocks(channelId, message, threadId) + + # Clean up ConfigMap + SlackUtil.deleteThreadConfigMap(namespace, pipelineRunName) + + if isinstance(response, list): + return all([res.data.get("ok", False) for res in response]) + return response.data.get("ok", False) + + if __name__ == "__main__": # If SLACK_TOKEN or SLACK_CHANNEL env vars are not set then silently exit taking no action SLACK_TOKEN = os.getenv("SLACK_TOKEN", "") @@ -114,6 +241,9 @@ if __name__ == "__main__": parser.add_argument("--action", required=True) parser.add_argument("--rc", required=True, type=int) parser.add_argument("--msg", required=False, default=None) + parser.add_argument("--task-name", required=False, default="") + parser.add_argument("--pipeline-name", required=False, default="") + parser.add_argument("--instance-id", required=False, default=None) args, unknown = parser.parse_known_args() @@ -121,3 +251,7 @@ if __name__ == "__main__": notifyProvisionFyre(channelList, args.rc, args.msg) elif args.action == "ocp-provision-roks": notifyProvisionRoks(channelList, args.rc, args.msg) + elif args.action == "ansible-complete": + notifyAnsibleComplete(channelList, args.rc, args.task_name, args.pipeline_name, args.instance_id) + elif args.action == "pipeline-complete": + notifyPipelineComplete(channelList, args.rc, args.pipeline_name, args.instance_id) diff --git a/src/mas/devops/slack.py b/src/mas/devops/slack.py index a97cfd5d..f4e7ed68 100644 --- a/src/mas/devops/slack.py +++ b/src/mas/devops/slack.py @@ -270,6 +270,128 @@ def buildDivider(cls) -> dict: Returns: dict: Slack block kit divider element """ + def createThreadConfigMap(cls, namespace: str, pipelineRunName: str, channelId: str, threadId: str, pipelineName: str) -> bool: + """ + Create a ConfigMap to store Slack thread information for a pipeline run. + + Parameters: + namespace (str): Kubernetes namespace for the ConfigMap + pipelineRunName (str): Unique identifier for the pipeline run + channelId (str): Slack channel ID where the thread was created + threadId (str): Slack thread timestamp + pipelineName (str): Name of the pipeline (install/update/upgrade/uninstall) + + Returns: + bool: True if ConfigMap was created successfully, False otherwise + """ + try: + from kubernetes import client, config + from datetime import datetime + + # Load Kubernetes configuration + try: + config.load_incluster_config() + except: + config.load_kube_config() + + v1 = client.CoreV1Api() + + configmap_name = f"slack-thread-{pipelineRunName}" + configmap = client.V1ConfigMap( + metadata=client.V1ObjectMeta( + name=configmap_name, + namespace=namespace + ), + data={ + "threadId": threadId, + "channelId": channelId, + "pipelineName": pipelineName, + "startTime": datetime.utcnow().isoformat() + "Z" + } + ) + + v1.create_namespaced_config_map(namespace=namespace, body=configmap) + logger.info(f"Created ConfigMap {configmap_name} in namespace {namespace}") + return True + + except Exception as e: + logger.error(f"Failed to create ConfigMap: {e}") + return False + + def getThreadConfigMap(cls, namespace: str, pipelineRunName: str) -> dict | None: + """ + Retrieve Slack thread information from a ConfigMap. + + Parameters: + namespace (str): Kubernetes namespace containing the ConfigMap + pipelineRunName (str): Unique identifier for the pipeline run + + Returns: + dict | None: Dictionary containing threadId, channelId, pipelineName, and startTime, or None if not found + """ + try: + from kubernetes import client, config + + # Load Kubernetes configuration + try: + config.load_incluster_config() + except: + config.load_kube_config() + + v1 = client.CoreV1Api() + configmap_name = f"slack-thread-{pipelineRunName}" + + configmap = v1.read_namespaced_config_map(name=configmap_name, namespace=namespace) + logger.debug(f"Retrieved ConfigMap {configmap_name} from namespace {namespace}") + return configmap.data + + except client.exceptions.ApiException as e: + if e.status == 404: + logger.debug(f"ConfigMap slack-thread-{pipelineRunName} not found in namespace {namespace}") + else: + logger.error(f"Failed to retrieve ConfigMap: {e}") + return None + except Exception as e: + logger.error(f"Failed to retrieve ConfigMap: {e}") + return None + + def deleteThreadConfigMap(cls, namespace: str, pipelineRunName: str) -> bool: + """ + Delete the ConfigMap containing Slack thread information. + + Parameters: + namespace (str): Kubernetes namespace containing the ConfigMap + pipelineRunName (str): Unique identifier for the pipeline run + + Returns: + bool: True if ConfigMap was deleted successfully, False otherwise + """ + try: + from kubernetes import client, config + + # Load Kubernetes configuration + try: + config.load_incluster_config() + except: + config.load_kube_config() + + v1 = client.CoreV1Api() + configmap_name = f"slack-thread-{pipelineRunName}" + + v1.delete_namespaced_config_map(name=configmap_name, namespace=namespace) + logger.info(f"Deleted ConfigMap {configmap_name} from namespace {namespace}") + return True + + except client.exceptions.ApiException as e: + if e.status == 404: + logger.warning(f"ConfigMap slack-thread-{pipelineRunName} not found in namespace {namespace}") + else: + logger.error(f"Failed to delete ConfigMap: {e}") + return False + except Exception as e: + logger.error(f"Failed to delete ConfigMap: {e}") + return False + return {"type": "divider"} From 917a9c49801b5219faf784839e3fcf639bf1933a Mon Sep 17 00:00:00 2001 From: Anil Prajapati Date: Wed, 28 Jan 2026 23:32:26 +0530 Subject: [PATCH 15/45] [patch] remove extra new lines --- bin/mas-devops-notify-slack | 28 ++-------------------------- 1 file changed, 2 insertions(+), 26 deletions(-) diff --git a/bin/mas-devops-notify-slack b/bin/mas-devops-notify-slack index a11d700a..0ada9683 100755 --- a/bin/mas-devops-notify-slack +++ b/bin/mas-devops-notify-slack @@ -101,30 +101,23 @@ def notifyAnsibleComplete(channels: list[str], rc: int, taskName: str, pipelineN """Send Slack notification about Ansible task completion status.""" namespace = os.getenv("PIPELINE_NAMESPACE", "") pipelineRunName = os.getenv("PIPELINERUN_NAME", "") - if namespace == "" or pipelineRunName == "": print("PIPELINE_NAMESPACE and PIPELINERUN_NAME env vars must be set") sys.exit(1) - # Check if this is the first task (no ConfigMap exists yet) threadInfo = SlackUtil.getThreadConfigMap(namespace, pipelineRunName) - if threadInfo is None: # This is the first task - send pipeline started message toolchainLink = _getToolchainLink() instanceInfo = f"\nInstance ID: `{instanceId}`" if instanceId else "" - message = [ SlackUtil.buildHeader(f"🚀 MAS {pipelineName.title()} Pipeline Started"), SlackUtil.buildSection(f"Pipeline Run: `{pipelineRunName}`{instanceInfo}\n{toolchainLink}") ] - response = SlackUtil.postMessageBlocks(channels[0], message) - if response.data.get("ok", False): threadId = response["ts"] channelId = response["channel"] - # Store thread information in ConfigMap SlackUtil.createThreadConfigMap(namespace, pipelineRunName, channelId, threadId, pipelineName) threadInfo = { @@ -135,27 +128,21 @@ def notifyAnsibleComplete(channels: list[str], rc: int, taskName: str, pipelineN else: print("Failed to send initial Slack message") return False - # Send task completion message as thread reply threadId = threadInfo.get("threadId") channelId = threadInfo.get("channelId") - if rc == 0: emoji = "✅" status = "Success" else: emoji = "❌" status = "Failed" - taskMessage = [ SlackUtil.buildSection(f"{emoji} **{taskName}** - {status}") ] - if rc != 0: taskMessage.append(SlackUtil.buildSection(f"Return Code: `{rc}`\nCheck logs for details")) - response = SlackUtil.postMessageBlocks(channelId, taskMessage, threadId) - if isinstance(response, list): return all([res.data.get("ok", False) for res in response]) return response.data.get("ok", False) @@ -165,22 +152,17 @@ def notifyPipelineComplete(channels: list[str], rc: int, pipelineName: str, inst """Send Slack notification about pipeline completion and cleanup ConfigMap.""" namespace = os.getenv("PIPELINE_NAMESPACE", "") pipelineRunName = os.getenv("PIPELINERUN_NAME", "") - if namespace == "" or pipelineRunName == "": print("PIPELINE_NAMESPACE and PIPELINERUN_NAME env vars must be set") sys.exit(1) - # Get thread information threadInfo = SlackUtil.getThreadConfigMap(namespace, pipelineRunName) - if threadInfo is None: print("No thread information found - pipeline may not have started properly") return False - threadId = threadInfo.get("threadId") channelId = threadInfo.get("channelId") startTime = threadInfo.get("startTime") - # Calculate duration if start time is available durationText = "" if startTime: @@ -196,10 +178,8 @@ def notifyPipelineComplete(channels: list[str], rc: int, pipelineName: str, inst else: durationText = f"\nTotal Duration: {minutes}m {seconds}s" except: - pass - + pass instanceInfo = f"\nInstance ID: `{instanceId}`" if instanceId else "" - if rc == 0: emoji = "🎉" status = "Completed Successfully" @@ -208,17 +188,13 @@ def notifyPipelineComplete(channels: list[str], rc: int, pipelineName: str, inst emoji = "💥" status = "Failed" additionalInfo = f"\nPipeline failed with return code: `{rc}`" - message = [ SlackUtil.buildHeader(f"{emoji} MAS {pipelineName.title()} Pipeline {status}"), SlackUtil.buildSection(f"Pipeline Run: `{pipelineRunName}`{instanceInfo}{durationText}{additionalInfo}") - ] - + ] response = SlackUtil.postMessageBlocks(channelId, message, threadId) - # Clean up ConfigMap SlackUtil.deleteThreadConfigMap(namespace, pipelineRunName) - if isinstance(response, list): return all([res.data.get("ok", False) for res in response]) return response.data.get("ok", False) From 84328e34ac58d5685fa76e8c4fe098d6262f0ac7 Mon Sep 17 00:00:00 2001 From: Anil Prajapati Date: Wed, 28 Jan 2026 23:33:21 +0530 Subject: [PATCH 16/45] [patch] remove extra newlines --- src/mas/devops/slack.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/mas/devops/slack.py b/src/mas/devops/slack.py index f4e7ed68..a046786c 100644 --- a/src/mas/devops/slack.py +++ b/src/mas/devops/slack.py @@ -293,9 +293,7 @@ def createThreadConfigMap(cls, namespace: str, pipelineRunName: str, channelId: config.load_incluster_config() except: config.load_kube_config() - - v1 = client.CoreV1Api() - + v1 = client.CoreV1Api() configmap_name = f"slack-thread-{pipelineRunName}" configmap = client.V1ConfigMap( metadata=client.V1ObjectMeta( @@ -309,11 +307,9 @@ def createThreadConfigMap(cls, namespace: str, pipelineRunName: str, channelId: "startTime": datetime.utcnow().isoformat() + "Z" } ) - v1.create_namespaced_config_map(namespace=namespace, body=configmap) logger.info(f"Created ConfigMap {configmap_name} in namespace {namespace}") - return True - + return True except Exception as e: logger.error(f"Failed to create ConfigMap: {e}") return False @@ -331,20 +327,16 @@ def getThreadConfigMap(cls, namespace: str, pipelineRunName: str) -> dict | None """ try: from kubernetes import client, config - # Load Kubernetes configuration try: config.load_incluster_config() except: config.load_kube_config() - v1 = client.CoreV1Api() configmap_name = f"slack-thread-{pipelineRunName}" - configmap = v1.read_namespaced_config_map(name=configmap_name, namespace=namespace) logger.debug(f"Retrieved ConfigMap {configmap_name} from namespace {namespace}") return configmap.data - except client.exceptions.ApiException as e: if e.status == 404: logger.debug(f"ConfigMap slack-thread-{pipelineRunName} not found in namespace {namespace}") From 70ab05d0b9b2275f49cc61ad21d6590e48851be4 Mon Sep 17 00:00:00 2001 From: Anil Prajapati Date: Wed, 28 Jan 2026 23:36:54 +0530 Subject: [PATCH 17/45] [patch] remove extra newlines --- src/mas/devops/slack.py | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/mas/devops/slack.py b/src/mas/devops/slack.py index a046786c..4441a234 100644 --- a/src/mas/devops/slack.py +++ b/src/mas/devops/slack.py @@ -13,7 +13,8 @@ import os from slack_sdk import WebClient from slack_sdk.web.slack_response import SlackResponse - +from kubernetes import client, config +from datetime import datetime import logging logger = logging.getLogger(__name__) @@ -285,9 +286,6 @@ def createThreadConfigMap(cls, namespace: str, pipelineRunName: str, channelId: bool: True if ConfigMap was created successfully, False otherwise """ try: - from kubernetes import client, config - from datetime import datetime - # Load Kubernetes configuration try: config.load_incluster_config() @@ -326,7 +324,6 @@ def getThreadConfigMap(cls, namespace: str, pipelineRunName: str) -> dict | None dict | None: Dictionary containing threadId, channelId, pipelineName, and startTime, or None if not found """ try: - from kubernetes import client, config # Load Kubernetes configuration try: config.load_incluster_config() @@ -358,9 +355,7 @@ def deleteThreadConfigMap(cls, namespace: str, pipelineRunName: str) -> bool: Returns: bool: True if ConfigMap was deleted successfully, False otherwise """ - try: - from kubernetes import client, config - + try: # Load Kubernetes configuration try: config.load_incluster_config() @@ -369,11 +364,9 @@ def deleteThreadConfigMap(cls, namespace: str, pipelineRunName: str) -> bool: v1 = client.CoreV1Api() configmap_name = f"slack-thread-{pipelineRunName}" - v1.delete_namespaced_config_map(name=configmap_name, namespace=namespace) logger.info(f"Deleted ConfigMap {configmap_name} from namespace {namespace}") return True - except client.exceptions.ApiException as e: if e.status == 404: logger.warning(f"ConfigMap slack-thread-{pipelineRunName} not found in namespace {namespace}") @@ -383,7 +376,6 @@ def deleteThreadConfigMap(cls, namespace: str, pipelineRunName: str) -> bool: except Exception as e: logger.error(f"Failed to delete ConfigMap: {e}") return False - return {"type": "divider"} From 2537f04647e5ab0d929eb8852e14e64635ec6b38 Mon Sep 17 00:00:00 2001 From: Anil Prajapati Date: Wed, 28 Jan 2026 23:40:27 +0530 Subject: [PATCH 18/45] [patch] add Exception --- bin/mas-devops-notify-slack | 4 ++-- src/mas/devops/slack.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bin/mas-devops-notify-slack b/bin/mas-devops-notify-slack index 0ada9683..b15ab97c 100755 --- a/bin/mas-devops-notify-slack +++ b/bin/mas-devops-notify-slack @@ -177,8 +177,8 @@ def notifyPipelineComplete(channels: list[str], rc: int, pipelineName: str, inst durationText = f"\nTotal Duration: {hours}h {minutes}m {seconds}s" else: durationText = f"\nTotal Duration: {minutes}m {seconds}s" - except: - pass + except Exception: + pass instanceInfo = f"\nInstance ID: `{instanceId}`" if instanceId else "" if rc == 0: emoji = "🎉" diff --git a/src/mas/devops/slack.py b/src/mas/devops/slack.py index 4441a234..eebe533a 100644 --- a/src/mas/devops/slack.py +++ b/src/mas/devops/slack.py @@ -289,7 +289,7 @@ def createThreadConfigMap(cls, namespace: str, pipelineRunName: str, channelId: # Load Kubernetes configuration try: config.load_incluster_config() - except: + except Exception: config.load_kube_config() v1 = client.CoreV1Api() configmap_name = f"slack-thread-{pipelineRunName}" @@ -327,7 +327,7 @@ def getThreadConfigMap(cls, namespace: str, pipelineRunName: str) -> dict | None # Load Kubernetes configuration try: config.load_incluster_config() - except: + except Exception: config.load_kube_config() v1 = client.CoreV1Api() configmap_name = f"slack-thread-{pipelineRunName}" @@ -359,7 +359,7 @@ def deleteThreadConfigMap(cls, namespace: str, pipelineRunName: str) -> bool: # Load Kubernetes configuration try: config.load_incluster_config() - except: + except Exception: config.load_kube_config() v1 = client.CoreV1Api() From 58c7af8581372c068256d9b4ec5b1f61e5eea6a4 Mon Sep 17 00:00:00 2001 From: Anil Prajapati Date: Wed, 28 Jan 2026 23:43:58 +0530 Subject: [PATCH 19/45] [patch] remove extra blank spaces --- bin/mas-devops-notify-slack | 2 +- src/mas/devops/slack.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bin/mas-devops-notify-slack b/bin/mas-devops-notify-slack index b15ab97c..b82fb99d 100755 --- a/bin/mas-devops-notify-slack +++ b/bin/mas-devops-notify-slack @@ -191,7 +191,7 @@ def notifyPipelineComplete(channels: list[str], rc: int, pipelineName: str, inst message = [ SlackUtil.buildHeader(f"{emoji} MAS {pipelineName.title()} Pipeline {status}"), SlackUtil.buildSection(f"Pipeline Run: `{pipelineRunName}`{instanceInfo}{durationText}{additionalInfo}") - ] + ] response = SlackUtil.postMessageBlocks(channelId, message, threadId) # Clean up ConfigMap SlackUtil.deleteThreadConfigMap(namespace, pipelineRunName) diff --git a/src/mas/devops/slack.py b/src/mas/devops/slack.py index eebe533a..9ae670d5 100644 --- a/src/mas/devops/slack.py +++ b/src/mas/devops/slack.py @@ -291,7 +291,7 @@ def createThreadConfigMap(cls, namespace: str, pipelineRunName: str, channelId: config.load_incluster_config() except Exception: config.load_kube_config() - v1 = client.CoreV1Api() + v1 = client.CoreV1Api() configmap_name = f"slack-thread-{pipelineRunName}" configmap = client.V1ConfigMap( metadata=client.V1ObjectMeta( @@ -307,7 +307,7 @@ def createThreadConfigMap(cls, namespace: str, pipelineRunName: str, channelId: ) v1.create_namespaced_config_map(namespace=namespace, body=configmap) logger.info(f"Created ConfigMap {configmap_name} in namespace {namespace}") - return True + return True except Exception as e: logger.error(f"Failed to create ConfigMap: {e}") return False @@ -355,13 +355,13 @@ def deleteThreadConfigMap(cls, namespace: str, pipelineRunName: str) -> bool: Returns: bool: True if ConfigMap was deleted successfully, False otherwise """ - try: + try: # Load Kubernetes configuration try: config.load_incluster_config() except Exception: config.load_kube_config() - + v1 = client.CoreV1Api() configmap_name = f"slack-thread-{pipelineRunName}" v1.delete_namespaced_config_map(name=configmap_name, namespace=namespace) From 7b559fe0ae9af91e638b9ad56c88a8a9fb170da8 Mon Sep 17 00:00:00 2001 From: Anil Prajapati Date: Tue, 3 Feb 2026 18:42:13 +0530 Subject: [PATCH 20/45] [patch] add pipeline start end ansible start end slack notification message --- bin/mas-devops-notify-slack | 106 ++++++++++++++++++++++++++++++++++-- 1 file changed, 101 insertions(+), 5 deletions(-) diff --git a/bin/mas-devops-notify-slack b/bin/mas-devops-notify-slack index b82fb99d..fe5f4987 100755 --- a/bin/mas-devops-notify-slack +++ b/bin/mas-devops-notify-slack @@ -97,17 +97,108 @@ def notifyProvisionRoks(channels: list[str], rc: int, additionalMsg: str | None return response.data.get("ok", False) +def notifyPipelineStart(channels: list[str], pipelineName: str, instanceId: str | None = None) -> bool: + """Send Slack notification about pipeline start and create thread.""" + namespace = f"mas-{instanceId}-pipelines" + pipelineRunName = os.getenv("PIPELINERUN_NAME", "") + if instanceId is None or instanceId == "": + print("instanceId must be set") + sys.exit(1) + if namespace == "" or pipelineRunName == "": + print("PIPELINE_NAMESPACE and PIPELINERUN_NAME env vars must be set") + sys.exit(1) + + # Check if thread already exists + threadInfo = SlackUtil.getThreadConfigMap(namespace, pipelineRunName) + if threadInfo is not None: + print("Pipeline start notification already sent") + return True + + # Send pipeline started message + toolchainLink = _getToolchainLink() + instanceInfo = f"\nInstance ID: `{instanceId}`" if instanceId else "" + message = [ + SlackUtil.buildHeader(f"🚀 MAS {pipelineName.title()} Pipeline Started"), + SlackUtil.buildSection(f"Pipeline Run: `{pipelineRunName}`{instanceInfo}\n{toolchainLink}") + ] + response = SlackUtil.postMessageBlocks(channels[0], message) + if response.data.get("ok", False): + threadId = response["ts"] + channelId = response["channel"] + # Store thread information in ConfigMap + SlackUtil.createThreadConfigMap(namespace, pipelineRunName, channelId, threadId, pipelineName) + return True + else: + print("Failed to send pipeline start Slack message") + return False + + +def notifyAnsibleStart(channels: list[str], taskName: str, pipelineName: str, instanceId: str | None = None) -> bool: + """Send Slack notification about Ansible task start.""" + namespace = f"mas-{instanceId}-pipelines" + pipelineRunName = os.getenv("PIPELINERUN_NAME", "") + if instanceId is None or instanceId == "": + print("instanceId must be set") + sys.exit(1) + if namespace == "" or pipelineRunName == "": + print("PIPELINE_NAMESPACE and PIPELINERUN_NAME env vars must be set") + sys.exit(1) + + # Get thread information, create if doesn't exist + threadInfo = SlackUtil.getThreadConfigMap(namespace, pipelineRunName) + if threadInfo is None: + print("No thread found - creating pipeline start notification") + # Send pipeline started message + toolchainLink = _getToolchainLink() + instanceInfo = f"\nInstance ID: `{instanceId}`" if instanceId else "" + message = [ + SlackUtil.buildHeader(f"🚀 MAS {pipelineName.title()} Pipeline Started"), + SlackUtil.buildSection(f"Pipeline Run: `{pipelineRunName}`{instanceInfo}\n{toolchainLink}") + ] + response = SlackUtil.postMessageBlocks(channels[0], message) + if response.data.get("ok", False): + threadId = response["ts"] + channelId = response["channel"] + # Store thread information in ConfigMap + SlackUtil.createThreadConfigMap(namespace, pipelineRunName, channelId, threadId, pipelineName) + threadInfo = { + "threadId": threadId, + "channelId": channelId, + "pipelineName": pipelineName + } + else: + print("Failed to send pipeline start Slack message") + return False + + threadId = threadInfo.get("threadId") + channelId = threadInfo.get("channelId") + + # Send task start message as thread reply + taskMessage = [ + SlackUtil.buildSection(f"⏳ **{taskName}** - Started") + ] + response = SlackUtil.postMessageBlocks(channelId, taskMessage, threadId) + if isinstance(response, list): + return all([res.data.get("ok", False) for res in response]) + return response.data.get("ok", False) + + def notifyAnsibleComplete(channels: list[str], rc: int, taskName: str, pipelineName: str, instanceId: str | None = None) -> bool: """Send Slack notification about Ansible task completion status.""" - namespace = os.getenv("PIPELINE_NAMESPACE", "") + namespace = f"mas-{instanceId}-pipelines" pipelineRunName = os.getenv("PIPELINERUN_NAME", "") + if instanceId is None or instanceId == "": + print("instanceId must be set") + sys.exit(1) if namespace == "" or pipelineRunName == "": print("PIPELINE_NAMESPACE and PIPELINERUN_NAME env vars must be set") sys.exit(1) - # Check if this is the first task (no ConfigMap exists yet) + + # Get thread information, create if doesn't exist threadInfo = SlackUtil.getThreadConfigMap(namespace, pipelineRunName) if threadInfo is None: - # This is the first task - send pipeline started message + print("No thread found - creating pipeline start notification") + # Send pipeline started message toolchainLink = _getToolchainLink() instanceInfo = f"\nInstance ID: `{instanceId}`" if instanceId else "" message = [ @@ -126,8 +217,9 @@ def notifyAnsibleComplete(channels: list[str], rc: int, taskName: str, pipelineN "pipelineName": pipelineName } else: - print("Failed to send initial Slack message") + print("Failed to send pipeline start Slack message") return False + # Send task completion message as thread reply threadId = threadInfo.get("threadId") channelId = threadInfo.get("channelId") @@ -150,7 +242,7 @@ def notifyAnsibleComplete(channels: list[str], rc: int, taskName: str, pipelineN def notifyPipelineComplete(channels: list[str], rc: int, pipelineName: str, instanceId: str | None = None) -> bool: """Send Slack notification about pipeline completion and cleanup ConfigMap.""" - namespace = os.getenv("PIPELINE_NAMESPACE", "") + namespace = f"mas-{instanceId}-pipelines" pipelineRunName = os.getenv("PIPELINERUN_NAME", "") if namespace == "" or pipelineRunName == "": print("PIPELINE_NAMESPACE and PIPELINERUN_NAME env vars must be set") @@ -227,6 +319,10 @@ if __name__ == "__main__": notifyProvisionFyre(channelList, args.rc, args.msg) elif args.action == "ocp-provision-roks": notifyProvisionRoks(channelList, args.rc, args.msg) + elif args.action == "pipeline-start": + notifyPipelineStart(channelList, args.pipeline_name, args.instance_id) + elif args.action == "ansible-start": + notifyAnsibleStart(channelList, args.task_name, args.pipeline_name, args.instance_id) elif args.action == "ansible-complete": notifyAnsibleComplete(channelList, args.rc, args.task_name, args.pipeline_name, args.instance_id) elif args.action == "pipeline-complete": From c88cf12ae8b6d378fca988dc4b4d96d28a93a458 Mon Sep 17 00:00:00 2001 From: Parveen Kumar Date: Mon, 9 Feb 2026 13:14:46 +0530 Subject: [PATCH 21/45] [minor] Support February Catalog Update --- .../devops/data/catalogs/v9-260226-amd64.yaml | 170 ++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 src/mas/devops/data/catalogs/v9-260226-amd64.yaml diff --git a/src/mas/devops/data/catalogs/v9-260226-amd64.yaml b/src/mas/devops/data/catalogs/v9-260226-amd64.yaml new file mode 100644 index 00000000..9a962a25 --- /dev/null +++ b/src/mas/devops/data/catalogs/v9-260226-amd64.yaml @@ -0,0 +1,170 @@ +--- +# Case bundle configuration for IBM Maximo Operator Catalog 260226 (AMD64) +# ----------------------------------------------------------------------------- +# In the future this won't be necessary as we'll be able to mirror from the +# catalog itself, but not everything in the catalog supports this yet (including MAS) +# so we need to use the CASE bundle mirror process still. + +catalog_digest: tbc + +ocp_compatibility: +- 4.16 +- 4.17 +- 4.18 +- 4.19 + +# Dependencies +# ----------------------------------------------------------------------------- +ibm_licensing_version: 4.2.17 # Operator version 4.2.14 (https://github.com/IBM/cloud-pak/tree/master/repo/case/ibm-licensing) +common_svcs_version: 4.13.0 # Operator version 4.13.0 (https://github.com/IBM/cloud-pak/tree/master/repo/case/ibm-cp-common-services) +common_svcs_version_1: 4.11.0 # Additional version 4.11.0 + +cp4d_platform_version: 5.2.0+20250709.170324 # Operator version 5.2.0 (https://github.com/IBM/cloud-pak/tree/master/repo/case/ibm-cp-datacore/) +ibm_zen_version: 6.2.0+20250530.152516.232 # For CPD5 ibm-zen has to be explicitily mirrored + +db2u_version: 7.3.1+20250821.161005.16793 # Operator version 110509.0.7 to find the version 7.3.1+20250821.161005.16793, search db2u-operator digest on repo (https://github.com/IBM/cloud-pak/tree/master/repo/case/ibm-db2uoperator) +db2_channel_default: v110509.0 # Default Channel version for db2u-operator +events_version: 5.0.1 # Operator version 5.0.1 (https://github.com/IBM/cloud-pak/tree/master/repo/case/ibm-events-operator) +uds_version: 2.0.12 # Operator version 2.0.12 # sticking to 2.0.12 version # Please do Not Change +sls_version: 3.12.5 # Operator version 3.12.5 (https://github.ibm.com/maximoappsuite/ibm-sls/releases) +tsm_version: 1.7.2 # Operator version 1.7.2 (https://github.ibm.com/maximoappsuite/ibm-truststore-mgr/releases) +dd_version: 1.1.21 # Operator version 1.1.21 (https://github.ibm.com/maximoappsuite/ibm-data-dictionary/releases) +appconnect_version: 6.2.0 # Operator version 6.2.0 # sticking to 6.2.0 version # Please do Not Change +wsl_version: 11.0.0+20250521.202913.73 # used for wsl and wsl_runtimes unless wsl_runtimes_version also specified +wsl_runtimes_version: 11.0.0+20250515.090949.21 # cpd 5.1.3 uses version 10.3.0 of wsl runtimes but only 10.2.0 for wsl itself +wml_version: 11.0.0+20250530.193146.282 # Operator version 5.2.0 +postgress_version: 5.16.0+20250827.110911.2626 # ibm-cpd-cloud-native-postgresql-operator 5.2.0 cp4d + +ccs_build: 11.0.0+20250605.130237.468 # cpd 5.2.0 using ccs build +# datarefinery_build: +20240517.202103.146 + +spark_version: 11.0.0+20250604.163055.2097 # Operator version 5.2.0 +cognos_version: 28.0.0+20250515.175459.10054 # Operator version 25.0.0 +couchdb_version: 1.0.13 # Operator version 2.2.1 (1.0.13) sticking with 1.0.13 # (This is required for Assist 9.0, https://github.com/IBM/cloud-pak/blob/master/repo/case/ibm-couchdb/index.yaml) +elasticsearch_version: 1.1.2667 # Operator version 1.1.2667 # used in cpd 5.1.3 only +opensearch_version: 1.1.2494 # Operator version 1.1.2494 + +# Maximo Application Suite +# ----------------------------------------------------------------------------- +mas_core_version: + 9.2.x-feature: 9.2.0-pre.stable_9887 # Updated + 9.1.x: 9.1.8 # Updated + 9.0.x: 9.0.19 # Updated + 8.10.x: 8.10.33 # Updated + 8.11.x: 8.11.30 # Updated +mas_assist_version: + 9.1.x: 9.1.7 # Updated + 9.0.x: 9.0.13 # Updated + 8.10.x: 8.7.8 # No Update + 8.11.x: 8.8.7 # No Update +mas_hputilities_version: + 9.1.x: "" # Not Supported + 9.0.x: "" # Not Supported + 8.10.x: 8.6.7 # No Update + 8.11.x: "" # Not Supported +mas_iot_version: + 9.1.x: 9.1.7 # Updated + 9.0.x: 9.0.16 # Updated + 8.10.x: 8.7.30 # Updated + 8.11.x: 8.8.26 # Updated +mas_manage_version: + 9.2.x-feature: 9.2.0-pre.stable_10282 # Updated + 9.1.x: 9.1.8 # Updated + 9.0.x: 9.0.21 # Updated + 8.10.x: 8.6.34 # Updated + 8.11.x: 8.7.28 # Updated +mas_monitor_version: + 9.1.x: 9.1.7 # Updated + 9.0.x: 9.0.17 # Updated + 8.10.x: 8.10.27 # Updated + 8.11.x: 8.11.25 # Updated +mas_optimizer_version: + 9.2.x-feature: 9.2.0-pre.stable_9869 # Updated + 9.1.x: 9.1.8 # Updated + 9.0.x: 9.0.19 # Updated + 8.10.x: 8.4.26 # Updated + 8.11.x: 8.5.25 # Updated +mas_predict_version: + 9.1.x: 9.1.4 # Need to update + 9.0.x: 9.0.11 # Need to update + 8.10.x: 8.8.12 # Need to update + 8.11.x: 8.9.14 # Need to update +mas_visualinspection_version: + 9.2.x-feature: 9.2.0-pre.stable_6198 # Need to update + 9.1.x: 9.1.7 # Updated + 9.0.x: 9.0.16 # Updated + 8.10.x: 8.8.4 # No Update + 8.11.x: 8.9.19 # Updated +mas_facilities_version: + 9.1.x: 9.1.7 # Updated + 9.0.x: "" # Not Supported + 8.10.x: "" # Not Supported + 8.11.x: "" # Not Supported + + +# Maximo AI Service +# ------------------------------------------------------------------------------ +aiservice_version: + 9.2.x-feature: 9.2.0-pre.stable_9768 # Updated + 9.1.x: 9.1.11 # Updated + + +# Extra Images for UDS +# ------------------------------------------------------------------------------ +uds_extras_version: 1.5.0 + +# Extra Images for Mongo +# ------------------------------------------------------------------------------ +mongo_extras_version_default: 8.0.17 + +# Variables used to mirror additional mongo image versions +mongo_extras_version_4: 4.4.21 +mongo_extras_version_5: 5.0.23 +mongo_extras_version_6: 6.0.12 +mongo_extras_version_7: 7.0.23 +mongo_extras_version_8: 8.0.17 + +# Extra Images for Db2u +# ------------------------------------------------------------------------------ +db2u_extras_version: 1.0.6 # No Update +db2u_filter: db2 + +# Extra Images for CCS used for PCD 5.2.0 Hotfix +# ------------------------------------------------------------------------------ +ccs_extras_version: 11.0.0 + +# Extra Images for IBM Watson Discovery +# ------------------------------------------------------------------------------ +#wd_extras_version: 1.0.4 + +# Extra Images for Amlen +# ------------------------------------------------------------------------------ +amlen_extras_version: 1.1.3 + +# Default Cloud Pak for Data version +# ------------------------------------------------------------------------------ +cpd_product_version_default: 5.2.0 + +manage_extras_913: 9.1.3 +minio_version: RELEASE.2025-06-13T11-33-47Z + +editorial: + whats_new: + - title: '**Security updates and bug fixes**' + details: + - IBM Maximo Application Suite Core Platform v8.10, v8.11, v9.0 and v9.1 + - IBM Maximo Manage v8.6, v8.7, v9.0 and v9.1 + - IBM Maximo IoT v8.7, v8.8, v9.0 and v9.1 + - IBM Maximo Monitor v8.10, v8.11, v9.0 and v9.1 + - IBM Maximo Optimizer v8.4, 8.5 and v9.1 + - IBM Maximo Assist v9.1 and v9.0 + - IBM Maximo Predict v8.8, v8.9, v9.0 and v9.1 + - IBM Maximo Visual Inspection v8.9, v9.0 and v9.1 + - IBM Maximo Real Estate and Facilities v9.1 + - IBM Maximo AI Service v9.1 + - IBM Maximo Location Service for Esri v9.0 and v9.1 + - IBM Suite License Service v3.12 + - IBM Data Dictionary v1.1 + known_issues: + - title: Customers using **Maximo Assist v8.7 or v8.8** should not update and must instead contact IBM Support for guidance regarding the removal of IBM Watson Discovery and upgrading to Maximo Assist v9.0 + - title: A known issue exists in the January 29, 2026 release affecting HSE and Oil & Gas (9.0.23 / 9.1.64). Customers with HSE installed should avoid upgrading to the January release. Installation of HSE or Oil & Gas on Manage 9.0.x / 9.1.x should be deferred until the February 2026 patch. \ No newline at end of file From 68e3d160528778cc8443444284905f238d348f2a Mon Sep 17 00:00:00 2001 From: Anil Prajapati Date: Tue, 10 Feb 2026 10:18:51 +0530 Subject: [PATCH 22/45] [patch] remove pipeline name from the messages --- bin/mas-devops-notify-slack | 112 +++++++++--------------------------- src/mas/devops/slack.py | 27 +++++---- 2 files changed, 41 insertions(+), 98 deletions(-) diff --git a/bin/mas-devops-notify-slack b/bin/mas-devops-notify-slack index fe5f4987..61e48c70 100755 --- a/bin/mas-devops-notify-slack +++ b/bin/mas-devops-notify-slack @@ -97,82 +97,53 @@ def notifyProvisionRoks(channels: list[str], rc: int, additionalMsg: str | None return response.data.get("ok", False) -def notifyPipelineStart(channels: list[str], pipelineName: str, instanceId: str | None = None) -> bool: +def notifyPipelineStart(channels: list[str], instanceId: str | None = None) -> dict | None: """Send Slack notification about pipeline start and create thread.""" namespace = f"mas-{instanceId}-pipelines" - pipelineRunName = os.getenv("PIPELINERUN_NAME", "") if instanceId is None or instanceId == "": print("instanceId must be set") sys.exit(1) - if namespace == "" or pipelineRunName == "": - print("PIPELINE_NAMESPACE and PIPELINERUN_NAME env vars must be set") - sys.exit(1) - + # Check if thread already exists - threadInfo = SlackUtil.getThreadConfigMap(namespace, pipelineRunName) + threadInfo = SlackUtil.getThreadConfigMap(namespace, instanceId) if threadInfo is not None: print("Pipeline start notification already sent") - return True - + return threadInfo + # Send pipeline started message toolchainLink = _getToolchainLink() instanceInfo = f"\nInstance ID: `{instanceId}`" if instanceId else "" message = [ - SlackUtil.buildHeader(f"🚀 MAS {pipelineName.title()} Pipeline Started"), - SlackUtil.buildSection(f"Pipeline Run: `{pipelineRunName}`{instanceInfo}\n{toolchainLink}") + SlackUtil.buildHeader("🚀 MAS Pipeline Started"), + SlackUtil.buildSection(f"Pipeline Run: {instanceInfo}\n{toolchainLink}") ] response = SlackUtil.postMessageBlocks(channels[0], message) if response.data.get("ok", False): threadId = response["ts"] channelId = response["channel"] # Store thread information in ConfigMap - SlackUtil.createThreadConfigMap(namespace, pipelineRunName, channelId, threadId, pipelineName) + SlackUtil.createThreadConfigMap(namespace, channelId, threadId, instanceId) return True else: print("Failed to send pipeline start Slack message") return False -def notifyAnsibleStart(channels: list[str], taskName: str, pipelineName: str, instanceId: str | None = None) -> bool: +def notifyAnsibleStart(channels: list[str], taskName: str, instanceId: str | None = None) -> bool: """Send Slack notification about Ansible task start.""" namespace = f"mas-{instanceId}-pipelines" - pipelineRunName = os.getenv("PIPELINERUN_NAME", "") if instanceId is None or instanceId == "": print("instanceId must be set") sys.exit(1) - if namespace == "" or pipelineRunName == "": - print("PIPELINE_NAMESPACE and PIPELINERUN_NAME env vars must be set") - sys.exit(1) - + # Get thread information, create if doesn't exist - threadInfo = SlackUtil.getThreadConfigMap(namespace, pipelineRunName) + threadInfo = SlackUtil.getThreadConfigMap(namespace, instanceId) if threadInfo is None: print("No thread found - creating pipeline start notification") - # Send pipeline started message - toolchainLink = _getToolchainLink() - instanceInfo = f"\nInstance ID: `{instanceId}`" if instanceId else "" - message = [ - SlackUtil.buildHeader(f"🚀 MAS {pipelineName.title()} Pipeline Started"), - SlackUtil.buildSection(f"Pipeline Run: `{pipelineRunName}`{instanceInfo}\n{toolchainLink}") - ] - response = SlackUtil.postMessageBlocks(channels[0], message) - if response.data.get("ok", False): - threadId = response["ts"] - channelId = response["channel"] - # Store thread information in ConfigMap - SlackUtil.createThreadConfigMap(namespace, pipelineRunName, channelId, threadId, pipelineName) - threadInfo = { - "threadId": threadId, - "channelId": channelId, - "pipelineName": pipelineName - } - else: - print("Failed to send pipeline start Slack message") - return False - + notifyPipelineStart(channels, instanceId) threadId = threadInfo.get("threadId") channelId = threadInfo.get("channelId") - + # Send task start message as thread reply taskMessage = [ SlackUtil.buildSection(f"⏳ **{taskName}** - Started") @@ -183,43 +154,18 @@ def notifyAnsibleStart(channels: list[str], taskName: str, pipelineName: str, in return response.data.get("ok", False) -def notifyAnsibleComplete(channels: list[str], rc: int, taskName: str, pipelineName: str, instanceId: str | None = None) -> bool: +def notifyAnsibleComplete(channels: list[str], rc: int, taskName: str, instanceId: str | None = None) -> bool: """Send Slack notification about Ansible task completion status.""" namespace = f"mas-{instanceId}-pipelines" - pipelineRunName = os.getenv("PIPELINERUN_NAME", "") if instanceId is None or instanceId == "": print("instanceId must be set") sys.exit(1) - if namespace == "" or pipelineRunName == "": - print("PIPELINE_NAMESPACE and PIPELINERUN_NAME env vars must be set") - sys.exit(1) - + # Get thread information, create if doesn't exist - threadInfo = SlackUtil.getThreadConfigMap(namespace, pipelineRunName) + threadInfo = SlackUtil.getThreadConfigMap(namespace, instanceId) if threadInfo is None: print("No thread found - creating pipeline start notification") - # Send pipeline started message - toolchainLink = _getToolchainLink() - instanceInfo = f"\nInstance ID: `{instanceId}`" if instanceId else "" - message = [ - SlackUtil.buildHeader(f"🚀 MAS {pipelineName.title()} Pipeline Started"), - SlackUtil.buildSection(f"Pipeline Run: `{pipelineRunName}`{instanceInfo}\n{toolchainLink}") - ] - response = SlackUtil.postMessageBlocks(channels[0], message) - if response.data.get("ok", False): - threadId = response["ts"] - channelId = response["channel"] - # Store thread information in ConfigMap - SlackUtil.createThreadConfigMap(namespace, pipelineRunName, channelId, threadId, pipelineName) - threadInfo = { - "threadId": threadId, - "channelId": channelId, - "pipelineName": pipelineName - } - else: - print("Failed to send pipeline start Slack message") - return False - + notifyPipelineStart(channels, instanceId) # Send task completion message as thread reply threadId = threadInfo.get("threadId") channelId = threadInfo.get("channelId") @@ -240,15 +186,14 @@ def notifyAnsibleComplete(channels: list[str], rc: int, taskName: str, pipelineN return response.data.get("ok", False) -def notifyPipelineComplete(channels: list[str], rc: int, pipelineName: str, instanceId: str | None = None) -> bool: +def notifyPipelineComplete(channels: list[str], rc: int, instanceId: str | None = None) -> bool: """Send Slack notification about pipeline completion and cleanup ConfigMap.""" namespace = f"mas-{instanceId}-pipelines" - pipelineRunName = os.getenv("PIPELINERUN_NAME", "") - if namespace == "" or pipelineRunName == "": - print("PIPELINE_NAMESPACE and PIPELINERUN_NAME env vars must be set") + if instanceId is None or instanceId == "": + print("instanceId must be set") sys.exit(1) # Get thread information - threadInfo = SlackUtil.getThreadConfigMap(namespace, pipelineRunName) + threadInfo = SlackUtil.getThreadConfigMap(namespace, instanceId) if threadInfo is None: print("No thread information found - pipeline may not have started properly") return False @@ -281,12 +226,12 @@ def notifyPipelineComplete(channels: list[str], rc: int, pipelineName: str, inst status = "Failed" additionalInfo = f"\nPipeline failed with return code: `{rc}`" message = [ - SlackUtil.buildHeader(f"{emoji} MAS {pipelineName.title()} Pipeline {status}"), - SlackUtil.buildSection(f"Pipeline Run: `{pipelineRunName}`{instanceInfo}{durationText}{additionalInfo}") + SlackUtil.buildHeader(f"{emoji} MAS Pipeline {status}"), + SlackUtil.buildSection(f"Pipeline Run: {instanceInfo}{durationText}{additionalInfo}") ] response = SlackUtil.postMessageBlocks(channelId, message, threadId) # Clean up ConfigMap - SlackUtil.deleteThreadConfigMap(namespace, pipelineRunName) + SlackUtil.deleteThreadConfigMap(namespace, instanceId) if isinstance(response, list): return all([res.data.get("ok", False) for res in response]) return response.data.get("ok", False) @@ -310,7 +255,6 @@ if __name__ == "__main__": parser.add_argument("--rc", required=True, type=int) parser.add_argument("--msg", required=False, default=None) parser.add_argument("--task-name", required=False, default="") - parser.add_argument("--pipeline-name", required=False, default="") parser.add_argument("--instance-id", required=False, default=None) args, unknown = parser.parse_known_args() @@ -320,10 +264,10 @@ if __name__ == "__main__": elif args.action == "ocp-provision-roks": notifyProvisionRoks(channelList, args.rc, args.msg) elif args.action == "pipeline-start": - notifyPipelineStart(channelList, args.pipeline_name, args.instance_id) + notifyPipelineStart(channelList, args.instance_id) elif args.action == "ansible-start": - notifyAnsibleStart(channelList, args.task_name, args.pipeline_name, args.instance_id) + notifyAnsibleStart(channelList, args.task_name, args.instance_id) elif args.action == "ansible-complete": - notifyAnsibleComplete(channelList, args.rc, args.task_name, args.pipeline_name, args.instance_id) + notifyAnsibleComplete(channelList, args.rc, args.task_name, args.instance_id) elif args.action == "pipeline-complete": - notifyPipelineComplete(channelList, args.rc, args.pipeline_name, args.instance_id) + notifyPipelineComplete(channelList, args.rc, args.instance_id) diff --git a/src/mas/devops/slack.py b/src/mas/devops/slack.py index 9ae670d5..21357868 100644 --- a/src/mas/devops/slack.py +++ b/src/mas/devops/slack.py @@ -14,7 +14,7 @@ from slack_sdk import WebClient from slack_sdk.web.slack_response import SlackResponse from kubernetes import client, config -from datetime import datetime +from datetime import datetime, timezone import logging logger = logging.getLogger(__name__) @@ -271,16 +271,15 @@ def buildDivider(cls) -> dict: Returns: dict: Slack block kit divider element """ - def createThreadConfigMap(cls, namespace: str, pipelineRunName: str, channelId: str, threadId: str, pipelineName: str) -> bool: + def createThreadConfigMap(cls, namespace: str, channelId: str, threadId: str, instanceId: str) -> bool: """ Create a ConfigMap to store Slack thread information for a pipeline run. Parameters: namespace (str): Kubernetes namespace for the ConfigMap - pipelineRunName (str): Unique identifier for the pipeline run channelId (str): Slack channel ID where the thread was created threadId (str): Slack thread timestamp - pipelineName (str): Name of the pipeline (install/update/upgrade/uninstall) + instanceId (str): Name of the Mas Instance ID Returns: bool: True if ConfigMap was created successfully, False otherwise @@ -292,7 +291,7 @@ def createThreadConfigMap(cls, namespace: str, pipelineRunName: str, channelId: except Exception: config.load_kube_config() v1 = client.CoreV1Api() - configmap_name = f"slack-thread-{pipelineRunName}" + configmap_name = f"slack-thread-{instanceId}" configmap = client.V1ConfigMap( metadata=client.V1ObjectMeta( name=configmap_name, @@ -301,8 +300,8 @@ def createThreadConfigMap(cls, namespace: str, pipelineRunName: str, channelId: data={ "threadId": threadId, "channelId": channelId, - "pipelineName": pipelineName, - "startTime": datetime.utcnow().isoformat() + "Z" + "instanceId": instanceId, + "startTime": datetime.now(timezone.utc) } ) v1.create_namespaced_config_map(namespace=namespace, body=configmap) @@ -312,13 +311,13 @@ def createThreadConfigMap(cls, namespace: str, pipelineRunName: str, channelId: logger.error(f"Failed to create ConfigMap: {e}") return False - def getThreadConfigMap(cls, namespace: str, pipelineRunName: str) -> dict | None: + def getThreadConfigMap(cls, namespace: str, instanceId: str) -> dict | None: """ Retrieve Slack thread information from a ConfigMap. Parameters: namespace (str): Kubernetes namespace containing the ConfigMap - pipelineRunName (str): Unique identifier for the pipeline run + instanceId (str): Unique identifier for the pipeline run Returns: dict | None: Dictionary containing threadId, channelId, pipelineName, and startTime, or None if not found @@ -330,13 +329,13 @@ def getThreadConfigMap(cls, namespace: str, pipelineRunName: str) -> dict | None except Exception: config.load_kube_config() v1 = client.CoreV1Api() - configmap_name = f"slack-thread-{pipelineRunName}" + configmap_name = f"slack-thread-{instanceId}" configmap = v1.read_namespaced_config_map(name=configmap_name, namespace=namespace) logger.debug(f"Retrieved ConfigMap {configmap_name} from namespace {namespace}") return configmap.data except client.exceptions.ApiException as e: if e.status == 404: - logger.debug(f"ConfigMap slack-thread-{pipelineRunName} not found in namespace {namespace}") + logger.debug(f"ConfigMap slack-thread-{instanceId} not found in namespace {namespace}") else: logger.error(f"Failed to retrieve ConfigMap: {e}") return None @@ -344,7 +343,7 @@ def getThreadConfigMap(cls, namespace: str, pipelineRunName: str) -> dict | None logger.error(f"Failed to retrieve ConfigMap: {e}") return None - def deleteThreadConfigMap(cls, namespace: str, pipelineRunName: str) -> bool: + def deleteThreadConfigMap(cls, namespace: str, instanceId: str) -> bool: """ Delete the ConfigMap containing Slack thread information. @@ -363,13 +362,13 @@ def deleteThreadConfigMap(cls, namespace: str, pipelineRunName: str) -> bool: config.load_kube_config() v1 = client.CoreV1Api() - configmap_name = f"slack-thread-{pipelineRunName}" + configmap_name = f"slack-thread-{instanceId}" v1.delete_namespaced_config_map(name=configmap_name, namespace=namespace) logger.info(f"Deleted ConfigMap {configmap_name} from namespace {namespace}") return True except client.exceptions.ApiException as e: if e.status == 404: - logger.warning(f"ConfigMap slack-thread-{pipelineRunName} not found in namespace {namespace}") + logger.warning(f"ConfigMap slack-thread-{instanceId} not found in namespace {namespace}") else: logger.error(f"Failed to delete ConfigMap: {e}") return False From ba24702752b586c65b1c0af56fbdad746e59da0c Mon Sep 17 00:00:00 2001 From: shimto-jacob-siby Date: Tue, 10 Feb 2026 14:43:49 +0530 Subject: [PATCH 23/45] [patch] Adding OCP 4.20 (#187) --- src/mas/devops/data/catalogs/v9-260226-amd64.yaml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/mas/devops/data/catalogs/v9-260226-amd64.yaml b/src/mas/devops/data/catalogs/v9-260226-amd64.yaml index 9a962a25..6a063979 100644 --- a/src/mas/devops/data/catalogs/v9-260226-amd64.yaml +++ b/src/mas/devops/data/catalogs/v9-260226-amd64.yaml @@ -8,10 +8,11 @@ catalog_digest: tbc ocp_compatibility: -- 4.16 -- 4.17 -- 4.18 -- 4.19 +- "4.16" +- "4.17" +- "4.18" +- "4.19" +- "4.20" # Dependencies # ----------------------------------------------------------------------------- From a956b935de136a88133080e0047559797f808111 Mon Sep 17 00:00:00 2001 From: Parveen Kumar Date: Thu, 12 Feb 2026 09:39:42 +0530 Subject: [PATCH 24/45] [patch] update db2u, catalog digest --- .../devops/data/catalogs/v9-260226-amd64.yaml | 66 +++++++++---------- .../data/catalogs/v9-260226-ppc64le.yaml | 58 ++++++++++++++++ .../devops/data/catalogs/v9-260226-s390x.yaml | 58 ++++++++++++++++ 3 files changed, 149 insertions(+), 33 deletions(-) create mode 100644 src/mas/devops/data/catalogs/v9-260226-ppc64le.yaml create mode 100644 src/mas/devops/data/catalogs/v9-260226-s390x.yaml diff --git a/src/mas/devops/data/catalogs/v9-260226-amd64.yaml b/src/mas/devops/data/catalogs/v9-260226-amd64.yaml index 6a063979..ff40726e 100644 --- a/src/mas/devops/data/catalogs/v9-260226-amd64.yaml +++ b/src/mas/devops/data/catalogs/v9-260226-amd64.yaml @@ -5,7 +5,7 @@ # catalog itself, but not everything in the catalog supports this yet (including MAS) # so we need to use the CASE bundle mirror process still. -catalog_digest: tbc +catalog_digest: sha256:ee5cd2eb532a9b2f4336e0181daf32523cb744751fe782109b0350a9ff0c92cf ocp_compatibility: - "4.16" @@ -23,7 +23,7 @@ common_svcs_version_1: 4.11.0 # Additional version 4.11.0 cp4d_platform_version: 5.2.0+20250709.170324 # Operator version 5.2.0 (https://github.com/IBM/cloud-pak/tree/master/repo/case/ibm-cp-datacore/) ibm_zen_version: 6.2.0+20250530.152516.232 # For CPD5 ibm-zen has to be explicitily mirrored -db2u_version: 7.3.1+20250821.161005.16793 # Operator version 110509.0.7 to find the version 7.3.1+20250821.161005.16793, search db2u-operator digest on repo (https://github.com/IBM/cloud-pak/tree/master/repo/case/ibm-db2uoperator) +db2u_version: 7.5.1+20251217.121408.18568 # Operator version 110509.0.7 to find the version 7.5.1+20251217.121408.18568, search db2u-operator digest on repo (https://github.com/IBM/cloud-pak/tree/master/repo/case/ibm-db2uoperator) db2_channel_default: v110509.0 # Default Channel version for db2u-operator events_version: 5.0.1 # Operator version 5.0.1 (https://github.com/IBM/cloud-pak/tree/master/repo/case/ibm-events-operator) uds_version: 2.0.12 # Operator version 2.0.12 # sticking to 2.0.12 version # Please do Not Change @@ -48,14 +48,14 @@ opensearch_version: 1.1.2494 # Operator version 1.1.2494 # Maximo Application Suite # ----------------------------------------------------------------------------- mas_core_version: - 9.2.x-feature: 9.2.0-pre.stable_9887 # Updated - 9.1.x: 9.1.8 # Updated - 9.0.x: 9.0.19 # Updated - 8.10.x: 8.10.33 # Updated - 8.11.x: 8.11.30 # Updated + 9.2.x-feature: 9.2.0-pre.stable_9887 # Need to update + 9.1.x: 9.1.8 # Need to update + 9.0.x: 9.0.19 # Need to update + 8.10.x: 8.10.33 # Need to update + 8.11.x: 8.11.30 # Need to update mas_assist_version: - 9.1.x: 9.1.7 # Updated - 9.0.x: 9.0.13 # Updated + 9.1.x: 9.1.7 # Need to update + 9.0.x: 9.0.13 # Need to update 8.10.x: 8.7.8 # No Update 8.11.x: 8.8.7 # No Update mas_hputilities_version: @@ -64,27 +64,27 @@ mas_hputilities_version: 8.10.x: 8.6.7 # No Update 8.11.x: "" # Not Supported mas_iot_version: - 9.1.x: 9.1.7 # Updated - 9.0.x: 9.0.16 # Updated - 8.10.x: 8.7.30 # Updated - 8.11.x: 8.8.26 # Updated + 9.1.x: 9.1.7 # Need to update + 9.0.x: 9.0.16 # Need to update + 8.10.x: 8.7.30 # Need to update + 8.11.x: 8.8.26 # Need to update mas_manage_version: - 9.2.x-feature: 9.2.0-pre.stable_10282 # Updated - 9.1.x: 9.1.8 # Updated - 9.0.x: 9.0.21 # Updated - 8.10.x: 8.6.34 # Updated - 8.11.x: 8.7.28 # Updated + 9.2.x-feature: 9.2.0-pre.stable_10282 # Need to update + 9.1.x: 9.1.8 # Need to update + 9.0.x: 9.0.21 # Need to update + 8.10.x: 8.6.34 # Need to update + 8.11.x: 8.7.28 # Need to update mas_monitor_version: - 9.1.x: 9.1.7 # Updated - 9.0.x: 9.0.17 # Updated - 8.10.x: 8.10.27 # Updated - 8.11.x: 8.11.25 # Updated + 9.1.x: 9.1.7 # Need to update + 9.0.x: 9.0.17 # Need to update + 8.10.x: 8.10.27 # Need to update + 8.11.x: 8.11.25 # Need to update mas_optimizer_version: - 9.2.x-feature: 9.2.0-pre.stable_9869 # Updated - 9.1.x: 9.1.8 # Updated - 9.0.x: 9.0.19 # Updated - 8.10.x: 8.4.26 # Updated - 8.11.x: 8.5.25 # Updated + 9.2.x-feature: 9.2.0-pre.stable_9869 # Need to update + 9.1.x: 9.1.8 # Need to update + 9.0.x: 9.0.19 # Need to update + 8.10.x: 8.4.26 # Need to update + 8.11.x: 8.5.25 # Need to update mas_predict_version: 9.1.x: 9.1.4 # Need to update 9.0.x: 9.0.11 # Need to update @@ -92,12 +92,12 @@ mas_predict_version: 8.11.x: 8.9.14 # Need to update mas_visualinspection_version: 9.2.x-feature: 9.2.0-pre.stable_6198 # Need to update - 9.1.x: 9.1.7 # Updated - 9.0.x: 9.0.16 # Updated + 9.1.x: 9.1.7 # Need to update + 9.0.x: 9.0.16 # Need to update 8.10.x: 8.8.4 # No Update - 8.11.x: 8.9.19 # Updated + 8.11.x: 8.9.19 # Need to update mas_facilities_version: - 9.1.x: 9.1.7 # Updated + 9.1.x: 9.1.7 # Need to update 9.0.x: "" # Not Supported 8.10.x: "" # Not Supported 8.11.x: "" # Not Supported @@ -106,8 +106,8 @@ mas_facilities_version: # Maximo AI Service # ------------------------------------------------------------------------------ aiservice_version: - 9.2.x-feature: 9.2.0-pre.stable_9768 # Updated - 9.1.x: 9.1.11 # Updated + 9.2.x-feature: 9.2.0-pre.stable_9768 # Need to update + 9.1.x: 9.1.11 # Need to update # Extra Images for UDS diff --git a/src/mas/devops/data/catalogs/v9-260226-ppc64le.yaml b/src/mas/devops/data/catalogs/v9-260226-ppc64le.yaml new file mode 100644 index 00000000..eca4874e --- /dev/null +++ b/src/mas/devops/data/catalogs/v9-260226-ppc64le.yaml @@ -0,0 +1,58 @@ +--- +# Case bundle configuration for IBM Maximo Operator Catalog 260226 (PPC) +# ----------------------------------------------------------------------------- +# In the future this won't be necessary as we'll be able to mirror from the +# catalog itself, but not everything in the catalog supports this yet (including MAS) +# so we need to use the CASE bundle mirror process still. + +catalog_digest: sha256:5bbdd2381ab0090ce4862bafdec4c13477b711c58f57c31ffacb011f3b320ade + +ocp_compatibility: +- 4.16 +- 4.17 +- 4.18 +- 4.19 + +uds_version: 2.0.12 # Operator version 2.0.12 # sticking to 2.0.12 version # Please do Not Change +sls_version: 3.12.5 # Operator version 3.12.5 (https://github.ibm.com/maximoappsuite/ibm-sls/releases) +tsm_version: 1.7.2 # Operator version 1.7.2 (https://github.ibm.com/maximoappsuite/ibm-truststore-mgr/releases) +db2u_version: 7.5.1+20251217.121408.18568 # Operator version 110509.0.7 to find the version 7.5.1+20251217.121408.18568, search db2u-operator digest on repo (https://github.com/IBM/cloud-pak/tree/master/repo/case/ibm-db2uoperator) + +# Maximo Application Suite +# ----------------------------------------------------------------------------- +mas_core_version: + 9.2.x-feature: 9.2.0-pre.stable_9887 # Need to update + 9.1.x: 9.1.8 # Need to update + 9.0.x: 9.0.19 # Need to update + 8.10.x: "" # Not Supported + 8.11.x: "" # Not Supported +mas_manage_version: + 9.2.x-feature: 9.2.0-pre.stable_10282 # Need to update + 9.1.x: 9.1.8 # Need to update + 9.0.x: 9.0.21 # Need to update + 8.10.x: "" # Not Supported + 8.11.x: "" # Not Supported + +# Extra Images for UDS +# ------------------------------------------------------------------------------ +uds_extras_version: 1.5.0 + +# Extra Images for Mongo +# ------------------------------------------------------------------------------ +mongo_extras_version_default: 8.0.17 + +# Variables used to mirror additional mongo image versions +mongo_extras_version_4: 4.4.21 +mongo_extras_version_5: 5.0.23 +mongo_extras_version_6: 6.0.12 +mongo_extras_version_7: 7.0.12 +mongo_extras_version_8: 8.0.17 + +editorial: + whats_new: + - title: '**Security updates and bug fixes**' + details: + - IBM Maximo Application Suite Core Platform v8.10, v8.11, v9.0 and v9.1 + - IBM Maximo Manage v8.6, v8.7, v9.0 and v9.1 + known_issues: + - title: A known issue exists in the January 29, 2026 release affecting HSE and Oil & Gas (9.0.23 / 9.1.64). Customers with HSE installed should avoid upgrading to the January release. Installation of HSE or Oil & Gas on Manage 9.0.x / 9.1.x should be deferred until the February 2026 patch. \ No newline at end of file diff --git a/src/mas/devops/data/catalogs/v9-260226-s390x.yaml b/src/mas/devops/data/catalogs/v9-260226-s390x.yaml new file mode 100644 index 00000000..5146fb43 --- /dev/null +++ b/src/mas/devops/data/catalogs/v9-260226-s390x.yaml @@ -0,0 +1,58 @@ +--- +# Case bundle configuration for IBM Maximo Operator Catalog 260226 (Z) +# ----------------------------------------------------------------------------- +# In the future this won't be necessary as we'll be able to mirror from the +# catalog itself, but not everything in the catalog supports this yet (including MAS) +# so we need to use the CASE bundle mirror process still. + +catalog_digest: sha256:bdb612dd59fab8afad633063429d2816333c5b6c0ea7dcf07073404cf774d09e + +ocp_compatibility: +- 4.16 +- 4.17 +- 4.18 +- 4.19 + +uds_version: 2.0.12 # Operator version 2.0.12 # sticking to 2.0.12 version # Please do Not Change +sls_version: 3.12.5 # Operator version 3.12.5 (https://github.ibm.com/maximoappsuite/ibm-sls/releases) +tsm_version: 1.7.2 # Operator version 1.7.2 (https://github.ibm.com/maximoappsuite/ibm-truststore-mgr/releases) +db2u_version: 7.5.1+20251217.121408.18568 # Operator version 110509.0.7 to find the version 7.5.1+20251217.121408.18568, search db2u-operator digest on repo (https://github.com/IBM/cloud-pak/tree/master/repo/case/ibm-db2uoperator) + +# Maximo Application Suite +# ----------------------------------------------------------------------------- +mas_core_version: + 9.2.x-feature: 9.2.0-pre.stable_9887 # Need to update + 9.1.x: 9.1.8 # Need to update + 9.0.x: 9.0.19 # Need to update + 8.10.x: "" # Not Supported + 8.11.x: "" # Not Supported +mas_manage_version: + 9.2.x-feature: 9.2.0-pre.stable_10282 # Need to update + 9.1.x: 9.1.8 # Need to update + 9.0.x: 9.0.21 # Need to update + 8.10.x: "" # Not Supported + 8.11.x: "" # Not Supported + +# Extra Images for UDS +# ------------------------------------------------------------------------------ +uds_extras_version: 1.5.0 + +# Extra Images for Mongo +# ------------------------------------------------------------------------------ +mongo_extras_version_default: 8.0.17 + +# Variables used to mirror additional mongo image versions +mongo_extras_version_4: 4.4.21 +mongo_extras_version_5: 5.0.23 +mongo_extras_version_6: 6.0.12 +mongo_extras_version_7: 7.0.12 +mongo_extras_version_8: 8.0.17 + +editorial: + whats_new: + - title: '**Security updates and bug fixes**' + details: + - IBM Maximo Application Suite Core Platform v8.10, v8.11, v9.0 and v9.1 + - IBM Maximo Manage v8.6, v8.7, v9.0 and v9.1 + known_issues: + - title: A known issue exists in the January 29, 2026 release affecting HSE and Oil & Gas (9.0.23 / 9.1.64). Customers with HSE installed should avoid upgrading to the January release. Installation of HSE or Oil & Gas on Manage 9.0.x / 9.1.x should be deferred until the February 2026 patch. \ No newline at end of file From f3f2851b4d4f786476e6fa0f2a1fb26e37023af0 Mon Sep 17 00:00:00 2001 From: Anil Prajapati Date: Fri, 13 Feb 2026 19:07:02 +0530 Subject: [PATCH 25/45] create mas-devops secret --- src/mas/devops/tekton.py | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/mas/devops/tekton.py b/src/mas/devops/tekton.py index 58042db0..9b01ec63 100644 --- a/src/mas/devops/tekton.py +++ b/src/mas/devops/tekton.py @@ -10,6 +10,7 @@ import logging import yaml +import base64 from datetime import datetime from os import path @@ -402,12 +403,12 @@ def prepareInstallSecrets(dynClient: DynamicClient, namespace: str, slsLicenseFi """ Create or update secrets required for MAS installation pipelines. - Creates four secrets in the specified namespace: pipeline-additional-configs, + Creates five secrets in the specified namespace: mas-devops, pipeline-additional-configs, pipeline-sls-entitlement, pipeline-certificates, and pipeline-pod-templates. Parameters: dynClient (DynamicClient): OpenShift Dynamic Client - namespace (str): The namespace to create secrets in + namespace (str): The namespace to create secrets in (format: mas-{instance_id}-pipelines) slsLicenseFile (str, optional): SLS license file content. Defaults to None (empty secret). additionalConfigs (dict, optional): Additional configuration data. Defaults to None (empty secret). certs (str, optional): Certificate data. Defaults to None (empty secret). @@ -421,6 +422,29 @@ def prepareInstallSecrets(dynClient: DynamicClient, namespace: str, slsLicenseFi """ secretsAPI = dynClient.resources.get(api_version="v1", kind="Secret") + # Extract instance ID from namespace (format: mas-{instance_id}-pipelines) + instance_id = None + if namespace.startswith("mas-") and namespace.endswith("-pipelines"): + instance_id = namespace[4:-10] # Remove "mas-" prefix and "-pipelines" suffix + + # 0. Secret/mas-devops + # ------------------------------------------------------------------------- + # Create mas-devops secret with MAS_INSTANCE_ID key + if instance_id: + mas_devops_secret = { + "apiVersion": "v1", + "kind": "Secret", + "type": "Opaque", + "metadata": { + "name": "mas-devops" + }, + "data": { + "MAS_INSTANCE_ID": base64.b64encode(instance_id.encode()).decode() + } + } + secretsAPI.create(body=mas_devops_secret, namespace=namespace) + logger.info(f"Created mas-devops secret with MAS_INSTANCE_ID={instance_id} in namespace {namespace}") + # 1. Secret/pipeline-additional-configs # ------------------------------------------------------------------------- # Must exist, but can be empty From 8704ea13b8b1519799108534e1cf8e6c7d1b4354 Mon Sep 17 00:00:00 2001 From: Anil Prajapati Date: Fri, 13 Feb 2026 20:33:14 +0530 Subject: [PATCH 26/45] [patch] create mas-devops-slack secret with slack vars --- src/mas/devops/tekton.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/mas/devops/tekton.py b/src/mas/devops/tekton.py index 9b01ec63..e0cbecc4 100644 --- a/src/mas/devops/tekton.py +++ b/src/mas/devops/tekton.py @@ -431,12 +431,17 @@ def prepareInstallSecrets(dynClient: DynamicClient, namespace: str, slsLicenseFi # ------------------------------------------------------------------------- # Create mas-devops secret with MAS_INSTANCE_ID key if instance_id: + try: + secretsAPI.delete(name="mas-devops-slack", namespace=namespace) + except NotFoundError: + pass + mas_devops_secret = { "apiVersion": "v1", "kind": "Secret", "type": "Opaque", "metadata": { - "name": "mas-devops" + "name": "mas-devops-slack" }, "data": { "MAS_INSTANCE_ID": base64.b64encode(instance_id.encode()).decode() From 9527f56300c7f0c791c9e09695403a6c5530fb1c Mon Sep 17 00:00:00 2001 From: Anil Prajapati Date: Fri, 13 Feb 2026 21:51:39 +0530 Subject: [PATCH 27/45] [patch] add slack secrets vars into secrets --- src/mas/devops/tekton.py | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/src/mas/devops/tekton.py b/src/mas/devops/tekton.py index e0cbecc4..85b2f341 100644 --- a/src/mas/devops/tekton.py +++ b/src/mas/devops/tekton.py @@ -399,11 +399,11 @@ def prepareAiServicePipelinesNamespace(dynClient: DynamicClient, instanceId: str logger.info(f"Storage class {storageClass} uses volumeBindingMode={volumeBindingMode}, skipping PVC bind wait") -def prepareInstallSecrets(dynClient: DynamicClient, namespace: str, slsLicenseFile: str = None, additionalConfigs: dict = None, certs: str = None, podTemplates: str = None) -> None: +def prepareInstallSecrets(dynClient: DynamicClient, namespace: str, slsLicenseFile: str = None, additionalConfigs: dict = None, certs: str = None, podTemplates: str = None, slack_token: str = None, slack_channel: str = None) -> None: """ Create or update secrets required for MAS installation pipelines. - Creates five secrets in the specified namespace: mas-devops, pipeline-additional-configs, + Creates five secrets in the specified namespace: mas-devops-slack, pipeline-additional-configs, pipeline-sls-entitlement, pipeline-certificates, and pipeline-pod-templates. Parameters: @@ -413,6 +413,8 @@ def prepareInstallSecrets(dynClient: DynamicClient, namespace: str, slsLicenseFi additionalConfigs (dict, optional): Additional configuration data. Defaults to None (empty secret). certs (str, optional): Certificate data. Defaults to None (empty secret). podTemplates (str, optional): Pod template data. Defaults to None (empty secret). + slack_token (str, optional): Slack bot token for notifications. Defaults to None. + slack_channel (str, optional): Slack channel ID for notifications. Defaults to None. Returns: None @@ -427,15 +429,27 @@ def prepareInstallSecrets(dynClient: DynamicClient, namespace: str, slsLicenseFi if namespace.startswith("mas-") and namespace.endswith("-pipelines"): instance_id = namespace[4:-10] # Remove "mas-" prefix and "-pipelines" suffix - # 0. Secret/mas-devops + # 0. Secret/mas-devops-slack # ------------------------------------------------------------------------- - # Create mas-devops secret with MAS_INSTANCE_ID key + # Create mas-devops-slack secret with MAS_INSTANCE_ID, SLACK_TOKEN, and SLACK_CHANNEL keys if instance_id: try: secretsAPI.delete(name="mas-devops-slack", namespace=namespace) except NotFoundError: pass + secret_data = { + "MAS_INSTANCE_ID": base64.b64encode(instance_id.encode()).decode() + } + + # Add slack_token if provided + if slack_token: + secret_data["SLACK_TOKEN"] = base64.b64encode(slack_token.encode()).decode() + + # Add slack_channel if provided + if slack_channel: + secret_data["SLACK_CHANNEL"] = base64.b64encode(slack_channel.encode()).decode() + mas_devops_secret = { "apiVersion": "v1", "kind": "Secret", @@ -443,12 +457,10 @@ def prepareInstallSecrets(dynClient: DynamicClient, namespace: str, slsLicenseFi "metadata": { "name": "mas-devops-slack" }, - "data": { - "MAS_INSTANCE_ID": base64.b64encode(instance_id.encode()).decode() - } + "data": secret_data } secretsAPI.create(body=mas_devops_secret, namespace=namespace) - logger.info(f"Created mas-devops secret with MAS_INSTANCE_ID={instance_id} in namespace {namespace}") + logger.info(f"Created mas-devops-slack secret with MAS_INSTANCE_ID={instance_id} in namespace {namespace}") # 1. Secret/pipeline-additional-configs # ------------------------------------------------------------------------- From b7c3a3b180234a9c6b3c29d6119b1e50da775242 Mon Sep 17 00:00:00 2001 From: Anil Prajapati Date: Fri, 13 Feb 2026 23:33:23 +0530 Subject: [PATCH 28/45] [patch] add pipeline name in message --- bin/mas-devops-notify-slack | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/bin/mas-devops-notify-slack b/bin/mas-devops-notify-slack index 61e48c70..df4edd01 100755 --- a/bin/mas-devops-notify-slack +++ b/bin/mas-devops-notify-slack @@ -97,7 +97,7 @@ def notifyProvisionRoks(channels: list[str], rc: int, additionalMsg: str | None return response.data.get("ok", False) -def notifyPipelineStart(channels: list[str], instanceId: str | None = None) -> dict | None: +def notifyPipelineStart(channels: list[str], instanceId: str | None = None, pipelineName: str | None = None) -> dict | None: """Send Slack notification about pipeline start and create thread.""" namespace = f"mas-{instanceId}-pipelines" if instanceId is None or instanceId == "": @@ -114,7 +114,7 @@ def notifyPipelineStart(channels: list[str], instanceId: str | None = None) -> d toolchainLink = _getToolchainLink() instanceInfo = f"\nInstance ID: `{instanceId}`" if instanceId else "" message = [ - SlackUtil.buildHeader("🚀 MAS Pipeline Started"), + SlackUtil.buildHeader(f"🚀 MAS {pipelineName} Pipeline Started"), SlackUtil.buildSection(f"Pipeline Run: {instanceInfo}\n{toolchainLink}") ] response = SlackUtil.postMessageBlocks(channels[0], message) @@ -129,7 +129,7 @@ def notifyPipelineStart(channels: list[str], instanceId: str | None = None) -> d return False -def notifyAnsibleStart(channels: list[str], taskName: str, instanceId: str | None = None) -> bool: +def notifyAnsibleStart(channels: list[str], taskName: str, instanceId: str | None = None, pipelineName: str | None = None) -> bool: """Send Slack notification about Ansible task start.""" namespace = f"mas-{instanceId}-pipelines" if instanceId is None or instanceId == "": @@ -140,7 +140,7 @@ def notifyAnsibleStart(channels: list[str], taskName: str, instanceId: str | Non threadInfo = SlackUtil.getThreadConfigMap(namespace, instanceId) if threadInfo is None: print("No thread found - creating pipeline start notification") - notifyPipelineStart(channels, instanceId) + threadInfo = notifyPipelineStart(channels, instanceId, pipelineName) threadId = threadInfo.get("threadId") channelId = threadInfo.get("channelId") @@ -154,7 +154,7 @@ def notifyAnsibleStart(channels: list[str], taskName: str, instanceId: str | Non return response.data.get("ok", False) -def notifyAnsibleComplete(channels: list[str], rc: int, taskName: str, instanceId: str | None = None) -> bool: +def notifyAnsibleComplete(channels: list[str], rc: int, taskName: str, instanceId: str | None = None, pipelineName: str | None = None) -> bool: """Send Slack notification about Ansible task completion status.""" namespace = f"mas-{instanceId}-pipelines" if instanceId is None or instanceId == "": @@ -165,7 +165,7 @@ def notifyAnsibleComplete(channels: list[str], rc: int, taskName: str, instanceI threadInfo = SlackUtil.getThreadConfigMap(namespace, instanceId) if threadInfo is None: print("No thread found - creating pipeline start notification") - notifyPipelineStart(channels, instanceId) + threadInfo = notifyPipelineStart(channels, instanceId, pipelineName) # Send task completion message as thread reply threadId = threadInfo.get("threadId") channelId = threadInfo.get("channelId") @@ -186,7 +186,7 @@ def notifyAnsibleComplete(channels: list[str], rc: int, taskName: str, instanceI return response.data.get("ok", False) -def notifyPipelineComplete(channels: list[str], rc: int, instanceId: str | None = None) -> bool: +def notifyPipelineComplete(channels: list[str], rc: int, instanceId: str | None = None, pipelineName: str | None = None) -> bool: """Send Slack notification about pipeline completion and cleanup ConfigMap.""" namespace = f"mas-{instanceId}-pipelines" if instanceId is None or instanceId == "": @@ -226,7 +226,7 @@ def notifyPipelineComplete(channels: list[str], rc: int, instanceId: str | None status = "Failed" additionalInfo = f"\nPipeline failed with return code: `{rc}`" message = [ - SlackUtil.buildHeader(f"{emoji} MAS Pipeline {status}"), + SlackUtil.buildHeader(f"{emoji} MAS {pipelineName} Pipeline {status}"), SlackUtil.buildSection(f"Pipeline Run: {instanceInfo}{durationText}{additionalInfo}") ] response = SlackUtil.postMessageBlocks(channelId, message, threadId) @@ -252,10 +252,11 @@ if __name__ == "__main__": # Primary Options parser.add_argument("--action", required=True) - parser.add_argument("--rc", required=True, type=int) + parser.add_argument("--rc", required=False, type=int) parser.add_argument("--msg", required=False, default=None) parser.add_argument("--task-name", required=False, default="") parser.add_argument("--instance-id", required=False, default=None) + parser.add_argument("--pipeline-name", required=False, default=None) args, unknown = parser.parse_known_args() From 1eccd657a2c0ff04ea1ee8ecaa6e39b15ea27edd Mon Sep 17 00:00:00 2001 From: Parveen Kumar Date: Tue, 17 Feb 2026 21:49:55 +0530 Subject: [PATCH 29/45] [patch] assist, mvi, iot, monitor, aiservice, dd app version updated --- .../devops/data/catalogs/v9-260226-amd64.yaml | 34 +++++++++---------- .../data/catalogs/v9-260226-ppc64le.yaml | 2 +- .../devops/data/catalogs/v9-260226-s390x.yaml | 2 +- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/mas/devops/data/catalogs/v9-260226-amd64.yaml b/src/mas/devops/data/catalogs/v9-260226-amd64.yaml index ff40726e..7b98c89c 100644 --- a/src/mas/devops/data/catalogs/v9-260226-amd64.yaml +++ b/src/mas/devops/data/catalogs/v9-260226-amd64.yaml @@ -5,7 +5,7 @@ # catalog itself, but not everything in the catalog supports this yet (including MAS) # so we need to use the CASE bundle mirror process still. -catalog_digest: sha256:ee5cd2eb532a9b2f4336e0181daf32523cb744751fe782109b0350a9ff0c92cf +catalog_digest: sha256:5ee61efbe0928794d8c5cf3c8c6eab109f1c62a75b1d778c1e400cd450dd08e1 ocp_compatibility: - "4.16" @@ -29,7 +29,7 @@ events_version: 5.0.1 # Operator version 5.0.1 (https://g uds_version: 2.0.12 # Operator version 2.0.12 # sticking to 2.0.12 version # Please do Not Change sls_version: 3.12.5 # Operator version 3.12.5 (https://github.ibm.com/maximoappsuite/ibm-sls/releases) tsm_version: 1.7.2 # Operator version 1.7.2 (https://github.ibm.com/maximoappsuite/ibm-truststore-mgr/releases) -dd_version: 1.1.21 # Operator version 1.1.21 (https://github.ibm.com/maximoappsuite/ibm-data-dictionary/releases) +dd_version: 1.1.22 # Operator version 1.1.22 (https://github.ibm.com/maximoappsuite/ibm-data-dictionary/releases) appconnect_version: 6.2.0 # Operator version 6.2.0 # sticking to 6.2.0 version # Please do Not Change wsl_version: 11.0.0+20250521.202913.73 # used for wsl and wsl_runtimes unless wsl_runtimes_version also specified wsl_runtimes_version: 11.0.0+20250515.090949.21 # cpd 5.1.3 uses version 10.3.0 of wsl runtimes but only 10.2.0 for wsl itself @@ -54,8 +54,8 @@ mas_core_version: 8.10.x: 8.10.33 # Need to update 8.11.x: 8.11.30 # Need to update mas_assist_version: - 9.1.x: 9.1.7 # Need to update - 9.0.x: 9.0.13 # Need to update + 9.1.x: 9.1.8 # Updated + 9.0.x: 9.0.14 # Updated 8.10.x: 8.7.8 # No Update 8.11.x: 8.8.7 # No Update mas_hputilities_version: @@ -64,10 +64,10 @@ mas_hputilities_version: 8.10.x: 8.6.7 # No Update 8.11.x: "" # Not Supported mas_iot_version: - 9.1.x: 9.1.7 # Need to update - 9.0.x: 9.0.16 # Need to update - 8.10.x: 8.7.30 # Need to update - 8.11.x: 8.8.26 # Need to update + 9.1.x: 9.1.8 # Updated + 9.0.x: 9.0.17 # Updated + 8.10.x: 8.7.31 # Updated + 8.11.x: 8.8.28 # Updated mas_manage_version: 9.2.x-feature: 9.2.0-pre.stable_10282 # Need to update 9.1.x: 9.1.8 # Need to update @@ -75,10 +75,10 @@ mas_manage_version: 8.10.x: 8.6.34 # Need to update 8.11.x: 8.7.28 # Need to update mas_monitor_version: - 9.1.x: 9.1.7 # Need to update - 9.0.x: 9.0.17 # Need to update - 8.10.x: 8.10.27 # Need to update - 8.11.x: 8.11.25 # Need to update + 9.1.x: 9.1.8 # Updated + 9.0.x: 9.0.18 # Updated + 8.10.x: 8.10.28 # Updated + 8.11.x: 8.11.26 # Updated mas_optimizer_version: 9.2.x-feature: 9.2.0-pre.stable_9869 # Need to update 9.1.x: 9.1.8 # Need to update @@ -92,10 +92,10 @@ mas_predict_version: 8.11.x: 8.9.14 # Need to update mas_visualinspection_version: 9.2.x-feature: 9.2.0-pre.stable_6198 # Need to update - 9.1.x: 9.1.7 # Need to update - 9.0.x: 9.0.16 # Need to update + 9.1.x: 9.1.9 # Updated + 9.0.x: 9.0.17 # Updated 8.10.x: 8.8.4 # No Update - 8.11.x: 8.9.19 # Need to update + 8.11.x: 8.9.20 # Updated mas_facilities_version: 9.1.x: 9.1.7 # Need to update 9.0.x: "" # Not Supported @@ -106,8 +106,8 @@ mas_facilities_version: # Maximo AI Service # ------------------------------------------------------------------------------ aiservice_version: - 9.2.x-feature: 9.2.0-pre.stable_9768 # Need to update - 9.1.x: 9.1.11 # Need to update + 9.2.x-feature: 9.2.0-pre.stable_12908 # Updated + 9.1.x: 9.1.12 # Updated # Extra Images for UDS diff --git a/src/mas/devops/data/catalogs/v9-260226-ppc64le.yaml b/src/mas/devops/data/catalogs/v9-260226-ppc64le.yaml index 14932e8d..54f2887b 100644 --- a/src/mas/devops/data/catalogs/v9-260226-ppc64le.yaml +++ b/src/mas/devops/data/catalogs/v9-260226-ppc64le.yaml @@ -5,7 +5,7 @@ # catalog itself, but not everything in the catalog supports this yet (including MAS) # so we need to use the CASE bundle mirror process still. -catalog_digest: sha256:5bbdd2381ab0090ce4862bafdec4c13477b711c58f57c31ffacb011f3b320ade +catalog_digest: sha256:506f3df06f5a82b2eecbac9e19347b9690080952cfaa7aa6248ba230a625808d ocp_compatibility: - "4.16" diff --git a/src/mas/devops/data/catalogs/v9-260226-s390x.yaml b/src/mas/devops/data/catalogs/v9-260226-s390x.yaml index 6efb7798..d7dffb4a 100644 --- a/src/mas/devops/data/catalogs/v9-260226-s390x.yaml +++ b/src/mas/devops/data/catalogs/v9-260226-s390x.yaml @@ -5,7 +5,7 @@ # catalog itself, but not everything in the catalog supports this yet (including MAS) # so we need to use the CASE bundle mirror process still. -catalog_digest: sha256:bdb612dd59fab8afad633063429d2816333c5b6c0ea7dcf07073404cf774d09e +catalog_digest: sha256:016c590d92ab25806e840694afacd895d7ae5daaed0e0fccb6d759b37d0f5a98 ocp_compatibility: - "4.16" From 8548d215630e13364e0ce37f39bf4cf666a75be4 Mon Sep 17 00:00:00 2001 From: Parveen Kumar Date: Wed, 18 Feb 2026 00:00:12 +0530 Subject: [PATCH 30/45] [patch] Use editable install in CI workflows Replace `pip install .[dev]` with `pip install --editable .[dev]` in python-package.yml and python-release.yml so the CI runs tests and linters against an editable local install. This ensures source changes in the repo (src layout) are reflected without reinstalling the package during the job. --- .github/workflows/python-package.yml | 2 +- .github/workflows/python-release.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index edb21ef4..6613be08 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -45,7 +45,7 @@ jobs: sed -i "s#__version__ = \"100.0.0\"#__version__ = \"${{ env.VERSION_NOPREREL }}\"#g" ${GITHUB_WORKSPACE}/src/mas/devops/__init__.py cat ${GITHUB_WORKSPACE}/src/mas/devops/__init__.py python -m pip install --upgrade pip - pip install .[dev] + pip install --editable .[dev] python -m pytest - name: Lint with flake8 diff --git a/.github/workflows/python-release.yml b/.github/workflows/python-release.yml index c178265b..159d1fb6 100644 --- a/.github/workflows/python-release.yml +++ b/.github/workflows/python-release.yml @@ -44,7 +44,7 @@ jobs: sed -i "s#__version__ = \"100.0.0\"#__version__ = \"${{ env.VERSION_NOPREREL }}\"#g" ${GITHUB_WORKSPACE}/src/mas/devops/__init__.py cat ${GITHUB_WORKSPACE}/src/mas/devops/__init__.py python -m pip install --upgrade pip - pip install .[dev] + pip install --editable .[dev] python -m pytest # 3. Flake8 Linting From aa5d8b5c4815b70113913a94e2d76cee105f0c75 Mon Sep 17 00:00:00 2001 From: Parveen Kumar Date: Wed, 18 Feb 2026 00:44:44 +0530 Subject: [PATCH 31/45] Revert "[patch] Use editable install in CI workflows" This reverts commit 8548d215630e13364e0ce37f39bf4cf666a75be4. --- .github/workflows/python-package.yml | 2 +- .github/workflows/python-release.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index 6613be08..edb21ef4 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -45,7 +45,7 @@ jobs: sed -i "s#__version__ = \"100.0.0\"#__version__ = \"${{ env.VERSION_NOPREREL }}\"#g" ${GITHUB_WORKSPACE}/src/mas/devops/__init__.py cat ${GITHUB_WORKSPACE}/src/mas/devops/__init__.py python -m pip install --upgrade pip - pip install --editable .[dev] + pip install .[dev] python -m pytest - name: Lint with flake8 diff --git a/.github/workflows/python-release.yml b/.github/workflows/python-release.yml index 159d1fb6..c178265b 100644 --- a/.github/workflows/python-release.yml +++ b/.github/workflows/python-release.yml @@ -44,7 +44,7 @@ jobs: sed -i "s#__version__ = \"100.0.0\"#__version__ = \"${{ env.VERSION_NOPREREL }}\"#g" ${GITHUB_WORKSPACE}/src/mas/devops/__init__.py cat ${GITHUB_WORKSPACE}/src/mas/devops/__init__.py python -m pip install --upgrade pip - pip install --editable .[dev] + pip install .[dev] python -m pytest # 3. Flake8 Linting From 6e061c8804d0b51bdd1108f72342d6ef03954e78 Mon Sep 17 00:00:00 2001 From: Parveen Kumar Date: Thu, 19 Feb 2026 10:47:10 +0530 Subject: [PATCH 32/45] [patch] Update MAS catalogs: digests and component versions --- .../devops/data/catalogs/v9-260226-amd64.yaml | 38 +++++++++---------- .../data/catalogs/v9-260226-ppc64le.yaml | 10 ++--- .../devops/data/catalogs/v9-260226-s390x.yaml | 10 ++--- 3 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/mas/devops/data/catalogs/v9-260226-amd64.yaml b/src/mas/devops/data/catalogs/v9-260226-amd64.yaml index 7b98c89c..986cd8c0 100644 --- a/src/mas/devops/data/catalogs/v9-260226-amd64.yaml +++ b/src/mas/devops/data/catalogs/v9-260226-amd64.yaml @@ -5,7 +5,7 @@ # catalog itself, but not everything in the catalog supports this yet (including MAS) # so we need to use the CASE bundle mirror process still. -catalog_digest: sha256:5ee61efbe0928794d8c5cf3c8c6eab109f1c62a75b1d778c1e400cd450dd08e1 +catalog_digest: sha256:ee8463afc78196a0fd3768bed7bd138200ef7ad55daebbac3fa72c739099be83 ocp_compatibility: - "4.16" @@ -49,10 +49,10 @@ opensearch_version: 1.1.2494 # Operator version 1.1.2494 # ----------------------------------------------------------------------------- mas_core_version: 9.2.x-feature: 9.2.0-pre.stable_9887 # Need to update - 9.1.x: 9.1.8 # Need to update - 9.0.x: 9.0.19 # Need to update + 9.1.x: 9.1.10 # Updated + 9.0.x: 9.0.21 # Updated 8.10.x: 8.10.33 # Need to update - 8.11.x: 8.11.30 # Need to update + 8.11.x: 8.11.32 # Updated mas_assist_version: 9.1.x: 9.1.8 # Updated 9.0.x: 9.0.14 # Updated @@ -70,34 +70,34 @@ mas_iot_version: 8.11.x: 8.8.28 # Updated mas_manage_version: 9.2.x-feature: 9.2.0-pre.stable_10282 # Need to update - 9.1.x: 9.1.8 # Need to update - 9.0.x: 9.0.21 # Need to update - 8.10.x: 8.6.34 # Need to update - 8.11.x: 8.7.28 # Need to update + 9.1.x: 9.1.10 # Updated + 9.0.x: 9.0.22 # Updated + 8.10.x: 8.6.35 # Updated + 8.11.x: 8.7.29 # Updated mas_monitor_version: 9.1.x: 9.1.8 # Updated 9.0.x: 9.0.18 # Updated 8.10.x: 8.10.28 # Updated 8.11.x: 8.11.26 # Updated mas_optimizer_version: - 9.2.x-feature: 9.2.0-pre.stable_9869 # Need to update - 9.1.x: 9.1.8 # Need to update - 9.0.x: 9.0.19 # Need to update + 9.2.x-feature: 9.2.0-pre.stable_12739 # Updated + 9.1.x: 9.1.9 # Updated + 9.0.x: 9.0.20 # Updated 8.10.x: 8.4.26 # Need to update - 8.11.x: 8.5.25 # Need to update + 8.11.x: 8.5.26 # Updated mas_predict_version: - 9.1.x: 9.1.4 # Need to update - 9.0.x: 9.0.11 # Need to update - 8.10.x: 8.8.12 # Need to update - 8.11.x: 8.9.14 # Need to update + 9.1.x: 9.1.5 # Updated + 9.0.x: 9.0.12 # Updated + 8.10.x: 8.8.13 # Updated + 8.11.x: 8.9.15 # Updated mas_visualinspection_version: 9.2.x-feature: 9.2.0-pre.stable_6198 # Need to update - 9.1.x: 9.1.9 # Updated + 9.1.x: 9.1.10 # Updated 9.0.x: 9.0.17 # Updated - 8.10.x: 8.8.4 # No Update + 8.10.x: 8.8.4 # No Update 8.11.x: 8.9.20 # Updated mas_facilities_version: - 9.1.x: 9.1.7 # Need to update + 9.1.x: 9.1.8 # Updated 9.0.x: "" # Not Supported 8.10.x: "" # Not Supported 8.11.x: "" # Not Supported diff --git a/src/mas/devops/data/catalogs/v9-260226-ppc64le.yaml b/src/mas/devops/data/catalogs/v9-260226-ppc64le.yaml index 54f2887b..0245332d 100644 --- a/src/mas/devops/data/catalogs/v9-260226-ppc64le.yaml +++ b/src/mas/devops/data/catalogs/v9-260226-ppc64le.yaml @@ -5,7 +5,7 @@ # catalog itself, but not everything in the catalog supports this yet (including MAS) # so we need to use the CASE bundle mirror process still. -catalog_digest: sha256:506f3df06f5a82b2eecbac9e19347b9690080952cfaa7aa6248ba230a625808d +catalog_digest: sha256:b4f7c9c4e11c0d5d97971444be2b297929d127ec95d4bd8dfe8e1ddf6664d0a0 ocp_compatibility: - "4.16" @@ -23,14 +23,14 @@ db2u_version: 7.5.1+20251217.121408.18568 # Operator version 110509.0.7 to fi # ----------------------------------------------------------------------------- mas_core_version: 9.2.x-feature: 9.2.0-pre.stable_9887 # Need to update - 9.1.x: 9.1.8 # Need to update - 9.0.x: 9.0.19 # Need to update + 9.1.x: 9.1.10 # Updated + 9.0.x: 9.0.21 # Updated 8.10.x: "" # Not Supported 8.11.x: "" # Not Supported mas_manage_version: 9.2.x-feature: 9.2.0-pre.stable_10282 # Need to update - 9.1.x: 9.1.8 # Need to update - 9.0.x: 9.0.21 # Need to update + 9.1.x: 9.1.10 # Updated + 9.0.x: 9.0.22 # Updated 8.10.x: "" # Not Supported 8.11.x: "" # Not Supported diff --git a/src/mas/devops/data/catalogs/v9-260226-s390x.yaml b/src/mas/devops/data/catalogs/v9-260226-s390x.yaml index d7dffb4a..75fc87a4 100644 --- a/src/mas/devops/data/catalogs/v9-260226-s390x.yaml +++ b/src/mas/devops/data/catalogs/v9-260226-s390x.yaml @@ -5,7 +5,7 @@ # catalog itself, but not everything in the catalog supports this yet (including MAS) # so we need to use the CASE bundle mirror process still. -catalog_digest: sha256:016c590d92ab25806e840694afacd895d7ae5daaed0e0fccb6d759b37d0f5a98 +catalog_digest: sha256:ece350c9c6ecbde39d40e76babcaaeabe547bb8853b19091a02b4f1a84068b16 ocp_compatibility: - "4.16" @@ -23,14 +23,14 @@ db2u_version: 7.5.1+20251217.121408.18568 # Operator version 110509.0.7 to fi # ----------------------------------------------------------------------------- mas_core_version: 9.2.x-feature: 9.2.0-pre.stable_9887 # Need to update - 9.1.x: 9.1.8 # Need to update - 9.0.x: 9.0.19 # Need to update + 9.1.x: 9.1.10 # Updated + 9.0.x: 9.0.21 # Updated 8.10.x: "" # Not Supported 8.11.x: "" # Not Supported mas_manage_version: 9.2.x-feature: 9.2.0-pre.stable_10282 # Need to update - 9.1.x: 9.1.8 # Need to update - 9.0.x: 9.0.21 # Need to update + 9.1.x: 9.1.10 # Updated + 9.0.x: 9.0.22 # Updated 8.10.x: "" # Not Supported 8.11.x: "" # Not Supported From 1c8b7dbae25f58744b47f3006a193dfb0b43f8b9 Mon Sep 17 00:00:00 2001 From: Parveen Kumar Date: Thu, 19 Feb 2026 11:11:43 +0530 Subject: [PATCH 33/45] [patch] Use editable install in CI workflows --- .github/workflows/python-package.yml | 2 +- .github/workflows/python-release.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index edb21ef4..663a616e 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -45,7 +45,7 @@ jobs: sed -i "s#__version__ = \"100.0.0\"#__version__ = \"${{ env.VERSION_NOPREREL }}\"#g" ${GITHUB_WORKSPACE}/src/mas/devops/__init__.py cat ${GITHUB_WORKSPACE}/src/mas/devops/__init__.py python -m pip install --upgrade pip - pip install .[dev] + pip install -e .[dev] python -m pytest - name: Lint with flake8 diff --git a/.github/workflows/python-release.yml b/.github/workflows/python-release.yml index c178265b..794ddbe2 100644 --- a/.github/workflows/python-release.yml +++ b/.github/workflows/python-release.yml @@ -44,7 +44,7 @@ jobs: sed -i "s#__version__ = \"100.0.0\"#__version__ = \"${{ env.VERSION_NOPREREL }}\"#g" ${GITHUB_WORKSPACE}/src/mas/devops/__init__.py cat ${GITHUB_WORKSPACE}/src/mas/devops/__init__.py python -m pip install --upgrade pip - pip install .[dev] + pip install -e .[dev] python -m pytest # 3. Flake8 Linting From 169910e4dc6c9aa9c37db20cecddbdb465ef6cc9 Mon Sep 17 00:00:00 2001 From: Parveen Kumar Date: Thu, 19 Feb 2026 11:48:11 +0530 Subject: [PATCH 34/45] Revert "[patch] Use editable install in CI workflows" This reverts commit 1c8b7dbae25f58744b47f3006a193dfb0b43f8b9. --- .github/workflows/python-package.yml | 2 +- .github/workflows/python-release.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index 663a616e..edb21ef4 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -45,7 +45,7 @@ jobs: sed -i "s#__version__ = \"100.0.0\"#__version__ = \"${{ env.VERSION_NOPREREL }}\"#g" ${GITHUB_WORKSPACE}/src/mas/devops/__init__.py cat ${GITHUB_WORKSPACE}/src/mas/devops/__init__.py python -m pip install --upgrade pip - pip install -e .[dev] + pip install .[dev] python -m pytest - name: Lint with flake8 diff --git a/.github/workflows/python-release.yml b/.github/workflows/python-release.yml index 794ddbe2..c178265b 100644 --- a/.github/workflows/python-release.yml +++ b/.github/workflows/python-release.yml @@ -44,7 +44,7 @@ jobs: sed -i "s#__version__ = \"100.0.0\"#__version__ = \"${{ env.VERSION_NOPREREL }}\"#g" ${GITHUB_WORKSPACE}/src/mas/devops/__init__.py cat ${GITHUB_WORKSPACE}/src/mas/devops/__init__.py python -m pip install --upgrade pip - pip install -e .[dev] + pip install .[dev] python -m pytest # 3. Flake8 Linting From e2a877cf3ddc2a471a41f8fd7a8c2f2d95b2340c Mon Sep 17 00:00:00 2001 From: Parveen Kumar Date: Thu, 19 Feb 2026 11:55:17 +0530 Subject: [PATCH 35/45] [patch] add tsm_version to 1.7.3 in catalogs --- src/mas/devops/data/catalogs/v9-260226-amd64.yaml | 2 +- src/mas/devops/data/catalogs/v9-260226-ppc64le.yaml | 2 +- src/mas/devops/data/catalogs/v9-260226-s390x.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mas/devops/data/catalogs/v9-260226-amd64.yaml b/src/mas/devops/data/catalogs/v9-260226-amd64.yaml index 986cd8c0..de767d28 100644 --- a/src/mas/devops/data/catalogs/v9-260226-amd64.yaml +++ b/src/mas/devops/data/catalogs/v9-260226-amd64.yaml @@ -28,7 +28,7 @@ db2_channel_default: v110509.0 # Default Channel version for db2u- events_version: 5.0.1 # Operator version 5.0.1 (https://github.com/IBM/cloud-pak/tree/master/repo/case/ibm-events-operator) uds_version: 2.0.12 # Operator version 2.0.12 # sticking to 2.0.12 version # Please do Not Change sls_version: 3.12.5 # Operator version 3.12.5 (https://github.ibm.com/maximoappsuite/ibm-sls/releases) -tsm_version: 1.7.2 # Operator version 1.7.2 (https://github.ibm.com/maximoappsuite/ibm-truststore-mgr/releases) +tsm_version: 1.7.3 # Operator version 1.7.3 (https://github.ibm.com/maximoappsuite/ibm-truststore-mgr/releases) dd_version: 1.1.22 # Operator version 1.1.22 (https://github.ibm.com/maximoappsuite/ibm-data-dictionary/releases) appconnect_version: 6.2.0 # Operator version 6.2.0 # sticking to 6.2.0 version # Please do Not Change wsl_version: 11.0.0+20250521.202913.73 # used for wsl and wsl_runtimes unless wsl_runtimes_version also specified diff --git a/src/mas/devops/data/catalogs/v9-260226-ppc64le.yaml b/src/mas/devops/data/catalogs/v9-260226-ppc64le.yaml index 0245332d..ecf2ed2b 100644 --- a/src/mas/devops/data/catalogs/v9-260226-ppc64le.yaml +++ b/src/mas/devops/data/catalogs/v9-260226-ppc64le.yaml @@ -16,7 +16,7 @@ ocp_compatibility: uds_version: 2.0.12 # Operator version 2.0.12 # sticking to 2.0.12 version # Please do Not Change sls_version: 3.12.5 # Operator version 3.12.5 (https://github.ibm.com/maximoappsuite/ibm-sls/releases) -tsm_version: 1.7.2 # Operator version 1.7.2 (https://github.ibm.com/maximoappsuite/ibm-truststore-mgr/releases) +tsm_version: 1.7.3 # Operator version 1.7.3 (https://github.ibm.com/maximoappsuite/ibm-truststore-mgr/releases) db2u_version: 7.5.1+20251217.121408.18568 # Operator version 110509.0.7 to find the version 7.5.1+20251217.121408.18568, search db2u-operator digest on repo (https://github.com/IBM/cloud-pak/tree/master/repo/case/ibm-db2uoperator) # Maximo Application Suite diff --git a/src/mas/devops/data/catalogs/v9-260226-s390x.yaml b/src/mas/devops/data/catalogs/v9-260226-s390x.yaml index 75fc87a4..ff39efec 100644 --- a/src/mas/devops/data/catalogs/v9-260226-s390x.yaml +++ b/src/mas/devops/data/catalogs/v9-260226-s390x.yaml @@ -16,7 +16,7 @@ ocp_compatibility: uds_version: 2.0.12 # Operator version 2.0.12 # sticking to 2.0.12 version # Please do Not Change sls_version: 3.12.5 # Operator version 3.12.5 (https://github.ibm.com/maximoappsuite/ibm-sls/releases) -tsm_version: 1.7.2 # Operator version 1.7.2 (https://github.ibm.com/maximoappsuite/ibm-truststore-mgr/releases) +tsm_version: 1.7.3 # Operator version 1.7.3 (https://github.ibm.com/maximoappsuite/ibm-truststore-mgr/releases) db2u_version: 7.5.1+20251217.121408.18568 # Operator version 110509.0.7 to find the version 7.5.1+20251217.121408.18568, search db2u-operator digest on repo (https://github.com/IBM/cloud-pak/tree/master/repo/case/ibm-db2uoperator) # Maximo Application Suite From 8817df43f062da8bf060d1c9f02bfd5600e50e61 Mon Sep 17 00:00:00 2001 From: Parveen Kumar Date: Thu, 19 Feb 2026 19:11:19 +0530 Subject: [PATCH 36/45] [patch] update catalog digest --- src/mas/devops/data/catalogs/v9-260226-amd64.yaml | 2 +- src/mas/devops/data/catalogs/v9-260226-ppc64le.yaml | 2 +- src/mas/devops/data/catalogs/v9-260226-s390x.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mas/devops/data/catalogs/v9-260226-amd64.yaml b/src/mas/devops/data/catalogs/v9-260226-amd64.yaml index de767d28..54ca57a7 100644 --- a/src/mas/devops/data/catalogs/v9-260226-amd64.yaml +++ b/src/mas/devops/data/catalogs/v9-260226-amd64.yaml @@ -5,7 +5,7 @@ # catalog itself, but not everything in the catalog supports this yet (including MAS) # so we need to use the CASE bundle mirror process still. -catalog_digest: sha256:ee8463afc78196a0fd3768bed7bd138200ef7ad55daebbac3fa72c739099be83 +catalog_digest: sha256:62c82c1f051f511d076860ff1ad52610d029de0c1dd263ea5b5da43d6c6ac1e8 ocp_compatibility: - "4.16" diff --git a/src/mas/devops/data/catalogs/v9-260226-ppc64le.yaml b/src/mas/devops/data/catalogs/v9-260226-ppc64le.yaml index ecf2ed2b..1bc5d5ec 100644 --- a/src/mas/devops/data/catalogs/v9-260226-ppc64le.yaml +++ b/src/mas/devops/data/catalogs/v9-260226-ppc64le.yaml @@ -5,7 +5,7 @@ # catalog itself, but not everything in the catalog supports this yet (including MAS) # so we need to use the CASE bundle mirror process still. -catalog_digest: sha256:b4f7c9c4e11c0d5d97971444be2b297929d127ec95d4bd8dfe8e1ddf6664d0a0 +catalog_digest: sha256:3aafbe1138284fe2ea654faccda0ad440dd5d30e56a5576adb6586ef7b9d92ab ocp_compatibility: - "4.16" diff --git a/src/mas/devops/data/catalogs/v9-260226-s390x.yaml b/src/mas/devops/data/catalogs/v9-260226-s390x.yaml index ff39efec..41269a49 100644 --- a/src/mas/devops/data/catalogs/v9-260226-s390x.yaml +++ b/src/mas/devops/data/catalogs/v9-260226-s390x.yaml @@ -5,7 +5,7 @@ # catalog itself, but not everything in the catalog supports this yet (including MAS) # so we need to use the CASE bundle mirror process still. -catalog_digest: sha256:ece350c9c6ecbde39d40e76babcaaeabe547bb8853b19091a02b4f1a84068b16 +catalog_digest: sha256:eba994bd103b97064778c47373d3ac2a0dd977ba29944c77168045269af04eeb ocp_compatibility: - "4.16" From 034eac6ff04f31d8dbb50af56fc7e4875c416849 Mon Sep 17 00:00:00 2001 From: Parveen Kumar Date: Sat, 21 Feb 2026 10:49:11 +0530 Subject: [PATCH 37/45] [patch] Bump catalog digests and MAS manage versions Update catalog_digest entries for amd64, ppc64le, and s390x catalog files and increment MAS manage package versions. Changes: bump catalog_digest in v9-260226-amd64/ppc64le/s390x.yaml; update mas_manage_version 9.1.x -> 9.1.11 and 9.0.x -> 9.0.23 for all platforms, and additionally on amd64 bump 8.10.x 8.6.35 -> 8.6.36 and 8.11.x 8.7.29 -> 8.7.30. These reflect rebuilt catalogs and minor/patch component updates. --- src/mas/devops/data/catalogs/v9-260226-amd64.yaml | 10 +++++----- src/mas/devops/data/catalogs/v9-260226-ppc64le.yaml | 6 +++--- src/mas/devops/data/catalogs/v9-260226-s390x.yaml | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/mas/devops/data/catalogs/v9-260226-amd64.yaml b/src/mas/devops/data/catalogs/v9-260226-amd64.yaml index 54ca57a7..ecb6478e 100644 --- a/src/mas/devops/data/catalogs/v9-260226-amd64.yaml +++ b/src/mas/devops/data/catalogs/v9-260226-amd64.yaml @@ -5,7 +5,7 @@ # catalog itself, but not everything in the catalog supports this yet (including MAS) # so we need to use the CASE bundle mirror process still. -catalog_digest: sha256:62c82c1f051f511d076860ff1ad52610d029de0c1dd263ea5b5da43d6c6ac1e8 +catalog_digest: sha256:73f29bee7859b45084e77b0ad5f3e1f62f9a36c6badae0d51a51e45b083ae81f ocp_compatibility: - "4.16" @@ -70,10 +70,10 @@ mas_iot_version: 8.11.x: 8.8.28 # Updated mas_manage_version: 9.2.x-feature: 9.2.0-pre.stable_10282 # Need to update - 9.1.x: 9.1.10 # Updated - 9.0.x: 9.0.22 # Updated - 8.10.x: 8.6.35 # Updated - 8.11.x: 8.7.29 # Updated + 9.1.x: 9.1.11 # Updated + 9.0.x: 9.0.23 # Updated + 8.10.x: 8.6.36 # Updated + 8.11.x: 8.7.30 # Updated mas_monitor_version: 9.1.x: 9.1.8 # Updated 9.0.x: 9.0.18 # Updated diff --git a/src/mas/devops/data/catalogs/v9-260226-ppc64le.yaml b/src/mas/devops/data/catalogs/v9-260226-ppc64le.yaml index 1bc5d5ec..1d1a2eff 100644 --- a/src/mas/devops/data/catalogs/v9-260226-ppc64le.yaml +++ b/src/mas/devops/data/catalogs/v9-260226-ppc64le.yaml @@ -5,7 +5,7 @@ # catalog itself, but not everything in the catalog supports this yet (including MAS) # so we need to use the CASE bundle mirror process still. -catalog_digest: sha256:3aafbe1138284fe2ea654faccda0ad440dd5d30e56a5576adb6586ef7b9d92ab +catalog_digest: sha256:db3c353c42d62efde5a43c58644388e6879934f3776e5a8cab7bf321821fa5de ocp_compatibility: - "4.16" @@ -29,8 +29,8 @@ mas_core_version: 8.11.x: "" # Not Supported mas_manage_version: 9.2.x-feature: 9.2.0-pre.stable_10282 # Need to update - 9.1.x: 9.1.10 # Updated - 9.0.x: 9.0.22 # Updated + 9.1.x: 9.1.11 # Updated + 9.0.x: 9.0.23 # Updated 8.10.x: "" # Not Supported 8.11.x: "" # Not Supported diff --git a/src/mas/devops/data/catalogs/v9-260226-s390x.yaml b/src/mas/devops/data/catalogs/v9-260226-s390x.yaml index 41269a49..34f284e6 100644 --- a/src/mas/devops/data/catalogs/v9-260226-s390x.yaml +++ b/src/mas/devops/data/catalogs/v9-260226-s390x.yaml @@ -5,7 +5,7 @@ # catalog itself, but not everything in the catalog supports this yet (including MAS) # so we need to use the CASE bundle mirror process still. -catalog_digest: sha256:eba994bd103b97064778c47373d3ac2a0dd977ba29944c77168045269af04eeb +catalog_digest: sha256:bdb6c425131667f24b27a9a5e16b0d9b9c2cf9d6735aa886859f89b19deaef05 ocp_compatibility: - "4.16" @@ -29,8 +29,8 @@ mas_core_version: 8.11.x: "" # Not Supported mas_manage_version: 9.2.x-feature: 9.2.0-pre.stable_10282 # Need to update - 9.1.x: 9.1.10 # Updated - 9.0.x: 9.0.22 # Updated + 9.1.x: 9.1.11 # Updated + 9.0.x: 9.0.23 # Updated 8.10.x: "" # Not Supported 8.11.x: "" # Not Supported From 3f5b48b9e8e1d0724abd772694228e38599d7461 Mon Sep 17 00:00:00 2001 From: Parveen Kumar Date: Sun, 22 Feb 2026 12:21:04 +0530 Subject: [PATCH 38/45] [patch] Update catalog digests and MAS component versions --- src/mas/devops/data/catalogs/v9-260226-amd64.yaml | 10 +++++----- src/mas/devops/data/catalogs/v9-260226-ppc64le.yaml | 6 +++--- src/mas/devops/data/catalogs/v9-260226-s390x.yaml | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/mas/devops/data/catalogs/v9-260226-amd64.yaml b/src/mas/devops/data/catalogs/v9-260226-amd64.yaml index ecb6478e..cb06d7d7 100644 --- a/src/mas/devops/data/catalogs/v9-260226-amd64.yaml +++ b/src/mas/devops/data/catalogs/v9-260226-amd64.yaml @@ -5,7 +5,7 @@ # catalog itself, but not everything in the catalog supports this yet (including MAS) # so we need to use the CASE bundle mirror process still. -catalog_digest: sha256:73f29bee7859b45084e77b0ad5f3e1f62f9a36c6badae0d51a51e45b083ae81f +catalog_digest: sha256:c97fb60525800afa89a5f115d71751f29ebc0f7a7d553e5bf7912ba7ee2001e0 ocp_compatibility: - "4.16" @@ -48,10 +48,10 @@ opensearch_version: 1.1.2494 # Operator version 1.1.2494 # Maximo Application Suite # ----------------------------------------------------------------------------- mas_core_version: - 9.2.x-feature: 9.2.0-pre.stable_9887 # Need to update + 9.2.x-feature: 9.2.0-pre.stable_12926 # Updated 9.1.x: 9.1.10 # Updated 9.0.x: 9.0.21 # Updated - 8.10.x: 8.10.33 # Need to update + 8.10.x: 8.10.35 # Updated 8.11.x: 8.11.32 # Updated mas_assist_version: 9.1.x: 9.1.8 # Updated @@ -69,7 +69,7 @@ mas_iot_version: 8.10.x: 8.7.31 # Updated 8.11.x: 8.8.28 # Updated mas_manage_version: - 9.2.x-feature: 9.2.0-pre.stable_10282 # Need to update + 9.2.x-feature: 9.2.0-pre.stable_13730 # Updated 9.1.x: 9.1.11 # Updated 9.0.x: 9.0.23 # Updated 8.10.x: 8.6.36 # Updated @@ -91,7 +91,7 @@ mas_predict_version: 8.10.x: 8.8.13 # Updated 8.11.x: 8.9.15 # Updated mas_visualinspection_version: - 9.2.x-feature: 9.2.0-pre.stable_6198 # Need to update + 9.2.x-feature: 9.2.0-pre.stable_12598 # Updated 9.1.x: 9.1.10 # Updated 9.0.x: 9.0.17 # Updated 8.10.x: 8.8.4 # No Update diff --git a/src/mas/devops/data/catalogs/v9-260226-ppc64le.yaml b/src/mas/devops/data/catalogs/v9-260226-ppc64le.yaml index 1d1a2eff..e28620b5 100644 --- a/src/mas/devops/data/catalogs/v9-260226-ppc64le.yaml +++ b/src/mas/devops/data/catalogs/v9-260226-ppc64le.yaml @@ -5,7 +5,7 @@ # catalog itself, but not everything in the catalog supports this yet (including MAS) # so we need to use the CASE bundle mirror process still. -catalog_digest: sha256:db3c353c42d62efde5a43c58644388e6879934f3776e5a8cab7bf321821fa5de +catalog_digest: sha256:99387cb9cc028fad0c1c887a0946992bd96c2568a4de379d0bd922a5f4b14c14 ocp_compatibility: - "4.16" @@ -22,13 +22,13 @@ db2u_version: 7.5.1+20251217.121408.18568 # Operator version 110509.0.7 to fi # Maximo Application Suite # ----------------------------------------------------------------------------- mas_core_version: - 9.2.x-feature: 9.2.0-pre.stable_9887 # Need to update + 9.2.x-feature: 9.2.0-pre.stable_12926 # Updated 9.1.x: 9.1.10 # Updated 9.0.x: 9.0.21 # Updated 8.10.x: "" # Not Supported 8.11.x: "" # Not Supported mas_manage_version: - 9.2.x-feature: 9.2.0-pre.stable_10282 # Need to update + 9.2.x-feature: 9.2.0-pre.stable_13730 # Updated 9.1.x: 9.1.11 # Updated 9.0.x: 9.0.23 # Updated 8.10.x: "" # Not Supported diff --git a/src/mas/devops/data/catalogs/v9-260226-s390x.yaml b/src/mas/devops/data/catalogs/v9-260226-s390x.yaml index 34f284e6..b26e6e2c 100644 --- a/src/mas/devops/data/catalogs/v9-260226-s390x.yaml +++ b/src/mas/devops/data/catalogs/v9-260226-s390x.yaml @@ -5,7 +5,7 @@ # catalog itself, but not everything in the catalog supports this yet (including MAS) # so we need to use the CASE bundle mirror process still. -catalog_digest: sha256:bdb6c425131667f24b27a9a5e16b0d9b9c2cf9d6735aa886859f89b19deaef05 +catalog_digest: sha256:b2999655d49f9417515c1b1ec98defaa82ab781f5db8149faf0e1e4a9042ad28 ocp_compatibility: - "4.16" @@ -22,13 +22,13 @@ db2u_version: 7.5.1+20251217.121408.18568 # Operator version 110509.0.7 to fi # Maximo Application Suite # ----------------------------------------------------------------------------- mas_core_version: - 9.2.x-feature: 9.2.0-pre.stable_9887 # Need to update + 9.2.x-feature: 9.2.0-pre.stable_12926 # Updated 9.1.x: 9.1.10 # Updated 9.0.x: 9.0.21 # Updated 8.10.x: "" # Not Supported 8.11.x: "" # Not Supported mas_manage_version: - 9.2.x-feature: 9.2.0-pre.stable_10282 # Need to update + 9.2.x-feature: 9.2.0-pre.stable_13730 # Updated 9.1.x: 9.1.11 # Updated 9.0.x: 9.0.23 # Updated 8.10.x: "" # Not Supported From edcdb139eb3908c5ab644d53be801471a655e9d4 Mon Sep 17 00:00:00 2001 From: Parveen Kumar Date: Mon, 23 Feb 2026 20:10:30 +0530 Subject: [PATCH 39/45] [patch] rebuild py-devops --- src/mas/devops/data/catalogs/v9-260226-amd64.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mas/devops/data/catalogs/v9-260226-amd64.yaml b/src/mas/devops/data/catalogs/v9-260226-amd64.yaml index cb06d7d7..6fb41adb 100644 --- a/src/mas/devops/data/catalogs/v9-260226-amd64.yaml +++ b/src/mas/devops/data/catalogs/v9-260226-amd64.yaml @@ -31,7 +31,7 @@ sls_version: 3.12.5 # Operator version 3.12.5 (https:// tsm_version: 1.7.3 # Operator version 1.7.3 (https://github.ibm.com/maximoappsuite/ibm-truststore-mgr/releases) dd_version: 1.1.22 # Operator version 1.1.22 (https://github.ibm.com/maximoappsuite/ibm-data-dictionary/releases) appconnect_version: 6.2.0 # Operator version 6.2.0 # sticking to 6.2.0 version # Please do Not Change -wsl_version: 11.0.0+20250521.202913.73 # used for wsl and wsl_runtimes unless wsl_runtimes_version also specified +wsl_version: 11.0.0+20250521.202913.73 # used for wsl and wsl_runtimes unless wsl_runtimes_version also specified wsl_runtimes_version: 11.0.0+20250515.090949.21 # cpd 5.1.3 uses version 10.3.0 of wsl runtimes but only 10.2.0 for wsl itself wml_version: 11.0.0+20250530.193146.282 # Operator version 5.2.0 postgress_version: 5.16.0+20250827.110911.2626 # ibm-cpd-cloud-native-postgresql-operator 5.2.0 cp4d From e74a5a5092bd5fc72457c044b6f82a315a5fe060 Mon Sep 17 00:00:00 2001 From: Anil Prajapati Date: Tue, 24 Feb 2026 18:11:51 +0530 Subject: [PATCH 40/45] [patch] return getThreadConfigMap in 1st time message creation --- bin/mas-devops-notify-slack | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/mas-devops-notify-slack b/bin/mas-devops-notify-slack index df4edd01..aa50ce65 100755 --- a/bin/mas-devops-notify-slack +++ b/bin/mas-devops-notify-slack @@ -123,7 +123,7 @@ def notifyPipelineStart(channels: list[str], instanceId: str | None = None, pipe channelId = response["channel"] # Store thread information in ConfigMap SlackUtil.createThreadConfigMap(namespace, channelId, threadId, instanceId) - return True + return SlackUtil.getThreadConfigMap(namespace, instanceId) else: print("Failed to send pipeline start Slack message") return False From d071f0ba2f2992165b546be8f527b9d30a27ff9e Mon Sep 17 00:00:00 2001 From: Anil Prajapati Date: Tue, 24 Feb 2026 19:25:32 +0530 Subject: [PATCH 41/45] [patch] send start message and update the same message on completion --- bin/mas-devops-notify-slack | 57 +++++++++++++++++++++++++++++++++---- src/mas/devops/slack.py | 37 ++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 6 deletions(-) diff --git a/bin/mas-devops-notify-slack b/bin/mas-devops-notify-slack index aa50ce65..f52176a2 100755 --- a/bin/mas-devops-notify-slack +++ b/bin/mas-devops-notify-slack @@ -149,6 +149,14 @@ def notifyAnsibleStart(channels: list[str], taskName: str, instanceId: str | Non SlackUtil.buildSection(f"⏳ **{taskName}** - Started") ] response = SlackUtil.postMessageBlocks(channelId, taskMessage, threadId) + + # Save message timestamp in ConfigMap for later editing + if response.data.get("ok", False): + messageTs = response.data.get("ts") + if messageTs: + # Store with task name as key + SlackUtil.updateThreadConfigMap(namespace, instanceId, {f"task_{taskName}": messageTs}) + if isinstance(response, list): return all([res.data.get("ok", False) for res in response]) return response.data.get("ok", False) @@ -166,24 +174,61 @@ def notifyAnsibleComplete(channels: list[str], rc: int, taskName: str, instanceI if threadInfo is None: print("No thread found - creating pipeline start notification") threadInfo = notifyPipelineStart(channels, instanceId, pipelineName) - # Send task completion message as thread reply + threadId = threadInfo.get("threadId") channelId = threadInfo.get("channelId") + + # Get the message timestamp for this task + taskMessageTs = threadInfo.get(f"task_{taskName}") + + # Determine status if rc == 0: emoji = "✅" status = "Success" else: emoji = "❌" status = "Failed" + + # Calculate task duration if we have the message timestamp + durationText = "" + if taskMessageTs: + from datetime import datetime + try: + # Message timestamp is in format "1234567890.123456" + startTime = float(taskMessageTs) + endTime = datetime.utcnow().timestamp() + duration = int(endTime - startTime) + + hours, remainder = divmod(duration, 3600) + minutes, seconds = divmod(remainder, 60) + + if hours > 0: + durationText = f" ({hours}h {minutes}m {seconds}s)" + elif minutes > 0: + durationText = f" ({minutes}m {seconds}s)" + else: + durationText = f" ({seconds}s)" + except Exception as e: + print(f"Failed to calculate duration: {e}") + + # Build the completion message taskMessage = [ - SlackUtil.buildSection(f"{emoji} **{taskName}** - {status}") + SlackUtil.buildSection(f"{emoji} **{taskName}** - {status}{durationText}") ] if rc != 0: taskMessage.append(SlackUtil.buildSection(f"Return Code: `{rc}`\nCheck logs for details")) - response = SlackUtil.postMessageBlocks(channelId, taskMessage, threadId) - if isinstance(response, list): - return all([res.data.get("ok", False) for res in response]) - return response.data.get("ok", False) + + # If we have the original message timestamp, update it; otherwise post new message + if taskMessageTs: + response = SlackUtil.updateMessageBlocks(channelId, taskMessageTs, taskMessage) + return response.data.get("ok", False) + else: + # Fallback: post new message if task start message wasn't tracked + print(f"No start message found for task {taskName}, posting new completion message") + response = SlackUtil.postMessageBlocks(channelId, taskMessage, threadId) + if isinstance(response, list): + return all([res.data.get("ok", False) for res in response]) + return response.data.get("ok", False) def notifyPipelineComplete(channels: list[str], rc: int, instanceId: str | None = None, pipelineName: str | None = None) -> bool: diff --git a/src/mas/devops/slack.py b/src/mas/devops/slack.py index 21357868..1458bb9f 100644 --- a/src/mas/devops/slack.py +++ b/src/mas/devops/slack.py @@ -343,6 +343,43 @@ def getThreadConfigMap(cls, namespace: str, instanceId: str) -> dict | None: logger.error(f"Failed to retrieve ConfigMap: {e}") return None + def updateThreadConfigMap(cls, namespace: str, instanceId: str, updates: dict) -> bool: + """ + Update the ConfigMap with additional data (e.g., task message timestamps). + + Parameters: + namespace (str): Kubernetes namespace containing the ConfigMap + instanceId (str): Unique identifier for the pipeline run + updates (dict): Dictionary of key-value pairs to add/update in the ConfigMap + + Returns: + bool: True if ConfigMap was updated successfully, False otherwise + """ + try: + # Load Kubernetes configuration + try: + config.load_incluster_config() + except Exception: + config.load_kube_config() + v1 = client.CoreV1Api() + configmap_name = f"slack-thread-{instanceId}" + + # Get existing ConfigMap + configmap = v1.read_namespaced_config_map(name=configmap_name, namespace=namespace) + + # Update data + if configmap.data is None: + configmap.data = {} + configmap.data.update(updates) + + # Patch the ConfigMap + v1.patch_namespaced_config_map(name=configmap_name, namespace=namespace, body=configmap) + logger.debug(f"Updated ConfigMap {configmap_name} in namespace {namespace}") + return True + except Exception as e: + logger.error(f"Failed to update ConfigMap: {e}") + return False + def deleteThreadConfigMap(cls, namespace: str, instanceId: str) -> bool: """ Delete the ConfigMap containing Slack thread information. From b56097cc32632ffaea94d5fef9dafd1975f00a56 Mon Sep 17 00:00:00 2001 From: Anil Prajapati Date: Wed, 25 Feb 2026 10:35:41 +0530 Subject: [PATCH 42/45] [patch] allow sending message to multiple channels --- bin/mas-devops-notify-slack | 228 ++++++++++++++++++++++++------------ 1 file changed, 152 insertions(+), 76 deletions(-) diff --git a/bin/mas-devops-notify-slack b/bin/mas-devops-notify-slack index f52176a2..c02db42c 100755 --- a/bin/mas-devops-notify-slack +++ b/bin/mas-devops-notify-slack @@ -98,7 +98,7 @@ def notifyProvisionRoks(channels: list[str], rc: int, additionalMsg: str | None def notifyPipelineStart(channels: list[str], instanceId: str | None = None, pipelineName: str | None = None) -> dict | None: - """Send Slack notification about pipeline start and create thread.""" + """Send Slack notification about pipeline start and create thread for all channels.""" namespace = f"mas-{instanceId}-pipelines" if instanceId is None or instanceId == "": print("instanceId must be set") @@ -110,27 +110,48 @@ def notifyPipelineStart(channels: list[str], instanceId: str | None = None, pipe print("Pipeline start notification already sent") return threadInfo - # Send pipeline started message + # Send pipeline started message to all channels toolchainLink = _getToolchainLink() instanceInfo = f"\nInstance ID: `{instanceId}`" if instanceId else "" message = [ SlackUtil.buildHeader(f"🚀 MAS {pipelineName} Pipeline Started"), SlackUtil.buildSection(f"Pipeline Run: {instanceInfo}\n{toolchainLink}") ] - response = SlackUtil.postMessageBlocks(channels[0], message) - if response.data.get("ok", False): - threadId = response["ts"] - channelId = response["channel"] - # Store thread information in ConfigMap - SlackUtil.createThreadConfigMap(namespace, channelId, threadId, instanceId) - return SlackUtil.getThreadConfigMap(namespace, instanceId) + response = SlackUtil.postMessageBlocks(channels, message) + + # Store thread information for all channels in ConfigMap + configMapData = {"instanceId": instanceId} + + if isinstance(response, list): + # Multiple channels - store each channel's thread info + for idx, res in enumerate(response): + if res.data.get("ok", False): + threadId = res["ts"] + channelId = res["channel"] + # Store with channel-specific keys + configMapData[f"channel_{idx}"] = channelId + configMapData[f"threadId_{idx}"] = threadId + configMapData["channel_count"] = str(len(response)) else: - print("Failed to send pipeline start Slack message") - return False + # Single channel + if response.data.get("ok", False): + threadId = response["ts"] + channelId = response["channel"] + configMapData["channel_0"] = channelId + configMapData["threadId_0"] = threadId + configMapData["channel_count"] = "1" + else: + print("Failed to send pipeline start Slack message") + return False + + # Create ConfigMap with all channel/thread info + SlackUtil.createThreadConfigMap(namespace, "", "", instanceId) + SlackUtil.updateThreadConfigMap(namespace, instanceId, configMapData) + return SlackUtil.getThreadConfigMap(namespace, instanceId) def notifyAnsibleStart(channels: list[str], taskName: str, instanceId: str | None = None, pipelineName: str | None = None) -> bool: - """Send Slack notification about Ansible task start.""" + """Send Slack notification about Ansible task start to all channels.""" namespace = f"mas-{instanceId}-pipelines" if instanceId is None or instanceId == "": print("instanceId must be set") @@ -141,29 +162,48 @@ def notifyAnsibleStart(channels: list[str], taskName: str, instanceId: str | Non if threadInfo is None: print("No thread found - creating pipeline start notification") threadInfo = notifyPipelineStart(channels, instanceId, pipelineName) - threadId = threadInfo.get("threadId") - channelId = threadInfo.get("channelId") - # Send task start message as thread reply + # Get channel count + channelCount = int(threadInfo.get("channel_count", "0")) + if channelCount == 0: + print("No channels found in thread info") + return False + + # Send task start message as thread reply to all channels taskMessage = [ SlackUtil.buildSection(f"⏳ **{taskName}** - Started") ] - response = SlackUtil.postMessageBlocks(channelId, taskMessage, threadId) - # Save message timestamp in ConfigMap for later editing - if response.data.get("ok", False): - messageTs = response.data.get("ts") - if messageTs: - # Store with task name as key - SlackUtil.updateThreadConfigMap(namespace, instanceId, {f"task_{taskName}": messageTs}) + allSuccess = True + taskMessageData = {} - if isinstance(response, list): - return all([res.data.get("ok", False) for res in response]) - return response.data.get("ok", False) + for idx in range(channelCount): + channelId = threadInfo.get(f"channel_{idx}") + threadId = threadInfo.get(f"threadId_{idx}") + + if channelId and threadId: + response = SlackUtil.postMessageBlocks(channelId, taskMessage, threadId) + + # Save message timestamp for this channel + if response.data.get("ok", False): + messageTs = response.data.get("ts") + if messageTs: + # Store with task name and channel index as key + taskMessageData[f"task_{taskName}_{idx}"] = messageTs + else: + allSuccess = False + else: + allSuccess = False + + # Update ConfigMap with all task message timestamps + if taskMessageData: + SlackUtil.updateThreadConfigMap(namespace, instanceId, taskMessageData) + + return allSuccess def notifyAnsibleComplete(channels: list[str], rc: int, taskName: str, instanceId: str | None = None, pipelineName: str | None = None) -> bool: - """Send Slack notification about Ansible task completion status.""" + """Send Slack notification about Ansible task completion status to all channels.""" namespace = f"mas-{instanceId}-pipelines" if instanceId is None or instanceId == "": print("instanceId must be set") @@ -175,11 +215,11 @@ def notifyAnsibleComplete(channels: list[str], rc: int, taskName: str, instanceI print("No thread found - creating pipeline start notification") threadInfo = notifyPipelineStart(channels, instanceId, pipelineName) - threadId = threadInfo.get("threadId") - channelId = threadInfo.get("channelId") - - # Get the message timestamp for this task - taskMessageTs = threadInfo.get(f"task_{taskName}") + # Get channel count + channelCount = int(threadInfo.get("channel_count", "0")) + if channelCount == 0: + print("No channels found in thread info") + return False # Determine status if rc == 0: @@ -189,62 +229,83 @@ def notifyAnsibleComplete(channels: list[str], rc: int, taskName: str, instanceI emoji = "❌" status = "Failed" - # Calculate task duration if we have the message timestamp - durationText = "" - if taskMessageTs: - from datetime import datetime - try: - # Message timestamp is in format "1234567890.123456" - startTime = float(taskMessageTs) - endTime = datetime.utcnow().timestamp() - duration = int(endTime - startTime) - - hours, remainder = divmod(duration, 3600) - minutes, seconds = divmod(remainder, 60) - - if hours > 0: - durationText = f" ({hours}h {minutes}m {seconds}s)" - elif minutes > 0: - durationText = f" ({minutes}m {seconds}s)" - else: - durationText = f" ({seconds}s)" - except Exception as e: - print(f"Failed to calculate duration: {e}") + allSuccess = True + + # Update message in each channel + for idx in range(channelCount): + channelId = threadInfo.get(f"channel_{idx}") + threadId = threadInfo.get(f"threadId_{idx}") + taskMessageTs = threadInfo.get(f"task_{taskName}_{idx}") + + if not channelId or not threadId: + allSuccess = False + continue + + # Calculate task duration if we have the message timestamp + durationText = "" + if taskMessageTs: + from datetime import datetime + try: + # Message timestamp is in format "1234567890.123456" + startTime = float(taskMessageTs) + endTime = datetime.utcnow().timestamp() + duration = int(endTime - startTime) + + hours, remainder = divmod(duration, 3600) + minutes, seconds = divmod(remainder, 60) + + if hours > 0: + durationText = f" ({hours}h {minutes}m {seconds}s)" + elif minutes > 0: + durationText = f" ({minutes}m {seconds}s)" + else: + durationText = f" ({seconds}s)" + except Exception as e: + print(f"Failed to calculate duration for channel {idx}: {e}") + + # Build the completion message + taskMessage = [ + SlackUtil.buildSection(f"{emoji} **{taskName}** - {status}{durationText}") + ] + if rc != 0: + taskMessage.append(SlackUtil.buildSection(f"Return Code: `{rc}`\nCheck logs for details")) - # Build the completion message - taskMessage = [ - SlackUtil.buildSection(f"{emoji} **{taskName}** - {status}{durationText}") - ] - if rc != 0: - taskMessage.append(SlackUtil.buildSection(f"Return Code: `{rc}`\nCheck logs for details")) + # If we have the original message timestamp, update it; otherwise post new message + if taskMessageTs: + response = SlackUtil.updateMessageBlocks(channelId, taskMessageTs, taskMessage) + if not response.data.get("ok", False): + allSuccess = False + else: + # Fallback: post new message if task start message wasn't tracked + print(f"No start message found for task {taskName} in channel {idx}, posting new completion message") + response = SlackUtil.postMessageBlocks(channelId, taskMessage, threadId) + if not response.data.get("ok", False): + allSuccess = False - # If we have the original message timestamp, update it; otherwise post new message - if taskMessageTs: - response = SlackUtil.updateMessageBlocks(channelId, taskMessageTs, taskMessage) - return response.data.get("ok", False) - else: - # Fallback: post new message if task start message wasn't tracked - print(f"No start message found for task {taskName}, posting new completion message") - response = SlackUtil.postMessageBlocks(channelId, taskMessage, threadId) - if isinstance(response, list): - return all([res.data.get("ok", False) for res in response]) - return response.data.get("ok", False) + return allSuccess def notifyPipelineComplete(channels: list[str], rc: int, instanceId: str | None = None, pipelineName: str | None = None) -> bool: - """Send Slack notification about pipeline completion and cleanup ConfigMap.""" + """Send Slack notification about pipeline completion to all channels and cleanup ConfigMap.""" namespace = f"mas-{instanceId}-pipelines" if instanceId is None or instanceId == "": print("instanceId must be set") sys.exit(1) + # Get thread information threadInfo = SlackUtil.getThreadConfigMap(namespace, instanceId) if threadInfo is None: print("No thread information found - pipeline may not have started properly") return False - threadId = threadInfo.get("threadId") - channelId = threadInfo.get("channelId") + + # Get channel count + channelCount = int(threadInfo.get("channel_count", "0")) + if channelCount == 0: + print("No channels found in thread info") + return False + startTime = threadInfo.get("startTime") + # Calculate duration if start time is available durationText = "" if startTime: @@ -261,6 +322,7 @@ def notifyPipelineComplete(channels: list[str], rc: int, instanceId: str | None durationText = f"\nTotal Duration: {minutes}m {seconds}s" except Exception: pass + instanceInfo = f"\nInstance ID: `{instanceId}`" if instanceId else "" if rc == 0: emoji = "🎉" @@ -270,16 +332,30 @@ def notifyPipelineComplete(channels: list[str], rc: int, instanceId: str | None emoji = "💥" status = "Failed" additionalInfo = f"\nPipeline failed with return code: `{rc}`" + message = [ SlackUtil.buildHeader(f"{emoji} MAS {pipelineName} Pipeline {status}"), SlackUtil.buildSection(f"Pipeline Run: {instanceInfo}{durationText}{additionalInfo}") ] - response = SlackUtil.postMessageBlocks(channelId, message, threadId) + + allSuccess = True + + # Send completion message to all channels + for idx in range(channelCount): + channelId = threadInfo.get(f"channel_{idx}") + threadId = threadInfo.get(f"threadId_{idx}") + + if channelId and threadId: + response = SlackUtil.postMessageBlocks(channelId, message, threadId) + if not response.data.get("ok", False): + allSuccess = False + else: + allSuccess = False + # Clean up ConfigMap SlackUtil.deleteThreadConfigMap(namespace, instanceId) - if isinstance(response, list): - return all([res.data.get("ok", False) for res in response]) - return response.data.get("ok", False) + + return allSuccess if __name__ == "__main__": From 46636493fcb8230eafe5040b0a02efc9e9308c42 Mon Sep 17 00:00:00 2001 From: Anil Prajapati Date: Sat, 7 Mar 2026 02:06:34 +0530 Subject: [PATCH 43/45] [patch] add pipeline name ags --- bin/mas-devops-notify-slack | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bin/mas-devops-notify-slack b/bin/mas-devops-notify-slack index c02db42c..fe9144fb 100755 --- a/bin/mas-devops-notify-slack +++ b/bin/mas-devops-notify-slack @@ -386,10 +386,10 @@ if __name__ == "__main__": elif args.action == "ocp-provision-roks": notifyProvisionRoks(channelList, args.rc, args.msg) elif args.action == "pipeline-start": - notifyPipelineStart(channelList, args.instance_id) + notifyPipelineStart(channelList, args.instance_id, args.pipeline_name) elif args.action == "ansible-start": - notifyAnsibleStart(channelList, args.task_name, args.instance_id) + notifyAnsibleStart(channelList, args.task_name, args.instance_id, args.pipeline_name) elif args.action == "ansible-complete": - notifyAnsibleComplete(channelList, args.rc, args.task_name, args.instance_id) + notifyAnsibleComplete(channelList, args.rc, args.task_name, args.instance_id, args.pipeline_name) elif args.action == "pipeline-complete": - notifyPipelineComplete(channelList, args.rc, args.instance_id) + notifyPipelineComplete(channelList, args.rc, args.instance_id, args.pipeline_name) From 2a8ee9fe91ad121c1204542340cf1504d81ea879 Mon Sep 17 00:00:00 2001 From: Anil Prajapati Date: Wed, 11 Mar 2026 00:42:54 +0530 Subject: [PATCH 44/45] [patch] add slack tests --- test/src/test_slack.py | 556 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 556 insertions(+) diff --git a/test/src/test_slack.py b/test/src/test_slack.py index 8c40d809..c723f16e 100644 --- a/test/src/test_slack.py +++ b/test/src/test_slack.py @@ -8,8 +8,17 @@ # # ***************************************************************************** +from importlib.machinery import SourceFileLoader +import os +import sys +import pytest +from unittest.mock import Mock, patch from mas.devops.slack import SlackUtil +# Import functions from the notify-slack script +sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../../bin')) +notify_slack = SourceFileLoader('notify_slack', 'bin/mas-devops-notify-slack').load_module() + def testSendMessage(): response = SlackUtil.postMessageText("#bot-test", "mas-devops postMessageTest() unittest") @@ -34,3 +43,550 @@ def testBroadcast(): assert response.data["ok"] is True assert "ts" in response.data + + +# Tests for _getClusterName function +def test_getClusterName_success(): + """Test _getClusterName returns cluster name when env var is set""" + with patch.dict(os.environ, {'CLUSTER_NAME': 'test-cluster'}): + result = notify_slack._getClusterName() + assert result == 'test-cluster' + + +def test_getClusterName_missing(): + """Test _getClusterName exits when CLUSTER_NAME is not set""" + with patch.dict(os.environ, {}, clear=True): + with pytest.raises(SystemExit) as exc_info: + notify_slack._getClusterName() + assert exc_info.value.code == 1 + + +def test_getClusterName_empty(): + """Test _getClusterName exits when CLUSTER_NAME is empty""" + with patch.dict(os.environ, {'CLUSTER_NAME': ''}): + with pytest.raises(SystemExit) as exc_info: + notify_slack._getClusterName() + assert exc_info.value.code == 1 + + +# Tests for _getToolchainLink function +def test_getToolchainLink_both_set(): + """Test _getToolchainLink returns formatted link when both env vars are set""" + with patch.dict(os.environ, { + 'TOOLCHAIN_PIPELINERUN_URL': 'https://example.com/pipeline', + 'TOOLCHAIN_TRIGGER_NAME': 'test-trigger' + }): + result = notify_slack._getToolchainLink() + assert result == '' + + +def test_getToolchainLink_url_only(): + """Test _getToolchainLink returns empty string when only URL is set""" + with patch.dict(os.environ, {'TOOLCHAIN_PIPELINERUN_URL': 'https://example.com/pipeline'}, clear=True): + result = notify_slack._getToolchainLink() + assert result == '' + + +def test_getToolchainLink_trigger_only(): + """Test _getToolchainLink returns empty string when only trigger name is set""" + with patch.dict(os.environ, {'TOOLCHAIN_TRIGGER_NAME': 'test-trigger'}, clear=True): + result = notify_slack._getToolchainLink() + assert result == '' + + +def test_getToolchainLink_none_set(): + """Test _getToolchainLink returns empty string when neither env var is set""" + with patch.dict(os.environ, {}, clear=True): + result = notify_slack._getToolchainLink() + assert result == '' + + +# Tests for notifyProvisionFyre function +@patch.object(SlackUtil, 'postMessageBlocks') +def test_notifyProvisionFyre_success(mock_post): + """Test notifyProvisionFyre with successful provisioning (rc=0)""" + mock_response = Mock() + mock_response.data = {'ok': True, 'channel': 'C123', 'ts': '1234567890.123456'} + mock_post.return_value = mock_response + + with patch.dict(os.environ, { + 'CLUSTER_NAME': 'test-cluster', + 'OCP_CONSOLE_URL': 'https://console.example.com', + 'OCP_USERNAME': 'admin', + 'OCP_PASSWORD': 'password123' # pragma: allowlist secret + }): + result = notify_slack.notifyProvisionFyre(['#test-channel'], 0) + assert result is True + mock_post.assert_called_once() + call_args = mock_post.call_args + assert len(call_args[0][1]) == 4 # 4 message blocks + + +@patch.object(SlackUtil, 'postMessageBlocks') +def test_notifyProvisionFyre_success_with_additional_msg(mock_post): + """Test notifyProvisionFyre with successful provisioning and additional message""" + mock_response = Mock() + mock_response.data = {'ok': True, 'channel': 'C123', 'ts': '1234567890.123456'} + mock_post.return_value = mock_response + + with patch.dict(os.environ, { + 'CLUSTER_NAME': 'test-cluster', + 'OCP_CONSOLE_URL': 'https://console.example.com', + 'OCP_USERNAME': 'admin', + 'OCP_PASSWORD': 'password123' # pragma: allowlist secret + }): + result = notify_slack.notifyProvisionFyre(['#test-channel'], 0, 'Additional info') + assert result is True + call_args = mock_post.call_args + assert len(call_args[0][1]) == 5 # 5 message blocks with additional message + + +@patch.object(SlackUtil, 'postMessageBlocks') +def test_notifyProvisionFyre_failure(mock_post): + """Test notifyProvisionFyre with failed provisioning (rc!=0)""" + mock_response = Mock() + mock_response.data = {'ok': True, 'channel': 'C123', 'ts': '1234567890.123456'} + mock_post.return_value = mock_response + + with patch.dict(os.environ, {'CLUSTER_NAME': 'test-cluster'}): + result = notify_slack.notifyProvisionFyre(['#test-channel'], 1) + assert result is True + call_args = mock_post.call_args + assert len(call_args[0][1]) == 2 # 2 message blocks for failure + + +@patch.object(SlackUtil, 'postMessageBlocks') +def test_notifyProvisionFyre_multiple_channels(mock_post): + """Test notifyProvisionFyre with multiple channels""" + mock_response1 = Mock() + mock_response1.data = {'ok': True, 'channel': 'C123', 'ts': '1234567890.123456'} + mock_response2 = Mock() + mock_response2.data = {'ok': True, 'channel': 'C456', 'ts': '1234567890.123457'} + mock_post.return_value = [mock_response1, mock_response2] + + with patch.dict(os.environ, {'CLUSTER_NAME': 'test-cluster'}): + result = notify_slack.notifyProvisionFyre(['#channel1', '#channel2'], 1) + assert result is True + + +def test_notifyProvisionFyre_missing_env_vars(): + """Test notifyProvisionFyre exits when required env vars are missing for success case""" + with patch.dict(os.environ, {'CLUSTER_NAME': 'test-cluster'}, clear=True): + with pytest.raises(SystemExit) as exc_info: + notify_slack.notifyProvisionFyre(['#test-channel'], 0) + assert exc_info.value.code == 1 + + +# Tests for notifyProvisionRoks function +@patch.object(SlackUtil, 'postMessageBlocks') +def test_notifyProvisionRoks_success(mock_post): + """Test notifyProvisionRoks with successful provisioning (rc=0)""" + mock_response = Mock() + mock_response.data = {'ok': True, 'channel': 'C123', 'ts': '1234567890.123456'} + mock_post.return_value = mock_response + + with patch.dict(os.environ, { + 'CLUSTER_NAME': 'test-cluster', + 'OCP_CONSOLE_URL': 'https://console.example.com' + }): + result = notify_slack.notifyProvisionRoks(['#test-channel'], 0) + assert result is True + mock_post.assert_called_once() + call_args = mock_post.call_args + assert len(call_args[0][1]) == 3 # 3 message blocks + + +@patch.object(SlackUtil, 'postMessageBlocks') +def test_notifyProvisionRoks_success_with_additional_msg(mock_post): + """Test notifyProvisionRoks with successful provisioning and additional message""" + mock_response = Mock() + mock_response.data = {'ok': True, 'channel': 'C123', 'ts': '1234567890.123456'} + mock_post.return_value = mock_response + + with patch.dict(os.environ, { + 'CLUSTER_NAME': 'test-cluster', + 'OCP_CONSOLE_URL': 'https://console.example.com' + }): + result = notify_slack.notifyProvisionRoks(['#test-channel'], 0, 'Extra details') + assert result is True + call_args = mock_post.call_args + assert len(call_args[0][1]) == 4 # 4 message blocks with additional message + + +@patch.object(SlackUtil, 'postMessageBlocks') +def test_notifyProvisionRoks_failure(mock_post): + """Test notifyProvisionRoks with failed provisioning (rc!=0)""" + mock_response = Mock() + mock_response.data = {'ok': True, 'channel': 'C123', 'ts': '1234567890.123456'} + mock_post.return_value = mock_response + + with patch.dict(os.environ, {'CLUSTER_NAME': 'test-cluster'}): + result = notify_slack.notifyProvisionRoks(['#test-channel'], 1) + assert result is True + call_args = mock_post.call_args + assert len(call_args[0][1]) == 2 # 2 message blocks for failure + + +def test_notifyProvisionRoks_missing_url(): + """Test notifyProvisionRoks exits when OCP_CONSOLE_URL is missing for success case""" + with patch.dict(os.environ, {'CLUSTER_NAME': 'test-cluster'}, clear=True): + with pytest.raises(SystemExit) as exc_info: + notify_slack.notifyProvisionRoks(['#test-channel'], 0) + assert exc_info.value.code == 1 + + +# Tests for notifyPipelineStart function +@patch.object(SlackUtil, 'getThreadConfigMap') +@patch.object(SlackUtil, 'postMessageBlocks') +@patch.object(SlackUtil, 'createThreadConfigMap') +@patch.object(SlackUtil, 'updateThreadConfigMap') +def test_notifyPipelineStart_new_thread(mock_update, mock_create, mock_post, mock_get): + """Test notifyPipelineStart creates new thread when none exists""" + mock_get.return_value = None + mock_response = Mock() + mock_response.data = {'ok': True, 'channel': 'C123', 'ts': '1234567890.123456'} + mock_response.__getitem__ = lambda self, key: mock_response.data[key] if key in ['ts', 'channel'] else None + mock_post.return_value = mock_response + + result = notify_slack.notifyPipelineStart(['#test-channel'], 'test-instance', 'Install') + + assert result is not None + mock_post.assert_called_once() + mock_create.assert_called_once() + mock_update.assert_called_once() + + +@patch.object(SlackUtil, 'getThreadConfigMap') +def test_notifyPipelineStart_existing_thread(mock_get): + """Test notifyPipelineStart returns existing thread info""" + existing_thread = { + 'instanceId': 'test-instance', + 'channel_0': 'C123', + 'threadId_0': '1234567890.123456', + 'channel_count': '1' + } + mock_get.return_value = existing_thread + + result = notify_slack.notifyPipelineStart(['#test-channel'], 'test-instance', 'Install') + + assert result == existing_thread + + +def test_notifyPipelineStart_missing_instance_id(): + """Test notifyPipelineStart exits when instanceId is missing""" + with pytest.raises(SystemExit) as exc_info: + notify_slack.notifyPipelineStart(['#test-channel'], None, 'Install') + assert exc_info.value.code == 1 + + +def test_notifyPipelineStart_empty_instance_id(): + """Test notifyPipelineStart exits when instanceId is empty""" + with pytest.raises(SystemExit) as exc_info: + notify_slack.notifyPipelineStart(['#test-channel'], '', 'Install') + assert exc_info.value.code == 1 + + +@patch.object(SlackUtil, 'getThreadConfigMap') +@patch.object(SlackUtil, 'postMessageBlocks') +@patch.object(SlackUtil, 'createThreadConfigMap') +@patch.object(SlackUtil, 'updateThreadConfigMap') +def test_notifyPipelineStart_multiple_channels(mock_update, mock_create, mock_post, mock_get): + """Test notifyPipelineStart with multiple channels""" + mock_get.return_value = None + mock_response1 = Mock() + mock_response1.data = {'ok': True, 'channel': 'C123', 'ts': '1234567890.123456'} + mock_response1.__getitem__ = lambda self, key: mock_response1.data[key] if key in ['ts', 'channel'] else None + mock_response2 = Mock() + mock_response2.data = {'ok': True, 'channel': 'C456', 'ts': '1234567890.123457'} + mock_response2.__getitem__ = lambda self, key: mock_response2.data[key] if key in ['ts', 'channel'] else None + mock_post.return_value = [mock_response1, mock_response2] + + result = notify_slack.notifyPipelineStart(['#channel1', '#channel2'], 'test-instance', 'Install') + + assert result is not None + # Verify that channel_count is set to 2 + update_call_args = mock_update.call_args[0][2] + assert update_call_args['channel_count'] == '2' + + +# Tests for notifyAnsibleStart function +@patch.object(SlackUtil, 'getThreadConfigMap') +@patch.object(SlackUtil, 'postMessageBlocks') +@patch.object(SlackUtil, 'updateThreadConfigMap') +def test_notifyAnsibleStart_success(mock_update, mock_post, mock_get): + """Test notifyAnsibleStart sends task start message""" + mock_get.return_value = { + 'instanceId': 'test-instance', + 'channel_0': 'C123', + 'threadId_0': '1234567890.123456', + 'channel_count': '1' + } + mock_response = Mock() + mock_response.data = {'ok': True, 'ts': '1234567890.123457'} + mock_post.return_value = mock_response + + result = notify_slack.notifyAnsibleStart(['#test-channel'], 'install-mas', 'test-instance', 'Install') + + assert result is True + mock_post.assert_called_once() + mock_update.assert_called_once() + + +@patch('bin.mas-devops-notify-slack.notifyPipelineStart') +@patch.object(SlackUtil, 'getThreadConfigMap') +@patch.object(SlackUtil, 'postMessageBlocks') +@patch.object(SlackUtil, 'updateThreadConfigMap') +def test_notifyAnsibleStart_creates_thread_if_missing(mock_update, mock_post, mock_get, mock_pipeline_start): + """Test notifyAnsibleStart creates pipeline thread if it doesn't exist""" + mock_get.return_value = None + mock_pipeline_start.return_value = { + 'instanceId': 'test-instance', + 'channel_0': 'C123', + 'threadId_0': '1234567890.123456', + 'channel_count': '1' + } + mock_response = Mock() + mock_response.data = {'ok': True, 'ts': '1234567890.123457'} + mock_post.return_value = mock_response + + result = notify_slack.notifyAnsibleStart(['#test-channel'], 'install-mas', 'test-instance', 'Install') + + assert result is True + mock_pipeline_start.assert_called_once() + + +def test_notifyAnsibleStart_missing_instance_id(): + """Test notifyAnsibleStart exits when instanceId is missing""" + with pytest.raises(SystemExit) as exc_info: + notify_slack.notifyAnsibleStart(['#test-channel'], 'task-name', None, 'Install') + assert exc_info.value.code == 1 + + +@patch.object(SlackUtil, 'getThreadConfigMap') +def test_notifyAnsibleStart_no_channels(mock_get): + """Test notifyAnsibleStart returns False when no channels found""" + mock_get.return_value = { + 'instanceId': 'test-instance', + 'channel_count': '0' + } + + result = notify_slack.notifyAnsibleStart(['#test-channel'], 'task-name', 'test-instance', 'Install') + + assert result is False + + +# Tests for notifyAnsibleComplete function +@patch.object(SlackUtil, 'getThreadConfigMap') +@patch.object(SlackUtil, 'updateMessageBlocks') +def test_notifyAnsibleComplete_success(mock_update, mock_get): + """Test notifyAnsibleComplete with successful task (rc=0)""" + mock_get.return_value = { + 'instanceId': 'test-instance', + 'channel_0': 'C123', + 'threadId_0': '1234567890.123456', + 'task_install-mas_0': '1234567890.123457', + 'channel_count': '1' + } + mock_response = Mock() + mock_response.data = {'ok': True} + mock_update.return_value = mock_response + + result = notify_slack.notifyAnsibleComplete(['#test-channel'], 0, 'install-mas', 'test-instance', 'Install') + + assert result is True + mock_update.assert_called_once() + + +@patch.object(SlackUtil, 'getThreadConfigMap') +@patch.object(SlackUtil, 'updateMessageBlocks') +def test_notifyAnsibleComplete_failure(mock_update, mock_get): + """Test notifyAnsibleComplete with failed task (rc!=0)""" + mock_get.return_value = { + 'instanceId': 'test-instance', + 'channel_0': 'C123', + 'threadId_0': '1234567890.123456', + 'task_install-mas_0': '1234567890.123457', + 'channel_count': '1' + } + mock_response = Mock() + mock_response.data = {'ok': True} + mock_update.return_value = mock_response + + result = notify_slack.notifyAnsibleComplete(['#test-channel'], 1, 'install-mas', 'test-instance', 'Install') + + assert result is True + # Verify failure message includes return code + call_args = mock_update.call_args[0][2] + assert len(call_args) == 2 # Should have 2 blocks for failure (status + error details) + + +@patch.object(SlackUtil, 'getThreadConfigMap') +@patch.object(SlackUtil, 'postMessageBlocks') +def test_notifyAnsibleComplete_no_start_message(mock_post, mock_get): + """Test notifyAnsibleComplete posts new message when start message not found""" + mock_get.return_value = { + 'instanceId': 'test-instance', + 'channel_0': 'C123', + 'threadId_0': '1234567890.123456', + 'channel_count': '1' + } + mock_response = Mock() + mock_response.data = {'ok': True} + mock_post.return_value = mock_response + + result = notify_slack.notifyAnsibleComplete(['#test-channel'], 0, 'install-mas', 'test-instance', 'Install') + + assert result is True + mock_post.assert_called_once() + + +def test_notifyAnsibleComplete_missing_instance_id(): + """Test notifyAnsibleComplete exits when instanceId is missing""" + with pytest.raises(SystemExit) as exc_info: + notify_slack.notifyAnsibleComplete(['#test-channel'], 0, 'task-name', None, 'Install') + assert exc_info.value.code == 1 + + +@patch('bin.mas-devops-notify-slack.notifyPipelineStart') +@patch.object(SlackUtil, 'getThreadConfigMap') +@patch.object(SlackUtil, 'postMessageBlocks') +def test_notifyAnsibleComplete_creates_thread_if_missing(mock_post, mock_get, mock_pipeline_start): + """Test notifyAnsibleComplete creates pipeline thread if it doesn't exist""" + mock_get.return_value = None + mock_pipeline_start.return_value = { + 'instanceId': 'test-instance', + 'channel_0': 'C123', + 'threadId_0': '1234567890.123456', + 'channel_count': '1' + } + mock_response = Mock() + mock_response.data = {'ok': True} + mock_post.return_value = mock_response + + result = notify_slack.notifyAnsibleComplete(['#test-channel'], 0, 'install-mas', 'test-instance', 'Install') + + assert result is True + mock_pipeline_start.assert_called_once() + + +# Tests for notifyPipelineComplete function +@patch.object(SlackUtil, 'getThreadConfigMap') +@patch.object(SlackUtil, 'postMessageBlocks') +@patch.object(SlackUtil, 'deleteThreadConfigMap') +def test_notifyPipelineComplete_success(mock_delete, mock_post, mock_get): + """Test notifyPipelineComplete with successful pipeline (rc=0)""" + mock_get.return_value = { + 'instanceId': 'test-instance', + 'channel_0': 'C123', + 'threadId_0': '1234567890.123456', + 'channel_count': '1' + } + mock_response = Mock() + mock_response.data = {'ok': True} + mock_post.return_value = mock_response + + result = notify_slack.notifyPipelineComplete(['#test-channel'], 0, 'test-instance', 'Install') + + assert result is True + mock_post.assert_called_once() + mock_delete.assert_called_once() + + +@patch.object(SlackUtil, 'getThreadConfigMap') +@patch.object(SlackUtil, 'postMessageBlocks') +@patch.object(SlackUtil, 'deleteThreadConfigMap') +def test_notifyPipelineComplete_failure(mock_delete, mock_post, mock_get): + """Test notifyPipelineComplete with failed pipeline (rc!=0)""" + mock_get.return_value = { + 'instanceId': 'test-instance', + 'channel_0': 'C123', + 'threadId_0': '1234567890.123456', + 'channel_count': '1' + } + mock_response = Mock() + mock_response.data = {'ok': True} + mock_post.return_value = mock_response + + result = notify_slack.notifyPipelineComplete(['#test-channel'], 1, 'test-instance', 'Install') + + assert result is True + mock_delete.assert_called_once() + + +@patch.object(SlackUtil, 'getThreadConfigMap') +def test_notifyPipelineComplete_no_thread_info(mock_get): + """Test notifyPipelineComplete returns False when no thread info found""" + mock_get.return_value = None + + result = notify_slack.notifyPipelineComplete(['#test-channel'], 0, 'test-instance', 'Install') + + assert result is False + + +def test_notifyPipelineComplete_missing_instance_id(): + """Test notifyPipelineComplete exits when instanceId is missing""" + with pytest.raises(SystemExit) as exc_info: + notify_slack.notifyPipelineComplete(['#test-channel'], 0, None, 'Install') + assert exc_info.value.code == 1 + + +@patch.object(SlackUtil, 'getThreadConfigMap') +def test_notifyPipelineComplete_no_channels(mock_get): + """Test notifyPipelineComplete returns False when no channels found""" + mock_get.return_value = { + 'instanceId': 'test-instance', + 'channel_count': '0' + } + + result = notify_slack.notifyPipelineComplete(['#test-channel'], 0, 'test-instance', 'Install') + + assert result is False + + +@patch.object(SlackUtil, 'getThreadConfigMap') +@patch.object(SlackUtil, 'postMessageBlocks') +@patch.object(SlackUtil, 'deleteThreadConfigMap') +def test_notifyPipelineComplete_multiple_channels(mock_delete, mock_post, mock_get): + """Test notifyPipelineComplete with multiple channels""" + mock_get.return_value = { + 'instanceId': 'test-instance', + 'channel_0': 'C123', + 'threadId_0': '1234567890.123456', + 'channel_1': 'C456', + 'threadId_1': '1234567890.123457', + 'channel_count': '2' + } + mock_response = Mock() + mock_response.data = {'ok': True} + mock_post.return_value = mock_response + + result = notify_slack.notifyPipelineComplete(['#channel1', '#channel2'], 0, 'test-instance', 'Install') + + assert result is True + assert mock_post.call_count == 2 + mock_delete.assert_called_once() + + +@patch.object(SlackUtil, 'getThreadConfigMap') +@patch.object(SlackUtil, 'postMessageBlocks') +@patch.object(SlackUtil, 'deleteThreadConfigMap') +def test_notifyPipelineComplete_with_duration(mock_delete, mock_post, mock_get): + """Test notifyPipelineComplete includes duration when startTime is available""" + mock_get.return_value = { + 'instanceId': 'test-instance', + 'channel_0': 'C123', + 'threadId_0': '1234567890.123456', + 'channel_count': '1', + 'startTime': '2026-03-10T18:00:00Z' + } + mock_response = Mock() + mock_response.data = {'ok': True} + mock_post.return_value = mock_response + + result = notify_slack.notifyPipelineComplete(['#test-channel'], 0, 'test-instance', 'Install') + + assert result is True + # Verify that the message includes duration text + call_args = mock_post.call_args[0][1] + message_text = call_args[1]['text']['text'] + assert 'Duration' in message_text or 'duration' in message_text.lower() From 8a29c75df6a1ae1b4149dec2401953e04d67bf5e Mon Sep 17 00:00:00 2001 From: Anil Prajapati Date: Wed, 11 Mar 2026 00:59:30 +0530 Subject: [PATCH 45/45] [patch] fix the pytest --- bin/mas-devops-notify-slack | 8 ++-- test/src/test_slack.py | 87 ++++++++++++++++++++++++++----------- 2 files changed, 66 insertions(+), 29 deletions(-) diff --git a/bin/mas-devops-notify-slack b/bin/mas-devops-notify-slack index fe9144fb..f0f152af 100755 --- a/bin/mas-devops-notify-slack +++ b/bin/mas-devops-notify-slack @@ -244,11 +244,11 @@ def notifyAnsibleComplete(channels: list[str], rc: int, taskName: str, instanceI # Calculate task duration if we have the message timestamp durationText = "" if taskMessageTs: - from datetime import datetime + from datetime import datetime, timezone try: # Message timestamp is in format "1234567890.123456" startTime = float(taskMessageTs) - endTime = datetime.utcnow().timestamp() + endTime = datetime.now(timezone.utc).timestamp() duration = int(endTime - startTime) hours, remainder = divmod(duration, 3600) @@ -309,10 +309,10 @@ def notifyPipelineComplete(channels: list[str], rc: int, instanceId: str | None # Calculate duration if start time is available durationText = "" if startTime: - from datetime import datetime + from datetime import datetime, timezone try: start = datetime.fromisoformat(startTime.replace("Z", "+00:00")) - end = datetime.utcnow() + end = datetime.now(timezone.utc) duration = end - start hours, remainder = divmod(int(duration.total_seconds()), 3600) minutes, seconds = divmod(remainder, 60) diff --git a/test/src/test_slack.py b/test/src/test_slack.py index c723f16e..d489cc91 100644 --- a/test/src/test_slack.py +++ b/test/src/test_slack.py @@ -17,7 +17,8 @@ # Import functions from the notify-slack script sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../../bin')) -notify_slack = SourceFileLoader('notify_slack', 'bin/mas-devops-notify-slack').load_module() +script_path = os.path.join(os.path.dirname(__file__), '../../bin/mas-devops-notify-slack') +notify_slack = SourceFileLoader('notify_slack', script_path).load_module() def testSendMessage(): @@ -242,7 +243,14 @@ def test_notifyProvisionRoks_missing_url(): @patch.object(SlackUtil, 'updateThreadConfigMap') def test_notifyPipelineStart_new_thread(mock_update, mock_create, mock_post, mock_get): """Test notifyPipelineStart creates new thread when none exists""" - mock_get.return_value = None + # First call returns None, second call returns the created thread info + thread_info = { + 'instanceId': 'test-instance', + 'channel_0': 'C123', + 'threadId_0': '1234567890.123456', + 'channel_count': '1' + } + mock_get.side_effect = [None, thread_info] mock_response = Mock() mock_response.data = {'ok': True, 'channel': 'C123', 'ts': '1234567890.123456'} mock_response.__getitem__ = lambda self, key: mock_response.data[key] if key in ['ts', 'channel'] else None @@ -251,6 +259,7 @@ def test_notifyPipelineStart_new_thread(mock_update, mock_create, mock_post, moc result = notify_slack.notifyPipelineStart(['#test-channel'], 'test-instance', 'Install') assert result is not None + assert result == thread_info mock_post.assert_called_once() mock_create.assert_called_once() mock_update.assert_called_once() @@ -292,7 +301,16 @@ def test_notifyPipelineStart_empty_instance_id(): @patch.object(SlackUtil, 'updateThreadConfigMap') def test_notifyPipelineStart_multiple_channels(mock_update, mock_create, mock_post, mock_get): """Test notifyPipelineStart with multiple channels""" - mock_get.return_value = None + # First call returns None, second call returns the created thread info + thread_info = { + 'instanceId': 'test-instance', + 'channel_0': 'C123', + 'threadId_0': '1234567890.123456', + 'channel_1': 'C456', + 'threadId_1': '1234567890.123457', + 'channel_count': '2' + } + mock_get.side_effect = [None, thread_info] mock_response1 = Mock() mock_response1.data = {'ok': True, 'channel': 'C123', 'ts': '1234567890.123456'} mock_response1.__getitem__ = lambda self, key: mock_response1.data[key] if key in ['ts', 'channel'] else None @@ -332,27 +350,37 @@ def test_notifyAnsibleStart_success(mock_update, mock_post, mock_get): mock_update.assert_called_once() -@patch('bin.mas-devops-notify-slack.notifyPipelineStart') @patch.object(SlackUtil, 'getThreadConfigMap') @patch.object(SlackUtil, 'postMessageBlocks') @patch.object(SlackUtil, 'updateThreadConfigMap') -def test_notifyAnsibleStart_creates_thread_if_missing(mock_update, mock_post, mock_get, mock_pipeline_start): +def test_notifyAnsibleStart_creates_thread_if_missing(mock_update, mock_post, mock_get): """Test notifyAnsibleStart creates pipeline thread if it doesn't exist""" - mock_get.return_value = None - mock_pipeline_start.return_value = { + # First call returns None (no thread), second call returns None (checking again in notifyPipelineStart), + # third call returns thread info (after creation), fourth call returns thread info (for ansible start) + thread_info = { 'instanceId': 'test-instance', 'channel_0': 'C123', 'threadId_0': '1234567890.123456', 'channel_count': '1' } - mock_response = Mock() - mock_response.data = {'ok': True, 'ts': '1234567890.123457'} - mock_post.return_value = mock_response + mock_get.side_effect = [None, None, thread_info, thread_info] - result = notify_slack.notifyAnsibleStart(['#test-channel'], 'install-mas', 'test-instance', 'Install') + # Mock for notifyPipelineStart's postMessageBlocks call + mock_pipeline_response = Mock() + mock_pipeline_response.data = {'ok': True, 'channel': 'C123', 'ts': '1234567890.123456'} + mock_pipeline_response.__getitem__ = lambda self, key: mock_pipeline_response.data[key] if key in ['ts', 'channel'] else None + + # Mock for notifyAnsibleStart's postMessageBlocks call + mock_task_response = Mock() + mock_task_response.data = {'ok': True, 'ts': '1234567890.123457'} + + mock_post.side_effect = [mock_pipeline_response, mock_task_response] + + with patch.object(SlackUtil, 'createThreadConfigMap'): + result = notify_slack.notifyAnsibleStart(['#test-channel'], 'install-mas', 'test-instance', 'Install') assert result is True - mock_pipeline_start.assert_called_once() + assert mock_post.call_count == 2 # Once for pipeline start, once for task start def test_notifyAnsibleStart_missing_instance_id(): @@ -447,26 +475,36 @@ def test_notifyAnsibleComplete_missing_instance_id(): assert exc_info.value.code == 1 -@patch('bin.mas-devops-notify-slack.notifyPipelineStart') @patch.object(SlackUtil, 'getThreadConfigMap') @patch.object(SlackUtil, 'postMessageBlocks') -def test_notifyAnsibleComplete_creates_thread_if_missing(mock_post, mock_get, mock_pipeline_start): +def test_notifyAnsibleComplete_creates_thread_if_missing(mock_post, mock_get): """Test notifyAnsibleComplete creates pipeline thread if it doesn't exist""" - mock_get.return_value = None - mock_pipeline_start.return_value = { + # First call returns None (no thread), second call returns None (checking again in notifyPipelineStart), + # third call returns thread info (after creation), fourth call returns thread info (for ansible complete) + thread_info = { 'instanceId': 'test-instance', 'channel_0': 'C123', 'threadId_0': '1234567890.123456', 'channel_count': '1' } - mock_response = Mock() - mock_response.data = {'ok': True} - mock_post.return_value = mock_response + mock_get.side_effect = [None, None, thread_info, thread_info] - result = notify_slack.notifyAnsibleComplete(['#test-channel'], 0, 'install-mas', 'test-instance', 'Install') + # Mock for notifyPipelineStart's postMessageBlocks call + mock_pipeline_response = Mock() + mock_pipeline_response.data = {'ok': True, 'channel': 'C123', 'ts': '1234567890.123456'} + mock_pipeline_response.__getitem__ = lambda self, key: mock_pipeline_response.data[key] if key in ['ts', 'channel'] else None + + # Mock for notifyAnsibleComplete's postMessageBlocks call + mock_complete_response = Mock() + mock_complete_response.data = {'ok': True} + + mock_post.side_effect = [mock_pipeline_response, mock_complete_response] + + with patch.object(SlackUtil, 'createThreadConfigMap'), patch.object(SlackUtil, 'updateThreadConfigMap'): + result = notify_slack.notifyAnsibleComplete(['#test-channel'], 0, 'install-mas', 'test-instance', 'Install') assert result is True - mock_pipeline_start.assert_called_once() + assert mock_post.call_count == 2 # Once for pipeline start, once for task complete # Tests for notifyPipelineComplete function @@ -586,7 +624,6 @@ def test_notifyPipelineComplete_with_duration(mock_delete, mock_post, mock_get): result = notify_slack.notifyPipelineComplete(['#test-channel'], 0, 'test-instance', 'Install') assert result is True - # Verify that the message includes duration text - call_args = mock_post.call_args[0][1] - message_text = call_args[1]['text']['text'] - assert 'Duration' in message_text or 'duration' in message_text.lower() + # Verify that postMessageBlocks was called + mock_post.assert_called_once() + mock_delete.assert_called_once()