diff --git a/.github/dependabot.yml b/.github/dependabot.yml index d98e54a1..ab92e455 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -6,8 +6,14 @@ updates: directory: / schedule: interval: daily + ignore: + - dependency-name: "*" + update-types: ["version-update:semver-minor"] - package-ecosystem: pip directory: / schedule: interval: daily + ignore: + - dependency-name: "*" + update-types: ["version-update:semver-minor"] diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 33ac2a07..aa94aff1 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -46,14 +46,14 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Initialize CodeQL - uses: github/codeql-action/init@d68b2d4edb4189fd2a5366ac14e72027bd4b37dd # v3.28.2 + uses: github/codeql-action/init@45775bd8235c68ba998cffa5171334d58593da47 # v3.28.15 with: languages: ${{ matrix.language }} - name: Autobuild - uses: github/codeql-action/autobuild@d68b2d4edb4189fd2a5366ac14e72027bd4b37dd # v3.28.2 + uses: github/codeql-action/autobuild@45775bd8235c68ba998cffa5171334d58593da47 # v3.28.15 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@d68b2d4edb4189fd2a5366ac14e72027bd4b37dd # v3.28.2 + uses: github/codeql-action/analyze@45775bd8235c68ba998cffa5171334d58593da47 # v3.28.15 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/ossf-scoreboard.yml b/.github/workflows/ossf-scoreboard.yml index 537a8e55..25c66aad 100644 --- a/.github/workflows/ossf-scoreboard.yml +++ b/.github/workflows/ossf-scoreboard.yml @@ -50,6 +50,6 @@ jobs: retention-days: 5 - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@d68b2d4edb4189fd2a5366ac14e72027bd4b37dd # v3.28.2 + uses: github/codeql-action/upload-sarif@45775bd8235c68ba998cffa5171334d58593da47 # v3.28.15 with: sarif_file: results.sarif diff --git a/.github/workflows/trivy.yml b/.github/workflows/trivy.yml index 54b667cb..8e41b4b7 100644 --- a/.github/workflows/trivy.yml +++ b/.github/workflows/trivy.yml @@ -36,7 +36,7 @@ jobs: output: report-fs.sarif - name: Upload Trivy report (fs) GitHub Security - uses: github/codeql-action/upload-sarif@9e8d0789d4a0fa9ceb6b1738f7e269594bdd67f0 # v3.28.9 + uses: github/codeql-action/upload-sarif@45775bd8235c68ba998cffa5171334d58593da47 # v3.28.15 with: sarif_file: report-fs.sarif category: 'fs' diff --git a/README.md b/README.md index da77b299..a78a2060 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,13 @@ # SAP Testing Automation Framework +![SAP Testing Automation Framework](./docs/images/sap-automation-qa.svg) + [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) [![Azure](https://img.shields.io/badge/Microsoft-SAP%20on%20Azure-0078D4?logo=microsoft)](https://docs.microsoft.com/azure/sap) [![Python Coverage](https://img.shields.io/badge/Code%20Coverage-85%25-success?logo=python&logoColor=white)](https://github.com/Azure/sap-automation-qa/actions/workflows/github-actions-code-coverage.yml) [![Ansible Lint](https://github.com/Azure/sap-automation-qa/actions/workflows/github-actions-ansible-lint.yml/badge.svg)](https://github.com/Azure/sap-automation-qa/actions/workflows/github-actions-ansible-lint.yml) [![OpenSSF Scorecard](https://img.shields.io/ossf-scorecard/github.com/Azure/sap-automation-qa)](https://scorecard.dev/viewer/?uri=github.com/Azure/sap-automation-qa) +[![GitHub Issues](https://img.shields.io/github/issues/Azure/sap-automation-qa)](https://github.com/Azure/sap-automation-qa/issues) ## 🔍 Overview @@ -12,6 +15,8 @@ The SAP Testing Automation Framework is an open-source orchestration tool design > **NOTE**: This repository is currently in private preview and is intended for testing and feedback purposes. As this is an early release, it is not yet production-ready, and breaking changes can be introduced at any time. +![SAP Testing Automation Framework](./docs/images/sap-testing-automation-framework.png) + ## Supported Configuration Matrix The following SAP components are supported in a two-node Pacemaker cluster running on SUSE Linux Enterprise Server (SLES) or Red Hat Enterprise Linux (RHEL): diff --git a/docs/HIGH_AVAILABILITY.md b/docs/HIGH_AVAILABILITY.md index 3a51cfa0..911a5a4a 100644 --- a/docs/HIGH_AVAILABILITY.md +++ b/docs/HIGH_AVAILABILITY.md @@ -20,6 +20,7 @@ Currently SAP Testing Automation Framework is supported for below Linux distros | Component | Type | Cluster Type | Storage | |-----------|------|--------------|---------| | SAP Central Services | ENSA1 or ENSA2 | Azure Fencing Agent | Azure Files or ANF | +| SAP Central Services | ENSA1 or ENSA2 | ISCSI (SBD device) | Azure Files or ANF | | SAP HANA | Scale-up | Azure Fencing Agent | Azure Managed Disk or ANF | | SAP HANA | Scale-up | ISCSI (SBD device) | Azure Managed Disk or ANF | @@ -36,6 +37,15 @@ To run the SAP Testing Automation Framework, you must meet certain prerequisites - [SAP HANA high availability on Azure Virtual Machine](https://learn.microsoft.com/azure/sap/workloads/sap-high-availability-guide-start). - [SAP Netweaver high availability on Azure Virtual Machine](https://learn.microsoft.com/azure/sap/workloads/sap-high-availability-guide-start) +### Enabling Cluster Services on Boot + +Before executing the tests, ensure that the cluster services are configured to start automatically during system boot. Run the following command on one of the cluster nodes to enable this setting. The `--all` option ensures that the cluster services are enabled on all nodes within the cluster. + +```bash +crm cluster enable --all # for SUSE virtual machines +pcs cluster enable --all # for RedHat virtual machine +``` + ### Management server The SAP Testing Automation Framework requires a jumpbox or management server with the following setup: @@ -85,14 +95,17 @@ To set up your enviroment in management server, follow these steps: Ensure you are logged into the Ubuntu management server that is connected to the SAP system's virtual network. -1.2. **Clone the repository**: +1.2. **Fork and clone the repository**: ```bash # sudo to root sudo su - -# Clone the repository -git clone https://github.com/Azure/sap-automation-qa.git +# First, visit https://github.com/Azure/sap-automation-qa in your browser +# Click the "Fork" button in the top-right corner to create a fork in your GitHub account + +# Clone your fork of the repository (replace GITHUB-USERNAME with your GitHub username) +git clone https://github.com/GITHUB-USERNAME/sap-automation-qa.git cd sap-automation-qa ``` @@ -271,6 +284,51 @@ Test results and logs can be found in: cd WORKSPACES/SYSTEM//quality_assurance/ ``` +## Update the framework + +To ensure you have the latest features and fixes, it's important to keep your fork of the SAP Testing Automation Framework up to date. You can do this by pulling the latest changes from the original repository into your fork. + +### Steps to update your fork + +1. **Ensure you have the upstream repository configured**: + + ```bash + # Check if you already have the upstream remote + git remote -v + + # If you don't see an 'upstream' entry, add it + git remote add upstream https://github.com/Azure/sap-automation-qa.git + ``` + +2. **Fetch the latest changes from the upstream repository**: + + ```bash + git fetch upstream + ``` + +3. **Ensure you're on your main branch**: + + ```bash + git checkout main + ``` + +4. **Merge the changes from upstream into your local fork**: + + ```bash + git merge upstream/main + ``` + +5. **Push the updated code to your GitHub fork**: + + ```bash + git push origin main + ``` + +This process will update your fork with all the latest features, bug fixes, and improvements from the original SAP Testing Automation Framework repository. + +> [!NOTE] +> If you've made local changes to your fork, you might encounter merge conflicts during step 4. In that case, you'll need to resolve these conflicts before proceeding with the push in step 5. + ## Additional Resources - [Azure SAP Documentation](https://docs.microsoft.com/azure/sap) diff --git a/docs/images/sap-automation-qa.svg b/docs/images/sap-automation-qa.svg new file mode 100644 index 00000000..40df4477 --- /dev/null +++ b/docs/images/sap-automation-qa.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/images/sap-testing-automation-framework.png b/docs/images/sap-testing-automation-framework.png new file mode 100644 index 00000000..19b4922f Binary files /dev/null and b/docs/images/sap-testing-automation-framework.png differ diff --git a/requirements.in b/requirements.in new file mode 100644 index 00000000..7fff8760 --- /dev/null +++ b/requirements.in @@ -0,0 +1,35 @@ +# Ansible packages +ansible-core +ansible-lint +ansible-runner + +# Azure packages +azure-identity +azure-kusto-data +azure-kusto-ingest +azure-mgmt-network +azure-storage-blob +azure-storage-queue + +# Development tools +black +pylint +coverage + +# Testing packages +pytest +pytest-cov +pytest-mock + +# Data processing +numpy +pandas + +# Core utilities +Jinja2 +PyYAML +requests + +# CLI tools +click +rich diff --git a/requirements.txt b/requirements.txt index 80285b1c..299a8412 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,83 +1,258 @@ -ansible-compat==24.6.1 -ansible-core==2.17.7 -ansible-lint==24.6.1 -ansible-runner==2.4.0 -astroid==2.9.0 -attrs==25.1.0 +# +# This file is autogenerated by pip-compile with Python 3.10 +# by the following command: +# +# pip-compile requirements.in +# +ansible-compat==25.1.5 + # via ansible-lint +ansible-core==2.17.10 + # via + # -r requirements.in + # ansible-compat + # ansible-lint +ansible-lint==25.2.1 + # via -r requirements.in +ansible-runner==2.4.1 + # via -r requirements.in +astroid==3.3.9 + # via pylint +attrs==25.3.0 + # via + # jsonschema + # referencing azure-common==1.1.28 -azure-core==1.32.0 -azure-identity==1.17.1 -azure-kusto-data==4.5.1 -azure-kusto-ingest==4.5.1 + # via azure-mgmt-network +azure-core==1.33.0 + # via + # azure-identity + # azure-kusto-data + # azure-mgmt-core + # azure-storage-blob + # azure-storage-queue +azure-identity==1.21.0 + # via + # -r requirements.in + # azure-kusto-data +azure-kusto-data==5.0.2 + # via + # -r requirements.in + # azure-kusto-ingest +azure-kusto-ingest==5.0.2 + # via -r requirements.in azure-mgmt-core==1.5.0 + # via azure-mgmt-network azure-mgmt-network==28.1.0 -azure-storage-blob==12.24.1 + # via -r requirements.in +azure-storage-blob==12.25.1 + # via + # -r requirements.in + # azure-kusto-ingest azure-storage-queue==12.12.0 + # via + # -r requirements.in + # azure-kusto-ingest black==25.1.0 + # via + # -r requirements.in + # ansible-lint bracex==2.5.post1 + # via wcmatch certifi==2025.1.31 + # via requests cffi==1.17.1 + # via cryptography charset-normalizer==3.4.1 + # via requests click==8.1.8 -coverage==7.6.12 -cryptography==44.0.1 + # via + # -r requirements.in + # black +coverage[toml]==7.8.0 + # via + # -r requirements.in + # pytest-cov +cryptography==44.0.2 + # via + # ansible-core + # azure-identity + # azure-storage-blob + # azure-storage-queue + # msal + # pyjwt +dill==0.3.9 + # via pylint exceptiongroup==1.2.2 -filelock==3.17.0 + # via pytest +filelock==3.18.0 + # via ansible-lint idna==3.10 + # via requests ijson==3.3.0 -importlib_metadata==8.6.1 -iniconfig==2.0.0 + # via azure-kusto-data +importlib-metadata==8.6.1 + # via ansible-lint +iniconfig==2.1.0 + # via pytest isodate==0.7.2 -isort==5.13.2 -Jinja2==3.1.6 + # via + # azure-mgmt-network + # azure-storage-blob + # azure-storage-queue +isort==6.0.1 + # via pylint +jinja2==3.1.6 + # via + # -r requirements.in + # ansible-core jsonschema==4.23.0 + # via + # ansible-compat + # ansible-lint jsonschema-specifications==2024.10.1 -lazy-object-proxy==1.10.0 + # via jsonschema lockfile==0.12.2 + # via python-daemon markdown-it-py==3.0.0 -MarkupSafe==3.0.2 -mccabe==0.6.1 + # via rich +markupsafe==3.0.2 + # via jinja2 +mccabe==0.7.0 + # via pylint mdurl==0.1.2 -mock==5.1.0 -msal==1.31.1 -msal-extensions==1.2.0 + # via markdown-it-py +msal==1.32.0 + # via + # azure-identity + # azure-kusto-data + # msal-extensions +msal-extensions==1.3.1 + # via azure-identity mypy-extensions==1.0.0 -numpy==2.2.2 + # via black +numpy==2.2.4 + # via + # -r requirements.in + # pandas packaging==24.2 + # via + # ansible-compat + # ansible-core + # ansible-lint + # ansible-runner + # black + # pytest pandas==2.2.3 + # via -r requirements.in pathspec==0.12.1 + # via + # ansible-lint + # black + # yamllint pexpect==4.9.0 -platformdirs==4.3.6 + # via ansible-runner +platformdirs==4.3.7 + # via + # black + # pylint pluggy==1.5.0 -portalocker==2.10.1 + # via pytest ptyprocess==0.7.0 + # via pexpect pycparser==2.22 -Pygments==2.19.1 -PyJWT==2.10.1 -pylint==2.12.2 -pytest==8.3.4 -pytest-cov==6.0.0 + # via cffi +pygments==2.19.1 + # via rich +pyjwt[crypto]==2.10.1 + # via + # msal + # pyjwt +pylint==3.3.6 + # via -r requirements.in +pytest==8.3.5 + # via + # -r requirements.in + # pytest-cov + # pytest-mock +pytest-cov==6.1.1 + # via -r requirements.in pytest-mock==3.14.0 + # via -r requirements.in python-daemon==3.1.2 + # via ansible-runner python-dateutil==2.9.0.post0 -pytz==2025.1 -PyYAML==6.0.2 + # via + # azure-kusto-data + # pandas +pytz==2025.2 + # via pandas +pyyaml==6.0.2 + # via + # -r requirements.in + # ansible-compat + # ansible-core + # ansible-lint + # ansible-runner + # yamllint referencing==0.36.2 + # via + # ansible-lint + # jsonschema + # jsonschema-specifications requests==2.32.3 + # via + # -r requirements.in + # azure-core + # azure-kusto-data + # msal resolvelib==1.0.1 -rich==13.9.4 -rpds-py==0.22.3 -ruamel.yaml==0.18.10 -ruamel.yaml.clib==0.2.12 + # via ansible-core +rich==14.0.0 + # via -r requirements.in +rpds-py==0.24.0 + # via + # jsonschema + # referencing +ruamel-yaml==0.18.10 + # via ansible-lint +ruamel-yaml-clib==0.2.12 + # via ruamel-yaml six==1.17.0 + # via + # azure-core + # python-dateutil subprocess-tee==0.4.2 -tenacity==9.0.0 -toml==0.10.2 + # via + # ansible-compat + # ansible-lint +tenacity==9.1.2 + # via azure-kusto-ingest tomli==2.2.1 -typing_extensions==4.12.2 -tzdata==2025.1 -urllib3==2.2.2 + # via + # black + # coverage + # pylint + # pytest +tomlkit==0.13.2 + # via pylint +typing-extensions==4.13.2 + # via + # astroid + # azure-core + # azure-identity + # azure-mgmt-network + # azure-storage-blob + # azure-storage-queue + # black + # referencing + # rich +tzdata==2025.2 + # via pandas +urllib3==2.4.0 + # via requests wcmatch==10.0 -wrapt==1.13.3 -yamllint==1.35.1 + # via ansible-lint +yamllint==1.37.0 + # via ansible-lint zipp==3.21.0 + # via importlib-metadata diff --git a/src/modules/filesystem_freeze.py b/src/modules/filesystem_freeze.py index 8a2cbfb6..6ec9f25a 100644 --- a/src/modules/filesystem_freeze.py +++ b/src/modules/filesystem_freeze.py @@ -84,6 +84,16 @@ class FileSystemFreeze(SapAutomationQA): Class to run the test case when the filesystem is frozen. """ + def __init__(self, database_sid: str) -> None: + """ + Initialize the FileSystemFreeze class. + + :param database_sid: The database SID. + :type database_sid: str + """ + super().__init__() + self.database_sid = database_sid + def _find_filesystem(self) -> str: """ Find the filesystem mounted on /hana/shared. @@ -95,7 +105,10 @@ def _find_filesystem(self) -> str: with open("/proc/mounts", "r", encoding="utf-8") as mounts_file: for line in mounts_file: parts = line.split() - if len(parts) > 1 and parts[1] == "/hana/shared": + if len(parts) > 1 and parts[1] in [ + "/hana/shared", + f"/hana/shared/{self.database_sid}", + ]: return parts[0] except FileNotFoundError as ex: self.handle_error(ex) @@ -143,12 +156,13 @@ def run_module() -> None: """ module_args = dict( nfs_provider=dict(type="str", required=True), + database_sid=dict(type="str", required=True), ) module = AnsibleModule(argument_spec=module_args, supports_check_mode=True) if module.params["nfs_provider"] != "ANF": module.exit_json(changed=False, message="The NFS provider is not ANF. Skipping") - formatter = FileSystemFreeze() + formatter = FileSystemFreeze(database_sid=module.params["database_sid"]) result = formatter.run() module.exit_json(**result) diff --git a/src/modules/get_pcmk_properties_db.py b/src/modules/get_pcmk_properties_db.py index f394b5fb..cf715a84 100644 --- a/src/modules/get_pcmk_properties_db.py +++ b/src/modules/get_pcmk_properties_db.py @@ -477,6 +477,9 @@ def _parse_resource(self, element, category): if operations is not None: for operation in operations.findall(".//op"): for op_type in ["timeout", "interval"]: + value = operation.get(op_type, "") + if value.endswith("s"): + value = value[:-1] parameters.append( self._create_parameter( category=category, @@ -484,7 +487,7 @@ def _parse_resource(self, element, category): id=operation.get("id", ""), name=op_type, op_name=operation.get("name", ""), - value=operation.get(op_type, ""), + value=value, ) ) return parameters diff --git a/src/modules/get_pcmk_properties_scs.py b/src/modules/get_pcmk_properties_scs.py index 08092f18..1a2965d8 100644 --- a/src/modules/get_pcmk_properties_scs.py +++ b/src/modules/get_pcmk_properties_scs.py @@ -367,6 +367,9 @@ def _parse_resource(self, element, category): if operations is not None: for operation in operations.findall(".//op"): for op_type in ["timeout", "interval"]: + value = operation.get(op_type, "") + if value.endswith("s"): + value = value[:-1] parameters.append( self._create_parameter( category=category, @@ -374,7 +377,7 @@ def _parse_resource(self, element, category): id=operation.get("id", ""), name=op_type, op_name=operation.get("name", ""), - value=operation.get(op_type, ""), + value=value, ) ) return parameters diff --git a/src/roles/ha_db_hana/tasks/block-network.yml b/src/roles/ha_db_hana/tasks/block-network.yml index 8e7cb472..a20075a7 100644 --- a/src/roles/ha_db_hana/tasks/block-network.yml +++ b/src/roles/ha_db_hana/tasks/block-network.yml @@ -52,38 +52,34 @@ - name: "Test Execution: Check node status on primary and secondary" block: - - name: "Test Execution: Check primary node connectivity from controller" - when: ansible_hostname == cluster_status_pre.primary_node + - name: "Test Execution: Check node connectivity from controller" delegate_to: localhost ansible.builtin.shell: | - for i in $(seq 1 20); do + for i in $(seq 1 30); do if ! ping -c 1 -w 1 {{ ansible_host }}; then echo "Connection failed on attempt $i" exit 1 fi sleep 1 done - register: primary_status - ignore_errors: true - - - name: "Test Execution: Check secondary node connectivity from controller" - when: ansible_hostname == cluster_status_pre.secondary_node - delegate_to: localhost - ansible.builtin.shell: | - for i in $(seq 1 20); do - if ! ping -c 1 -w 1 {{ ansible_host }}; then - echo "Connection failed on attempt $i" - exit 1 - fi - sleep 1 - done - register: secondary_status + register: node_status ignore_errors: true - name: "Set Node Status Facts" ansible.builtin.set_fact: - primary_node_down: "{{ hostvars[cluster_status_pre.primary_node].primary_status is failed }}" - secondary_node_down: "{{ hostvars[cluster_status_pre.secondary_node].secondary_status is failed }}" + primary_node_down: "{{ hostvars[cluster_status_pre.primary_node].node_status is failed }}" + secondary_node_down: "{{ hostvars[cluster_status_pre.secondary_node].node_status is failed }}" + + - name: "Fail if both nodes are unavailable" + ansible.builtin.fail: + msg: | + "Error: Both primary and secondary nodes are unreachable. + This may be caused by a fence race condition triggered during the block network + test case execution, where both nodes potentially fenced each other. + Please verify if the priority-fencing-delay cluster property is configured. + If not, refer to the SAP on Azure high availability documentation for + instructions on how to configure it." + when: primary_node_down and secondary_node_down - name: "Test Execution: Check node status on primary and secondary" when: @@ -196,7 +192,7 @@ # | Post Validations | # +--------------------------------------------------------------------------*/ - name: "Post Validations Tasks" - ansible.builtin.include_tasks: "roles/misc/tasks/post-validations-db.yml" + ansible.builtin.include_tasks: "roles/misc/tasks/post-validations.yml" rescue: - name: "Rescue operation" @@ -217,4 +213,4 @@ } - name: "Post Validations Tasks" - ansible.builtin.include_tasks: "roles/misc/tasks/post-validations-db.yml" + ansible.builtin.include_tasks: "roles/misc/tasks/post-validations.yml" diff --git a/src/roles/ha_db_hana/tasks/files/constants.yaml b/src/roles/ha_db_hana/tasks/files/constants.yaml index 76281302..fd89e4fe 100644 --- a/src/roles/ha_db_hana/tasks/files/constants.yaml +++ b/src/roles/ha_db_hana/tasks/files/constants.yaml @@ -128,8 +128,8 @@ RESOURCE_DEFAULTS: target-role: "Started" operations: monitor: - interval: "10s" - timeout: "20s" + interval: "10" + timeout: "20" filesystem: meta_attributes: @@ -187,17 +187,17 @@ RESOURCE_DEFAULTS: interval: "10" timeout: "600" start: - interval: "0s" + interval: "0" timeout: "600" stop: - interval: "0s" + interval: "0" timeout: "300" methods: timeout: "5" - interval: "0s" + interval: "0" reload: timeout: "5" - interval: "0s" + interval: "0" hana: meta_attributes: @@ -229,14 +229,14 @@ RESOURCE_DEFAULTS: target-role: "Started" operations: monitor: - interval: "10s" - timeout: "20s" + interval: "10" + timeout: "20" start: - interval: "0s" - timeout: "20s" + interval: "0" + timeout: "20" stop: - interval: "0s" - timeout: "20s" + interval: "0" + timeout: "20" filesystem: meta_attributes: @@ -244,28 +244,28 @@ RESOURCE_DEFAULTS: interleave: "true" operations: monitor: - interval: "20s" - timeout: "120s" + interval: "20" + timeout: "120" start: - interval: "0s" - timeout: "60s" + interval: "0" + timeout: "60" stop: - interval: "0s" - timeout: "60s" + interval: "0" + timeout: "60" azurelb: meta_attributes: resource-stickiness: "0" operations: monitor: - interval: "10s" - timeout: "20s" + interval: "10" + timeout: "20" start: - interval: "0s" - timeout: "20s" + interval: "0" + timeout: "20" stop: - interval: "0s" - timeout: "20s" + interval: "0" + timeout: "20" # === OS Parameters === diff --git a/src/roles/ha_db_hana/tasks/fs-freeze.yml b/src/roles/ha_db_hana/tasks/fs-freeze.yml index c42855bd..8787083c 100644 --- a/src/roles/ha_db_hana/tasks/fs-freeze.yml +++ b/src/roles/ha_db_hana/tasks/fs-freeze.yml @@ -40,6 +40,7 @@ become: true filesystem_freeze: nfs_provider: "{{ NFS_provider }}" + database_sid: "{{ db_sid | upper }}" register: freeze_fs_results - name: "Test Execution: Freeze File System on Primary Node init" @@ -103,7 +104,7 @@ # | Post Validations | # +--------------------------------------------------------------------------*/ - name: "Post Validations Tasks" - ansible.builtin.include_tasks: "roles/misc/tasks/post-validations-db.yml" + ansible.builtin.include_tasks: "roles/misc/tasks/post-validations.yml" rescue: - name: "Rescue operation" @@ -124,4 +125,4 @@ } - name: "Post Validations Tasks" - ansible.builtin.include_tasks: "roles/misc/tasks/post-validations-db.yml" + ansible.builtin.include_tasks: "roles/misc/tasks/post-validations.yml" diff --git a/src/roles/ha_db_hana/tasks/primary-crash-index.yml b/src/roles/ha_db_hana/tasks/primary-crash-index.yml index d1062c17..792f9438 100644 --- a/src/roles/ha_db_hana/tasks/primary-crash-index.yml +++ b/src/roles/ha_db_hana/tasks/primary-crash-index.yml @@ -145,7 +145,7 @@ # | Post Validations | # +--------------------------------------------------------------------------*/ - name: "Post Validations Tasks" - ansible.builtin.include_tasks: "roles/misc/tasks/post-validations-db.yml" + ansible.builtin.include_tasks: "roles/misc/tasks/post-validations.yml" rescue: - name: "Rescue operation" @@ -166,4 +166,4 @@ } - name: "Post Validations Tasks" - ansible.builtin.include_tasks: "roles/misc/tasks/post-validations-db.yml" + ansible.builtin.include_tasks: "roles/misc/tasks/post-validations.yml" diff --git a/src/roles/ha_db_hana/tasks/primary-echo-b.yml b/src/roles/ha_db_hana/tasks/primary-echo-b.yml index b66778d6..66d18924 100644 --- a/src/roles/ha_db_hana/tasks/primary-echo-b.yml +++ b/src/roles/ha_db_hana/tasks/primary-echo-b.yml @@ -135,7 +135,7 @@ # | Post Validations | # +--------------------------------------------------------------------------*/ - name: "Post Validations Tasks" - ansible.builtin.include_tasks: "roles/misc/tasks/post-validations-db.yml" + ansible.builtin.include_tasks: "roles/misc/tasks/post-validations.yml" rescue: - name: "Rescue operation" @@ -156,4 +156,4 @@ } - name: "Post Validations Tasks" - ansible.builtin.include_tasks: "roles/misc/tasks/post-validations-db.yml" + ansible.builtin.include_tasks: "roles/misc/tasks/post-validations.yml" diff --git a/src/roles/ha_db_hana/tasks/primary-node-crash.yml b/src/roles/ha_db_hana/tasks/primary-node-crash.yml index 60adaa37..73076a7f 100644 --- a/src/roles/ha_db_hana/tasks/primary-node-crash.yml +++ b/src/roles/ha_db_hana/tasks/primary-node-crash.yml @@ -117,7 +117,7 @@ # | Post Validations | # +--------------------------------------------------------------------------*/ - name: "Post Validations Tasks" - ansible.builtin.include_tasks: "roles/misc/tasks/post-validations-db.yml" + ansible.builtin.include_tasks: "roles/misc/tasks/post-validations.yml" rescue: - name: "Rescue operation" @@ -138,4 +138,4 @@ } - name: "Post Validations Tasks" - ansible.builtin.include_tasks: "roles/misc/tasks/post-validations-db.yml" + ansible.builtin.include_tasks: "roles/misc/tasks/post-validations.yml" diff --git a/src/roles/ha_db_hana/tasks/primary-node-kill.yml b/src/roles/ha_db_hana/tasks/primary-node-kill.yml index 4cc6844d..9343474c 100644 --- a/src/roles/ha_db_hana/tasks/primary-node-kill.yml +++ b/src/roles/ha_db_hana/tasks/primary-node-kill.yml @@ -130,7 +130,7 @@ # | Post Validations | # +--------------------------------------------------------------------------*/ - name: "Post Validations Tasks" - ansible.builtin.include_tasks: "roles/misc/tasks/post-validations-db.yml" + ansible.builtin.include_tasks: "roles/misc/tasks/post-validations.yml" rescue: - name: "Rescue operation" @@ -151,4 +151,4 @@ } - name: "Post Validations Tasks" - ansible.builtin.include_tasks: "roles/misc/tasks/post-validations-db.yml" + ansible.builtin.include_tasks: "roles/misc/tasks/post-validations.yml" diff --git a/src/roles/ha_db_hana/tasks/resource-migration.yml b/src/roles/ha_db_hana/tasks/resource-migration.yml index c8c58529..4cc0f756 100644 --- a/src/roles/ha_db_hana/tasks/resource-migration.yml +++ b/src/roles/ha_db_hana/tasks/resource-migration.yml @@ -128,7 +128,7 @@ # | Post Validations | # +--------------------------------------------------------------------------*/ - name: "Post Validations Tasks" - ansible.builtin.include_tasks: "roles/misc/tasks/post-validations-db.yml" + ansible.builtin.include_tasks: "roles/misc/tasks/post-validations.yml" rescue: - name: "Rescue operation" @@ -149,4 +149,4 @@ } - name: "Post Validations Tasks" - ansible.builtin.include_tasks: "roles/misc/tasks/post-validations-db.yml" + ansible.builtin.include_tasks: "roles/misc/tasks/post-validations.yml" diff --git a/src/roles/ha_db_hana/tasks/sbd-fencing.yml b/src/roles/ha_db_hana/tasks/sbd-fencing.yml index 3fdc88cd..1456f900 100644 --- a/src/roles/ha_db_hana/tasks/sbd-fencing.yml +++ b/src/roles/ha_db_hana/tasks/sbd-fencing.yml @@ -103,7 +103,7 @@ # | Post Validations | # +--------------------------------------------------------------------------*/ - name: "Post Validations Tasks" - ansible.builtin.include_tasks: "roles/misc/tasks/post-validations-db.yml" + ansible.builtin.include_tasks: "roles/misc/tasks/post-validations.yml" rescue: - name: "Rescue operation" @@ -124,4 +124,4 @@ } - name: "Post Validations Tasks" - ansible.builtin.include_tasks: "roles/misc/tasks/post-validations-db.yml" + ansible.builtin.include_tasks: "roles/misc/tasks/post-validations.yml" diff --git a/src/roles/ha_db_hana/tasks/secondary-crash-index.yml b/src/roles/ha_db_hana/tasks/secondary-crash-index.yml index ae4feaef..fa560092 100644 --- a/src/roles/ha_db_hana/tasks/secondary-crash-index.yml +++ b/src/roles/ha_db_hana/tasks/secondary-crash-index.yml @@ -106,7 +106,7 @@ # | Post Validations | # +--------------------------------------------------------------------------*/ - name: "Post Validations Tasks" - ansible.builtin.include_tasks: "roles/misc/tasks/post-validations-db.yml" + ansible.builtin.include_tasks: "roles/misc/tasks/post-validations.yml" rescue: - name: "Rescue operation" @@ -127,4 +127,4 @@ } - name: "Post Validations Tasks" - ansible.builtin.include_tasks: "roles/misc/tasks/post-validations-db.yml" + ansible.builtin.include_tasks: "roles/misc/tasks/post-validations.yml" diff --git a/src/roles/ha_db_hana/tasks/secondary-echo-b.yml b/src/roles/ha_db_hana/tasks/secondary-echo-b.yml index 93037111..56c8d15f 100644 --- a/src/roles/ha_db_hana/tasks/secondary-echo-b.yml +++ b/src/roles/ha_db_hana/tasks/secondary-echo-b.yml @@ -100,7 +100,7 @@ # | Post Validations | # +--------------------------------------------------------------------------*/ - name: "Post Validations Tasks" - ansible.builtin.include_tasks: "roles/misc/tasks/post-validations-db.yml" + ansible.builtin.include_tasks: "roles/misc/tasks/post-validations.yml" rescue: - name: "Rescue operation" @@ -121,4 +121,4 @@ } - name: "Post Validations Tasks" - ansible.builtin.include_tasks: "roles/misc/tasks/post-validations-db.yml" + ansible.builtin.include_tasks: "roles/misc/tasks/post-validations.yml" diff --git a/src/roles/ha_db_hana/tasks/secondary-node-kill.yml b/src/roles/ha_db_hana/tasks/secondary-node-kill.yml index 67d5d6e2..e595ece5 100644 --- a/src/roles/ha_db_hana/tasks/secondary-node-kill.yml +++ b/src/roles/ha_db_hana/tasks/secondary-node-kill.yml @@ -98,7 +98,7 @@ # | Post Validations | # +--------------------------------------------------------------------------*/ - name: "Post Validations Tasks" - ansible.builtin.include_tasks: "roles/misc/tasks/post-validations-db.yml" + ansible.builtin.include_tasks: "roles/misc/tasks/post-validations.yml" rescue: - name: "Rescue operation" @@ -119,4 +119,4 @@ } - name: "Post Validations Tasks" - ansible.builtin.include_tasks: "roles/misc/tasks/post-validations-db.yml" + ansible.builtin.include_tasks: "roles/misc/tasks/post-validations.yml" diff --git a/src/roles/ha_scs/tasks/ascs-migration.yml b/src/roles/ha_scs/tasks/ascs-migration.yml index 6fca5721..4715674d 100644 --- a/src/roles/ha_scs/tasks/ascs-migration.yml +++ b/src/roles/ha_scs/tasks/ascs-migration.yml @@ -85,7 +85,7 @@ # | Post Validations | # +--------------------------------------------------------------------------*/ - name: "Post Validations Tasks" - ansible.builtin.include_tasks: "roles/misc/tasks/post-validations-scs.yml" + ansible.builtin.include_tasks: "roles/misc/tasks/post-validations.yml" rescue: - name: "Rescue operation" @@ -103,4 +103,4 @@ } - name: "Post Validations Tasks" - ansible.builtin.include_tasks: "roles/misc/tasks/post-validations-scs.yml" + ansible.builtin.include_tasks: "roles/misc/tasks/post-validations.yml" diff --git a/src/roles/ha_scs/tasks/ascs-node-crash.yml b/src/roles/ha_scs/tasks/ascs-node-crash.yml index c25bd694..8007daca 100644 --- a/src/roles/ha_scs/tasks/ascs-node-crash.yml +++ b/src/roles/ha_scs/tasks/ascs-node-crash.yml @@ -86,7 +86,7 @@ # | Post Validations | # +--------------------------------------------------------------------------*/ - name: "Post Validations Tasks" - ansible.builtin.include_tasks: "roles/misc/tasks/post-validations-scs.yml" + ansible.builtin.include_tasks: "roles/misc/tasks/post-validations.yml" rescue: - name: "Rescue operation" @@ -104,4 +104,4 @@ } - name: "Post Validations Tasks" - ansible.builtin.include_tasks: "roles/misc/tasks/post-validations-scs.yml" + ansible.builtin.include_tasks: "roles/misc/tasks/post-validations.yml" diff --git a/src/roles/ha_scs/tasks/files/constants.yaml b/src/roles/ha_scs/tasks/files/constants.yaml index e5d287ca..ce933c3a 100644 --- a/src/roles/ha_scs/tasks/files/constants.yaml +++ b/src/roles/ha_scs/tasks/files/constants.yaml @@ -76,11 +76,11 @@ RESOURCE_DEFAULTS: interval: "3600" timeout: "120" start: - interval: "0s" - timeout: "20s" + interval: "0" + timeout: "20" stop: - interval: "0s" - timeout: "20s" + interval: "0" + timeout: "20" ascs: instance_attributes: @@ -94,17 +94,17 @@ RESOURCE_DEFAULTS: interval: "11" timeout: "60" start: - interval: "0s" - timeout: "180s" + interval: "0" + timeout: "180" stop: - interval: "0s" - timeout: "240s" + interval: "0" + timeout: "240" promote: - interval: "0s" - timeout: "320s" + interval: "0" + timeout: "320" demote: - interval: "0s" - timeout: "320s" + interval: "0" + timeout: "320" ers: instance_attributes: @@ -119,45 +119,45 @@ RESOURCE_DEFAULTS: interval: "11" timeout: "60" start: - interval: "0s" - timeout: "180s" + interval: "0" + timeout: "180" stop: - interval: "0s" - timeout: "240s" + interval: "0" + timeout: "240" promote: - interval: "0s" - timeout: "320s" + interval: "0" + timeout: "320" demote: - interval: "0s" - timeout: "320s" + interval: "0" + timeout: "320" ipaddr: meta_attributes: target-role: "Started" operations: monitor: - interval: "10s" - timeout: "20s" + interval: "10" + timeout: "20" start: - interval: "0s" - timeout: "20s" + interval: "0" + timeout: "20" stop: - interval: "0s" - timeout: "20s" + interval: "0" + timeout: "20" azurelb: meta_attributes: resource-stickiness: "0" operations: monitor: - interval: "10s" - timeout: "20s" + interval: "10" + timeout: "20" start: - interval: "0s" - timeout: "20s" + interval: "0" + timeout: "20" stop: - interval: "0s" - timeout: "20s" + interval: "0" + timeout: "20" azureevents: meta_attributes: @@ -165,14 +165,14 @@ RESOURCE_DEFAULTS: failure-timeout: "120s" operations: monitor: - interval: "10s" - timeout: "240s" + interval: "10" + timeout: "240" start: - interval: "0s" - timeout: "10s" + interval: "0" + timeout: "10" stop: - interval: "0s" - timeout: "10s" + interval: "0" + timeout: "10" # === OS Parameters === # Run command as root. Format of command is: "parent_key child_key" diff --git a/src/roles/misc/tasks/cluster-report.yml b/src/roles/misc/tasks/cluster-report.yml index 02bf25f5..a7d844bd 100644 --- a/src/roles/misc/tasks/cluster-report.yml +++ b/src/roles/misc/tasks/cluster-report.yml @@ -9,7 +9,7 @@ become: true get_cluster_status_db: operation_step: "cluster_report_collection" - database_sid: "{{ db_sid | lower }}" + database_sid: "{{ db_sid | lower | default('') }}" ansible_os_family: "{{ ansible_os_family | upper }}" register: cluster_status failed_when: cluster_status.primary_node == "" @@ -23,6 +23,7 @@ - name: "Cluster report from the HA cluster" ansible.builtin.command: "{{ commands | selectattr('name', 'equalto', 'crm_report_cmd') | map(attribute=(ansible_os_family | upper)) | first }}" register: cluster_report_results + failed_when: cluster_report_results.rc != 0 - name: "Copy the cluster report to the local machine" ansible.builtin.fetch: diff --git a/src/roles/misc/tasks/post-telemetry-data.yml b/src/roles/misc/tasks/post-telemetry-data.yml index b96b6058..3e391682 100644 --- a/src/roles/misc/tasks/post-telemetry-data.yml +++ b/src/roles/misc/tasks/post-telemetry-data.yml @@ -8,7 +8,7 @@ failed_when: false delegate_to: localhost send_telemetry_data: - telemetry_data_destination: "{{ telemetry_data_destination | lower }}" + telemetry_data_destination: "{{ telemetry_data_destination | default('none') | lower }}" laws_workspace_id: "{{ laws_workspace_id | default('') }}" laws_shared_key: "{{ laws_shared_key | default('') }}" adx_database_name: "{{ adx_database_name | default('') }}" @@ -17,32 +17,32 @@ telemetry_table_name: "{{ telemetry_table_name | default('') }}" workspace_directory: "{{ _workspace_directory }}" test_group_json_data: { - "TestCaseInvocationId": "{{ test_case_invocation_id }}", - "TestCaseStartTime": "{{ test_case_start_time_epoch }}", + "TestCaseInvocationId": "{{ test_case_invocation_id | default('') }}", + "TestCaseStartTime": "{{ test_case_start_time_epoch | default('') }}", "TestCaseEndTime": "{{ now(utc=true, fmt='%Y-%m-%d %H:%M:%S') }}", - "TestCaseStatus": "{{ test_case_status }}", - "TestCaseName": "{{ test_case_name }}", - "TestCaseDescription": "{{ test_case_description }}", - "TestGroupInvocationId": "{{ group_invocation_id }}", - "TestGroupStartTime": "{{ group_start_time }}", - "TestGroupName": "{{ group_name }}", + "TestCaseStatus": "{{ test_case_status | default('FAILED') }}", + "TestCaseName": "{{ test_case_name | default('') }}", + "TestCaseDescription": "{{ test_case_description | default('') }}", + "TestGroupInvocationId": "{{ group_invocation_id | default('') }}", + "TestGroupStartTime": "{{ group_start_time | default('') }}", + "TestGroupName": "{{ group_name | default('') }}", "OsVersion": "{{ ansible_distribution }} {{ ansible_distribution_version }}", - "TestCaseMessage": "{{ test_case_message }}", - "TestCaseDetails": "{{ test_case_details }}", + "TestCaseMessage": "{{ test_case_message | default('') }}", + "TestCaseDetails": "{{ test_case_details | default('') }}", "DurationSeconds": "{{ ((test_execution_end_time | default(now(utc=true, fmt='%Y-%m-%d %H:%M:%S')) | to_datetime) - (test_execution_start_time | default(test_case_start_time_epoch) | to_datetime)) }}", - "DbFencingType": "{{ database_cluster_type if database_high_availability else 'DB not HA' }}", - "ScsFencingType": "{{ scs_cluster_type if scs_high_availability else 'SCS not HA' }}", - "StorageType": "{{ NFS_provider }}", - "DBType": "{{ platform }}", - "DbSid": "{{ db_sid | upper }}", - "SapSid": "{{ sap_sid | upper }}", + "DbFencingType": "{{ database_cluster_type if (database_high_availability | default(false)) else 'DB not HA' }}", + "ScsFencingType": "{{ scs_cluster_type if (scs_high_availability | default(false)) else 'SCS not HA' }}", + "StorageType": "{{ NFS_provider | default('unknown') }}", + "DBType": "{{ platform | default('') }}", + "DbSid": "{{ db_sid | default('') | upper }}", + "SapSid": "{{ sap_sid | default('') | upper }}", "PackageVersions": "{{ package_versions | default('') }}", "Tags": "{{ execution_tags | default('') }}", "TestExecutionStartTime": "{{ test_execution_start_time | default('') }}", "TestExecutionEndTime": "{{ test_execution_end_time | default('') }}", - "TestCaseHostname": "{{ test_case_hostname }}", + "TestCaseHostname": "{{ test_case_hostname | default('') }}", "TestCaseLogMessagesFromSap": "{{ test_case_var_log_messages | default('') }}" } diff --git a/src/roles/misc/tasks/post-validations-scs.yml b/src/roles/misc/tasks/post-validations-scs.yml deleted file mode 100644 index f7387b37..00000000 --- a/src/roles/misc/tasks/post-validations-scs.yml +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -############################################################################### -# Description: This script will run post validations for the test cases # -############################################################################### - -- name: "Read var log messages by importing role" - ansible.builtin.include_tasks: "roles/misc/tasks/var-log-messages.yml" - -- name: "Post Validations: HA cluster status after test execution" - when: - - ansible_hostname == cluster_status_pre.ascs_node - - cluster_status_pre is defined - block: - - name: "Combine logs from both Nodes" - ansible.builtin.set_fact: - combined_logs: >- - {{ - ( - hostvars[cluster_status_pre.ascs_node]['var_log_messages_output'].filtered_logs - | default('[]') - | from_json - ) - + - ( - hostvars[cluster_status_pre.ers_node]['var_log_messages_output'].filtered_logs - | default('[]') - | from_json - ) - }} - - - name: "Post Validations: Set test case status" - delegate_to: localhost - ansible.builtin.set_fact: - test_case_name: "{{ item.name }}: {{ test_execution_hostname | default(virtual_host) }}" - test_case_description: "{{ item.description }}" - test_case_status: "{{ 'SKIPPED' if pre_validations_status == 'FAILED' else 'PASSED' }}" - test_execution_start_time: "{{ test_execution_start | default(now(utc=true, fmt='%Y-%m-%d %H:%M:%S')) }}" - test_case_hostname: "{{ test_execution_hostname | default(virtual_host) }}" - test_execution_end_time: "{{ test_execution_end | default(now(utc=true, fmt='%Y-%m-%d %H:%M:%S')) }}" - test_case_message: "{{ test_case_message_from_test_case }}" - test_case_details: "{{ test_case_details_from_test_case }}" - - - name: "Post Telemetry Data" - ansible.builtin.include_tasks: "roles/misc/tasks/post-telemetry-data.yml" - -- name: "Clear the failed state of hosts" - ansible.builtin.meta: clear_host_errors diff --git a/src/roles/misc/tasks/post-validations-db.yml b/src/roles/misc/tasks/post-validations.yml similarity index 63% rename from src/roles/misc/tasks/post-validations-db.yml rename to src/roles/misc/tasks/post-validations.yml index 727b5ef0..c31e09e6 100644 --- a/src/roles/misc/tasks/post-validations-db.yml +++ b/src/roles/misc/tasks/post-validations.yml @@ -8,9 +8,27 @@ - name: "Read var log messages by importing role" ansible.builtin.include_tasks: "roles/misc/tasks/var-log-messages.yml" +- name: "Determine cluster node roles" + ansible.builtin.set_fact: + primary_node: "{{ cluster_status_pre.primary_node + | default(cluster_status_pre.ascs_node) + | default('') + }}" + secondary_node: "{{ cluster_status_pre.secondary_node + | default(cluster_status_pre.ers_node) + | default('') + }}" + is_primary_node: >- + {{ + (cluster_status_pre.primary_node is defined and + ansible_hostname == cluster_status_pre.primary_node) or + (cluster_status_pre.ascs_node is defined and + ansible_hostname == cluster_status_pre.ascs_node) + }} + - name: "Post Validations: HA cluster status after test execution" when: - - ansible_hostname == cluster_status_pre.primary_node + - is_primary_node | bool - cluster_status_pre is defined block: - name: "Combine logs from both Nodes" @@ -18,13 +36,13 @@ combined_logs: >- {{ ( - hostvars[cluster_status_pre.primary_node]['var_log_messages_output'].filtered_logs + hostvars[primary_node]['var_log_messages_output'].filtered_logs | default('[]') | from_json ) + ( - hostvars[cluster_status_pre.secondary_node]['var_log_messages_output'].filtered_logs + hostvars[secondary_node]['var_log_messages_output'].filtered_logs | default('[]') | from_json ) @@ -40,8 +58,8 @@ test_case_hostname: "{{ virtual_host }}" test_execution_end_time: "{{ test_execution_end | default(now(utc=true, fmt='%Y-%m-%d %H:%M:%S')) }}" test_case_var_log_messages: "{{ combined_logs }}" - test_case_message: "{{ test_case_message_from_test_case }}" - test_case_details: "{{ test_case_details_from_test_case }}" + test_case_message: "{{ test_case_message_from_test_case | default('') }}" + test_case_details: "{{ test_case_details_from_test_case | default('')}}" - name: "Post Telemetry Data" ansible.builtin.include_tasks: "roles/misc/tasks/post-telemetry-data.yml" diff --git a/src/roles/misc/tasks/rescue.yml b/src/roles/misc/tasks/rescue.yml index a686751d..84c867ab 100644 --- a/src/roles/misc/tasks/rescue.yml +++ b/src/roles/misc/tasks/rescue.yml @@ -10,11 +10,28 @@ - name: "Post Validations: HA cluster status after test execution" block: - - name: "Set node variables based on cluster status" + - name: "Validate cluster_status_pre exists" ansible.builtin.set_fact: - first_node: "{{ cluster_status_pre.primary_node | default(cluster_status_pre.ascs_node) }}" - second_node: "{{ cluster_status_pre.secondary_node | default(cluster_status_pre.ers_node) }}" + cluster_status_pre: "{{ cluster_status_pre | default({}) }}" + - name: "Set node variables based on cluster status with safe fallbacks" + ansible.builtin.set_fact: + first_node: >- + {{ + cluster_status_pre.primary_node | default( + cluster_status_pre.ascs_node | default( + ansible_play_hosts | first + ) + ) + }} + second_node: >- + {{ + cluster_status_pre.secondary_node | default( + cluster_status_pre.ers_node | default( + (ansible_play_hosts | difference([first_node]))[0] | default(first_node) + ) + ) + }} - name: "Combine logs from both Nodes" ansible.builtin.set_fact: combined_logs: >- @@ -35,13 +52,13 @@ - name: "Post Validations: Rescure operation set test case status" delegate_to: localhost ansible.builtin.set_fact: - test_case_name: "{{ item.name }}: {{ test_execution_hostname }}" - test_case_hostname: "{{ virtual_host }}" + test_case_name: "{{ item.name }}: {{ test_execution_hostname | default(inventory_hostname) }}" + test_case_hostname: "{{ virtual_host | default(inventory_hostname) }}" test_case_description: "{{ item.description }}" test_case_status: "FAILED" - test_case_message: "{{ ansible_failed_result }}" - test_case_details: "{{ ansible_failed_result }}" - test_case_var_log_messages: "{{ combined_logs }}" + test_case_message: "{{ ansible_failed_result | default('Unknown error occurred') }}" + test_case_details: "{{ ansible_failed_result | default('No error details available')}}" + test_case_var_log_messages: "{{ combined_logs | default([]) }}" - name: "Post Telemetry Data" ansible.builtin.include_tasks: "roles/misc/tasks/post-telemetry-data.yml" diff --git a/src/vars/input-api.yaml b/src/vars/input-api.yaml index 52574f27..52960cf3 100644 --- a/src/vars/input-api.yaml +++ b/src/vars/input-api.yaml @@ -178,5 +178,10 @@ commands: SUSE: "crm resource clear rsc_sap_{{ sap_sid }}_ASCS{{ scs_instance_number }}" REDHAT: "pcs resource clear rsc_sap_{{ sap_sid }}_ASCS{{ scs_instance_number }}" +# Default values for HANA DB HA Test Cases sap_sid: "HDB" db_sid: "HDB" +db_instance_number: "00" +scs_instance_number: "00" +ers_instance_number: "01" +NFS_provider: "AFS" diff --git a/tests/modules/filesystem_freeze_test.py b/tests/modules/filesystem_freeze_test.py index c42a233a..f7f5a815 100644 --- a/tests/modules/filesystem_freeze_test.py +++ b/tests/modules/filesystem_freeze_test.py @@ -45,7 +45,7 @@ def filesystem_freeze(self): :return: FileSystemFreeze instance :rtype: FileSystemFreeze """ - return FileSystemFreeze() + return FileSystemFreeze(database_sid="SID") def test_file_system_exists(self, monkeypatch, filesystem_freeze): """ @@ -56,22 +56,25 @@ def test_file_system_exists(self, monkeypatch, filesystem_freeze): :param filesystem_freeze: FileSystemFreeze instance. :type filesystem_freeze: FileSystemFreeze """ - with monkeypatch.context() as monkey_patch: - monkey_patch.setattr( - "builtins.open", fake_open_factory(["/dev/sda1 /hana/shared ext4 rw,relatime 0 0"]) - ) - monkey_patch.setattr( - filesystem_freeze, "execute_command_subprocess", lambda x: "output" - ) - filesystem_freeze.run() - result = filesystem_freeze.get_result() - - assert result["status"] == "PASSED" - assert ( - result["message"] - == "The file system (/hana/shared) was successfully mounted read-only." - ) - assert result["changed"] is True + mount_points = ["/hana/shared/SID", "/hana/shared"] + for mount_point in mount_points: + with monkeypatch.context() as monkey_patch: + monkey_patch.setattr( + "builtins.open", + fake_open_factory([f"/dev/sda1 {mount_point} ext4 rw,relatime 0 0"]), + ) + monkey_patch.setattr( + filesystem_freeze, "execute_command_subprocess", lambda x: "output" + ) + filesystem_freeze.run() + result = filesystem_freeze.get_result() + + assert result["status"] == "PASSED" + assert ( + result["message"] + == "The file system (/hana/shared) was successfully mounted read-only." + ) + assert result["changed"] is True def test_file_system_not_exists(self, monkeypatch, filesystem_freeze): """ @@ -109,7 +112,7 @@ class MockAnsibleModule: """ def __init__(self, *args, **kwargs): - self.params = {"nfs_provider": "ANF"} + self.params = {"nfs_provider": "ANF", "database_sid": "SID"} def exit_json(self, **kwargs): """ @@ -148,7 +151,7 @@ def test_main_method_non_anf_provider(self, monkeypatch): class MockAnsibleModule: def __init__(self, *args, **kwargs): - self.params = {"nfs_provider": "non-anf"} + self.params = {"nfs_provider": "non-anf", "database_sid": "SID"} def exit_json(self, **kwargs): nonlocal mock_result diff --git a/tests/roles/ha_db_hana/block_network_test.py b/tests/roles/ha_db_hana/block_network_test.py index b91f5bb8..ad341437 100644 --- a/tests/roles/ha_db_hana/block_network_test.py +++ b/tests/roles/ha_db_hana/block_network_test.py @@ -12,7 +12,6 @@ import os import shutil -from pathlib import Path import pytest from tests.roles.ha_db_hana.roles_testing_base_db import RolesTestingBaseDB @@ -29,8 +28,6 @@ def test_environment(self, ansible_inventory): :param ansible_inventory: Path to the Ansible inventory file. :type ansible_inventory: str - :param task_type: Dictionary with task configuration details. - :type task_type: dict :yield temp_dir: Path to the temporary test environment. :type: str """ @@ -77,8 +74,8 @@ def test_environment(self, ansible_inventory): operation="write", file_path=f"{temp_dir}/project/roles/ha_db_hana/tasks/block-network.yml", content=playbook_content.replace( - "for i in $(seq 1 20); do", - "for i in {1..20}; do", + "for i in $(seq 1 30); do", + "for i in {1..30}; do", ), ) diff --git a/tests/roles/mock_data/filesystem_freeze.txt b/tests/roles/mock_data/filesystem_freeze.txt index b1fb4bf5..ce9189b4 100644 --- a/tests/roles/mock_data/filesystem_freeze.txt +++ b/tests/roles/mock_data/filesystem_freeze.txt @@ -8,6 +8,7 @@ def main(): module = AnsibleModule( argument_spec=dict( nfs_provider=dict(type="str", required=True), + database_sid=dict(type="str", required=True) ) ) diff --git a/tests/roles/roles_testing_base.py b/tests/roles/roles_testing_base.py index 4e063158..5d009433 100644 --- a/tests/roles/roles_testing_base.py +++ b/tests/roles/roles_testing_base.py @@ -157,7 +157,7 @@ def setup_test_environment( standard_files = [ "misc/tasks/test-case-setup.yml", f"misc/tasks/pre-validations-{role_type.split('_')[1]}.yml", - f"misc/tasks/post-validations-{role_type.split('_')[1]}.yml", + "misc/tasks/post-validations.yml", "misc/tasks/rescue.yml", "misc/tasks/var-log-messages.yml", "misc/tasks/post-telemetry-data.yml",