Skip to content

Commit 9bb0048

Browse files
committed
Add additional asserts and use of retry override variables, improve loop task names and j2 formatting
1 parent b6fc9bc commit 9bb0048

File tree

9 files changed

+236
-129
lines changed

9 files changed

+236
-129
lines changed

roles/sap_control/README.md

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@ The Ansible role `sap_control` executes predefined that cover range of SAP admin
1010
- Start/Stop/Restart/Update of SAP Netweaver System.
1111
<!-- END Description -->
1212

13+
<!-- BEGIN Disclaimer -->
14+
## Disclaimer
15+
> **IMPORTANT:** This role is designed to perform administrative actions on SAP systems, such as starting and stopping instances.
16+
> Misuse of this role, especially in production environments, can lead to system downtime and potential data loss.
17+
> It is crucial to understand the function you are executing and its impact on your SAP landscape.
18+
> Always test in non-production environments before applying to production systems. Use with caution.
19+
<!-- END Disclaimer -->
20+
1321
<!-- BEGIN Dependencies -->
1422
## Dependencies
1523
> This is optional dependency, active only when the variable `sap_control_use_sap_system_facts` is set to `true`.
@@ -27,7 +35,7 @@ This Ansible Role assumes that SAP Netweaver and HANA are installed in standard
2735

2836
## Execution
2937
<!-- BEGIN Execution -->
30-
Primary variable is `sap_control_function` and it drives all logic of this role.</br>
38+
Primary variable is `sap_control_function` and it drives all logic of this role.
3139
The function names are constructed using the pattern: [`ACTION`]_[`SCOPE`]_[`TARGET`]
3240

3341
`ACTION`: The operation to perform.
@@ -125,33 +133,33 @@ Apache 2.0
125133
### sap_control_function
126134
- _Type:_ `string`
127135

128-
The sapcontrol function to execute on target host.</br>
136+
The sapcontrol function to execute on target host.
129137
These are predefined functions defined in variable `__sap_control_function_definitions`.
130138

131139
### sap_control_sid
132140
- _Type:_ `string`
133141

134-
The 3-letter SAP System ID (e.g., 'PRD', 'QAS').</br>
142+
The 3-letter SAP System ID (e.g., 'PRD', 'QAS').
135143
This is required when executing a function that targets a specific SAP instance (e.g., `start_sap_nw`) instead of all instances on the host.
136144

137145
### sap_control_command_nowait
138146
- _Type:_ `boolean`
139147
- _Default:_ `false`
140148

141-
If set to `true`, the role will not wait for start/stop operations to complete.</br>
149+
If set to `true`, the role will not wait for start/stop operations to complete.
142150
> **NOTE:** This option should be used with caution, as the role will not verify the final status of the instance.
143151

144152
### sap_control_cleanipc
145153
- _Type:_ `boolean`
146154
- _Default:_ `true`
147155

148-
If set to false, the 'cleanipc' command will not be executed after stopping an SAP instance.
156+
If set to `false`, the `cleanipc` command will not be executed after stopping an SAP instance.
149157

150158
### sap_control_use_sap_system_facts
151159
- _Type:_ `boolean`
152160
- _Default:_ `false`
153161

154-
Enable this variable to use `community.sap_libs.sap_system_facts` to detect SAP instances.</br>
155-
This can be useful if this role is part of a playbook that expects facts set by that module.</br>
162+
Enable this variable to use `community.sap_libs.sap_system_facts` to detect SAP instances.
163+
This can be useful if this role is part of a playbook that expects facts set by that module.
156164
> **NOTE:** This module will not detect instances with `sapstartsrv` stopped.
157165
<!-- END Role Variables -->

roles/sap_control/defaults/main.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,17 @@ sap_control_function: ''
3434

3535
# If set to true, the role will not wait for start/stop operations to complete.
3636
# This option should be used with caution, as the role will not verify the final status of the instance.
37-
sap_control_command_nowait: false
37+
# sap_control_command_nowait: false
3838

3939
# If set to false, the 'cleanipc' command will not be executed after stopping an SAP instance.
40-
sap_control_cleanipc: true
40+
# sap_control_cleanipc: true
4141

