diff --git a/.github/workflows/auto_cherry_pick_merged.yaml b/.github/workflows/auto_cherry_pick_merged.yaml new file mode 100644 index 00000000000..c93cc02e7bf --- /dev/null +++ b/.github/workflows/auto_cherry_pick_merged.yaml @@ -0,0 +1,169 @@ +### The workflow for retrying/rerunning the merged PRs AutoCherryPick which was missed/failed due to any circumstances +name: Retry Merged PRs AutoCherryPick + +# Run on workflow dispatch from CI +on: + workflow_dispatch: + inputs: + parent_pr: + type: string + description: | + An identifier for parent PR to retry it's cherrypick + e.g 12314 + + branches: + type: string + description: | + Comma separated list of branches where the master PR to be cherrypicked. + e.g: 6.15.z, 6.16.z + +env: + number: ${{ github.event.inputs.parent_pr }} + is_dependabot_pr: '' + +jobs: + get-parentPR-details: + runs-on: ubuntu-latest + outputs: + labels: ${{ steps.parentPR.outputs.labels }} + state: ${{ steps.parentPR.outputs.state }} + base_ref: ${{ steps.parentPR.outputs.base_ref }} + assignee: ${{ steps.parentPR.outputs.assignee }} + title: ${{ steps.parentPR.outputs.title }} + prt_comment: ${{ steps.fc.outputs.comment-body }} + + steps: + - name: Find parent PR details + id: parentPR + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.CHERRYPICK_PAT }} + script: | + const { data: pr } = await github.rest.pulls.get({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: ${{ env.number }}, + }); + core.setOutput('labels', pr.labels); + core.setOutput('state', pr.state); + core.setOutput('base_ref', pr.base.ref); + core.setOutput('assignee', pr.assignee.login); + core.setOutput('title', pr.title); + + - name: Find & Save last PRT comment of Parent PR + uses: peter-evans/find-comment@v3 + id: fc + with: + issue-number: ${{ env.number }} + body-includes: "trigger: test-robottelo" + direction: last + + - name: Print PR details + run: | + echo "Labels are ${{ steps.parentPR.outputs.labels }}" + echo "State is ${{ steps.parentPR.outputs.state }}" + echo "Base Ref is ${{ steps.parentPR.outputs.base_ref }}" + echo "Assignee is ${{ steps.parentPR.outputs.assignee }}" + echo "Title is ${{ steps.parentPR.outputs.title }}" + + arrayconversion: + needs: get-parentPR-details + if: ${{ needs.get-parentPR-details.outputs.state }} == closed + runs-on: ubuntu-latest + outputs: + branches: ${{ steps.conversion.outputs.branches }} + steps: + - name: Convert String to List + id: conversion + uses: actions/github-script@v7 + with: + script: | + const branches = "${{ github.event.inputs.branches }}"; + const branchesArray = branches.includes(',') ? branches.split(',').map(item => item.trim()) : [branches.trim()]; + core.setOutput('branches', JSON.stringify(branchesArray)); + + + run-the-branch-matrix: + name: Auto Cherry Pick to labeled branches + runs-on: ubuntu-latest + needs: [arrayconversion, get-parentPR-details] + if: ${{ needs.arrayconversion.outputs.branches != '' }} + strategy: + matrix: + branch: ${{ fromJson(needs.arrayconversion.outputs.branches) }} + steps: + - name: Tell me the branch name + run: | + echo "Branch is: ${{ matrix.branch }}" + + # Needed to avoid out-of-memory error + - name: Set Swap Space + uses: pierotofy/set-swap-space@master + with: + swap-size-gb: 10 + + ## Robottelo Repo Checkout + - uses: actions/checkout@v4 + if: ${{ startsWith(matrix.branch, '6.') && matrix.branch != needs.get-parentPR-details.outputs.base_ref }} + with: + fetch-depth: 0 + + ## Set env var for dependencies label PR + - name: Set env var is_dependabot_pr to `dependencies` to set the label + if: contains(needs.get-parentPR-details.outputs.labels.*.name, 'dependencies') + run: | + echo "is_dependabot_pr=dependencies" >> $GITHUB_ENV + + ## CherryPicking and AutoMerging + - name: Cherrypicking to zStream branch + id: cherrypick + if: ${{ startsWith(matrix.branch, '6.') && matrix.branch != needs.get-parentPR-details.outputs.base_ref }} + uses: jyejare/github-cherry-pick-action@main + with: + token: ${{ secrets.CHERRYPICK_PAT }} + pull_number: ${{ env.number }} + branch: ${{ matrix.branch }} + labels: | + Auto_Cherry_Picked + ${{ matrix.branch }} + No-CherryPick + ${{ env.is_dependabot_pr }} + assignees: ${{ needs.get-parentPR-details.outputs.assignee }} + + - name: Add Parent PR's PRT comment to Auto_Cherry_Picked PR's + id: add-parent-prt-comment + if: ${{ always() && needs.get-parentPR-details.outputs.prt_comment != '' && steps.cherrypick.outcome == 'success' }} + uses: thollander/actions-comment-pull-request@v2 + with: + message: | + ${{ needs.get-parentPR-details.outputs.prt_comment }} + pr_number: ${{ steps.cherrypick.outputs.number }} + GITHUB_TOKEN: ${{ secrets.CHERRYPICK_PAT }} + + - name: is autoMerging enabled for Auto CherryPicked PRs ? + if: ${{ always() && steps.cherrypick.outcome == 'success' && contains(needs.get-parentPR-details.outputs.labels.*.name, 'AutoMerge_Cherry_Picked') }} + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.CHERRYPICK_PAT }} + script: | + github.rest.issues.addLabels({ + issue_number: ${{ steps.cherrypick.outputs.number }}, + owner: context.repo.owner, + repo: context.repo.repo, + labels: ["AutoMerge_Cherry_Picked"] + }) + + - name: Check if cherrypick pr is created + id: search_pr + if: always() + run: | + PR_TITLE="[${{ matrix.branch }}] ${{ needs.get-parentPR-details.outputs.title }}" + API_URL="https://api.github.com/repos/${{ github.repository }}/pulls?state=open" + PR_SEARCH_RESULT=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" "$API_URL" | jq --arg title "$PR_TITLE" '.[] | select(.title == $title)') + if [ -n "$PR_SEARCH_RESULT" ]; then + echo "pr_found=true" >> $GITHUB_OUTPUT + echo "PR is Found with title $PR_TITLE" + else + echo "pr_found=false" >> $GITHUB_OUTPUT + echo "PR is not Found with title $PR_TITLE" + fi diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 1e65633a285..4f1cb45d5aa 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -9,7 +9,6 @@ env: PYCURL_SSL_LIBRARY: openssl ROBOTTELO_BUGZILLA__API_KEY: ${{ secrets.BUGZILLA_KEY }} ROBOTTELO_JIRA__API_KEY: ${{ secrets.JIRA_KEY }} - ROBOTTELO_ROBOTTELO__SETTINGS__IGNORE_VALIDATION_ERRORS: true jobs: codechecks: @@ -18,6 +17,9 @@ jobs: strategy: matrix: python-version: ['3.10', '3.11', '3.12'] + env: + UV_CACHE_DIR: /tmp/.uv-cache + UV_SYSTEM_PYTHON: 1 steps: - name: Checkout Robottelo uses: actions/checkout@v4 @@ -27,22 +29,34 @@ jobs: with: python-version: ${{ matrix.python-version }} + - name: Set up uv + run: curl -LsSf https://astral.sh/uv/install.sh | sh + + - name: Restore uv cache + uses: actions/cache@v4 + with: + path: /tmp/.uv-cache + key: uv-${{ runner.os }}-${{ hashFiles('uv.lock') }} + restore-keys: | + uv-${{ runner.os }}-${{ hashFiles('uv.lock') }} + uv-${{ runner.os }} + - name: Install Dependencies run: | sudo apt update sudo apt-get install -y libgnutls28-dev libcurl4-openssl-dev libssl-dev - wget https://raw.githubusercontent.com/SatelliteQE/broker/master/broker_settings.yaml.example # link vs compile time ssl implementations can break the environment when installing requirements # Uninstall pycurl - its likely not installed, but in case the ubuntu-latest packages change # Then compile and install it with PYCURL_SSL_LIBRARY set to openssl - pip install -U pip wheel - pip uninstall -y pycurl - pip install --compile --no-cache-dir pycurl - pip install -U --no-cache-dir -r requirements.txt -r requirements-optional.txt + uv pip uninstall pycurl + uv pip install --compile --no-cache-dir pycurl + uv pip install -r requirements.txt -r requirements-optional.txt for conffile in conf/*.yaml.template; do mv -- "$conffile" "${conffile%.yaml.template}.yaml"; done - cp broker_settings.yaml.example broker_settings.yaml cp .env.example .env + - name: Minimize uv cache + run: uv cache prune --ci + - name: Collect Tests run: | # To skip vault login in pull request checks diff --git a/.github/workflows/update_robottelo_image.yml b/.github/workflows/update_robottelo_image.yml index 945f76b15dc..8e6a7126dcb 100644 --- a/.github/workflows/update_robottelo_image.yml +++ b/.github/workflows/update_robottelo_image.yml @@ -16,6 +16,9 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + with: + # do not store the auth token in git config + persist-credentials: false - name: Get image tag id: image_tag diff --git a/.github/workflows/weekly.yml b/.github/workflows/weekly.yml index 92fa9f329a9..2c8a80278cf 100644 --- a/.github/workflows/weekly.yml +++ b/.github/workflows/weekly.yml @@ -15,6 +15,9 @@ jobs: strategy: matrix: python-version: [3.12] + env: + UV_CACHE_DIR: /tmp/.uv-cache + UV_SYSTEM_PYTHON: 1 steps: - name: Checkout Robottelo uses: actions/checkout@v4 @@ -24,22 +27,34 @@ jobs: with: python-version: ${{ matrix.python-version }} + - name: Set up uv + run: curl -LsSf https://astral.sh/uv/install.sh | sh + + - name: Restore uv cache + uses: actions/cache@v4 + with: + path: /tmp/.uv-cache + key: uv-${{ runner.os }}-${{ hashFiles('uv.lock') }} + restore-keys: | + uv-${{ runner.os }}-${{ hashFiles('uv.lock') }} + uv-${{ runner.os }} + - name: Install Dependencies run: | - sudo apt-get update -y + sudo apt update sudo apt-get install -y libgnutls28-dev libcurl4-openssl-dev libssl-dev - wget https://raw.githubusercontent.com/SatelliteQE/broker/master/broker_settings.yaml.example # link vs compile time ssl implementations can break the environment when installing requirements # Uninstall pycurl - its likely not installed, but in case the ubuntu-latest packages change # Then compile and install it with PYCURL_SSL_LIBRARY set to openssl - pip install -U pip - pip uninstall -y pycurl - pip install --compile --no-cache-dir pycurl - pip install -U -r requirements.txt -r requirements-optional.txt + uv pip uninstall pycurl + uv pip install --compile --no-cache-dir pycurl + uv pip install -r requirements.txt -r requirements-optional.txt for conffile in conf/*.yaml.template; do mv -- "$conffile" "${conffile%.yaml.template}.yaml"; done - cp broker_settings.yaml.example broker_settings.yaml cp .env.example .env + - name: Minimize uv cache + run: uv cache prune --ci + - name: Customer scenario check run: | touch .env.md @@ -48,7 +63,7 @@ jobs: echo "assignees: pondrejk " >> .env.md echo "labels: Documentation" >> .env.md echo "---" >> .env.md - echo CS_TAGS="$(make customer-scenario-check)" >> .env.md + echo CS_TAGS="$(make customer-scenario-check-jira)" >> .env.md if grep 'The following tests need customerscenario tags' .env.md; then echo "::set-output name=result::0" fi diff --git a/.gitignore b/.gitignore index 37a548e7d4f..b991e4a5107 100644 --- a/.gitignore +++ b/.gitignore @@ -35,6 +35,7 @@ logs/** /inventory.yaml # manifester local files +/manifester_inventory.yaml /manifester_settings.yaml /manifests/ @@ -80,11 +81,6 @@ tests/foreman/pytest.ini /conf/*.conf !/conf/supportability.yaml -# I don't know where those 2 files come from -# but they are always there. -full_upgrade -upgrade_highlights - #Robottelo artifact screenshots/ tmp/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0df5dd8a857..0b136c0b043 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -12,7 +12,7 @@ repos: - id: check-yaml - id: debug-statements - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.5.6 + rev: v0.6.4 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] diff --git a/Dockerfile b/Dockerfile index 2b88a306431..9fdb18421d5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,13 +1,15 @@ -FROM fedora:38 +FROM quay.io/fedora/python-312:latest MAINTAINER https://github.com/SatelliteQE -RUN dnf install -y gcc git make cmake libffi-devel openssl-devel python3-devel \ - python3-pip redhat-rpm-config which libcurl-devel libxml2-devel +ENV PYCURL_SSL_LIBRARY=openssl \ + ROBOTTELO_DIR="${HOME}/robottelo" -COPY / /robottelo/ -WORKDIR /robottelo +COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv -ENV PYCURL_SSL_LIBRARY=openssl -RUN pip install -r requirements.txt +USER 1001 +COPY --chown=1001:0 / ${ROBOTTELO_DIR} + +WORKDIR "${ROBOTTELO_DIR}" +RUN uv pip install -r requirements.txt CMD make test-robottelo diff --git a/Makefile b/Makefile index ff0920c70ee..ac14dc3a0eb 100644 --- a/Makefile +++ b/Makefile @@ -169,8 +169,11 @@ clean-cache: clean-all: docs-clean logs-clean pyc-clean clean-cache clean-shared -customer-scenario-check: - @scripts/customer_scenarios.py +customer-scenario-check-bz: + @scripts/customer_scenarios.py --bz + +customer-scenario-check-jira: + @scripts/customer_scenarios.py --jira vault-login: @scripts/vault_login.py --login diff --git a/conf/capsule.yaml.template b/conf/capsule.yaml.template index b618bf57ea9..11ae548d61a 100644 --- a/conf/capsule.yaml.template +++ b/conf/capsule.yaml.template @@ -16,4 +16,4 @@ CAPSULE: PRODUCT: deploy-capsule # workflow to deploy OS with product running on top of it OS: deploy-rhel # workflow to deploy OS that is ready to run the product # Dictionary of arguments which should be passed along to the deploy workflow - DEPLOY_ARGUMENTS: + DEPLOY_ARGUMENTS: {} diff --git a/conf/dynaconf_hooks.py b/conf/dynaconf_hooks.py index 85baf7d52cb..ff5c538f86d 100644 --- a/conf/dynaconf_hooks.py +++ b/conf/dynaconf_hooks.py @@ -52,7 +52,7 @@ def config_migrations(settings, data): :type data: dict """ logger.info('Running config migration hooks') - sys.path.append(str(Path(__file__).parent)) + sys.path.append(str(Path(__file__).parent.parent)) from conf import migrations migration_functions = [ diff --git a/conf/gce.yaml.template b/conf/gce.yaml.template index 23f92263c61..18b53233ccb 100644 --- a/conf/gce.yaml.template +++ b/conf/gce.yaml.template @@ -1,8 +1,8 @@ GCE: # Google Provider as Compute Resource # client json Certificate path which is local path on satellite - CERT_PATH: /path/to/certificate.json + CERT_PATH: /usr/share/foreman/path/to/certificate.json # Zones - ZONE: example-zone + ZONE: northamerica-northeast1-a # client certificate CERT: "{}" # client json Certificate diff --git a/conf/provisioning.yaml.template b/conf/provisioning.yaml.template index 308686cf84e..d2e547d91be 100644 --- a/conf/provisioning.yaml.template +++ b/conf/provisioning.yaml.template @@ -3,3 +3,5 @@ PROVISIONING: HOST_ROOT_PASSWORD: HOST_SSH_KEY_PRIV: HOST_SSH_KEY_PUB: + PROVISIONING_SAT_WORKFLOW: + PROVISIONING_HOST_WORKFLOW: diff --git a/conf/rh_cloud.yaml.template b/conf/rh_cloud.yaml.template index 752585b210e..acaa5fc7b9b 100644 --- a/conf/rh_cloud.yaml.template +++ b/conf/rh_cloud.yaml.template @@ -1,4 +1,5 @@ RH_CLOUD: + TOKEN: this-isnt-the-token INSTALL_RHC: false ORGANIZATION: org_name ACTIVATION_KEY: ak_name diff --git a/docs/code_standards.rst b/docs/code_standards.rst index 34af971c26f..72f9ffe5c50 100644 --- a/docs/code_standards.rst +++ b/docs/code_standards.rst @@ -23,9 +23,9 @@ Black Linting -* All code will be linted to black-compatible `PEP8`_ standards using `flake8`_. -* In the root of the **Robottelo** directory, run :code:`flake8 .` -* If flake8 returns errors, make corrections before submitting a pull request. +* All code will be linted to black-compatible `PEP8`_ standards using `ruff linter`_. +* In the root of the **Robottelo** directory, run :code:`ruff check .` +* If ruff linter returns errors, make corrections before submitting a pull request. * pre-commit configuration is available, and its use is strongly encouraged in local development. Docstrings @@ -146,7 +146,7 @@ Categorize each standard into how strictly they are enforced .. _PEP8: http://legacy.python.org/dev/peps/pep-0008/ -.. _flake8: http://flake8.readthedocs.org/ +.. _ruff linter: https://docs.astral.sh/ruff/linter/ .. _testimony: https://github.com/SatelliteQE/testimony .. _sphinx: http://sphinx-doc.org/markup/para.html .. _properly format strings: https://docs.python.org/3/library/stdtypes.html#printf-style-string-formatting diff --git a/docs/committing.rst b/docs/committing.rst index c610c3cdcf8..01715163267 100644 --- a/docs/committing.rst +++ b/docs/committing.rst @@ -41,11 +41,11 @@ documented, it doesn’t exist. In order to ensure you are able to pass the Travis CI build, it is recommended that you run the following commands in the base of your Robottelo directory.:: - $ flake8 . + $ ruff check . $ make test-docstrings $ make test-robottelo -:code:`flake8` will ensure that the changes you made are not in violation of +:code:`ruff linter` will ensure that the changes you made are not in violation of PEP8 standards. If the command gives no output, then you have passed. If not, then address any corrections recommended. diff --git a/pytest_fixtures/component/provision_capsule_pxe.py b/pytest_fixtures/component/provision_capsule_pxe.py index c1dadd9589a..a48b42ddc60 100644 --- a/pytest_fixtures/component/provision_capsule_pxe.py +++ b/pytest_fixtures/component/provision_capsule_pxe.py @@ -35,7 +35,7 @@ def capsule_provisioning_sat( sat = module_target_sat provisioning_domain_name = f"{gen_string('alpha').lower()}.foo" broker_data_out = Broker().execute( - workflow='configure-install-sat-provisioning-rhv', + workflow=settings.provisioning.provisioning_sat_workflow, artifacts='last', target_vlan_id=settings.provisioning.vlan_id, target_host=module_capsule_configured.name, diff --git a/pytest_fixtures/component/provision_pxe.py b/pytest_fixtures/component/provision_pxe.py index 24efae4c98d..9d00134a6e4 100644 --- a/pytest_fixtures/component/provision_pxe.py +++ b/pytest_fixtures/component/provision_pxe.py @@ -146,8 +146,8 @@ def module_provisioning_sat( provisioning_domain_name = f"{gen_string('alpha').lower()}.foo" broker_data_out = Broker().execute( - workflow="configure-install-sat-provisioning-rhv", - artifacts="last", + workflow=settings.provisioning.provisioning_sat_workflow, + artifacts='last', target_vlan_id=settings.provisioning.vlan_id, target_host=sat.name, provisioning_dns_zone=provisioning_domain_name, @@ -217,11 +217,11 @@ def provisioning_host(module_ssh_key_file, pxe_loader): "" # TODO: Make this an optional fixture parameter (update vm_firmware when adding this) ) with Broker( - workflow="deploy-configure-pxe-provisioning-host-rhv", + workflow=settings.provisioning.provisioning_host_workflow, host_class=ContentHost, target_vlan_id=vlan_id, target_vm_firmware=pxe_loader.vm_firmware, - target_vm_cd_iso=cd_iso, + target_pxeless_image=cd_iso, blank=True, target_memory='6GiB', auth=module_ssh_key_file, @@ -239,12 +239,12 @@ def provision_multiple_hosts(module_ssh_key_file, pxe_loader, request): "" # TODO: Make this an optional fixture parameter (update vm_firmware when adding this) ) with Broker( - workflow="deploy-configure-pxe-provisioning-host-rhv", + workflow=settings.provisioning.provisioning_host_workflow, host_class=ContentHost, _count=getattr(request, 'param', 2), target_vlan_id=vlan_id, target_vm_firmware=pxe_loader.vm_firmware, - target_vm_cd_iso=cd_iso, + target_pxeless_image=cd_iso, blank=True, target_memory='6GiB', auth=module_ssh_key_file, @@ -310,7 +310,7 @@ def pxe_loader(request): @pytest.fixture -def pxeless_discovery_host(provisioning_host, module_discovery_sat): +def pxeless_discovery_host(provisioning_host, module_discovery_sat, pxe_loader): """Fixture for returning a pxe-less discovery host for provisioning""" sat = module_discovery_sat.sat image_name = f"{gen_string('alpha')}-{module_discovery_sat.iso}" @@ -327,23 +327,16 @@ def pxeless_discovery_host(provisioning_host, module_discovery_sat): workflow='import-disk-image', import_disk_image_name=image_name, import_disk_image_url=(f'https://{sat.hostname}/pub/{fdi}'), + firmware_type=pxe_loader.vm_firmware, ).execute() - # Change host to boot from CD ISO + # Change host to boot discovery image Broker( - job_template='configure-pxe-boot-rhv', + job_template='configure-pxe-boot', target_host=provisioning_host.name, target_vlan_id=settings.provisioning.vlan_id, target_vm_firmware=provisioning_host._broker_args['target_vm_firmware'], - target_vm_cd_iso=image_name, + target_pxeless_image=image_name, target_boot_scenario='pxeless_pre', ).execute() yield provisioning_host - # Remove ISO from host and delete disk image - Broker( - job_template='configure-pxe-boot-rhv', - target_host=provisioning_host.name, - target_vlan_id=settings.provisioning.vlan_id, - target_vm_firmware=provisioning_host._broker_args['target_vm_firmware'], - target_boot_scenario='pxeless_pre', - ).execute() Broker(workflow='remove-disk-image', remove_disk_image_name=image_name).execute() diff --git a/pytest_plugins/markers.py b/pytest_plugins/markers.py index 7d5c0865582..c222150a89d 100644 --- a/pytest_plugins/markers.py +++ b/pytest_plugins/markers.py @@ -25,6 +25,7 @@ def pytest_configure(config): "capsule_only: For satellite-maintain tests to run only on Capsules", "manifester: Tests that require manifester", "ldap: Tests related to ldap authentication", + "no_compose : Skip the marked sanity test for nightly compose", ] markers.extend(module_markers()) for marker in markers: diff --git a/requirements-optional.txt b/requirements-optional.txt index d6cfa4e3599..cc41b459ba5 100644 --- a/requirements-optional.txt +++ b/requirements-optional.txt @@ -1,12 +1,12 @@ # For running tests and checking code quality using these modules. -flake8==7.1.0 pytest-cov==5.0.0 redis==5.0.8 pre-commit==3.8.0 +ruff==0.6.5 # For generating documentation. sphinx==8.0.2 -sphinx-autoapi==3.2.1 +sphinx-autoapi==3.3.1 # For 'manage' interactive shell manage==0.1.15 diff --git a/requirements.txt b/requirements.txt index 9ae20047979..c7d27482183 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,22 +1,22 @@ # Version updates managed by dependabot betelgeuse==1.11.0 -broker[docker,podman,hussh]==0.5.2 -cryptography==43.0.0 -deepdiff==7.0.1 +broker[docker,podman,hussh]==0.5.6 +cryptography==43.0.1 +deepdiff==8.0.1 dynaconf[vault]==3.2.6 fauxfactory==3.1.1 jinja2==3.1.4 -manifester==0.2.7 +manifester==0.2.8 navmazing==1.2.2 -productmd==1.38 +productmd==1.40 pyotp==2.9.0 python-box==7.2.0 -pytest==8.3.2 -pytest-order==1.2.1 +pytest==8.3.3 +pytest-order==1.3.0 pytest-services==2.2.1 pytest-mock==3.14.0 -pytest-reportportal==5.4.1 +pytest-reportportal==5.4.2 pytest-xdist==3.6.1 pytest-fixturecollection==0.1.2 pytest-ibutsu==2.2.4 diff --git a/robottelo/config/__init__.py b/robottelo/config/__init__.py index 16af2133b31..13769cdef2a 100644 --- a/robottelo/config/__init__.py +++ b/robottelo/config/__init__.py @@ -28,6 +28,7 @@ def get_settings(): settings = LazySettings( envvar_prefix="ROBOTTELO", core_loaders=["YAML"], + root_path=str(robottelo_root_dir), settings_file="settings.yaml", preload=["conf/*.yaml"], includes=["settings.local.yaml", ".secrets.yaml", ".secrets_*.yaml"], diff --git a/robottelo/constants/__init__.py b/robottelo/constants/__init__.py index ce7af04bb06..3d91a131b71 100644 --- a/robottelo/constants/__init__.py +++ b/robottelo/constants/__init__.py @@ -1673,7 +1673,6 @@ 'controller': 'provisioning_templates', 'session_name': 'provisioningtemplate', }, - {'name': 'Repository', 'controller': 'katello_repositories', 'session_name': 'repository'}, ] STRING_TYPES = ['alpha', 'numeric', 'alphanumeric', 'latin1', 'utf8', 'cjk', 'html'] diff --git a/robottelo/host_helpers/contenthost_mixins.py b/robottelo/host_helpers/contenthost_mixins.py index 074e15c35e1..8202f00d6c3 100644 --- a/robottelo/host_helpers/contenthost_mixins.py +++ b/robottelo/host_helpers/contenthost_mixins.py @@ -167,7 +167,7 @@ def get_facts(self): if result.status == 0: for line in result.stdout.splitlines(): if ': ' in line: - key, val = line.split(': ') + key, val = line.split(': ', 1) else: key = last_key val = f'{fact_dict[key]} {line}' diff --git a/robottelo/utils/issue_handlers/jira.py b/robottelo/utils/issue_handlers/jira.py index f9ec6e47bfc..e48e32e6b77 100644 --- a/robottelo/utils/issue_handlers/jira.py +++ b/robottelo/utils/issue_handlers/jira.py @@ -20,6 +20,31 @@ # The .version group being a `d.d` string that can be casted to Version() VERSION_RE = re.compile(r'(?:sat-)*?(?P\d\.\d)\.\w*') +common_jira_fields = ['key', 'summary', 'status', 'labels', 'resolution', 'fixVersions'] + +mapped_response_fields = { + 'key': "{obj_name}['key']", + 'summary': "{obj_name}['fields']['summary']", + 'status': "{obj_name}['fields']['status']['name']", + 'labels': "{obj_name}['fields']['labels']", + 'resolution': "{obj_name}['fields']['resolution']['name'] if {obj_name}['fields']['resolution'] else ''", + 'fixVersions': "[ver['name'] for ver in {obj_name}['fields']['fixVersions']] if {obj_name}['fields']['fixVersions'] else []", + # Custom Field - SFDC Cases Counter + 'customfield_12313440': "{obj_name}['fields']['customfield_12313440']", +} + + +def sanitized_issue_data(issue, out_fields): + """fetches the value for all the given fields from a given jira issue + + Arguments: + issue {dict} -- The json data for a jira issue + out_fields {list} -- The list of fields for which data to be retrieved from jira issue + """ + return { + field: eval(mapped_response_fields[field].format(obj_name=issue)) for field in out_fields + } + def is_open_jira(issue_id, data=None): """Check if specific Jira is open consulting a cached `data` dict or @@ -131,8 +156,7 @@ def collect_data_jira(collected_data, cached_data): # pragma: no cover """ jira_data = ( get_data_jira( - [item for item in collected_data if item.startswith('SAT-')], - cached_data=cached_data, + [item for item in collected_data if item.startswith('SAT-')], cached_data=cached_data ) or [] ) @@ -169,16 +193,41 @@ def collect_dupes(jira, collected_data, cached_data=None): # pragma: no cover stop=stop_after_attempt(4), # Retry 3 times before raising wait=wait_fixed(20), # Wait seconds between retries ) -def get_data_jira(issue_ids, cached_data=None): # pragma: no cover +def get_jira(jql, fields=None): + """Accepts the jql to retrieve the data from Jira for the given fields + + Arguments: + jql {str} -- The query for retrieving the issue(s) details from jira + fields {list} -- The custom fields in query to retrieve the data for + + Returns: Jira object of response after status check + """ + params = {"jql": jql} + if fields: + params.update({"fields": ",".join(fields)}) + response = requests.get( + f"{settings.jira.url}/rest/api/latest/search/", + params=params, + headers={"Authorization": f"Bearer {settings.jira.api_key}"}, + ) + response.raise_for_status() + return response + + +def get_data_jira(issue_ids, cached_data=None, jira_fields=None): # pragma: no cover """Get a list of marked Jira data and query Jira REST API. Arguments: issue_ids {list of str} -- ['SAT-12345', ...] cached_data {dict} -- Cached data previous loaded from API + jira_fields {list of str} -- List of fields to be retrieved by a jira issue GET request Returns: [list of dicts] -- [{'id':..., 'status':..., 'resolution': ...}] """ + if not jira_fields: + jira_fields = common_jira_fields + if not issue_ids: return [] @@ -204,48 +253,18 @@ def get_data_jira(issue_ids, cached_data=None): # pragma: no cover # No cached data so Call Jira API logger.debug(f"Calling Jira API for {set(issue_ids)}") - jira_fields = [ - "key", - "summary", - "status", - "labels", - "resolution", - "fixVersions", - ] # Following fields are dynamically calculated/loaded for field in ('is_open', 'version'): assert field not in jira_fields # Generate jql + if isinstance(issue_ids, str): + issue_ids = [issue_id.strip() for issue_id in issue_ids.split(',')] jql = ' OR '.join([f"id = {issue_id}" for issue_id in issue_ids]) - - response = requests.get( - f"{settings.jira.url}/rest/api/latest/search/", - params={ - "jql": jql, - "fields": ",".join(jira_fields), - }, - headers={"Authorization": f"Bearer {settings.jira.api_key}"}, - ) - response.raise_for_status() + response = get_jira(jql, jira_fields) data = response.json().get('issues') # Clean the data, only keep the required info. - data = [ - { - 'key': issue['key'], - 'summary': issue['fields']['summary'], - 'status': issue['fields']['status']['name'], - 'labels': issue['fields']['labels'], - 'resolution': issue['fields']['resolution']['name'] - if issue['fields']['resolution'] - else '', - 'fixVersions': [ver['name'] for ver in issue['fields']['fixVersions']] - if issue['fields']['fixVersions'] - else [], - } - for issue in data - if issue is not None - ] + data = [sanitized_issue_data(issue, jira_fields) for issue in data if issue is not None] CACHED_RESPONSES['get_data'][str(sorted(issue_ids))] = data return data diff --git a/scripts/config_helpers.py b/scripts/config_helpers.py index bc559c5091b..f3bc89bd085 100644 --- a/scripts/config_helpers.py +++ b/scripts/config_helpers.py @@ -1,3 +1,12 @@ +# /// script +# requires-python = ">=3.10" +# dependencies = [ +# "click", +# "deepdiff", +# "logzero", +# "pyyaml", +# ] +# /// """A series of commands to help with robottelo configuration""" from pathlib import Path diff --git a/scripts/customer_scenarios.py b/scripts/customer_scenarios.py index b81137042b9..95863ff19e3 100755 --- a/scripts/customer_scenarios.py +++ b/scripts/customer_scenarios.py @@ -1,4 +1,12 @@ #!/usr/bin/env python +# /// script +# requires-python = ">=3.10" +# dependencies = [ +# "click", +# "requests", +# "testimony", +# ] +# /// from functools import cache import click @@ -6,6 +14,7 @@ import testimony from robottelo.config import settings +from robottelo.utils.issue_handlers.jira import get_data_jira @click.group() @@ -30,10 +39,39 @@ def get_bz_data(paths): for test in tests: test_dict = test.to_dict() test_data = {**test_dict['tokens'], **test_dict['invalid-tokens']} - if 'bz' in test_data and ( - 'customerscenario' not in test_data or test_data['customerscenario'] == 'false' + lowered_test_data = {name.lower(): val for name, val in test_data.items()} + if 'bz' in lowered_test_data and ( + 'customerscenario' not in lowered_test_data + or lowered_test_data['customerscenario'] == 'false' ): - path_result.append([test.name, test_data['bz']]) + path_result.append([test.name, lowered_test_data['bz']]) + if path_result: + result[path] = path_result + return result + + +def get_tests_path_without_customer_tag(paths): + """Returns the path and test name that does not have customerscenario token even + though it has verifies token when necessary + + Arguments: + paths {list} -- List of test modules paths + """ + testcases = testimony.get_testcases(paths) + result = {} + for path, tests in testcases.items(): + path_result = [] + for test in tests: + test_dict = test.to_dict() + test_data = {**test_dict['tokens'], **test_dict['invalid-tokens']} + # 1st level lowering should be good enough as `verifies` and `customerscenario` + # tokens are at 1st level + lowered_test_data = {name.lower(): val for name, val in test_data.items()} + if 'verifies' in lowered_test_data and ( + 'customerscenario' not in lowered_test_data + or lowered_test_data['customerscenario'] == 'false' + ): + path_result.append([test.name, lowered_test_data['verifies']]) if path_result: result[path] = path_result return result @@ -82,11 +120,41 @@ def query_bz(data): return set(output) +def query_jira(data): + """Returns the list of path and test name for missing customerscenario token + + Arguments: + data {dict} -- The list of test modules and tests without customerscenario tags + """ + output = [] + sfdc_counter_field = 'customfield_12313440' + with click.progressbar(data.items()) as bar: + for path, tests in bar: + for test in tests: + jira_data = get_data_jira(test[1], jira_fields=[sfdc_counter_field]) + for data in jira_data: + customer_cases = int(float(data[sfdc_counter_field])) + if customer_cases and customer_cases >= 1: + output.append(f'{path} {test}') + break + return set(output) + + @main.command() -def run(paths=None): - path_list = make_path_list(paths) - values = get_bz_data(path_list) - results = query_bz(values) +@click.option('--jira', is_flag=True, help='Run the customer scripting for Jira') +@click.option('--bz', is_flag=True, help='Run the customer scripting for BZ') +def run(jira, bz, paths=None): + if jira: + path_list = make_path_list(paths) + values = get_tests_path_without_customer_tag(path_list) + results = query_jira(values) + elif bz: + path_list = make_path_list(paths) + values = get_bz_data(path_list) + results = query_bz(values) + else: + raise UserWarning('Choose either `--jira` or `--bz` option') + if len(results) == 0: click.echo('No action needed for customerscenario tags') else: diff --git a/scripts/fixture_cli.py b/scripts/fixture_cli.py index c68559d3c1b..1614d54b052 100644 --- a/scripts/fixture_cli.py +++ b/scripts/fixture_cli.py @@ -1,3 +1,10 @@ +# /// script +# requires-python = ">=3.10" +# dependencies = [ +# "click", +# "pytest", +# ] +# /// from pathlib import Path import click diff --git a/scripts/tokenize_customer_scenario.py b/scripts/tokenize_customer_scenario.py index f810e00c4e0..2768f52f51b 100644 --- a/scripts/tokenize_customer_scenario.py +++ b/scripts/tokenize_customer_scenario.py @@ -1,6 +1,11 @@ +# /// script +# requires-python = ">=3.10" +# dependencies = [ +# "codemod", +# ] +# /// """ This script adds ':customerscenario: true' to all tests by uuid -depends on `pip install https://github.com/facebook/codemod/tarball/master` On command line should be like: diff --git a/scripts/validate_config.py b/scripts/validate_config.py index 04af5d7ac48..4a1fc5a69c5 100644 --- a/scripts/validate_config.py +++ b/scripts/validate_config.py @@ -1,3 +1,9 @@ +# /// script +# requires-python = ">=3.10" +# dependencies = [ +# "dynaconf", +# ] +# /// """Usage: python scripts/validate_config.py""" from dynaconf.validator import ValidationError diff --git a/settings.sample.yaml b/settings.sample.yaml index 56ddbcfe94a..55bf41ee33a 100644 --- a/settings.sample.yaml +++ b/settings.sample.yaml @@ -3,6 +3,11 @@ # example: # `export SATQE_SERVER__HOSTNAME=myserver.redhat.com` --- + +# merge settings from this file with the files that were preloaded from the conf/ directory +# see: https://www.dynaconf.com/merging/ +dynaconf_merge: true + server: admin_password: "" admin_username: "" diff --git a/tests/foreman/api/test_ansible.py b/tests/foreman/api/test_ansible.py index d12a5e65128..304c8694754 100644 --- a/tests/foreman/api/test_ansible.py +++ b/tests/foreman/api/test_ansible.py @@ -419,3 +419,91 @@ def test_negative_ansible_job_timeout_to_kill( assert [i['output'] for i in result if i['output'] == termination_msg] assert [i['output'] for i in result if i['output'] == 'StandardError: Job execution failed'] assert [i['output'] for i in result if i['output'] == 'Exit status: 2'] + + @pytest.mark.tier2 + @pytest.mark.no_containers + @pytest.mark.rhel_ver_list([settings.content_host.default_rhel_version]) + def test_positive_ansible_job_privilege_escalation( + self, + target_sat, + rhel_contenthost, + module_org, + module_location, + module_ak_with_synced_repo, + ): + """Verify privilege escalation defined inside ansible playbook tasks is working + when executing the playbook via Ansible - Remote Execution + + :id: 8c63fd1a-2121-4cce-9ec1-ae12817c9cc4 + + :steps: + 1. Register a RHEL host to Satellite. + 2. Setup a user on that host. + 3. Create a playbook. + 4. Set the SSH user to the created user, and unset the Effective user. + 5. Run the playbook. + + :expectedresults: In the playbook, created user is expected instead root user. + + :BZ: 1955385 + + :customerscenario: true + """ + playbook = ''' + --- + - name: Test Play + hosts: all + gather_facts: false + tasks: + - name: Check current user + command: bash -c "whoami" + register: def_user + - debug: + var: def_user.stdout + - name: Check become user + command: bash -c "whoami" + become: true + become_user: testing + register: bec_user + - debug: + var: bec_user.stdout + ''' + result = rhel_contenthost.register( + module_org, module_location, module_ak_with_synced_repo.name, target_sat + ) + assert result.status == 0, f'Failed to register host: {result.stderr}' + assert rhel_contenthost.execute('useradd testing').status == 0 + pwd = rhel_contenthost.execute( + f'echo {settings.server.ssh_password} | passwd testing --stdin' + ) + assert 'passwd: all authentication tokens updated successfully.' in pwd.stdout + template_id = ( + target_sat.api.JobTemplate() + .search(query={'search': 'name="Ansible - Run playbook"'})[0] + .id + ) + job = target_sat.api.JobInvocation().run( + synchronous=False, + data={ + 'job_category': 'Ansible Playbook', + 'job_template_id': template_id, + 'search_query': f'name = {rhel_contenthost.hostname}', + 'targeting_type': 'static_query', + 'inputs': {'playbook': playbook}, + }, + ) + target_sat.wait_for_tasks( + f'resource_type = JobInvocation and resource_id = {job["id"]}', + poll_timeout=1000, + ) + + result = target_sat.api.JobInvocation(id=job['id']).read() + assert result.pending == 0 + assert result.succeeded == 1 + assert result.status_label == 'succeeded' + + task = target_sat.wait_for_tasks( + f'resource_type = JobInvocation and resource_id = {job["id"]}', + ) + assert '"def_user.stdout": "root"' in task[0].humanized['output'] + assert '"bec_user.stdout": "testing"' in task[0].humanized['output'] diff --git a/tests/foreman/api/test_computeresource_azurerm.py b/tests/foreman/api/test_computeresource_azurerm.py index 04be34f7e9c..11f8e3efb42 100644 --- a/tests/foreman/api/test_computeresource_azurerm.py +++ b/tests/foreman/api/test_computeresource_azurerm.py @@ -193,8 +193,8 @@ def class_setup( "script_uris": AZURERM_FILE_URI, "image_id": self.rhel7_ft_img, } - - nw_id = module_azurerm_cr.available_networks()['results'][-1]['id'] + results = module_azurerm_cr.available_networks()['results'] + nw_id = next((item for item in results if item['name'] == 'default'), None)['id'] request.cls.interfaces_attributes = { "0": { "compute_attributes": { @@ -343,8 +343,8 @@ def class_setup( "script_uris": AZURERM_FILE_URI, "image_id": self.rhel7_ud_img, } - - nw_id = module_azurerm_cr.available_networks()['results'][-1]['id'] + results = module_azurerm_cr.available_networks()['results'] + nw_id = next((item for item in results if item['name'] == 'default'), None)['id'] request.cls.interfaces_attributes = { "0": { "compute_attributes": { @@ -495,8 +495,8 @@ def class_setup( "script_uris": AZURERM_FILE_URI, "image_id": AZURERM_RHEL7_FT_CUSTOM_IMG_URN, } - - nw_id = module_azurerm_cr.available_networks()['results'][-1]['id'] + results = module_azurerm_cr.available_networks()['results'] + nw_id = next((item for item in results if item['name'] == 'default'), None)['id'] request.cls.interfaces_attributes = { "0": { "compute_attributes": { diff --git a/tests/foreman/api/test_registration.py b/tests/foreman/api/test_registration.py index 298de5d505a..84720b23155 100644 --- a/tests/foreman/api/test_registration.py +++ b/tests/foreman/api/test_registration.py @@ -116,10 +116,11 @@ def test_positive_allow_reregistration_when_dmi_uuid_changed( location=module_location, ) assert result.status == 0, f'Failed to register host: {result.stderr}' - + target_sat.execute(f'echo \'{{"dmi.system.uuid": "{uuid_2}"}}\' > /etc/rhsm/facts/uuid.facts') + result = rhel_contenthost.execute('subscription-manager unregister') + assert result.status == 0 result = rhel_contenthost.execute('subscription-manager clean') assert result.status == 0 - target_sat.execute(f'echo \'{{"dmi.system.uuid": "{uuid_2}"}}\' > /etc/rhsm/facts/uuid.facts') result = rhel_contenthost.api_register( target_sat, organization=org, diff --git a/tests/foreman/cli/test_computeresource_azurerm.py b/tests/foreman/cli/test_computeresource_azurerm.py index 1c64a55c5bc..f2dae18d8a0 100644 --- a/tests/foreman/cli/test_computeresource_azurerm.py +++ b/tests/foreman/cli/test_computeresource_azurerm.py @@ -322,7 +322,8 @@ def class_setup( f'script_uris={AZURERM_FILE_URI},' f'premium_os_disk={self.premium_os_disk}' ) - nw_id = module_azurerm_cr.available_networks()['results'][-1]['id'] + results = module_azurerm_cr.available_networks()['results'] + nw_id = next((item for item in results if item['name'] == 'default'), None)['id'] request.cls.interfaces_attributes = ( f'compute_network={nw_id},compute_public_ip=Static,compute_private_ip=false' ) @@ -454,7 +455,8 @@ def class_setup( f'script_uris={AZURERM_FILE_URI},' f'premium_os_disk={self.premium_os_disk}' ) - nw_id = module_azurerm_cr.available_networks()['results'][-1]['id'] + results = module_azurerm_cr.available_networks()['results'] + nw_id = next((item for item in results if item['name'] == 'default'), None)['id'] request.cls.interfaces_attributes = ( f'compute_network={nw_id},compute_public_ip=Dynamic,compute_private_ip=false' ) diff --git a/tests/foreman/cli/test_discoveredhost.py b/tests/foreman/cli/test_discoveredhost.py index c7dee908790..d11039c1e7e 100644 --- a/tests/foreman/cli/test_discoveredhost.py +++ b/tests/foreman/cli/test_discoveredhost.py @@ -427,8 +427,6 @@ def test_positive_verify_updated_fdi_image(target_sat): Verifies: SAT-24197, SAT-25275 - :BZ: 2271598 - :customerscenario: true :CaseImportance: Critical diff --git a/tests/foreman/cli/test_errata.py b/tests/foreman/cli/test_errata.py index 4f26e58ca6f..e92c0c366fe 100644 --- a/tests/foreman/cli/test_errata.py +++ b/tests/foreman/cli/test_errata.py @@ -1623,7 +1623,7 @@ def test_errata_list_by_contentview_filter(module_entitlement_manifest_org, modu :customerscenario: true - :BZ: 1785146 + :verifies: SAT-7987 """ product = entities.Product(organization=module_entitlement_manifest_org).create() repo = module_target_sat.cli_factory.make_repository( diff --git a/tests/foreman/cli/test_fact.py b/tests/foreman/cli/test_fact.py index 7913d68287c..2a1c515bfb5 100644 --- a/tests/foreman/cli/test_fact.py +++ b/tests/foreman/cli/test_fact.py @@ -12,9 +12,12 @@ """ -from fauxfactory import gen_string +from fauxfactory import gen_ipaddr, gen_mac, gen_string import pytest +from robottelo.config import settings +from robottelo.utils.issue_handlers import is_open + pytestmark = [pytest.mark.tier1] @@ -61,3 +64,71 @@ def test_negative_list_by_name(module_target_sat): assert ( module_target_sat.cli.Fact().list(options={'search': f'fact={gen_string("alpha")}'}) == [] ) + + +@pytest.mark.e2e +@pytest.mark.no_containers +@pytest.mark.pit_client +@pytest.mark.rhel_ver_list([settings.content_host.default_rhel_version]) +def test_positive_facts_end_to_end( + module_target_sat, rhel_contenthost, module_org, module_location, module_activation_key +): + """Update client facts and run Ansible roles and verify the facts are updated in Satellite. + + :id: ea94ccb7-a125-4be3-932a-bfcb035d3604 + + :Verifies: SAT-27056 + + :steps: + 1. Add a new interface to the host. + 2. Register the host to Satellite + 3. Gather ansible facts by running ansible roles on the host. + 4. Update the facts in Satellite. + 5. Read all the facts for the host. + 6. Verify that all the facts (new and existing) are updated in Satellite. + + :expectedresults: Facts are successfully updated in the Satellite. + """ + ip = gen_ipaddr() + mac_address = gen_mac(multicast=False) + # Create eth1 interface on the host + add_interface_command = ( + f'nmcli connection add type dummy ifname eth1 ipv4.method manual ipv4.addresses {ip} && ' + f'nmcli connection modify id dummy-eth1 ethernet.mac-address {mac_address}' + ) + assert rhel_contenthost.execute(add_interface_command).status == 0 + result = rhel_contenthost.register( + target=module_target_sat, + org=module_org, + loc=module_location, + activation_keys=[module_activation_key.name], + ) + assert result.status == 0, f'Failed to register host: {result.stderr}' + + host = rhel_contenthost.nailgun_host + # gather ansible facts by running ansible roles on the host + task_id = host.play_ansible_roles() + module_target_sat.wait_for_tasks( + search_query=f'id = {task_id}', + poll_timeout=100, + ) + task_details = module_target_sat.api.ForemanTask().search(query={'search': f'id = {task_id}'}) + assert task_details[0].result == 'success' + facts = module_target_sat.cli.Fact().list( + options={'search': f'host={rhel_contenthost.hostname}'}, output_format='json' + ) + facts_dict = {fact['fact']: fact['value'] for fact in facts} + expected_values = { + 'net::interface::eth1::ipv4_address': ip, + 'network::fqdn': rhel_contenthost.hostname, + 'lscpu::architecture': rhel_contenthost.arch, + 'ansible_distribution_major_version': str(rhel_contenthost.os_version.major), + 'ansible_fqdn': rhel_contenthost.hostname, + } + if not is_open('SAT-27056'): + expected_values['net::interface::eth1::mac_address'] = mac_address.lower() + for fact, expected_value in expected_values.items(): + actual_value = facts_dict.get(fact) + assert ( + actual_value == expected_value + ), f'Assertion failed: {fact} (expected: {expected_value}, actual: {actual_value})' diff --git a/tests/foreman/cli/test_organization.py b/tests/foreman/cli/test_organization.py index a35754d87b6..9a57ceb2aa9 100644 --- a/tests/foreman/cli/test_organization.py +++ b/tests/foreman/cli/test_organization.py @@ -647,7 +647,7 @@ def test_negative_update_name(new_name, module_org, module_target_sat): @pytest.mark.tier2 -def test_positive_create_user_with_timezone(module_org, module_target_sat): +def test_positive_create_user_with_timezone(module_target_sat): """Create and remove user with valid timezone in an organization :id: b9b92c00-ee99-4da2-84c5-0a576a862100 @@ -665,6 +665,12 @@ def test_positive_create_user_with_timezone(module_org, module_target_sat): :expectedresults: User created and removed successfully with valid timezone """ + name = valid_org_names_list()[0] + label = valid_labels_list()[0] + desc = list(valid_data_list().values())[0] + org = module_target_sat.cli_factory.make_org( + {'name': name, 'label': label, 'description': desc} + ) users_timezones = [ 'Pacific Time (US & Canada)', 'International Date Line West', @@ -674,10 +680,10 @@ def test_positive_create_user_with_timezone(module_org, module_target_sat): ] for timezone in users_timezones: user = module_target_sat.cli_factory.user({'timezone': timezone, 'admin': '1'}) - module_target_sat.cli.Org.add_user({'name': module_org.name, 'user': user['login']}) - org_info = module_target_sat.cli.Org.info({'name': module_org.name}) + module_target_sat.cli.Org.add_user({'name': org.name, 'user': user['login']}) + org_info = module_target_sat.cli.Org.info({'name': org.name}) assert user['login'] in org_info['users'] assert user['timezone'] == timezone - module_target_sat.cli.Org.remove_user({'id': module_org.id, 'user-id': user['id']}) - org_info = module_target_sat.cli.Org.info({'name': module_org.name}) + module_target_sat.cli.Org.remove_user({'id': org.id, 'user-id': user['id']}) + org_info = module_target_sat.cli.Org.info({'name': org.name}) assert user['login'] not in org_info['users'] diff --git a/tests/foreman/cli/test_ping.py b/tests/foreman/cli/test_ping.py index 1a1471d5d2f..d0e03f0411b 100644 --- a/tests/foreman/cli/test_ping.py +++ b/tests/foreman/cli/test_ping.py @@ -17,6 +17,7 @@ pytestmark = [pytest.mark.tier1, pytest.mark.upgrade] +@pytest.mark.pit_server @pytest.mark.parametrize('switch_user', [False, True], ids=['root', 'non-root']) def test_positive_ping(target_sat, switch_user): """hammer ping return code diff --git a/tests/foreman/cli/test_registration.py b/tests/foreman/cli/test_registration.py index a137d0f19af..6d628255423 100644 --- a/tests/foreman/cli/test_registration.py +++ b/tests/foreman/cli/test_registration.py @@ -43,7 +43,7 @@ def test_host_registration_end_to_end( :expectedresults: Host registered successfully - :BZ: 2156926 + :verifies: SAT-14716 :customerscenario: true """ diff --git a/tests/foreman/cli/test_report.py b/tests/foreman/cli/test_report.py index 588346f9431..eac89c8ae5f 100644 --- a/tests/foreman/cli/test_report.py +++ b/tests/foreman/cli/test_report.py @@ -78,7 +78,9 @@ def test_positive_install_configure_host( :customerscenario: true - :BZ: 2126891, 2026239 + :BZ: 2026239 + + :verifies: SAT-25418 """ puppet_infra_host = [session_puppet_enabled_sat, session_puppet_enabled_capsule] for client, puppet_proxy in zip(content_hosts, puppet_infra_host, strict=True): diff --git a/tests/foreman/cli/test_webhook.py b/tests/foreman/cli/test_webhook.py index b981f01f8b1..ec363ecd309 100644 --- a/tests/foreman/cli/test_webhook.py +++ b/tests/foreman/cli/test_webhook.py @@ -57,6 +57,7 @@ def assert_created(options, hook): class TestWebhook: @pytest.mark.tier3 + @pytest.mark.pit_server @pytest.mark.e2e def test_positive_end_to_end(self, webhook_factory, class_target_sat): """Test creation, list, update and removal of webhook diff --git a/tests/foreman/destructive/test_clone.py b/tests/foreman/destructive/test_clone.py index 513dfbdd850..06915606337 100644 --- a/tests/foreman/destructive/test_clone.py +++ b/tests/foreman/destructive/test_clone.py @@ -44,7 +44,9 @@ def test_positive_clone_backup( :parametrized: yes - :BZ: 2142514, 2013776 + :BZ: 2142514 + + :Verifies: SAT-10789 :customerscenario: true """ diff --git a/tests/foreman/destructive/test_rename.py b/tests/foreman/destructive/test_rename.py index 8f06cd7a5f8..c267b8dd346 100644 --- a/tests/foreman/destructive/test_rename.py +++ b/tests/foreman/destructive/test_rename.py @@ -191,7 +191,10 @@ def test_negative_rename_sat_wrong_passwd(module_target_sat): f'satellite-change-hostname -y {new_hostname} -u {username} -p {password}' ) assert result.status == 1 - assert BAD_CREDS_MSG in result.stderr[1].decode() + assert BAD_CREDS_MSG in result.stderr + # assert no changes were made + hostname_result = module_target_sat.execute('hostname') + assert original_name == hostname_result.stdout.strip(), "Invalid hostame assigned" @pytest.mark.stubbed diff --git a/tests/foreman/endtoend/test_api_endtoend.py b/tests/foreman/endtoend/test_api_endtoend.py index 93d34394f53..b7a4df25148 100644 --- a/tests/foreman/endtoend/test_api_endtoend.py +++ b/tests/foreman/endtoend/test_api_endtoend.py @@ -33,7 +33,6 @@ from robottelo.utils.issue_handlers import is_open API_PATHS = { - # flake8:noqa (line-too-long) 'activation_keys': ( '/katello/api/activation_keys', '/katello/api/activation_keys', diff --git a/tests/foreman/longrun/test_oscap.py b/tests/foreman/longrun/test_oscap.py index 87c61ae39f6..f16d2727399 100644 --- a/tests/foreman/longrun/test_oscap.py +++ b/tests/foreman/longrun/test_oscap.py @@ -256,7 +256,7 @@ def test_positive_oscap_run_via_ansible_bz_1814988( :expectedresults: REX job should be success and ARF report should be sent to satellite - :BZ: 1814988 + :verifies: SAT-19505 """ hgrp_name = gen_string('alpha') policy_name = gen_string('alpha') diff --git a/tests/foreman/maintain/test_backup_restore.py b/tests/foreman/maintain/test_backup_restore.py index 0e110b78f1b..44c11b50425 100644 --- a/tests/foreman/maintain/test_backup_restore.py +++ b/tests/foreman/maintain/test_backup_restore.py @@ -58,6 +58,11 @@ def get_exp_files(sat_maintain, backup_type, skip_pulp=False): return expected_files +def get_instance_name(sat_maintain): + """Get the instance name depending on target type.""" + return 'satellite' if type(sat_maintain) is Satellite else 'capsule' + + @pytest.mark.include_capsule @pytest.mark.parametrize('backup_type', ['online', 'offline']) def test_positive_backup_preserve_directory( @@ -126,7 +131,7 @@ def test_positive_backup_split_pulp_tar( :BZ: 2164413 """ subdir = f'{BACKUP_DIR}backup-{gen_string("alpha")}' - instance = 'satellite' if type(sat_maintain) is Satellite else 'capsule' + instance = get_instance_name(sat_maintain) set_size = 100 result = sat_maintain.cli.Backup.run_backup( backup_dir=subdir, @@ -170,7 +175,7 @@ def test_positive_backup_capsule_features( 2. expected files are present in the backup """ subdir = f'{BACKUP_DIR}backup-{gen_string("alpha")}' - instance = 'satellite' if type(sat_maintain) is Satellite else 'capsule' + instance = get_instance_name(sat_maintain) features = 'dns,tftp,dhcp,openscap' result = sat_maintain.cli.Backup.run_backup( backup_dir=subdir, @@ -206,7 +211,7 @@ def test_positive_backup_all(sat_maintain, setup_backup_tests, module_synced_rep 1. both backups succeed """ subdir = f'{BACKUP_DIR}backup-{gen_string("alpha")}' - instance = 'satellite' if type(sat_maintain) is Satellite else 'capsule' + instance = get_instance_name(sat_maintain) sat_maintain.execute(f'mkdir -m 0777 {subdir}') result = sat_maintain.cli.Backup.run_backup( backup_dir=subdir, @@ -426,7 +431,7 @@ def test_positive_puppet_backup_restore( sat_maintain.enable_puppet_satellite() subdir = f'{BACKUP_DIR}backup-{gen_string("alpha")}' - instance = 'satellite' if type(sat_maintain) is Satellite else 'capsule' + instance = get_instance_name(sat_maintain) result = sat_maintain.cli.Backup.run_backup( backup_dir=subdir, backup_type=backup_type, @@ -511,7 +516,7 @@ def test_positive_backup_restore( :BZ: 2172540, 1978764, 1979045 """ subdir = f'{BACKUP_DIR}backup-{gen_string("alpha")}' - instance = 'satellite' if type(sat_maintain) is Satellite else 'capsule' + instance = get_instance_name(sat_maintain) result = sat_maintain.cli.Backup.run_backup( backup_dir=subdir, backup_type=backup_type, @@ -597,6 +602,7 @@ def test_positive_backup_restore_incremental( 5. system health check succeeds 6. content is present after restore """ + instance = get_instance_name(sat_maintain) subdir = f'{BACKUP_DIR}backup-{gen_string("alpha")}' result = sat_maintain.cli.Backup.run_backup( backup_dir=subdir, @@ -606,7 +612,7 @@ def test_positive_backup_restore_incremental( assert result.status == 0 assert 'FAIL' not in result.stdout - init_backup_dir = re.findall(rf'{subdir}\/satellite-backup-.*-[0-5][0-9]', result.stdout)[0] + init_backup_dir = re.findall(rf'{subdir}\/{instance}-backup-.*-[0-5][0-9]', result.stdout)[0] # create additional content secondary_repo = sat_maintain.api.Repository( @@ -625,7 +631,7 @@ def test_positive_backup_restore_incremental( assert 'FAIL' not in result.stdout # check for expected files - inc_backup_dir = re.findall(rf'{subdir}\/satellite-backup-.*-[0-5][0-9]', result.stdout)[0] + inc_backup_dir = re.findall(rf'{subdir}\/{instance}-backup-.*-[0-5][0-9]', result.stdout)[0] files = sat_maintain.execute(f'ls -a {inc_backup_dir}').stdout.split('\n') files = [i for i in files if not re.compile(r'^\.*$').search(i)] diff --git a/tests/foreman/sanity/test_bvt.py b/tests/foreman/sanity/test_bvt.py index 9c37152fa34..57356ed689f 100644 --- a/tests/foreman/sanity/test_bvt.py +++ b/tests/foreman/sanity/test_bvt.py @@ -22,6 +22,7 @@ pytestmark = [pytest.mark.build_sanity] +@pytest.mark.no_compose def test_installed_packages_with_versions(target_sat): """Compare the packages that suppose to be installed from repo vs installed packages diff --git a/tests/foreman/ui/test_ansible.py b/tests/foreman/ui/test_ansible.py index c82ac61c11e..530f9eeeea2 100644 --- a/tests/foreman/ui/test_ansible.py +++ b/tests/foreman/ui/test_ansible.py @@ -249,78 +249,6 @@ def test_positive_role_variable_information(self): :expectedresults: The variables information for the given Host is visible. """ - @pytest.mark.stubbed - @pytest.mark.tier2 - def test_positive_assign_role_in_new_ui(self): - """Using the new Host UI, assign a role to a Host - - :id: 044f38b4-cff2-4ddc-b93c-7e9f2826d00d - - :steps: - 1. Register a RHEL host to Satellite. - 2. Import all roles available by default. - 3. Navigate to the new UI for the given Host. - 4. Select the 'Ansible' tab - 5. Click the 'Assign Ansible Roles' button. - 6. Using the popup, assign a role to the Host. - - :expectedresults: The Role is successfully assigned to the Host, and visible on the UI - """ - - @pytest.mark.stubbed - @pytest.mark.tier2 - def test_positive_remove_role_in_new_ui(self): - """Using the new Host UI, remove the role(s) of a Host - - :id: d6de5130-45f6-4349-b490-fbde2aed082c - - :steps: - 1. Register a RHEL host to Satellite. - 2. Import all roles available by default. - 3. Assign a role to the host. - 4. Navigate to the new UI for the given Host. - 5. Select the 'Ansible' tab - 6. Click the 'Edit Ansible roles' button. - 7. Using the popup, remove the assigned role from the Host. - - :expectedresults: Role is successfully removed from the Host, and not visible on the UI - """ - - @pytest.mark.stubbed - @pytest.mark.tier3 - def test_positive_ansible_config_report_failed_tasks_errors(self): - """Check that failed Ansible tasks show as errors in the config report - - :id: 1a91e534-143f-4f35-953a-7ad8b7d2ddf3 - - :steps: - 1. Import Ansible roles - 2. Assign Ansible roles to a host - 3. Run Ansible roles on host - - :expectedresults: Verify that any task failures are listed as errors in the config report - - :CaseAutomation: NotAutomated - """ - - @pytest.mark.stubbed - @pytest.mark.tier3 - def test_positive_ansible_config_report_changes_notice(self): - """Check that Ansible tasks that make changes on a host show as notice in the config report - - :id: 8c90f179-8b70-4932-a477-75dc3566c437 - - :steps: - 1. Import Ansible Roles - 2. Assign Ansible roles to a host - 3. Run Ansible Roles on a host - - :expectedresults: Verify that any tasks that make changes on the host - are listed as notice in the config report - - :CaseAutomation: NotAutomated - """ - @pytest.mark.stubbed @pytest.mark.tier3 def test_positive_ansible_variables_imported_with_roles(self): @@ -411,6 +339,87 @@ def test_positive_set_ansible_role_order_per_hostgroup(self): :CaseAutomation: NotAutomated """ + @pytest.mark.no_containers + @pytest.mark.rhel_ver_list([settings.content_host.default_rhel_version]) + def test_positive_ansible_config_report_changes_notice_and_failed_tasks_errors( + self, + rhel_contenthost, + module_target_sat, + module_org, + module_location, + module_activation_key, + ): + """Check that Ansible tasks that make changes on a host show as notice in the config report and + failed Ansible tasks show as errors in the config report + + :id: 286048f8-0f4f-4a3c-b5c7-fe9c7af8a780 + + :steps: + 1. Import Ansible Roles + 2. Assign and Run Ansible roles to a host + 3. Run Ansible Roles on a host + 4. Check Config Report + + :expectedresults: + 1. Verify that any tasks that make changes on the host are listed as notice in the config report + 2. Verify that any task failures are listed as errors in the config report + """ + SELECTED_ROLE = 'theforeman.foreman_scap_client' + nc = module_target_sat.nailgun_smart_proxy + nc.location = [module_location] + nc.organization = [module_org] + nc.update(['organization', 'location']) + module_target_sat.api.AnsibleRoles().sync( + data={'proxy_id': nc.id, 'role_names': SELECTED_ROLE} + ) + rhel_ver = rhel_contenthost.os_version.major + rhel_repo_urls = getattr(settings.repos, f'rhel{rhel_ver}_os', None) + rhel_contenthost.create_custom_repos(**rhel_repo_urls) + result = rhel_contenthost.register( + module_org, module_location, module_activation_key.name, module_target_sat + ) + assert result.status == 0, f'Failed to register host: {result.stderr}' + with module_target_sat.ui_session() as session: + session.location.select(module_location.name) + session.organization.select(module_org.name) + session.host_new.add_single_ansible_role(rhel_contenthost.hostname) + ansible_roles_table = session.host_new.get_ansible_roles(rhel_contenthost.hostname) + assert ansible_roles_table[0]['Name'] == SELECTED_ROLE + # Verify error log for config report after ansible role is executed + session.host_new.run_job(rhel_contenthost.hostname) + session.jobinvocation.wait_job_invocation_state( + entity_name='Run ansible roles', + host_name=rhel_contenthost.hostname, + expected_state='failed', + ) + err_log = session.configreport.search(rhel_contenthost.hostname) + package_name = SELECTED_ROLE.split('.')[1] + assert f'err Install the {package_name} package' in err_log['permission_denied'] + assert ( + 'Execution error: Failed to install some of the specified packages' + in err_log['permission_denied'] + ) + + # Verify notice log for config report after ansible role is successfully executed + rhel_contenthost.create_custom_repos( + client_repo=settings.repos.satclient_repo[f'rhel{rhel_ver}'] + ) + result = rhel_contenthost.register( + module_org, + module_location, + module_activation_key.name, + module_target_sat, + force=True, + ) + assert result.status == 0, f'Failed to register host: {result.stderr}' + session.host_new.run_job(rhel_contenthost.hostname) + session.jobinvocation.wait_job_invocation_state( + entity_name='Run ansible roles', host_name=rhel_contenthost.hostname + ) + notice_log = session.configreport.search(rhel_contenthost.hostname) + assert f'notice Install the {package_name} package' in notice_log['permission_denied'] + assert f'Installed: rubygem-{package_name}' in notice_log['permission_denied'] + class TestAnsibleREX: """Test class for remote execution via Ansible diff --git a/tests/foreman/ui/test_computeresource_azurerm.py b/tests/foreman/ui/test_computeresource_azurerm.py index 4157a3bad87..74e9d8f2605 100644 --- a/tests/foreman/ui/test_computeresource_azurerm.py +++ b/tests/foreman/ui/test_computeresource_azurerm.py @@ -30,7 +30,8 @@ def module_azure_cp_attrs(module_azurerm_cr, module_azurerm_custom_finishimg, sat_azure): """Create compute attributes on COMPUTE_PROFILE_SMALL""" - nw_id = module_azurerm_cr.available_networks()['results'][-1]['id'] + results = module_azurerm_cr.available_networks()['results'] + nw_id = next((item for item in results if item['name'] == 'default'), None)['id'] return sat_azure.api.ComputeAttribute( compute_profile=COMPUTE_PROFILE_SMALL, compute_resource=module_azurerm_cr, diff --git a/tests/foreman/ui/test_contentcredentials.py b/tests/foreman/ui/test_contentcredentials.py index 42be72d12ec..6548114706e 100644 --- a/tests/foreman/ui/test_contentcredentials.py +++ b/tests/foreman/ui/test_contentcredentials.py @@ -250,50 +250,6 @@ def test_positive_add_repo_from_product_with_repos(session, target_sat, module_o assert values['repositories']['table'][0]['Name'] == repo1.name -@pytest.mark.tier2 -@pytest.mark.upgrade -@pytest.mark.skipif((not settings.robottelo.REPOS_HOSTING_URL), reason='Missing repos_hosting_url') -@pytest.mark.usefixtures('allow_repo_discovery') -def test_positive_add_product_using_repo_discovery(session, gpg_path): - """Create gpg key with valid name and valid gpg key - then associate it with custom product using Repo discovery method - - :id: 7490a5a6-8575-45eb-addc-298ed3b62649 - - :expectedresults: gpg key is associated with product as well as with - the repositories - - :BZ: 1210180, 1461804, 1595792 - """ - name = gen_string('alpha') - product_name = gen_string('alpha') - repo_name = 'fakerepo01' - with session: - session.contentcredential.create( - { - 'name': name, - 'content_type': CONTENT_CREDENTIALS_TYPES['gpg'], - 'upload_file': gpg_path, - } - ) - assert session.contentcredential.search(name)[0]['Name'] == name - session.product.discover_repo( - { - 'repo_type': 'Yum Repositories', - 'url': settings.repos.repo_discovery.url, - 'discovered_repos.repos': repo_name, - 'create_repo.product_type': 'New Product', - 'create_repo.product_content.product_name': product_name, - 'create_repo.product_content.gpg_key': name, - } - ) - values = session.contentcredential.read(name) - assert len(values['products']['table']) == 1 - assert values['products']['table'][0]['Name'] == product_name - assert len(values['repositories']['table']) == 1 - assert values['repositories']['table'][0]['Name'].split(' ')[-1] == repo_name - - @pytest.mark.tier2 @pytest.mark.skipif((not settings.robottelo.REPOS_HOSTING_URL), reason='Missing repos_hosting_url') def test_positive_add_product_and_search(session, target_sat, module_org, gpg_content): diff --git a/tests/foreman/ui/test_errata.py b/tests/foreman/ui/test_errata.py index d9d46d29a38..e075c1ea9a4 100644 --- a/tests/foreman/ui/test_errata.py +++ b/tests/foreman/ui/test_errata.py @@ -192,6 +192,8 @@ def test_end_to_end( :BZ: 2029192 + :verifies: SAT-23414 + :customerscenario: true """ ERRATA_DETAILS = { diff --git a/tests/foreman/ui/test_fact.py b/tests/foreman/ui/test_fact.py new file mode 100644 index 00000000000..08fdf63fd3c --- /dev/null +++ b/tests/foreman/ui/test_fact.py @@ -0,0 +1,62 @@ +"""Test class for Fact UI + +:Requirement: Fact + +:CaseAutomation: Automated + +:CaseComponent: Fact + +:Team: Rocket + +:CaseImportance: High + +""" + +import pytest + +from robottelo.config import settings + + +@pytest.mark.rhel_ver_list([settings.content_host.default_rhel_version]) +def test_positive_upload_host_facts( + module_target_sat, + rhel_contenthost, + module_entitlement_manifest_org, + module_location, + module_activation_key, + default_os, +): + """Verify Facts option is available on the Host UI and it is successfully updated in Satellite after registration + + :id: f32093d2-4088-4025-9623-adb3141bd770 + + :steps: + 1. Register host to Satellite. + 2. Navigate to the Host page and click on kebab. + 3. Verify that the facts option is available and is updated on Satellite. + + :expectedresults: Facts option is available on the Host UI and all the facts of the host are updated in Satellite. + + :BZ: 2001552 + + :customerscenario: true + """ + with module_target_sat.ui_session() as session: + session.organization.select(module_entitlement_manifest_org.name) + session.location.select(module_location.name) + cmd = session.host.get_register_command( + { + 'general.operating_system': default_os.title, + 'general.activation_keys': module_activation_key.name, + 'general.insecure': True, + } + ) + result = rhel_contenthost.execute(cmd) + assert result.status == 0, f'Failed to register host: {result.stderr}' + + rhel_contenthost.execute('subscription-manager facts --update') + host_facts = session.host_new.get_host_facts(rhel_contenthost.hostname, fact='network') + assert host_facts is not None + assert rhel_contenthost.hostname in [ + var['Value'] for var in host_facts if var['Name'] == 'networkfqdn' + ] diff --git a/tests/foreman/ui/test_hostgroup.py b/tests/foreman/ui/test_hostgroup.py index 34b27ffeba2..b168c7ef306 100644 --- a/tests/foreman/ui/test_hostgroup.py +++ b/tests/foreman/ui/test_hostgroup.py @@ -267,7 +267,6 @@ def test_positive_nested_host_groups( assert not target_sat.api.HostGroup().search(query={'search': f'name={child_hg_name}'}) -@pytest.mark.skip_if_open('BZ:2122261') @pytest.mark.tier2 def test_positive_clone_host_groups( session, module_org, module_lce, module_published_cv, module_ak_cv_lce, target_sat @@ -287,6 +286,8 @@ def test_positive_clone_host_groups( :BZ: 2122261 + :BlockedBy: SAT-20435 + :customerscenario: true """ parent_hg_name = gen_string('alpha') diff --git a/tests/foreman/ui/test_location.py b/tests/foreman/ui/test_location.py index b340575d292..11eabaa3b1b 100644 --- a/tests/foreman/ui/test_location.py +++ b/tests/foreman/ui/test_location.py @@ -115,7 +115,9 @@ def test_positive_update_with_all_users(session, target_sat): :expectedresults: Location entity is assigned to user after checkbox was enabled and then disabled afterwards - :BZ: 1321543, 1479736, 1479736 + :BZ: 1479736 + + :verifies: SAT-25386 :BlockedBy: SAT-25386 """ diff --git a/tests/foreman/ui/test_organization.py b/tests/foreman/ui/test_organization.py index 3af1fe6420f..43d9a0156d6 100644 --- a/tests/foreman/ui/test_organization.py +++ b/tests/foreman/ui/test_organization.py @@ -198,7 +198,7 @@ def test_positive_create_with_all_users(session, module_target_sat): :expectedresults: Organization and user entities assigned to each other - :BZ: 1321543 + :verifies: SAT-25386 :BlockedBy: SAT-25386 """ diff --git a/tests/foreman/ui/test_registration.py b/tests/foreman/ui/test_registration.py index 6cdb3ef89ea..7b35726a4cd 100644 --- a/tests/foreman/ui/test_registration.py +++ b/tests/foreman/ui/test_registration.py @@ -129,14 +129,13 @@ def test_negative_global_registration_without_ak( @pytest.mark.tier3 @pytest.mark.rhel_ver_match('[^6]') def test_positive_global_registration_end_to_end( - session, module_activation_key, module_org, smart_proxy_location, default_os, default_smart_proxy, rhel_contenthost, - target_sat, + module_target_sat, ): """Host registration form produces a correct registration command and host is registered successfully with it, remote execution and insights are set up @@ -154,25 +153,27 @@ def test_positive_global_registration_end_to_end( """ # make sure global parameters for rex and insights are set to true insights_cp = ( - target_sat.api.CommonParameter() + module_target_sat.api.CommonParameter() .search(query={'search': 'name=host_registration_insights'})[0] .read() ) rex_cp = ( - target_sat.api.CommonParameter() + module_target_sat.api.CommonParameter() .search(query={'search': 'name=host_registration_remote_execution'})[0] .read() ) if not insights_cp.value: - target_sat.api.CommonParameter(id=insights_cp.id, value=1).update(['value']) + module_target_sat.api.CommonParameter(id=insights_cp.id, value=1).update(['value']) if not rex_cp.value: - target_sat.api.CommonParameter(id=rex_cp.id, value=1).update(['value']) + module_target_sat.api.CommonParameter(id=rex_cp.id, value=1).update(['value']) # rex interface iface = 'eth0' # fill in the global registration form - with session: + with module_target_sat.ui_session() as session: + session.organization.select(org_name=module_org.name) + session.location.select(loc_name=smart_proxy_location.name) cmd = session.host.get_register_command( { 'general.operating_system': default_os.title, @@ -219,11 +220,11 @@ def test_positive_global_registration_end_to_end( # Assert that a yum update was made this day ("Update" or "I, U" in history) timezone_offset = rhel_contenthost.execute('date +"%:z"').stdout.strip() tzinfo = datetime.strptime(timezone_offset, '%z').tzinfo - result = rhel_contenthost.execute('yum history | grep U') + result = rhel_contenthost.execute('yum history | grep -E "I|U"') assert result.status == 0 assert datetime.now(tzinfo).strftime('%Y-%m-%d') in result.stdout # Set "Connect to host using IP address" - target_sat.api.Parameter( + module_target_sat.api.Parameter( host=rhel_contenthost.hostname, name='remote_execution_connect_by_ip', parameter_type='boolean', @@ -231,7 +232,7 @@ def test_positive_global_registration_end_to_end( ).create() # run insights-client via REX command = "insights-client --status" - invocation_command = target_sat.cli_factory.job_invocation( + invocation_command = module_target_sat.cli_factory.job_invocation( { 'job-template': 'Run Command - Script Default', 'inputs': f'command={command}', @@ -240,24 +241,24 @@ def test_positive_global_registration_end_to_end( ) # results provide all info but job invocation might not be finished yet result = ( - target_sat.api.JobInvocation() + module_target_sat.api.JobInvocation() .search( query={'search': f'id={invocation_command["id"]} and host={rhel_contenthost.hostname}'} )[0] .read() ) # make sure that task is finished - task_result = target_sat.wait_for_tasks( + task_result = module_target_sat.wait_for_tasks( search_query=(f'id = {result.task.id}'), search_rate=2, max_tries=60 ) assert task_result[0].result == 'success' host = ( - target_sat.api.Host() + module_target_sat.api.Host() .search(query={'search': f'name={rhel_contenthost.hostname}'})[0] .read() ) for interface in host.interface: - interface_result = target_sat.api.Interface(host=host.id).search( + interface_result = module_target_sat.api.Interface(host=host.id).search( query={'search': f'{interface.id}'} )[0] # more interfaces can be inside the host diff --git a/tests/upgrades/test_provisioningtemplate.py b/tests/upgrades/test_provisioningtemplate.py index cc686e3d22f..e0eec3aaf50 100644 --- a/tests/upgrades/test_provisioningtemplate.py +++ b/tests/upgrades/test_provisioningtemplate.py @@ -12,6 +12,8 @@ """ +import json + from fauxfactory import gen_string import pytest @@ -74,12 +76,12 @@ def test_pre_scenario_provisioning_templates( for kind in provisioning_template_kinds: assert host.read_template(data={'template_kind': kind}) - save_test_data( - { - 'provision_host_id': host.id, - 'pxe_loader': pxe_loader.pxe_loader, - } - ) + pre_update_data_dict = { + 'provision_host_id': host.id, + 'pxe_loader': pxe_loader.pxe_loader, + } + pre_update_json_file = json.dumps(pre_update_data_dict, indent=2) + save_test_data(pre_update_json_file) @pytest.mark.post_upgrade(depend_on=test_pre_scenario_provisioning_templates) @pytest.mark.parametrize('pre_upgrade_data', ['bios', 'uefi'], indirect=True)