Skip to content

Commit d8b706d

Browse files
Enhance AzureDataParser to support additional mount point formats (#145)
1 parent 15051b5 commit d8b706d

File tree

11 files changed

+270
-92
lines changed

11 files changed

+270
-92
lines changed

scripts/sap_automation_qa.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ Examples:
102102
# Configuration Checks (requires TEST_TYPE: ConfigurationChecks in vars.yaml)
103103
$0 --extra-vars='{"configuration_test_type":"all"}'
104104
$0 --extra-vars='{"configuration_test_type":"high_availability"}'
105-
$0 --extra-vars='{"configuration_test_type":"Database"}' -vv
105+
$0 --extra-vars='{"configuration_test_type":"Database"}' -v
106106
107107
Available Test Cases for groups:
108108
$0 --test_groups=HA_DB_HANA

src/module_utils/collector.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,11 @@ def collect(self, check, context) -> str:
109109
user = check.collector_args.get("user", "")
110110
if not command:
111111
return "ERROR: No command specified"
112+
if user:
113+
if not re.match(r"^[a-zA-Z0-9_-]+$", user):
114+
self.parent.log(logging.ERROR, f"Invalid user parameter detected: {user}")
115+
return "ERROR: Invalid user parameter"
116+
112117
try:
113118
command = self.sanitize_command(command)
114119
except ValueError as e:
@@ -123,16 +128,13 @@ def collect(self, check, context) -> str:
123128
)
124129
return f"ERROR: Command sanitization failed after substitution: {e}"
125130

126-
check.command = command
127131
if user and user != "root":
128-
if not re.match(r"^[a-zA-Z0-9_-]+$", user):
129-
self.parent.log(logging.ERROR, f"Invalid user parameter: {user}")
130-
return f"ERROR: Invalid user parameter: {user}"
131-
132132
if user == "db2sid":
133133
user = f"db2{context.get('database_sid', '').lower()}"
134+
command = f"su - {user} -c {shlex.quote(command)}"
135+
self.parent.log(logging.INFO, f"Executing command as user {user} {command}")
134136

135-
command = f"sudo -u {shlex.quote(user)} {command}"
137+
check.command = command
136138

