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 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 07065d5..5a07dc4 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" @@ -22,6 +57,14 @@ sap_control_instance_type_sortorder: # Functions sap_control_functions_list: + - restartsystem_all_nw + - 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 @@ -38,7 +81,33 @@ 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" + +restartsystem_sap_nw_list: + - sap_control_function_current: "nw_restartsystem" + +updatesystem_sap_nw_list: + - sap_control_function_current: "nw_updatesystem" + +startsystem_sap_nw_list: + - sap_control_function_current: "nw_startsystem" + +stopsystem_sap_nw_list: + - sap_control_function_current: "nw_stopsystem" + 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 0204f63..ffde9fe 100644 --- a/roles/sap_control/tasks/main.yml +++ b/roles/sap_control/tasks/main.yml @@ -112,10 +112,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 91d718a..ff8dfef 100644 --- a/roles/sap_control/tasks/prepare.yml +++ b/roles/sap_control/tasks/prepare.yml @@ -36,3 +36,18 @@ loop: "{{ sorted_sap_facts }}" when: - item.InstanceType | lower == sap_type | lower + - not funct_type is match('.*system') + +- name: Prepare - SAP Control for system 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: "{{ sorted_sap_facts }}" + 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..a704c18 --- /dev/null +++ b/roles/sap_control/tasks/sapcontrol_async.yml @@ -0,0 +1,55 @@ +--- +- name: Wait for status to change if using restart or update + when: funct_type is match('restart|update') + block: + - name: SAP {{ sap_control_name_header }} - Getting current system state + 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: initial_test_function_result + + - name: SAP {{ sap_control_name_header }} - Waiting for state to change before polling + 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: wait_for_change_result + retries: "{{ async_function_dict.retries | default(0) | int }}" + delay: "{{ async_function_dict.delay | default(0) | int }}" + until: > + (wait_for_change_result.stdout | regex_findall('GREEN|YELLOW|GRAY|RED', multiline=True) | sort | join(',')) + != (initial_test_function_result.stdout | regex_findall('GREEN|YELLOW|GRAY|RED', multiline=True) | sort | join(',')) + +- name: Pause for 20 Seconds to ensure the async function is started + ansible.builtin.wait_for: + timeout: 20 + +- 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 + 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 test_function_result.stdout | regex_search(async_function_dict.until_false, multiline=True) is none) 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) is not none) + +- 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 }}