From e92d1b18629b71e39eacce8f877b82ebe1050d84 Mon Sep 17 00:00:00 2001 From: Nicolas Bettembourg Date: Fri, 18 Jul 2025 17:08:22 +0200 Subject: [PATCH 1/3] Add SAP System-level Function Support with Asynchronous Status Tracking (#1) * Adding support for system wide functions * Nested Jinja makes the use of dynamic variables inside sapcontrol functions complicated. Falling back to declarative commands. * Adding steps to make sure that the system is started before attempting RKS * Enhance debug output for SAP Control parameters --------- Signed-off-by: Nicolas Bettembourg Co-authored-by: Rainer Leber <39616583+rainerleber@users.noreply.github.com> --- roles/sap_control/README.md | 3 +- roles/sap_control/defaults/main.yml | 53 ++++++++++++++++++++ roles/sap_control/tasks/main.yml | 16 ++++-- roles/sap_control/tasks/prepare.yml | 17 ++++++- roles/sap_control/tasks/sapcontrol.yml | 8 +++ roles/sap_control/tasks/sapcontrol_async.yml | 29 +++++++++++ 6 files changed, 120 insertions(+), 6 deletions(-) create mode 100644 roles/sap_control/tasks/sapcontrol_async.yml diff --git a/roles/sap_control/README.md b/roles/sap_control/README.md index 0409cef..8e513fb 100644 --- a/roles/sap_control/README.md +++ b/roles/sap_control/README.md @@ -7,6 +7,7 @@ This Ansible Role executes basic SAP administration tasks on Linux operating sys This Ansible Role executes basic SAP administration tasks on Linux operating systems, including: - Start/Stop/Restart of SAP HANA Database Server - Start/Stop/Restart of SAP NetWeaver Application Server +- Start/Stop/Restart/Update of SAP Netweaver System - Multiple Automatic discovery and Start/Stop/Restart of SAP HANA Database Server or SAP NetWeaver Application Server ## Example execution @@ -62,7 +63,7 @@ Assumptions for executing this role include: | :--- |:--- | :--- | | `SID` | SAP system SID | no, only if you are targetting a single SAP system| | `nowait` | Default: `false` | no, use only when absolutely sure! This will bypass all waiting and ignore all necessary steps for a graceful stop / start| -| `sap_control_function` | Function to execute:
| yes, only this is required to detect the Instance Number which is used with SAP Host Agent `sapcontrol` CLI


_Note: Executions using `all` will automatically detect any System IDs and corresponding Instance Numbers_ | +| `sap_control_function` | Function to execute:
| yes, only this is required to detect the Instance Number which is used with SAP Host Agent `sapcontrol` CLI


_Note: Executions using `all` will automatically detect any System IDs and corresponding Instance Numbers_ | ## Ansible Role workflow and structure diff --git a/roles/sap_control/defaults/main.yml b/roles/sap_control/defaults/main.yml index c1c65f3..558e91e 100644 --- a/roles/sap_control/defaults/main.yml +++ b/roles/sap_control/defaults/main.yml @@ -6,6 +6,41 @@ sap_control_name_header: "initial" nowait: false sap_control_start: "StartWait 180 2" sap_control_stop: "StopWait 180 2" +sap_control_startsystem: "StartSystem ALL 180" # function StartSystem waittimeout +sap_control_stopsystem: "StopSystem ALL 180 480" # function StopSystem waittimeout softtimeout +sap_control_restartsystem: "RestartSystem ALL 180 480" # function RestartSystem waittimeout softtimeout +sap_control_updatesystem: "UpdateSystem 180 480 0" # function UpdateSystem waittimeout softtimeout force +sap_control_waitforstopped: "WaitforStopped 180 2" # function WaitforStopped waittimeout delay +sap_control_waitforstarted: "WaitforStarted 180 2" # function WaitforStarted waittimeout delay + +# Parameters to handle async functions in sapcontrol_async.yml + +sap_control_startsystem_waitforasync: + test_function: "GetSystemInstanceList" + retries: 60 + delay: 10 + until_false: 'GRAY\s*$|RED\s*$|YELLOW\s*$' + until_true: 'GREEN\s*$' + +sap_control_restartsystem_waitforasync: + test_function: "GetSystemInstanceList" + retries: 60 + delay: 10 + until_false: 'GRAY\s*$|RED\s*$|YELLOW\s*$' + until_true: 'GREEN\s*$' + +sap_control_stopsystem_waitforasync: + test_function: "GetSystemInstanceList" + retries: 60 + delay: 10 + until_false: 'GREEN\s*$|RED\s*$|YELLOW\s*$' + until_true: 'GRAY\s*$' + +sap_control_updatesystem_waitforasync: + test_function: "GetSystemUpdateList" + retries: 60 + delay: 10 + until_false: 'GRAY\s*$|RED\s*$|YELLOW\s*$|GREEN\s*$' # get_all_sap_sid_dir_nw: "/sapmnt" # get_all_sap_sid_dir_hana: "/hana/shared" @@ -13,6 +48,10 @@ sap_control_stop: "StopWait 180 2" # Functions sap_control_functions_list: + - restartsystem_all_nw + - updatesystem_all_nw + - startsystem_all_nw + - stopsystem_all_nw - restart_all_sap - stop_all_sap - start_all_sap @@ -29,7 +68,21 @@ sap_control_functions_list: - stop_sap_hana - start_sap_hana + # Functions flow +restartsystem_all_nw_list: + - sap_control_function_current: "nw_restartsystem" + +startsystem_all_nw_list: + - sap_control_function_current: "nw_startsystem" + +stopsystem_all_nw_list: + - sap_control_function_current: "nw_stopsystem" + +updatesystem_all_nw_list: + - sap_control_function_current: "nw_startsystem" + - sap_control_function_current: "nw_updatesystem" + restart_all_sap_list: - sap_control_function_current: "nw_stop" - sap_control_function_current: "hana_stop" diff --git a/roles/sap_control/tasks/main.yml b/roles/sap_control/tasks/main.yml index 880eec9..6d8f8fd 100644 --- a/roles/sap_control/tasks/main.yml +++ b/roles/sap_control/tasks/main.yml @@ -104,10 +104,18 @@ ansible.builtin.debug: msg: - "Starting sap_control with the following parameters: " - - "{{ sap_control_function }}" - - "{{ sap_control_start }}" - - "{{ sap_control_stop }}" - - "{{ nowait }}" + - "Function: {{ sap_control_function }}" + - "Standard commands:" + - " Start: {{ sap_control_start }}" + - " Stop: {{ sap_control_stop }}" + - "System commands (if applicable):" + - " StartSystem: {{ sap_control_startsystem }}" + - " StopSystem: {{ sap_control_stopsystem }}" + - " RestartSystem: {{ sap_control_restartsystem }}" + - " UpdateSystem: {{ sap_control_updatesystem }}" + - " WaitforStopped: {{ sap_control_waitforstopped }}" + - " WaitforStarted: {{ sap_control_waitforstarted }}" + - "NoWait: {{ nowait }}" # Start SAP Control - name: SAP Control diff --git a/roles/sap_control/tasks/prepare.yml b/roles/sap_control/tasks/prepare.yml index a15777f..394c398 100644 --- a/roles/sap_control/tasks/prepare.yml +++ b/roles/sap_control/tasks/prepare.yml @@ -9,7 +9,7 @@ ansible.builtin.set_fact: sap_control_name_header: "{{ sap_type | upper }} {{ funct_type | capitalize }}" -- name: SAP Control +- name: SAP Control (not System wide functions) vars: sap_control_execute_sid: "{{ item.SID }}" sap_control_execute_type: "{{ item.Type }}" @@ -19,3 +19,18 @@ loop: "{{ sap_facts_register.ansible_facts.sap }}" when: - "item.InstanceType | lower == sap_type | lower" + - "not funct_type is match('.*system')" + +- name: SAP Control (System wide functions) + vars: + sap_control_execute_sid: "{{ item.SID }}" + sap_control_execute_type: "{{ item.Type }}" + sap_control_execute_instance_nr: "{{ item.NR }}" + sap_control_execute_instance_type: "{{ item.InstanceType }}" + ansible.builtin.include_tasks: "sapcontrol.yml" + loop: "{{ sap_facts_register.ansible_facts.sap }}" + when: + - "item.InstanceType | lower == sap_type | lower" + - "funct_type is match('.*system')" + - "item.TYPE | lower == 'ascs' + or item.TYPE | lower == 'scs'" diff --git a/roles/sap_control/tasks/sapcontrol.yml b/roles/sap_control/tasks/sapcontrol.yml index af3cda8..aa181a2 100644 --- a/roles/sap_control/tasks/sapcontrol.yml +++ b/roles/sap_control/tasks/sapcontrol.yml @@ -22,6 +22,14 @@ register: sapcontrol_status failed_when: "'FAIL' in sapcontrol_status.stdout" +# Include sapcontrol async tasks +- name: SAP {{ sap_control_name_header }} - Include async tasks + vars: + async_function_dict: "{{ vars['sap_control_' + funct_type + '_waitforasync'] }}" + ansible.builtin.include_tasks: sapcontrol_async.yml + when: + - funct_type is match('.*system') + # Cleanipc - name: SAP {{ sap_control_name_header }} - Cleanipc ansible.builtin.include_tasks: functions/cleanipc.yml diff --git a/roles/sap_control/tasks/sapcontrol_async.yml b/roles/sap_control/tasks/sapcontrol_async.yml new file mode 100644 index 0000000..ebe65bc --- /dev/null +++ b/roles/sap_control/tasks/sapcontrol_async.yml @@ -0,0 +1,29 @@ +--- +- name: Pause for 5 Seconds + ansible.builtin.wait_for: + timeout: 5 + +- name: SAP {{ sap_control_name_header }} - Checking if Async action is over by executing sapcontrol -nr {{ passed_sap_nr }} -function {{ async_function_dict.test_function }} + ansible.builtin.shell: | + source ~/.profile && sapcontrol -nr {{ passed_sap_nr }} -function {{ async_function_dict.test_function }} + args: + executable: /bin/bash + become: true + become_user: "{{ passed_sap_sid | lower }}adm" + register: test_function_result +# failed_when: "'FAIL' in test_function_result.stdout" + retries: "{{ async_function_dict.retries | default(0) | int }}" + delay: "{{ async_function_dict.delay | default(0) | int }}" + until: > + (async_function_dict.until_false is not defined + or async_function_dict.until_false is defined and not test_function_result.stdout | regex_search(async_function_dict.until_false, multiline=True)) and + (async_function_dict.until_true is not defined or + async_function_dict.until_true is defined and test_function_result.stdout | regex_search(async_function_dict.until_true, multiline=True)) + failed_when: false + +- name: Debug stdout + ansible.builtin.debug: + msg: | + Async function {{ async_function_dict.test_function }} for SAP SID {{ passed_sap_sid }} + is done with result: + {{ test_function_result.stdout }} From afa95bac9edd215f41ce1e845a0a1ff0f83a41b3 Mon Sep 17 00:00:00 2001 From: Nicolas Bettembourg Date: Mon, 21 Jul 2025 13:04:05 +0200 Subject: [PATCH 2/3] Changelog fragment Signed-off-by: Nicolas Bettembourg --- changelogs/fragments/37_sap_control_add_system_functions | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changelogs/fragments/37_sap_control_add_system_functions diff --git a/changelogs/fragments/37_sap_control_add_system_functions b/changelogs/fragments/37_sap_control_add_system_functions new file mode 100644 index 0000000..a87938f --- /dev/null +++ b/changelogs/fragments/37_sap_control_add_system_functions @@ -0,0 +1,3 @@ +minor_changes: + - sap_control - add the mechanisms to handle asynchronous sapcontrol functions + - sap_control - add UpdateSystem, RestartSystem, StartSystem, StopSystem functions From 1f71f918381b69c340ea876b5bde0ec9efee03ad Mon Sep 17 00:00:00 2001 From: Nicolas Bettembourg Date: Mon, 21 Jul 2025 13:53:24 +0200 Subject: [PATCH 3/3] Adding *system_sap_nw functions to act only on selected SID Signed-off-by: Nicolas Bettembourg --- roles/sap_control/defaults/main.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/roles/sap_control/defaults/main.yml b/roles/sap_control/defaults/main.yml index 558e91e..170dd68 100644 --- a/roles/sap_control/defaults/main.yml +++ b/roles/sap_control/defaults/main.yml @@ -52,6 +52,10 @@ sap_control_functions_list: - updatesystem_all_nw - startsystem_all_nw - stopsystem_all_nw + - restartsystem_sap_nw + - updatesystem_sap_nw + - startsystem_sap_nw + - stopsystem_sap_nw - restart_all_sap - stop_all_sap - start_all_sap