137139
return self.parent.execute_command_subprocess(
138140
command, shell_command=check.collector_args.get("shell", True)
@@ -339,7 +341,11 @@ def parse_disks_vars(self, check, context) -> str:
339341

340342
fs_entry = None
341343
for fs in filesystem_data:
342-
if fs.get("target") == mount_point:
344+
if fs.get("target") in (
345+
mount_point,
346+
f"{mount_point}/{context.get('database_sid', '').upper()}",
347+
f"{mount_point}/{context.get('sap_sid', '').upper()}",
348+
):
343349
fs_entry = fs
344350
break
345351

src/module_utils/filesystem_collector.py

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,25 @@ def _parse_filesystem_data(
112112
for nfs_share in afs_storage_data:
113113
storage_account_name = nfs_share.get("Pool", "")
114114
share_address = nfs_share.get("NFSAddress", "")
115-
if (
115+
ip_match = (
116116
":" in share_address and share_address.split(":")[0] == nfs_address
117-
) or storage_account_name in nfs_address:
117+
)
118+
fqdn_match = storage_account_name and storage_account_name in nfs_source
119+
ip_to_account_match = False
120+
try:
121+
ipaddress.ip_address(nfs_address)
122+
except Exception as ex:
123+
self.parent.log(
124+
logging.DEBUG,
125+
f"NFS address {nfs_address} is not a valid IP: {ex}",
126+
)
127+
if ":" in nfs_source and "/" in nfs_source:
128+
mount_path = nfs_source.split(":", 1)[1]
129+
ip_to_account_match = (
130+
storage_account_name
131+
and ("/" + storage_account_name + "/") in mount_path
132+
)
133+
if ip_match or fqdn_match or ip_to_account_match:
118134
filesystem_entry["max_mbps"] = nfs_share.get("ThroughputMibps", 0)
119135
filesystem_entry["max_iops"] = nfs_share.get("IOPS", 0)
120136
filesystem_entry["nfs_type"] = "AFS"
@@ -472,16 +488,36 @@ def gather_all_filesystem_info(
472488
if not matched:
473489
for nfs_share in afs_storage_data:
474490
share_address = nfs_share.get("NFSAddress", "")
475-
if (
491+
storage_account_name = nfs_share.get("Pool", "")
492+
ip_match = (
476493
":" in share_address
477494
and share_address.split(":")[0] == nfs_address
478-
):
495+
)
496+
fqdn_match = storage_account_name and storage_account_name in source
497+
ip_to_account_match = False
498+
try:
499+
ipaddress.ip_address(nfs_address)
500+
if ":" in source and "/" in source:
501+
mount_path = source.split(":", 1)[1]
502+
ip_to_account_match = (
503+
storage_account_name
504+
and ("/" + storage_account_name + "/") in mount_path
505+
)
506+
except ValueError:
507+
pass
508+
509+
if ip_match or fqdn_match or ip_to_account_match:
479510
max_mbps = nfs_share.get("ThroughputMibps", 0)
480511
max_iops = nfs_share.get("IOPS", 0)
512+
match_type = (
513+
"IP"
514+
if ip_match
515+
else ("FQDN" if fqdn_match else "IP→Account")
516+
)
481517
self.parent.log(
482518
logging.INFO,
483519
f"Correlated NFS {target} with "
484-
+ f"AFS: MBPS={max_mbps}, IOPS={max_iops}",
520+
+ f"AFS ({match_type}): MBPS={max_mbps}, IOPS={max_iops}, Account={storage_account_name}",
485521
)
486522
break
487523

src/modules/configuration_check_module.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ def is_check_applicable(self, check: Check) -> bool:
281281
"""
282282
self.log(
283283
logging.DEBUG,
284-
f"Checking applicability for check {check.applicability} with context: {self.context}",
284+
f"Checking applicability for check {check.applicability}",
285285
)
286286
for rule in check.applicability:
287287
context_value = self.context.get(rule.property)

src/playbook_00_configuration_checks.yml

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
msg: "Host {{ inventory_hostname }} assigned role: {{ role }} from groups: {{ group_names }}"
7777

7878
- name: "Load supported VM information"
79+
no_log: true
7980
ansible.builtin.include_vars:
8081
file: "./roles/configuration_checks/vars/vm-support.yml"
8182
name: vm_support
@@ -258,12 +259,12 @@
258259
'check_type': 'vm_info',
259260
'metadata': hostvars[item].vm_info_results_metadata
260261
| default({})}] }}"
261-
loop: "{{ groups[sap_sid | upper + '_SCS']|default([]) +
262+
loop: "{{ (groups[sap_sid | upper + '_SCS']|default([]) +
262263
groups[sap_sid | upper + '_ERS']|default([]) +
263264
groups[sap_sid | upper + '_DB']|default([]) +
264265
groups[sap_sid | upper + '_APP']|default([]) +
265266
groups[sap_sid | upper + '_WEB']|default([]) +
266-
groups[sap_sid | upper + '_PAS']|default([]) }}"
267+
groups[sap_sid | upper + '_PAS']|default([])) | unique }}"
267268
when: hostvars[item].vm_info_results is defined
268269

269270
- name: "Collect package info check results"
@@ -275,12 +276,12 @@
275276
'check_type': 'package_info',
276277
'metadata': hostvars[item].package_info_results_metadata
277278
| default({})}] }}"
278-
loop: "{{ groups[sap_sid | upper + '_SCS']|default([]) +
279+
loop: "{{ (groups[sap_sid | upper + '_SCS']|default([]) +
279280
groups[sap_sid | upper + '_ERS']|default([]) +
280281
groups[sap_sid | upper + '_DB']|default([]) +
281282
groups[sap_sid | upper + '_APP']|default([]) +
282283
groups[sap_sid | upper + '_WEB']|default([]) +
283-
groups[sap_sid | upper + '_PAS']|default([]) }}"
284+
groups[sap_sid | upper + '_PAS']|default([])) | unique }}"
284285
when: hostvars[item].package_info_results is defined
285286

286287
- name: "Collect common SAP check results"
@@ -292,12 +293,12 @@
292293
'check_type': 'common_sap',
293294
'metadata': hostvars[item].common_sap_results_metadata
294295
| default({})}] }}"
295-
loop: "{{ groups[sap_sid | upper + '_SCS']|default([]) +
296+
loop: "{{ (groups[sap_sid | upper + '_SCS']|default([]) +
296297
groups[sap_sid | upper + '_ERS']|default([]) +
297298
groups[sap_sid | upper + '_DB']|default([]) +
298299
groups[sap_sid | upper + '_APP']|default([]) +
299300
groups[sap_sid | upper + '_WEB']|default([]) +
300-
groups[sap_sid | upper + '_PAS']|default([]) }}"
301+
groups[sap_sid | upper + '_PAS']|default([])) | unique }}"
301302
when: hostvars[item].common_sap_results is defined
302303

303304
- name: "Collect networking check results"
@@ -309,12 +310,12 @@
309310
'check_type': 'networking',
310311
'metadata': hostvars[item].networking_results_metadata
311312
| default({})}] }}"
312-
loop: "{{ groups[sap_sid | upper + '_SCS']|default([]) +
313+
loop: "{{ (groups[sap_sid | upper + '_SCS']|default([]) +
313314
groups[sap_sid | upper + '_ERS']|default([]) +
314315
groups[sap_sid | upper + '_DB']|default([]) +
315316
groups[sap_sid | upper + '_APP']|default([]) +
316317
groups[sap_sid | upper + '_WEB']|default([]) +
317-
groups[sap_sid | upper + '_PAS']|default([]) }}"
318+
groups[sap_sid | upper + '_PAS']|default([])) | unique }}"
318319
when: hostvars[item].networking_results is defined
319320

320321
- name: "Collect DB (HANA) check results"
@@ -362,8 +363,8 @@
362363
'check_type': 'ascs_scs',
363364
'metadata': hostvars[item].ascs_scs_results_metadata
364365
| default({})}] }}"
365-
loop: "{{ groups[sap_sid | upper + '_SCS']|default([]) +
366-
groups[sap_sid | upper + '_ERS']|default([]) }}"
366+
loop: "{{ (groups[sap_sid | upper + '_SCS']|default([]) +
367+
groups[sap_sid | upper + '_ERS']|default([])) | unique }}"
367368
when: hostvars[item].ascs_scs_results is defined
368369

369370
- name: "Collect SCS/ERS HA configuration check results"
@@ -375,8 +376,8 @@
375376
'check_type': 'scs_ha_config',
376377
'metadata': hostvars[item].scs_ha_config_results_metadata
377378
| default({})}] }}"
378-
loop: "{{ groups[sap_sid | upper + '_SCS']|default([]) +
379-
groups[sap_sid | upper + '_ERS']|default([]) }}"
379+
loop: "{{ (groups[sap_sid | upper + '_SCS']|default([]) +
380+
groups[sap_sid | upper + '_ERS']|default([])) | unique }}"
380381
when: hostvars[item].scs_ha_config_results is defined
381382

382383
- name: "Collect Application Server check results"
@@ -388,9 +389,9 @@
388389
'check_type': 'app_server',
389390
'metadata': hostvars[item].app_server_results_metadata
390391
| default({})}] }}"
391-
loop: "{{ groups[sap_sid | upper + '_APP']|default([]) +
392+
loop: "{{ (groups[sap_sid | upper + '_APP']|default([]) +
392393
groups[sap_sid | upper + '_PAS']|default([]) +
393-
groups[sap_sid | upper + '_WEB']|default([]) }}"
394+
groups[sap_sid | upper + '_WEB']|default([])) | unique }}"
394395
when: hostvars[item].app_server_results is defined
395396

396397
- name: "Debug execution metadata"
@@ -427,12 +428,12 @@
427428
if scs_high_availability
428429
| default(false) | bool
429430
else 'N/A' }}"
430-
hostnames: "{{ groups[sap_sid | upper + '_SCS']|default([]) +
431+
hostnames: "{{ (groups[sap_sid | upper + '_SCS']|default([]) +
431432
groups[sap_sid | upper + '_ERS']|default([]) +
432433
groups[sap_sid | upper + '_DB']|default([]) +
433434
groups[sap_sid | upper + '_APP']|default([]) +
434435
groups[sap_sid | upper + '_WEB']|default([]) +
435-
groups[sap_sid | upper + '_PAS']|default([]) }}"
436+
groups[sap_sid | upper + '_PAS']|default([])) | unique }}"
436437
passed_count: "{{ all_results | selectattr('status', 'equalto', 'PASSED') | list | length }}"
437438
error_count: "{{ all_results | selectattr('status', 'equalto', 'FAILED') | list | length }}"
438439
warning_count: "{{ all_results | selectattr('status', 'equalto', 'WARNING') | list | length }}"
@@ -441,10 +442,11 @@
441442

442443
- name: "Render HTML report for configuration checks"
443444
ansible.builtin.include_tasks: "./roles/misc/tasks/render-html-report.yml"
445+
no_log: true
444446
vars:
445447
html_template_name: "./templates/config_checks_report.html"
446448
report_file_name: "CONFIG_{{ sap_sid | upper }}_{{ platform | upper }}"
447449

448450
- name: "Debug the file name of the report generated"
449451
ansible.builtin.debug:
450-
msg: "Report file CONFIG_{{ sap_sid | upper }}_{{ platform | upper }} generated."
452+
msg: "Report file CONFIG_{{ sap_sid | upper }}_{{ platform | upper }}_{{ test_group_invocation_id }} generated."

0 commit comments

Comments
 (0)