4242
# Override for the number of retries and delay for asynchronous tasks.
4343
# Asynchronous steps are part of functions that include 'system' in their name (e.g., 'startsystem_all_nw').
44-
sap_control_async_retries: '60'
45-
sap_control_async_delay: '10'
44+
# sap_control_async_retries: '60'
45+
# sap_control_async_delay: '10'
4646

4747
# Enable this variable to use 'community.sap_libs.sap_system_facts' to detect SAP instances.
4848
# This can be useful if this role is part of a playbook that expects facts set by that module.
4949
# NOTE: This module will not detect instances with 'sapstartsrv' stopped.
50-
sap_control_use_sap_system_facts: false
50+
# sap_control_use_sap_system_facts: false
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
---
3+
4+
- name: Block to wait for status to change if using restart or update
5+
when:
6+
- sap_control_function is match('restart|update')
7+
block:
8+
- name: SAP Control - Get initial system state for instance - {{ command_item['nr'] }} # noqa no-changed-when
9+
ansible.builtin.shell:
10+
cmd: >-
11+
source ~/.profile &&
12+
sapcontrol
13+
-nr {{ command_item['nr'] }}
14+
-function {{ command_item['async']['test_function'] | d('GetSystemInstanceList') }}
15+
become: true
16+
become_user: "{{ command_item['user'] }}"
17+
register: __sap_control_register_async_update_before
18+
changed_when: false
19+
20+
- name: SAP Control - Wait for initial state change for instance - {{ command_item['nr'] }}
21+
ansible.builtin.shell:
22+
cmd: >-
23+
source ~/.profile &&
24+
sapcontrol
25+
-nr {{ command_item['nr'] }}
26+
-function {{ command_item['async']['test_function'] | d('GetSystemInstanceList') }}
27+
become: true
28+
become_user: "{{ command_item['user'] }}"
29+
register: __sap_control_register_async_update_after
30+
changed_when: false
31+
retries: "{{ sap_control_async_retries | d(command_item['async']['retries']) | d(0) | int }}"
32+
delay: "{{ sap_control_async_delay | d(command_item['async']['delay']) | d(0) | int }}"
33+
until: >
34+
(__sap_control_register_async_update_after.stdout
35+
| regex_findall('GREEN|YELLOW|GRAY|RED', multiline=True) | sort | join(','))
36+
!= (__sap_control_register_async_update_before.stdout
37+
| regex_findall('GREEN|YELLOW|GRAY|RED', multiline=True) | sort | join(','))
38+
39+
40+
# This is hardcoded 20 second wait as safety measure so we give SAP time to process our commands.
41+
- name: SAP Control - Wait for 20 Seconds to before checking state for instance - {{ command_item['nr'] }}
42+
ansible.builtin.wait_for:
43+
timeout: 20
44+
45+
- name: SAP Control - Poll for final system state for instance - {{ command_item['nr'] }}
46+
ansible.builtin.shell:
47+
cmd: >-
48+
source ~/.profile &&
49+
sapcontrol
50+
-nr {{ command_item['nr'] }}
51+
-function {{ command_item['async']['test_function'] | d('GetSystemInstanceList') }}
52+
become: true
53+
become_user: "{{ command_item['user'] }}"
54+
register: __sap_control_register_async_command_output
55+
changed_when: false
56+
retries: "{{ sap_control_async_retries | d(command_item['async']['retries']) | d(0) | int }}"
57+
delay: "{{ sap_control_async_delay | d(command_item['async']['delay']) | d(0) | int }}"
58+
until: >
59+
( command_item['async']['until_false'] is not defined
60+
or __sap_control_register_async_command_output.stdout
61+
| regex_search(command_item['async']['until_false'], multiline=True) is none)
62+
and
63+
(command_item['async']['until_true'] is not defined
64+
or __sap_control_register_async_command_output.stdout
65+
| regex_search(command_item['async']['until_true'], multiline=True) is not none)
Lines changed: 14 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
# SPDX-License-Identifier: Apache-2.0
22
---
33

