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:
- `restart_all_sap`
- `restart_all_nw`
- `restart_all_hana`
- `restart_sap_nw`
- `restart_sap_hana`
- `stop_all_sap`
- `start_all_sap`
- `stop_all_nw`
- `start_all_nw`
- `stop_all_hana`
- `start_all_hana`
- `stop_sap_nw`
- `start_sap_nw`
- `stop_sap_hana`
- `start_sap_hana`
| 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:
- `restart_all_sap`
- `restart_all_nw`
- `restart_all_hana`
- `restart_sap_nw`
- `restart_sap_hana`
- `stop_all_sap`
- `start_all_sap`
- `stop_all_nw`
- `start_all_nw`
- `stop_all_hana`
- `start_all_hana`
- `stop_sap_nw`
- `start_sap_nw`
- `stop_sap_hana`
- `start_sap_hana`
- `restartsystem_all_nw`
- `updatesystem_all_nw`
- `startsystem_all_nw`
- `stopsystem_all_nw`
| 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 }}