diff --git a/roles/sap_swpm/README.md b/roles/sap_swpm/README.md index aafa3f751..f5148f53c 100644 --- a/roles/sap_swpm/README.md +++ b/roles/sap_swpm/README.md @@ -110,6 +110,8 @@ It is also possible to use method 1 for creating the inifile and then replace or - Set expiry of Linux created users to 'never' - (Optional) Apply firewall rules for SAP Netweaver if `sap_swpm_setup_firewall` is set to `true` (Default: `false`). + +- (Optional) Handle the execution of SUM if SWPM started it (See Up-To-Date Installation below). ### Example @@ -181,6 +183,16 @@ With the following tags, the role can be called to perform certain activities on - tag `sap_swpm_update_etchosts`: Only update file `/etc/hosts` (but only if variable `sap_swpm_update_etchosts` is set to `true`). +## Additional information + +### Up-To-Date Installation (UDI) +The Software Update Manager can run on any host with an Application Server instance (e.g. NWAS ABAP PAS/AAS, NWAS JAVA CI/AAS) with correct permissions to access /usr/sap/ and /sapmnt/ directories. + +When using the Software Provisioning Manager (SWPM) with a Maintenance Planner Stack XML file to perform an "up-to-date installation" (UDI) - it will start the Software Update Manager (SUM) automatically at the end of the installation process. This UDI feature applies only to SAP ABAP Platform / SAP NetWeaver, and must be performed from the Primary Application Server instance (i.e. NWAS ABAP PAS, or a OneHost installation). + +Furthermore, during SWPM variable selection the enabling of Transport Management System (TMS) is required, see SAP Note 2522253 - SWPM can not call SUM automatically when doing the up-to-date installation. + + ## License Apache 2.0 diff --git a/roles/sap_swpm/tasks/post_install.yml b/roles/sap_swpm/tasks/post_install.yml index 65fba3cf0..33fdc96f9 100644 --- a/roles/sap_swpm/tasks/post_install.yml +++ b/roles/sap_swpm/tasks/post_install.yml @@ -57,3 +57,13 @@ - __sap_swpm_post_install_register_hdbuserstore_exists.stat.exists register: __sap_swpm_post_install_register_hdbuserstore_connection changed_when: __sap_swpm_post_install_register_hdbuserstore_connection is succeeded + +# Now that SWPM finished we may need to deal with SUM before continuing when sap_swpm_sum_start: 'true' +# and if we are doing OneHost or CI/PAS installation +# If observer mode is enabled, SWPM will wait for SUM to finish before continuing so we can't do anything here +- name: SAP SWPM Post Install - Control SUM if required + ansible.builtin.include_tasks: post_install/sum_push_to_finish.yml + when: + - sap_swpm_sum_start + - not sap_swpm_swpm_observer_mode + - "'NW_ABAP_CI:' in sap_swpm_product_catalog_id or 'NW_ABAP_OneHost:' in sap_swpm_product_catalog_id" diff --git a/roles/sap_swpm/tasks/post_install/sum_push_to_finish.yml b/roles/sap_swpm/tasks/post_install/sum_push_to_finish.yml new file mode 100644 index 000000000..24e416a2c --- /dev/null +++ b/roles/sap_swpm/tasks/post_install/sum_push_to_finish.yml @@ -0,0 +1,188 @@ +# SPDX-License-Identifier: Apache-2.0 +--- +# Will keep pushing SUM through the two key manual steps until it finishes +# This allows to fully automate the SWPM+SUM installation process +# Based on research by @sean-freeman + +# Check if the SUMup process is running, give it 5 minutes to start +- name: Check if SAPup_real process is running (wait for 5 minutes until it starts) + ansible.builtin.command: pgrep -c -u "{{ sap_swpm_sid | lower }}adm" -f SAPup_real + register: _sapup_process + retries: 5 + delay: 60 + until: _sapup_process.rc == 0 and _sapup_process.stdout|int > 0 + failed_when: _sapup_process.rc != 0 + changed_when: false + +- name: Print SUM monitoring and action URLs + ansible.builtin.debug: + msg: + - "Check the following URLs for SAP Software Update Manager (SUM) monitoring or actions:" + - "Note: If these URLs don't work, check the sapinst.log file for the correct URLs." + - "SUM Monitor - https://{{ ansible_fqdn }}:1129/lmsl/sumobserver/{{ sap_swpm_sid | upper }}/monitor/index.html" + - "SUM Admin - https://{{ ansible_fqdn }}:1129/lmsl/sumabap/{{ sap_swpm_sid | upper }}/slui/" + - "SUM Admin Utilities - https://{{ ansible_fqdn }}:1129/lmsl/sumabap/{{ sap_swpm_sid | upper }}/slui_ext/" + +# Check the SUM status via SUMOBSEVER.XML, wait for 60 minutes until we are in BIND_PATCH phase +- name: Checking the status of SUM (BIND_PATCH) + ansible.builtin.uri: + url: "https://localhost:1129/lmsl/sumobserver/{{ sap_swpm_sid | upper }}/analysis/SUMOBSERVER.XML" + method: GET + validate_certs: false + return_content: true + status_code: 200 + user: "{{ sap_swpm_sid | lower }}adm" + password: "{{ sap_swpm_sap_sidadm_password }}" + register: _sap_swpm_sum_push + until: _sap_swpm_sum_push.status == 200 and 'SUM4ABAP|CONFIGURE|PREP_EXTENSION|BIND_PATCH|PatchSelection' in _sap_swpm_sum_push.content + retries: 60 + delay: 60 + failed_when: _sap_swpm_sum_push.status != 200 or 'SUM4ABAP|CONFIGURE|PREP_EXTENSION|BIND_PATCH|PatchSelection' not in _sap_swpm_sum_push.content + +# Get the config XML from SUM, repeat 3 times in case SUM is still busy and doesn't respond promptly +- name: Get the config XML from SUM (BIND_PATCH) + ansible.builtin.uri: + url: "https://localhost:1129/slp/sumabap/{{ sap_swpm_sid | upper }}/config" + method: GET + validate_certs: false + return_content: true + status_code: 200 + user: "{{ sap_swpm_sid | lower }}adm" + password: "{{ sap_swpm_sap_sidadm_password }}" + # headers: + # Cookie: "{{ _sap_swpm_sum_push.cookies_string }}" + register: _sap_swpm_sum_push_config + until: _sap_swpm_sum_push_config.status == 200 + retries: 3 + delay: 60 + failed_when: _sap_swpm_sum_push_config.status != 200 + +# Get the CSRF token from SUM by calling config +- name: Get the CSRF token from SUM (BIND_PATCH) + ansible.builtin.uri: + url: "https://localhost:1129/slp/sumabap/{{ sap_swpm_sid | upper }}/config" + method: GET + validate_certs: false + return_content: false + status_code: 200 + user: "{{ sap_swpm_sid | lower }}adm" + password: "{{ sap_swpm_sap_sidadm_password }}" + headers: + Cookie: "{{ _sap_swpm_sum_push_config.cookies_string }}" + X-CSRF-Token: Fetch + # X-Requested-With: XMLHttpRequest + register: _sap_swpm_sum_push + failed_when: _sap_swpm_sum_push.status != 200 + +# Post the config XML back to SUM unchanged as we want to keep the default patch levels as per the XML file. This will move SUM to the next step. +- name: Move SUM to the next step (SPAUINFO) + ansible.builtin.uri: + url: "https://localhost:1129/slp/sumabap/{{ sap_swpm_sid | upper }}/config" + method: POST + validate_certs: false + return_content: true + status_code: 200 + user: "{{ sap_swpm_sid | lower }}adm" + password: "{{ sap_swpm_sap_sidadm_password }}" + headers: + Cookie: "{{ _sap_swpm_sum_push_config.cookies_string }}" + X-CSRF-Token: "{{ _sap_swpm_sum_push.x_csrf_token }}" + body_format: raw + body: "{{ _sap_swpm_sum_push_config.content }}" + register: _sap_swpm_sum_push + until: _sap_swpm_sum_push.status == 200 + failed_when: _sap_swpm_sum_push.status != 200 + +# At this point SUM should be running. This will take anything between 6-12 hours to complete. +# Patiently check every 10 minutes to see if SUM has completed all the steps and is now in the SPAUINFO step. +# Check the SUM status via SUMOBSEVER.XML +- name: Checking the status of SUM (SPAUINFO) every 5 minutes + ansible.builtin.uri: + url: "https://localhost:1129/lmsl/sumobserver/{{ sap_swpm_sid | upper }}/analysis/SUMOBSERVER.XML" + method: GET + validate_certs: false + return_content: true + status_code: 200 + user: "{{ sap_swpm_sid | lower }}adm" + password: "{{ sap_swpm_sap_sidadm_password }}" + register: _sap_swpm_sum_push + until: _sap_swpm_sum_push.status == 200 and ('SUM4ABAP|POST-EXECUTE|MAIN_POSTPROC|SPAUINFO|FinishSPAU' in _sap_swpm_sum_push.content or 'SUM4ABAP|MAIN_POSTCLEAN|EXIT|UnitWizard' in _sap_swpm_sum_push.content) + retries: 144 # 12 hours + delay: 300 # 5 minutes + failed_when: _sap_swpm_sum_push.status != 200 or ('SUM4ABAP|POST-EXECUTE|MAIN_POSTPROC|SPAUINFO|FinishSPAU' not in _sap_swpm_sum_push.content and 'SUM4ABAP|MAIN_POSTCLEAN|EXIT|UnitWizard' not in _sap_swpm_sum_push.content) + +# If SUM is already in MAIN_POSTCLEAN|EXIT phase it has skipped SPAUINFO and has finished +# Process SPAUINFO if required +- name: Check if SUM is still in SPAUINFO or has finished + when: "'SUM4ABAP|POST-EXECUTE|MAIN_POSTPROC|SPAUINFO|FinishSPAU' in _sap_swpm_sum_push.content" + block: + # Get the config XML from SUM, repeat 3 times in case SUM is still busy and doesn't respond promptly + # Need to get config XML even through we are not going to use it. This is to get the diagtime cookie. + - name: Get the config XML from SUM (SPAUINFO) + ansible.builtin.uri: + url: "https://localhost:1129/slp/sumabap/{{ sap_swpm_sid | upper }}/config" + method: GET + validate_certs: false + return_content: true + status_code: 200 + user: "{{ sap_swpm_sid | lower }}adm" + password: "{{ sap_swpm_sap_sidadm_password }}" + # headers: + # Cookie: "{{ _sap_swpm_sum_push.cookies_string }}" + register: _sap_swpm_sum_push_config2 + until: _sap_swpm_sum_push_config2.status == 200 + retries: 3 + delay: 60 + failed_when: _sap_swpm_sum_push_config2.status != 200 + + # Get the CSRF token from SUM by calling config + - name: Get the CSRF token from SUM (SPAUINFO) + ansible.builtin.uri: + url: "https://localhost:1129/slp/sumabap/{{ sap_swpm_sid | upper }}/config" + method: GET + validate_certs: false + return_content: false + status_code: 200 + user: "{{ sap_swpm_sid | lower }}adm" + password: "{{ sap_swpm_sap_sidadm_password }}" + headers: + Cookie: "{{ _sap_swpm_sum_push_config2.cookies_string }}" + X-CSRF-Token: Fetch + # X-Requested-With: XMLHttpRequest + register: _sap_swpm_sum_push2 + failed_when: _sap_swpm_sum_push2.status != 200 + + # Post confirmation to SUM that no SPAU is required. This will move SUM to the next step. + - name: Move SUM to the next step (Past SPAUINFO) + ansible.builtin.uri: + url: "https://localhost:1129/slp/sumabap/{{ sap_swpm_sid | upper }}/config" + method: POST + validate_certs: false + return_content: true + status_code: 200 + user: "{{ sap_swpm_sid | lower }}adm" + password: "{{ sap_swpm_sap_sidadm_password }}" + headers: + Cookie: "{{ _sap_swpm_sum_push_config2.cookies_string }}" + X-CSRF-Token: "{{ _sap_swpm_sum_push2.x_csrf_token }}" + body_format: raw + body: 'DialogueValueslp.parameter.type.SCALAR10yes' + register: _sap_swpm_sum_push2 + failed_when: _sap_swpm_sum_push2.status != 200 + +# Finally wait for SUM to finish the final steps. This shouldn't take more than 1 hour. +# Check the SUM status via SUMOBSEVER.XML, wait for 60 minutes until the status is 'MAIN_POSTCLEAN|EXIT' +- name: Checking the status of SUM and making sure it has finished (MAIN_POSTCLEAN|EXIT) + ansible.builtin.uri: + url: "https://localhost:1129/lmsl/sumobserver/{{ sap_swpm_sid | upper }}/analysis/SUMOBSERVER.XML" + method: GET + validate_certs: false + return_content: true + status_code: 200 + user: "{{ sap_swpm_sid | lower }}adm" + password: "{{ sap_swpm_sap_sidadm_password }}" + register: _sap_swpm_sum_push + until: _sap_swpm_sum_push.status == 200 and 'SUM4ABAP|MAIN_POSTCLEAN|EXIT|UnitWizard' in _sap_swpm_sum_push.content + retries: 60 + delay: 60 + failed_when: _sap_swpm_sum_push.status != 200 or 'SUM4ABAP|MAIN_POSTCLEAN|EXIT|UnitWizard' not in _sap_swpm_sum_push.content