From 5cb291c4e04c258f807368d7c6e7afba2cd5e76e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Du=C5=A1ek?= Date: Mon, 17 Jun 2024 10:14:20 +0200 Subject: [PATCH 01/34] Convert cpadminservice to real user MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan Dušek --- .../cp4ba/common/tasks/iam-token-client.yml | 39 --------- .../cp4ba/cp4ba-core/tasks/postdeploy/odm.yml | 21 +---- .../cp4ba/cp4ba-core/tasks/postdeploy/zen.yml | 79 ++----------------- .../cp4ba-core/templates/postdeploy.md.j2 | 4 +- .../openldap/templates/configmaps.yaml.j2 | 12 +++ .../usage/templates/usage-configmap.yaml.j2 | 4 +- .../cp4ba/usage/templates/usage.md.j2 | 4 +- 7 files changed, 26 insertions(+), 137 deletions(-) delete mode 100644 automation-roles/50-install-cloud-pak/cp4ba/common/tasks/iam-token-client.yml diff --git a/automation-roles/50-install-cloud-pak/cp4ba/common/tasks/iam-token-client.yml b/automation-roles/50-install-cloud-pak/cp4ba/common/tasks/iam-token-client.yml deleted file mode 100644 index d77b76aba..000000000 --- a/automation-roles/50-install-cloud-pak/cp4ba/common/tasks/iam-token-client.yml +++ /dev/null @@ -1,39 +0,0 @@ -# Example of the functionality call -# Based on https://www.ibm.com/docs/en/cpfs?topic=apis-oidc-registration#get2 (Get access token by using username and password) -# -# - name: Get IAM token -# ansible.builtin.include_role: -# name: common -# tasks_from: iam-token -# vars: -# common_cpfs_project: _cpfs_project -# common_client_id: _client_id -# common_client_secret: _client_secret -# common_output_to_var: "iam_token" - -- name: Get OCP Apps domain - ansible.builtin.include_role: - name: common - tasks_from: apps-endpoint - vars: - common_output_to_var: "apps_endpoint_domain" - -- name: Get IAM access token - ansible.builtin.uri: - url: "https://cp-console-{{ common_cpfs_project }}.{{ apps_endpoint_domain }}/idprovider/v1/auth/identitytoken" - method: POST - headers: - Content-Type: application/x-www-form-urlencoded;charset=UTF-8 - body_format: form-urlencoded - body: - grant_type: client_credentials - client_id: "{{ common_client_id }}" - client_secret: "{{ common_client_secret }}" - scope: openid - validate_certs: false - status_code: 200 - register: token_response - -- name: Set apps endpoint - ansible.builtin.set_fact: - "{{ common_output_to_var }}": "{{ token_response | json_query('json.access_token') }}" diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/odm.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/odm.yml index b6a27f84d..1a198c16e 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/odm.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/odm.yml @@ -98,24 +98,6 @@ failed_when: group_response.status == 500 and group_response.json | json_query('exception') is not search('.*duplicate key value*') with_items: "{{ lc_general_groups }}" -- name: Add ODM Admin role to service user - ansible.builtin.uri: - url: "https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/usermgmt/v1/user/cpadminservice?add_roles=true" - method: PUT - headers: - Authorization: "Bearer {{ zen_token }}" - body_format: json - body: - username: cpadminservice - user_roles: - - odm_admin_role - - odm_runtime_admin_role - - odm_runtime_user_role - - odm_business_user_role - validate_certs: false - status_code: - - 200 - - name: Regenerate Zen token for new permissions ansible.builtin.include_role: name: common @@ -154,7 +136,8 @@ - name: Find zen api key ansible.builtin.set_fact: - zen_api_key: "{{ usage.resources[0].data['zen-api-key'] if usage.resources | length != 0 and usage.resources[0].data['zen-api-key'] is defined }}" + zen_api_key: "{{ usage.resources[0].data['cpadminservice-zen-api-key'] + if usage.resources | length != 0 and usage.resources[0].data['cpadminservice-zen-api-key'] is defined }}" - name: Update credentials for server ansible.builtin.uri: diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/zen.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/zen.yml index 996c84d2f..2b0f1aba1 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/zen.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/zen.yml @@ -324,76 +324,6 @@ common_password: "{{ cp4ba_universal_password }}" common_output_to_var: "iam_token" -# Based on https://www.ibm.com/docs/en/cpfs?topic=apis-oidc-registration#register -- name: Add service client to IAM - ansible.builtin.uri: - url: "https://cp-console-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/idprovider/v1/auth/registration" - method: POST - headers: - Authorization: Bearer {{ iam_token }} - body_format: json - body: - { - "client_id": "cpadminservice", - "client_name": "cpadminservice", - "client_secret": "{{ cp4ba_universal_password }}", - "scope": "openid profile email", - "preauthorized_scope": "openid profile email", - "introspect_tokens": true, - "proofKeyForCodeExchange": true, - "response_types": [ - "code", - "token", - "id_token token" - ], - "grant_types": [ - "authorization_code", - "client_credentials", - "implicit", - "refresh_token", - "urn:ietf:params:oauth:grant-type:jwt-bearer", - "password" - ], - "allow_regexp_redirects":true, - "redirect_uris": [ - "regexp:https://.*/oidcclient/redirect/.*" - ], - "appTokenAllowed": true, - "application_type": "web", - "subject_type": "public" - } - validate_certs: false - status_code: - - 201 - - 400 - register: client_response - failed_when: client_response.status == 400 and client_response.json | json_query('error_description') is not search('.*already exists.*') - - -- name: Add cpadminservice to zen - ansible.builtin.uri: - url: "https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/usermgmt/v1/user" - method: POST - headers: - Content-Type: application/json - Authorization: "Bearer {{ zen_token }}" - body_format: json - body: - username: cpadminservice - displayName: cpadminservice - user_roles: - - zen_administrator_role - - iaf-automation-admin - - iaf-automation-analyst - - iaf-automation-developer - - iaf-automation-operator - - zen_user_role - validate_certs: false - status_code: - - 201 - - 409 - register: cpadminservice_response - - name: Get Usage configmap kubernetes.core.k8s_info: api_version: v1 @@ -406,7 +336,8 @@ - name: Find zen api key ansible.builtin.set_fact: - zen_api_key: "{{ usage.resources[0].data['zen-api-key'] if usage.resources | length != 0 and usage.resources[0].data['zen-api-key'] is defined }}" + zen_api_key: "{{ usage.resources[0].data['cpadminservice-zen-api-key'] + if usage.resources | length != 0 and usage.resources[0].data['cpadminservice-zen-api-key'] is defined }}" - name: Generate new Zen Api key when: zen_api_key | length == 0 @@ -414,11 +345,11 @@ - name: Get IAM token ansible.builtin.include_role: name: common - tasks_from: iam-token-client + tasks_from: iam-token-user vars: common_cpfs_project: "{{ cp4ba_project_name }}" - common_client_id: "cpadminservice" - common_client_secret: "{{ cp4ba_universal_password }}" + common_user: "cpadminservice" + common_password: "{{ cp4ba_universal_password }}" common_output_to_var: "iam_token" - name: Get Zen token diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/postdeploy.md.j2 b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/postdeploy.md.j2 index 3250f9bff..7d3b9a687 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/postdeploy.md.j2 +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/postdeploy.md.j2 @@ -122,13 +122,13 @@ When configuring RES connection in Deployment use URL: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/odm/res Method: Zen API Key UserID: cpadminservice -API Key: As found in Project cloud-pak-deployer, ConfigMap {{ cp4ba_project_name }}-usage, key zen-api-key +API Key: As found in Project cloud-pak-deployer, ConfigMap {{ cp4ba_project_name }}-usage, key cpadminservice-zen-api-key When configuring Decision Center use URL: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/odm/decisioncenter Authentication: Zen API Key User ID: cpadminservice -API Key: As found in Project cloud-pak-deployer, ConfigMap {{ cp4ba_project_name }}-usage, key zen-api-key +API Key: As found in Project cloud-pak-deployer, ConfigMap {{ cp4ba_project_name }}-usage, key cpadminservice-zen-api-key ## Automation Decision Services (ADS) (decisions_ads pattern) diff --git a/automation-roles/50-install-cloud-pak/cp4ba/openldap/templates/configmaps.yaml.j2 b/automation-roles/50-install-cloud-pak/cp4ba/openldap/templates/configmaps.yaml.j2 index 0430f22e0..cda8458f0 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/openldap/templates/configmaps.yaml.j2 +++ b/automation-roles/50-install-cloud-pak/cp4ba/openldap/templates/configmaps.yaml.j2 @@ -68,6 +68,16 @@ data: userpassword:: {{ universal_password | b64encode }} employeeType: admin + dn: {{ lc_ldap_user_id_attribute }}=cpadminservice,{{ lc_ldap_user_base_dn }} + objectClass: inetOrgPerson + objectClass: top + cn: cpadminservice + sn: cpadminservice + uid: cpadminservice + mail: cpadminservice@{{ lc_ldap_domain }} + userpassword:: {{ universal_password | b64encode }} + employeeType: admin + dn: {{ lc_ldap_user_id_attribute }}=cpuser,{{ lc_ldap_user_base_dn }} objectClass: {{ lc_ldap_user_object_class }} objectClass: top @@ -103,6 +113,7 @@ data: member: {{ lc_ldap_user_id_attribute }}={{ lc_principal_admin_user }},{{ lc_ldap_user_base_dn }} member: {{ lc_ldap_user_id_attribute }}=cpadmin1,{{ lc_ldap_user_base_dn }} member: {{ lc_ldap_user_id_attribute }}=cpadmin2,{{ lc_ldap_user_base_dn }} + member: {{ lc_ldap_user_id_attribute }}=cpadminservice,{{ lc_ldap_user_base_dn }} dn: {{ lc_ldap_group_id_attribute }}=cpusers,{{ lc_ldap_group_base_dn }} objectClass: {{ lc_ldap_group_object_class }} @@ -111,6 +122,7 @@ data: member: {{ lc_ldap_user_id_attribute }}=cpadmin,{{ lc_ldap_user_base_dn }} member: {{ lc_ldap_user_id_attribute }}=cpadmin1,{{ lc_ldap_user_base_dn }} member: {{ lc_ldap_user_id_attribute }}=cpadmin2,{{ lc_ldap_user_base_dn }} + member: {{ lc_ldap_user_id_attribute }}=cpadminservice,{{ lc_ldap_user_base_dn }} member: {{ lc_ldap_user_id_attribute }}=cpuser,{{ lc_ldap_user_base_dn }} member: {{ lc_ldap_user_id_attribute }}=cpuser1,{{ lc_ldap_user_base_dn }} member: {{ lc_ldap_user_id_attribute }}=cpuser2,{{ lc_ldap_user_base_dn }} diff --git a/automation-roles/50-install-cloud-pak/cp4ba/usage/templates/usage-configmap.yaml.j2 b/automation-roles/50-install-cloud-pak/cp4ba/usage/templates/usage-configmap.yaml.j2 index 798e1882c..afdde12a0 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/usage/templates/usage-configmap.yaml.j2 +++ b/automation-roles/50-install-cloud-pak/cp4ba/usage/templates/usage-configmap.yaml.j2 @@ -7,5 +7,7 @@ data: usage.md: |- {{ lookup('file', usage_path) | indent(4) }} {% if zen_api_key_new is defined %} - zen-api-key: {{ zen_api_key_new }} + cpadminservice-zen-api-key: |- + Zen API key for cpadminservice user as generated in the UI: {{ zen_api_key_new }} + Zen API key for cpadminservice user in the form of header: ZenApiKey {{ 'cpadminservice:' + zen_api_key_new | b64encode }} {% endif %} \ No newline at end of file diff --git a/automation-roles/50-install-cloud-pak/cp4ba/usage/templates/usage.md.j2 b/automation-roles/50-install-cloud-pak/cp4ba/usage/templates/usage.md.j2 index cb7e70f57..9cff507eb 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/usage/templates/usage.md.j2 +++ b/automation-roles/50-install-cloud-pak/cp4ba/usage/templates/usage.md.j2 @@ -170,8 +170,8 @@ As DB UI for PostgreSQL, MSSQL ### Zen service account credentials -Based on https://www.ibm.com/docs/en/cloud-paks/1.0?topic=users-generating-api-keys-authentication -If you need to call CP4BA endpoints with ZenApiKey (e.g. for ODM) a service account with username *cpadminservice* has been prepared for you with the generated api key which can be found in Project *cloud-pak-deployer* in ConfigMap *cp4ba-usage* in *zen-api-key* key. +Based on https://www.ibm.com/docs/en/cloud-paks/cp-biz-automation/23.0.2?topic=access-using-zen-api-key-authentication +If you need to call CP4BA endpoints with ZenApiKey (e.g. for ODM) a service account with username *cpadminservice* has been prepared for you with the generated api key which can be found in Project *cloud-pak-deployer* in ConfigMap *cp4ba-usage* in *cpadminservice-zen-api-key* key. ### Useful info From 860f8a1ece38fbfb5ecd7832426dbb5e91e4fb0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Du=C5=A1ek?= Date: Mon, 17 Jun 2024 10:16:52 +0200 Subject: [PATCH 02/34] Add emitter to BAWTOS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan Dušek --- .../cp4ba/cp4ba-core/templates/bawaut/cr.yaml.j2 | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/bawaut/cr.yaml.j2 b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/bawaut/cr.yaml.j2 index 16f52ec17..9758285eb 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/bawaut/cr.yaml.j2 +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/bawaut/cr.yaml.j2 @@ -101,7 +101,10 @@ spec: name: BAWTOS_dbconnection dc_os_datasource_name: BAWTOS dc_os_xa_datasource_name: BAWTOSXA - oc_cpe_obj_store_admin_user_groups: [{% for item in (lc_admin_groups+lc_admin_users) %}'{{ item }}'{{ "," if not loop.last else "" }}{% endfor %}] + oc_cpe_obj_store_admin_user_groups: [{% for item in (lc_admin_groups+lc_admin_users) %}'{{ item }}'{{ "," if not loop.last else "" }}{% endfor %}] +{% if _current_cp4ba_cluster.cp4ba.patterns.foundation.optional_components.bai %} + oc_cpe_obj_store_enable_content_event_emitter: true +{% endif %} oc_cpe_obj_store_enable_workflow: true oc_cpe_obj_store_workflow_region_name: bawtos_region_name oc_cpe_obj_store_workflow_data_tbl_space: bawtos_tbs From 93f9b2844b3b150523ada0cd79d30ef48e5bb18a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Du=C5=A1ek?= Date: Mon, 17 Jun 2024 11:32:39 +0200 Subject: [PATCH 03/34] Add Zen PG to cloudbeaver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan Dušek --- .../cp4ba/cloudbeaver/tasks/install.yml | 44 +++------ .../cp4ba/common/tasks/cloudbeaver-add-pg.yml | 95 +++++++++++++++++++ .../cp4ba/config/tasks/internal-variables.yml | 2 + .../cp4ba/cp4ba-core/tasks/postdeploy/zen.yml | 28 ++++++ 4 files changed, 139 insertions(+), 30 deletions(-) create mode 100644 automation-roles/50-install-cloud-pak/cp4ba/common/tasks/cloudbeaver-add-pg.yml diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cloudbeaver/tasks/install.yml b/automation-roles/50-install-cloud-pak/cp4ba/cloudbeaver/tasks/install.yml index f836ed16d..b0d52f9d9 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cloudbeaver/tasks/install.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cloudbeaver/tasks/install.yml @@ -131,36 +131,6 @@ register: cloudbeaver_existing_response failed_when: cloudbeaver_existing_response.status != 200 or cloudbeaver_existing_response.json.errors is defined -- name: Add PostgreSQL to cloudbeaver - ansible.builtin.uri: - url: https://cloudbeaver-{{ cloudbeaver_project_name }}.{{ apps_endpoint_domain }}/api/gql - validate_certs: false - method: POST - headers: - content-type: "application/json" - Cookie: "cb-session-id={{ cb_session_id }}" - body_format: json - body: - query: 'mutation createConnection($providerProperties: Object) { - createConnection( - config: { credentials: {userName: "postgres", userPassword: "{{ cloudbeaver_postgresql_universal_password }}"}, - saveCredentials: true, driverId: "postgresql:postgres-jdbc", host: "{{ cloudbeaver_postgresql_hostname }}", port: "5432", - databaseName: "postgres" name:"PostgreSQL", - providerProperties: $providerProperties} - projectId: "g_GlobalConfiguration" - ) { - id - } - }' - variables: { - "providerProperties": { - "@dbeaver-show-non-default-db@": true - } - } - register: cloudbeaver_create_response - failed_when: cloudbeaver_create_response.status != 200 or cloudbeaver_create_response.json.errors is defined - when: cloudbeaver_existing_response is not search('.*PostgreSQL.*') - - name: Add MSSQL to cloudbeaver ansible.builtin.uri: url: https://cloudbeaver-{{ cloudbeaver_project_name }}.{{ apps_endpoint_domain }}/api/gql @@ -184,3 +154,17 @@ register: cloudbeaver_create_response failed_when: cloudbeaver_create_response.status != 200 or cloudbeaver_create_response.json.errors is defined when: _current_cp4ba_cluster.rpa.enabled and cloudbeaver_existing_response is not search('.*MSSQL.*') + +- name: Add PG to cloudbeaver + ansible.builtin.include_role: + name: common + tasks_from: cloudbeaver-add-pg + vars: + common_cloudbeaver_project: "{{ cloudbeaver_project_name }}" + common_cloudbeaver_username: "{{ lc_principal_admin_user }}" + common_cloudbeaver_password: "{{ cloudbeaver_universal_password }}" + common_cloudbeaver_connection_name: CP4BA PostgreSQL + common_pg_host: "{{ cloudbeaver_postgresql_hostname }}" + common_pg_port: "5432" + common_pg_username: postgres + common_pg_password: "{{ cloudbeaver_postgresql_universal_password }}" diff --git a/automation-roles/50-install-cloud-pak/cp4ba/common/tasks/cloudbeaver-add-pg.yml b/automation-roles/50-install-cloud-pak/cp4ba/common/tasks/cloudbeaver-add-pg.yml new file mode 100644 index 000000000..53ddbe8b9 --- /dev/null +++ b/automation-roles/50-install-cloud-pak/cp4ba/common/tasks/cloudbeaver-add-pg.yml @@ -0,0 +1,95 @@ +# Example of the functionality call +# +# - name: Add PG to cloudbeaver +# ansible.builtin.include_role: +# name: common +# tasks_from: cloudbeaver-add-pg +# vars: +# common_cloudbeaver_project: _cloudbeaver_project +# common_cloudbeaver_username: _cloudbeaver_username +# common_cloudbeaver_password: _cloudbeaver_password +# common_cloudbeaver_connection_name: _cloudbeaver_connection_name +# common_pg_host: _pg_host +# common_pg_port: _pg_port +# common_pg_username: _pg_username +# common_pg_password: _pg_password + +- name: Get OCP Apps domain + ansible.builtin.include_role: + name: common + tasks_from: apps-endpoint + vars: + common_output_to_var: "apps_endpoint_domain" + +- name: Hash universal password MD5 + ansible.builtin.set_fact: + cb_universal_password_md5: "{{ common_cloudbeaver_password | md5 | upper }}" + +- name: Login to cloudbeaver + ansible.builtin.uri: + url: https://cloudbeaver-{{ common_cloudbeaver_project }}.{{ apps_endpoint_domain }}/api/gql + validate_certs: false + method: POST + headers: + content-type: "application/json" + body_format: json + body: + query: 'query { + authLogin(credentials: {user: "{{ common_cloudbeaver_username }}", password: "{{ cb_universal_password_md5 }}"}, provider: "local") { + authStatus + } + }' + register: cloudbeaver_login_response + failed_when: cloudbeaver_login_response.status != 200 or cloudbeaver_login_response.json.errors is defined + +- name: Get session id + ansible.builtin.set_fact: + cb_session_id: "{{ cloudbeaver_login_response.cookies['cb-session-id'] }}" + +- name: Get existing connections + ansible.builtin.uri: + url: https://cloudbeaver-{{ common_cloudbeaver_project }}.{{ apps_endpoint_domain }}/api/gql + validate_certs: false + method: POST + headers: + content-type: "application/json" + Cookie: "cb-session-id={{ cb_session_id }}" + body_format: json + body: + query: 'query { + userConnections { + name + } + }' + register: cloudbeaver_existing_response + failed_when: cloudbeaver_existing_response.status != 200 or cloudbeaver_existing_response.json.errors is defined + +- name: Add PostgreSQL to cloudbeaver + ansible.builtin.uri: + url: https://cloudbeaver-{{ common_cloudbeaver_project }}.{{ apps_endpoint_domain }}/api/gql + validate_certs: false + method: POST + headers: + content-type: "application/json" + Cookie: "cb-session-id={{ cb_session_id }}" + body_format: json + body: + query: 'mutation createConnection($providerProperties: Object) { + createConnection( + config: { credentials: {userName: "{{ common_pg_username }}", userPassword: "{{ common_pg_password }}"}, + saveCredentials: true, driverId: "postgresql:postgres-jdbc", host: "{{ common_pg_host }}", port: "{{ common_pg_port }}", + databaseName: "postgres" name:"{{ common_cloudbeaver_connection_name }}", + providerProperties: $providerProperties} + projectId: "g_GlobalConfiguration" + ) { + id + } + }' + variables: { + "providerProperties": { + "@dbeaver-show-non-default-db@": true + } + } + register: cloudbeaver_create_response + failed_when: cloudbeaver_create_response.status != 200 or cloudbeaver_create_response.json.errors is defined + when: cloudbeaver_existing_response is not search('.*' + common_cloudbeaver_connection_name + '.*') diff --git a/automation-roles/50-install-cloud-pak/cp4ba/config/tasks/internal-variables.yml b/automation-roles/50-install-cloud-pak/cp4ba/config/tasks/internal-variables.yml index f959e0890..53369430b 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/config/tasks/internal-variables.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/config/tasks/internal-variables.yml @@ -173,6 +173,8 @@ cp4ba_mongodb_admin_user: "{{ mongodb_admin_user }}" cp4ba_mail_hostname: "{{ mail_hostname }}" cp4ba_nexus_project: "{{ nexus_project_name }}" cp4ba_gitea_project: "{{ gitea_project_name }}" +cp4ba_cloudbeaver_project: "{{ cloudbeaver_project_name }}" +cp4ba_cloudbeaver_universal_password: "{{ cloudbeaver_universal_password }}" cp4ba_kibana_project: "{{ kibana_project_name }}" cp4ba_kibana_url: "{{ kibana_url }}" cp4ba_cr_meta_name: icp4adeploy diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/zen.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/zen.yml index 2b0f1aba1..ada57c0ee 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/zen.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/zen.yml @@ -385,3 +385,31 @@ - name: Assign zen api key for further post deploy task ansible.builtin.set_fact: zen_api_key: "{{ zen_api_key_new }}" + +- name: Get Zen PostgreSQL secret + kubernetes.core.k8s_info: + api_version: v1 + kind: Secret + namespace: "{{ cp4ba_project_name }}" + name: zen-metastore-edb-app + register: zen_pg_secret + retries: 40 + delay: 15 + +- name: Set Zen PosgreSQL password + ansible.builtin.set_fact: + zen_pg_password: "{{ zen_pg_secret.resources[0].data.password | b64decode }}" + +- name: Add PG to cloudbeaver + ansible.builtin.include_role: + name: common + tasks_from: cloudbeaver-add-pg + vars: + common_cloudbeaver_project: "{{ cp4ba_cloudbeaver_project }}" + common_cloudbeaver_username: "{{ lc_principal_admin_user }}" + common_cloudbeaver_password: "{{ cp4ba_cloudbeaver_universal_password }}" + common_cloudbeaver_connection_name: Zen PostgreSQL + common_pg_host: "zen-metastore-edb-rw.{{ cp4ba_project_name }}.svc.cluster.local" + common_pg_port: "5432" + common_pg_username: zen_user + common_pg_password: "{{ zen_pg_password }}" From 18bdc33284e2f229c2255d6bb52370c828557647 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Du=C5=A1ek?= Date: Mon, 17 Jun 2024 11:36:39 +0200 Subject: [PATCH 04/34] Condition for Zen PG cloudbeaver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan Dušek --- .../cp4ba/cp4ba-core/tasks/postdeploy/zen.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/zen.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/zen.yml index ada57c0ee..d93238527 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/zen.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/zen.yml @@ -413,3 +413,4 @@ common_pg_port: "5432" common_pg_username: zen_user common_pg_password: "{{ zen_pg_password }}" + when: _current_cp4ba_cluster.cloudbeaver_enabled From f45a29470915984b74b91b80fb40df27a1cfd9a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Du=C5=A1ek?= Date: Mon, 17 Jun 2024 11:48:15 +0200 Subject: [PATCH 05/34] Bump collateral versions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan Dušek --- .../50-install-cloud-pak/cp4ba/akhq/defaults/main.yml | 2 +- .../cp4ba/cloudbeaver/defaults/main.yml | 2 +- .../50-install-cloud-pak/cp4ba/gitea/defaults/main.yml | 2 +- .../50-install-cloud-pak/cp4ba/mssql/defaults/main.yml | 2 +- .../50-install-cloud-pak/cp4ba/nexus/defaults/main.yml | 2 +- .../50-install-cloud-pak/cp4ba/openldap/defaults/main.yml | 2 +- .../50-install-cloud-pak/cp4ba/postgresql/defaults/main.yml | 2 +- .../50-install-cloud-pak/cp4ba/roundcube/defaults/main.yml | 6 +++--- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/automation-roles/50-install-cloud-pak/cp4ba/akhq/defaults/main.yml b/automation-roles/50-install-cloud-pak/cp4ba/akhq/defaults/main.yml index 0970ba2a0..882bce7ac 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/akhq/defaults/main.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/akhq/defaults/main.yml @@ -4,6 +4,6 @@ akhq_dir_name: akhq akhq_project_name: "" akhq_universal_password: "" akhq_storage_class_name: "" -akhq_image: docker.io/tchiotludo/akhq:0.24.0 +akhq_image: docker.io/tchiotludo/akhq:0.25.0 akhq_admin_user: "" akhq_cp4ba_project_name: "" diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cloudbeaver/defaults/main.yml b/automation-roles/50-install-cloud-pak/cp4ba/cloudbeaver/defaults/main.yml index 1c9efdfa3..555cb843e 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cloudbeaver/defaults/main.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cloudbeaver/defaults/main.yml @@ -4,7 +4,7 @@ cloudbeaver_dir_name: cloudbeaver cloudbeaver_project_name: "" cloudbeaver_universal_password: "" cloudbeaver_storage_class_name: "" -cloudbeaver_image: docker.io/dbeaver/cloudbeaver:24.0.0 +cloudbeaver_image: docker.io/dbeaver/cloudbeaver:24.1.0 cloudbeaver_postgresql_hostname: "" cloudbeaver_postgresql_universal_password: "" cloudbeaver_mssql_hostname: "" diff --git a/automation-roles/50-install-cloud-pak/cp4ba/gitea/defaults/main.yml b/automation-roles/50-install-cloud-pak/cp4ba/gitea/defaults/main.yml index be35b3706..b44885de8 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/gitea/defaults/main.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/gitea/defaults/main.yml @@ -4,5 +4,5 @@ gitea_dir_name: gitea gitea_project_name: "" gitea_universal_password: "" gitea_storage_class_name: "" -gitea_image: docker.io/gitea/gitea:1.21.7-rootless +gitea_image: docker.io/gitea/gitea:1.22.0-rootless gitea_ldap_hostname: "" diff --git a/automation-roles/50-install-cloud-pak/cp4ba/mssql/defaults/main.yml b/automation-roles/50-install-cloud-pak/cp4ba/mssql/defaults/main.yml index 58964d81a..3db4c39c2 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/mssql/defaults/main.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/mssql/defaults/main.yml @@ -5,4 +5,4 @@ mssql_project_name: "" mssql_universal_password: "" mssql_storage_class_name: "" # From https://mcr.microsoft.com/v2/mssql/rhel/server/tags/list -mssql_image: mcr.microsoft.com/mssql/rhel/server:2019-CU25-rhel-8.7 +mssql_image: mcr.microsoft.com/mssql/rhel/server:2022-CU13-rhel-9.1 diff --git a/automation-roles/50-install-cloud-pak/cp4ba/nexus/defaults/main.yml b/automation-roles/50-install-cloud-pak/cp4ba/nexus/defaults/main.yml index b2769f35a..80fdedce8 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/nexus/defaults/main.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/nexus/defaults/main.yml @@ -4,6 +4,6 @@ nexus_dir_name: nexus nexus_project_name: "" nexus_universal_password: "" nexus_storage_class_name: "" -nexus_image: docker.io/sonatype/nexus3:3.66.0 +nexus_image: docker.io/sonatype/nexus3:3.69.0 nexus_output_namespace: "cloud-pak-deployer" nexus_ldap_hostname: "" diff --git a/automation-roles/50-install-cloud-pak/cp4ba/openldap/defaults/main.yml b/automation-roles/50-install-cloud-pak/cp4ba/openldap/defaults/main.yml index 48ee8c448..c972db82f 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/openldap/defaults/main.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/openldap/defaults/main.yml @@ -4,4 +4,4 @@ openldap_dir_name: openldap openldap_project_name: "" openldap_universal_password: "" openldap_storage_class_name: "" -openldap_image: docker.io/bitnami/openldap:2.6.7 +openldap_image: docker.io/bitnami/openldap:2.6.8 diff --git a/automation-roles/50-install-cloud-pak/cp4ba/postgresql/defaults/main.yml b/automation-roles/50-install-cloud-pak/cp4ba/postgresql/defaults/main.yml index eb181deeb..c0b90854e 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/postgresql/defaults/main.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/postgresql/defaults/main.yml @@ -4,5 +4,5 @@ postgresql_dir_name: postgresql postgresql_project_name: "" postgresql_universal_password: "" postgresql_storage_class_name: "" -postgresql_image: docker.io/bitnami/postgresql:14.11.0-debian-12-r6 +postgresql_image: docker.io/bitnami/postgresql:15.7.0-debian-12-r9 postgresql_admin_user: "" diff --git a/automation-roles/50-install-cloud-pak/cp4ba/roundcube/defaults/main.yml b/automation-roles/50-install-cloud-pak/cp4ba/roundcube/defaults/main.yml index a180c38b2..5bbe9f446 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/roundcube/defaults/main.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/roundcube/defaults/main.yml @@ -4,7 +4,7 @@ roundcube_dir_name: roundcube roundcube_project_name: "" roundcube_universal_password: "" roundcube_storage_class_name: "" -roundcube_db_image: docker.io/postgres:16.2-alpine3.19 -roundcube_image: docker.io/roundcube/roundcubemail:1.6.6-fpm-alpine -roundcube_nginx_image: docker.io/nginx:1.25.4-alpine3.18 +roundcube_db_image: docker.io/postgres:16.3-alpine3.20 +roundcube_image: docker.io/roundcube/roundcubemail:1.6.7-fpm-alpine +roundcube_nginx_image: docker.io/nginx:1.27.0-alpine3.19 roundcube_mail_hostname: "" From 17d28eeaef6211eff9a23236c37d10ad090bf9ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Du=C5=A1ek?= Date: Mon, 17 Jun 2024 14:16:30 +0200 Subject: [PATCH 06/34] Convert mail server to statefulset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan Dušek --- .../cp4ba/mail/defaults/main.yml | 2 +- .../cp4ba/mail/tasks/install.yml | 6 ++--- .../cp4ba/mail/tasks/remove.yml | 18 ++++++++++--- .../templates/persistentvolumeclaims.yaml.j2 | 14 ---------- ...ployments.yaml.j2 => statefulsets.yaml.j2} | 27 ++++++++++++++----- 5 files changed, 37 insertions(+), 30 deletions(-) delete mode 100644 automation-roles/50-install-cloud-pak/cp4ba/mail/templates/persistentvolumeclaims.yaml.j2 rename automation-roles/50-install-cloud-pak/cp4ba/mail/templates/{deployments.yaml.j2 => statefulsets.yaml.j2} (87%) diff --git a/automation-roles/50-install-cloud-pak/cp4ba/mail/defaults/main.yml b/automation-roles/50-install-cloud-pak/cp4ba/mail/defaults/main.yml index 36a0332b6..34ae7173c 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/mail/defaults/main.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/mail/defaults/main.yml @@ -4,6 +4,6 @@ mail_dir_name: mail mail_project_name: "" mail_universal_password: "" mail_storage_class_name: "" -mail_image: docker.io/mailserver/docker-mailserver:13.3.1 +mail_image: docker.io/mailserver/docker-mailserver:14.0.0 mail_ca_key_path: "" mail_ca_crt_path: "" diff --git a/automation-roles/50-install-cloud-pak/cp4ba/mail/tasks/install.yml b/automation-roles/50-install-cloud-pak/cp4ba/mail/tasks/install.yml index 6758e2723..f3f6bad87 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/mail/tasks/install.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/mail/tasks/install.yml @@ -76,8 +76,7 @@ - rolebindings - configmaps - secrets - - persistentvolumeclaims - - deployments + - statefulsets - services - name: Add {{ item.name }} @@ -92,6 +91,5 @@ - {name: rolebindings, wait_sleep: 15, wait_timeout: 15} - {name: configmaps, wait_sleep: 15, wait_timeout: 15} - {name: secrets, wait_sleep: 15, wait_timeout: 15} - - {name: persistentvolumeclaims, wait_sleep: 15, wait_timeout: 300} - - {name: deployments, wait_sleep: 15, wait_timeout: 600} + - {name: statefulsets, wait_sleep: 15, wait_timeout: 600} - {name: services, wait_sleep: 15, wait_timeout: 15} diff --git a/automation-roles/50-install-cloud-pak/cp4ba/mail/tasks/remove.yml b/automation-roles/50-install-cloud-pak/cp4ba/mail/tasks/remove.yml index 0db61cf11..00b7a4b5a 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/mail/tasks/remove.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/mail/tasks/remove.yml @@ -19,8 +19,7 @@ - rolebindings - configmaps - secrets - - persistentvolumeclaims - - deployments + - statefulsets - services - name: Remove {{ item.name }} @@ -32,13 +31,24 @@ wait_timeout: "{{ item.wait_timeout }}" with_items: - {name: services, wait_sleep: 15, wait_timeout: 15} - - {name: deployments, wait_sleep: 15, wait_timeout: 600} - - {name: persistentvolumeclaims, wait_sleep: 15, wait_timeout: 300} + - {name: statefulsets, wait_sleep: 15, wait_timeout: 600} - {name: secrets, wait_sleep: 15, wait_timeout: 15} - {name: configmaps, wait_sleep: 15, wait_timeout: 15} - {name: rolebindings, wait_sleep: 15, wait_timeout: 15} - {name: serviceaccounts, wait_sleep: 15, wait_timeout: 15} +- name: Remove PersistentVolumeClaims + kubernetes.core.k8s: + state: absent + api_version: v1 + kind: PersistentVolumeClaim + label_selectors: + - app = mail + namespace: "{{ mail_project_name }}" + wait: true + wait_sleep: 15 + wait_timeout: 120 + - name: Remove Empty Project ansible.builtin.include_role: name: common diff --git a/automation-roles/50-install-cloud-pak/cp4ba/mail/templates/persistentvolumeclaims.yaml.j2 b/automation-roles/50-install-cloud-pak/cp4ba/mail/templates/persistentvolumeclaims.yaml.j2 deleted file mode 100644 index f59895e10..000000000 --- a/automation-roles/50-install-cloud-pak/cp4ba/mail/templates/persistentvolumeclaims.yaml.j2 +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: mail-storage - namespace: "{{ mail_project_name }}" - labels: - app: mail -spec: - accessModes: - - ReadWriteMany - storageClassName: "{{mail_storage_class_name}}" - resources: - requests: - storage: 5Gi diff --git a/automation-roles/50-install-cloud-pak/cp4ba/mail/templates/deployments.yaml.j2 b/automation-roles/50-install-cloud-pak/cp4ba/mail/templates/statefulsets.yaml.j2 similarity index 87% rename from automation-roles/50-install-cloud-pak/cp4ba/mail/templates/deployments.yaml.j2 rename to automation-roles/50-install-cloud-pak/cp4ba/mail/templates/statefulsets.yaml.j2 index c4ebbfd4e..4d971499e 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/mail/templates/deployments.yaml.j2 +++ b/automation-roles/50-install-cloud-pak/cp4ba/mail/templates/statefulsets.yaml.j2 @@ -1,11 +1,12 @@ apiVersion: apps/v1 -kind: Deployment +kind: StatefulSet metadata: name: mail namespace: "{{ mail_project_name }}" labels: app: mail spec: + serviceName: mail replicas: 1 selector: matchLabels: @@ -65,10 +66,10 @@ spec: subPath: postfix-main.cf mountPath: /tmp/docker-mailserver/postfix-main.cf readOnly: true - - name: data + - name: mail-storage mountPath: /var/mail subPath: data - - name: data + - name: mail-storage mountPath: /var/mail-state subPath: state - name: public-dir-pipe-folder @@ -77,7 +78,7 @@ spec: - name: private-dir-pipe-folder mountPath: /var/mail-state/spool-postfix/private subPath: public - - name: data + - name: mail-storage mountPath: /var/log/mail subPath: log - name: tls @@ -106,9 +107,6 @@ spec: - name: config configMap: name: mail-config - - name: data - persistentVolumeClaim: - claimName: mail-storage # Cannot create named pipes on connected storage class, must be in. Risk of loosing data. - name: public-dir-pipe-folder emptyDir: {} @@ -119,3 +117,18 @@ spec: secret: secretName: mail-tls defaultMode: 256 + volumeClaimTemplates: + - kind: PersistentVolumeClaim + apiVersion: v1 + metadata: + name: mail-storage + labels: + app: mail + spec: + accessModes: + - ReadWriteOnce + storageClassName: "{{ mail_storage_class_name }}" + resources: + requests: + storage: 5Gi + volumeMode: Filesystem From 57489c1f543a27979d330dc1629972035f0ffaf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Du=C5=A1ek?= Date: Mon, 17 Jun 2024 14:16:47 +0200 Subject: [PATCH 07/34] Update password secret for LSR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan Dušek --- .../50-install-cloud-pak/cp4ba/usage/templates/usage.md.j2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/automation-roles/50-install-cloud-pak/cp4ba/usage/templates/usage.md.j2 b/automation-roles/50-install-cloud-pak/cp4ba/usage/templates/usage.md.j2 index 9cff507eb..2ec2e0b7e 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/usage/templates/usage.md.j2 +++ b/automation-roles/50-install-cloud-pak/cp4ba/usage/templates/usage.md.j2 @@ -529,7 +529,7 @@ As Cloud Pak Foundational Services. #### Endpoints - Base page: https://ibm-licensing-service-instance-ibm-licensing.{{ apps_endpoint_domain }} -- Direct status page: https://ibm-licensing-service-instance-ibm-licensing.{{ apps_endpoint_domain }}/status?token=[token] (*[token]* generated by `oc get secret ibm-licensing-token -o jsonpath={.data.token} -n cs-control | base64 -d`) +- Direct status page: https://ibm-licensing-service-instance-ibm-licensing.{{ apps_endpoint_domain }}/status?token=[token] (*[token]* generated by `oc get secret ibm-licensing-token -o jsonpath={.data.token} -n ibm-licensing | base64 -d`) - License Service Reporter: https://ibm-lsr-console-ibm-lsr.{{ apps_endpoint_domain }}/license-service-reporter - credentials {{ lc_principal_admin_user }} / {{ universal_password }} #### Getting license info From 326760d5512eb44db2a8953379a744fd22a0b37e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Du=C5=A1ek?= Date: Tue, 18 Jun 2024 08:54:19 +0200 Subject: [PATCH 08/34] Reaplace kibana with opensearch stack MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan Dušek --- .../cp4ba/cerebro/tasks/install.yml | 14 ++++ .../cerebro/templates/configmaps.yaml.j2 | 8 +- .../cp4ba/config/tasks/internal-variables.yml | 18 +---- .../cp4ba/config/tasks/main.yml | 4 - .../cp4ba/cp4ba-cluster/tasks/remove.yml | 20 ++--- .../cp4ba/cp4ba-core/tasks/deploy.yml | 8 +- .../cp4ba/cp4ba-core/tasks/postdeploy/zen.yml | 24 ------ .../cp4ba/cp4ba-core/tasks/predeploy/bai.yml | 11 --- .../bai-external-app-network-policy.yaml.j2 | 17 ---- .../templates/bai/bai-secret.yaml.j2 | 2 - .../cp4ba/cp4ba-core/templates/bai/cr.yaml.j2 | 5 +- .../cp4ba/kibana/defaults/main.yml | 9 --- .../cp4ba/kibana/tasks/main.yml | 16 ---- .../kibana/templates/deployments.yaml.j2 | 79 ------------------- .../cp4ba/kibana/templates/services.yaml.j2 | 15 ---- .../opensearch_dashboards/defaults/main.yml | 6 ++ .../tasks/install.yml | 18 ++--- .../opensearch_dashboards/tasks/main.yml | 16 ++++ .../tasks/remove.yml | 12 +-- .../templates/deployments.yaml.j2 | 64 +++++++++++++++ .../templates/services.yaml.j2 | 15 ++++ .../cp4ba/usage/templates/usage.md.j2 | 11 +-- .../30-reference/configuration/cloud-pak.md | 4 + .../sample-dynamic/config-samples/cp4ba.yaml | 3 + 24 files changed, 168 insertions(+), 231 deletions(-) delete mode 100644 automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/bai/bai-external-app-network-policy.yaml.j2 delete mode 100644 automation-roles/50-install-cloud-pak/cp4ba/kibana/defaults/main.yml delete mode 100644 automation-roles/50-install-cloud-pak/cp4ba/kibana/tasks/main.yml delete mode 100644 automation-roles/50-install-cloud-pak/cp4ba/kibana/templates/deployments.yaml.j2 delete mode 100644 automation-roles/50-install-cloud-pak/cp4ba/kibana/templates/services.yaml.j2 create mode 100644 automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/defaults/main.yml rename automation-roles/50-install-cloud-pak/cp4ba/{kibana => opensearch_dashboards}/tasks/install.yml (63%) create mode 100644 automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/tasks/main.yml rename automation-roles/50-install-cloud-pak/cp4ba/{kibana => opensearch_dashboards}/tasks/remove.yml (70%) create mode 100644 automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/templates/deployments.yaml.j2 create mode 100644 automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/templates/services.yaml.j2 diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cerebro/tasks/install.yml b/automation-roles/50-install-cloud-pak/cp4ba/cerebro/tasks/install.yml index 26fe55fb0..e251a8fe8 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cerebro/tasks/install.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cerebro/tasks/install.yml @@ -12,6 +12,20 @@ common_namespace_name: "{{ cerebro_project_name }}" common_output_directory: "{{ cerebro_output_directory }}" +- name: Get OpenSearch password + kubernetes.core.k8s_info: + api_version: v1 + kind: Secret + namespace: "{{ cerebro_cp4ba_project_name }}" + name: "opensearch-ibm-elasticsearch-cred-secret" + register: os_secret + retries: 40 + delay: 15 + +- name: Set OpenSearch password + ansible.builtin.set_fact: + os_password: "{{ os_secret.resources[0].data.elastic | b64decode }}" + - name: Prepare yaml file for {{ item }} ansible.builtin.template: src: "{{ item }}.yaml.j2" diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cerebro/templates/configmaps.yaml.j2 b/automation-roles/50-install-cloud-pak/cp4ba/cerebro/templates/configmaps.yaml.j2 index d501c44d0..3e3dbaed8 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cerebro/templates/configmaps.yaml.j2 +++ b/automation-roles/50-install-cloud-pak/cp4ba/cerebro/templates/configmaps.yaml.j2 @@ -78,11 +78,11 @@ data: # A list of known hosts hosts = [ { - host = "https://iaf-system-elasticsearch-es.{{ cerebro_cp4ba_project_name }}:9200" - name = "IAF Elastic" + host = "https://opensearch-ibm-elasticsearch-srv.{{ cerebro_cp4ba_project_name }}.svc.cluster.local:443" + name = "OpenSearch" auth = { - username = "{{ cerebro_elasticsearch_admin_user }}" - password = "{{ cerebro_elasticsearch_universal_password }}" + username = "elastic" + password = "{{ os_password }}" } } ] diff --git a/automation-roles/50-install-cloud-pak/cp4ba/config/tasks/internal-variables.yml b/automation-roles/50-install-cloud-pak/cp4ba/config/tasks/internal-variables.yml index 53369430b..ba4d6edeb 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/config/tasks/internal-variables.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/config/tasks/internal-variables.yml @@ -54,7 +54,6 @@ mongodb_hostname: "mongodb.{{ mongodb_project_name }}.svc.cluster.local" mail_hostname: "mail.{{ mail_project_name }}.svc.cluster.local" mssql_hostname: "mssql.{{ mssql_project_name }}.svc.cluster.local" nexus_hostname: "nexus.{{ nexus_project_name }}.svc.cluster.local" -kibana_url: "http://kibana.{{ kibana_project_name }}.svc.cluster.local:5601" elasticsearch_admin_user: elasticsearch-admin elasticsearch_universal_password: "{{ universal_password }}" @@ -97,8 +96,6 @@ cerebro_action: "{{ global_action }}" cerebro_project_name: "{{ collateral_project_name }}" cerebro_universal_password: "{{ universal_password }}" cerebro_cp4ba_project_name: "{{ cp4ba_project_name }}" -cerebro_elasticsearch_universal_password: "{{ elasticsearch_universal_password }}" -cerebro_elasticsearch_admin_user: "{{ elasticsearch_admin_user }}" akhq_action: "{{ global_action }}" akhq_project_name: "{{ collateral_project_name }}" @@ -107,14 +104,9 @@ akhq_cp4ba_project_name: "{{ cp4ba_project_name }}" akhq_admin_user: "{{ principal_admin_user }}" akhq_storage_class_name: "{{ storage_class_name }}" -kibana_action: "{{ global_action }}" -kibana_project_name: "{{ collateral_project_name }}" -kibana_elasticsearch_universal_password: "{{ elasticsearch_universal_password }}" -kibana_universal_password: "{{ kibana_elasticsearch_universal_password }}" -kibana_storage_class_name: "{{ storage_class_name }}" -kibana_cp4ba_project_name: "{{ cp4ba_project_name }}" -kibana_elasticsearch_admin_user: "{{ elasticsearch_admin_user }}" -kibana_admin_user: "{{ kibana_elasticsearch_admin_user }}" +opensearch_dashboards_action: "{{ global_action }}" +opensearch_dashboards_project_name: "{{ collateral_project_name }}" +opensearch_dashboards_cp4ba_project_name: "{{ cp4ba_project_name }}" mongodb_action: "{{ global_action }}" mongodb_project_name: "{{ collateral_project_name }}" @@ -175,8 +167,6 @@ cp4ba_nexus_project: "{{ nexus_project_name }}" cp4ba_gitea_project: "{{ gitea_project_name }}" cp4ba_cloudbeaver_project: "{{ cloudbeaver_project_name }}" cp4ba_cloudbeaver_universal_password: "{{ cloudbeaver_universal_password }}" -cp4ba_kibana_project: "{{ kibana_project_name }}" -cp4ba_kibana_url: "{{ kibana_url }}" cp4ba_cr_meta_name: icp4adeploy cp4ba_ca_key_path: "{{ ca_key_path }}" cp4ba_ca_crt_path: "{{ ca_crt_path }}" @@ -184,8 +174,6 @@ cp4ba_external_share_google: "{{ external_share_google }}" cp4ba_google_client_id: "{{ google_client_id }}" cp4ba_google_client_secret: "{{ google_client_secret }}" cp4ba_deployment_platform: "{{ deployment_platform }}" -cp4ba_kibana_universal_password: "{{ kibana_universal_password }}" -cp4ba_kibana_admin_user: "{{ kibana_admin_user }}" cp4ba_elasticsearch_universal_password: "{{ elasticsearch_universal_password }}" cp4ba_elasticsearch_admin_user: "{{ elasticsearch_admin_user }}" diff --git a/automation-roles/50-install-cloud-pak/cp4ba/config/tasks/main.yml b/automation-roles/50-install-cloud-pak/cp4ba/config/tasks/main.yml index 6695bd479..757b426d3 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/config/tasks/main.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/config/tasks/main.yml @@ -58,10 +58,6 @@ mongodb_enabled: "{{ true if ((_current_cp4ba_cluster.cp4ba.enabled and _current_cp4ba_cluster.cp4ba.patterns.decisions_ads.enabled) or _current_cp4ba_cluster.pm.enabled) else false }}" -- name: Kibana config variable - ansible.builtin.set_fact: - kibana_enabled: "{{ true if _current_cp4ba_cluster.cp4ba.enabled and _current_cp4ba_cluster.cp4ba.patterns.foundation.optional_components.bai else false }}" - - name: MSSQL config variable ansible.builtin.set_fact: mssql_enabled: "{{ true if _current_cp4ba_cluster.rpa.enabled else false }}" diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-cluster/tasks/remove.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-cluster/tasks/remove.yml index f62267104..d0438f440 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-cluster/tasks/remove.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-cluster/tasks/remove.yml @@ -18,6 +18,16 @@ name: akhq when: _current_cp4ba_cluster.akhq_enabled +- name: Remove OpenSearch Dashboards + ansible.builtin.include_role: + name: opensearch_dashboards + when: _current_cp4ba_cluster.opensearch_dashboards_enabled + +- name: Remove Cerebro + ansible.builtin.include_role: + name: cerebro + when: _current_cp4ba_cluster.cerebro_enabled + - name: Remove CP4BA ansible.builtin.include_role: name: cp4ba-core @@ -37,11 +47,6 @@ name: mongo_express when: _current_cp4ba_cluster.mongo_express_enabled -- name: Remove Cerebro - ansible.builtin.include_role: - name: cerebro - when: _current_cp4ba_cluster.cerebro_enabled - - name: Remove Roundcube ansible.builtin.include_role: name: roundcube @@ -52,11 +57,6 @@ name: cloudbeaver when: _current_cp4ba_cluster.cloudbeaver_enabled -- name: Remove Kibana - ansible.builtin.include_role: - name: kibana - when: kibana_enabled - - name: Remove MongoDB ansible.builtin.include_role: name: mongodb diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/deploy.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/deploy.yml index 683c02827..3c254b92f 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/deploy.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/deploy.yml @@ -475,11 +475,11 @@ name: common tasks_from: wait-resource-condition vars: - common_api_version: elastic.automation.ibm.com/v1beta1 - common_resource_kind: Elasticsearch - common_resource_name: iaf-system + common_api_version: elasticsearch.opencontent.ibm.com/v1 + common_resource_kind: ElasticsearchCluster + common_resource_name: opensearch common_resource_namespace: "{{ cp4ba_project_name }}" - common_condition_name: Ready + common_condition_name: Started common_retries: 30 common_delay: 60 when: _current_cp4ba_cluster.cp4ba.patterns.foundation.optional_components.bai or _current_cp4ba_cluster.cp4ba.patterns.workflow.enabled diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/zen.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/zen.yml index d93238527..45cfb8e37 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/zen.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/zen.yml @@ -71,30 +71,6 @@ common_retries: 80 common_delay: 15 -- name: Delete Kibana pods - kubernetes.core.k8s: - state: absent - api_version: v1 - kind: Pod - namespace: "{{ cp4ba_kibana_project }}" - label_selectors: - - app=kibana - when: kibana_enabled - -- name: Wait for Kibana Deployment Available State - ansible.builtin.include_role: - name: common - tasks_from: wait-resource-condition - vars: - common_api_version: v1 - common_resource_kind: Deployment - common_resource_name: kibana - common_resource_namespace: "{{ cp4ba_kibana_project }}" - common_condition_name: Available - common_retries: 80 - common_delay: 15 - when: kibana_enabled - - name: Get OCP Apps domain ansible.builtin.include_role: name: common diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/predeploy/bai.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/predeploy/bai.yml index e0721552b..ac73c6dfa 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/predeploy/bai.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/predeploy/bai.yml @@ -10,14 +10,3 @@ kubernetes.core.k8s: state: present src: "{{ cp4ba_output_directory }}/bai-secret.yaml" - -- name: Prepare yaml file for BAI external app network policy - ansible.builtin.template: - src: bai/bai-external-app-network-policy.yaml.j2 - dest: "{{ cp4ba_output_directory }}/bai-external-app-network-policy.yaml" - mode: u+rwx - -- name: Add BAI external app network policy - kubernetes.core.k8s: - state: present - src: "{{ cp4ba_output_directory }}/bai-external-app-network-policy.yaml" diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/bai/bai-external-app-network-policy.yaml.j2 b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/bai/bai-external-app-network-policy.yaml.j2 deleted file mode 100644 index 42da71105..000000000 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/bai/bai-external-app-network-policy.yaml.j2 +++ /dev/null @@ -1,17 +0,0 @@ -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: "{{ cp4ba_cr_meta_name }}-cp4a-egress-external-app-bai" - namespace: "{{ cp4ba_project_name }}" -spec: - podSelector: - matchLabels: - com.ibm.cp4a.networking/egress-external-app-component: BAI - policyTypes: - - Egress - egress: - - to: - - podSelector: {} - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: "{{ cp4ba_kibana_project }}" diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/bai/bai-secret.yaml.j2 b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/bai/bai-secret.yaml.j2 index 74ce97763..fe441b34c 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/bai/bai-secret.yaml.j2 +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/bai/bai-secret.yaml.j2 @@ -14,7 +14,5 @@ metadata: namespace: "{{ cp4ba_project_name }}" type: Opaque stringData: - kibana-username: "{{ cp4ba_kibana_admin_user }}" - kibana-password: "{{ cp4ba_kibana_universal_password }}" management-username: "{{ lc_principal_admin_user }}" management-password: "{{ lc_principal_admin_password }}" diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/bai/cr.yaml.j2 b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/bai/cr.yaml.j2 index ae18c1dbb..caa70cc02 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/bai/cr.yaml.j2 +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/bai/cr.yaml.j2 @@ -2,7 +2,6 @@ spec: bai_configuration: bai_secret: custom-bai-secret settings: - external_kibana_url: "{{ cp4ba_kibana_url }}" egress: true flink: create_route: true @@ -19,7 +18,11 @@ spec: install: true odm: install: true + ads: + install: true content: install: true + navigator: + install: true event_forwarder: install: false diff --git a/automation-roles/50-install-cloud-pak/cp4ba/kibana/defaults/main.yml b/automation-roles/50-install-cloud-pak/cp4ba/kibana/defaults/main.yml deleted file mode 100644 index 3937a629b..000000000 --- a/automation-roles/50-install-cloud-pak/cp4ba/kibana/defaults/main.yml +++ /dev/null @@ -1,9 +0,0 @@ -kibana_action: install -kibana_base_dir: "{{ generic_directory }}" -kibana_dir_name: kibana -kibana_project_name: "" -kibana_universal_password: "" -kibana_storage_class_name: "" -kibana_image: docker.elastic.co/kibana/kibana-oss:7.10.2 -kibana_admin_user: "" -kibana_cp4ba_project_name: "" diff --git a/automation-roles/50-install-cloud-pak/cp4ba/kibana/tasks/main.yml b/automation-roles/50-install-cloud-pak/cp4ba/kibana/tasks/main.yml deleted file mode 100644 index 32b25b439..000000000 --- a/automation-roles/50-install-cloud-pak/cp4ba/kibana/tasks/main.yml +++ /dev/null @@ -1,16 +0,0 @@ -- name: Set output directory variable - ansible.builtin.set_fact: - kibana_output_directory: "{{ kibana_base_dir }}/{{ kibana_dir_name }}" - -- name: Remove kibana directory for generated files - ansible.builtin.file: - path: "{{ kibana_output_directory }}" - state: absent - -- name: Install kibana - ansible.builtin.include_tasks: install.yml - when: "kibana_action == 'install'" - -- name: Remove kibana - ansible.builtin.include_tasks: remove.yml - when: "kibana_action == 'remove'" diff --git a/automation-roles/50-install-cloud-pak/cp4ba/kibana/templates/deployments.yaml.j2 b/automation-roles/50-install-cloud-pak/cp4ba/kibana/templates/deployments.yaml.j2 deleted file mode 100644 index 496f37522..000000000 --- a/automation-roles/50-install-cloud-pak/cp4ba/kibana/templates/deployments.yaml.j2 +++ /dev/null @@ -1,79 +0,0 @@ -kind: Deployment -apiVersion: apps/v1 -metadata: - name: kibana - namespace: "{{ kibana_project_name }}" - labels: - app: kibana -spec: - replicas: 1 - selector: - matchLabels: - app: kibana - template: - metadata: - labels: - app: kibana - restartPolicy: Always - spec: - containers: - - name: kibana - image: "{{ kibana_image }}" - resources: - requests: - cpu: 50m - memory: 512Mi - limits: - cpu: 1000m - memory: 1536Mi - startupProbe: - httpGet: - path: /app/kibana - port: 5601 - scheme: HTTP - httpHeaders: - - name: Authorization - value: "Basic {{ (kibana_admin_user + ':' + kibana_universal_password) | b64encode }}" - timeoutSeconds: 1 - periodSeconds: 20 - successThreshold: 1 - failureThreshold: 30 - readinessProbe: - httpGet: - path: /app/kibana - port: 5601 - scheme: HTTP - httpHeaders: - - name: Authorization - value: "Basic {{ (kibana_admin_user + ':' + kibana_universal_password) | b64encode }}" - timeoutSeconds: 1 - periodSeconds: 10 - successThreshold: 1 - failureThreshold: 30 - livenessProbe: - httpGet: - path: /app/kibana - port: 5601 - scheme: HTTP - httpHeaders: - - name: Authorization - value: "Basic {{ (kibana_admin_user + ':' + kibana_universal_password) | b64encode }}" - timeoutSeconds: 1 - periodSeconds: 10 - successThreshold: 1 - failureThreshold: 30 - env: - - name: ELASTICSEARCH_HOSTS - value: 'https://iaf-system-elasticsearch-es.{{ kibana_cp4ba_project_name }}.svc.cluster.local:9200' - - name: ELASTICSEARCH_USERNAME - value: '{{ kibana_elasticsearch_admin_user }}' - - name: ELASTICSEARCH_PASSWORD - value: '{{ kibana_elasticsearch_universal_password }}' - - name: ELASTICSEARCH_SSL_VERIFICATIONMODE - value: 'none' - - name: LOGGING_VERBOSE - value: 'true' - ports: - - name: kibana-ui - containerPort: 5601 - protocol: TCP diff --git a/automation-roles/50-install-cloud-pak/cp4ba/kibana/templates/services.yaml.j2 b/automation-roles/50-install-cloud-pak/cp4ba/kibana/templates/services.yaml.j2 deleted file mode 100644 index f3a10ee5b..000000000 --- a/automation-roles/50-install-cloud-pak/cp4ba/kibana/templates/services.yaml.j2 +++ /dev/null @@ -1,15 +0,0 @@ -kind: Service -apiVersion: v1 -metadata: - name: kibana - namespace: "{{ kibana_project_name }}" - labels: - app: kibana -spec: - ports: - - name: kibana-ui - protocol: TCP - port: 5601 - targetPort: kibana-ui - selector: - app: kibana diff --git a/automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/defaults/main.yml b/automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/defaults/main.yml new file mode 100644 index 000000000..c0f8c77ca --- /dev/null +++ b/automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/defaults/main.yml @@ -0,0 +1,6 @@ +opensearch_dashboards_action: install +opensearch_dashboards_base_dir: "{{ generic_directory }}" +opensearch_dashboards_dir_name: opensearch_dashboards +opensearch_dashboards_project_name: "" +opensearch_dashboards_image: docker.io/opensearchproject/opensearch-dashboards:2.13.0 +opensearch_dashboards_cp4ba_project_name: "" diff --git a/automation-roles/50-install-cloud-pak/cp4ba/kibana/tasks/install.yml b/automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/tasks/install.yml similarity index 63% rename from automation-roles/50-install-cloud-pak/cp4ba/kibana/tasks/install.yml rename to automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/tasks/install.yml index b350c98f8..61f75d421 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/kibana/tasks/install.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/tasks/install.yml @@ -1,6 +1,6 @@ - name: Create directory for generated files ansible.builtin.file: - path: "{{ kibana_output_directory }}" + path: "{{ opensearch_dashboards_output_directory }}" state: directory mode: u+rwx @@ -9,13 +9,13 @@ name: common tasks_from: create-project vars: - common_namespace_name: "{{ kibana_project_name }}" - common_output_directory: "{{ kibana_output_directory }}" + common_namespace_name: "{{ opensearch_dashboards_project_name }}" + common_output_directory: "{{ opensearch_dashboards_output_directory }}" - name: Prepare yaml file for {{ item }} ansible.builtin.template: src: "{{ item }}.yaml.j2" - dest: "{{ kibana_output_directory }}/{{ item }}.yaml" + dest: "{{ opensearch_dashboards_output_directory }}/{{ item }}.yaml" mode: u+rwx with_items: - deployments @@ -24,7 +24,7 @@ - name: Add {{ item.name }} kubernetes.core.k8s: state: present - src: "{{ kibana_output_directory }}/{{ item.name }}.yaml" + src: "{{ opensearch_dashboards_output_directory }}/{{ item.name }}.yaml" wait: "{{ item.wait }}" wait_sleep: "{{ item.wait_sleep }}" wait_timeout: "{{ item.wait_timeout }}" @@ -45,8 +45,8 @@ name: common tasks_from: create-edge-route vars: - common_namespace_name: "{{ kibana_project_name }}" - common_route_name: "kibana-{{ kibana_project_name }}" - common_service_name: kibana + common_namespace_name: "{{ opensearch_dashboards_project_name }}" + common_route_name: "opensearch-dashboards-{{ opensearch_dashboards_project_name }}" + common_service_name: opensearch-dashboards common_apps_endpoint_domain: "{{ apps_endpoint_domain }}" - common_output_directory: "{{ kibana_output_directory }}" + common_output_directory: "{{ opensearch_dashboards_output_directory }}" diff --git a/automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/tasks/main.yml b/automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/tasks/main.yml new file mode 100644 index 000000000..b70e1a2b7 --- /dev/null +++ b/automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/tasks/main.yml @@ -0,0 +1,16 @@ +- name: Set output directory variable + ansible.builtin.set_fact: + opensearch_dashboards_output_directory: "{{ opensearch_dashboards_base_dir }}/{{ opensearch_dashboards_dir_name }}" + +- name: Remove opensearch_dashboards directory for generated files + ansible.builtin.file: + path: "{{ opensearch_dashboards_output_directory }}" + state: absent + +- name: Install opensearch_dashboards + ansible.builtin.include_tasks: install.yml + when: "opensearch_dashboards_action == 'install'" + +- name: Remove opensearch_dashboards + ansible.builtin.include_tasks: remove.yml + when: "opensearch_dashboards_action == 'remove'" diff --git a/automation-roles/50-install-cloud-pak/cp4ba/kibana/tasks/remove.yml b/automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/tasks/remove.yml similarity index 70% rename from automation-roles/50-install-cloud-pak/cp4ba/kibana/tasks/remove.yml rename to automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/tasks/remove.yml index ee8d6bef9..740337443 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/kibana/tasks/remove.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/tasks/remove.yml @@ -1,13 +1,13 @@ - name: Create directory for generated files ansible.builtin.file: - path: "{{ kibana_output_directory }}" + path: "{{ opensearch_dashboards_output_directory }}" state: directory mode: u+rwx - name: Prepare yaml file for {{ item }} ansible.builtin.template: src: "{{ item }}.yaml.j2" - dest: "{{ kibana_output_directory }}/{{ item }}.yaml" + dest: "{{ opensearch_dashboards_output_directory }}/{{ item }}.yaml" mode: u+rwx with_items: - deployments @@ -16,7 +16,7 @@ - name: Remove {{ item.name }} kubernetes.core.k8s: state: absent - src: "{{ kibana_output_directory }}/{{ item.name }}.yaml" + src: "{{ opensearch_dashboards_output_directory }}/{{ item.name }}.yaml" wait: true wait_sleep: "{{ item.wait_sleep }}" wait_timeout: "{{ item.wait_timeout }}" @@ -29,8 +29,8 @@ state: absent api_version: route.openshift.io/v1 kind: Route - namespace: "{{ kibana_project_name }}" - name: kibana + namespace: "{{ opensearch_dashboards_project_name }}" + name: opensearch_dashboards wait: true wait_sleep: 15 wait_timeout: 120 @@ -40,4 +40,4 @@ name: common tasks_from: remove-empty-project vars: - common_project_name: "{{ kibana_project_name }}" + common_project_name: "{{ opensearch_dashboards_project_name }}" diff --git a/automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/templates/deployments.yaml.j2 b/automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/templates/deployments.yaml.j2 new file mode 100644 index 000000000..ecb828282 --- /dev/null +++ b/automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/templates/deployments.yaml.j2 @@ -0,0 +1,64 @@ +kind: Deployment +apiVersion: apps/v1 +metadata: + name: opensearch-dashboards + namespace: "{{ opensearch_dashboards_project_name }}" + labels: + app: opensearch-dashboards +spec: + replicas: 1 + selector: + matchLabels: + app: opensearch-dashboards + template: + metadata: + labels: + app: opensearch-dashboards + restartPolicy: Always + spec: + containers: + - name: opensearch-dashboards + image: "{{ opensearch_dashboards_image }}" + resources: + requests: + cpu: 50m + memory: 512Mi + limits: + cpu: 1000m + memory: 1536Mi + startupProbe: + tcpSocket: + port: 5601 + timeoutSeconds: 1 + periodSeconds: 20 + successThreshold: 1 + failureThreshold: 30 + readinessProbe: + tcpSocket: + port: 5601 + timeoutSeconds: 1 + periodSeconds: 10 + successThreshold: 1 + failureThreshold: 30 + livenessProbe: + tcpSocket: + port: 5601 + timeoutSeconds: 1 + periodSeconds: 10 + successThreshold: 1 + failureThreshold: 30 + env: + - name: OPENSEARCH_HOSTS + value: 'https://opensearch-ibm-elasticsearch-srv.{{ opensearch_dashboards_cp4ba_project_name }}.svc.cluster.local:443' + - name: OPENSEARCH_USERNAME + value: 'elastic' + - name: OPENSEARCH_PASSWORD + value: '{{ os_password }}' + - name: OPENSEARCH_SSL_VERIFICATIONMODE + value: 'none' + - name: LOGGING_VERBOSE + value: 'true' + ports: + - name: opensearch-dashboards-ui + containerPort: 5601 + protocol: TCP diff --git a/automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/templates/services.yaml.j2 b/automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/templates/services.yaml.j2 new file mode 100644 index 000000000..1c999184c --- /dev/null +++ b/automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/templates/services.yaml.j2 @@ -0,0 +1,15 @@ +kind: Service +apiVersion: v1 +metadata: + name: opensearch-dashboards + namespace: "{{ opensearch_dashboards_project_name }}" + labels: + app: opensearch-dashboards +spec: + ports: + - name: opensearch-dashboards-ui + protocol: TCP + port: 5601 + targetPort: opensearch-dashboards-ui + selector: + app: opensearch-dashboards diff --git a/automation-roles/50-install-cloud-pak/cp4ba/usage/templates/usage.md.j2 b/automation-roles/50-install-cloud-pak/cp4ba/usage/templates/usage.md.j2 index 2ec2e0b7e..90e5ed34c 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/usage/templates/usage.md.j2 +++ b/automation-roles/50-install-cloud-pak/cp4ba/usage/templates/usage.md.j2 @@ -92,18 +92,19 @@ Pre-configured for CPFS Kafka with custom user ( {{ lc_principal_admin_user }} / - UI: https://akhq-{{ akhq_project_name }}.{{ apps_endpoint_domain }} {% endif %} -{% if kibana_enabled == true %} -### Kibana +{% if _current_cp4ba_cluster.cp4ba.enabled == true and (_current_cp4ba_cluster.cp4ba.patterns.foundation.optional_components.bai == true or +_current_cp4ba_cluster.cp4ba.patterns.workflow.enabled == true) and (_current_cp4ba_cluster.opensearch_dashboards_enabled | default(true)) == true %} +### OpenSearch Dashbaords -As elastic search content browser and for BAI dashboards. +As OpenSearch content browser. #### Endpoints -- UI: https://kibana-{{ kibana_project_name }}.{{ apps_endpoint_domain }} +- UI: https://opensearch-dashboards-{{ opensearch_dashboards_project_name }}.{{ apps_endpoint_domain }} #### Credentials -- {{ kibana_admin_user }} / {{ kibana_universal_password }} +- elastic / {{ TODO }} {% endif %} {% if mail_enabled == true %} diff --git a/docs/src/30-reference/configuration/cloud-pak.md b/docs/src/30-reference/configuration/cloud-pak.md index 50d15aef9..247c4a168 100644 --- a/docs/src/30-reference/configuration/cloud-pak.md +++ b/docs/src/30-reference/configuration/cloud-pak.md @@ -633,6 +633,9 @@ cp4ba: # Set to false if you don't want to install (or remove) phpLDAPAdmin phpldapadmin_enabled: true + + # Set to false if you don't want to install (or remove) OpenSearch Dashboards + opensearch_dashboards_enabled: true ``` ### CP4BA main properties @@ -790,3 +793,4 @@ The following properties are defined on the project level. | akhq_enabled | Set to `true` to enable AKHQ. Client for Kafka in CP4BA. | Yes | true, false | | mongo_express_enabled | Set to `true` to enable Mongo Express. Client for MongoDB. | Yes | true, false | | phpldapadmin_enabled | Set to `true` to enable phpLDApAdmin. Client for OpenLDAP. | Yes | true, false | +| opensearch_dashboards_enabled | Set to `true` to enable OpenSearch Dashboards. Client for OpenSearch. | Yes | true, false | diff --git a/sample-configurations/sample-dynamic/config-samples/cp4ba.yaml b/sample-configurations/sample-dynamic/config-samples/cp4ba.yaml index d8c2289e6..df0de1533 100644 --- a/sample-configurations/sample-dynamic/config-samples/cp4ba.yaml +++ b/sample-configurations/sample-dynamic/config-samples/cp4ba.yaml @@ -124,3 +124,6 @@ cp4ba: # Set to false if you don't want to install (or remove) phpLDAPAdmin phpldapadmin_enabled: true + + # Set to false if you don't want to install (or remove) OpenSearch Dashboards + opensearch_dashboards_enabled: true From 9d2b2462b59187ae175694d9db631055d88a7943 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Du=C5=A1ek?= Date: Tue, 18 Jun 2024 08:55:25 +0200 Subject: [PATCH 09/34] Update cp4ba to 24.0.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan Dušek --- .../cp4ba/cp4ba-core/defaults/main.yml | 14 +-- .../cp4ba/cp4ba-core/tasks/predeploy.yml | 10 +- .../cp4ba/cp4ba-core/tasks/remove.yml | 10 +- .../templates/catalogsource.yaml.j2 | 109 ++++++++++++++---- .../cpfs/templates/catalogsource.yaml.j2 | 8 +- 5 files changed, 111 insertions(+), 40 deletions(-) diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/defaults/main.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/defaults/main.yml index e525c239e..d0c37619e 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/defaults/main.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/defaults/main.yml @@ -4,21 +4,17 @@ cp4ba_dir_name: cp4ba ## Should not be changed in particular guide version. ## Version of the Subscription channel as defined on ## https://www.ibm.com/docs/en/cloud-paks/cp-biz-automation/latest?topic=cluster-setting-up-in-openshift-console -cp4ba_operator_channel: v23.2 -## Should not be changed in particular guide version. -## Version of Cloud Pak CASE archive as found on -## https://github.com/IBM/cloud-pak/tree/master/repo/case/ibm-cp-automation e.g. 3.0.1 -cp4ba_case_version: 5.1.3 +cp4ba_operator_channel: v24.0 ## Should not be changed in particular guide version. ## Version of cert-kubernetes folder from Cloud Pak CASE archive e.g. 21.0.1 -cp4ba_case_cert_k8s_version: 23.0.2 +cp4ba_cert_k8s_branch: main # 24.0.0 cp4ba_storage_class_name: "" cp4ba_block_storage_class_name: "" ## Should not be changed in particular guide version. ## Version of Cloud Pak e.g. 20.0.2.1, 20.0.3 -cp4ba_version: 23.0.2 +cp4ba_version: 24.0.0 ## Version in CPFS catalog CatalogSource -cpfs_cs_version: v4-4 +cpfs_cs_version: v4-6-2 ## Name of the CP4BA instance in cr.yaml at path metadata.name cp4ba_cr_meta_name: icp4adeploy ## Name of OCP CP4BA project @@ -33,8 +29,6 @@ cp4ba_postgresql_universal_password: "" cp4ba_mongodb_hostname: "" cp4ba_mongodb_admin_user: "" cp4ba_mail_hostname: "" -cp4ba_kibana_project: "" -cp4ba_kibana_url: "" cp4ba_external_share_google: "" cp4ba_google_client_id: "" cp4ba_google_client_secret: "" diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/predeploy.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/predeploy.yml index 91a5e148b..29a06556c 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/predeploy.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/predeploy.yml @@ -32,12 +32,16 @@ until: ('READY' in catalogsource | json_query('resources[*].status.connectionState.lastObservedState') | unique) with_items: - ibm-cp4a-operator-catalog - - ibm-cs-flink-operator-catalog - - ibm-cs-elastic-operator-catalog - - opencloud-operators-{{ cpfs_cs_version }} + - ibm-opencontent-flink + - ibm-cs-opensearch-catalog + - ibm-cs-install-catalog-{{ cpfs_cs_version }} - bts-operator + - ibm-iam-operator-catalog + - ibm-zen-operator-catalog + - ibm-events-operator-catalog - cloud-native-postgresql-catalog - ibm-fncm-operator-catalog + - ibm-bai-operator-catalog - name: Manage Operator ansible.builtin.include_tasks: predeploy/operator.yml diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/remove.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/remove.yml index 6a7631322..298503aaa 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/remove.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/remove.yml @@ -83,12 +83,16 @@ wait: true with_items: - ibm-cp4a-operator-catalog - - ibm-cs-flink-operator-catalog - - ibm-cs-elastic-operator-catalog - - opencloud-operators + - ibm-opencontent-flink + - ibm-cs-opensearch-catalog + - ibm-cs-install-catalog-{{ cpfs_cs_version }} - bts-operator + - ibm-iam-operator-catalog + - ibm-zen-operator-catalog + - ibm-events-operator-catalog - cloud-native-postgresql-catalog - ibm-fncm-operator-catalog + - ibm-bai-operator-catalog # Based on https://www.ibm.com/docs/en/cpfs?topic=online-uninstalling-foundational-services diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/catalogsource.yaml.j2 b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/catalogsource.yaml.j2 index afb569224..de9ea401f 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/catalogsource.yaml.j2 +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/catalogsource.yaml.j2 @@ -16,7 +16,7 @@ # disclosure restricted by GSA ADP Schedule Contract with IBM Corp. # ############################################################################### -# CP4BA 23.0.2-IF003 catalog +# CP4BA 24.0.0 catalog apiVersion: operators.coreos.com/v1alpha1 kind: CatalogSource metadata: @@ -26,62 +26,62 @@ spec: displayName: ibm-cp4a-operator publisher: IBM sourceType: grpc - image: icr.io/cpopen/ibm-cp-automation-catalog@sha256:916ca9cc9f2a08071274480ee76a5a0886b136aeaf22bf5ba77ccabaaf03f39a + image: icr.io/cpopen/ibm-cp-automation-catalog@sha256:6e3ab074046facca9c02485391a34b5c80588afd8e0c9bd7d1d0edfcb6ed5b4b updateStrategy: registryPoll: interval: 45m --- -# IBM CS Flink Operator Catalog 1.3.15 +# IBM CS Flink Operator Catalog 1.18.1 (2.0.1) apiVersion: operators.coreos.com/v1alpha1 kind: CatalogSource metadata: - name: ibm-cs-flink-operator-catalog + name: ibm-opencontent-flink namespace: "{{ cp4ba_project_name }}" spec: - displayName: IBM CS Flink Operator + displayName: IBM CS Opencontent Flink Catalog publisher: IBM sourceType: grpc - image: icr.io/cpopen/ibm-cs-flink-operator-catalog@sha256:5a744274e32baf10be70aae58c69323d22d34b14bf79759494293b6b109117df + image: >- + icr.io/cpopen/ibm-opencontent-flink-operator-catalog@sha256:880fdd2641a478b5c868c8d8e7459aae599e2f59f499d866dfdc4eccf9c9ed75 updateStrategy: registryPoll: interval: 45m priority: 100 --- -# IBM CS Elastic Operator Catalog 1.3.15 +# IBM CS Opensearch Operator Catalog 1.1.2153 apiVersion: operators.coreos.com/v1alpha1 kind: CatalogSource metadata: - name: ibm-cs-elastic-operator-catalog + name: ibm-cs-opensearch-catalog namespace: "{{ cp4ba_project_name }}" spec: - displayName: IBM CS Elastic Search Operator + displayName: IBM CS Opencontent Opensearch Catalog publisher: IBM sourceType: grpc - image: icr.io/cpopen/ibm-cs-elastic-operator-catalog@sha256:35b4c316cad135283a08d1f06dd9a471f7c6358ade45af3f323944949bd3c88e + image: icr.io/cpopen/opencontent-elasticsearch-operator-catalog@sha256:755b5177805a37c1dbfa450ccd4e8e9cd4798b73835b07663e3915b9c7efadc4 updateStrategy: registryPoll: interval: 45m priority: 100 --- -# IBM Cloud Foundational Services 4.4.0 apiVersion: operators.coreos.com/v1alpha1 kind: CatalogSource metadata: - name: opencloud-operators-v4-4 + name: ibm-cs-install-catalog-v4-6-2 namespace: "{{ cp4ba_project_name }}" annotations: bedrock_catalogsource_priority: '1' spec: - displayName: IBMCS Operators + displayName: IBM CS Install Operators publisher: IBM sourceType: grpc - image: icr.io/cpopen/ibm-common-service-catalog@sha256:e639ec5b8bfc542ef13f8d615fecb8f70ace9231ef8210ad0eb68826e8cecdf3 + image: icr.io/cpopen/ibm-cs-install-catalog@sha256:68738260ffcd7edaacae1c99e41e166f4d4131e0ce3571af05010af9e5eccb49 updateStrategy: registryPoll: interval: 45m - priority: 100 + priority: 100 --- -# IBM Business Teams Service version 3.32.0 +# IBM Business Teams Service version 3.33.1 apiVersion: operators.coreos.com/v1alpha1 kind: CatalogSource metadata: @@ -93,12 +93,66 @@ spec: displayName: BTS Operator publisher: IBM sourceType: grpc - image: icr.io/cpopen/ibm-bts-operator-catalog@sha256:b26469f7ad7e602db95b36f75c4adf61407ebb044690193b0d80da543b9198bf + image: icr.io/cpopen/ibm-bts-operator-catalog@sha256:866f0212eab7bc70cc7fcf7ebdbb4dfac561991f6d25900bd52f33cd90846adf updateStrategy: registryPoll: interval: 45m --- -# Cloud Native PostgresSQL 1.18.7 (4.18.0) +# IBM CS IM Operator Catalog 4.5.1 +apiVersion: operators.coreos.com/v1alpha1 +kind: CatalogSource +metadata: + name: ibm-iam-operator-catalog + namespace: "{{ cp4ba_project_name }}" + annotations: + bedrock_catalogsource_priority: '1' +spec: + displayName: IBM IAM Operator Catalog + publisher: IBM + sourceType: grpc + image: icr.io/cpopen/ibm-iam-operator-catalog@sha256:022616861c676e7607bc5da54f69a048b51cf6f55ab49c932d7a010ccee8d764 + updateStrategy: + registryPoll: + interval: 45m + priority: 100 +--- +# IBM Zen Operator Catalog 5.1.4 +apiVersion: operators.coreos.com/v1alpha1 +kind: CatalogSource +metadata: + name: ibm-zen-operator-catalog + namespace: "{{ cp4ba_project_name }}" + annotations: + bedrock_catalogsource_priority: '1' +spec: + displayName: IBM Zen Operator Catalog + publisher: IBM + sourceType: grpc + image: icr.io/cpopen/ibm-zen-operator-catalog@sha256:690874d908989ddd76e05514c056b09984adff81af8568f7b1a789c057e26d71 + updateStrategy: + registryPoll: + interval: 45m + priority: 100 +--- +# IBM Events Operator Catalog 5.0.1 +apiVersion: operators.coreos.com/v1alpha1 +kind: CatalogSource +metadata: + name: ibm-events-operator-catalog + namespace: "{{ cp4ba_project_name }}" + annotations: + bedrock_catalogsource_priority: '1' +spec: + displayName: IBM Events Operator Catalog + publisher: IBM + sourceType: grpc + image: icr.io/cpopen/ibm-events-operator-catalog@sha256:4cd92e1a78b080cc94beae89c257078314a6a0fae66e8a14512953b1c4004c09 + updateStrategy: + registryPoll: + interval: 45m + priority: 100 +--- +# Cloud Native PostgresSQL 1.18.12 (4.25.0) apiVersion: operators.coreos.com/v1alpha1 kind: CatalogSource metadata: @@ -110,7 +164,7 @@ spec: displayName: Cloud Native Postgresql Catalog publisher: IBM sourceType: grpc - image: icr.io/cpopen/ibm-cpd-cloud-native-postgresql-operator-catalog@sha256:c96aa2e6bce92f2e5e4874116cf1cc1cdd60676499cd04ab1631462b8b883357 + image: icr.io/cpopen/ibm-cpd-cloud-native-postgresql-operator-catalog@sha256:0b46a3ec66622dd4a96d96243602a21d7a29cd854f67a876ad745ec524337a1f updateStrategy: registryPoll: interval: 45m @@ -126,7 +180,22 @@ spec: displayName: ibm-fncm-operator publisher: IBM sourceType: grpc - image: icr.io/cpopen/ibm-fncm-catalog@sha256:c8ca90434c2d9b7846097daab2eeb99168e16fcd9382873af31399119b1ced9f + image: icr.io/cpopen/ibm-fncm-catalog@sha256:758877ed3384f778d9ab869ebdaa6efc1075056c883674b1f1c2966f850b992a updateStrategy: registryPoll: interval: 45m +--- +# BAI stand-alone 2400.2408 catalog +apiVersion: operators.coreos.com/v1alpha1 +kind: CatalogSource +metadata: + name: ibm-bai-operator-catalog + namespace: "{{ cp4ba_project_name }}" +spec: + displayName: ibm-bai-operator + publisher: IBM + sourceType: grpc + image: icr.io/cpopen/ibm-bai-catalog@sha256:84a2dd29379067ef2b56356a938268cf10fc1bb693ff94b7b4df72df244d37e1 + updateStrategy: + registryPoll: + interval: 45m \ No newline at end of file diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cpfs/templates/catalogsource.yaml.j2 b/automation-roles/50-install-cloud-pak/cp4ba/cpfs/templates/catalogsource.yaml.j2 index b61eb7bfb..4cc583bad 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cpfs/templates/catalogsource.yaml.j2 +++ b/automation-roles/50-install-cloud-pak/cp4ba/cpfs/templates/catalogsource.yaml.j2 @@ -11,10 +11,10 @@ metadata: name: ibm-cert-manager-catalog namespace: ibm-cert-manager spec: - displayName: ibm-cert-manager-4.2.2 + displayName: ibm-cert-manager-4.2.4 publisher: IBM sourceType: grpc - image: icr.io/cpopen/ibm-cert-manager-operator-catalog@sha256:955732299dd174524612ec8e8076237a491cedee1264e4e4be39c2a92f48bc39 + image: icr.io/cpopen/ibm-cert-manager-operator-catalog@sha256:41084f653ef84c61443bb1bfffedeffb0bca65f267a56f14fb8757410c6412aa updateStrategy: registryPoll: interval: 45m @@ -26,9 +26,9 @@ metadata: name: ibm-licensing-catalog namespace: ibm-licensing spec: - displayName: ibm-licensing-4.2.2 + displayName: ibm-licensing-4.2.4 publisher: IBM - image: icr.io/cpopen/ibm-licensing-catalog@sha256:dfdd38cac150cd354853ac88d02396a9457d22964f898d10126b4a880b4d0916 + image: icr.io/cpopen/ibm-licensing-catalog@sha256:7435cec615ad3cde5f04a2ad7d22fe8bf22ae063816daac9a211258da21c6866 sourceType: grpc updateStrategy: registryPoll: From 98a71f3d00bbe2dbbb6309c8bc7f7a276a929527 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Du=C5=A1ek?= Date: Tue, 18 Jun 2024 08:55:41 +0200 Subject: [PATCH 10/34] Update ADP db handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan Dušek --- .../cp4ba/cp4ba-core/tasks/db/adp.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/db/adp.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/db/adp.yml index 9a54dd78d..023bb0330 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/db/adp.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/db/adp.yml @@ -109,7 +109,9 @@ bash -c " cd /tmp/_adp_tmp/PG; chmod +x InitBaseDB.sh; + chmod +x CreateBaseDB.sh; chmod +x InitTenantDB.sh; + chmod +x AddTenant.sh; " register: command_status @@ -136,6 +138,8 @@ export base_pwdconfirmed=1; export confirmation=y; export ssl=No; + export table_space_already_defined=1; + export tablespace_name=pg_default; ./InitBaseDB.sh; ' register: command_status @@ -176,6 +180,8 @@ export tenant_ontology=default; export confirmation=y; export ssl=No; + export table_space_already_defined=1; + export tablespace_name=pg_default; ./InitTenantDB.sh; ' register: command_status @@ -216,6 +222,8 @@ export tenant_ontology=default; export confirmation=y; export ssl=No; + export table_space_already_defined=1; + export tablespace_name=pg_default; ./InitTenantDB.sh; ' register: command_status From 1d62168a8d4201f9c97384c6d28ea6fa013cf143 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Du=C5=A1ek?= Date: Tue, 18 Jun 2024 08:56:13 +0200 Subject: [PATCH 11/34] Add cpfs PG to cloudbeaver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan Dušek --- .../cp4ba-core/tasks/postdeploy/cpfs.yml | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/cpfs.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/cpfs.yml index c6c95128c..1e485e5a6 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/cpfs.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/cpfs.yml @@ -85,3 +85,61 @@ common_condition_name: Available common_retries: 80 common_delay: 15 + +- name: Get IM PostgreSQL secret + kubernetes.core.k8s_info: + api_version: v1 + kind: Secret + namespace: "{{ cp4ba_project_name }}" + name: common-service-db-app + register: im_pg_secret + retries: 40 + delay: 15 + +- name: Set IM PosgreSQL password + ansible.builtin.set_fact: + im_pg_password: "{{ im_pg_secret.resources[0].data.password | b64decode }}" + +- name: Add PG to cloudbeaver + ansible.builtin.include_role: + name: common + tasks_from: cloudbeaver-add-pg + vars: + common_cloudbeaver_project: "{{ cp4ba_cloudbeaver_project }}" + common_cloudbeaver_username: "{{ lc_principal_admin_user }}" + common_cloudbeaver_password: "{{ cp4ba_cloudbeaver_universal_password }}" + common_cloudbeaver_connection_name: IM PostgreSQL + common_pg_host: "common-service-db-rw.{{ cp4ba_project_name }}.svc.cluster.local" + common_pg_port: "5432" + common_pg_username: cpadmin + common_pg_password: "{{ im_pg_password }}" + when: _current_cp4ba_cluster.cloudbeaver_enabled + +- name: Get BTS PostgreSQL secret + kubernetes.core.k8s_info: + api_version: v1 + kind: Secret + namespace: "{{ cp4ba_project_name }}" + name: "ibm-bts-cnpg-{{ cp4ba_project_name }}-{{ cp4ba_project_name }}-bts-app" + register: bts_pg_secret + retries: 40 + delay: 15 + +- name: Set BTS PosgreSQL password + ansible.builtin.set_fact: + bts_pg_password: "{{ bts_pg_secret.resources[0].data.password | b64decode }}" + +- name: Add PG to cloudbeaver + ansible.builtin.include_role: + name: common + tasks_from: cloudbeaver-add-pg + vars: + common_cloudbeaver_project: "{{ cp4ba_cloudbeaver_project }}" + common_cloudbeaver_username: "{{ lc_principal_admin_user }}" + common_cloudbeaver_password: "{{ cp4ba_cloudbeaver_universal_password }}" + common_cloudbeaver_connection_name: BTS PostgreSQL + common_pg_host: "ibm-bts-cnpg-{{ cp4ba_project_name }}-{{ cp4ba_project_name }}-bts-rw.{{ cp4ba_project_name }}.svc.cluster.local" + common_pg_port: "5432" + common_pg_username: postgresadmin + common_pg_password: "{{ bts_pg_password }}" + when: _current_cp4ba_cluster.cloudbeaver_enabled From 5efc8e5aa9e6f7ba7d23aafb3153166f8645129f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Du=C5=A1ek?= Date: Tue, 18 Jun 2024 08:56:34 +0200 Subject: [PATCH 12/34] Codestyle in CR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan Dušek --- .../50-install-cloud-pak/cp4ba/cp4ba-core/templates/cr.yaml.j2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/cr.yaml.j2 b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/cr.yaml.j2 index 20f0eebad..963670bb0 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/cr.yaml.j2 +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/cr.yaml.j2 @@ -31,7 +31,7 @@ spec: sc_iam: default_admin_username: cpfsadmin sc_egress_configuration: - sc_restricted_internet_access: false + sc_restricted_internet_access: false trusted_certificate_list: ['global-ca', 'default-ca'] encryption_key_secret: ibm-iaws-shared-key-secret storage_configuration: From 012745fa636ab6fdced854cccbb68e46dc88e63d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Du=C5=A1ek?= Date: Tue, 18 Jun 2024 09:10:44 +0200 Subject: [PATCH 13/34] Update PM to 1.15 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan Dušek --- .../50-install-cloud-pak/cp4ba/pm/defaults/main.yml | 2 +- .../cp4ba/pm/templates/catalogsource.yaml.j2 | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/automation-roles/50-install-cloud-pak/cp4ba/pm/defaults/main.yml b/automation-roles/50-install-cloud-pak/cp4ba/pm/defaults/main.yml index 1d6db8468..8a20f3185 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/pm/defaults/main.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/pm/defaults/main.yml @@ -3,7 +3,7 @@ pm_base_dir: "{{ generic_directory }}" pm_dir_name: pm pm_project_name: "" pm_operator_channel: v3.0 -pm_version: 1.14.4 +pm_version: 1.15.0 pm_storage_class_name: "" pm_universal_password: "" pm_postgresql_project: "" diff --git a/automation-roles/50-install-cloud-pak/cp4ba/pm/templates/catalogsource.yaml.j2 b/automation-roles/50-install-cloud-pak/cp4ba/pm/templates/catalogsource.yaml.j2 index 8a7e1ed08..62723a6f9 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/pm/templates/catalogsource.yaml.j2 +++ b/automation-roles/50-install-cloud-pak/cp4ba/pm/templates/catalogsource.yaml.j2 @@ -1,4 +1,4 @@ -# case 3.1.0 / https://github.com/IBM/cloud-pak/tree/master/repo/case/ibm-process-mining +# case 3.3.0 / https://github.com/IBM/cloud-pak/tree/master/repo/case/ibm-process-mining apiVersion: operators.coreos.com/v1alpha1 kind: CatalogSource metadata: @@ -8,7 +8,7 @@ spec: displayName: IBM ProcessMining Operators publisher: IBM sourceType: grpc - image: icr.io/cpopen/processmining-operator-catalog@sha256:f5cfcb8c13cade29deb5235c3e8bfdceb03255a5c78621b4a3cd76ebc7f146d3 + image: icr.io/cpopen/processmining-operator-catalog@sha256:1ce27f1b47619aaadd2c44ac0aecae1c4b07388fbca31058ba2f0b52bc1d2749 updateStrategy: registryPoll: interval: 45m @@ -28,7 +28,7 @@ spec: registryPoll: interval: 45m --- -# case 5.4.2 / https://github.com/IBM/cloud-pak/tree/master/repo/case/ibm-db2uoperator +# case 5.6.1 / https://github.com/IBM/cloud-pak/tree/master/repo/case/ibm-db2uoperator apiVersion: operators.coreos.com/v1alpha1 kind: CatalogSource metadata: From 184de90d14677b3bd942a91e69167ee2e13d910b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Du=C5=A1ek?= Date: Tue, 18 Jun 2024 11:09:05 +0200 Subject: [PATCH 14/34] Change kibana to opensearch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan Dušek --- .../cp4ba/cp4ba-cluster/tasks/install.yml | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-cluster/tasks/install.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-cluster/tasks/install.yml index 86ec9e16e..113afb6bf 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-cluster/tasks/install.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-cluster/tasks/install.yml @@ -51,11 +51,6 @@ name: mongodb when: mongodb_enabled -- name: Install Kibana - ansible.builtin.include_role: - name: kibana - when: kibana_enabled - - name: Install cloudbeaver ansible.builtin.include_role: name: cloudbeaver @@ -66,12 +61,6 @@ name: roundcube when: mail_enabled and _current_cp4ba_cluster.roundcube_enabled -- name: Install Cerebro - ansible.builtin.include_role: - name: cerebro - when: _current_cp4ba_cluster.cp4ba.enabled and (_current_cp4ba_cluster.cp4ba.patterns.foundation.optional_components.bai or - _current_cp4ba_cluster.cp4ba.patterns.workflow.enabled) and _current_cp4ba_cluster.cerebro_enabled - - name: Install Mongo Express ansible.builtin.include_role: name: mongo_express @@ -91,6 +80,18 @@ name: cp4ba-core when: _current_cp4ba_cluster.cp4ba.enabled +- name: Install Cerebro + ansible.builtin.include_role: + name: cerebro + when: _current_cp4ba_cluster.cp4ba.enabled and (_current_cp4ba_cluster.cp4ba.patterns.foundation.optional_components.bai or + _current_cp4ba_cluster.cp4ba.patterns.workflow.enabled) and _current_cp4ba_cluster.cerebro_enabled + +- name: Install OpenSearch Dashboards + ansible.builtin.include_role: + name: opensearch_dashboards + when: _current_cp4ba_cluster.cp4ba.enabled and (_current_cp4ba_cluster.cp4ba.patterns.foundation.optional_components.bai or + _current_cp4ba_cluster.cp4ba.patterns.workflow.enabled) and (_current_cp4ba_cluster.opensearch_dashboards_enabled | default(true)) + - name: Install AKHQ ansible.builtin.include_role: name: akhq From 825d4a9a3038616c61c4950f0b450b7c32ef98d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Du=C5=A1ek?= Date: Tue, 18 Jun 2024 11:57:02 +0200 Subject: [PATCH 15/34] Remove obsolete PG admin param MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan Dušek --- .../cp4ba/config/tasks/internal-variables.yml | 2 -- .../50-install-cloud-pak/cp4ba/cp4ba-core/defaults/main.yml | 1 - .../50-install-cloud-pak/cp4ba/postgresql/defaults/main.yml | 1 - 3 files changed, 4 deletions(-) diff --git a/automation-roles/50-install-cloud-pak/cp4ba/config/tasks/internal-variables.yml b/automation-roles/50-install-cloud-pak/cp4ba/config/tasks/internal-variables.yml index ba4d6edeb..c1c6eb5c6 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/config/tasks/internal-variables.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/config/tasks/internal-variables.yml @@ -130,7 +130,6 @@ phpldapadmin_openldap_hostname: "{{ ldap_hostname }}" postgresql_action: "{{ global_action }}" postgresql_project_name: "{{ collateral_project_name }}" postgresql_storage_class_name: "{{ storage_class_name }}" -postgresql_admin_user: "{{ principal_admin_user }}" postgresql_universal_password: "{{ universal_password }}" cloudbeaver_action: "{{ global_action }}" @@ -158,7 +157,6 @@ cp4ba_icr_password: "{{ icr_password }}" cp4ba_ldap_hostname: "{{ ldap_hostname }}" cp4ba_postgresql_project: "{{ postgresql_project_name }}" cp4ba_postgresql_hostname: "{{ postgresql_hostname }}" -cp4ba_postgresql_admin_user: "{{ postgresql_admin_user }}" cp4ba_postgresql_universal_password: "{{ postgresql_universal_password }}" cp4ba_mongodb_hostname: "{{ mongodb_hostname }}" cp4ba_mongodb_admin_user: "{{ mongodb_admin_user }}" diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/defaults/main.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/defaults/main.yml index d0c37619e..04aac8a30 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/defaults/main.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/defaults/main.yml @@ -24,7 +24,6 @@ cp4ba_icr_password: "" cp4ba_ldap_hostname: "" cp4ba_postgresql_project: "" cp4ba_postgresql_hostname: "" -cp4ba_postgresql_admin_user: "" cp4ba_postgresql_universal_password: "" cp4ba_mongodb_hostname: "" cp4ba_mongodb_admin_user: "" diff --git a/automation-roles/50-install-cloud-pak/cp4ba/postgresql/defaults/main.yml b/automation-roles/50-install-cloud-pak/cp4ba/postgresql/defaults/main.yml index c0b90854e..1141dd986 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/postgresql/defaults/main.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/postgresql/defaults/main.yml @@ -5,4 +5,3 @@ postgresql_project_name: "" postgresql_universal_password: "" postgresql_storage_class_name: "" postgresql_image: docker.io/bitnami/postgresql:15.7.0-debian-12-r9 -postgresql_admin_user: "" From abd8e414880d0fda90780ff5217ca82af2073639 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Du=C5=A1ek?= Date: Fri, 21 Jun 2024 15:09:47 +0200 Subject: [PATCH 16/34] SPlit usage creation, add cpadminservice user, other MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan Dušek --- .../cp4ba/akhq/tasks/install.yml | 17 +++ .../cp4ba/cerebro/tasks/install.yml | 17 +++ .../cp4ba/cloudbeaver/tasks/install.yml | 21 +++ .../cp4ba/cp4ba-core/tasks/postdeploy/aae.yml | 27 ++++ .../cp4ba/cp4ba-core/tasks/postdeploy/adp.yml | 31 ++++- .../cp4ba/cp4ba-core/tasks/postdeploy/ads.yml | 33 ++++- .../cp4ba/cp4ba-core/tasks/postdeploy/bai.yml | 56 ++++++++ .../cp4ba/cp4ba-core/tasks/postdeploy/ban.yml | 29 ++++ .../cp4ba/cp4ba-core/tasks/postdeploy/bas.yml | 29 ++++ .../cp4ba-core/tasks/postdeploy/bawaut.yml | 64 +++++++++ .../cp4ba-core/tasks/postdeploy/cpfs.yml | 124 ++++++++++++++++++ .../cp4ba-core/tasks/postdeploy/fncm.yml | 89 +++++++++++++ .../cp4ba/cp4ba-core/tasks/postdeploy/odm.yml | 60 ++++++++- .../cp4ba-core/tasks/postdeploy/operator.yml | 77 +++++++++++ .../cp4ba/cp4ba-core/tasks/postdeploy/rr.yml | 31 +++++ .../cp4ba/cp4ba-core/tasks/postdeploy/zen.yml | 49 +++++-- .../cp4ba/cpfs/tasks/install.yml | 81 ++++++++++++ .../cp4ba/gitea/tasks/install.yml | 25 ++++ .../cp4ba/mail/tasks/install.yml | 28 ++++ .../cp4ba/mongo_express/tasks/install.yml | 21 +++ .../cp4ba/mongodb/tasks/install.yml | 29 ++++ .../cp4ba/mssql/tasks/install.yml | 29 ++++ .../cp4ba/nexus/tasks/install.yml | 25 ++++ .../cp4ba/openldap/tasks/install.yml | 65 +++++++++ .../cp4ba/phpldapadmin/tasks/install.yml | 21 +++ .../cp4ba/pm/tasks/install.yml | 54 +++++++- .../cp4ba/postgresql/tasks/install.yml | 29 ++++ .../cp4ba/roundcube/tasks/install.yml | 25 ++++ .../cp4ba/rpa/tasks/install.yml | 21 +++ .../cp4ba/usage/tasks/install.yml | 17 --- .../cp4ba/usage/tasks/set-entry.yml | 21 +++ 31 files changed, 1204 insertions(+), 41 deletions(-) create mode 100644 automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/aae.yml create mode 100644 automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/bai.yml create mode 100644 automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/ban.yml create mode 100644 automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/bas.yml create mode 100644 automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/fncm.yml create mode 100644 automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/operator.yml create mode 100644 automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/rr.yml create mode 100644 automation-roles/50-install-cloud-pak/cp4ba/usage/tasks/set-entry.yml diff --git a/automation-roles/50-install-cloud-pak/cp4ba/akhq/tasks/install.yml b/automation-roles/50-install-cloud-pak/cp4ba/akhq/tasks/install.yml index ee38f54e2..d9729621a 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/akhq/tasks/install.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/akhq/tasks/install.yml @@ -75,3 +75,20 @@ common_service_port: http common_apps_endpoint_domain: "{{ apps_endpoint_domain }}" common_output_directory: "{{ akhq_output_directory }}" + +- name: Set usage entry + ansible.builtin.include_role: + name: usage + tasks_from: set-entry + vars: + usage_entry_name: Extras-AKHQ + usage_entry_value: + "# AKHQ + + As kafka browser. + + ## Endpoints + + - UI: https://akhq-{{ akhq_project_name }}.{{ apps_endpoint_domain }} + + " diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cerebro/tasks/install.yml b/automation-roles/50-install-cloud-pak/cp4ba/cerebro/tasks/install.yml index e251a8fe8..b5da06fa8 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cerebro/tasks/install.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cerebro/tasks/install.yml @@ -70,3 +70,20 @@ common_service_name: cerebro common_apps_endpoint_domain: "{{ apps_endpoint_domain }}" common_output_directory: "{{ cerebro_output_directory }}" + +- name: Set usage entry + ansible.builtin.include_role: + name: usage + tasks_from: set-entry + vars: + usage_entry_name: Extras-Cerebro + usage_entry_value: + "# Cerebro + + As OpenSearch browser. + + ## Endpoints + + - UI: https://cerebro-{{ cerebro_project_name }}.{{ apps_endpoint_domain }} + + " diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cloudbeaver/tasks/install.yml b/automation-roles/50-install-cloud-pak/cp4ba/cloudbeaver/tasks/install.yml index b0d52f9d9..b06002529 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cloudbeaver/tasks/install.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cloudbeaver/tasks/install.yml @@ -168,3 +168,24 @@ common_pg_port: "5432" common_pg_username: postgres common_pg_password: "{{ cloudbeaver_postgresql_universal_password }}" + +- name: Set usage entry + ansible.builtin.include_role: + name: usage + tasks_from: set-entry + vars: + usage_entry_name: Extras-CloudBeaver + usage_entry_value: + "# CloudBeaver + + As DB UI for PostgreSQL, MSSQL + + ## Endpoints + + - CloudBeaver UI: https://cloudbeaver-{{ cloudbeaver_project_name }}.{{ apps_endpoint_domain }} + + ## Credentials + + - UI: {{ principal_admin_user }} / {{ cloudbeaver_universal_password }} + + " diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/aae.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/aae.yml new file mode 100644 index 000000000..f66721b3d --- /dev/null +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/aae.yml @@ -0,0 +1,27 @@ +- name: Get OCP Apps domain + ansible.builtin.include_role: + name: common + tasks_from: apps-endpoint + vars: + common_output_to_var: "apps_endpoint_domain" + +- name: Set usage entry + ansible.builtin.include_role: + name: usage + tasks_from: set-entry + vars: + usage_entry_name: CP4BA-Automation-Application-Engine-AAE + usage_entry_value: + "# Automation Application Engine (AAE) (application pattern) + + ## Endpoints + + - AAE Server apps list: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/ae-workspace/v2/applications + + - AAE API Docs https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/ae-workspace/public/apidoc + + ## Credentials + + - {{ lc_principal_admin_user }} / {{ lc_principal_admin_password }} + + " diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/adp.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/adp.yml index eac76750a..d4a35f922 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/adp.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/adp.yml @@ -28,13 +28,6 @@ - 201 - 422 -- name: Get OCP Apps domain - ansible.builtin.include_role: - name: common - tasks_from: apps-endpoint - vars: - common_output_to_var: "apps_endpoint_domain" - - name: Get IAM token ansible.builtin.include_role: name: common @@ -89,3 +82,27 @@ status_code: - 201 - 200 + +- name: Set usage entry + ansible.builtin.include_role: + name: usage + tasks_from: set-entry + vars: + usage_entry_name: CP4BA-Automation-Document-Processing-ADP + usage_entry_value: + "# CP4BA Automation Document Processing (ADP) (document_processing pattern) + + ## Endpoints + + - CDRA API: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/adp/cdra/cdapi/ + + - Content Project Deployment Service: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/adp/cpds/ibm-dba-content-deployment/ \ + (Note: This URL is meant to use with ADP scripts and not to be accessed as is without context root) + + - Ping page: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/adp/aca/ping + + ## Credentials + + - {{ lc_principal_admin_user }} / {{ lc_principal_admin_password }} + + " diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/ads.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/ads.yml index ba953db65..110c6620d 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/ads.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/ads.yml @@ -154,12 +154,15 @@ Authorization: "Bearer {{ zen_token }}" body_format: json body: - username: "{{ lc_principal_admin_user }}" + username: "{{ item }}" user_roles: - "{{ ads_admin_role_id }}" validate_certs: false status_code: - 200 + with_items: + - cpadminservice + - "{{ lc_principal_admin_user }}" # Based on https://www.ibm.com/docs/en/cloud-paks/cp-biz-automation/latest?topic=credentials-configuring-maven-repository-manager - name: Add Maven credential @@ -212,3 +215,31 @@ register: git_provider_response failed_when: git_provider_response.status != 200 and git_provider_response.json.message is not search('It is not allowed to create more than one git provider.') + +- name: Set usage entry + ansible.builtin.include_role: + name: usage + tasks_from: set-entry + vars: + usage_entry_name: CP4BA-Automation-Decision-Services-ADS + usage_entry_value: + "# Automation Decision Services (ADS) (decisions_ads pattern) + + ## Endpoints + + - Administration: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/ads/admin-platform + + - Runtime OAS: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/ads/runtime/api/swagger-ui + + - Runtime OAS JSON file: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/ads/runtime/api/v1/openapi.json + + - Runtime service invocation template: \ + https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/ads/runtime/api/v1/deploymentSpaces/embedded/decisions/\ + {decisionId}/operations/{operation}/execute (using ZenApiKey Authentication with Zen token \ + (https://www.ibm.com/docs/en/cloud-paks/cp-biz-automation/latest?topic=administering-authorizing-http-requests-by-using-zen-api-key)) + + ## Credentials + + - {{ lc_principal_admin_user }} / {{ lc_principal_admin_password }} + + " diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/bai.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/bai.yml new file mode 100644 index 000000000..d61b6d241 --- /dev/null +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/bai.yml @@ -0,0 +1,56 @@ +- name: Get OCP Apps domain + ansible.builtin.include_role: + name: common + tasks_from: apps-endpoint + vars: + common_output_to_var: "apps_endpoint_domain" + +- name: Get flink password secret + kubernetes.core.k8s_info: + api_version: v1 + kind: Secret + namespace: "{{ cp4ba_project_name }}" + name: "{{ cp4ba_cr_meta_name }}-insights-engine-flink-admin-user" + register: flink_secret + retries: 40 + delay: 15 + +- name: Set flink password + ansible.builtin.set_fact: + flink_password: "{{ flink_secret.resources[0].data.password | b64decode }}" + +- name: Set usage entry + ansible.builtin.include_role: + name: usage + tasks_from: set-entry + vars: + usage_entry_name: CP4BA-Business-Automation-Insights-BAI + usage_entry_value: + "# Business Automation Insights (BAI) (foundation pattern) + + ## Endpoints + + - Business Performance Center UI: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/bai-bpc + + - Business Performance Center About JSON: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/bai-bpc/about.json + + - Business Performance Center UI in BAN: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/icn/navigator/?desktop=BAI + + - Flink: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/bai-flink-ui + + ## Credentials + + - for BAI - {{ lc_principal_admin_user }} / {{ lc_principal_admin_password }} + + - for Flink - eventprocessing-admin / {{ flink_password }} + + #### Extracting generated templates from operator for debug + + ```bash + + oc cp -n {{ cp4ba_project_name }} `oc get pod --no-headers -n {{ cp4ba_project_name }} | grep cp4a-operator | \ + awk '{print $1}'`:/tmp/ansible-operator/runner/tmp/bai/templates/bai_all_in_one.yaml bai_all_in_one.yaml + + ``` + + " diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/ban.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/ban.yml new file mode 100644 index 000000000..65d780021 --- /dev/null +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/ban.yml @@ -0,0 +1,29 @@ +- name: Get OCP Apps domain + ansible.builtin.include_role: + name: common + tasks_from: apps-endpoint + vars: + common_output_to_var: "apps_endpoint_domain" + +- name: Set usage entry + ansible.builtin.include_role: + name: usage + tasks_from: set-entry + vars: + usage_entry_name: CP4BA-Business-Automation-Navigator-BAN + usage_entry_value: + "# Business Automation Navigator (BAN) (foundation pattern) + + ## Endpoints + + - Admin desktop: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/icn/navigator/?desktop=admin + + - Health API: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/icn/navigator/jaxrs/api/health + + - Ping: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/icn/navigator/ping.jsp + + ## Credentials + + - {{ lc_principal_admin_user }} / {{ lc_principal_admin_password }} + + " diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/bas.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/bas.yml new file mode 100644 index 000000000..9fbca0c54 --- /dev/null +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/bas.yml @@ -0,0 +1,29 @@ +- name: Get OCP Apps domain + ansible.builtin.include_role: + name: common + tasks_from: apps-endpoint + vars: + common_output_to_var: "apps_endpoint_domain" + +- name: Set usage entry + ansible.builtin.include_role: + name: usage + tasks_from: set-entry + vars: + usage_entry_name: CP4BA-Business-Automation-Studio-BAS + usage_entry_value: + "# Business Automation Studio (BAS) (foundation pattern) + + ## Endpoints + + - Business Automations Studio: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/bas/BAStudio/build/index.jsp#/automationservices + + - Business Applications Studio: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/bas/BAStudio/build/index.jsp#/apps/platformRepo + + - Playback AAE Server apps list: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/ae-pbk/v2/applications + + ## Credentials + + - {{ lc_principal_admin_user }} / {{ lc_principal_admin_password }} + + " diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/bawaut.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/bawaut.yml index 8d09d2033..3379f9777 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/bawaut.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/bawaut.yml @@ -46,3 +46,67 @@ status_code: - 200 with_items: "{{ lc_general_groups + lc_admin_groups }}" + + +- name: Set usage entry + ansible.builtin.include_role: + name: usage + tasks_from: set-entry + vars: + usage_entry_name: CP4BA-Business-Automation-Workflow-Authoring-BAWAUT + usage_entry_value: + "# Business Automation Workflow Authoring (BAWAUT) + + ## Endpoints + + - Process Portal: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/bas/ProcessPortal + + - Process Admin: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/bas/ProcessAdmin + + - Process Inspector: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/bas/ProcessInspector + + - OAS REST API: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/bas/bpm/explorer + + - OAS REST API Operations: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/bas/bpm/explorer/?url=/bas/ops/docs + + - OAS REST API Case: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/bas/bpm/explorer/?url=/bas/case/docs + + - Original REST API: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/bas/bpmrest-ui + + - PFS federated systems: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/bas/rest/bpm/federated/v1/systems + + - Workplace on App Engine: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/icn/navigator/?desktop=workplace \ + (If you encounter error stating that you are using self-signed certificates, clear you cookies) + + - Workplace on BAS: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/bas/Workplace + + - Case monitor: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/icn/navigator/?desktop=bawmonitor + + - Case Client: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/icn/navigator/?desktop=baw + + - Case administration: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/icn/navigator/?desktop=bawadmin + + - Case REST endpoint: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/bas/CaseManager/CASEREST/ + + - Case Builder: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/bas/CaseBuilder + + - FNCM Server definition in BAW: + + - Host name: icp4adeploy-cmis-svc.cp4ba.svc.cluster.local + + - Port: 9443 + + - Context path: /cmis/openfncmis_wlp/services + + - Secure server: true + + - Repository: depends on which you want to connect in internal FNCM (e.g. BAWDOCS or OS1) + + - Credentials as in Credentials section + + + ## Credentials + + - {{ lc_principal_admin_user }} / {{ lc_principal_admin_password }} + + " diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/cpfs.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/cpfs.yml index 1e485e5a6..ef4d7aaeb 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/cpfs.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/cpfs.yml @@ -143,3 +143,127 @@ common_pg_username: postgresadmin common_pg_password: "{{ bts_pg_password }}" when: _current_cp4ba_cluster.cloudbeaver_enabled + +- name: Set usage entry for BTS + ansible.builtin.include_role: + name: usage + tasks_from: set-entry + vars: + usage_entry_name: CP4BA-CPFS-Business-Teams-Service-BTS + usage_entry_value: + "# Business Teams Service (BTS) + + ## Endpoints + + - Admin UI: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/teamserver/ui + + - API Explorer: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/teamserver/api/explorer + + - Teams API: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/teamserver/rest + + ## Credentials + + - {{ lc_principal_admin_user }} / {{ lc_principal_admin_password }} + + " + +- name: Set usage entry for Zen + ansible.builtin.include_role: + name: usage + tasks_from: set-entry + vars: + usage_entry_name: CP4BA-CPFS-Platform-UI-Zen-UI + usage_entry_value: + "# Platform UI + + ## Endpoints + + - Platform UI (Zen UI): https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/zen/ + + ## Credentials + + - {{ lc_principal_admin_user }} / {{ lc_principal_admin_password }} + + " + +- name: Get OpenSearch password secret + kubernetes.core.k8s_info: + api_version: v1 + kind: Secret + namespace: "{{ cp4ba_project_name }}" + name: "opensearch-ibm-elasticsearch-cred-secret" + register: os_secret + retries: 40 + delay: 15 + +- name: Set OpenSearch password + ansible.builtin.set_fact: + os_password: "{{ os_secret.resources[0].data.elastic | b64decode }}" + +- name: Set usage entry for OpenSearch + ansible.builtin.include_role: + name: usage + tasks_from: set-entry + vars: + usage_entry_name: CP4BA-CPFS-OpenSearch + usage_entry_value: + "# OpenSearch + + ## Endpoints + + - OpenSearch: https://opensearch-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }} + + ## Credentials + + - elastic / {{ os_password }} + + " + when: _current_cp4ba_cluster.cp4ba.patterns.workflow.enabled or _current_cp4ba_cluster.cp4ba.patterns.foundation.optional_components.bai + +- name: Get OpenSearch password secret + kubernetes.core.k8s_info: + api_version: v1 + kind: Secret + namespace: "{{ cp4ba_project_name }}" + name: "icp4ba-kafka-auth-0" + register: kafka_secret + retries: 40 + delay: 15 + +- name: Set OpenSearch password + ansible.builtin.set_fact: + kafka_password: "{{ kafka_secret.resources[0].data.password | b64decode }}" + +- name: Set usage entry for Kafka + ansible.builtin.include_role: + name: usage + tasks_from: set-entry + vars: + usage_entry_name: CP4BA-CPFS-Kafka + usage_entry_value: + "# Kafka + + ## Endpoints + + - Kafka: iaf-system-kafka-bootstrap-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}:443 + + ## Credentials + + - icp4ba-kafka-auth-0 / {{ kafka_password }} (username: ```oc get kafkauser icp4ba-kafka-auth-0 -n {{ cp4ba_project_name }} \ + -o jsonpath='{.status.username}'```, password: ```oc get secret -n {{ cp4ba_project_name }} \ + $(oc get kafkauser icp4ba-kafka-auth-0 -n {{ cp4ba_project_name }} -o jsonpath='{.status.secret}') \ + -o jsonpath='{.data.password}' | base64 -d```) + + - Alternative custom user: cpadmin / {{ universal_password }} + + ## Configuration for Kafka connection + + - Security protocol: Sasl Ssl + + - Sasl Mechanism: SCRAM-SHA-512 + + - Root CA cert (used in *Path to root CA certificates file*): \ + ```oc get kafka iaf-system -n {{ cp4ba_project_name }} -o jsonpath='{.status.listeners[1].certificates[0]}'``` + + " + when: _current_cp4ba_cluster.cp4ba.patterns.workflow.enabled or _current_cp4ba_cluster.cp4ba.patterns.foundation.optional_components.bai diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/fncm.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/fncm.yml new file mode 100644 index 000000000..4c7b69d00 --- /dev/null +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/fncm.yml @@ -0,0 +1,89 @@ +- name: Get OCP Apps domain + ansible.builtin.include_role: + name: common + tasks_from: apps-endpoint + vars: + common_output_to_var: "apps_endpoint_domain" + +- name: Set usage entry + ansible.builtin.include_role: + name: usage + tasks_from: set-entry + vars: + usage_entry_name: CP4BA-FileNet-Content-Manager-FNCM + usage_entry_value: + "# FileNet Content Manager (FNCM) (content pattern) + + ## Endpoints + + For external share you need to use ingress prefixed set of endpoints. + + - ACCE console UI: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/cpe/acce + + - CPE WSI endpoint: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/cpe/wsi/FNCEWS40MTOM \ + (https://cpe-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/wsi/FNCEWS40MTOM) + + - CPE health check: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/cpe/P8CE/Health + + - CPE ping page: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/cpe/FileNet/Engine + + - CPE automatic upgrade status endpoint: https://cpe-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/FileNet/AutomaticUpgradeStatus + + - PE ping page: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/cpe/peengine/IOR/ping + + - PE details page: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/cpe/peengine/IOR/admin/help + + - CSS health check: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/cpe/P8CE/Health/CBRDashboard \ + (https://cpe-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/P8CE/Health/CBRDashboard) + + - CMIS definitions UI: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/cmis/openfncmis_wlp + + - CMIS endpoint: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/cmis/openfncmis_wlp/services (e.g. for BAW CMIS) + + - GraphiQL UI: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/content-services-graphql + + - GraphQL endpoint: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/content-services-graphql/graphql + + - OS1 Desktop: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/icn/navigator/?desktop=OS1 + + - External Share ingress for navigator: https://ingress-es-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/navigator/?desktop=admin + + - External Share ingress for plugin: https://ingress-es-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/contentapi/plugins/sharePlugin.jar + + - External Share ingress for rest endpoint: https://ingress-es-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/contentapi/rest/share/v1/info + + - External Share ingress for desktop: https://ingress-es-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/navigator/?desktop=OS1 + + - External Share ingress for external desktop: https://ingress-es-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/navigator/?desktop=ExternalShareOS1 + + - Task Manager API endpoint: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/tm/api/v1 + + - Task Manager Ping page: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/tm/api/v1/tasks/ping + + - IER application plugin: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/ier/EnterpriseRecordsPlugin/IERApplicationPlugin.jar + + #### Credentials + + - {{ lc_principal_admin_user }} / {{ lc_principal_admin_password }} + + ## Other + + If you want FDM to connect to CPE, you need to provide it with Zen certificate. To do it update DeploymentManager.ini file and add to it + + ```text + + # Overrides default TLS. + + -Dcom.ibm.jsse2.overrideDefaultTLS=true + + # Path to your truststrore.jks containing Zen certificate chain. Can be download e.g. from ODM Decision center. + + -Djavax.net.ssl.trustStore=C:\\truststore.jks + + # Password for the truststore if any. If none completely omit the line. + + -Djavax.net.ssl.trustStorePassword=password + + ``` + + " diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/odm.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/odm.yml index 1a198c16e..c445a7d08 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/odm.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/odm.yml @@ -67,7 +67,7 @@ Authorization: "Bearer {{ zen_token }}" body_format: json body: - username: "{{ lc_principal_admin_user }}" + username: "{{ item }}" user_roles: - odm_admin_role - odm_runtime_admin_role @@ -76,6 +76,10 @@ validate_certs: false status_code: - 200 + with_items: + - cpadminservice + - "{{ lc_principal_admin_user }}" + - name: Add ODM regular roles to group {{ item }} ansible.builtin.uri: @@ -136,8 +140,10 @@ - name: Find zen api key ansible.builtin.set_fact: - zen_api_key: "{{ usage.resources[0].data['cpadminservice-zen-api-key'] + zen_api_key: "{{ usage.resources[0].data['cpadminservice-zen-api-key'] | regex_search(regexp,'\\1') if usage.resources | length != 0 and usage.resources[0].data['cpadminservice-zen-api-key'] is defined }}" + vars: + regexp: 'key: (.*)' - name: Update credentials for server ansible.builtin.uri: @@ -180,3 +186,53 @@ status_code: - 200 register: server_update_response + +- name: Set usage entry + ansible.builtin.include_role: + name: usage + tasks_from: set-entry + vars: + usage_entry_name: CP4BA-Automation-Decision-Services-ADS + usage_entry_value: + "# Operational Decision Manager (ODM) (decisions pattern) + + You may get 400 not authorized error when accessing endpoints. In this case clear cookies and refresh browser. + + ## Endpoints + + - Decision Center UI: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/odm/decisioncenter + + - Decision Center OAS: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/odm/decisioncenter-api + + - Decision Center remote API jars: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/\ + odm/decisioncenter/assets/decision-center-client-api.zip \ + (details on https://www.ibm.com/docs/en/odm/latest?topic=8110-accessing-decision-center-remotely-from-java-client) + + - Decision Center build command API jars: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/odm/decisioncenter/assets/buildcommand.zip \ + (details on https://www.ibm.com/docs/en/odm/latest?topic=8110-automating-project-builds-build-command) + + - Decision Center custom data providers API jars: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/\ + odm/decisioncenter/assets/decision-center-client-api.zip \ + (details on https://www.ibm.com/docs/en/odm/latest?topic=8110-setting-up-custom-data-providers) + + - Decision Center truststore: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/odm/decisioncenter/assets/truststore.jks + + - Decision Center OIDC providers: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/odm/decisioncenter/assets/OdmOidcProvidersRD.json + + - Decision Runner UI: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/odm/DecisionRunner + + - Decision Server Console: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/odm/res + + - Decision Server Runtime: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/odm/DecisionService + + ## Credentials + + - {{ lc_principal_admin_user }} / {{ lc_principal_admin_password }} for access through web UIs + + - odmAdmin / {{ universal_password }} who can be used for ODM REST Basic Auth + + - For ODM REST auth with {{ lc_principal_admin_user }} user or other LDAP users, follow guide on \ + https://www.ibm.com/docs/en/cloud-paks/cp-biz-automation/latest?\ + topic=access-using-zen-api-key-authentication with REST Authorization header with ZenApiKey type + + " diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/operator.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/operator.yml new file mode 100644 index 000000000..2c050401a --- /dev/null +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/operator.yml @@ -0,0 +1,77 @@ +- name: Get OCP Apps domain + ansible.builtin.include_role: + name: common + tasks_from: apps-endpoint + vars: + common_output_to_var: "apps_endpoint_domain" + +- name: Set usage entry + ansible.builtin.include_role: + name: usage + tasks_from: set-entry + vars: + usage_entry_name: CP4BA-Operators-useful-info + usage_entry_value: + "# Useful info + + If you want to investigate the actual ansible code that is running in the operator, \ + you can get it from running operator pod from /opt/ansible/roles directory. + + ```bash + + # CP4BA + + mkdir cp4ba-ansible-roles + + oc rsync -n {{ cp4ba_project_name }} `oc get pod -n {{ cp4ba_project_name }} --no-headers -l name=ibm-cp4a-operator |\ + awk '{print $1}'`:/opt/ansible/roles cp4ba-ansible-roles + + # Content + + mkdir content-ansible-roles + + oc rsync -n {{ cp4ba_project_name }} `oc get pod -n {{ cp4ba_project_name }} --no-headers -l name=ibm-content-operator |\ + awk '{print $1}'`:/opt/ansible/roles content-ansible-roles + + # DPE + + mkdir dpe-ansible-roles + + oc rsync -n {{ cp4ba_project_name }} `oc get pod -n {{ cp4ba_project_name }} --no-headers -l name=ibm-dpe-operator |\ + awk '{print $1}'`:/opt/ansible/roles dpe-ansible-roles + + # Foundation + + mkdir foundation-ansible-roles + + oc rsync -n {{ cp4ba_project_name }} `oc get pod -n {{ cp4ba_project_name }} --no-headers -l name=icp4a-foundation-operator |\ + awk '{print $1}'`:/opt/ansible/roles foundation-ansible-roles + + ``` + + + Order of capabilities deployment can be found in operator code in */opt/ansible/roles/icp4a/tasks/main.yml*. + + + To get logs from Operator. + + ```bash + + oc logs deployment/ibm-cp4a-operator > cp4ba-operator.log + + ``` + + + In operator log you can search for error using *playbook task failed*. + + Operator loop in cp4ba-operator.log begins with output *TASK [Gathering Facts]*. + + If you want to determine Operator version use the following command. + + ```bash + + oc exec -it -n {{ cp4ba_project_name }} `oc get pod -n {{ cp4ba_project_name }} | grep ibm-cp4a-operator | awk '{print $1}'` -- cat /opt/ibm/version.txt + + ``` + + " diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/rr.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/rr.yml new file mode 100644 index 000000000..8e576cf19 --- /dev/null +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/rr.yml @@ -0,0 +1,31 @@ +- name: Get OCP Apps domain + ansible.builtin.include_role: + name: common + tasks_from: apps-endpoint + vars: + common_output_to_var: "apps_endpoint_domain" + +- name: Set usage entry + ansible.builtin.include_role: + name: usage + tasks_from: set-entry + vars: + usage_entry_name: CP4BA-Resource-Registry-RR + usage_entry_value: + "# Resource Registry (RR) (foundation pattern) + + ## Endpoints + + - Version info: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/resreg/version + + ## Reading content of ETCD from RR container terminal + + ```bash + + etcdctl get --from-key '' --insecure-skip-tls-verify=true --user=\"root:{{ universal_password }}\" \ + --endpoints=https://{{ cp4ba_project_name }}-dba-rr-client.{{ cp4ba_project_name }}.svc:2379 \ + --insecure-transport=true --cacert=¨\"/shared/resources/tls/ca-cert.pem\" + + ``` + + " diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/zen.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/zen.yml index 45cfb8e37..6e7ee152b 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/zen.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/zen.yml @@ -290,15 +290,29 @@ - 409 register: cpfsadmin_response -- name: Get IAM token - ansible.builtin.include_role: - name: common - tasks_from: iam-token-user - vars: - common_cpfs_project: "{{ cp4ba_project_name }}" - common_user: "cpfsadmin" - common_password: "{{ cp4ba_universal_password }}" - common_output_to_var: "iam_token" +- name: Add cpadminservice to zen + ansible.builtin.uri: + url: "https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/usermgmt/v1/user" + method: POST + headers: + Content-Type: application/json + Authorization: "Bearer {{ zen_token }}" + body_format: json + body: + username: cpadminservice + displayName: cpadminservice + user_roles: + - zen_administrator_role + - iaf-automation-admin + - iaf-automation-analyst + - iaf-automation-developer + - iaf-automation-operator + - zen_user_role + validate_certs: false + status_code: + - 201 + - 409 + register: cpadminservice_response - name: Get Usage configmap kubernetes.core.k8s_info: @@ -354,13 +368,22 @@ zen_api_key_new: "{{ zen_api_key_response.json.apiKey }}" # Regenerate usage with zen_api_key - - name: Generate usage + - name: Set usage entry for cpadminservice user ansible.builtin.include_role: name: usage + tasks_from: set-entry + vars: + usage_entry_name: cpadminservice-zen-api-key + usage_entry_value: + "Based on https://www.ibm.com/docs/en/cloud-paks/cp-biz-automation/23.0.2?topic=access-using-zen-api-key-authentication + If you need to call CP4BA endpoints with ZenApiKey (e.g. for ODM) a service account with username \ + *cpadminservice* has been prepared for you with the generated api key. - - name: Assign zen api key for further post deploy task - ansible.builtin.set_fact: - zen_api_key: "{{ zen_api_key_new }}" + Zen API key for cpadminservice user as generated in the UI: {{ zen_api_key_new }} + + Zen API key for cpadminservice user in the form of header: ZenApiKey {{ 'cpadminservice:' + zen_api_key_new | b64encode }} + + " - name: Get Zen PostgreSQL secret kubernetes.core.k8s_info: diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cpfs/tasks/install.yml b/automation-roles/50-install-cloud-pak/cp4ba/cpfs/tasks/install.yml index a5f0cf95d..78f971c03 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cpfs/tasks/install.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cpfs/tasks/install.yml @@ -330,3 +330,84 @@ sender: reporterSecretToken: ibm-license-service-reporter-token reporterURL: "https://{{ reporter_route.resources[0].spec.host }}" + +- name: Get OCP Apps Endpoint + ansible.builtin.include_role: + name: common + tasks_from: apps-endpoint + vars: + common_output_to_var: "apps_endpoint_domain" + when: apps_endpoint_domain is not defined + +- name: Set usage entry for CPFS + ansible.builtin.include_role: + name: usage + tasks_from: set-entry + vars: + usage_entry_name: CPFS-Base + usage_entry_value: + "# CPFS Base + + As Cloud Pak Foundational Services. + + ## Endpoints + + - Console UI: https://cp-console-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }} + + - IAM login page: https://cp-console-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/oidc/login.jsp + + ## Credentials + + - for CPFS admin: cpfsadmin / {{ cpfs_universal_password }} (IBM provided credentials (admin only)) + + - for CP4BA admin: {{ lc_principal_admin_user }} / {{ lc_principal_admin_password }} (Enterprise LDAP) + + " + +- name: Get License Service secret + kubernetes.core.k8s_info: + api_version: v1 + kind: Secret + namespace: ibm-licensing + name: ibm-licensing-token + register: ls_secret + retries: 40 + delay: 15 + +- name: Set License Service token + ansible.builtin.set_fact: + ls_token: "{{ ls_secret.resources[0].data.token | b64decode }}" + +- name: Set usage entry for License Service + ansible.builtin.include_role: + name: usage + tasks_from: set-entry + vars: + usage_entry_name: CPFS-License-Service + usage_entry_value: + "# License Service + + ## Endpoints + + - Base page: https://ibm-licensing-service-instance-ibm-licensing.{{ apps_endpoint_domain }} + + - Direct status page: https://ibm-licensing-service-instance-ibm-licensing.{{ apps_endpoint_domain }}/status?token={{ ls_token }} + (token generated by `oc get secret ibm-licensing-token -o jsonpath={.data.token} -n ibm-licensing | base64 -d`) + + - License Service Reporter: https://ibm-lsr-console-ibm-lsr.{{ apps_endpoint_domain }}/license-service-reporter + + - credentials {{ lc_principal_admin_user }} / {{ cpfs_universal_password }} + + ## Getting license info + + Based on https://www.ibm.com/docs/en/cpfs?topic=service-obtaining-updating-api-token + + Based on https://www.ibm.com/docs/en/cpfs?topic=pcfls-apis#auditSnapshot + + ```bash + + curl -kL https:/ibm-licensing-service-instance-ibm-licensing.{{ apps_endpoint_domain }}/snapshot?token={{ ls_token }} --output snapshot.zip + + ``` + + " diff --git a/automation-roles/50-install-cloud-pak/cp4ba/gitea/tasks/install.yml b/automation-roles/50-install-cloud-pak/cp4ba/gitea/tasks/install.yml index 6c1e52533..1925c94c9 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/gitea/tasks/install.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/gitea/tasks/install.yml @@ -66,3 +66,28 @@ validate_certs: false force_basic_auth: true status_code: 204 + +- name: Set usage entry + ansible.builtin.include_role: + name: usage + tasks_from: set-entry + vars: + usage_entry_name: Extras-Gitea + usage_entry_value: + "# Gitea + + As Git server provider. + + ## Endpoints + + - UI: https://gitea-{{ gitea_project_name }}.{{ apps_endpoint_domain }} + + - OAS: https://gitea-{{ gitea_project_name }}.{{ apps_endpoint_domain }}/api/swagger#/ + + ## Credentials + + - Credentials you should use: {{ lc_principal_admin_user }} / {{ lc_principal_admin_password }} + + - Initial administrative user credentials: giteaadmin / {{ gitea_universal_password }} + + " diff --git a/automation-roles/50-install-cloud-pak/cp4ba/mail/tasks/install.yml b/automation-roles/50-install-cloud-pak/cp4ba/mail/tasks/install.yml index f3f6bad87..e7c945413 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/mail/tasks/install.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/mail/tasks/install.yml @@ -93,3 +93,31 @@ - {name: secrets, wait_sleep: 15, wait_timeout: 15} - {name: statefulsets, wait_sleep: 15, wait_timeout: 600} - {name: services, wait_sleep: 15, wait_timeout: 15} + +- name: Set usage entry + ansible.builtin.include_role: + name: usage + tasks_from: set-entry + vars: + usage_entry_name: Extras-Mail + usage_entry_value: + "# Mail + + As mail server. + + Emails sent to cpadmin@{{ lc_ldap_domain }}, cpadmin1@{{ lc_ldap_domain }}, cpadmin2@{{ lc_ldap_domain }}, \ + cpuser@{{ lc_ldap_domain }}, cpuser1@{{ lc_ldap_domain }}, cpuser2@{{ lc_ldap_domain }} \ + will be delivered in their respective mailboxes. \ + Any email received at other *\\*@{{ lc_ldap_domain }} will be delivered to *{{ lc_principal_admin_user }}*. + + ## Endpoints + + - Exposed as NodePort as found in Project *{{ mail_project_name }}* in Service *mail*. + + ## Credentials + + - for admin: {{ lc_principal_admin_user }}@{{ lc_ldap_domain }}/ {{ mail_universal_password }} + + - for user: cpuser@{{ lc_ldap_domain }} / {{ mail_universal_password }} + + " diff --git a/automation-roles/50-install-cloud-pak/cp4ba/mongo_express/tasks/install.yml b/automation-roles/50-install-cloud-pak/cp4ba/mongo_express/tasks/install.yml index 03ada3514..57858f827 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/mongo_express/tasks/install.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/mongo_express/tasks/install.yml @@ -50,3 +50,24 @@ common_service_name: mongo-express common_apps_endpoint_domain: "{{ apps_endpoint_domain }}" common_output_directory: "{{ mongo_express_output_directory }}" + +- name: Set usage entry + ansible.builtin.include_role: + name: usage + tasks_from: set-entry + vars: + usage_entry_name: Extras-Mongo-Express + usage_entry_value: + "# Mongo Express + + As UI for MongoDB + + ## Endpoints + + - Mongo Express UI: https://mongo-express-{{ mongo_express_project_name }}.{{ apps_endpoint_domain }} + + ## Credentials + + - {{ principal_admin_user }} / {{ mongo_express_universal_password }} + + " diff --git a/automation-roles/50-install-cloud-pak/cp4ba/mongodb/tasks/install.yml b/automation-roles/50-install-cloud-pak/cp4ba/mongodb/tasks/install.yml index d4b73ffc0..f3dd269a1 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/mongodb/tasks/install.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/mongodb/tasks/install.yml @@ -35,3 +35,32 @@ - {name: secrets, wait_sleep: 15, wait_timeout: 15} - {name: statefulsets, wait_sleep: 15, wait_timeout: 600} - {name: services, wait_sleep: 15, wait_timeout: 15} + +- name: Set usage entry + ansible.builtin.include_role: + name: usage + tasks_from: set-entry + vars: + usage_entry_name: Pre-requisites-MongoDB + usage_entry_value: + "# MongoDB + + As MongoDB database storage for the platform. + + ## Endpoints + + - Exposed as NodePort as found in Project *{{ mongodb_project_name }}* in Service *mongodb*. + + ## Credentials + + - root / {{ mongodb_universal_password }} / authentication database is *admin* + + ## CLI in container + + ```bash + + mongo --username root --password {{ mongodb_universal_password }} --authenticationDatabase admin + + ``` + + " diff --git a/automation-roles/50-install-cloud-pak/cp4ba/mssql/tasks/install.yml b/automation-roles/50-install-cloud-pak/cp4ba/mssql/tasks/install.yml index 24fe3e257..205d75c08 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/mssql/tasks/install.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/mssql/tasks/install.yml @@ -39,3 +39,32 @@ - {name: secrets, wait_sleep: 15, wait_timeout: 15} - {name: statefulsets, wait_sleep: 15, wait_timeout: 600} - {name: services, wait_sleep: 15, wait_timeout: 15} + +- name: Set usage entry + ansible.builtin.include_role: + name: usage + tasks_from: set-entry + vars: + usage_entry_name: Pre-requisites-MSSQL + usage_entry_value: + "# MSSQL + + As DB server for RPA. + + ## Endpoints + + - Exposed as NodePort as found in Project *{{ mssql_project_name }}* in Service *mssql*. + + ## Credentials + + - sa / {{ mssql_universal_password }} + + ## CLI in container + + ```bash + + /opt/mssql-tools/bin/sqlcmd -S 127.0.0.1 -U sa -P {{ mssql_universal_password }} + + ``` + + " diff --git a/automation-roles/50-install-cloud-pak/cp4ba/nexus/tasks/install.yml b/automation-roles/50-install-cloud-pak/cp4ba/nexus/tasks/install.yml index c533c4ed8..b4d070613 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/nexus/tasks/install.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/nexus/tasks/install.yml @@ -249,3 +249,28 @@ status_code: 204 return_content: true register: nexus_response + +- name: Set usage entry + ansible.builtin.include_role: + name: usage + tasks_from: set-entry + vars: + usage_entry_name: Extras-Nexus + usage_entry_value: + "# Nexus + + As package manager. + + ## Endpoints + + - UI: https://nexus-{{ nexus_project_name }}.{{ apps_endpoint_domain }}/ + + - OAS: https://nexus-{{ nexus_project_name }}.{{ apps_endpoint_domain }}/service/rest/swagger.json + + ## Credentials + + - Credentials you should use: {{ lc_principal_admin_user }} / {{ lc_principal_admin_password }} + + - Initial administrative user credentials: admin / {{ nexus_universal_password }} + + " diff --git a/automation-roles/50-install-cloud-pak/cp4ba/openldap/tasks/install.yml b/automation-roles/50-install-cloud-pak/cp4ba/openldap/tasks/install.yml index 0c725df1b..064feae61 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/openldap/tasks/install.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/openldap/tasks/install.yml @@ -37,3 +37,68 @@ - {name: persistentvolumeclaims, wait_sleep: 15, wait_timeout: 300} - {name: deployments, wait_sleep: 15, wait_timeout: 600} - {name: services, wait_sleep: 15, wait_timeout: 15} + +- name: Set usage entry + ansible.builtin.include_role: + name: usage + tasks_from: set-entry + vars: + usage_entry_name: Pre-requisites-OpenLDAP + usage_entry_value: + "# OpenLDAP + + As LDAP directory provider. + + ## Endpoints + + - Exposed as NodePort as found in Project *{{ openldap_project_name }}* in Service *openldap*. + + ## Credentials + + - {{ lc_bind_admin_user }} / {{ lc_bind_admin_password }} + + ## Users and Groups + + LDAP contains the following users in {{ lc_ldap_user_base_dn }}.: + + - {{ lc_principal_admin_user }}/{{ lc_principal_admin_password }} + + - cpadmin1/{{ openldap_universal_password }} + + - cpadmin2/{{ openldap_universal_password }} + + - cpuser/{{ openldap_universal_password }} + + - cpuser1/{{ openldap_universal_password }} + + - cpuser2/{{ openldap_universal_password }} + + LDAP contains the following groups in {{ lc_ldap_group_base_dn }}: + + - {{ lc_principal_admin_group }} - members: {{ lc_ldap_user_id_attribute }}={{ lc_principal_admin_user }},{{ lc_ldap_user_base_dn }}; \ + {{ lc_ldap_user_id_attribute }}=cpadmin1,{{ lc_ldap_user_base_dn }}; {{ lc_ldap_user_id_attribute }}=cpadmin2,{{ lc_ldap_user_base_dn }} + + - cpusers - members: {{ lc_ldap_user_id_attribute }}={{ lc_principal_admin_user }},{{ lc_ldap_user_base_dn }}; \ + {{ lc_ldap_user_id_attribute }}=cpadmin1,{{ lc_ldap_user_base_dn }}; {{ lc_ldap_user_id_attribute }}=cpadmin2,{{ lc_ldap_user_base_dn }}; \ + {{ lc_ldap_user_id_attribute }}=cpuser,{{ lc_ldap_user_base_dn }}; {{ lc_ldap_user_id_attribute }}=cpuser1,{{ lc_ldap_user_base_dn }}; \ + {{ lc_ldap_user_id_attribute }}=cpuser2,{{ lc_ldap_user_base_dn }} + + - cpusers1 - members: {{ lc_ldap_user_id_attribute }}=cpuser,{{ lc_ldap_user_base_dn }}; \ + {{ lc_ldap_user_id_attribute }}=cpuser1,{{ lc_ldap_user_base_dn }}; \ + {{ lc_ldap_user_id_attribute }}=cpuser2,{{ lc_ldap_user_base_dn }} + + ## CLI in OpenLDAP Pod + + ```bash + + #Search for regular attributes + + ldapsearch -x -b \"{{ lc_ldap_base_dn }}\" -H ldap://localhost:1389 -D '{{ lc_bind_admin_user }}' -w {{ lc_bind_admin_password }} \"objectclass=*\" + + #Search for hidden attributes + + ldapsearch -x -b \"{{ lc_ldap_base_dn }}\" -H ldap://localhost:1389 -D '{{ lc_bind_admin_user }}' -w {{ lc_bind_admin_password }} \"objectclass=*\" '+' + + ``` + + " diff --git a/automation-roles/50-install-cloud-pak/cp4ba/phpldapadmin/tasks/install.yml b/automation-roles/50-install-cloud-pak/cp4ba/phpldapadmin/tasks/install.yml index c6e3782fc..0d4262e6a 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/phpldapadmin/tasks/install.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/phpldapadmin/tasks/install.yml @@ -56,3 +56,24 @@ common_service_name: phpldapadmin common_apps_endpoint_domain: "{{ apps_endpoint_domain }}" common_output_directory: "{{ phpldapadmin_output_directory }}" + +- name: Set usage entry + ansible.builtin.include_role: + name: usage + tasks_from: set-entry + vars: + usage_entry_name: Extras-phpLDAPadmin + usage_entry_value: + "# phpLDAPadmin + + As LDAP management tool. + + ## Endpoints + + - PHP LDAP admin management console: https://phpldapadmin-{{ phpldapadmin_project_name }}.{{ apps_endpoint_domain }}/ + + ## Credentials + + - {{ lc_bind_admin_user }} / {{ lc_bind_admin_password }} + + " diff --git a/automation-roles/50-install-cloud-pak/cp4ba/pm/tasks/install.yml b/automation-roles/50-install-cloud-pak/cp4ba/pm/tasks/install.yml index ca34f1a63..06a94f414 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/pm/tasks/install.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/pm/tasks/install.yml @@ -215,8 +215,9 @@ Cookie: ibm-private-cloud-session={{ zen_token }} validate_certs: false return_content: true + status_code: + - 200 register: groups_response - until: groups_response.status == 200 retries: 10 delay: 60 @@ -277,6 +278,8 @@ status_code: - 200 register: groups_response + retries: 10 + delay: 60 - name: Get TaskMiningAdmins group ansible.builtin.set_fact: @@ -536,3 +539,52 @@ wait: true wait_sleep: 15 wait_timeout: 15 + +- name: Set usage entry + ansible.builtin.include_role: + name: usage + tasks_from: set-entry + vars: + usage_entry_name: Process-Mining + usage_entry_value: + "# Process Mining + + ## Endpoints + + - Process Mining UI & API base: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/processmining + + - Process Mining User Profile (to determine user API key) \ + https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/processmining/api/account/profile + + - Task Mining UI: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/taskmining + + - Process Mining non Zen Route: https://processmining-pm-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/ + + ## Credentials + + - {{ lc_principal_admin_user }} / {{ lc_principal_admin_password }} + + ## Useful info + + If you want to investigate the actual ansible code that is running in the operator,\ + you can get it from running operator pod from /opt/ansible/roles directory. + + ```bash + + mkdir pm-ansible-roles + + oc rsync -n {{ cp4ba_project_name }} `oc get pod -n {{ cp4ba_project_name }} --no-headers |\ + grep processmining-operator-controller-manager | awk '{print $1}'`:/opt/ansible/roles pm-ansible-roles + + ``` + + To get logs for Operator. + + ```bash + + oc get pods -n {{ cp4ba_project_name }} -o name | grep processmining-operator-controller |\ + xargs oc logs -n {{ cp4ba_project_name }} > process-mining-operator.log + + ``` + + " diff --git a/automation-roles/50-install-cloud-pak/cp4ba/postgresql/tasks/install.yml b/automation-roles/50-install-cloud-pak/cp4ba/postgresql/tasks/install.yml index c6675f56e..ca8907132 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/postgresql/tasks/install.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/postgresql/tasks/install.yml @@ -37,3 +37,32 @@ - {name: secrets, wait_sleep: 15, wait_timeout: 15} - {name: statefulsets, wait_sleep: 15, wait_timeout: 600} - {name: services, wait_sleep: 15, wait_timeout: 15} + +- name: Set usage entry + ansible.builtin.include_role: + name: usage + tasks_from: set-entry + vars: + usage_entry_name: Pre-requisites-PostgreSQL + usage_entry_value: + "# PostgreSQL + + As PostgreSQL database storage for the platform. + + ## Endpoints + + - Exposed as NodePort as found in Project *{{ postgresql_project_name }}* in Service *postgresql*. + + ## Credentials + + - postgres / {{ postgresql_universal_password }} + + ## CLI in container + + ```bash + + psql postgresql://postgres:$POSTGRES_PASSWORD@localhost:5432 + + ``` + + " diff --git a/automation-roles/50-install-cloud-pak/cp4ba/roundcube/tasks/install.yml b/automation-roles/50-install-cloud-pak/cp4ba/roundcube/tasks/install.yml index e54b262fe..2718e88e7 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/roundcube/tasks/install.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/roundcube/tasks/install.yml @@ -62,3 +62,28 @@ common_service_name: roundcube-nginx common_apps_endpoint_domain: "{{ apps_endpoint_domain }}" common_output_directory: "{{ roundcube_output_directory }}" + +- name: Set usage entry + ansible.builtin.include_role: + name: usage + tasks_from: set-entry + vars: + usage_entry_name: Extras-Roundcube + usage_entry_value: + "# Roundcube + + As mail client. + + ## Endpoints + + - UI: https://roundcube-{{ roundcube_project_name }}.{{ apps_endpoint_domain }} + + ## Credentials + + - for admin: {{ lc_principal_admin_user }}@{{ lc_ldap_domain }} / {{ roundcube_universal_password }} \ + (you can also use only *{{ lc_principal_admin_user }}* without domain as username to login) + + - for other users: cpadmin1, cpadmin2, cpuser, cpuser1, cpuser2 with domain @{{ lc_ldap_domain }} / {{ roundcube_universal_password }} \ + (you can also use only the usernames without domain to login) + + " diff --git a/automation-roles/50-install-cloud-pak/cp4ba/rpa/tasks/install.yml b/automation-roles/50-install-cloud-pak/cp4ba/rpa/tasks/install.yml index 611c4e21f..7e0be32a5 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/rpa/tasks/install.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/rpa/tasks/install.yml @@ -355,3 +355,24 @@ wait: true wait_sleep: 15 wait_timeout: 15 + +- name: Set usage entry + ansible.builtin.include_role: + name: usage + tasks_from: set-entry + vars: + usage_entry_name: RPA + usage_entry_value: + "# RPA + + # Endpoints + + - UI: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/rpa/ui + + - API: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/rpa/api/v1.2/en/configuration + + # Credentials + + - {{ lc_principal_admin_user }} / {{ lc_principal_admin_password }} + + " diff --git a/automation-roles/50-install-cloud-pak/cp4ba/usage/tasks/install.yml b/automation-roles/50-install-cloud-pak/cp4ba/usage/tasks/install.yml index ce3b78b09..497f6eeba 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/usage/tasks/install.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/usage/tasks/install.yml @@ -1,20 +1,3 @@ -- name: Get OCP Apps domain - ansible.builtin.include_role: - name: common - tasks_from: apps-endpoint - vars: - common_output_to_var: "apps_endpoint_domain" - -- name: Set path to usage.md - ansible.builtin.set_fact: - usage_path: "{{ generic_directory }}/usage.md" - -- name: Prepare Usage md - ansible.builtin.template: - src: usage.md.j2 - dest: "{{ usage_path }}" - mode: u+rwx - - name: Prepare usage Config Map ansible.builtin.template: src: usage-configmap.yaml.j2 diff --git a/automation-roles/50-install-cloud-pak/cp4ba/usage/tasks/set-entry.yml b/automation-roles/50-install-cloud-pak/cp4ba/usage/tasks/set-entry.yml new file mode 100644 index 000000000..bd5be2ee5 --- /dev/null +++ b/automation-roles/50-install-cloud-pak/cp4ba/usage/tasks/set-entry.yml @@ -0,0 +1,21 @@ +# Example of the functionality call +# +# - name: Set usage entry +# ansible.builtin.include_role: +# name: usage +# tasks_from: set-entry +# vars: +# usage_entry_name: _usage_entry_name +# usage_entry_value: _usage_entry_value + +- name: Set usage entry + kubernetes.core.k8s: + state: present + api_version: v1 + kind: ConfigMap + name: "{{ _current_cp4ba_cluster.project }}-usage" + namespace: cloud-pak-deployer + definition: | + data: + {{ usage_entry_name }}: | + {{ usage_entry_value | indent(4) }} From a5879b05ba50422226cb3b2f09713fe0173633c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Du=C5=A1ek?= Date: Fri, 21 Jun 2024 15:10:08 +0200 Subject: [PATCH 17/34] Remove obsolete usage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan Dušek --- .../cp4ba/usage/templates/usage.md.j2 | 645 ------------------ 1 file changed, 645 deletions(-) delete mode 100644 automation-roles/50-install-cloud-pak/cp4ba/usage/templates/usage.md.j2 diff --git a/automation-roles/50-install-cloud-pak/cp4ba/usage/templates/usage.md.j2 b/automation-roles/50-install-cloud-pak/cp4ba/usage/templates/usage.md.j2 deleted file mode 100644 index 90e5ed34c..000000000 --- a/automation-roles/50-install-cloud-pak/cp4ba/usage/templates/usage.md.j2 +++ /dev/null @@ -1,645 +0,0 @@ -# Usage & Operations - -This file contains endpoints, credentials and other useful information about capabilities installed in the platform. - -- [Extras](#extras) -- [CP4BA - CP4BA capabilities](#cp4ba---cp4ba-capabilities) -- [CP4BA - CPFS dedicated capabilities](#cp4ba---cpfs-dedicated-capabilities) -{% if _current_cp4ba_cluster.pm.enabled == true %} -- [Process Mining](#process-mining) -{% endif %} -{% if _current_cp4ba_cluster.rpa.enabled == true %} -- [RPA](#rpa) -{% endif %} -- [CPFS](#cpfs) -- [Pre-requisites](#pre-requisites) - -## Extras - -{% if gitea_enabled == true %} -### Gitea - -As Git server provider. - -#### Endpoints - -UI: https://gitea-{{ gitea_project_name }}.{{ apps_endpoint_domain }} -OAS: https://gitea-{{ gitea_project_name }}.{{ apps_endpoint_domain }}/api/swagger#/ - -#### Credentials - -- Credentials you should use: {{ lc_principal_admin_user }} / {{ lc_principal_admin_password }} -- Initial administrative user credentials: giteaadmin / {{ universal_password }} - -{% endif %} -{% if nexus_enabled == true %} -### Nexus - -As package manager. - -#### Endpoints - -UI: https://nexus-{{ nexus_project_name }}.{{ apps_endpoint_domain }}/ -OAS: https://nexus-{{ nexus_project_name }}.{{ apps_endpoint_domain }}/service/rest/swagger.json - -#### Credentials - -- Credentials you should use: {{ lc_principal_admin_user }} / {{ lc_principal_admin_password }} -- Initial administrative user credentials: admin / {{ universal_password }} - -{% endif %} -{% if mail_enabled == true and _current_cp4ba_cluster.roundcube_enabled == true %} -### Roundcube - -As mail client. - -#### Endpoints - -- UI: https://roundcube-{{ roundcube_project_name }}.{{ apps_endpoint_domain }} - -#### Credentials - -- for admin: {{ lc_principal_admin_user }}@{{ lc_ldap_domain }} / {{ universal_password }} (you can also use only *{{ lc_principal_admin_user }}* without domain as username to login) -- for other users: cpadmin1, cpadmin2, cpuser, cpuser1, cpuser2 with domain @{{ lc_ldap_domain }} / {{ universal_password }} (you can also use only the usernames without domain to login) - -{% endif %} -{% if _current_cp4ba_cluster.cp4ba.enabled == true and (_current_cp4ba_cluster.cp4ba.patterns.foundation.optional_components.bai == true or -_current_cp4ba_cluster.cp4ba.patterns.workflow.enabled == true) and _current_cp4ba_cluster.cerebro_enabled == true %} -### Cerebro - -As elastic search browser. - -Pre-configured for CPFS elastic search. - -#### Endpoints - -- UI: https://cerebro-{{ cerebro_project_name }}.{{ apps_endpoint_domain }} - -#### Credentials - -- {{ cerebro_elasticsearch_admin_user }} / {{ cerebro_elasticsearch_universal_password }} - -{% endif %} -{% if _current_cp4ba_cluster.cp4ba.enabled == true and _current_cp4ba_cluster.cp4ba.patterns.foundation.optional_components.bai == true and _current_cp4ba_cluster.akhq_enabled == true %} -### AKHQ - -As kafka browser. - -Pre-configured for CPFS Kafka with custom user ( {{ lc_principal_admin_user }} / {{ lc_principal_admin_password }} ). Admin credentials can be found in this doc in [CPFS Kafka section](#kafka). - -#### Endpoints - -- UI: https://akhq-{{ akhq_project_name }}.{{ apps_endpoint_domain }} - -{% endif %} -{% if _current_cp4ba_cluster.cp4ba.enabled == true and (_current_cp4ba_cluster.cp4ba.patterns.foundation.optional_components.bai == true or -_current_cp4ba_cluster.cp4ba.patterns.workflow.enabled == true) and (_current_cp4ba_cluster.opensearch_dashboards_enabled | default(true)) == true %} -### OpenSearch Dashbaords - -As OpenSearch content browser. - -#### Endpoints - -- UI: https://opensearch-dashboards-{{ opensearch_dashboards_project_name }}.{{ apps_endpoint_domain }} - -#### Credentials - -- elastic / {{ TODO }} - -{% endif %} -{% if mail_enabled == true %} -### Mail - -As mail server. - -Emails sent to cpadmin@{{ lc_ldap_domain }}, cpadmin1@{{ lc_ldap_domain }}, cpadmin2@{{ lc_ldap_domain }}, cpuser@{{ lc_ldap_domain }}, cpuser1@{{ lc_ldap_domain }}, cpuser2@{{ lc_ldap_domain }} will be delivered in their respective mailboxes. Any email received at other *\*@{{ lc_ldap_domain }} will be delivered to *{{ lc_principal_admin_user }}*. - -#### Endpoints - -- Exposed as NodePort as found in Project *{{ mail_project_name }}* in Service *mail*. - -#### Credentials - -- for admin: {{ lc_principal_admin_user }}@{{ lc_ldap_domain }}/ {{ mail_universal_password }} -- for user: cpuser@{{ lc_ldap_domain }} / {{ mail_universal_password }} - -{% endif %} -{% if mongodb_enabled == true and _current_cp4ba_cluster.mongo_express_enabled == true %} -### Mongo Express - -As UI for MongoDB - -#### Endpoints - -- Mongo Express UI: https://mongo-express-{{ mongo_express_project_name }}.{{ apps_endpoint_domain }} - -#### Credentials - -- {{ principal_admin_user }} / {{ universal_password }} - -{% endif %} -{% if openldap_enabled == true and _current_cp4ba_cluster.phpldapadmin_enabled == true %} -### phpLDAPadmin - -As LDAP management tool. - -#### Endpoints - -- PHP LDAP admin management console: https://phpldapadmin-{{ phpldapadmin_project_name }}.{{ apps_endpoint_domain }}/ - -#### Credentials - -- {{ lc_bind_admin_user }} / {{ lc_bind_admin_password }} - -{% endif %} -{% if (postgresql_enabled == true or mssql_enabled == true) and _current_cp4ba_cluster.cloudbeaver_enabled == true %} -### CloudBeaver - -As DB UI for PostgreSQL, MSSQL - -#### Endpoints - -- CloudBeaver UI: https://cloudbeaver-{{ cloudbeaver_project_name }}.{{ apps_endpoint_domain }} - -#### Credentials - -- UI: {{ principal_admin_user }} / {{ universal_password }} - -{% endif %} -{% if _current_cp4ba_cluster.cp4ba.enabled == true %} -## CP4BA - CP4BA capabilities - -### Zen service account credentials - -Based on https://www.ibm.com/docs/en/cloud-paks/cp-biz-automation/23.0.2?topic=access-using-zen-api-key-authentication -If you need to call CP4BA endpoints with ZenApiKey (e.g. for ODM) a service account with username *cpadminservice* has been prepared for you with the generated api key which can be found in Project *cloud-pak-deployer* in ConfigMap *cp4ba-usage* in *cpadminservice-zen-api-key* key. - -### Useful info - -If you want to investigate the actual ansible code that is running in the operator, you can get it from running operator pod from /opt/ansible/roles directory. -```bash -# CP4BA -mkdir cp4ba-ansible-roles -oc rsync -n {{ cp4ba_project_name }} `oc get pod -n {{ cp4ba_project_name }} --no-headers -l name=ibm-cp4a-operator | awk '{print $1}'`:/opt/ansible/roles cp4ba-ansible-roles -# Content -mkdir content-ansible-roles -oc rsync -n {{ cp4ba_project_name }} `oc get pod -n {{ cp4ba_project_name }} --no-headers -l name=ibm-content-operator | awk '{print $1}'`:/opt/ansible/roles content-ansible-roles -# DPE -mkdir dpe-ansible-roles -oc rsync -n {{ cp4ba_project_name }} `oc get pod -n {{ cp4ba_project_name }} --no-headers -l name=ibm-dpe-operator | awk '{print $1}'`:/opt/ansible/roles dpe-ansible-roles -# Foundation -mkdir foundation-ansible-roles -oc rsync -n {{ cp4ba_project_name }} `oc get pod -n {{ cp4ba_project_name }} --no-headers -l name=icp4a-foundation-operator | awk '{print $1}'`:/opt/ansible/roles foundation-ansible-roles -``` - -Order of capabilities deployment can be found in operator code in */opt/ansible/roles/icp4a/tasks/main.yml*. - -To get logs from Operator. -```bash -oc logs deployment/ibm-cp4a-operator > cp4ba-operator.log -``` - -In operator log you can search for error using *playbook task failed*. - -Operator loop in cp4ba-operator.log begins with output *TASK [Gathering Facts]*. - -If you want to determine Operator version use the following command. -```bash -oc exec -it -n {{ cp4ba_project_name }} `oc get pod -n {{ cp4ba_project_name }} | grep ibm-cp4a-operator | awk '{print $1}'` -- cat /opt/ibm/version.txt -``` - -### Resource Registry (RR) (foundation pattern) - -#### Endpoints - -- Version info: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/resreg/version - -#### Reading content of ETCD from RR container terminal - -```bash -etcdctl get --from-key '' --insecure-skip-tls-verify=true --user="root:{{ universal_password }}" --endpoints=https://{{ cp4ba_project_name }}-dba-rr-client.{{ cp4ba_project_name }}.svc:2379 --insecure-transport=true --cacert="/shared/resources/tls/ca-cert.pem" -``` - -### Business Automation Navigator (BAN) (foundation pattern) - -#### Endpoints - -- Admin desktop: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/icn/navigator/?desktop=admin -- Health API: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/icn/navigator/jaxrs/api/health -- Ping: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/icn/navigator/ping.jsp - -#### Credentials - -- {{ lc_principal_admin_user }} / {{ lc_principal_admin_password }} - -{% if _current_cp4ba_cluster.cp4ba.patterns.foundation.optional_components.bai == true %} -### Business Automation Studio (BAS) (foundation pattern) - -#### Endpoints - -- Playback AAE Server apps list: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/ae-pbk/v2/applications - -#### Credentials - -- {{ lc_principal_admin_user }} / {{ lc_principal_admin_password }} - -{% endif %} -{% if _current_cp4ba_cluster.cp4ba.patterns.foundation.optional_components.bai == true %} -### Business Automation Insights (BAI) (foundation pattern) - -#### Endpoints - -- Business Performance Center UI: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/bai-bpc -- Business Performance Center About JSON: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/bai-bpc/about.json -- Business Performance Center UI in BAN: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/icn/navigator/?desktop=BAI -- Flink: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/bai-flink-ui - -#### Credentials - -- for BAI - {{ lc_principal_admin_user }} / {{ lc_principal_admin_password }} -- for Flink - username: eventprocessing-admin (```oc get secret -n {{ cp4ba_project_name }} $(oc get InsightsEngine -n {{ cp4ba_project_name }} {{ cp4ba_cr_meta_name }} -o jsonpath='{.status.components.flinkUi.endpoints[0].authentication.secret.secretName}') -o jsonpath='{.data.username}' | base64 -d```) / password: ```oc get secret -n {{ cp4ba_project_name }} $(oc get InsightsEngine -n {{ cp4ba_project_name }} {{ cp4ba_cr_meta_name }} -o jsonpath='{.status.components.flinkUi.endpoints[0].authentication.secret.secretName}') -o jsonpath='{.data.password}' | base64 -d``` - -#### Extracting generated templates from operator for debug - -```bash -oc cp -n {{ cp4ba_project_name }} `oc get pod --no-headers -n {{ cp4ba_project_name }} | grep cp4a-operator | awk '{print $1}'`:/tmp/ansible-operator/runner/tmp/bai/templates/bai_all_in_one.yaml bai_all_in_one.yaml -``` -{% endif %} - -{% if _current_cp4ba_cluster.cp4ba.patterns.decisions.enabled == true %} -### Operational Decision Manager (ODM) (decisions pattern) - -You may get 400 not authorized error when accessing endpoints. In this case clear cookies and refresh browser. - -#### Endpoints - -- Decision Center UI: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/odm/decisioncenter -- Decision Center OAS: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/odm/decisioncenter-api -- Decision Center remote API jars: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/odm/decisioncenter/assets/decision-center-client-api.zip (details on https://www.ibm.com/docs/en/odm/latest?topic=8110-accessing-decision-center-remotely-from-java-client) -- Decision Center build command API jars: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/odm/decisioncenter/assets/buildcommand.zip (details on https://www.ibm.com/docs/en/odm/latest?topic=8110-automating-project-builds-build-command) -- Decision Center custom data providers API jars: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/odm/decisioncenter/assets/decision-center-client-api.zip (details on https://www.ibm.com/docs/en/odm/latest?topic=8110-setting-up-custom-data-providers) -- Decision Center truststore: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/odm/decisioncenter/assets/truststore.jks -- Decision Center OIDC providers: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/odm/decisioncenter/assets/OdmOidcProvidersRD.json -- Decision Runner UI: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/odm/DecisionRunner -- Decision Server Console: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/odm/res -- Decision Server Runtime: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/odm/DecisionService - -#### Credentials - -- {{ lc_principal_admin_user }} / {{ lc_principal_admin_password }} for access through web UIs -- odmAdmin / {{ universal_password }} who can be used for ODM REST Basic Auth -- For ODM REST auth with {{ lc_principal_admin_user }} user or other LDAP users, follow guide on https://www.ibm.com/docs/en/cloud-paks/cp-biz-automation/latest?topic=access-using-zen-api-key-authentication with REST Authorization header with ZenApiKey type - -{% endif %} -{% if _current_cp4ba_cluster.cp4ba.patterns.decisions_ads.enabled == true %} -### Automation Decision Services (ADS) (decisions_ads pattern) - -#### Endpoints - -- Administration: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/ads/admin-platform -- Runtime OAS: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/ads/runtime/api/swagger-ui -- Runtime OAS JSON file: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/ads/runtime/api/v1/openapi.json -- Runtime service invocation template: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/ads/runtime/api/v1/deploymentSpaces/embedded/decisions/{decisionId}/operations/{operation}/execute (using ZenApiKey Authentication with Zen token (https://www.ibm.com/docs/en/cloud-paks/cp-biz-automation/latest?topic=administering-authorizing-http-requests-by-using-zen-api-key)) - -#### Credentials - -- {{ lc_principal_admin_user }} / {{ lc_principal_admin_password }} - -{% endif %} -{% if _current_cp4ba_cluster.cp4ba.patterns.content.enabled == true %} -### FileNet Content Manager (FNCM) (content pattern) - -#### Endpoints - -For external share you need to use ingress prefixed set of endpoints. - -- ACCE console UI: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/cpe/acce -- CPE WSI endpoint: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/cpe/wsi/FNCEWS40MTOM (https://cpe-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/wsi/FNCEWS40MTOM) -- CPE health check: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/cpe/P8CE/Health -- CPE ping page: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/cpe/FileNet/Engine -- CPE automatic upgrade status endpoint: https://cpe-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/FileNet/AutomaticUpgradeStatus -- PE ping page: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/cpe/peengine/IOR/ping -- PE details page: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/cpe/peengine/IOR/admin/help -- CSS health check: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/cpe/P8CE/Health/CBRDashboard (https://cpe-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/P8CE/Health/CBRDashboard) -- CMIS definitions UI: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/cmis/openfncmis_wlp -- CMIS endpoint: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/cmis/openfncmis_wlp/services (e.g. for BAW CMIS) -- GraphiQL UI: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/content-services-graphql -- GraphQL endpoint: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/content-services-graphql/graphql -- OS1 Desktop: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/icn/navigator/?desktop=OS1 -- External Share ingress for navigator: https://ingress-es-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/navigator/?desktop=admin -- External Share ingress for plugin: https://ingress-es-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/contentapi/plugins/sharePlugin.jar -- External Share ingress for rest endpoint: https://ingress-es-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/contentapi/rest/share/v1/info -- External Share ingress for desktop: https://ingress-es-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/navigator/?desktop=OS1 -- External Share ingress for external desktop: https://ingress-es-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/navigator/?desktop=ExternalShareOS1 -- Task Manager API endpoint: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/tm/api/v1 -- Task Manager Ping page: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/tm/api/v1/tasks/ping -- IER application plugin: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/ier/EnterpriseRecordsPlugin/IERApplicationPlugin.jar - -#### Credentials - -- {{ lc_principal_admin_user }} / {{ lc_principal_admin_password }} - -#### Other - -If you want FDM to connect to CPE, you need to provide it with Zen certificate. To do it update DeploymentManager.ini file and add to it -```text -# Overrides default TLS. --Dcom.ibm.jsse2.overrideDefaultTLS=true -# Path to your truststrore.jks containing Zen certificate chain. Can be download e.g. from ODM Decision center. --Djavax.net.ssl.trustStore=C:\\truststore.jks -# Password for the truststore if any. If none completely omit the line. --Djavax.net.ssl.trustStorePassword=password -``` - -{% endif %} -{% if _current_cp4ba_cluster.cp4ba.patterns.foundation.optional_components.ae == true %} -### Automation Application Engine (AAE) (application pattern) - -#### Endpoints - -- AAE Server apps list: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/ae-workspace/v2/applications -- AAE API Docs https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/ae-workspace/public/apidoc - -#### Credentials - -- {{ lc_principal_admin_user }} / {{ lc_principal_admin_password }} - -{% endif %} -{% if _current_cp4ba_cluster.cp4ba.patterns.document_processing.enabled == true %} -### Automation Document Processing (ADP) (document_processing pattern) - -#### Endpoints - -- CDRA API: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/adp/cdra/cdapi/ -- Content Project Deployment Service: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/adp/cpds/ibm-dba-content-deployment/ (Note: This URL is meant to use with ADP scripts and not to be accessed as is without context root) -- Ping page: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/adp/aca/ping - -#### Credentials - -- {{ lc_principal_admin_user }} / {{ lc_principal_admin_password }} - -{% endif %} -{% if _current_cp4ba_cluster.cp4ba.patterns.workflow.enabled and _current_cp4ba_cluster.cp4ba.patterns.workflow.optional_components.baw_authoring == true %} -### Business Automation Workflow Authoring (BAWAUT) - -#### Endpoints - -- Process Portal: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/bas/ProcessPortal -- Process Admin: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/bas/ProcessAdmin -- Process Inspector: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/bas/ProcessInspector -- OAS REST API: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/bas/bpm/explorer -- OAS REST API Operations: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/bas/bpm/explorer/?url=/bas/ops/docs -- OAS REST API Case: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/bas/bpm/explorer/?url=/bas/case/docs -- Original REST API: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/bas/bpmrest-ui -- PFS federated systems: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/bas/rest/bpm/federated/v1/systems -- Workplace on App Engine: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/icn/navigator/?desktop=workplace (If you encounter error stating that you are using self-signed certificates, clear you cookies) -- Workplace on BAS: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/bas/Workplace -- Case monitor: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/icn/navigator/?desktop=bawmonitor -- Case Client: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/icn/navigator/?desktop=baw -- Case administration: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/icn/navigator/?desktop=bawadmin -- Case REST endpoint: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/bas/CaseManager/CASEREST/ -- Case Builder: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/bas/CaseBuilder -- FNCM Server definition in BAW: - - Host name: icp4adeploy-cmis-svc.cp4ba.svc.cluster.local - - Port: 9443 - - Context path: /cmis/openfncmis_wlp/services - - Secure server: true - - Repository: depends on which you want to connect in internal FNCM (e.g. BAWDOCS or OS1) - - Credentials as in Credentials section - -#### Credentials - -- {{ lc_principal_admin_user }} / {{ lc_principal_admin_password }} - -{% endif %} -## CP4BA - CPFS dedicated capabilities - -### BTS - -#### Endpoints - -- Admin UI: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/teamserver/ui -- API Explorer: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/teamserver/api/explorer -- Teams API: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/teamserver/rest - -#### Credentials - -- {{ lc_principal_admin_user }} / {{ lc_principal_admin_password }} - -### Platform UI - -#### Endpoints - -- Platform UI (Zen UI): https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/zen/ - -#### Credentials - -- {{ lc_principal_admin_user }} / {{ lc_principal_admin_password }} - -{% if _current_cp4ba_cluster.cp4ba.patterns.workflow.enabled == true or _current_cp4ba_cluster.cp4ba.patterns.foundation.optional_components.bai == true %} -### Elastic Search - -#### Endpoints - -- Elastic Search: https://iaf-system-es-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }} - -#### Credentials - -- {{ elasticsearch_admin_user }} / {{ elasticsearch_universal_password }} - -{% endif %} -{% if (_current_cp4ba_cluster.cp4ba.patterns.workflow.enabled == true and _current_cp4ba_cluster.cp4ba.patterns.workflow.optional_components.kafka == true) or _current_cp4ba_cluster.cp4ba.patterns.foundation.optional_components.bai == true %} -### Kafka - -#### Endpoints - -- Kafka: iaf-system-kafka-bootstrap-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}:443 - -#### Credentials - -- Username: icp4ba-kafka-auth-0 (```oc get kafkauser icp4ba-kafka-auth-0 -n {{ cp4ba_project_name }} -o jsonpath='{.status.username}'```) -- Password: ```oc get secret -n {{ cp4ba_project_name }} $(oc get kafkauser icp4ba-kafka-auth-0 -n {{ cp4ba_project_name }} -o jsonpath='{.status.secret}') -o jsonpath='{.data.password}' | base64 -d``` - -Alternative custom user: cpadmin / {{ universal_password }} - -#### Configuration for Kafka connection - -- Security protocol: Sasl Ssl -- Sasl Mechanism: SCRAM-SHA-512 -- Root CA cert (used in *Path to root CA certificates file*): ```oc get kafka iaf-system -n {{ cp4ba_project_name }} -o jsonpath='{.status.listeners[1].certificates[0]}'``` - -{% endif %} -{% endif %} -{% if _current_cp4ba_cluster.pm.enabled == true %} -## Process Mining - -### Endpoints - -- Process Mining UI & API base: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/processmining -- Process Mining User Profile (to determine user API key) https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/processmining/api/account/profile -- Task Mining UI: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/taskmining -- Process Mining non Zen Route: https://processmining-pm-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/ -- Task Mining non Zen Route: https://processmining-tm-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/ - -### Credentials - -- {{ lc_principal_admin_user }} / {{ lc_principal_admin_password }} - -{% endif %} -### Useful info - -If you want to investigate the actual ansible code that is running in the operator, you can get it from running operator pod from /opt/ansible/roles directory. -```bash -oc cp -n {{ cp4ba_project_name }} `oc get pod -n {{ cp4ba_project_name }} --no-headers | grep processmining-operator-controller-manager | awk '{print $1}'`:/opt/ansible/roles pm-ansible-roles -``` - -To get logs for Operator. -```bash -oc get pods -n {{ cp4ba_project_name }} -o name | grep processmining-operator-controller | xargs oc logs > process-mining-operator.log -``` - -{% if _current_cp4ba_cluster.rpa.enabled == true %} -## RPA - -### Endpoints - -- UI: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/rpa/ui -- API: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/rpa/api/v1.2/en/configuration - -### Credentials - -- {{ lc_principal_admin_user }} / {{ lc_principal_admin_password }} - -{% endif %} -## CPFS - -As Cloud Pak Foundational Services. - -#### Endpoints - -- Console UI: https://cp-console-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }} -- IAM login page: https://cp-console-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/oidc/login.jsp - -#### Credentials - -- for CPFS admin: cpfsadmin / {{ universal_password }} (IBM provided credentials (admin only)) -- for CP4BA admin: {{ lc_principal_admin_user }} / {{ lc_principal_admin_password }} (Enterprise LDAP) - -### License Service - -#### Endpoints - -- Base page: https://ibm-licensing-service-instance-ibm-licensing.{{ apps_endpoint_domain }} -- Direct status page: https://ibm-licensing-service-instance-ibm-licensing.{{ apps_endpoint_domain }}/status?token=[token] (*[token]* generated by `oc get secret ibm-licensing-token -o jsonpath={.data.token} -n ibm-licensing | base64 -d`) -- License Service Reporter: https://ibm-lsr-console-ibm-lsr.{{ apps_endpoint_domain }}/license-service-reporter - credentials {{ lc_principal_admin_user }} / {{ universal_password }} - -#### Getting license info - -Based on https://www.ibm.com/docs/en/cpfs?topic=service-obtaining-updating-api-token -Based on https://www.ibm.com/docs/en/cpfs?topic=pcfls-apis#auditSnapshot - -```bash -TOKEN=`oc get secret ibm-licensing-token -o jsonpath={.data.token} -n ibm-licensing | base64 -d` -curl -kL https:/ibm-licensing-service-instance-ibm-licensing.{{ apps_endpoint_domain }}/snapshot?token=$TOKEN --output snapshot.zip -``` - -## Pre-requisites - -{% if postgresql_enabled == true %} -### PostgreSQL - -As PostgreSQL database storage for the platform. - -#### Endpoints - -- Exposed as NodePort as found in Project *{{ postgresql_project_name }}* in Service *postgresql*. - -#### Credentials - -- {{ lc_principal_admin_user }} / {{ universal_password }} - -#### CLI in container - -```bash -psql postgresql://postgres:{{ universal_password }}@localhost:5432 -``` - -{% endif %} -{% if openldap_enabled == true %} -### OpenLDAP - -As LDAP directory provider. - -#### Endpoints - -- Exposed as NodePort as found in Project *{{ openldap_project_name }}* in Service *openldap*. - -#### Credentials - -- {{ lc_bind_admin_user }} / {{ lc_bind_admin_password }} - -#### Users and Groups - -LDAP contains the following users in {{ lc_ldap_user_base_dn }}.: -- {{ lc_principal_admin_user }}/{{ lc_principal_admin_password }} -- cpadmin1/{{ universal_password }} -- cpadmin2/{{ universal_password }} -- cpuser/{{ universal_password }} -- cpuser1/{{ universal_password }} -- cpuser2/{{ universal_password }} - -LDAP contains the following groups in {{ lc_ldap_group_base_dn }}: -- {{ lc_principal_admin_group }} - members: {{ lc_ldap_user_id_attribute }}={{ lc_principal_admin_user }},{{ lc_ldap_user_base_dn }}; {{ lc_ldap_user_id_attribute }}=cpadmin1,{{ lc_ldap_user_base_dn }}; {{ lc_ldap_user_id_attribute }}=cpadmin2,{{ lc_ldap_user_base_dn }} -- cpusers - members: {{ lc_ldap_user_id_attribute }}={{ lc_principal_admin_user }},{{ lc_ldap_user_base_dn }}; {{ lc_ldap_user_id_attribute }}=cpadmin1,{{ lc_ldap_user_base_dn }}; {{ lc_ldap_user_id_attribute }}=cpadmin2,{{ lc_ldap_user_base_dn }}; {{ lc_ldap_user_id_attribute }}=cpuser,{{ lc_ldap_user_base_dn }}; {{ lc_ldap_user_id_attribute }}=cpuser1,{{ lc_ldap_user_base_dn }}; {{ lc_ldap_user_id_attribute }}=cpuser2,{{ lc_ldap_user_base_dn }} -- cpusers1 - members: {{ lc_ldap_user_id_attribute }}=cpuser,{{ lc_ldap_user_base_dn }}; {{ lc_ldap_user_id_attribute }}=cpuser1,{{ lc_ldap_user_base_dn }}; {{ lc_ldap_user_id_attribute }}=cpuser2,{{ lc_ldap_user_base_dn }} - -#### CLI in OpenLDAP Pod - -```bash -#Search for regular attributes -ldapsearch -x -b "{{ lc_ldap_base_dn }}" -H ldap://localhost:1389 -D '{{ lc_bind_admin_user }}' -w {{ lc_bind_admin_password }} "objectclass=*" -#Search for hidden attributes -ldapsearch -x -b "{{ lc_ldap_base_dn }}" -H ldap://localhost:1389 -D '{{ lc_bind_admin_user }}' -w {{ lc_bind_admin_password }} "objectclass=*" '+' -``` - -{% endif %} -{% if mssql_enabled == true %} -### MSSQL - -As DB server for RPA. - -#### Endpoints - -- Exposed as NodePort as found in Project *{{ mssql_project_name }}* in Service *mssql*. - -#### Credentials - -- sa / {{ universal_password }} - -#### CLI in container - -```bash -/opt/mssql-tools/bin/sqlcmd -S 127.0.0.1 -U sa -P {{ universal_password }} -``` - -{% endif %} -{% if mongodb_enabled == true %} -### MongoDB - -As MongoDB database storage for the platform. - -#### Endpoints - -- Exposed as NodePort as found in Project *{{ mongodb_project_name }}* in Service *mongodb*. - -#### Credentials - -- root / {{ universal_password }} / authentication database is *admin* - -#### CLI in container - -```bash -mongo --username root --password {{ universal_password }} --authenticationDatabase admin -``` - -{% endif %} From 91da3f0d91cc10ca8b897ff8500d2778408c7e5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Du=C5=A1ek?= Date: Fri, 21 Jun 2024 15:10:30 +0200 Subject: [PATCH 18/34] Add OpenSearch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan Dušek --- .../opensearch_dashboards/tasks/install.yml | 45 +++++++++++++++++-- .../opensearch_dashboards/tasks/remove.yml | 9 ++++ .../templates/deployments.yaml.j2 | 11 ++++- .../templates/rolebindings.yaml.j2 | 15 +++++++ .../templates/serviceaccounts.yaml.j2 | 5 +++ .../templates/services.yaml.j2 | 4 +- 6 files changed, 83 insertions(+), 6 deletions(-) create mode 100644 automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/templates/rolebindings.yaml.j2 create mode 100644 automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/templates/serviceaccounts.yaml.j2 diff --git a/automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/tasks/install.yml b/automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/tasks/install.yml index 61f75d421..2139ce0d2 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/tasks/install.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/tasks/install.yml @@ -12,12 +12,28 @@ common_namespace_name: "{{ opensearch_dashboards_project_name }}" common_output_directory: "{{ opensearch_dashboards_output_directory }}" +- name: Get OpenSearch password secret + kubernetes.core.k8s_info: + api_version: v1 + kind: Secret + namespace: "{{ opensearch_dashboards_cp4ba_project_name }}" + name: "opensearch-ibm-elasticsearch-cred-secret" + register: os_secret + retries: 40 + delay: 15 + +- name: Set OpenSearch password + ansible.builtin.set_fact: + os_password: "{{ os_secret.resources[0].data.elastic | b64decode }}" + - name: Prepare yaml file for {{ item }} ansible.builtin.template: src: "{{ item }}.yaml.j2" dest: "{{ opensearch_dashboards_output_directory }}/{{ item }}.yaml" mode: u+rwx with_items: + - serviceaccounts + - rolebindings - deployments - services @@ -25,12 +41,14 @@ kubernetes.core.k8s: state: present src: "{{ opensearch_dashboards_output_directory }}/{{ item.name }}.yaml" - wait: "{{ item.wait }}" + wait: true wait_sleep: "{{ item.wait_sleep }}" wait_timeout: "{{ item.wait_timeout }}" with_items: - - {name: deployments, wait_sleep: 0, wait_timeout: 0, wait: false} - - {name: services, wait_sleep: 15, wait_timeout: 15, wait: true} + - {name: serviceaccounts, wait_sleep: 15, wait_timeout: 15} + - {name: rolebindings, wait_sleep: 15, wait_timeout: 15} + - {name: deployments, wait_sleep: 15, wait_timeout: 600} + - {name: services, wait_sleep: 15, wait_timeout: 15} - name: Get OCP Apps Endpoint ansible.builtin.include_role: @@ -50,3 +68,24 @@ common_service_name: opensearch-dashboards common_apps_endpoint_domain: "{{ apps_endpoint_domain }}" common_output_directory: "{{ opensearch_dashboards_output_directory }}" + +- name: Set usage entry + ansible.builtin.include_role: + name: usage + tasks_from: set-entry + vars: + usage_entry_name: Extras-OpenSearch-Dashboards + usage_entry_value: + "# OpenSearch Dashboards + + As OpenSearch content browser. + + ## Endpoints + + - UI: https://opensearch-dashboards-{{ opensearch_dashboards_project_name }}.{{ apps_endpoint_domain }} + + ## Credentials + + - elastic / {{ os_password }} + + " diff --git a/automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/tasks/remove.yml b/automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/tasks/remove.yml index 740337443..cf415ed2e 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/tasks/remove.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/tasks/remove.yml @@ -4,12 +4,19 @@ state: directory mode: u+rwx +- name: Mock variables + ansible.builtin.set_fact: + apps_endpoint_domain: mock + os_password: mock + - name: Prepare yaml file for {{ item }} ansible.builtin.template: src: "{{ item }}.yaml.j2" dest: "{{ opensearch_dashboards_output_directory }}/{{ item }}.yaml" mode: u+rwx with_items: + - serviceaccounts + - rolebindings - deployments - services @@ -23,6 +30,8 @@ with_items: - {name: services, wait_sleep: 15, wait_timeout: 15} - {name: deployments, wait_sleep: 15, wait_timeout: 600} + - {name: rolebindings, wait_sleep: 15, wait_timeout: 15} + - {name: serviceaccounts, wait_sleep: 15, wait_timeout: 15} - name: Remove Route kubernetes.core.k8s: diff --git a/automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/templates/deployments.yaml.j2 b/automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/templates/deployments.yaml.j2 index ecb828282..4050632bc 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/templates/deployments.yaml.j2 +++ b/automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/templates/deployments.yaml.j2 @@ -58,7 +58,16 @@ spec: value: 'none' - name: LOGGING_VERBOSE value: 'true' + - name: DISABLE_SECURITY_DASHBOARDS_PLUGIN + value: 'true' ports: - - name: opensearch-dashboards-ui + - name: dashboards-ui containerPort: 5601 protocol: TCP + securityContext: + capabilities: + drop: + - ALL + runAsNonRoot: true + runAsUser: 1000 + serviceAccountName: opensearch-dashboards diff --git a/automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/templates/rolebindings.yaml.j2 b/automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/templates/rolebindings.yaml.j2 new file mode 100644 index 000000000..294b286eb --- /dev/null +++ b/automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/templates/rolebindings.yaml.j2 @@ -0,0 +1,15 @@ +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: opensearch-dashboards-privileged + namespace: "{{ opensearch_dashboards_project_name }}" + labels: + app: opensearch-dashboards +subjects: + - kind: ServiceAccount + name: opensearch-dashboards + namespace: "{{ opensearch_dashboards_project_name }}" +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: 'system:openshift:scc:privileged' diff --git a/automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/templates/serviceaccounts.yaml.j2 b/automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/templates/serviceaccounts.yaml.j2 new file mode 100644 index 000000000..e86e19ae8 --- /dev/null +++ b/automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/templates/serviceaccounts.yaml.j2 @@ -0,0 +1,5 @@ +kind: ServiceAccount +apiVersion: v1 +metadata: + name: opensearch-dashboards + namespace: "{{ opensearch_dashboards_project_name }}" diff --git a/automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/templates/services.yaml.j2 b/automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/templates/services.yaml.j2 index 1c999184c..a200865aa 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/templates/services.yaml.j2 +++ b/automation-roles/50-install-cloud-pak/cp4ba/opensearch_dashboards/templates/services.yaml.j2 @@ -7,9 +7,9 @@ metadata: app: opensearch-dashboards spec: ports: - - name: opensearch-dashboards-ui + - name: dashboards-ui protocol: TCP port: 5601 - targetPort: opensearch-dashboards-ui + targetPort: dashboards-ui selector: app: opensearch-dashboards From bf2629d90a4567acd194aa5fb5b44efd1b6f276d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Du=C5=A1ek?= Date: Fri, 21 Jun 2024 15:10:48 +0200 Subject: [PATCH 19/34] Cleanup usage creation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan Dušek --- .../cp4ba/usage/templates/usage-configmap.yaml.j2 | 8 -------- 1 file changed, 8 deletions(-) diff --git a/automation-roles/50-install-cloud-pak/cp4ba/usage/templates/usage-configmap.yaml.j2 b/automation-roles/50-install-cloud-pak/cp4ba/usage/templates/usage-configmap.yaml.j2 index afdde12a0..06fd7dc37 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/usage/templates/usage-configmap.yaml.j2 +++ b/automation-roles/50-install-cloud-pak/cp4ba/usage/templates/usage-configmap.yaml.j2 @@ -3,11 +3,3 @@ kind: ConfigMap metadata: name: "{{_current_cp4ba_cluster.project}}-usage" namespace: cloud-pak-deployer -data: - usage.md: |- - {{ lookup('file', usage_path) | indent(4) }} -{% if zen_api_key_new is defined %} - cpadminservice-zen-api-key: |- - Zen API key for cpadminservice user as generated in the UI: {{ zen_api_key_new }} - Zen API key for cpadminservice user in the form of header: ZenApiKey {{ 'cpadminservice:' + zen_api_key_new | b64encode }} -{% endif %} \ No newline at end of file From b79f7785f50d0465d977f35a726d4eaf539fa953 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Du=C5=A1ek?= Date: Fri, 21 Jun 2024 15:11:04 +0200 Subject: [PATCH 20/34] OpenSearch in Docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan Dušek --- docs/src/30-reference/configuration/cp4ba.md | 2 +- .../images/cp4ba-installation.png | Bin 84854 -> 87872 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/30-reference/configuration/cp4ba.md b/docs/src/30-reference/configuration/cp4ba.md index a7108a9df..73b04f5f5 100644 --- a/docs/src/30-reference/configuration/cp4ba.md +++ b/docs/src/30-reference/configuration/cp4ba.md @@ -79,7 +79,7 @@ Contains extra software which makes working with the platform even easier. - Roundcube - Web UI for included Mail server to be able to browse incoming emails. - Cerebro - Web UI elastic search browser automatically connected to ES instance deployed with CP4BA. - AKHQ - Web UI kafka browser automatically connected to Kafka instance deployed with CP4BA. -- Kibana - Web UI elastic search dashboard tool automatically connected to ES instance deployed with CP4BA. +- OpenSearch Dashboards - Web UI OpenSearch dashboard tool automatically connected to OpenSearch instance deployed with CP4BA. - Mail server - For various mail integrations e.g. from BAN, BAW and RPA. - Mongo Express - Web UI for Mongo DB databases for CP4BA and Process Mining to easier troubleshoot DB. - CloudBeaver - Web UI for Postgresql and MSSQL databases making it easier to admin and troubleshoot the DBs. diff --git a/docs/src/30-reference/configuration/images/cp4ba-installation.png b/docs/src/30-reference/configuration/images/cp4ba-installation.png index d38e454dce5b2e7e4e39ce2d9b345fc60523a262..85a4bb6eecbdddaf98676df61a2b5f7e7f18fbb7 100755 GIT binary patch literal 87872 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 yz_l*0TOMd{NZ6L_1 Date: Fri, 21 Jun 2024 15:11:33 +0200 Subject: [PATCH 21/34] Add new Cp4BA post depoy steps for components MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan Dušek --- .../cp4ba/cp4ba-core/tasks/postdeploy.yml | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy.yml index e87715834..4c57be72c 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy.yml @@ -4,17 +4,35 @@ - name: Manage Zen ansible.builtin.include_tasks: postdeploy/zen.yml +- name: Manage RR + ansible.builtin.include_tasks: postdeploy/rr.yml + +- name: Manage BAN + ansible.builtin.include_tasks: postdeploy/ban.yml + +- name: Manage BAS + ansible.builtin.include_tasks: postdeploy/bas.yml + when: _current_cp4ba_cluster.cp4ba.patterns.foundation.optional_components.bas + +- name: Manage BAI + ansible.builtin.include_tasks: postdeploy/bai.yml + when: _current_cp4ba_cluster.cp4ba.patterns.foundation.optional_components.bai + - name: Manage BAML ansible.builtin.include_tasks: postdeploy/baml.yml when: _current_cp4ba_cluster.cp4ba.patterns.foundation.optional_components.bai and _current_cp4ba_cluster.cp4ba.patterns.workflow.enabled +- name: Manage ODM + ansible.builtin.include_tasks: postdeploy/odm.yml + when: _current_cp4ba_cluster.cp4ba.patterns.decisions.enabled + - name: Manage ADS ansible.builtin.include_tasks: postdeploy/ads.yml when: _current_cp4ba_cluster.cp4ba.patterns.decisions_ads.enabled -- name: Manage ODM - ansible.builtin.include_tasks: postdeploy/odm.yml - when: _current_cp4ba_cluster.cp4ba.patterns.decisions.enabled +- name: Manage AAE + ansible.builtin.include_tasks: postdeploy/aae.yml + when: _current_cp4ba_cluster.cp4ba.patterns.foundation.optional_components.ae - name: Manage ADP ansible.builtin.include_tasks: postdeploy/adp.yml From 4bf5c441cd7502a7e132ea4d6fe8f5acb8bb1228 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Du=C5=A1ek?= Date: Fri, 21 Jun 2024 15:12:09 +0200 Subject: [PATCH 22/34] Comment out MSSQL as RPA prereq MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan Dušek --- .../cp4ba/cp4ba-cluster/tasks/install.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-cluster/tasks/install.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-cluster/tasks/install.yml index 113afb6bf..bc285fec1 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-cluster/tasks/install.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-cluster/tasks/install.yml @@ -98,10 +98,10 @@ when: _current_cp4ba_cluster.cp4ba.enabled and _current_cp4ba_cluster.cp4ba.patterns.foundation.optional_components.bai and _current_cp4ba_cluster.akhq_enabled -- name: Install MSSQL - ansible.builtin.include_role: - name: mssql - when: mssql_enabled +# - name: Install MSSQL +# ansible.builtin.include_role: +# name: mssql +# when: mssql_enabled # - name: Install RPA # ansible.builtin.include_role: From 6fe30dbd2fe04593628be31917d66d25e383559c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Du=C5=A1ek?= Date: Fri, 21 Jun 2024 15:12:40 +0200 Subject: [PATCH 23/34] Remove obsolete ADS component from waiting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan Dušek --- .../50-install-cloud-pak/cp4ba/cp4ba-core/tasks/deploy.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/deploy.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/deploy.yml index 3c254b92f..66264734f 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/deploy.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/deploy.yml @@ -737,9 +737,6 @@ _current_cp4ba_cluster.cp4ba.patterns.decisions_ads.optional_components.ads_designer | ternary(cp4ba_cr_meta_name + '-ads-git-service', '') }}" - "{{ _current_cp4ba_cluster.cp4ba.patterns.decisions_ads.enabled and _current_cp4ba_cluster.cp4ba.patterns.decisions_ads.optional_components.ads_designer | ternary(cp4ba_cr_meta_name + '-ads-rest-api', '') }}" - - "{{ _current_cp4ba_cluster.cp4ba.patterns.decisions_ads.enabled and - _current_cp4ba_cluster.cp4ba.patterns.decisions_ads.optional_components.ads_designer | - ternary(cp4ba_cr_meta_name + '-ads-embedded-build-service', '') }}" - "{{ _current_cp4ba_cluster.cp4ba.patterns.decisions_ads.enabled and _current_cp4ba_cluster.cp4ba.patterns.decisions_ads.optional_components.ads_designer | ternary(cp4ba_cr_meta_name + '-ads-credentials-service', '') }}" - "{{ _current_cp4ba_cluster.cp4ba.patterns.decisions_ads.enabled and From 9a41b484ce2c26914539d28c221baf26d89dd642 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Du=C5=A1ek?= Date: Fri, 21 Jun 2024 15:13:00 +0200 Subject: [PATCH 24/34] Update catalog sources MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan Dušek --- .../cp4ba/cp4ba-core/tasks/repository.yml | 26 ++++++------------- .../templates/catalogsource.yaml.j2 | 6 ++--- 2 files changed, 11 insertions(+), 21 deletions(-) diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/repository.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/repository.yml index 074582e79..004b4ab5b 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/repository.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/repository.yml @@ -1,20 +1,10 @@ # Based on https://www.ibm.com/docs/en/cloud-paks/cp-biz-automation/latest?topic=operator-preparing-log-file-storage -- name: Download installation repository - ansible.builtin.get_url: - url: https://github.com/IBM/cloud-pak/raw/master/repo/case/ibm-cp-automation/{{ cp4ba_case_version }}/ibm-cp-automation-{{ cp4ba_case_version }}.tgz - dest: "{{ cp4ba_output_directory }}/ibm-cp-automation-{{ cp4ba_case_version }}.tgz" - mode: u+rw - timeout: 60 - retries: 10 - delay: 1 - -- name: Extract installation repository - ansible.builtin.unarchive: - src: "{{ cp4ba_output_directory }}/ibm-cp-automation-{{ cp4ba_case_version }}.tgz" - dest: "{{ cp4ba_output_directory }}" - -- name: Extract cert k8s repository - ansible.builtin.unarchive: - src: "{{ cp4ba_output_directory }}/ibm-cp-automation/inventory/cp4aOperatorSdk/files/deploy/crs/cert-k8s-{{ cp4ba_case_cert_k8s_version }}.tar" - dest: "{{ cp4ba_output_directory }}" +- name: Clone cert-kubernetes repo + ansible.builtin.git: + repo: https://github.com/Vincent-Le/cert-kubernetes-beta.git + #repo: https://github.com/icp4a/cert-kubernetes.git + dest: "{{ cp4ba_output_directory }}/cert-kubernetes" + # single_branch: true from 2.11 only + version: "{{ cp4ba_cert_k8s_branch }}" + retries: 5 diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/catalogsource.yaml.j2 b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/catalogsource.yaml.j2 index de9ea401f..5c5e0f450 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/catalogsource.yaml.j2 +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/catalogsource.yaml.j2 @@ -26,7 +26,7 @@ spec: displayName: ibm-cp4a-operator publisher: IBM sourceType: grpc - image: icr.io/cpopen/ibm-cp-automation-catalog@sha256:6e3ab074046facca9c02485391a34b5c80588afd8e0c9bd7d1d0edfcb6ed5b4b + image: icr.io/cpopen/ibm-cp-automation-catalog@sha256:0c76e8fdf314733a9924ef011b58cfcc220df967468377524b3940bb57daa46b updateStrategy: registryPoll: interval: 45m @@ -180,7 +180,7 @@ spec: displayName: ibm-fncm-operator publisher: IBM sourceType: grpc - image: icr.io/cpopen/ibm-fncm-catalog@sha256:758877ed3384f778d9ab869ebdaa6efc1075056c883674b1f1c2966f850b992a + image: icr.io/cpopen/ibm-fncm-catalog@sha256:3effd576286efe58f09819647bac128fd3e5e9033b5c7688a3b2fcc9785e5272 updateStrategy: registryPoll: interval: 45m @@ -195,7 +195,7 @@ spec: displayName: ibm-bai-operator publisher: IBM sourceType: grpc - image: icr.io/cpopen/ibm-bai-catalog@sha256:84a2dd29379067ef2b56356a938268cf10fc1bb693ff94b7b4df72df244d37e1 + image: icr.io/cpopen/ibm-bai-catalog@sha256:a54f7c1026f4b0904396a90619127ab0ffc46d182f8bf8a536a06121c47098b1 updateStrategy: registryPoll: interval: 45m \ No newline at end of file From dd762169765057caada8a77bd592c5e4e0d3f53f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Du=C5=A1ek?= Date: Mon, 24 Jun 2024 09:31:23 +0200 Subject: [PATCH 25/34] Code style MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan Dušek --- .../cp4ba/cp4ba-cluster/tasks/main.yml | 15 ++++++++----- .../cp4ba/cp4ba-core/tasks/deploy.yml | 3 ++- .../cp4ba-core/tasks/postdeploy/fncm.yml | 2 +- .../cp4ba/cp4ba-core/tasks/remove.yml | 22 +++++++++++++++++++ .../cp4ba/cp4ba-core/tasks/repository.yml | 2 +- .../cp4ba/gitea/tasks/install.yml | 4 ++-- .../cp4ba/global_ca/tasks/remove.yml | 10 ++++++++- .../cp4ba/mail/tasks/install.yml | 2 +- .../cp4ba/roundcube/tasks/install.yml | 2 +- 9 files changed, 49 insertions(+), 13 deletions(-) diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-cluster/tasks/main.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-cluster/tasks/main.yml index 9016b8aa1..1055cfd51 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-cluster/tasks/main.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-cluster/tasks/main.yml @@ -119,8 +119,10 @@ ansible.builtin.set_fact: deployment_platform: "{{ 'ROKS' if _existing_ocp_infra_type == 'ibm-roks' else 'OCP' }}" -- ansible.builtin.set_fact: - _cp4ba_admin_password_vault_key_name: "cp4ba_admin_{{ _current_cp4ba_cluster.project| replace('-','_') }}_{{ _current_cp4ba_cluster.openshift_cluster_name| replace('-','_') }}" +- name: Set passwrod from vault + ansible.builtin.set_fact: + _cp4ba_admin_password_vault_key_name: + "cp4ba_admin_{{ _current_cp4ba_cluster.project | replace('-', '_') }}_{{ _current_cp4ba_cluster.openshift_cluster_name | replace('-', '_') }}" - name: Validate if an existing admin password for {{ _cp4ba_admin_password_vault_key_name }} exists in the vault ansible.builtin.include_role: @@ -138,7 +140,8 @@ name: generate-password when: (global_config.universal_password | default('')) == '' - - ansible.builtin.set_fact: + - name: Set new generated password + ansible.builtin.set_fact: _cp4ba_admin_password_new: "{{ _p_generated_password }}" when: (global_config.universal_password | default('')) == '' @@ -152,11 +155,13 @@ name: vault-set-secret vars: secret_name: "{{ _cp4ba_admin_password_vault_key_name }}" - secret_description: "cp4ba admin password for namespace {{ _current_cp4ba_cluster.project }}, cluster {{ _current_cp4ba_cluster.openshift_cluster_name }}" + secret_description: + "cp4ba admin password for namespace {{ _current_cp4ba_cluster.project }}, cluster {{ _current_cp4ba_cluster.openshift_cluster_name }}" secret_payload: "{{ _cp4ba_admin_password_new }}" secret_group: "{{ environment_name }}" - - ansible.builtin.set_fact: + - name: Set universal password + ansible.builtin.set_fact: universal_password: "{{ _cp4ba_admin_password_new }}" - name: Prepare the Playbook Configuration variables diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/deploy.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/deploy.yml index 66264734f..afcd28a35 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/deploy.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/deploy.yml @@ -665,7 +665,8 @@ common_delay: 300 with_items: - "{{ cp4ba_cr_meta_name }}-deep-learning" - when: _current_cp4ba_cluster.cp4ba.patterns.document_processing.cr_custom.spec.ca_configuration.ocrextraction.deep_learning_object_detection.enabled | default(false) | bool + when: _current_cp4ba_cluster.cp4ba.patterns.document_processing.cr_custom.spec.ca_configuration.ocrextraction.deep_learning_object_detection.enabled + | default(false) | bool - name: Wait for BAI InsightsEngine instance Ready state ansible.builtin.include_role: diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/fncm.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/fncm.yml index 4c7b69d00..6961d06b7 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/fncm.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/fncm.yml @@ -71,7 +71,7 @@ If you want FDM to connect to CPE, you need to provide it with Zen certificate. To do it update DeploymentManager.ini file and add to it ```text - + # Overrides default TLS. -Dcom.ibm.jsse2.overrideDefaultTLS=true diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/remove.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/remove.yml index 298503aaa..043fb6bfd 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/remove.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/remove.yml @@ -73,6 +73,28 @@ common_namespace_name: "{{ cp4ba_project_name }}" when: clients.resources | length != 0 +# wait for the FlinkDeployment instances to disappear as if we do not wait, they will have finalizers left +- name: Wait for FlinkDeployment intances to disappear + kubernetes.core.k8s_info: + api_version: flink.ibm.com/v1beta1 + kind: FlinkDeployment + namespace: "{{ cp4ba_project_name }}" + register: flink_deployments + retries: 10 + delay: 30 + until: flink_deployments.resources | length == 0 + ignore_errors: true + +- name: Clear FlinkDeployment instances finalizers + ansible.builtin.include_role: + name: common + tasks_from: clear-resource-finalizers + vars: + common_api_version: flink.ibm.com/v1beta1 + common_kind: FlinkDeployment + common_namespace_name: "{{ cp4ba_project_name }}" + when: flink_deployments.resources | length != 0 + - name: Remove Catalog Sources kubernetes.core.k8s: state: absent diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/repository.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/repository.yml index 004b4ab5b..e32bd5c75 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/repository.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/repository.yml @@ -3,7 +3,7 @@ - name: Clone cert-kubernetes repo ansible.builtin.git: repo: https://github.com/Vincent-Le/cert-kubernetes-beta.git - #repo: https://github.com/icp4a/cert-kubernetes.git + # repo: https://github.com/icp4a/cert-kubernetes.git dest: "{{ cp4ba_output_directory }}/cert-kubernetes" # single_branch: true from 2.11 only version: "{{ cp4ba_cert_k8s_branch }}" diff --git a/automation-roles/50-install-cloud-pak/cp4ba/gitea/tasks/install.yml b/automation-roles/50-install-cloud-pak/cp4ba/gitea/tasks/install.yml index 1925c94c9..9111b586f 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/gitea/tasks/install.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/gitea/tasks/install.yml @@ -81,13 +81,13 @@ ## Endpoints - UI: https://gitea-{{ gitea_project_name }}.{{ apps_endpoint_domain }} - + - OAS: https://gitea-{{ gitea_project_name }}.{{ apps_endpoint_domain }}/api/swagger#/ ## Credentials - Credentials you should use: {{ lc_principal_admin_user }} / {{ lc_principal_admin_password }} - + - Initial administrative user credentials: giteaadmin / {{ gitea_universal_password }} " diff --git a/automation-roles/50-install-cloud-pak/cp4ba/global_ca/tasks/remove.yml b/automation-roles/50-install-cloud-pak/cp4ba/global_ca/tasks/remove.yml index 2dde66174..2dbb38741 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/global_ca/tasks/remove.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/global_ca/tasks/remove.yml @@ -1 +1,9 @@ -# Nothing to do +- name: Remove Global CA Secret + kubernetes.core.k8s: + state: absent + api_version: v1 + kind: Secret + name: "{{ _current_cp4ba_cluster.project }}-global-ca" + namespace: "{{ global_ca_output_namespace }}" + wait: true + wait_timeout: 60 diff --git a/automation-roles/50-install-cloud-pak/cp4ba/mail/tasks/install.yml b/automation-roles/50-install-cloud-pak/cp4ba/mail/tasks/install.yml index e7c945413..52d87ebe4 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/mail/tasks/install.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/mail/tasks/install.yml @@ -117,7 +117,7 @@ ## Credentials - for admin: {{ lc_principal_admin_user }}@{{ lc_ldap_domain }}/ {{ mail_universal_password }} - + - for user: cpuser@{{ lc_ldap_domain }} / {{ mail_universal_password }} " diff --git a/automation-roles/50-install-cloud-pak/cp4ba/roundcube/tasks/install.yml b/automation-roles/50-install-cloud-pak/cp4ba/roundcube/tasks/install.yml index 2718e88e7..f88056f99 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/roundcube/tasks/install.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/roundcube/tasks/install.yml @@ -82,7 +82,7 @@ - for admin: {{ lc_principal_admin_user }}@{{ lc_ldap_domain }} / {{ roundcube_universal_password }} \ (you can also use only *{{ lc_principal_admin_user }}* without domain as username to login) - + - for other users: cpadmin1, cpadmin2, cpuser, cpuser1, cpuser2 with domain @{{ lc_ldap_domain }} / {{ roundcube_universal_password }} \ (you can also use only the usernames without domain to login) From 45fbe5249f220bede9a42bcd98f0bcfdca696907 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Du=C5=A1ek?= Date: Mon, 24 Jun 2024 15:14:35 +0200 Subject: [PATCH 26/34] Adhoc fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan Dušek --- .../50-install-cloud-pak/cp4ba/cp4ba-core/tasks/deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/deploy.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/deploy.yml index afcd28a35..26a0b1f23 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/deploy.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/deploy.yml @@ -565,7 +565,7 @@ _current_cp4ba_cluster.cp4ba.patterns.content.optional_components.tm | ternary(cp4ba_cr_meta_name + '-tm-deploy', '') }}" - "{{ _current_cp4ba_cluster.cp4ba.patterns.document_processing.enabled | ternary(cp4ba_cr_meta_name + '-mongo-deploy', '') }}" - "{{ _current_cp4ba_cluster.cp4ba.patterns.document_processing.enabled | ternary(cp4ba_cr_meta_name + '-gitgateway-deploy', '') }}" - - "{{ _current_cp4ba_cluster.cp4ba.patterns.document_processing.enabled | ternary(cp4ba_cr_meta_name + '-viewone-deploy', '') }}" + # TODO uncomment when pod ready - "{{ _current_cp4ba_cluster.cp4ba.patterns.document_processing.enabled | ternary(cp4ba_cr_meta_name + '-viewone-deploy', '') }}" - "{{ _current_cp4ba_cluster.cp4ba.patterns.document_processing.enabled | ternary(cp4ba_cr_meta_name + '-cpds-deploy', '') }}" - "{{ _current_cp4ba_cluster.cp4ba.patterns.document_processing.enabled | ternary(cp4ba_cr_meta_name + '-cds-deploy', '') }}" - "{{ cp4ba_cr_meta_name + '-navigator-deploy' }}" From 809524b34aebb245b4b54b302dc30c55ae70ac4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Du=C5=A1ek?= Date: Tue, 25 Jun 2024 09:08:49 +0200 Subject: [PATCH 27/34] Fix BAI templates download MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan Dušek --- .../cp4ba/cp4ba-core/tasks/postdeploy/bai.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/bai.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/bai.yml index d61b6d241..3a72d8c90 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/bai.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/bai.yml @@ -48,8 +48,8 @@ ```bash - oc cp -n {{ cp4ba_project_name }} `oc get pod --no-headers -n {{ cp4ba_project_name }} | grep cp4a-operator | \ - awk '{print $1}'`:/tmp/ansible-operator/runner/tmp/bai/templates/bai_all_in_one.yaml bai_all_in_one.yaml + oc cp -n {{ cp4ba_project_name }} `oc get pod --no-headers -n {{ cp4ba_project_name }} -l name=ibm-insights-engine-operator | \ + awk '{print $1}'`:/tmp/ansible-operator/runner/tmp/insightsengine/templates/insights_engine_all_in_one.yaml insights_engine_all_in_one.yaml ``` From 969779a0c82ab5617b2bda14fc11a703d1e7eaf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Du=C5=A1ek?= Date: Thu, 27 Jun 2024 07:40:42 +0200 Subject: [PATCH 28/34] Update post deployes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan Dušek --- .../cp4ba/cp4ba-core/templates/postdeploy.md.j2 | 2 -- .../50-install-cloud-pak/cp4ba/pm/templates/postdeploy.md.j2 | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/postdeploy.md.j2 b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/postdeploy.md.j2 index 7d3b9a687..b2eeef943 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/postdeploy.md.j2 +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/postdeploy.md.j2 @@ -31,9 +31,7 @@ oc login --server= -u -p --token= - oc project {{ cp4ba_project_name }} - ``` diff --git a/automation-roles/50-install-cloud-pak/cp4ba/pm/templates/postdeploy.md.j2 b/automation-roles/50-install-cloud-pak/cp4ba/pm/templates/postdeploy.md.j2 index c298aca5c..b359b8c1c 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/pm/templates/postdeploy.md.j2 +++ b/automation-roles/50-install-cloud-pak/cp4ba/pm/templates/postdeploy.md.j2 @@ -8,6 +8,6 @@ The following list specifies when you need to perform particular post-deployment Based on https://www.ibm.com/docs/en/process-mining/latest?topic=installation-process-mining-packages Based on https://www.ibm.com/docs/en/process-mining/latest?topic=optional-installing-task-mining-agent -You need to download and install Process Mining Client installer from PPA or Fix Central for corresponding version and OS (e.g. M0BMQML Process Mining 1.14.0 Client Windows Multilingual). +You need to download and install Process Mining Client installer from PPA or Fix Central for corresponding version and OS (e.g. M0JJ0ML Process Mining 1.15.0 Client Windows Multilingual). Task mining endpoint: https://cpd-{{ pm_project_name }}.{{ apps_endpoint_domain }}/processmining/ From b5a3db2a41d4637df5ca155e7276225ae98780fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Du=C5=A1ek?= Date: Thu, 27 Jun 2024 08:38:10 +0200 Subject: [PATCH 29/34] Resolve todos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan Dušek --- .../50-install-cloud-pak/cp4ba/cp4ba-core/tasks/deploy.yml | 2 -- .../cp4ba/cp4ba-core/templates/aae/cr.yaml.j2 | 2 -- .../cp4ba/openldap/templates/configmaps.yaml.j2 | 1 - 3 files changed, 5 deletions(-) diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/deploy.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/deploy.yml index 26a0b1f23..ea5be8d31 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/deploy.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/deploy.yml @@ -462,8 +462,6 @@ dest: "{{ cp4ba_output_directory }}/kafkauser-secret.yaml" mode: u+rwx - # TODO patch secret with correct password - # base64 encode and oc patch module - name: Add KafkaUser Secret kubernetes.core.k8s: state: present diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/aae/cr.yaml.j2 b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/aae/cr.yaml.j2 index eb27336ed..4fbadafd6 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/aae/cr.yaml.j2 +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/aae/cr.yaml.j2 @@ -12,5 +12,3 @@ spec: object_store_name: AEOS env: server_env_type: development - # TODO delete when default fixed - last seen in 23.0.1.2 - admin_secret_name: {{ cp4ba_cr_meta_name }}-workspace-aae-app-engine-admin-secret diff --git a/automation-roles/50-install-cloud-pak/cp4ba/openldap/templates/configmaps.yaml.j2 b/automation-roles/50-install-cloud-pak/cp4ba/openldap/templates/configmaps.yaml.j2 index cda8458f0..f24a7f242 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/openldap/templates/configmaps.yaml.j2 +++ b/automation-roles/50-install-cloud-pak/cp4ba/openldap/templates/configmaps.yaml.j2 @@ -43,7 +43,6 @@ data: cn: {{ lc_principal_admin_user }} sn: {{ lc_principal_admin_user }} {{ lc_ldap_user_id_attribute }}: {{ lc_principal_admin_user }} - # ToDo set some domain mail: {{ lc_principal_admin_user }}@{{ lc_ldap_domain }} userpassword:: {{ lc_principal_admin_password | b64encode }} employeeType: admin From da1fa37b2d0682f5a17a30c4e458390b98d6ecf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Du=C5=A1ek?= Date: Thu, 27 Jun 2024 15:05:55 +0200 Subject: [PATCH 30/34] Use official repository MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan Dušek --- .../50-install-cloud-pak/cp4ba/cp4ba-core/defaults/main.yml | 2 +- .../50-install-cloud-pak/cp4ba/cp4ba-core/tasks/repository.yml | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/defaults/main.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/defaults/main.yml index 04aac8a30..e1e80c77f 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/defaults/main.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/defaults/main.yml @@ -7,7 +7,7 @@ cp4ba_dir_name: cp4ba cp4ba_operator_channel: v24.0 ## Should not be changed in particular guide version. ## Version of cert-kubernetes folder from Cloud Pak CASE archive e.g. 21.0.1 -cp4ba_cert_k8s_branch: main # 24.0.0 +cp4ba_cert_k8s_branch: 24.0.0 cp4ba_storage_class_name: "" cp4ba_block_storage_class_name: "" ## Should not be changed in particular guide version. diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/repository.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/repository.yml index e32bd5c75..e349c8351 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/repository.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/repository.yml @@ -2,8 +2,7 @@ - name: Clone cert-kubernetes repo ansible.builtin.git: - repo: https://github.com/Vincent-Le/cert-kubernetes-beta.git - # repo: https://github.com/icp4a/cert-kubernetes.git + repo: https://github.com/icp4a/cert-kubernetes.git dest: "{{ cp4ba_output_directory }}/cert-kubernetes" # single_branch: true from 2.11 only version: "{{ cp4ba_cert_k8s_branch }}" From be42931266a0e115b8750a987866635f0bdf9135 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Du=C5=A1ek?= Date: Fri, 28 Jun 2024 10:24:52 +0200 Subject: [PATCH 31/34] Add new endpoints MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan Dušek --- .../cp4ba/cp4ba-core/tasks/postdeploy/adp.yml | 2 ++ .../cp4ba/cp4ba-core/tasks/postdeploy/ban.yml | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/adp.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/adp.yml index d4a35f922..121f2d8e0 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/adp.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/adp.yml @@ -101,6 +101,8 @@ - Ping page: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/adp/aca/ping + - Project admin API: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/adp/designer/?projectId=&features=adminapi + ## Credentials - {{ lc_principal_admin_user }} / {{ lc_principal_admin_password }} diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/ban.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/ban.yml index 65d780021..977816a69 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/ban.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/ban.yml @@ -22,6 +22,10 @@ - Ping: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/icn/navigator/ping.jsp + - Admin REST API: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/icn/navigator/rest.jsp + + - Admin REST API sample endpoint: https://cpd-{{ cp4ba_project_name }}.{{ apps_endpoint_domain }}/icn/navigator/admin/v1/desktops + ## Credentials - {{ lc_principal_admin_user }} / {{ lc_principal_admin_password }} From 3f7e2c61def6d1663cec9f7958be0459bf7fe6ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Du=C5=A1ek?= Date: Sat, 29 Jun 2024 13:51:25 +0200 Subject: [PATCH 32/34] Add viewone waiting back MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan Dušek --- .../50-install-cloud-pak/cp4ba/cp4ba-core/tasks/deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/deploy.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/deploy.yml index ea5be8d31..f7fe43c86 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/deploy.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/deploy.yml @@ -563,7 +563,7 @@ _current_cp4ba_cluster.cp4ba.patterns.content.optional_components.tm | ternary(cp4ba_cr_meta_name + '-tm-deploy', '') }}" - "{{ _current_cp4ba_cluster.cp4ba.patterns.document_processing.enabled | ternary(cp4ba_cr_meta_name + '-mongo-deploy', '') }}" - "{{ _current_cp4ba_cluster.cp4ba.patterns.document_processing.enabled | ternary(cp4ba_cr_meta_name + '-gitgateway-deploy', '') }}" - # TODO uncomment when pod ready - "{{ _current_cp4ba_cluster.cp4ba.patterns.document_processing.enabled | ternary(cp4ba_cr_meta_name + '-viewone-deploy', '') }}" + - "{{ _current_cp4ba_cluster.cp4ba.patterns.document_processing.enabled | ternary(cp4ba_cr_meta_name + '-viewone-deploy', '') }}" - "{{ _current_cp4ba_cluster.cp4ba.patterns.document_processing.enabled | ternary(cp4ba_cr_meta_name + '-cpds-deploy', '') }}" - "{{ _current_cp4ba_cluster.cp4ba.patterns.document_processing.enabled | ternary(cp4ba_cr_meta_name + '-cds-deploy', '') }}" - "{{ cp4ba_cr_meta_name + '-navigator-deploy' }}" From db82b3854da877096cefeebad6b2968cf93f86ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Du=C5=A1ek?= Date: Mon, 1 Jul 2024 13:47:15 +0200 Subject: [PATCH 33/34] Fix viewone pod MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan Dušek --- .../cp4ba/cp4ba-core/templates/adp/cr.yaml.j2 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/adp/cr.yaml.j2 b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/adp/cr.yaml.j2 index 2eb5931fb..348e0ef5f 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/adp/cr.yaml.j2 +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/templates/adp/cr.yaml.j2 @@ -34,6 +34,10 @@ spec: viewone: auto_scaling: enabled: false + # TODO temporary workaround for viewone pod to startup, last sen in 24.0.0 GA + viewone_production_setting: + jvm_initial_heap_percentage: 20 + jvm_max_heap_percentage: 33 deploy_mongo: true initialize_configuration: ic_obj_store_creation: From a954f2f5dbd9080f85ba6bee129e883282fd0aa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Du=C5=A1ek?= Date: Mon, 1 Jul 2024 13:47:29 +0200 Subject: [PATCH 34/34] FIx usage generation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan Dušek --- .../cp4ba/cp4ba-core/tasks/postdeploy.yml | 4 ++++ .../cp4ba/cp4ba-core/tasks/postdeploy/bawaut.yml | 12 ++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy.yml index 4c57be72c..e900ad921 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy.yml @@ -30,6 +30,10 @@ ansible.builtin.include_tasks: postdeploy/ads.yml when: _current_cp4ba_cluster.cp4ba.patterns.decisions_ads.enabled +- name: Manage FNCM + ansible.builtin.include_tasks: postdeploy/fncm.yml + when: _current_cp4ba_cluster.cp4ba.patterns.content.enabled + - name: Manage AAE ansible.builtin.include_tasks: postdeploy/aae.yml when: _current_cp4ba_cluster.cp4ba.patterns.foundation.optional_components.ae diff --git a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/bawaut.yml b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/bawaut.yml index 3379f9777..e1999f6e5 100644 --- a/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/bawaut.yml +++ b/automation-roles/50-install-cloud-pak/cp4ba/cp4ba-core/tasks/postdeploy/bawaut.yml @@ -92,17 +92,17 @@ - FNCM Server definition in BAW: - - Host name: icp4adeploy-cmis-svc.cp4ba.svc.cluster.local + \ \ - Host name: icp4adeploy-cmis-svc.cp4ba.svc.cluster.local - - Port: 9443 + \ \ - Port: 9443 - - Context path: /cmis/openfncmis_wlp/services + \ \ - Context path: /cmis/openfncmis_wlp/services - - Secure server: true + \ \ - Secure server: true - - Repository: depends on which you want to connect in internal FNCM (e.g. BAWDOCS or OS1) + \ \ - Repository: depends on which you want to connect in internal FNCM (e.g. BAWDOCS or OS1) - - Credentials as in Credentials section + \ \ - Credentials as in Credentials section ## Credentials