4-
- name: SAP Control - Show command to be executed - {{ command_item['nr'] }}
4+
- name: SAP Control - Show command to be executed for instance - {{ command_item['nr'] }}
55
ansible.builtin.debug:
66
msg: |
77
User: {{ command_item['user'] }}
88
Command: {{ command_item['command'] }}
99
10-
- name: SAP Control - Execute sapcontrol command # noqa command-instead-of-shell no-changed-when
10+
- name: SAP Control - Execute sapcontrol command for instance - {{ command_item['nr'] }} # noqa command-instead-of-shell no-changed-when
1111
ansible.builtin.shell:
1212
cmd: "{{ command_item['command'] }}"
1313
become: true
@@ -16,78 +16,15 @@
1616
ignore_errors: true
1717

1818

19-
- name: Block to wait for status to change if using restart or update
19+
- name: SAP Control - Start asynchronous monitoring for instance - {{ command_item['nr'] }}
20+
ansible.builtin.include_tasks:
21+
file: actions/async_monitor.yml
2022
when:
21-
- sap_control_function is match('restart|update')
2223
- command_item['async'] is defined
2324
- command_item['async'] | length > 0
24-
block:
25-
- name: SAP Control - Get current system state - {{ command_item['nr'] }} # noqa no-changed-when
26-
ansible.builtin.shell:
27-
cmd: >-
28-
source ~/.profile &&
29-
sapcontrol
30-
-nr {{ command_item['nr'] }}
31-
-function {{ command_item['async']['test_function'] | d('GetSystemInstanceList') }}
32-
become: true
33-
become_user: "{{ command_item['user'] }}"
34-
register: __sap_control_register_async_update_before
35-
changed_when: false
3625

37-
- name: SAP Control - Wait for state to change for update and restart - {{ command_item['nr'] }}
38-
ansible.builtin.shell:
39-
cmd: >-
40-
source ~/.profile &&
41-
sapcontrol
42-
-nr {{ command_item['nr'] }}
43-
-function {{ command_item['async']['test_function'] | d('GetSystemInstanceList') }}
44-
become: true
45-
become_user: "{{ command_item['user'] }}"
46-
register: __sap_control_register_async_update_after
47-
changed_when: false
48-
retries: "{{ command_item['async']['retries'] | d(0) | int }}"
49-
delay: "{{ command_item['async']['delay'] | d(0) | int }}"
50-
until: >
51-
(__sap_control_register_async_update_after.stdout
52-
| regex_findall('GREEN|YELLOW|GRAY|RED', multiline=True) | sort | join(','))
53-
!= (__sap_control_register_async_update_before.stdout
54-
| regex_findall('GREEN|YELLOW|GRAY|RED', multiline=True) | sort | join(','))
5526

56-
57-
- name: Block for async wait
58-
when:
59-
- command_item['async'] is defined
60-
- command_item['async'] | length > 0
61-
block:
62-
- name: SAP Control - Wait for 20 Seconds to ensure the async function is started
63-
ansible.builtin.wait_for:
64-
timeout: 20
65-
66-
- name: SAP Control - Wait for state to change in retry loop - {{ command_item['nr'] }}
67-
ansible.builtin.shell:
68-
cmd: >-
69-
source ~/.profile &&
70-
sapcontrol
71-
-nr {{ command_item['nr'] }}
72-
-function {{ command_item['async']['test_function'] | d('GetSystemInstanceList') }}
73-
become: true
74-
become_user: "{{ command_item['user'] }}"
75-
register: __sap_control_register_async_command_output
76-
changed_when: false
77-
retries: "{{ command_item['async']['retries'] | d(0) | int }}"
78-
delay: "{{ command_item['async']['delay'] | d(0) | int }}"
79-
until: >
80-
( command_item['async']['until_false'] is not defined
81-
or command_item['async']['until_false'] is defined
82-
and __sap_control_register_async_command_output.stdout
83-
| regex_search(command_item['async']['until_false'], multiline=True) is none) and
84-
(command_item['async']['until_true'] is not defined or
85-
command_item['async']['until_true'] is defined
86-
and __sap_control_register_async_command_output.stdout
87-
| regex_search(command_item['async']['until_true'], multiline=True) is not none)
88-
89-
90-
- name: SAP Control - Execute 'cleanipc' command
27+
- name: SAP Control - Execute 'cleanipc' command for instance - {{ command_item['nr'] }}
9128
ansible.builtin.shell:
9229
cmd: >-
9330
source ~/.profile &&
@@ -108,7 +45,7 @@
10845
| int > 0
10946
11047
111-
- name: SAP Control - Get final status of instance - {{ command_item['nr'] }}
48+
- name: SAP Control - Get final status for instance - {{ command_item['nr'] }}
11249
ansible.builtin.shell:
11350
cmd: >-
11451
source ~/.profile &&
@@ -128,8 +65,7 @@
12865
if command_item['command'] is match('.*system$')
12966
or (sap_control_function.split('_')[0] | lower) is match('.*system$')
13067
else
131-
'GetProcessList'
132-
}}
68+
'GetProcessList' }}
13369
13470
13571
- name: SAP Control - Show final status of instance - {{ command_item['nr'] }}
@@ -139,5 +75,11 @@
13975
User: {{ command_item['user'] }}
14076
Command: {{ command_item['command'] }}
14177
78+
{% if sap_control_command_nowait | d(false)
79+
and (command_item['async'] is not defined or command_item['async'] | length == 0) %}
80+
This role was executed with 'sap_control_command_nowait' set to 'true',
81+
which skipped waiting for command and reported status can be inaccurate.
82+
{% endif %}
83+
14284
Status:
14385
{{ __sap_control_register_final_status.stdout }}

