diff --git a/src/modules/configuration_check_module.py b/src/modules/configuration_check_module.py index d3eda21f..fc482c81 100644 --- a/src/modules/configuration_check_module.py +++ b/src/modules/configuration_check_module.py @@ -8,6 +8,7 @@ import logging import time import json +import re from typing import Optional, Dict, Any, List, Type from datetime import datetime from concurrent.futures import ThreadPoolExecutor @@ -437,6 +438,8 @@ def validate_string(self, check: Check, collected_data: str) -> Dict[str, Any]: if check.validator_args.get("strip_whitespace", True): expected = str(expected).strip() + expected = re.sub(r'\s+', ' ', expected) + collected = re.sub(r'\s+', ' ', collected) if check.validator_args.get("case_insensitive", False): expected = expected.lower() diff --git a/src/modules/get_cluster_status_db.py b/src/modules/get_cluster_status_db.py index f44adc40..3a65d871 100644 --- a/src/modules/get_cluster_status_db.py +++ b/src/modules/get_cluster_status_db.py @@ -221,7 +221,7 @@ def _process_node_attributes(self, cluster_status_xml: ET.Element) -> Dict[str, HanaSRProvider.ANGI: { "clone_attr": f"hana_{self.database_sid}_clone_state", "sync_attr": ( - f"master-{self.hana_clone_resource_name}" + f"master-{self.hana_primitive_resource_name}" if self.hana_clone_resource_name else f"master-rsc_SAPHanaCon_{self.database_sid.upper()}" + f"_HDB{self.db_instance_number}" diff --git a/src/roles/configuration_checks/tasks/files/network.yml b/src/roles/configuration_checks/tasks/files/network.yml index 07cf25d1..bc741179 100644 --- a/src/roles/configuration_checks/tasks/files/network.yml +++ b/src/roles/configuration_checks/tasks/files/network.yml @@ -204,17 +204,20 @@ checks: command: |- az vm nic list --resource-group {{ CONTEXT.resource_group_name }} \ --vm-name {{ CONTEXT.vm_name }} \ - --subscription {{ CONTEXT.subscription_id }} \ - --query "[].id" -o tsv | while read nic_id; do \ - nic=$(basename "$nic_id"); \ + --subscription {{ CONTEXT.subscription_id }} --query "[].id" -o tsv | + while read -r nic_id; do + nic=$(basename "$nic_id") az network nic show --resource-group {{ CONTEXT.resource_group_name }} --name "$nic" \ - --query "ipConfigurations[].{IP:privateIPAddress, Primary:primary}" -o tsv | \ - while IFS=$'\t' read -r ip is_primary; do \ - if [ "${is_primary,,}" = "true" ]; then \ - echo "$nic: $ip Primary"; \ - else \ - echo "$nic: $ip Secondary"; \ - fi; \ - done; \ + --query "ipConfigurations[].{IP:privateIPAddress, Primary:primary}" -o tsv | + while read -r line; do + ip=$(echo "$line" | awk '{print $1}') + is_primary=$(echo "$line" | awk '{print $2}' | tr -d '\r\t ' | tr '[:upper:]' '[:lower:]') + if [ "$is_primary" = "true" ]; then + echo "$nic: $ip Primary" + else + echo "$nic: $ip Secondary" + fi + done done + report: *check diff --git a/src/roles/configuration_checks/tasks/files/virtual_machine.yml b/src/roles/configuration_checks/tasks/files/virtual_machine.yml index cbfb01b0..d381ab1a 100644 --- a/src/roles/configuration_checks/tasks/files/virtual_machine.yml +++ b/src/roles/configuration_checks/tasks/files/virtual_machine.yml @@ -413,7 +413,7 @@ checks: database_type: [*hana, *ase, *db2, *oracle] collector_type: *command collector_args: - command: "/bin/mdatp health" + command: "if command -v mdatp >/dev/null 2>&1; then mdatp health; else echo 'Microsoft Defender not installed'; fi" user: *root report: *section @@ -581,7 +581,7 @@ checks: database_type: [*hana, *ase, *db2, *oracle] collector_type: *command collector_args: - command: "/bin/mdatp exclusion list" + command: "if command -v mdatp >/dev/null 2>&1; then mdatp exclusion list; else echo 'Microsoft Defender not installed'; fi" user: *root report: *section diff --git a/src/roles/ha_db_hana/tasks/files/constants.yaml b/src/roles/ha_db_hana/tasks/files/constants.yaml index e936e8df..39c2b391 100644 --- a/src/roles/ha_db_hana/tasks/files/constants.yaml +++ b/src/roles/ha_db_hana/tasks/files/constants.yaml @@ -112,7 +112,7 @@ RESOURCE_DEFAULTS: required: false instance_attributes: pcmk_delay_max: - value: "15" + value: ["15", "15s"] required: false pcmk_monitor_retries: value: "4" @@ -142,7 +142,7 @@ RESOURCE_DEFAULTS: required: false instance_attributes: pcmk_delay_max: - value: "15" + value: ["15", "15s"] required: false pcmk_monitor_retries: value: "4" @@ -492,7 +492,7 @@ RESOURCE_DEFAULTS: required: false instance_attributes: pcmk_delay_max: - value: "15" + value: ["15", "15s"] required: false pcmk_monitor_retries: value: "4" @@ -815,7 +815,7 @@ GLOBAL_INI: value: "susHanaSR" required: true path: - value: ["/usr/share/SAPHanaSR", "/hana/shared/myHooks"] + value: ["/usr/share/SAPHanaSR-angi", "/hana/shared/myHooks"] required: true execution_order: value: "1" diff --git a/src/roles/ha_db_hana/tasks/ha-config.yml b/src/roles/ha_db_hana/tasks/ha-config.yml index db411ea8..5069429b 100644 --- a/src/roles/ha_db_hana/tasks/ha-config.yml +++ b/src/roles/ha_db_hana/tasks/ha-config.yml @@ -33,6 +33,104 @@ when: (ansible_os_family | upper) == "SUSE" ansible.builtin.include_tasks: "roles/misc/tasks/get-saphanasr-provider.yml" + - name: "Pre validation: Get HANA resource id for saphanasr_angi" + when: saphanasr_provider | default('SAPHanaSR') == "SAPHanaSR-angi" + block: + - name: "Pre validation: Get HANA clone resource id for saphanasr_angi" + become: true + ansible.builtin.shell: >- + set -o pipefail && {{ commands + | selectattr('name','equalto','get_hana_clone_resource_id_saphanasr_angi') + | map(attribute=(ansible_os_family|upper)) + | first + }} + args: + executable: /bin/bash + changed_when: false + register: hana_clone_resource_id + failed_when: hana_clone_resource_id.rc != 0 + + - name: "Pre validation: Get HANA primitive resource id for saphanasr_angi" + become: true + ansible.builtin.shell: >- + set -o pipefail && {{ commands + | selectattr('name','equalto','get_hana_primitive_resource_id_saphanasr_angi') + | map(attribute=(ansible_os_family|upper)) + | first + }} + args: + executable: /bin/bash + changed_when: false + register: hana_primitive_resource_id + failed_when: hana_primitive_resource_id.rc != 0 + + - name: "Pre validation: Set fact the hana_clone_resource_name" + ansible.builtin.set_fact: + hana_clone_resource_name: "{{ hana_clone_resource_id.stdout }}" + hana_primitive_resource_name: "{{ hana_primitive_resource_id.stdout }}" + + - name: "Pre validation: Get HANA Clone resource id" + when: saphanasr_provider | default('SAPHanaSR') == "SAPHanaSR" + block: + - name: "Try master resource ID" + become: true + ansible.builtin.shell: >- + set -o pipefail && {{ commands + | selectattr('name','equalto','get_hana_clone_resource_id') + | map(attribute=(ansible_os_family|upper)) + | first + }} + args: + executable: /bin/bash + changed_when: false + register: hana_clone_resource_id + failed_when: hana_clone_resource_id.rc != 0 + rescue: + - name: "Try clone resource ID" + become: true + ansible.builtin.shell: >- + set -o pipefail && {{ commands + | selectattr('name','equalto','get_hana_clone_resource_id') + | map(attribute='REDHAT') + | first + }} + args: + executable: /bin/bash + changed_when: false + register: hana_clone_resource_id + failed_when: hana_clone_resource_id.rc != 0 + ignore_errors: true + always: + - name: "Test Execution: Set the resource name" + when: + - hana_clone_resource_id.rc == 0 + - hana_clone_resource_id.stdout is defined + - hana_clone_resource_id.stdout | type_debug != 'NoneType' + - hana_clone_resource_id.stdout | trim | length > 1 + ansible.builtin.set_fact: + hana_clone_resource_name: "{{ hana_clone_resource_id.stdout }}" + + - name: "Pre validation: Get HANA Primitive resource id" + when: saphanasr_provider | default('SAPHanaSR') == "SAPHanaSR" + block: + - name: "Pre validation: Get HANA Primitive resource id" + become: true + ansible.builtin.shell: >- + set -o pipefail && {{ commands + | selectattr('name','equalto','get_hana_primitive_resource_id') + | map(attribute=(ansible_os_family|upper)) + | first + }} + args: + executable: /bin/bash + changed_when: false + register: hana_primitive_resource_id + failed_when: hana_primitive_resource_id.rc != 0 + + - name: "Pre validation: Set fact the hana_primitive_resource_name" + ansible.builtin.set_fact: + hana_primitive_resource_name: "{{ hana_primitive_resource_id.stdout }}" + - name: "Retrieve Virtual Machine name" ansible.builtin.uri: url: http://169.254.169.254/metadata/instance?api-version=2021-02-01 diff --git a/src/roles/ha_db_hana/tasks/resource-migration.yml b/src/roles/ha_db_hana/tasks/resource-migration.yml index 9f44334d..6325d80f 100644 --- a/src/roles/ha_db_hana/tasks/resource-migration.yml +++ b/src/roles/ha_db_hana/tasks/resource-migration.yml @@ -37,7 +37,7 @@ - name: "Test Execution: Get HANA resource id for saphanasr_angi" ansible.builtin.shell: >- set -o pipefail && {{ commands - | selectattr('name','equalto','get_hana_resource_id_saphanasr_angi') + | selectattr('name','equalto','get_hana_clone_resource_id_saphanasr_angi') | map(attribute=(ansible_os_family|upper)) | first }} diff --git a/src/roles/ha_scs/tasks/files/constants.yaml b/src/roles/ha_scs/tasks/files/constants.yaml index 3348fccf..66745245 100644 --- a/src/roles/ha_scs/tasks/files/constants.yaml +++ b/src/roles/ha_scs/tasks/files/constants.yaml @@ -129,7 +129,7 @@ RESOURCE_DEFAULTS: required: false instance_attributes: pcmk_delay_max: - value: "15" + value: ["15", "15s"] required: false pcmk_monitor_retries: value: "4" @@ -169,7 +169,7 @@ RESOURCE_DEFAULTS: sbd_stonith: instance_attributes: pcmk_delay_max: - value: "15" + value: ["15", "15s"] required: false pcmk_monitor_retries: value: "4" @@ -388,7 +388,7 @@ RESOURCE_DEFAULTS: fence_agent: instance_attributes: pcmk_delay_max: - value: "15" + value: ["15", "15s"] required: false pcmk_monitor_retries: value: "4" @@ -428,7 +428,7 @@ RESOURCE_DEFAULTS: sbd_stonith: instance_attributes: pcmk_delay_max: - value: "15" + value: ["15", "15s"] required: false pcmk_monitor_retries: value: "4" diff --git a/src/roles/misc/tasks/pre-validations-db.yml b/src/roles/misc/tasks/pre-validations-db.yml index 5c572943..a0bfadcd 100644 --- a/src/roles/misc/tasks/pre-validations-db.yml +++ b/src/roles/misc/tasks/pre-validations-db.yml @@ -21,11 +21,11 @@ - name: "Pre validation: Get HANA resource id for saphanasr_angi" when: saphanasr_provider | default('SAPHanaSR') == "SAPHanaSR-angi" block: - - name: "Pre validation: Get HANA resource id for saphanasr_angi" + - name: "Pre validation: Get HANA clone resource id for saphanasr_angi" become: true ansible.builtin.shell: >- set -o pipefail && {{ commands - | selectattr('name','equalto','get_hana_resource_id_saphanasr_angi') + | selectattr('name','equalto','get_hana_clone_resource_id_saphanasr_angi') | map(attribute=(ansible_os_family|upper)) | first }} @@ -35,9 +35,24 @@ register: hana_clone_resource_id failed_when: hana_clone_resource_id.rc != 0 + - name: "Pre validation: Get HANA primitive resource id for saphanasr_angi" + become: true + ansible.builtin.shell: >- + set -o pipefail && {{ commands + | selectattr('name','equalto','get_hana_primitive_resource_id_saphanasr_angi') + | map(attribute=(ansible_os_family|upper)) + | first + }} + args: + executable: /bin/bash + changed_when: false + register: hana_primitive_resource_id + failed_when: hana_primitive_resource_id.rc != 0 + - name: "Pre validation: Set fact the hana_clone_resource_name" ansible.builtin.set_fact: - hana_clone_resource_name: "{{ hana_clone_resource_id.stdout }}" + hana_clone_resource_name: "{{ hana_clone_resource_id.stdout }}" + hana_primitive_resource_name: "{{ hana_primitive_resource_id.stdout }}" - name: "Pre validation: Get HANA Clone resource id" when: saphanasr_provider | default('SAPHanaSR') == "SAPHanaSR" diff --git a/src/roles/misc/tasks/render-html-report.yml b/src/roles/misc/tasks/render-html-report.yml index 3c4ba8e4..8e41f712 100644 --- a/src/roles/misc/tasks/render-html-report.yml +++ b/src/roles/misc/tasks/render-html-report.yml @@ -19,6 +19,6 @@ test_group_name: "{{ test_group_name }}_{{ ansible_os_family | upper }}" report_template: "{{ html_report_template }}" workspace_directory: "{{ _workspace_directory }}" - test_case_results: "{{ all_results | default({}) }}" + test_case_results: "{{ all_results | default([]) }}" system_info: "{{ system_info | default({}) }}" register: report_file_path diff --git a/src/templates/config_checks_report.html b/src/templates/config_checks_report.html index b9c029c3..27c7a248 100644 --- a/src/templates/config_checks_report.html +++ b/src/templates/config_checks_report.html @@ -59,7 +59,8 @@ {% endfor %} {% endif %} {% endfor %} - + {% set has_status_column = 'status' in all_keys or 'Status' in all_keys %} +
{% for key in all_keys %} @@ -74,7 +75,13 @@ {% for key in all_keys %} {% set value = item.get(key, '') %} {% if key|lower == 'status' %} - + {% set status_class = value|lower %} + {% if status_class == 'success' or status_class == 'ok' %} + {% set status_class = 'passed' %} + {% elif status_class == 'failed' or status_class == 'error' %} + {% set status_class = 'failed' %} + {% endif %} + {% else %}
{{ value }}{{ value }} {% if value is mapping %} @@ -509,24 +516,47 @@ font-weight: 700; } - .status-passed { + .status-passed, + .status-success, + .status-ok { color: var(--success-color); font-weight: 700; + background-color: rgba(16, 124, 16, 0.1); + padding: 4px 8px; + border-radius: 4px; } - .status-failed { + .status-failed, + .status-error { color: var(--error-color); font-weight: 700; + background-color: rgba(209, 52, 56, 0.1); + padding: 4px 8px; + border-radius: 4px; } .status-warning { color: var(--warning-color); font-weight: 700; + background-color: rgba(255, 140, 0, 0.1); + padding: 4px 8px; + border-radius: 4px; } .status-info { color: var(--info-color); font-weight: 700; + background-color: rgba(0, 120, 215, 0.1); + padding: 4px 8px; + border-radius: 4px; + } + + .status-skipped { + color: #6c757d; + font-weight: 700; + background-color: rgba(108, 117, 125, 0.1); + padding: 4px 8px; + border-radius: 4px; } .summary-box { @@ -1476,13 +1506,19 @@