Skip to content

Commit a28992a

Browse files
authored
Merge pull request sap-linuxlab#1224 from ja9fuchs/feat-hsr-multinic
sap_ha_install_hana_hsr: Add dedicated replication network support
2 parents 3e57f3c + f063118 commit a28992a

6 files changed

Lines changed: 214 additions & 18 deletions

File tree

roles/sap_ha_install_hana_hsr/README.md

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,13 @@ It is recommended to execute this role together with other roles in this collect
6060
node_ip: "10.10.10.10"
6161
node_role: primary
6262
hana_site: DC01
63+
node_hsr_ip: "192.168.10.10" # optional
6364

6465
- node_name: h01hana1
6566
node_ip: "10.10.10.11"
6667
node_role: secondary
6768
hana_site: DC02
69+
node_hsr_ip: "192.168.10.11" # optional
6870

6971
sap_ha_install_hana_hsr_sid: H01
7072
sap_ha_install_hana_hsr_instance_number: "01"
@@ -131,6 +133,11 @@ This can be inherited from the variable `sap_hana_cluster_nodes`.
131133
Available options: `primary`, `secondary`.<br>
132134
- **hana_site**<br>
133135
A unique logical site name (e.g., DC01, EU-WEST) (String).<br>
136+
- **node_hsr_ip** (optional)<br>
137+
IP address of the dedicated replication network interface (String).<br>
138+
When set, configures `[system_replication_hostname_resolution]` in `global.ini`
139+
to map each peer's hostname to its replication IP.<br>
140+
It must be defined for all nodes or none.<br>
134141

135142
Example:
136143