roles/sap_control/tasks/actions/sapstartsrv.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# SPDX-License-Identifier: Apache-2.0
22
---
33

4-
- name: SAP Control - Get status of 'sapstartsrv' service - {{ __command_nr }}
4+
- name: SAP Control - Get status of 'sapstartsrv' service for instance - {{ __command_nr }}
55
ansible.builtin.shell:
66
cmd: >-
77
source ~/.profile &&
@@ -20,7 +20,7 @@
2020
'FAIL' in __sap_control_register_sapstartsrv_check.stdout
2121
or 'NIECONN_REFUSED' in __sap_control_register_sapstartsrv_check.stdout
2222
block:
23-
- name: SAP Control - Stop 'sapstartsrv' service - {{ __command_nr }} # noqa no-changed-when
23+
- name: SAP Control - Stop 'sapstartsrv' service for instance - {{ __command_nr }} # noqa no-changed-when
2424
ansible.builtin.shell:
2525
cmd: >-
2626
source ~/.profile &&
@@ -32,7 +32,7 @@
3232
register: __sap_control_register_sapstartsrv_stop
3333
ignore_errors: true
3434

35-
- name: SAP Control - Start 'sapstartsrv' service - {{ __command_nr }} # noqa no-changed-when
35+
- name: SAP Control - Start 'sapstartsrv' service for instance - {{ __command_nr }} # noqa no-changed-when
3636
ansible.builtin.shell:
3737
cmd: >-
3838
source ~/.profile &&
@@ -44,7 +44,7 @@
4444
register: __sap_control_register_sapstartsrv_start
4545
ignore_errors: true
4646

47-
- name: SAP Control - Get status of 'sapstartsrv' service - {{ __command_nr }}
47+
- name: SAP Control - Get status of 'sapstartsrv' service for instance - {{ __command_nr }}
4848
ansible.builtin.shell:
4949
cmd: >-
5050
source ~/.profile &&
@@ -58,7 +58,7 @@
5858
changed_when: false
5959

6060

61-
- name: SAP Control - Fail when 'sapstartsrv' cannot be verified - {{ __command_nr }}
61+
- name: SAP Control - Fail when 'sapstartsrv' cannot be verified for instance - {{ __command_nr }}
6262
ansible.builtin.fail:
6363
msg: |
6464
FAIL: Unable to verify that 'sapstartsrv' is running.
@@ -69,7 +69,7 @@
6969
or 'NIECONN_REFUSED' in __sap_control_register_sapstartsrv_recheck.stdout
7070
7171
72-
- name: SAP Control - Wait for 10 seconds for sapstartsrv to initialize
72+
- name: SAP Control - Wait for 10 seconds for sapstartsrv to initialize for instance - {{ __command_nr }}
7373
ansible.builtin.wait_for:
7474
timeout: 10
7575
when:

0 commit comments

Comments
 (0)