@@ -140,18 +147,20 @@ sap_ha_install_hana_hsr_cluster_nodes:
140147
node_ip: '192.168.1.11'
141148
node_role: 'primary'
142149
hana_site: 'DC01'
150+
node_hsr_ip: '10.0.0.11'
143151
144152
- node_name: 'node02'
145153
node_ip: '192.168.1.12'
146154
node_role: 'secondary'
147155
hana_site: 'DC02'
156+
node_hsr_ip: '10.0.0.12'
148157
```
149158

150159
### sap_ha_install_hana_hsr_hdbuserstore_system_backup_user
151160
- _Type:_ `string`
152161
- _Default:_ `HDB_SYSTEMDB`
153162

154-
The hdbuserstore key used for connecting to the SYSTEMDB for administrative tasks like backups.
163+
The hdbuserstore key used for connecting to the SYSTEMDB for administrative tasks like backups or updating the global.ini.
155164

156165
### sap_ha_install_hana_hsr_db_system_password
157166
- _Type:_ `string`
@@ -239,4 +248,13 @@ The specified ports are opened directly and no service definition is created.<br
239248
Optional name of firewall zone where service or ports will be configured.<br>
240249
Default firewall zone, usually `public`, is used if this variable is undefined.
241250

242-
<!-- END Role Variables -->
251+
### sap_ha_install_hana_hsr_listeninterface
252+
- _Type:_ `string`
253+
254+
SAP HANA System Replication listen interface.<br>
255+
Controls which network interface HANA listens on for incoming replication connections.<br>
256+
Available values: `.internal`, `.global`.<br>
257+
When not set, listeninterface is not configured and HANA uses its default.<br>
258+
Setting `.internal` requires `node_hsr_ip` to be defined on all nodes.
259+
260+
<!-- END Role Variables -->

roles/sap_ha_install_hana_hsr/defaults/main.yml

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,26 @@ sap_ha_install_hana_hsr_instance_number: ''
2323
# node_role: (string) Role of the node in the HSR setup. Valid options: 'primary', 'secondary'.
2424
# hana_site: (string) A unique logical site name (e.g., DC01, EU-WEST).
2525
#
26+
# Optional key for dedicated replication network:
27+
# node_hsr_ip: (string) IP address of the dedicated replication interface.
28+
# When set, configures [system_replication_hostname_resolution] in global.ini
29+
# to map each peer's hostname to its replication IP.
30+
#
2631
# Example:
2732
# sap_ha_install_hana_hsr_cluster_nodes:
2833
# - node_name: "hana01"
2934
# node_ip: "10.0.0.1"
3035
# node_role: primary
3136
# hana_site: DC01
37+
# node_hsr_ip: "192.168.10.1"
3238
# - node_name: "hana02"
3339
# node_ip: "10.0.0.2"
3440
# node_role: secondary
3541
# hana_site: DC02
42+
# node_hsr_ip: "192.168.10.2"
3643
sap_ha_install_hana_hsr_cluster_nodes: []
3744

38-
# The hdbuserstore key used for connecting to the SYSTEMDB for administrative tasks like backups (String).
45+
# The hdbuserstore key used for connecting to the SYSTEMDB for administrative tasks like backups or updating the global.ini (String).
3946
sap_ha_install_hana_hsr_hdbuserstore_system_backup_user: HDB_SYSTEMDB
4047

4148
# Password for the HANA 'SYSTEM' user (String).
@@ -104,3 +111,9 @@ sap_ha_install_hana_hsr_configure_firewall: false
104111
# Optional name of firewall zone where service or ports will be configured.
105112
# Default firewall zone, usually `public`, is used if this variable is undefined.
106113
# sap_ha_install_hana_hsr_firewall_zone: ''
114+
115+
# Optional: SAP HANA System Replication listen interface (String).
116+
# Controls which network interface HANA listens on for incoming replication connections.
117+
# Available values: '.internal', '.global'.
118+
# When not set, listeninterface is not configured and HANA uses its default.
119+
# sap_ha_install_hana_hsr_listeninterface: ''

roles/sap_ha_install_hana_hsr/tasks/main.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,16 @@
9191
tags: hsr_logmode
9292
tags: hsr_logmode
9393

94+
- name: SAP HSR - Configure dedicated HSR network
95+
ansible.builtin.include_tasks:
96+
file: pre_tasks/configure_hsr_network.yml
97+
apply:
98+
tags: hsr_network
99+
when:
100+
- __sap_ha_install_hana_hsr_fact_replication_network or
101+
sap_ha_install_hana_hsr_listeninterface | d('') | length > 0
102+
tags: hsr_network
103+
94104
- name: SAP HSR - Prepare and sync PKI Files
95105
ansible.builtin.include_tasks:
96106
file: pre_tasks/sync_pki_files.yml
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
---
3+
# Configure replication network settings at SYSTEM layer only. HOST layer overrides are not managed by this role.
4+
5+
- name: SAP HSR - Check current system_replication_hostname_resolution in global.ini
6+
become: true
7+
become_user: "{{ __sap_ha_install_hana_hsr_sid | lower }}adm"
8+
ansible.builtin.shell:
9+
cmd: |
10+
/usr/sap/{{ __sap_ha_install_hana_hsr_sid }}/SYS/exe/hdb/hdbsql \
11+
-U {{ sap_ha_install_hana_hsr_hdbuserstore_system_backup_user }} \
12+
-m <<EOF
13+
SELECT KEY, VALUE FROM M_INIFILE_CONTENTS
14+
WHERE FILE_NAME = 'global.ini'
15+
AND LAYER_NAME = 'SYSTEM'
16+
AND SECTION = 'system_replication_hostname_resolution'
17+
AND KEY = '{{ node_item.node_hsr_ip }}'
18+
AND VALUE = '{{ node_item.node_name }}';
19+
EOF
20+
loop: "{{ sap_ha_install_hana_hsr_cluster_nodes }}"
21+
loop_control:
22+
label: "{{ node_item.node_hsr_ip | d('undefined') }} = {{ node_item.node_name }}"
23+
loop_var: node_item
24+
register: __sap_ha_install_hana_hsr_register_hostname_resolution
25+
changed_when: false
26+
failed_when: false
27+
when: __sap_ha_install_hana_hsr_fact_replication_network
28+
29+
- name: SAP HSR - Configure system_replication_hostname_resolution in global.ini
30+
become: true
31+
become_user: "{{ __sap_ha_install_hana_hsr_sid | lower }}adm"
32+
ansible.builtin.shell:
33+
cmd: |
34+
/usr/sap/{{ __sap_ha_install_hana_hsr_sid }}/SYS/exe/hdb/hdbsql \
35+
-U {{ sap_ha_install_hana_hsr_hdbuserstore_system_backup_user }} \
36+
-m <<EOF
37+
ALTER SYSTEM ALTER CONFIGURATION('global.ini','SYSTEM')
38+
SET ('system_replication_hostname_resolution','{{ node_item.node_item.node_hsr_ip }}')
39+
= '{{ node_item.node_item.node_name }}' WITH RECONFIGURE;
40+
EOF
41+
loop: "{{ __sap_ha_install_hana_hsr_register_hostname_resolution.results }}"
42+
loop_control:
43+
label: "{{ node_item.node_item.node_hsr_ip | d('undefined') }} = {{ node_item.node_item.node_name }}"
44+
loop_var: node_item
45+
changed_when: true
46+
when:
47+
- __sap_ha_install_hana_hsr_fact_replication_network
48+
- node_item.node_item.node_name not in node_item.stdout
49+
50+
- name: SAP HSR - Check current listeninterface in global.ini
51+
become: true
52+
become_user: "{{ __sap_ha_install_hana_hsr_sid | lower }}adm"
53+
ansible.builtin.shell:
54+
cmd: |
55+
/usr/sap/{{ __sap_ha_install_hana_hsr_sid }}/SYS/exe/hdb/hdbsql \
56+
-U {{ sap_ha_install_hana_hsr_hdbuserstore_system_backup_user }} \
57+
-m <<EOF
58+
SELECT VALUE FROM M_INIFILE_CONTENTS
59+
WHERE FILE_NAME = 'global.ini'
60+
AND LAYER_NAME = 'SYSTEM'
61+
AND SECTION = 'system_replication_communication'
62+
AND KEY = 'listeninterface'
63+
AND VALUE = '{{ sap_ha_install_hana_hsr_listeninterface }}';
64+
EOF
65+
register: __sap_ha_install_hana_hsr_register_listeninterface
66+
changed_when: false
67+
failed_when: false
68+
when: sap_ha_install_hana_hsr_listeninterface | d('') | length > 0
69+
70+
- name: SAP HSR - Configure listeninterface in global.ini
71+
become: true
72+
become_user: "{{ __sap_ha_install_hana_hsr_sid | lower }}adm"
73+
ansible.builtin.shell:
74+
cmd: |
75+
/usr/sap/{{ __sap_ha_install_hana_hsr_sid }}/SYS/exe/hdb/hdbsql \
76+
-U {{ sap_ha_install_hana_hsr_hdbuserstore_system_backup_user }} \
77+
-m <<EOF
78+
ALTER SYSTEM ALTER CONFIGURATION('global.ini','SYSTEM')
79+
SET ('system_replication_communication','listeninterface')
80+
= '{{ sap_ha_install_hana_hsr_listeninterface }}' WITH RECONFIGURE;
81+
EOF
82+
changed_when: true
83+
when:
84+
- sap_ha_install_hana_hsr_listeninterface | d('') | length > 0
85+
- sap_ha_install_hana_hsr_listeninterface not in __sap_ha_install_hana_hsr_register_listeninterface.stdout

roles/sap_ha_install_hana_hsr/tasks/pre_tasks/prepare_variables.yml

Lines changed: 65 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -246,11 +246,12 @@
246246
success_msg: |
247247
PASS: Node '{{ node_item.node_name }}' has all required attributes.
248248
fail_msg: |
249-
FAIL: Node '{{ node_item.node_name | default('undefined') }}' is missing required attributes or has empty values.
249+
FAIL: Node '{{ node_item.node_name | d('undefined') }}' is missing required attributes or has empty values.
250250
Each node must have 'node_name', 'node_ip', 'node_role', and 'hana_site' defined with non-empty values."
251+
quiet: true
251252
loop: "{{ __sap_ha_install_hana_hsr_cluster_nodes }}"
252253
loop_control:
253-
label: "{{ node_item.node_name | default('N/A') }}"
254+
label: "{{ node_item.node_name | d('N/A') }}"
254255
loop_var: node_item
255256

256257
- name: SAP HSR - Assert that nodes in 'sap_ha_install_hana_hsr_cluster_nodes' have required 'node_role' values.
@@ -270,16 +271,65 @@
270271
{% endif %}
271272
272273
274+
# Replication network
275+
- name: SAP HSR - Set fact for replication network availability
276+
ansible.builtin.set_fact:
277+
__sap_ha_install_hana_hsr_fact_replication_network:
278+
"{{ __sap_ha_install_hana_hsr_cluster_nodes | selectattr('node_hsr_ip', 'defined') | list | length > 0 }}"
279+
280+
- name: SAP HSR - Assert that all nodes define 'node_hsr_ip' when any node does
281+
ansible.builtin.assert:
282+
that:
283+
- node_item.node_hsr_ip is defined
284+
- node_item.node_hsr_ip is string
285+
- node_item.node_hsr_ip | trim | string | length > 0
286+
success_msg: |
287+
PASS: Node '{{ node_item.node_name }}' has 'node_hsr_ip' defined.
288+
fail_msg: |
289+
FAIL: Node '{{ node_item.node_name }}' parameter 'node_hsr_ip' is undefined, empty, or invalid.
290+
When using a dedicated replication network, all nodes must define 'node_hsr_ip'.
291+
quiet: true
292+
loop: "{{ __sap_ha_install_hana_hsr_cluster_nodes }}"
293+
loop_control:
294+
label: "{{ node_item.node_name }}"
295+
loop_var: node_item
296+
when: __sap_ha_install_hana_hsr_fact_replication_network
297+
298+
299+
# Listeninterface
300+
- name: SAP HSR - Assert that the variable 'sap_ha_install_hana_hsr_listeninterface' is valid
301+
ansible.builtin.assert:
302+
that:
303+
- sap_ha_install_hana_hsr_listeninterface is string
304+
- sap_ha_install_hana_hsr_listeninterface in ['.internal', '.global']
305+
success_msg: |
306+
PASS: The variable 'sap_ha_install_hana_hsr_listeninterface' is '{{ sap_ha_install_hana_hsr_listeninterface }}'.
307+
fail_msg: |
308+
FAIL: The variable 'sap_ha_install_hana_hsr_listeninterface' must be '.internal' or '.global'.
309+
when: sap_ha_install_hana_hsr_listeninterface | d('') | length > 0
310+
311+
- name: SAP HSR - Assert that 'node_hsr_ip' is defined when listeninterface is '.internal'
312+
ansible.builtin.assert:
313+
that:
314+
- __sap_ha_install_hana_hsr_fact_replication_network
315+
fail_msg: |
316+
FAIL: 'sap_ha_install_hana_hsr_listeninterface' is set to '.internal' but no 'node_hsr_ip' is defined.
317+
HANA needs [system_replication_hostname_resolution] entries to bind to the internal interface.
318+
Define 'node_hsr_ip' on all nodes in 'sap_ha_install_hana_hsr_cluster_nodes'.
319+
when: sap_ha_install_hana_hsr_listeninterface | d('') == '.internal'
320+
321+
273322
# Host specific cluster configuration
274323
- name: SAP HSR - Set host specific connection variable
275324
ansible.builtin.set_fact:
276325
__sap_ha_install_hana_hsr_connection:
277326
node_fqdn: "{{ node_item.node_name }}"
278327
node_name: "{{ node_item.node_name.split('.')[0] }}"
279-
node_domain: "{{ node_item.node_name.split('.')[1:] | join('.') or __sap_ha_install_hana_hsr_domain | default('') }}"
328+
node_domain: "{{ node_item.node_name.split('.')[1:] | join('.') or __sap_ha_install_hana_hsr_domain | d('') }}"
280329
node_ip: "{{ node_item.node_ip }}"
281330
node_role: "{{ node_item.node_role }}"
282331
hana_site: "{{ node_item.hana_site }}"
332+
node_hsr_ip: "{{ node_item.node_hsr_ip | d('') }}"
283333
loop: "{{ __sap_ha_install_hana_hsr_cluster_nodes }}"
284334
loop_control:
285335
label: "{{ node_item.node_name }}"
@@ -291,8 +341,8 @@
291341
# Sets host specific flags that are used for running tasks on specific hosts.
292342
- name: SAP HSR - Set fact with boolean flags for each host
293343
ansible.builtin.set_fact:
294-
__sap_ha_install_hana_hsr_fact_is_primary: "{{ __sap_ha_install_hana_hsr_connection.node_role | default('') == 'primary' }}"
295-
__sap_ha_install_hana_hsr_fact_is_secondary: "{{ __sap_ha_install_hana_hsr_connection.node_role | default('') == 'secondary' }}"
344+
__sap_ha_install_hana_hsr_fact_is_primary: "{{ __sap_ha_install_hana_hsr_connection.node_role | d('') == 'primary' }}"
345+
__sap_ha_install_hana_hsr_fact_is_secondary: "{{ __sap_ha_install_hana_hsr_connection.node_role | d('') == 'secondary' }}"
296346

297347
- name: SAP HSR - Check that host is a defined member of the HSR cluster
298348
ansible.builtin.assert:
@@ -316,6 +366,16 @@
316366
317367
If this host is not supposed to be part of the HSR cluster, please remove it from hosts in Ansible Play.
318368
369+
- name: SAP HSR - Assert that 'node_hsr_ip' is present on this host
370+
ansible.builtin.assert:
371+
that:
372+
- __sap_ha_install_hana_hsr_connection.node_hsr_ip in ansible_facts['all_ipv4_addresses']
373+
fail_msg: |
374+
FAIL: The 'node_hsr_ip' ({{ __sap_ha_install_hana_hsr_connection.node_hsr_ip }})
375+
is not configured on host '{{ __sap_ha_install_hana_hsr_connection.node_name }}'.
376+
The replication IP must be present on a network interface before configuring HSR.
377+
when: __sap_ha_install_hana_hsr_fact_replication_network
378+
319379
# Set details of primary for connection from secondary
320380
- name: SAP HSR - Set connection variables for primary node
321381
ansible.builtin.set_fact:
Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,40 @@
11
# SPDX-License-Identifier: Apache-2.0
22
---
3+
# Set log_mode at SYSTEM layer only. HOST layer overrides are not managed by this role.
34

4-
- name: SAP HSR - check log_mode
5+
- name: SAP HSR - Check current log_mode in SYSTEM global.ini
56
become: true
67
become_user: "{{ __sap_ha_install_hana_hsr_sid | lower }}adm"
78
ansible.builtin.shell:
8-
cmd: >-
9-
set -o pipefail &&
10-
grep "log_mode" /usr/sap/{{ __sap_ha_install_hana_hsr_sid }}/SYS/global/hdb/custom/config/global.ini | grep normal
9+
cmd: |
10+
/usr/sap/{{ __sap_ha_install_hana_hsr_sid }}/SYS/exe/hdb/hdbsql \
11+
-U {{ sap_ha_install_hana_hsr_hdbuserstore_system_backup_user }} \
12+
-m <<EOF
13+
SELECT VALUE FROM M_INIFILE_CONTENTS
14+
WHERE FILE_NAME = 'global.ini'
15+
AND LAYER_NAME = 'SYSTEM'
16+
AND SECTION = 'persistence'
17+
AND KEY = 'log_mode'
18+
AND VALUE = 'normal';
19+
EOF
1120
register: __sap_ha_install_hana_hsr_register_log_mode
1221
failed_when: false
1322
changed_when: false
1423

15-
# CHECK, if ansible_facts['hostname'] needs to be replaced with interface name
16-
# This task will fail when HSR is already configured, because secondary node nameserver is not running with port 3XX13.
17-
- name: SAP HSR - Set log_mode to normal
24+
# This task will fail when HSR is already configured,
25+
# because secondary node nameserver is not running with port 3XX13.
26+
- name: SAP HSR - Set log_mode to normal for SYSTEM
1827
become: true
1928
become_user: "{{ __sap_ha_install_hana_hsr_sid | lower }}adm"
2029
ansible.builtin.shell:
2130
cmd: |
2231
/usr/sap/{{ __sap_ha_install_hana_hsr_sid }}/SYS/exe/hdb/hdbsql \
2332
-U {{ sap_ha_install_hana_hsr_hdbuserstore_system_backup_user }} \
2433
-m <<EOF
25-
ALTER SYSTEM ALTER CONFIGURATION ('global.ini', 'SYSTEM') SET ('persistence', 'log_mode') = 'normal' WITH RECONFIGURE;
26-
ALTER SYSTEM ALTER CONFIGURATION('global.ini','HOST','{{ ansible_facts['hostname'] }}') SET ('persistence','log_mode') = 'normal' WITH RECONFIGURE;
34+
ALTER SYSTEM ALTER CONFIGURATION('global.ini','SYSTEM')
35+
SET ('persistence','log_mode')
36+
= 'normal' WITH RECONFIGURE;
2737
EOF
2838
ignore_errors: true
29-
when: __sap_ha_install_hana_hsr_register_log_mode.rc != '0'
39+
when: "'normal' not in __sap_ha_install_hana_hsr_register_log_mode.stdout"
3040
changed_when: true

0 commit comments

Comments
 (0)