From 8c6da37d8c18dbf952c47a02c8ea7327a4681707 Mon Sep 17 00:00:00 2001 From: Lila Date: Fri, 8 Dec 2023 11:19:53 -0500 Subject: [PATCH] Added url for LDAP to method_auth. Fixed ldap url a bit and cleaned up a few things. Changed conditional back to adn rather than or and changed var back to password rather than username. fix wsrelay connection in ipv6 environments Fix: #14511 Add alt-text codeblock to Images for Userguide: main_menu.rst Signed-off-by: Ratan Gulati Revised the proposed Alt text for main_menu.rst Update insights.rst Update insights.rst Revised proposed alt text for insights.rst Updated images - Workflow Templates chapter of Userguide. Removed references to images that were deleted. Fix: #14523 Add alt-text codeblock to Images for workflow_template.rst (#14604) * add alt to images in workflow_templates.rst Signed-off-by: Ratan Gulati * add alt to images in workflow_templates.rst Signed-off-by: Ratan Gulati * Update workflow_templates.rst * Revised proposed alt text for workflow_templates.rst --------- Signed-off-by: Ratan Gulati Co-authored-by: TVo Added alt text for settings-menu.rst (#14639) * Re-do for PR #14595 to fix CI issues. * Added alt text to settings-menu.rst * Update docs/docsite/rst/common/settings-menu.rst Co-authored-by: Don Naro --------- Co-authored-by: Hao Liu <44379968+TheRealHaoLiu@users.noreply.github.com> Co-authored-by: Don Naro Docs: Include REST API reference content from swagger.json (#14607) Setting credential_type as required (#14651) * Setting credential_type as required * Added test for missing credential_type in credential module * Corrected test assertion --------- Co-authored-by: Lucas Benedito Replaced with larger graphic. (#14647) Correctly handle case where unpartitioned table does not exist (#14648) Set subscription type as developer for developer subscriptions. (#14584) * Set subscription type as developer for developer subscriptions. Signed-off-by: Tong He * Set subscription type as developer for developer subscription manifests. Signed-off-by: Tong He * Remedy the wrong character to assign value. Signed-off-by: Tong He * Reformat licensing.py by black. Signed-off-by: Tong He --------- Signed-off-by: Tong He issue #14653 heading does not render correctly (#14665) Adding the possibility to decode base64 decoded strings to Delinea's Devops Secret Vault (DSV) (#14646) Adding the possibility to decode base64 decoded strings to Delinea's Devops Secret Vault (DSV). This is necessary as uploading files to DSV is not possible (and not meant to be) and files should be added base64 encoded. The commit is making sure to remain backward compatible (no secret decoding), as a default is supplied. This has been tested with DSV and works for secrets that are base64 encoded and secrets that are not base64 encoded (which is the default). Signed-off-by: Steffen Scheib Added missing pointers to release notes (#14659) * Replaced with larger graphic. * Revert "Replaced with larger graphic." This reverts commit 1214b00052b43c46c5ee9b2833e61c779884ec1c. * Added missing pointers to release notes. Make vault init more idempotent (#14664) Currently if you cleanup docker volume for vault and bring docker-compose development back up with vault enabled we will not initialize vault because the secret files still exist. This change will attempt to initialize vault reguardless and update the secret file if vault is initialized Remove unused methods we attach to user model (#14668) Update RBAC docs, remove unused get_permissions (#14492) * Update RBAC docs, remove unused get_permissions * Add back in section for get_roles_on_resource Upgrade doc requirements (#14669) * upgrade when pip compiling doc reqs * upgrade doc requirements allow pytest --migrations to succeed (#14663) * allow pytest --migrations to succeed * We actually subvert migrations from running in test via pytest.ini --no-migrations option. This has led to bit rot for the sqlite migrations happy path. This changeset pays off that tech debt and allows for an sqlite migration happy path. * This paves the way for programatic invocation of individual migrations and weaving of the creation of resources (i.e. Instance, Job Template, etc). With this, a developer can instantiate various database states, trigger a migration, assert the state of the db, and then have pytest rollback all of that. * I will note that in practice, running these migrations is dog shit slow BUT this work also opens up the possibility of saving and re-using sqlite3 database files. Normally, caching is not THE answer and causes more harm than good. But in this case, our migrations are mostly write-once (I say mostly because this change set violates that :) so cache invalidation isn't a major issue. * functional test for migrations on sqlite * We commonly subvert running migrations in test land. Test land uses sqlite. By not constantly exercising this code path it atrophies. The smoke test here is to continuously exercise that code path. * Add ci test to run migration tests separately, they take =~ 2-3 minutes each on my laptop. * The smoke tests also serves as an example of how to write migration tests. * run migration tests in ci Fix awx collection publishing on galaxy (#14642) --location (-L) parameter will prompt curl to submit a new request if the URL is a redirect. After moving to galaxy-NG without -L the curl falsely return 302 for any version Co-authored-by: John Barker Fixing wsrelay connection loop (#14692) * Fixing wsrelay connection loop * The loop was being interrupted when reaching the return statements, causing a race condition that would make nodes remain disconnected from their websockets * Added log messages for the previous return state to improve the logging from this state. * Added logging for malformed payload * Update awx/main/wsrelay.py Co-authored-by: Rick Elrod * Moved logmsg outside condition --------- Co-authored-by: Lucas Benedito Co-authored-by: Rick Elrod Fix the bulk Job Launch Integration test in awx collection (#14702) * fix the integration tests [CI] Reduce GHA timeouts from 6h default (#14704) * [CI] Reduce GHA timeouts from 6h default The goal here is to never interfere with a real run (so most of the timeout-minutes values seem rather high) but to avoid having 6h long runs if something goes crazy and never ends. Signed-off-by: Rick Elrod * Do bash hackery instead Signed-off-by: Rick Elrod --------- Signed-off-by: Rick Elrod separate tox calls in readthedocs config (#14673) Add TLS certificate auth for HashiCorp Vault (#14534) * Add TLS certificate auth for HashiCorp Vault Add support for AWX to authenticate with HashiCorp Vault using TLS client certificates. Also updates the documentation for the HashiCorp Vault secret management plugins to include both the new TLS options and the missing Kubernetes auth method options. Signed-off-by: Andrew Austin * Refactor docker-compose vault for TLS cert auth Add TLS configuration to the docker-compose Vault configuration and use that method by default in vault plumbing. This ensures that the result of bringing up the docker-compose stack with vault enabled and running the plumb-vault playbook is a fully working credential retrieval setup using TLS client cert authentication. Signed-off-by: Andrew Austin * Remove incorrect trailing space Co-authored-by: Hao Liu <44379968+TheRealHaoLiu@users.noreply.github.com> * Make vault init idempotent - improve error handling for vault_initialization - ignore error if vault cert auth is already configured - removed unused register * Add VAULT_TLS option Make TLS for HashiCorp Vault optional and configurable via VAULT_TLS env var * Add retries for vault init Sometime it took longer for vault to fully come up and init will fail --------- Signed-off-by: Andrew Austin Co-authored-by: Hao Liu <44379968+TheRealHaoLiu@users.noreply.github.com> Co-authored-by: Hao Liu remove unnecessary required flags for saml backend (#14666) Signed-off-by: Tyler Muir Dependabot for docsite requirements (#14670) Add django-ansible-base (#14705) * add django-ansible-base Signed-off-by: jessicamack * add licenses * add django-ansible-base Signed-off-by: jessicamack * add licenses * apply patch to fix permissions issue --------- Signed-off-by: jessicamack Remove incorrectly formatted line from requirements.txt (#14714) remove git+ line Fix updater bug due to missing newline at EOF (#14713) Fix undefined error in settings/logging/edit form (#14715) Fix undefined error in logging settings edit form Update setuptools-scm (#14716) * properly format requirement * upgrade setuptools_scm * Revert "properly format requirement" This reverts commit 4c8792950fbdbc623c5c373b970850bc2eb5b844. * test ansible-runner package upgrade * Revert "test ansible-runner package upgrade" This reverts commit ba4b74f2bb173441195574ff70a4bc946391661f. Adding hosts bulk deletion feature (#14462) * Adding hosts bulk deletion feature Signed-off-by: Avi Layani * fix the type of the argument Signed-off-by: Avi Layani * fixing activity_entry tracking Signed-off-by: Avi Layani * Revert "fixing activity_entry tracking" This reverts commit c8eab52c2ccc5abe215d56d1704ba1157e5fbbd0. Since the bulk_delete is not related to an inventory, only hosts which can be from different inventories. * get only needed vars to reduce memory consumption Signed-off-by: Avi Layani * filtering the data to reduce memory increase the number of queries Signed-off-by: Avi Layani * update the activity stream for inventories Signed-off-by: Avi Layani * fix the changes dict initialiazation Signed-off-by: Avi Layani --------- Signed-off-by: Avi Layani Remove superwatcher from docker-compose dev (#14708) When making changes to the application sometime you can accidentally cause FATAL state and cause the dev container to crash which will remove any ephemeral changes that you have made and is ANNOYING! Recover rsyslog from 4xx error Due to https://github.com/ansible/awx/issues/7560 'omhttp' module for rsyslog will completely stop forwarding message to external log aggregator after receiving a 4xx error from the external log aggregator This PR is an "workaround" for this problem by restarting rsyslogd after detecting that rsyslog received a 4xx error Correct misuse of stdxxx_event_enabled Not every log messages need to be emitted as a event! Send SIGKILL to rsyslog if hard cancellation is needed Simplify RBAC get_roles_on_resource method (#14710) * Simplify RBAC get_roles_on_resource method * Fix bug * Fix query type bug Narrow the actor types accepted for RBAC evaluations (#14709) * Narrow the scope of RBAC evaluations * Update tests for RBAC method changes * Simplify querset for credentials in org * Fix call pattern to pass in team role obj Use filtering/sorting from django-ansible-base (#14726) * Move filtering to DAB * add comment to trigger building a new image Signed-off-by: jessicamack * remove unneeded comment Signed-off-by: jessicamack * remove unused imports Signed-off-by: jessicamack * change mock import Signed-off-by: jessicamack --------- Signed-off-by: jessicamack Co-authored-by: jessicamack add awx collection export tests * Basic export tests * Added test that highlights a problem with running Schedule exports as non-root user. We rely on the POST key in the OPTIONS response to determine the fields to export for a resource. The POST key is not present if a user does NOT have create privileges. * Fixed up forwarding all headers from the API server back to the test code. This was causing a problem in awxkit code that checks for allowed HTTP Verbs in the headers. refactor awxkit import code * Move awxkit import code into a pytest fixture to better control when the import happens * Ensure /awx_devel/awxkit is added to sys path before awxkit import runs Fix twilio_backend.py to send SMS to multiple destinations. (#14656) AWX only sends Twilio notifications to one destination with the current version of code, but this is a bug. Fixed this bug for sending SMS to multiple destinations. Persist schedule prompt on launch fields when editing (#14736) * persist schedule prompt on launch fields when editing * Merge job template default credentials with schedule overrides in schedule prompt * rename vars for clarity * handle undefined defaultCredentials --------- Co-authored-by: Michael Abashian --- .github/actions/run_awx_devel/action.yml | 12 +- .github/dependabot.yml | 10 + .github/workflows/ci.yml | 8 + .github/workflows/devel_images.yml | 1 + .github/workflows/docs.yml | 1 + .github/workflows/feature_branch_deletion.yml | 1 + .github/workflows/label_issue.yml | 2 + .github/workflows/label_pr.yml | 2 + .github/workflows/pr_body_check.yml | 1 + .github/workflows/promote.yml | 5 +- .github/workflows/stage.yml | 1 + .github/workflows/update_dependabot_prs.yml | 1 + .github/workflows/upload_schema.yml | 1 + .readthedocs.yaml | 3 +- MANIFEST.in | 2 +- Makefile | 14 +- awx/api/filters.py | 450 ------------------ awx/api/generics.py | 5 +- awx/api/serializers.py | 116 ++++- .../templates/api/bulk_host_delete_view.md | 22 + awx/api/urls/urls.py | 2 + awx/api/views/__init__.py | 10 +- awx/api/views/bulk.py | 18 + awx/conf/models.py | 4 +- awx/main/access.py | 8 +- awx/main/conf.py | 10 + awx/main/credential_plugins/dsv.py | 17 +- awx/main/credential_plugins/hashivault.py | 63 ++- awx/main/migrations/0006_v320_release.py | 5 +- .../0050_v340_drop_celery_tables.py | 33 +- awx/main/migrations/0113_v370_event_bigint.py | 9 +- awx/main/migrations/0144_event_partitions.py | 8 +- .../0185_move_JSONBlob_to_JSONField.py | 32 +- .../migrations/0186_drop_django_taggit.py | 6 +- awx/main/migrations/_sqlite_helper.py | 61 +++ awx/main/models/__init__.py | 8 +- awx/main/models/ad_hoc_commands.py | 4 +- awx/main/models/base.py | 18 - awx/main/models/ha.py | 4 +- awx/main/models/inventory.py | 4 +- awx/main/models/jobs.py | 3 +- awx/main/models/mixins.py | 25 +- awx/main/models/notifications.py | 4 +- awx/main/models/rbac.py | 37 +- awx/main/models/unified_jobs.py | 5 +- awx/main/models/workflow.py | 4 +- awx/main/notifications/twilio_backend.py | 18 +- awx/main/scheduler/task_manager.py | 3 +- .../tests/functional/api/test_survey_spec.py | 2 +- awx/main/tests/functional/test_bulk.py | 136 ++++++ .../functional/test_credential_plugins.py | 36 ++ awx/main/tests/functional/test_migrations.py | 44 ++ awx/main/tests/functional/test_rbac_core.py | 4 +- awx/main/tests/functional/test_rbac_team.py | 4 +- awx/main/tests/functional/test_rbac_user.py | 19 - awx/main/tests/unit/api/test_filters.py | 90 +--- awx/main/tests/unit/utils/test_common.py | 4 +- awx/main/tests/unit/utils/test_filters.py | 4 +- awx/main/utils/common.py | 22 - awx/main/utils/db.py | 17 - awx/main/utils/filters.py | 2 +- awx/main/utils/licensing.py | 26 +- awx/main/wsrelay.py | 26 +- awx/settings/defaults.py | 20 +- awx/sso/conf.py | 5 - .../Schedule/shared/ScheduleForm.js | 7 + .../shared/mergeArraysByCredentialType.js | 18 + .../Logging/LoggingEdit/LoggingEdit.js | 2 +- awx_collection/meta/runtime.yml | 1 + .../plugins/modules/bulk_host_delete.py | 65 +++ awx_collection/plugins/modules/credential.py | 3 +- awx_collection/test/awx/conftest.py | 106 ++++- awx_collection/test/awx/test_bulk.py | 25 + awx_collection/test/awx/test_completeness.py | 1 + awx_collection/test/awx/test_export.py | 154 ++++++ .../targets/bulk_host_delete/tasks/main.yml | 80 ++++ .../targets/bulk_job_launch/tasks/main.yml | 2 +- .../targets/credential/tasks/main.yml | 13 + .../targets/job_list/tasks/main.yml | 4 +- .../targets/job_wait/tasks/main.yml | 2 +- .../targets/lookup_api_plugin/tasks/main.yml | 2 +- .../targets/lookup_rruleset/tasks/main.yml | 2 +- .../targets/schedule/tasks/main.yml | 4 +- .../targets/schedule_rrule/tasks/main.yml | 2 +- .../targets/workflow_launch/tasks/main.yml | 2 +- awxkit/awxkit/cli/custom.py | 20 + awxkit/awxkit/cli/options.py | 4 + docs/bulk_api.md | 18 + docs/docsite/conf.py | 3 +- docs/docsite/requirements.txt | 16 +- .../rst/common/images/instances_list_view.png | Bin 227243 -> 131312 bytes .../images/wf-activity-stream-events.png | Bin 392117 -> 0 bytes .../common/images/wf-add-node-selections.png | Bin 52699 -> 28119 bytes .../images/wf-editor-convergent-node-all.png | Bin 12493 -> 0 bytes ...editor-create-new-add-template-example.png | Bin 12792 -> 20164 bytes ...f-editor-create-new-add-template-split.png | Bin 16883 -> 18305 bytes .../images/wf-editor-create-sibling-node.png | Bin 55144 -> 52163 bytes .../images/wf-editor-create-siblings.png | Bin 12596 -> 24773 bytes .../images/wf-editor-insert-node-template.png | Bin 34760 -> 37202 bytes .../images/wf-editor-key-dropdown-list.png | Bin 20805 -> 19285 bytes ...-editor-prompt-button-inventory-wizard.png | Bin 40532 -> 49093 bytes .../images/wf-editor-prompt-button-wizard.png | Bin 100029 -> 95572 bytes .../wf-editor-wizard-add-link-prompt.png | Bin 0 -> 11793 bytes .../images/wf-editor-wizard-buttons.png | Bin 18374 -> 0 bytes .../images/wf-editor-wizard-edit-link.png | Bin 11627 -> 26771 bytes .../common/images/wf-editor-wizard-unlink.png | Bin 10438 -> 36202 bytes .../images/wf-list-view-copy-example.png | Bin 233744 -> 111380 bytes .../common/images/wf-node-approval-form.png | Bin 24107 -> 44480 bytes .../common/images/wf-node-approval-node.png | Bin 5547 -> 11492 bytes .../images/wf-node-approval-notifications.png | Bin 75975 -> 101252 bytes .../common/images/wf-node-delete-scenario.png | Bin 45172 -> 48021 bytes .../common/images/wf-node-link-scenario.png | Bin 49242 -> 65268 bytes .../rst/common/images/wf-start-button.png | Bin 1064 -> 2240 bytes .../wf-template-completed-jobs-list.png | Bin 204379 -> 71089 bytes .../wf-template-job-detail-with-parent.png | Bin 92235 -> 0 bytes .../wf-template-jobID-detail-example.png | Bin 73295 -> 43802 bytes .../wf-template-jobs-detail-example.png | Bin 101005 -> 0 bytes docs/docsite/rst/common/settings-menu.rst | 1 + docs/docsite/rst/release_notes/relnotes.rst | 9 + .../_swagger/{tower.css => awx-rest-api.css} | 0 .../rst/rest_api/_swagger/download-json.py | 13 + docs/docsite/rst/rest_api/api_ref.rst | 4 +- docs/docsite/rst/rest_api/index.rst | 2 +- .../rst/userguide/credential_plugins.rst | 28 +- docs/docsite/rst/userguide/insights.rst | 11 +- docs/docsite/rst/userguide/main_menu.rst | 15 +- .../rst/userguide/workflow_templates.rst | 103 ++-- docs/rbac.md | 24 +- licenses/django-ansible-base.txt | 168 +++++++ licenses/django-filter.txt | 24 + licenses/drf-spectacular.txt | 30 ++ licenses/inflection.txt | 19 + licenses/tabulate.txt | 20 + licenses/uritemplate.txt | 202 ++++++++ requirements/requirements.in | 4 +- requirements/requirements.txt | 51 +- requirements/requirements_dev.txt | 1 + requirements/requirements_git.txt | 1 + requirements/updater.sh | 8 +- .../roles/dockerfile/templates/Dockerfile.j2 | 5 +- .../templates/supervisor_rsyslog.conf.j2 | 12 +- .../ansible/roles/sources/defaults/main.yml | 18 + .../ansible/roles/sources/tasks/main.yml | 4 + .../ansible/roles/sources/tasks/vault_tls.yml | 31 ++ .../sources/templates/docker-compose.yml.j2 | 9 +- .../ansible/roles/vault/defaults/main.yml | 5 + .../ansible/roles/vault/tasks/initialize.yml | 60 ++- .../ansible/roles/vault/tasks/plumb.yml | 36 +- .../roles/vault/tasks/set_vault_addr.yml | 19 + .../ansible/roles/vault/tasks/unseal.yml | 6 +- tools/docker-compose/supervisor.conf | 75 ++- ...ure-event-handler => rsyslog-4xx-recovery} | 28 +- tox.ini | 4 +- 153 files changed, 2187 insertions(+), 961 deletions(-) create mode 100644 .github/dependabot.yml delete mode 100644 awx/api/filters.py create mode 100644 awx/api/templates/api/bulk_host_delete_view.md create mode 100644 awx/main/migrations/_sqlite_helper.py create mode 100644 awx/main/tests/functional/test_migrations.py create mode 100644 awx/ui/src/components/Schedule/shared/mergeArraysByCredentialType.js create mode 100644 awx_collection/plugins/modules/bulk_host_delete.py create mode 100644 awx_collection/test/awx/test_export.py create mode 100644 awx_collection/tests/integration/targets/bulk_host_delete/tasks/main.yml delete mode 100644 docs/docsite/rst/common/images/wf-activity-stream-events.png delete mode 100644 docs/docsite/rst/common/images/wf-editor-convergent-node-all.png create mode 100644 docs/docsite/rst/common/images/wf-editor-wizard-add-link-prompt.png delete mode 100644 docs/docsite/rst/common/images/wf-editor-wizard-buttons.png delete mode 100644 docs/docsite/rst/common/images/wf-template-job-detail-with-parent.png delete mode 100644 docs/docsite/rst/common/images/wf-template-jobs-detail-example.png rename docs/docsite/rst/rest_api/_swagger/{tower.css => awx-rest-api.css} (100%) create mode 100644 docs/docsite/rst/rest_api/_swagger/download-json.py create mode 100644 licenses/django-ansible-base.txt create mode 100644 licenses/django-filter.txt create mode 100644 licenses/drf-spectacular.txt create mode 100644 licenses/inflection.txt create mode 100644 licenses/tabulate.txt create mode 100644 licenses/uritemplate.txt create mode 100644 tools/docker-compose/ansible/roles/sources/tasks/vault_tls.yml create mode 100644 tools/docker-compose/ansible/roles/vault/tasks/set_vault_addr.yml rename tools/scripts/{failure-event-handler => rsyslog-4xx-recovery} (71%) diff --git a/.github/actions/run_awx_devel/action.yml b/.github/actions/run_awx_devel/action.yml index 80b02669cf82..79c795c85d77 100644 --- a/.github/actions/run_awx_devel/action.yml +++ b/.github/actions/run_awx_devel/action.yml @@ -43,10 +43,14 @@ runs: - name: Update default AWX password shell: bash run: | - while [[ "$(curl -s -o /dev/null -w ''%{http_code}'' -k https://localhost:8043/api/v2/ping/)" != "200" ]] - do - echo "Waiting for AWX..." - sleep 5 + SECONDS=0 + while [[ "$(curl -s -o /dev/null -w ''%{http_code}'' -k https://localhost:8043/api/v2/ping/)" != "200" ]]; do + if [[ $SECONDS -gt 600 ]]; then + echo "Timing out, AWX never came up" + exit 1 + fi + echo "Waiting for AWX..." + sleep 5 done echo "AWX is up, updating the password..." docker exec -i tools_awx_1 sh <<-EOSH diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000000..fe86573269c6 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,10 @@ +version: 2 +updates: + - package-ecosystem: "pip" + directory: "docs/docsite/" + schedule: + interval: "weekly" + open-pull-requests-limit: 2 + labels: + - "docs" + - "dependencies" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7612aa61c2aa..afdbd69eb610 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,6 +11,7 @@ jobs: common-tests: name: ${{ matrix.tests.name }} runs-on: ubuntu-latest + timeout-minutes: 60 permissions: packages: write contents: read @@ -20,6 +21,8 @@ jobs: tests: - name: api-test command: /start_tests.sh + - name: api-migrations + command: /start_tests.sh test_migrations - name: api-lint command: /var/lib/awx/venv/awx/bin/tox -e linters - name: api-swagger @@ -47,6 +50,7 @@ jobs: dev-env: runs-on: ubuntu-latest + timeout-minutes: 60 steps: - uses: actions/checkout@v3 @@ -61,6 +65,7 @@ jobs: awx-operator: runs-on: ubuntu-latest + timeout-minutes: 60 steps: - name: Checkout awx uses: actions/checkout@v3 @@ -110,6 +115,7 @@ jobs: collection-sanity: name: awx_collection sanity runs-on: ubuntu-latest + timeout-minutes: 30 strategy: fail-fast: false steps: @@ -129,6 +135,7 @@ jobs: collection-integration: name: awx_collection integration runs-on: ubuntu-latest + timeout-minutes: 60 strategy: fail-fast: false matrix: @@ -180,6 +187,7 @@ jobs: collection-integration-coverage-combine: name: combine awx_collection integration coverage runs-on: ubuntu-latest + timeout-minutes: 10 needs: - collection-integration strategy: diff --git a/.github/workflows/devel_images.yml b/.github/workflows/devel_images.yml index 179828be7d97..7f8c791bc4e7 100644 --- a/.github/workflows/devel_images.yml +++ b/.github/workflows/devel_images.yml @@ -12,6 +12,7 @@ jobs: push: if: endsWith(github.repository, '/awx') || startsWith(github.ref, 'refs/heads/release_') runs-on: ubuntu-latest + timeout-minutes: 60 permissions: packages: write contents: read diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index d50793210ea1..a5dc51fb59ca 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -6,6 +6,7 @@ jobs: docsite-build: name: docsite test build runs-on: ubuntu-latest + timeout-minutes: 30 steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/feature_branch_deletion.yml b/.github/workflows/feature_branch_deletion.yml index 3e574b211b80..3fbd287cb126 100644 --- a/.github/workflows/feature_branch_deletion.yml +++ b/.github/workflows/feature_branch_deletion.yml @@ -9,6 +9,7 @@ on: jobs: push: runs-on: ubuntu-latest + timeout-minutes: 20 permissions: packages: write contents: read diff --git a/.github/workflows/label_issue.yml b/.github/workflows/label_issue.yml index f33efab60015..c5a2b2c7cb4c 100644 --- a/.github/workflows/label_issue.yml +++ b/.github/workflows/label_issue.yml @@ -13,6 +13,7 @@ permissions: jobs: triage: runs-on: ubuntu-latest + timeout-minutes: 20 name: Label Issue steps: @@ -26,6 +27,7 @@ jobs: community: runs-on: ubuntu-latest + timeout-minutes: 20 name: Label Issue - Community steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/label_pr.yml b/.github/workflows/label_pr.yml index 6ee5a34e8b7d..15571a866cf2 100644 --- a/.github/workflows/label_pr.yml +++ b/.github/workflows/label_pr.yml @@ -14,6 +14,7 @@ permissions: jobs: triage: runs-on: ubuntu-latest + timeout-minutes: 20 name: Label PR steps: @@ -25,6 +26,7 @@ jobs: community: runs-on: ubuntu-latest + timeout-minutes: 20 name: Label PR - Community steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/pr_body_check.yml b/.github/workflows/pr_body_check.yml index 7af1914bb4c0..9532aa87ede1 100644 --- a/.github/workflows/pr_body_check.yml +++ b/.github/workflows/pr_body_check.yml @@ -10,6 +10,7 @@ jobs: if: github.repository_owner == 'ansible' && endsWith(github.repository, 'awx') name: Scan PR description for semantic versioning keywords runs-on: ubuntu-latest + timeout-minutes: 20 permissions: packages: write contents: read diff --git a/.github/workflows/promote.yml b/.github/workflows/promote.yml index 444ed9594697..81a7878d6e80 100644 --- a/.github/workflows/promote.yml +++ b/.github/workflows/promote.yml @@ -13,8 +13,9 @@ permissions: jobs: promote: - if: endsWith(github.repository, '/awx') + if: endsWith(github.repository, '/awx') runs-on: ubuntu-latest + timeout-minutes: 90 steps: - name: Checkout awx uses: actions/checkout@v3 @@ -46,7 +47,7 @@ jobs: COLLECTION_TEMPLATE_VERSION: true run: | make build_collection - if [ "$(curl --head -sw '%{http_code}' https://galaxy.ansible.com/download/${{ env.collection_namespace }}-awx-${{ github.event.release.tag_name }}.tar.gz | tail -1)" == "302" ] ; then \ + if [ "$(curl -L --head -sw '%{http_code}' https://galaxy.ansible.com/download/${{ env.collection_namespace }}-awx-${{ github.event.release.tag_name }}.tar.gz | tail -1)" == "302" ] ; then \ echo "Galaxy release already done"; \ else \ ansible-galaxy collection publish \ diff --git a/.github/workflows/stage.yml b/.github/workflows/stage.yml index aab4ad83a500..f38cda55ec20 100644 --- a/.github/workflows/stage.yml +++ b/.github/workflows/stage.yml @@ -23,6 +23,7 @@ jobs: stage: if: endsWith(github.repository, '/awx') runs-on: ubuntu-latest + timeout-minutes: 90 permissions: packages: write contents: write diff --git a/.github/workflows/update_dependabot_prs.yml b/.github/workflows/update_dependabot_prs.yml index a61eb1c17222..bcb0b7674a70 100644 --- a/.github/workflows/update_dependabot_prs.yml +++ b/.github/workflows/update_dependabot_prs.yml @@ -9,6 +9,7 @@ jobs: name: Update Dependabot Prs if: contains(github.event.pull_request.labels.*.name, 'dependencies') && contains(github.event.pull_request.labels.*.name, 'component:ui') runs-on: ubuntu-latest + timeout-minutes: 20 steps: - name: Checkout branch diff --git a/.github/workflows/upload_schema.yml b/.github/workflows/upload_schema.yml index ae4e23d977ae..0b7bc7bf6e6d 100644 --- a/.github/workflows/upload_schema.yml +++ b/.github/workflows/upload_schema.yml @@ -13,6 +13,7 @@ on: jobs: push: runs-on: ubuntu-latest + timeout-minutes: 60 permissions: packages: write contents: read diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 0c11aab82f67..9376ce0e342b 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -10,6 +10,7 @@ build: 3.11 commands: - pip install --user tox - - python3 -m tox -e docs + - python3 -m tox -e docs --notest -v + - python3 -m tox -e docs --skip-pkg-install -q - mkdir -p _readthedocs/html/ - mv docs/docsite/build/html/* _readthedocs/html/ diff --git a/MANIFEST.in b/MANIFEST.in index 09a5392c509b..3db512ee138f 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -22,7 +22,7 @@ recursive-exclude awx/settings local_settings.py* include tools/scripts/request_tower_configuration.sh include tools/scripts/request_tower_configuration.ps1 include tools/scripts/automation-controller-service -include tools/scripts/failure-event-handler +include tools/scripts/rsyslog-4xx-recovery include tools/scripts/awx-python include awx/playbooks/library/mkfifo.py include tools/sosreport/* diff --git a/Makefile b/Makefile index 25005bdc9d6c..6d3411edc933 100644 --- a/Makefile +++ b/Makefile @@ -43,6 +43,8 @@ PROMETHEUS ?= false GRAFANA ?= false # If set to true docker-compose will also start a hashicorp vault instance VAULT ?= false +# If set to true docker-compose will also start a hashicorp vault instance with TLS enabled +VAULT_TLS ?= false # If set to true docker-compose will also start a tacacs+ instance TACACS ?= false @@ -61,7 +63,7 @@ RECEPTOR_IMAGE ?= quay.io/ansible/receptor:devel SRC_ONLY_PKGS ?= cffi,pycparser,psycopg,twilio # These should be upgraded in the AWX and Ansible venv before attempting # to install the actual requirements -VENV_BOOTSTRAP ?= pip==21.2.4 setuptools==65.6.3 setuptools_scm[toml]==7.0.5 wheel==0.38.4 +VENV_BOOTSTRAP ?= pip==21.2.4 setuptools==65.6.3 setuptools_scm[toml]==8.0.4 wheel==0.38.4 NAME ?= awx @@ -324,6 +326,12 @@ test: cd awxkit && $(VENV_BASE)/awx/bin/tox -re py3 awx-manage check_migrations --dry-run --check -n 'missing_migration_file' +test_migrations: + if [ "$(VENV_BASE)" ]; then \ + . $(VENV_BASE)/awx/bin/activate; \ + fi; \ + PYTHONDONTWRITEBYTECODE=1 py.test -p no:cacheprovider --migrations -m migration_test $(PYTEST_ARGS) $(TEST_DIRS) + ## Runs AWX_DOCKER_CMD inside a new docker container. docker-runner: docker run -u $(shell id -u) --rm -v $(shell pwd):/awx_devel/:Z --workdir=/awx_devel $(DEVEL_IMAGE_NAME) $(AWX_DOCKER_CMD) @@ -522,13 +530,15 @@ docker-compose-sources: .git/hooks/pre-commit -e enable_prometheus=$(PROMETHEUS) \ -e enable_grafana=$(GRAFANA) \ -e enable_vault=$(VAULT) \ + -e vault_tls=$(VAULT_TLS) \ -e enable_tacacs=$(TACACS) \ $(EXTRA_SOURCES_ANSIBLE_OPTS) docker-compose: awx/projects docker-compose-sources ansible-galaxy install --ignore-certs -r tools/docker-compose/ansible/requirements.yml; ansible-playbook -i tools/docker-compose/inventory tools/docker-compose/ansible/initialize_containers.yml \ - -e enable_vault=$(VAULT); + -e enable_vault=$(VAULT) \ + -e vault_tls=$(VAULT_TLS); $(DOCKER_COMPOSE) -f tools/docker-compose/_sources/docker-compose.yml $(COMPOSE_OPTS) up $(COMPOSE_UP_OPTS) --remove-orphans docker-compose-credential-plugins: awx/projects docker-compose-sources diff --git a/awx/api/filters.py b/awx/api/filters.py deleted file mode 100644 index 6169dc548afc..000000000000 --- a/awx/api/filters.py +++ /dev/null @@ -1,450 +0,0 @@ -# Copyright (c) 2015 Ansible, Inc. -# All Rights Reserved. - -# Python -import re -import json -from functools import reduce - -# Django -from django.core.exceptions import FieldError, ValidationError, FieldDoesNotExist -from django.db import models -from django.db.models import Q, CharField, IntegerField, BooleanField, TextField, JSONField -from django.db.models.fields.related import ForeignObjectRel, ManyToManyField, ForeignKey -from django.db.models.functions import Cast -from django.contrib.contenttypes.models import ContentType -from django.contrib.contenttypes.fields import GenericForeignKey -from django.utils.encoding import force_str -from django.utils.translation import gettext_lazy as _ - -# Django REST Framework -from rest_framework.exceptions import ParseError, PermissionDenied -from rest_framework.filters import BaseFilterBackend - -# AWX -from awx.main.utils import get_type_for_model, to_python_boolean -from awx.main.utils.db import get_all_field_names - - -class TypeFilterBackend(BaseFilterBackend): - """ - Filter on type field now returned with all objects. - """ - - def filter_queryset(self, request, queryset, view): - try: - types = None - for key, value in request.query_params.items(): - if key == 'type': - if ',' in value: - types = value.split(',') - else: - types = (value,) - if types: - types_map = {} - for ct in ContentType.objects.filter(Q(app_label='main') | Q(app_label='auth', model='user')): - ct_model = ct.model_class() - if not ct_model: - continue - ct_type = get_type_for_model(ct_model) - types_map[ct_type] = ct.pk - model = queryset.model - model_type = get_type_for_model(model) - if 'polymorphic_ctype' in get_all_field_names(model): - types_pks = set([v for k, v in types_map.items() if k in types]) - queryset = queryset.filter(polymorphic_ctype_id__in=types_pks) - elif model_type in types: - queryset = queryset - else: - queryset = queryset.none() - return queryset - except FieldError as e: - # Return a 400 for invalid field names. - raise ParseError(*e.args) - - -def get_fields_from_path(model, path): - """ - Given a Django ORM lookup path (possibly over multiple models) - Returns the fields in the line, and also the revised lookup path - ex., given - model=Organization - path='project__timeout' - returns tuple of fields traversed as well and a corrected path, - for special cases we do substitutions - ([], 'project__timeout') - """ - # Store of all the fields used to detect repeats - field_list = [] - new_parts = [] - for name in path.split('__'): - if model is None: - raise ParseError(_('No related model for field {}.').format(name)) - # HACK: Make project and inventory source filtering by old field names work for backwards compatibility. - if model._meta.object_name in ('Project', 'InventorySource'): - name = {'current_update': 'current_job', 'last_update': 'last_job', 'last_update_failed': 'last_job_failed', 'last_updated': 'last_job_run'}.get( - name, name - ) - - if name == 'type' and 'polymorphic_ctype' in get_all_field_names(model): - name = 'polymorphic_ctype' - new_parts.append('polymorphic_ctype__model') - else: - new_parts.append(name) - - if name in getattr(model, 'PASSWORD_FIELDS', ()): - raise PermissionDenied(_('Filtering on password fields is not allowed.')) - elif name == 'pk': - field = model._meta.pk - else: - name_alt = name.replace("_", "") - if name_alt in model._meta.fields_map.keys(): - field = model._meta.fields_map[name_alt] - new_parts.pop() - new_parts.append(name_alt) - else: - field = model._meta.get_field(name) - if isinstance(field, ForeignObjectRel) and getattr(field.field, '__prevent_search__', False): - raise PermissionDenied(_('Filtering on %s is not allowed.' % name)) - elif getattr(field, '__prevent_search__', False): - raise PermissionDenied(_('Filtering on %s is not allowed.' % name)) - if field in field_list: - # Field traversed twice, could create infinite JOINs, DoSing Tower - raise ParseError(_('Loops not allowed in filters, detected on field {}.').format(field.name)) - field_list.append(field) - model = getattr(field, 'related_model', None) - - return field_list, '__'.join(new_parts) - - -def get_field_from_path(model, path): - """ - Given a Django ORM lookup path (possibly over multiple models) - Returns the last field in the line, and the revised lookup path - ex. - (, 'project__timeout') - """ - field_list, new_path = get_fields_from_path(model, path) - return (field_list[-1], new_path) - - -class FieldLookupBackend(BaseFilterBackend): - """ - Filter using field lookups provided via query string parameters. - """ - - RESERVED_NAMES = ('page', 'page_size', 'format', 'order', 'order_by', 'search', 'type', 'host_filter', 'count_disabled', 'no_truncate', 'limit') - - SUPPORTED_LOOKUPS = ( - 'exact', - 'iexact', - 'contains', - 'icontains', - 'startswith', - 'istartswith', - 'endswith', - 'iendswith', - 'regex', - 'iregex', - 'gt', - 'gte', - 'lt', - 'lte', - 'in', - 'isnull', - 'search', - ) - - # A list of fields that we know can be filtered on without the possibility - # of introducing duplicates - NO_DUPLICATES_ALLOW_LIST = (CharField, IntegerField, BooleanField, TextField) - - def get_fields_from_lookup(self, model, lookup): - if '__' in lookup and lookup.rsplit('__', 1)[-1] in self.SUPPORTED_LOOKUPS: - path, suffix = lookup.rsplit('__', 1) - else: - path = lookup - suffix = 'exact' - - if not path: - raise ParseError(_('Query string field name not provided.')) - - # FIXME: Could build up a list of models used across relationships, use - # those lookups combined with request.user.get_queryset(Model) to make - # sure user cannot query using objects he could not view. - field_list, new_path = get_fields_from_path(model, path) - - new_lookup = new_path - new_lookup = '__'.join([new_path, suffix]) - return field_list, new_lookup - - def get_field_from_lookup(self, model, lookup): - '''Method to match return type of single field, if needed.''' - field_list, new_lookup = self.get_fields_from_lookup(model, lookup) - return (field_list[-1], new_lookup) - - def to_python_related(self, value): - value = force_str(value) - if value.lower() in ('none', 'null'): - return None - else: - return int(value) - - def value_to_python_for_field(self, field, value): - if isinstance(field, models.BooleanField): - return to_python_boolean(value) - elif isinstance(field, (ForeignObjectRel, ManyToManyField, GenericForeignKey, ForeignKey)): - try: - return self.to_python_related(value) - except ValueError: - raise ParseError(_('Invalid {field_name} id: {field_id}').format(field_name=getattr(field, 'name', 'related field'), field_id=value)) - else: - return field.to_python(value) - - def value_to_python(self, model, lookup, value): - try: - lookup.encode("ascii") - except UnicodeEncodeError: - raise ValueError("%r is not an allowed field name. Must be ascii encodable." % lookup) - - field_list, new_lookup = self.get_fields_from_lookup(model, lookup) - field = field_list[-1] - - needs_distinct = not all(isinstance(f, self.NO_DUPLICATES_ALLOW_LIST) for f in field_list) - - # Type names are stored without underscores internally, but are presented and - # and serialized over the API containing underscores so we remove `_` - # for polymorphic_ctype__model lookups. - if new_lookup.startswith('polymorphic_ctype__model'): - value = value.replace('_', '') - elif new_lookup.endswith('__isnull'): - value = to_python_boolean(value) - elif new_lookup.endswith('__in'): - items = [] - if not value: - raise ValueError('cannot provide empty value for __in') - for item in value.split(','): - items.append(self.value_to_python_for_field(field, item)) - value = items - elif new_lookup.endswith('__regex') or new_lookup.endswith('__iregex'): - try: - re.compile(value) - except re.error as e: - raise ValueError(e.args[0]) - elif new_lookup.endswith('__iexact'): - if not isinstance(field, (CharField, TextField)): - raise ValueError(f'{field.name} is not a text field and cannot be filtered by case-insensitive search') - elif new_lookup.endswith('__search'): - related_model = getattr(field, 'related_model', None) - if not related_model: - raise ValueError('%s is not searchable' % new_lookup[:-8]) - new_lookups = [] - for rm_field in related_model._meta.fields: - if rm_field.name in ('username', 'first_name', 'last_name', 'email', 'name', 'description', 'playbook'): - new_lookups.append('{}__{}__icontains'.format(new_lookup[:-8], rm_field.name)) - return value, new_lookups, needs_distinct - else: - if isinstance(field, JSONField): - new_lookup = new_lookup.replace(field.name, f'{field.name}_as_txt') - value = self.value_to_python_for_field(field, value) - return value, new_lookup, needs_distinct - - def filter_queryset(self, request, queryset, view): - try: - # Apply filters specified via query_params. Each entry in the lists - # below is (negate, field, value). - and_filters = [] - or_filters = [] - chain_filters = [] - role_filters = [] - search_filters = {} - needs_distinct = False - # Can only have two values: 'AND', 'OR' - # If 'AND' is used, an item must satisfy all conditions to show up in the results. - # If 'OR' is used, an item just needs to satisfy one condition to appear in results. - search_filter_relation = 'OR' - for key, values in request.query_params.lists(): - if key in self.RESERVED_NAMES: - continue - - # HACK: make `created` available via API for the Django User ORM model - # so it keep compatibility with other objects which exposes the `created` attr. - if queryset.model._meta.object_name == 'User' and key.startswith('created'): - key = key.replace('created', 'date_joined') - - # HACK: Make job event filtering by host name mostly work even - # when not capturing job event hosts M2M. - if queryset.model._meta.object_name == 'JobEvent' and key.startswith('hosts__name'): - key = key.replace('hosts__name', 'or__host__name') - or_filters.append((False, 'host__name__isnull', True)) - - # Custom __int filter suffix (internal use only). - q_int = False - if key.endswith('__int'): - key = key[:-5] - q_int = True - - # RBAC filtering - if key == 'role_level': - role_filters.append(values[0]) - continue - - # Search across related objects. - if key.endswith('__search'): - if values and ',' in values[0]: - search_filter_relation = 'AND' - values = reduce(lambda list1, list2: list1 + list2, [i.split(',') for i in values]) - for value in values: - search_value, new_keys, _ = self.value_to_python(queryset.model, key, force_str(value)) - assert isinstance(new_keys, list) - search_filters[search_value] = new_keys - # by definition, search *only* joins across relations, - # so it _always_ needs a .distinct() - needs_distinct = True - continue - - # Custom chain__ and or__ filters, mutually exclusive (both can - # precede not__). - q_chain = False - q_or = False - if key.startswith('chain__'): - key = key[7:] - q_chain = True - elif key.startswith('or__'): - key = key[4:] - q_or = True - - # Custom not__ filter prefix. - q_not = False - if key.startswith('not__'): - key = key[5:] - q_not = True - - # Convert value(s) to python and add to the appropriate list. - for value in values: - if q_int: - value = int(value) - value, new_key, distinct = self.value_to_python(queryset.model, key, value) - if distinct: - needs_distinct = True - if '_as_txt' in new_key: - fname = next(item for item in new_key.split('__') if item.endswith('_as_txt')) - queryset = queryset.annotate(**{fname: Cast(fname[:-7], output_field=TextField())}) - if q_chain: - chain_filters.append((q_not, new_key, value)) - elif q_or: - or_filters.append((q_not, new_key, value)) - else: - and_filters.append((q_not, new_key, value)) - - # Now build Q objects for database query filter. - if and_filters or or_filters or chain_filters or role_filters or search_filters: - args = [] - for n, k, v in and_filters: - if n: - args.append(~Q(**{k: v})) - else: - args.append(Q(**{k: v})) - for role_name in role_filters: - if not hasattr(queryset.model, 'accessible_pk_qs'): - raise ParseError(_('Cannot apply role_level filter to this list because its model does not use roles for access control.')) - args.append(Q(pk__in=queryset.model.accessible_pk_qs(request.user, role_name))) - if or_filters: - q = Q() - for n, k, v in or_filters: - if n: - q |= ~Q(**{k: v}) - else: - q |= Q(**{k: v}) - args.append(q) - if search_filters and search_filter_relation == 'OR': - q = Q() - for term, constrains in search_filters.items(): - for constrain in constrains: - q |= Q(**{constrain: term}) - args.append(q) - elif search_filters and search_filter_relation == 'AND': - for term, constrains in search_filters.items(): - q_chain = Q() - for constrain in constrains: - q_chain |= Q(**{constrain: term}) - queryset = queryset.filter(q_chain) - for n, k, v in chain_filters: - if n: - q = ~Q(**{k: v}) - else: - q = Q(**{k: v}) - queryset = queryset.filter(q) - queryset = queryset.filter(*args) - if needs_distinct: - queryset = queryset.distinct() - return queryset - except (FieldError, FieldDoesNotExist, ValueError, TypeError) as e: - raise ParseError(e.args[0]) - except ValidationError as e: - raise ParseError(json.dumps(e.messages, ensure_ascii=False)) - - -class OrderByBackend(BaseFilterBackend): - """ - Filter to apply ordering based on query string parameters. - """ - - def filter_queryset(self, request, queryset, view): - try: - order_by = None - for key, value in request.query_params.items(): - if key in ('order', 'order_by'): - order_by = value - if ',' in value: - order_by = value.split(',') - else: - order_by = (value,) - default_order_by = self.get_default_ordering(view) - # glue the order by and default order by together so that the default is the backup option - order_by = list(order_by or []) + list(default_order_by or []) - if order_by: - order_by = self._validate_ordering_fields(queryset.model, order_by) - # Special handling of the type field for ordering. In this - # case, we're not sorting exactly on the type field, but - # given the limited number of views with multiple types, - # sorting on polymorphic_ctype.model is effectively the same. - new_order_by = [] - if 'polymorphic_ctype' in get_all_field_names(queryset.model): - for field in order_by: - if field == 'type': - new_order_by.append('polymorphic_ctype__model') - elif field == '-type': - new_order_by.append('-polymorphic_ctype__model') - else: - new_order_by.append(field) - else: - for field in order_by: - if field not in ('type', '-type'): - new_order_by.append(field) - queryset = queryset.order_by(*new_order_by) - return queryset - except FieldError as e: - # Return a 400 for invalid field names. - raise ParseError(*e.args) - - def get_default_ordering(self, view): - ordering = getattr(view, 'ordering', None) - if isinstance(ordering, str): - return (ordering,) - return ordering - - def _validate_ordering_fields(self, model, order_by): - for field_name in order_by: - # strip off the negation prefix `-` if it exists - prefix = '' - path = field_name - if field_name[0] == '-': - prefix = field_name[0] - path = field_name[1:] - try: - field, new_path = get_field_from_path(model, path) - new_path = '{}{}'.format(prefix, new_path) - except (FieldError, FieldDoesNotExist) as e: - raise ParseError(e.args[0]) - yield new_path diff --git a/awx/api/generics.py b/awx/api/generics.py index 0c16a3790f3d..1081b02c7204 100644 --- a/awx/api/generics.py +++ b/awx/api/generics.py @@ -30,12 +30,13 @@ from rest_framework.renderers import StaticHTMLRenderer from rest_framework.negotiation import DefaultContentNegotiation +from ansible_base.filters.rest_framework.field_lookup_backend import FieldLookupBackend +from ansible_base.utils.models import get_all_field_names + # AWX -from awx.api.filters import FieldLookupBackend from awx.main.models import UnifiedJob, UnifiedJobTemplate, User, Role, Credential, WorkflowJobTemplateNode, WorkflowApprovalTemplate from awx.main.access import optimize_queryset from awx.main.utils import camelcase_to_underscore, get_search_fields, getattrd, get_object_or_400, decrypt_field, get_awx_version -from awx.main.utils.db import get_all_field_names from awx.main.utils.licensing import server_product_name from awx.main.views import ApiErrorView from awx.api.serializers import ResourceAccessListElementSerializer, CopySerializer diff --git a/awx/api/serializers.py b/awx/api/serializers.py index 392a068d06de..523b21af827b 100644 --- a/awx/api/serializers.py +++ b/awx/api/serializers.py @@ -43,6 +43,8 @@ # Django-Polymorphic from polymorphic.models import PolymorphicModel +from ansible_base.utils.models import get_type_for_model + # AWX from awx.main.access import get_user_capabilities from awx.main.constants import ACTIVE_STATES, CENSOR_VALUE @@ -99,10 +101,9 @@ CLOUD_INVENTORY_SOURCES, ) from awx.main.models.base import VERBOSITY_CHOICES, NEW_JOB_TYPE_CHOICES -from awx.main.models.rbac import get_roles_on_resource, role_summary_fields_generator +from awx.main.models.rbac import role_summary_fields_generator, RoleAncestorEntry from awx.main.fields import ImplicitRoleField from awx.main.utils import ( - get_type_for_model, get_model_for_type, camelcase_to_underscore, getattrd, @@ -2201,6 +2202,99 @@ def create(self, validated_data): return return_data +class BulkHostDeleteSerializer(serializers.Serializer): + hosts = serializers.ListField( + allow_empty=False, + max_length=100000, + write_only=True, + help_text=_('List of hosts ids to be deleted, e.g. [105, 130, 131, 200]'), + ) + + class Meta: + model = Host + fields = ('hosts',) + + def validate(self, attrs): + request = self.context.get('request', None) + max_hosts = settings.BULK_HOST_MAX_DELETE + # Validating the number of hosts to be deleted + if len(attrs['hosts']) > max_hosts: + raise serializers.ValidationError( + { + "ERROR": 'Number of hosts exceeds system setting BULK_HOST_MAX_DELETE', + "BULK_HOST_MAX_DELETE": max_hosts, + "Hosts_count": len(attrs['hosts']), + } + ) + + # Getting list of all host objects, filtered by the list of the hosts to delete + attrs['host_qs'] = Host.objects.get_queryset().filter(pk__in=attrs['hosts']).only('id', 'inventory_id', 'name') + + # Converting the queryset data in a dict. to reduce the number of queries when + # manipulating the data + attrs['hosts_data'] = attrs['host_qs'].values() + + if len(attrs['host_qs']) == 0: + error_hosts = {host: "Hosts do not exist or you lack permission to delete it" for host in attrs['hosts']} + raise serializers.ValidationError({'hosts': error_hosts}) + + if len(attrs['host_qs']) < len(attrs['hosts']): + hosts_exists = [host['id'] for host in attrs['hosts_data']] + failed_hosts = list(set(attrs['hosts']).difference(hosts_exists)) + error_hosts = {host: "Hosts do not exist or you lack permission to delete it" for host in failed_hosts} + raise serializers.ValidationError({'hosts': error_hosts}) + + # Getting all inventories that the hosts can be in + inv_list = list(set([host['inventory_id'] for host in attrs['hosts_data']])) + + # Checking that the user have permission to all inventories + errors = dict() + for inv in Inventory.objects.get_queryset().filter(pk__in=inv_list): + if request and not request.user.is_superuser: + if request.user not in inv.admin_role: + errors[inv.name] = "Lack permissions to delete hosts from this inventory." + if errors != {}: + raise PermissionDenied({"inventories": errors}) + + # check the inventory type only if the user have permission to it. + errors = dict() + for inv in Inventory.objects.get_queryset().filter(pk__in=inv_list): + if inv.kind != '': + errors[inv.name] = "Hosts can only be deleted from manual inventories." + if errors != {}: + raise serializers.ValidationError({"inventories": errors}) + attrs['inventories'] = inv_list + return attrs + + def delete(self, validated_data): + result = {"hosts": dict()} + changes = {'deleted_hosts': dict()} + for inventory in validated_data['inventories']: + changes['deleted_hosts'][inventory] = list() + + for host in validated_data['hosts_data']: + result["hosts"][host["id"]] = f"The host {host['name']} was deleted" + changes['deleted_hosts'][host["inventory_id"]].append({"host_id": host["id"], "host_name": host["name"]}) + + try: + validated_data['host_qs'].delete() + except Exception as e: + raise serializers.ValidationError({"detail": _(f"cannot delete hosts, host deletion error {e}")}) + + request = self.context.get('request', None) + + for inventory in validated_data['inventories']: + activity_entry = ActivityStream.objects.create( + operation='update', + object1='inventory', + changes=json.dumps(changes['deleted_hosts'][inventory]), + actor=request.user, + ) + activity_entry.inventory.add(inventory) + + return result + + class GroupTreeSerializer(GroupSerializer): children = serializers.SerializerMethodField() @@ -2664,6 +2758,17 @@ def to_representation(self, user): if 'summary_fields' not in ret: ret['summary_fields'] = {} + team_content_type = ContentType.objects.get_for_model(Team) + content_type = ContentType.objects.get_for_model(obj) + + def get_roles_on_resource(parent_role): + "Returns a string list of the roles a parent_role has for current obj." + return list( + RoleAncestorEntry.objects.filter(ancestor=parent_role, content_type_id=content_type.id, object_id=obj.id) + .values_list('role_field', flat=True) + .distinct() + ) + def format_role_perm(role): role_dict = {'id': role.id, 'name': role.name, 'description': role.description} try: @@ -2679,7 +2784,7 @@ def format_role_perm(role): else: # Singleton roles should not be managed from this view, as per copy/edit rework spec role_dict['user_capabilities'] = {'unattach': False} - return {'role': role_dict, 'descendant_roles': get_roles_on_resource(obj, role)} + return {'role': role_dict, 'descendant_roles': get_roles_on_resource(role)} def format_team_role_perm(naive_team_role, permissive_role_ids): ret = [] @@ -2705,12 +2810,9 @@ def format_team_role_perm(naive_team_role, permissive_role_ids): else: # Singleton roles should not be managed from this view, as per copy/edit rework spec role_dict['user_capabilities'] = {'unattach': False} - ret.append({'role': role_dict, 'descendant_roles': get_roles_on_resource(obj, team_role)}) + ret.append({'role': role_dict, 'descendant_roles': get_roles_on_resource(team_role)}) return ret - team_content_type = ContentType.objects.get_for_model(Team) - content_type = ContentType.objects.get_for_model(obj) - direct_permissive_role_ids = Role.objects.filter(content_type=content_type, object_id=obj.id).values_list('id', flat=True) all_permissive_role_ids = Role.objects.filter(content_type=content_type, object_id=obj.id).values_list('ancestors__id', flat=True) diff --git a/awx/api/templates/api/bulk_host_delete_view.md b/awx/api/templates/api/bulk_host_delete_view.md new file mode 100644 index 000000000000..1fff2a7e3c91 --- /dev/null +++ b/awx/api/templates/api/bulk_host_delete_view.md @@ -0,0 +1,22 @@ +# Bulk Host Delete + +This endpoint allows the client to delete multiple hosts from inventories. +They may do this by providing a list of hosts ID's to be deleted. + +Example: + + { + "hosts": [1, 2, 3, 4, 5] + } + +Return data: + + { + "hosts": { + "1": "The host a1 was deleted", + "2": "The host a2 was deleted", + "3": "The host a3 was deleted", + "4": "The host a4 was deleted", + "5": "The host a5 was deleted", + } + } \ No newline at end of file diff --git a/awx/api/urls/urls.py b/awx/api/urls/urls.py index c74f9f97e6c7..030ba25edef5 100644 --- a/awx/api/urls/urls.py +++ b/awx/api/urls/urls.py @@ -36,6 +36,7 @@ from awx.api.views.bulk import ( BulkView, BulkHostCreateView, + BulkHostDeleteView, BulkJobLaunchView, ) @@ -152,6 +153,7 @@ re_path(r'^workflow_approvals/', include(workflow_approval_urls)), re_path(r'^bulk/$', BulkView.as_view(), name='bulk'), re_path(r'^bulk/host_create/$', BulkHostCreateView.as_view(), name='bulk_host_create'), + re_path(r'^bulk/host_delete/$', BulkHostDeleteView.as_view(), name='bulk_host_delete'), re_path(r'^bulk/job_launch/$', BulkJobLaunchView.as_view(), name='bulk_job_launch'), ] diff --git a/awx/api/views/__init__.py b/awx/api/views/__init__.py index 0511b696645d..80fc152bf404 100644 --- a/awx/api/views/__init__.py +++ b/awx/api/views/__init__.py @@ -128,6 +128,10 @@ def unpartitioned_event_horizon(cls): + with connection.cursor() as cursor: + cursor.execute(f"SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE table_name = '_unpartitioned_{cls._meta.db_table}';") + if not cursor.fetchone(): + return 0 with connection.cursor() as cursor: try: cursor.execute(f'SELECT MAX(id) FROM _unpartitioned_{cls._meta.db_table}') @@ -738,8 +742,8 @@ def get_queryset(self): qs = self.request.user.get_queryset(self.model) return qs.filter( Q(team=parent) - | Q(project__in=models.Project.accessible_objects(parent, 'read_role')) - | Q(credential__in=models.Credential.accessible_objects(parent, 'read_role')) + | Q(project__in=models.Project.accessible_objects(parent.member_role, 'read_role')) + | Q(credential__in=models.Credential.accessible_objects(parent.member_role, 'read_role')) ) @@ -1393,7 +1397,7 @@ def get_queryset(self): self.check_parent_access(organization) user_visible = models.Credential.accessible_objects(self.request.user, 'read_role').all() - org_set = models.Credential.accessible_objects(organization.admin_role, 'read_role').all() + org_set = models.Credential.objects.filter(organization=organization) if self.request.user.is_superuser or self.request.user.is_system_auditor: return org_set diff --git a/awx/api/views/bulk.py b/awx/api/views/bulk.py index f8d52354ceea..a78dc43a3735 100644 --- a/awx/api/views/bulk.py +++ b/awx/api/views/bulk.py @@ -34,6 +34,7 @@ def get(self, request, format=None): '''List top level resources''' data = OrderedDict() data['host_create'] = reverse('api:bulk_host_create', request=request) + data['host_delete'] = reverse('api:bulk_host_delete', request=request) data['job_launch'] = reverse('api:bulk_job_launch', request=request) return Response(data) @@ -72,3 +73,20 @@ def post(self, request): result = serializer.create(serializer.validated_data) return Response(result, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + +class BulkHostDeleteView(GenericAPIView): + permission_classes = [IsAuthenticated] + model = Host + serializer_class = serializers.BulkHostDeleteSerializer + allowed_methods = ['GET', 'POST', 'OPTIONS'] + + def get(self, request): + return Response({"detail": "Bulk delete hosts with this endpoint"}, status=status.HTTP_200_OK) + + def post(self, request): + serializer = serializers.BulkHostDeleteSerializer(data=request.data, context={'request': request}) + if serializer.is_valid(): + result = serializer.delete(serializer.validated_data) + return Response(result, status=status.HTTP_201_CREATED) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) diff --git a/awx/conf/models.py b/awx/conf/models.py index 25cf0cd5846c..91274140fbae 100644 --- a/awx/conf/models.py +++ b/awx/conf/models.py @@ -7,8 +7,10 @@ # Django from django.db import models +from ansible_base.utils.models import prevent_search + # AWX -from awx.main.models.base import CreatedModifiedModel, prevent_search +from awx.main.models.base import CreatedModifiedModel from awx.main.utils import encrypt_field from awx.conf import settings_registry diff --git a/awx/main/access.py b/awx/main/access.py index 730c0decf779..6b57723e5b7e 100644 --- a/awx/main/access.py +++ b/awx/main/access.py @@ -20,11 +20,12 @@ # Django OAuth Toolkit from awx.main.models.oauth import OAuth2Application, OAuth2AccessToken +from ansible_base.utils.validation import to_python_boolean + # AWX from awx.main.utils import ( get_object_or_400, get_pk_from_dict, - to_python_boolean, get_licenser, ) from awx.main.models import ( @@ -79,7 +80,6 @@ 'get_user_queryset', 'check_user_access', 'check_user_access_with_errors', - 'user_accessible_objects', 'consumer_access', ] @@ -136,10 +136,6 @@ def register_access(model_class, access_class): access_registry[model_class] = access_class -def user_accessible_objects(user, role_name): - return ResourceMixin._accessible_objects(User, user, role_name) - - def get_user_queryset(user, model_class): """ Return a queryset for the given model_class containing only the instances diff --git a/awx/main/conf.py b/awx/main/conf.py index e11bb15ae456..e50aac8caf7e 100644 --- a/awx/main/conf.py +++ b/awx/main/conf.py @@ -827,6 +827,16 @@ category_slug='bulk', ) +register( + 'BULK_HOST_MAX_DELETE', + field_class=fields.IntegerField, + default=250, + label=_('Max number of hosts to allow to be deleted in a single bulk action'), + help_text=_('Max number of hosts to allow to be deleted in a single bulk action'), + category=_('Bulk Actions'), + category_slug='bulk', +) + register( 'UI_NEXT', field_class=fields.BooleanField, diff --git a/awx/main/credential_plugins/dsv.py b/awx/main/credential_plugins/dsv.py index 6e9441ed95fd..7dc74cab913a 100644 --- a/awx/main/credential_plugins/dsv.py +++ b/awx/main/credential_plugins/dsv.py @@ -3,6 +3,7 @@ from django.conf import settings from django.utils.translation import gettext_lazy as _ from delinea.secrets.vault import PasswordGrantAuthorizer, SecretsVault +from base64 import b64decode dsv_inputs = { 'fields': [ @@ -44,8 +45,16 @@ 'help_text': _('The field to extract from the secret'), 'type': 'string', }, + { + 'id': 'secret_decoding', + 'label': _('Should the secret be base64 decoded?'), + 'help_text': _('Specify whether the secret should be base64 decoded, typically used for storing files, such as SSH keys'), + 'choices': ['No Decoding', 'Decode Base64'], + 'type': 'string', + 'default': 'No Decoding', + }, ], - 'required': ['tenant', 'client_id', 'client_secret', 'path', 'secret_field'], + 'required': ['tenant', 'client_id', 'client_secret', 'path', 'secret_field', 'secret_decoding'], } if settings.DEBUG: @@ -67,12 +76,18 @@ def dsv_backend(**kwargs): client_secret = kwargs['client_secret'] secret_path = kwargs['path'] secret_field = kwargs['secret_field'] + # providing a default value to remain backward compatible for secrets that have not specified this option + secret_decoding = kwargs.get('secret_decoding', 'No Decoding') tenant_url = tenant_url_template.format(tenant_name, tenant_tld.strip(".")) authorizer = PasswordGrantAuthorizer(tenant_url, client_id, client_secret) dsv_secret = SecretsVault(tenant_url, authorizer).get_secret(secret_path) + # files can be uploaded base64 decoded to DSV and thus decoding it only, when asked for + if secret_decoding == 'Decode Base64': + return b64decode(dsv_secret['data'][secret_field]).decode() + return dsv_secret['data'][secret_field] diff --git a/awx/main/credential_plugins/hashivault.py b/awx/main/credential_plugins/hashivault.py index bc726af9a440..28473211e62a 100644 --- a/awx/main/credential_plugins/hashivault.py +++ b/awx/main/credential_plugins/hashivault.py @@ -41,6 +41,34 @@ 'secret': True, 'help_text': _('The Secret ID for AppRole Authentication'), }, + { + 'id': 'client_cert_public', + 'label': _('Client Certificate'), + 'type': 'string', + 'multiline': True, + 'help_text': _( + 'The PEM-encoded client certificate used for TLS client authentication.' + ' This should include the certificate and any intermediate certififcates.' + ), + }, + { + 'id': 'client_cert_private', + 'label': _('Client Certificate Key'), + 'type': 'string', + 'multiline': True, + 'secret': True, + 'help_text': _('The certificate private key used for TLS client authentication.'), + }, + { + 'id': 'client_cert_role', + 'label': _('TLS Authentication Role'), + 'type': 'string', + 'multiline': False, + 'help_text': _( + 'The role configured in Hashicorp Vault for TLS client authentication.' + ' If not provided, Hashicorp Vault may assign roles based on the certificate used.' + ), + }, { 'id': 'namespace', 'label': _('Namespace name (Vault Enterprise only)'), @@ -64,7 +92,7 @@ 'label': _('Username'), 'type': 'string', 'secret': False, - 'help_text': _('Username for authentication.'), + 'help_text': _('Username for user authentication.'), }, { 'id': 'password', @@ -179,9 +207,10 @@ def handle_auth(**kwargs): token = method_auth(**kwargs, auth_param=kubernetes_auth(**kwargs)) elif kwargs.get('username') and kwargs.get('password'): token = method_auth(**kwargs, auth_param=ldap_auth(**kwargs)) + elif kwargs.get('client_cert_public') and kwargs.get('client_cert_private'): + token = method_auth(**kwargs, auth_param=client_cert_auth(**kwargs)) else: raise Exception('Token, LDAP, AppRole, Kubernetes, or TLS authentication parameters must be set') - return token @@ -200,6 +229,10 @@ def kubernetes_auth(**kwargs): return {'role': kwargs['kubernetes_role'], 'jwt': jwt} +def client_cert_auth(**kwargs): + return {'name': kwargs.get('client_cert_role')} + + def method_auth(**kwargs): # get auth method specific params request_kwargs = {'json': kwargs['auth_param'], 'timeout': 30} @@ -212,13 +245,27 @@ def method_auth(**kwargs): cacert = kwargs.get('cacert', None) sess = requests.Session() + # Namespace support - if kwargs.get('namespace'): - sess.headers['X-Vault-Namespace'] = kwargs['namespace'] - request_url = '/'.join([url, 'auth', auth_path, 'login']).rstrip('/') - with CertFiles(cacert) as cert: - request_kwargs['verify'] = cert + if kwargs.get('username'): + request_url = '/'.join([url, 'auth', auth_path, 'login', kwargs['username']]).rstrip('/') resp = sess.post(request_url, **request_kwargs) + token = resp.json()['auth']['client_token'] + else: + if kwargs.get('namespace'): + sess.headers['X-Vault-Namespace'] = kwargs['namespace'] + request_url = '/'.join([url, 'auth', auth_path, 'login']).rstrip('/') + with CertFiles(cacert) as cert: + request_kwargs['verify'] = cert + # TLS client certificate support + if kwargs.get('client_cert_public') and kwargs.get('client_cert_private'): + # Add client cert to requests Session before making call + with CertFiles(kwargs['client_cert_public'], key=kwargs['client_cert_private']) as client_cert: + sess.cert = client_cert + resp = sess.post(request_url, **request_kwargs) + else: + # Make call without client certificate + resp = sess.post(request_url, **request_kwargs) resp.raise_for_status() token = resp.json()['auth']['client_token'] return token @@ -334,4 +381,4 @@ def ssh_backend(**kwargs): hashivault_kv_plugin = CredentialPlugin('HashiCorp Vault Secret Lookup', inputs=hashi_kv_inputs, backend=kv_backend) -hashivault_ssh_plugin = CredentialPlugin('HashiCorp Vault Signed SSH', inputs=hashi_ssh_inputs, backend=ssh_backend) +hashivault_ssh_plugin = CredentialPlugin('HashiCorp Vault Signed SSH', inputs=hashi_ssh_inputs, backend=ssh_backend) \ No newline at end of file diff --git a/awx/main/migrations/0006_v320_release.py b/awx/main/migrations/0006_v320_release.py index f1dd01d70852..a3059f1a6ed7 100644 --- a/awx/main/migrations/0006_v320_release.py +++ b/awx/main/migrations/0006_v320_release.py @@ -9,6 +9,7 @@ # AWX import awx.main.fields from awx.main.models import Host +from ._sqlite_helper import dbawaremigrations def replaces(): @@ -131,9 +132,11 @@ class Migration(migrations.Migration): help_text='If enabled, Tower will act as an Ansible Fact Cache Plugin; persisting facts at the end of a playbook run to the database and caching facts for use by Ansible.', ), ), - migrations.RunSQL( + dbawaremigrations.RunSQL( sql="CREATE INDEX host_ansible_facts_default_gin ON {} USING gin(ansible_facts jsonb_path_ops);".format(Host._meta.db_table), reverse_sql='DROP INDEX host_ansible_facts_default_gin;', + sqlite_sql=dbawaremigrations.RunSQL.noop, + sqlite_reverse_sql=dbawaremigrations.RunSQL.noop, ), # SCM file-based inventories migrations.AddField( diff --git a/awx/main/migrations/0050_v340_drop_celery_tables.py b/awx/main/migrations/0050_v340_drop_celery_tables.py index 5c98d7bc7c3a..ce34d81ef3f1 100644 --- a/awx/main/migrations/0050_v340_drop_celery_tables.py +++ b/awx/main/migrations/0050_v340_drop_celery_tables.py @@ -3,24 +3,27 @@ from django.db import migrations +from ._sqlite_helper import dbawaremigrations + +tables_to_drop = [ + 'celery_taskmeta', + 'celery_tasksetmeta', + 'djcelery_crontabschedule', + 'djcelery_intervalschedule', + 'djcelery_periodictask', + 'djcelery_periodictasks', + 'djcelery_taskstate', + 'djcelery_workerstate', + 'djkombu_message', + 'djkombu_queue', +] +postgres_sql = ([("DROP TABLE IF EXISTS {} CASCADE;".format(table))] for table in tables_to_drop) +sqlite_sql = ([("DROP TABLE IF EXISTS {};".format(table))] for table in tables_to_drop) + class Migration(migrations.Migration): dependencies = [ ('main', '0049_v330_validate_instance_capacity_adjustment'), ] - operations = [ - migrations.RunSQL([("DROP TABLE IF EXISTS {} CASCADE;".format(table))]) - for table in ( - 'celery_taskmeta', - 'celery_tasksetmeta', - 'djcelery_crontabschedule', - 'djcelery_intervalschedule', - 'djcelery_periodictask', - 'djcelery_periodictasks', - 'djcelery_taskstate', - 'djcelery_workerstate', - 'djkombu_message', - 'djkombu_queue', - ) - ] + operations = [dbawaremigrations.RunSQL(p, sqlite_sql=s) for p, s in zip(postgres_sql, sqlite_sql)] diff --git a/awx/main/migrations/0113_v370_event_bigint.py b/awx/main/migrations/0113_v370_event_bigint.py index d9f4ce1d9755..7795d4cc6524 100644 --- a/awx/main/migrations/0113_v370_event_bigint.py +++ b/awx/main/migrations/0113_v370_event_bigint.py @@ -2,6 +2,8 @@ from django.db import migrations, models, connection +from ._sqlite_helper import dbawaremigrations + def migrate_event_data(apps, schema_editor): # see: https://github.com/ansible/awx/issues/6010 @@ -24,6 +26,11 @@ def migrate_event_data(apps, schema_editor): cursor.execute(f'ALTER TABLE {tblname} ALTER COLUMN id TYPE bigint USING id::bigint;') +def migrate_event_data_sqlite(apps, schema_editor): + # TODO: cmeyers fill this in + return + + class FakeAlterField(migrations.AlterField): def database_forwards(self, *args): # this is intentionally left blank, because we're @@ -37,7 +44,7 @@ class Migration(migrations.Migration): ] operations = [ - migrations.RunPython(migrate_event_data), + dbawaremigrations.RunPython(migrate_event_data, sqlite_code=migrate_event_data_sqlite), FakeAlterField( model_name='adhoccommandevent', name='id', diff --git a/awx/main/migrations/0144_event_partitions.py b/awx/main/migrations/0144_event_partitions.py index efdcbb37fc4e..8813ae67e535 100644 --- a/awx/main/migrations/0144_event_partitions.py +++ b/awx/main/migrations/0144_event_partitions.py @@ -1,5 +1,7 @@ from django.db import migrations, models, connection +from ._sqlite_helper import dbawaremigrations + def migrate_event_data(apps, schema_editor): # see: https://github.com/ansible/awx/issues/9039 @@ -59,6 +61,10 @@ def migrate_event_data(apps, schema_editor): cursor.execute('DROP INDEX IF EXISTS main_jobevent_job_id_idx') +def migrate_event_data_sqlite(apps, schema_editor): + return None + + class FakeAddField(migrations.AddField): def database_forwards(self, *args): # this is intentionally left blank, because we're @@ -72,7 +78,7 @@ class Migration(migrations.Migration): ] operations = [ - migrations.RunPython(migrate_event_data), + dbawaremigrations.RunPython(migrate_event_data, sqlite_code=migrate_event_data_sqlite), FakeAddField( model_name='jobevent', name='job_created', diff --git a/awx/main/migrations/0185_move_JSONBlob_to_JSONField.py b/awx/main/migrations/0185_move_JSONBlob_to_JSONField.py index 42bab8eb87b1..b2efeecfb3c9 100644 --- a/awx/main/migrations/0185_move_JSONBlob_to_JSONField.py +++ b/awx/main/migrations/0185_move_JSONBlob_to_JSONField.py @@ -3,6 +3,8 @@ import awx.main.models.notifications from django.db import migrations, models +from ._sqlite_helper import dbawaremigrations + class Migration(migrations.Migration): dependencies = [ @@ -104,11 +106,12 @@ class Migration(migrations.Migration): name='deleted_actor', field=models.JSONField(null=True), ), - migrations.RunSQL( + dbawaremigrations.RunSQL( """ ALTER TABLE main_activitystream RENAME setting TO setting_old; ALTER TABLE main_activitystream ALTER COLUMN setting_old DROP NOT NULL; """, + sqlite_sql="ALTER TABLE main_activitystream RENAME setting TO setting_old", state_operations=[ migrations.RemoveField( model_name='activitystream', @@ -121,11 +124,12 @@ class Migration(migrations.Migration): name='setting', field=models.JSONField(blank=True, default=dict), ), - migrations.RunSQL( + dbawaremigrations.RunSQL( """ ALTER TABLE main_job RENAME survey_passwords TO survey_passwords_old; ALTER TABLE main_job ALTER COLUMN survey_passwords_old DROP NOT NULL; """, + sqlite_sql="ALTER TABLE main_job RENAME survey_passwords TO survey_passwords_old", state_operations=[ migrations.RemoveField( model_name='job', @@ -138,11 +142,12 @@ class Migration(migrations.Migration): name='survey_passwords', field=models.JSONField(blank=True, default=dict, editable=False), ), - migrations.RunSQL( + dbawaremigrations.RunSQL( """ ALTER TABLE main_joblaunchconfig RENAME char_prompts TO char_prompts_old; ALTER TABLE main_joblaunchconfig ALTER COLUMN char_prompts_old DROP NOT NULL; """, + sqlite_sql="ALTER TABLE main_joblaunchconfig RENAME char_prompts TO char_prompts_old", state_operations=[ migrations.RemoveField( model_name='joblaunchconfig', @@ -155,11 +160,12 @@ class Migration(migrations.Migration): name='char_prompts', field=models.JSONField(blank=True, default=dict), ), - migrations.RunSQL( + dbawaremigrations.RunSQL( """ ALTER TABLE main_joblaunchconfig RENAME survey_passwords TO survey_passwords_old; ALTER TABLE main_joblaunchconfig ALTER COLUMN survey_passwords_old DROP NOT NULL; """, + sqlite_sql="ALTER TABLE main_joblaunchconfig RENAME survey_passwords TO survey_passwords_old;", state_operations=[ migrations.RemoveField( model_name='joblaunchconfig', @@ -172,11 +178,12 @@ class Migration(migrations.Migration): name='survey_passwords', field=models.JSONField(blank=True, default=dict, editable=False), ), - migrations.RunSQL( + dbawaremigrations.RunSQL( """ ALTER TABLE main_notification RENAME body TO body_old; ALTER TABLE main_notification ALTER COLUMN body_old DROP NOT NULL; """, + sqlite_sql="ALTER TABLE main_notification RENAME body TO body_old", state_operations=[ migrations.RemoveField( model_name='notification', @@ -189,11 +196,12 @@ class Migration(migrations.Migration): name='body', field=models.JSONField(blank=True, default=dict), ), - migrations.RunSQL( + dbawaremigrations.RunSQL( """ ALTER TABLE main_unifiedjob RENAME job_env TO job_env_old; ALTER TABLE main_unifiedjob ALTER COLUMN job_env_old DROP NOT NULL; """, + sqlite_sql="ALTER TABLE main_unifiedjob RENAME job_env TO job_env_old", state_operations=[ migrations.RemoveField( model_name='unifiedjob', @@ -206,11 +214,12 @@ class Migration(migrations.Migration): name='job_env', field=models.JSONField(blank=True, default=dict, editable=False), ), - migrations.RunSQL( + dbawaremigrations.RunSQL( """ ALTER TABLE main_workflowjob RENAME char_prompts TO char_prompts_old; ALTER TABLE main_workflowjob ALTER COLUMN char_prompts_old DROP NOT NULL; """, + sqlite_sql="ALTER TABLE main_workflowjob RENAME char_prompts TO char_prompts_old", state_operations=[ migrations.RemoveField( model_name='workflowjob', @@ -223,11 +232,12 @@ class Migration(migrations.Migration): name='char_prompts', field=models.JSONField(blank=True, default=dict), ), - migrations.RunSQL( + dbawaremigrations.RunSQL( """ ALTER TABLE main_workflowjob RENAME survey_passwords TO survey_passwords_old; ALTER TABLE main_workflowjob ALTER COLUMN survey_passwords_old DROP NOT NULL; """, + sqlite_sql="ALTER TABLE main_workflowjob RENAME survey_passwords TO survey_passwords_old", state_operations=[ migrations.RemoveField( model_name='workflowjob', @@ -240,11 +250,12 @@ class Migration(migrations.Migration): name='survey_passwords', field=models.JSONField(blank=True, default=dict, editable=False), ), - migrations.RunSQL( + dbawaremigrations.RunSQL( """ ALTER TABLE main_workflowjobnode RENAME char_prompts TO char_prompts_old; ALTER TABLE main_workflowjobnode ALTER COLUMN char_prompts_old DROP NOT NULL; """, + sqlite_sql="ALTER TABLE main_workflowjobnode RENAME char_prompts TO char_prompts_old", state_operations=[ migrations.RemoveField( model_name='workflowjobnode', @@ -257,11 +268,12 @@ class Migration(migrations.Migration): name='char_prompts', field=models.JSONField(blank=True, default=dict), ), - migrations.RunSQL( + dbawaremigrations.RunSQL( """ ALTER TABLE main_workflowjobnode RENAME survey_passwords TO survey_passwords_old; ALTER TABLE main_workflowjobnode ALTER COLUMN survey_passwords_old DROP NOT NULL; """, + sqlite_sql="ALTER TABLE main_workflowjobnode RENAME survey_passwords TO survey_passwords_old", state_operations=[ migrations.RemoveField( model_name='workflowjobnode', diff --git a/awx/main/migrations/0186_drop_django_taggit.py b/awx/main/migrations/0186_drop_django_taggit.py index c9c767b74c1b..99aa102feee9 100644 --- a/awx/main/migrations/0186_drop_django_taggit.py +++ b/awx/main/migrations/0186_drop_django_taggit.py @@ -3,6 +3,8 @@ from django.db import migrations +from ._sqlite_helper import dbawaremigrations + def delete_taggit_contenttypes(apps, schema_editor): ContentType = apps.get_model('contenttypes', 'ContentType') @@ -20,8 +22,8 @@ class Migration(migrations.Migration): ] operations = [ - migrations.RunSQL("DROP TABLE IF EXISTS taggit_tag CASCADE;"), - migrations.RunSQL("DROP TABLE IF EXISTS taggit_taggeditem CASCADE;"), + dbawaremigrations.RunSQL("DROP TABLE IF EXISTS taggit_tag CASCADE;", sqlite_sql="DROP TABLE IF EXISTS taggit_tag;"), + dbawaremigrations.RunSQL("DROP TABLE IF EXISTS taggit_taggeditem CASCADE;", sqlite_sql="DROP TABLE IF EXISTS taggit_taggeditem;"), migrations.RunPython(delete_taggit_contenttypes), migrations.RunPython(delete_taggit_migration_records), ] diff --git a/awx/main/migrations/_sqlite_helper.py b/awx/main/migrations/_sqlite_helper.py new file mode 100644 index 000000000000..fcf0557c0f1e --- /dev/null +++ b/awx/main/migrations/_sqlite_helper.py @@ -0,0 +1,61 @@ +from django.db import migrations + + +class RunSQL(migrations.operations.special.RunSQL): + """ + Bit of a hack here. Django actually wants this decision made in the router + and we can pass **hints. + """ + + def __init__(self, *args, **kwargs): + if 'sqlite_sql' not in kwargs: + raise ValueError("sqlite_sql parameter required") + sqlite_sql = kwargs.pop('sqlite_sql') + + self.sqlite_sql = sqlite_sql + self.sqlite_reverse_sql = kwargs.pop('sqlite_reverse_sql', None) + super().__init__(*args, **kwargs) + + def database_forwards(self, app_label, schema_editor, from_state, to_state): + if not schema_editor.connection.vendor.startswith('postgres'): + self.sql = self.sqlite_sql or migrations.RunSQL.noop + super().database_forwards(app_label, schema_editor, from_state, to_state) + + def database_backwards(self, app_label, schema_editor, from_state, to_state): + if not schema_editor.connection.vendor.startswith('postgres'): + self.reverse_sql = self.sqlite_reverse_sql or migrations.RunSQL.noop + super().database_backwards(app_label, schema_editor, from_state, to_state) + + +class RunPython(migrations.operations.special.RunPython): + """ + Bit of a hack here. Django actually wants this decision made in the router + and we can pass **hints. + """ + + def __init__(self, *args, **kwargs): + if 'sqlite_code' not in kwargs: + raise ValueError("sqlite_code parameter required") + sqlite_code = kwargs.pop('sqlite_code') + + self.sqlite_code = sqlite_code + self.sqlite_reverse_code = kwargs.pop('sqlite_reverse_code', None) + super().__init__(*args, **kwargs) + + def database_forwards(self, app_label, schema_editor, from_state, to_state): + if not schema_editor.connection.vendor.startswith('postgres'): + self.code = self.sqlite_code or migrations.RunPython.noop + super().database_forwards(app_label, schema_editor, from_state, to_state) + + def database_backwards(self, app_label, schema_editor, from_state, to_state): + if not schema_editor.connection.vendor.startswith('postgres'): + self.reverse_code = self.sqlite_reverse_code or migrations.RunPython.noop + super().database_backwards(app_label, schema_editor, from_state, to_state) + + +class _sqlitemigrations: + RunPython = RunPython + RunSQL = RunSQL + + +dbawaremigrations = _sqlitemigrations() diff --git a/awx/main/models/__init__.py b/awx/main/models/__init__.py index fc779f9cf570..53b7ea63cd3c 100644 --- a/awx/main/models/__init__.py +++ b/awx/main/models/__init__.py @@ -6,8 +6,10 @@ from django.db import connection from django.db.models.signals import pre_delete # noqa +from ansible_base.utils.models import prevent_search + # AWX -from awx.main.models.base import BaseModel, PrimordialModel, prevent_search, accepts_json, CLOUD_INVENTORY_SOURCES, VERBOSITY_CHOICES # noqa +from awx.main.models.base import BaseModel, PrimordialModel, accepts_json, CLOUD_INVENTORY_SOURCES, VERBOSITY_CHOICES # noqa from awx.main.models.unified_jobs import UnifiedJob, UnifiedJobTemplate, StdoutMaxBytesExceeded # noqa from awx.main.models.organization import Organization, Profile, Team, UserSessionMembership # noqa from awx.main.models.credential import Credential, CredentialType, CredentialInputSource, ManagedCredentialType, build_safe_env # noqa @@ -57,7 +59,6 @@ from awx.main.models.rbac import ( # noqa Role, batch_role_ancestor_rebuilding, - get_roles_on_resource, role_summary_fields_generator, ROLE_SINGLETON_SYSTEM_ADMINISTRATOR, ROLE_SINGLETON_SYSTEM_AUDITOR, @@ -91,13 +92,12 @@ # Add custom methods to User model for permissions checks. from django.contrib.auth.models import User # noqa -from awx.main.access import get_user_queryset, check_user_access, check_user_access_with_errors, user_accessible_objects # noqa +from awx.main.access import get_user_queryset, check_user_access, check_user_access_with_errors # noqa User.add_to_class('get_queryset', get_user_queryset) User.add_to_class('can_access', check_user_access) User.add_to_class('can_access_with_errors', check_user_access_with_errors) -User.add_to_class('accessible_objects', user_accessible_objects) def convert_jsonfields(): diff --git a/awx/main/models/ad_hoc_commands.py b/awx/main/models/ad_hoc_commands.py index 3b71119031a4..9143f30f9830 100644 --- a/awx/main/models/ad_hoc_commands.py +++ b/awx/main/models/ad_hoc_commands.py @@ -12,9 +12,11 @@ from django.utils.translation import gettext_lazy as _ from django.core.exceptions import ValidationError +from ansible_base.utils.models import prevent_search + # AWX from awx.api.versioning import reverse -from awx.main.models.base import prevent_search, AD_HOC_JOB_TYPE_CHOICES, VERBOSITY_CHOICES, VarsDictProperty +from awx.main.models.base import AD_HOC_JOB_TYPE_CHOICES, VERBOSITY_CHOICES, VarsDictProperty from awx.main.models.events import AdHocCommandEvent, UnpartitionedAdHocCommandEvent from awx.main.models.unified_jobs import UnifiedJob from awx.main.models.notifications import JobNotificationMixin, NotificationTemplate diff --git a/awx/main/models/base.py b/awx/main/models/base.py index 0ef5b244f2e8..ce96d0bd3155 100644 --- a/awx/main/models/base.py +++ b/awx/main/models/base.py @@ -15,7 +15,6 @@ from awx.main.constants import CLOUD_PROVIDERS __all__ = [ - 'prevent_search', 'VarsDictProperty', 'BaseModel', 'CreatedModifiedModel', @@ -384,23 +383,6 @@ class Meta: notification_templates_started = models.ManyToManyField("NotificationTemplate", blank=True, related_name='%(class)s_notification_templates_for_started') -def prevent_search(relation): - """ - Used to mark a model field or relation as "restricted from filtering" - e.g., - - class AuthToken(BaseModel): - user = prevent_search(models.ForeignKey(...)) - sensitive_data = prevent_search(models.CharField(...)) - - The flag set by this function is used by - `awx.api.filters.FieldLookupBackend` to block fields and relations that - should not be searchable/filterable via search query params - """ - setattr(relation, '__prevent_search__', True) - return relation - - def accepts_json(relation): """ Used to mark a model field as allowing JSON e.g,. JobTemplate.extra_vars diff --git a/awx/main/models/ha.py b/awx/main/models/ha.py index 5d370d24c990..08490234f234 100644 --- a/awx/main/models/ha.py +++ b/awx/main/models/ha.py @@ -17,6 +17,8 @@ import redis from solo.models import SingletonModel +from ansible_base.utils.models import prevent_search + # AWX from awx import __version__ as awx_application_version from awx.main.utils import is_testing @@ -24,7 +26,7 @@ from awx.main.fields import ImplicitRoleField from awx.main.managers import InstanceManager, UUID_DEFAULT from awx.main.constants import JOB_FOLDER_PREFIX -from awx.main.models.base import BaseModel, HasEditsMixin, prevent_search +from awx.main.models.base import BaseModel, HasEditsMixin from awx.main.models.rbac import ( ROLE_SINGLETON_SYSTEM_ADMINISTRATOR, ROLE_SINGLETON_SYSTEM_AUDITOR, diff --git a/awx/main/models/inventory.py b/awx/main/models/inventory.py index 7cf7f0710e7f..ab8ae3284b1b 100644 --- a/awx/main/models/inventory.py +++ b/awx/main/models/inventory.py @@ -25,6 +25,8 @@ # REST Framework from rest_framework.exceptions import ParseError +from ansible_base.utils.models import prevent_search + # AWX from awx.api.versioning import reverse from awx.main.constants import CLOUD_PROVIDERS @@ -35,7 +37,7 @@ OrderedManyToManyField, ) from awx.main.managers import HostManager, HostMetricActiveManager -from awx.main.models.base import BaseModel, CommonModelNameNotUnique, VarsDictProperty, CLOUD_INVENTORY_SOURCES, prevent_search, accepts_json +from awx.main.models.base import BaseModel, CommonModelNameNotUnique, VarsDictProperty, CLOUD_INVENTORY_SOURCES, accepts_json from awx.main.models.events import InventoryUpdateEvent, UnpartitionedInventoryUpdateEvent from awx.main.models.unified_jobs import UnifiedJob, UnifiedJobTemplate from awx.main.models.mixins import ( diff --git a/awx/main/models/jobs.py b/awx/main/models/jobs.py index edbc3de0bdd2..a01f791af66c 100644 --- a/awx/main/models/jobs.py +++ b/awx/main/models/jobs.py @@ -20,13 +20,14 @@ # REST Framework from rest_framework.exceptions import ParseError +from ansible_base.utils.models import prevent_search + # AWX from awx.api.versioning import reverse from awx.main.constants import HOST_FACTS_FIELDS from awx.main.models.base import ( BaseModel, CreatedModifiedModel, - prevent_search, accepts_json, JOB_TYPE_CHOICES, NEW_JOB_TYPE_CHOICES, diff --git a/awx/main/models/mixins.py b/awx/main/models/mixins.py index 75b304a32a08..fd92b0b5c367 100644 --- a/awx/main/models/mixins.py +++ b/awx/main/models/mixins.py @@ -9,7 +9,6 @@ # Django from django.apps import apps from django.conf import settings -from django.contrib.auth.models import User # noqa from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ValidationError from django.db import models @@ -17,9 +16,10 @@ from django.utils.crypto import get_random_string from django.utils.translation import gettext_lazy as _ +from ansible_base.utils.models import prevent_search + # AWX -from awx.main.models.base import prevent_search -from awx.main.models.rbac import Role, RoleAncestorEntry, get_roles_on_resource +from awx.main.models.rbac import Role, RoleAncestorEntry from awx.main.utils import parse_yaml_or_json, get_custom_venv_choices, get_licenser, polymorphic from awx.main.utils.execution_environments import get_default_execution_environment from awx.main.utils.encryption import decrypt_value, get_encryption_key, is_encrypted @@ -54,10 +54,7 @@ def accessible_objects(cls, accessor, role_field): Use instead of `MyModel.objects` when you want to only consider resources that a user has specific permissions for. For example: MyModel.accessible_objects(user, 'read_role').filter(name__istartswith='bar'); - NOTE: This should only be used for list type things. If you have a - specific resource you want to check permissions on, it is more - performant to resolve the resource in question then call - `myresource.get_permissions(user)`. + NOTE: This should only be used for list type things. """ return ResourceMixin._accessible_objects(cls, accessor, role_field) @@ -67,13 +64,12 @@ def accessible_pk_qs(cls, accessor, role_field): @staticmethod def _accessible_pk_qs(cls, accessor, role_field, content_types=None): - if type(accessor) == User: + if accessor._meta.model_name == 'user': ancestor_roles = accessor.roles.all() elif type(accessor) == Role: ancestor_roles = [accessor] else: - accessor_type = ContentType.objects.get_for_model(accessor) - ancestor_roles = Role.objects.filter(content_type__pk=accessor_type.id, object_id=accessor.id) + raise RuntimeError(f'Role filters only valid for users and ancestor role, received {accessor}') if content_types is None: ct_kwarg = dict(content_type_id=ContentType.objects.get_for_model(cls).id) @@ -86,15 +82,6 @@ def _accessible_pk_qs(cls, accessor, role_field, content_types=None): def _accessible_objects(cls, accessor, role_field): return cls.objects.filter(pk__in=ResourceMixin._accessible_pk_qs(cls, accessor, role_field)) - def get_permissions(self, accessor): - """ - Returns a string list of the roles a accessor has for a given resource. - An accessor can be either a User, Role, or an arbitrary resource that - contains one or more Roles associated with it. - """ - - return get_roles_on_resource(self, accessor) - class SurveyJobTemplateMixin(models.Model): class Meta: diff --git a/awx/main/models/notifications.py b/awx/main/models/notifications.py index ef8304b6a667..4b5ce89fca05 100644 --- a/awx/main/models/notifications.py +++ b/awx/main/models/notifications.py @@ -15,9 +15,11 @@ from jinja2 import sandbox, ChainableUndefined from jinja2.exceptions import TemplateSyntaxError, UndefinedError, SecurityError +from ansible_base.utils.models import prevent_search + # AWX from awx.api.versioning import reverse -from awx.main.models.base import CommonModelNameNotUnique, CreatedModifiedModel, prevent_search +from awx.main.models.base import CommonModelNameNotUnique, CreatedModifiedModel from awx.main.utils import encrypt_field, decrypt_field, set_environ from awx.main.notifications.email_backend import CustomEmailBackend from awx.main.notifications.slack_backend import SlackBackend diff --git a/awx/main/models/rbac.py b/awx/main/models/rbac.py index 5febf88eb2f8..9078436404ee 100644 --- a/awx/main/models/rbac.py +++ b/awx/main/models/rbac.py @@ -15,12 +15,10 @@ # AWX from awx.api.versioning import reverse -from django.contrib.auth.models import User # noqa __all__ = [ 'Role', 'batch_role_ancestor_rebuilding', - 'get_roles_on_resource', 'ROLE_SINGLETON_SYSTEM_ADMINISTRATOR', 'ROLE_SINGLETON_SYSTEM_AUDITOR', 'role_summary_fields_generator', @@ -170,16 +168,10 @@ def get_absolute_url(self, request=None): return reverse('api:role_detail', kwargs={'pk': self.pk}, request=request) def __contains__(self, accessor): - if type(accessor) == User: + if accessor._meta.model_name == 'user': return self.ancestors.filter(members=accessor).exists() - elif accessor.__class__.__name__ == 'Team': - return self.ancestors.filter(pk=accessor.member_role.id).exists() - elif type(accessor) == Role: - return self.ancestors.filter(pk=accessor.pk).exists() else: - accessor_type = ContentType.objects.get_for_model(accessor) - roles = Role.objects.filter(content_type__pk=accessor_type.id, object_id=accessor.id) - return self.ancestors.filter(pk__in=roles).exists() + raise RuntimeError(f'Role evaluations only valid for users, received {accessor}') @property def name(self): @@ -460,31 +452,6 @@ class Meta: object_id = models.PositiveIntegerField(null=False) -def get_roles_on_resource(resource, accessor): - """ - Returns a string list of the roles a accessor has for a given resource. - An accessor can be either a User, Role, or an arbitrary resource that - contains one or more Roles associated with it. - """ - - if type(accessor) == User: - roles = accessor.roles.all() - elif type(accessor) == Role: - roles = [accessor] - else: - accessor_type = ContentType.objects.get_for_model(accessor) - roles = Role.objects.filter(content_type__pk=accessor_type.id, object_id=accessor.id) - - return [ - role_field - for role_field in RoleAncestorEntry.objects.filter( - ancestor__in=roles, content_type_id=ContentType.objects.get_for_model(resource).id, object_id=resource.id - ) - .values_list('role_field', flat=True) - .distinct() - ] - - def role_summary_fields_generator(content_object, role_field): global role_descriptions global role_names diff --git a/awx/main/models/unified_jobs.py b/awx/main/models/unified_jobs.py index 6ba605c0d4f3..83696d1eefce 100644 --- a/awx/main/models/unified_jobs.py +++ b/awx/main/models/unified_jobs.py @@ -30,8 +30,10 @@ # Django-Polymorphic from polymorphic.models import PolymorphicModel +from ansible_base.utils.models import prevent_search, get_type_for_model + # AWX -from awx.main.models.base import CommonModelNameNotUnique, PasswordFieldsModel, NotificationFieldsModel, prevent_search +from awx.main.models.base import CommonModelNameNotUnique, PasswordFieldsModel, NotificationFieldsModel from awx.main.dispatch import get_task_queuename from awx.main.dispatch.control import Control as ControlDispatcher from awx.main.registrar import activity_stream_registrar @@ -42,7 +44,6 @@ _inventory_updates, copy_model_by_class, copy_m2m_relationships, - get_type_for_model, parse_yaml_or_json, getattr_dne, ScheduleDependencyManager, diff --git a/awx/main/models/workflow.py b/awx/main/models/workflow.py index 3038db296725..5f0cbff7caa8 100644 --- a/awx/main/models/workflow.py +++ b/awx/main/models/workflow.py @@ -23,9 +23,11 @@ from jinja2 import sandbox from jinja2.exceptions import TemplateSyntaxError, UndefinedError, SecurityError +from ansible_base.utils.models import prevent_search + # AWX from awx.api.versioning import reverse -from awx.main.models import prevent_search, accepts_json, UnifiedJobTemplate, UnifiedJob +from awx.main.models import accepts_json, UnifiedJobTemplate, UnifiedJob from awx.main.models.notifications import NotificationTemplate, JobNotificationMixin from awx.main.models.base import CreatedModifiedModel, VarsDictProperty from awx.main.models.rbac import ROLE_SINGLETON_SYSTEM_ADMINISTRATOR, ROLE_SINGLETON_SYSTEM_AUDITOR diff --git a/awx/main/notifications/twilio_backend.py b/awx/main/notifications/twilio_backend.py index 420c5ef74d5e..34fbff53d4f7 100644 --- a/awx/main/notifications/twilio_backend.py +++ b/awx/main/notifications/twilio_backend.py @@ -39,11 +39,15 @@ def send_messages(self, messages): logger.error(smart_str(_("Exception connecting to Twilio: {}").format(e))) for m in messages: - try: - connection.messages.create(to=m.to, from_=m.from_email, body=m.subject) - sent_messages += 1 - except Exception as e: - logger.error(smart_str(_("Exception sending messages: {}").format(e))) - if not self.fail_silently: - raise + failed = False + for dest in m.to: + try: + logger.debug(smart_str(_("FROM: {} / TO: {}").format(m.from_email, dest))) + connection.messages.create(to=dest, from_=m.from_email, body=m.subject) + sent_messages += 1 + except Exception as e: + logger.error(smart_str(_("Exception sending messages: {}").format(e))) + failed = True + if not self.fail_silently and failed: + raise return sent_messages diff --git a/awx/main/scheduler/task_manager.py b/awx/main/scheduler/task_manager.py index 441c4e921ba9..18ebec427508 100644 --- a/awx/main/scheduler/task_manager.py +++ b/awx/main/scheduler/task_manager.py @@ -17,6 +17,8 @@ from django.conf import settings from django.contrib.contenttypes.models import ContentType +from ansible_base.utils.models import get_type_for_model + # AWX from awx.main.dispatch.reaper import reap_job from awx.main.models import ( @@ -34,7 +36,6 @@ from awx.main.scheduler.dag_workflow import WorkflowDAG from awx.main.utils.pglock import advisory_lock from awx.main.utils import ( - get_type_for_model, ScheduleTaskManager, ScheduleWorkflowManager, ) diff --git a/awx/main/tests/functional/api/test_survey_spec.py b/awx/main/tests/functional/api/test_survey_spec.py index cbb22b3bdcce..97a7f65c0fca 100644 --- a/awx/main/tests/functional/api/test_survey_spec.py +++ b/awx/main/tests/functional/api/test_survey_spec.py @@ -2,12 +2,12 @@ import pytest import json +from ansible_base.utils.models import get_type_for_model from awx.api.versioning import reverse from awx.main.models.jobs import JobTemplate, Job from awx.main.models.activity_stream import ActivityStream from awx.main.access import JobTemplateAccess -from awx.main.utils.common import get_type_for_model @pytest.fixture diff --git a/awx/main/tests/functional/test_bulk.py b/awx/main/tests/functional/test_bulk.py index d05bb7a1f8a2..6b166cdf2bff 100644 --- a/awx/main/tests/functional/test_bulk.py +++ b/awx/main/tests/functional/test_bulk.py @@ -309,3 +309,139 @@ def test_bulk_job_set_all_prompt(job_template, organization, inventory, project, assert node[0].limit == 'kansas' assert node[0].skip_tags == 'foobar' assert node[0].job_tags == 'untagged' + + +@pytest.mark.django_db +@pytest.mark.parametrize('num_hosts, num_queries', [(1, 70), (10, 150), (25, 250)]) +def test_bulk_host_delete_num_queries(organization, inventory, post, get, user, num_hosts, num_queries, django_assert_max_num_queries): + ''' + If I am a... + org admin + inventory admin at org level + admin of a particular inventory + superuser + + Bulk Host delete should take under a certain number of queries + ''' + users_list = setup_admin_users_list(organization, inventory, user) + for u in users_list: + hosts = [{'name': str(uuid4())} for i in range(num_hosts)] + with django_assert_max_num_queries(num_queries): + bulk_host_create_response = post(reverse('api:bulk_host_create'), {'inventory': inventory.id, 'hosts': hosts}, u, expect=201).data + assert len(bulk_host_create_response['hosts']) == len(hosts), f"unexpected number of hosts created for user {u}" + hosts_ids_created = get_inventory_hosts(get, inventory.id, u) + bulk_host_delete_response = post(reverse('api:bulk_host_delete'), {'hosts': hosts_ids_created}, u, expect=201).data + assert len(bulk_host_delete_response['hosts'].keys()) == len(hosts), f"unexpected number of hosts deleted for user {u}" + + +@pytest.mark.django_db +def test_bulk_host_delete_rbac(organization, inventory, post, get, user): + ''' + If I am a... + org admin + inventory admin at org level + admin of a particular invenotry + ... I can bulk delete hosts + + Everyone else cannot + ''' + admin_users_list = setup_admin_users_list(organization, inventory, user) + users_list = setup_none_admin_uses_list(organization, inventory, user) + + for indx, u in enumerate(admin_users_list): + bulk_host_create_response = post( + reverse('api:bulk_host_create'), {'inventory': inventory.id, 'hosts': [{'name': f'foobar-{indx}'}]}, u, expect=201 + ).data + assert len(bulk_host_create_response['hosts']) == 1, f"unexpected number of hosts created for user {u}" + assert Host.objects.filter(inventory__id=inventory.id)[0].name == f'foobar-{indx}' + hosts_ids_created = get_inventory_hosts(get, inventory.id, u) + bulk_host_delete_response = post(reverse('api:bulk_host_delete'), {'hosts': hosts_ids_created}, u, expect=201).data + assert len(bulk_host_delete_response['hosts'].keys()) == 1, f"unexpected number of hosts deleted by user {u}" + + for indx, create_u in enumerate(admin_users_list): + bulk_host_create_response = post( + reverse('api:bulk_host_create'), {'inventory': inventory.id, 'hosts': [{'name': f'foobar2-{indx}'}]}, create_u, expect=201 + ).data + print(bulk_host_create_response) + assert bulk_host_create_response['hosts'][0]['name'] == f'foobar2-{indx}' + hosts_ids_created = get_inventory_hosts(get, inventory.id, create_u) + print(f"Try to delete {hosts_ids_created}") + for delete_u in users_list: + bulk_host_delete_response = post(reverse('api:bulk_host_delete'), {'hosts': hosts_ids_created}, delete_u, expect=403).data + assert "Lack permissions to delete hosts from this inventory." in bulk_host_delete_response['inventories'].values() + + +@pytest.mark.django_db +def test_bulk_host_delete_from_multiple_inv(organization, inventory, post, get, user): + ''' + If I am inventory admin at org level + + Bulk Host delete should be enabled only on my inventory + ''' + num_hosts = 10 + inventory.organization = organization + + # Create second inventory + inv2 = organization.inventories.create(name="second-test-inv") + inv2.organization = organization + admin2_user = user('inventory2_admin', False) + inv2.admin_role.members.add(admin2_user) + + admin_user = user('inventory_admin', False) + inventory.admin_role.members.add(admin_user) + + organization.member_role.members.add(admin_user) + organization.member_role.members.add(admin2_user) + + hosts = [{'name': str(uuid4())} for i in range(num_hosts)] + hosts2 = [{'name': str(uuid4())} for i in range(num_hosts)] + + # create hosts in each of the inventories + bulk_host_create_response = post(reverse('api:bulk_host_create'), {'inventory': inventory.id, 'hosts': hosts}, admin_user, expect=201).data + assert len(bulk_host_create_response['hosts']) == len(hosts), f"unexpected number of hosts created for user {admin_user}" + + bulk_host_create_response2 = post(reverse('api:bulk_host_create'), {'inventory': inv2.id, 'hosts': hosts2}, admin2_user, expect=201).data + assert len(bulk_host_create_response2['hosts']) == len(hosts), f"unexpected number of hosts created for user {admin2_user}" + + # get all hosts ids - from both inventories + hosts_ids_created = get_inventory_hosts(get, inventory.id, admin_user) + hosts_ids_created += get_inventory_hosts(get, inv2.id, admin2_user) + + expected_error = "Lack permissions to delete hosts from this inventory." + # try to delete ALL hosts with admin user of inventory 1. + for inv_name, invadmin in zip([inv2.name, inventory.name], [admin_user, admin2_user]): + bulk_host_delete_response = post(reverse('api:bulk_host_delete'), {'hosts': hosts_ids_created}, invadmin, expect=403).data + result_message = bulk_host_delete_response['inventories'][inv_name] + assert result_message == expected_error, f"deleted hosts without permission by user {invadmin}" + + +def setup_admin_users_list(organization, inventory, user): + inventory.organization = organization + inventory_admin = user('inventory_admin', False) + org_admin = user('org_admin', False) + org_inv_admin = user('org_admin', False) + superuser = user('admin', True) + for u in [org_admin, org_inv_admin, inventory_admin]: + organization.member_role.members.add(u) + organization.admin_role.members.add(org_admin) + organization.inventory_admin_role.members.add(org_inv_admin) + inventory.admin_role.members.add(inventory_admin) + return [inventory_admin, org_inv_admin, superuser, org_admin] + + +def setup_none_admin_uses_list(organization, inventory, user): + inventory.organization = organization + auditor = user('auditor', False) + member = user('member', False) + use_inv_member = user('member', False) + for u in [auditor, member, use_inv_member]: + organization.member_role.members.add(u) + inventory.use_role.members.add(use_inv_member) + organization.auditor_role.members.add(auditor) + return [auditor, member, use_inv_member] + + +def get_inventory_hosts(get, inv_id, use_user): + data = get(reverse('api:inventory_hosts_list', kwargs={'pk': inv_id}), use_user, expect=200).data + results = [host['id'] for host in data['results']] + return results diff --git a/awx/main/tests/functional/test_credential_plugins.py b/awx/main/tests/functional/test_credential_plugins.py index 8cd238925517..9d199c31f583 100644 --- a/awx/main/tests/functional/test_credential_plugins.py +++ b/awx/main/tests/functional/test_credential_plugins.py @@ -40,6 +40,26 @@ def test_hashivault_kubernetes_auth(): assert res == expected_res +def test_hashivault_client_cert_auth_explicit_role(): + kwargs = { + 'client_cert_role': 'test-cert-1', + } + expected_res = { + 'name': 'test-cert-1', + } + res = hashivault.client_cert_auth(**kwargs) + assert res == expected_res + + +def test_hashivault_client_cert_auth_no_role(): + kwargs = {} + expected_res = { + 'name': None, + } + res = hashivault.client_cert_auth(**kwargs) + assert res == expected_res + + def test_hashivault_handle_auth_token(): kwargs = { 'token': 'the_token', @@ -73,6 +93,22 @@ def test_hashivault_handle_auth_kubernetes(): assert token == 'the_token' +def test_hashivault_handle_auth_client_cert(): + kwargs = { + 'client_cert_public': "foo", + 'client_cert_private': "bar", + 'client_cert_role': 'test-cert-1', + } + auth_params = { + 'name': 'test-cert-1', + } + with mock.patch.object(hashivault, 'method_auth') as method_mock: + method_mock.return_value = 'the_token' + token = hashivault.handle_auth(**kwargs) + method_mock.assert_called_with(**kwargs, auth_param=auth_params) + assert token == 'the_token' + + def test_hashivault_handle_auth_not_enough_args(): with pytest.raises(Exception): hashivault.handle_auth() diff --git a/awx/main/tests/functional/test_migrations.py b/awx/main/tests/functional/test_migrations.py new file mode 100644 index 000000000000..cd0889c20851 --- /dev/null +++ b/awx/main/tests/functional/test_migrations.py @@ -0,0 +1,44 @@ +import pytest + +from django_test_migrations.plan import all_migrations, nodes_to_tuples + +""" +Most tests that live in here can probably be deleted at some point. They are mainly +for a developer. When AWX versions that users upgrade from falls out of support that +is when migration tests can be deleted. This is also a good time to squash. Squashing +will likely mess with the tests that live here. + +The smoke test should be kept in here. The smoke test ensures that our migrations +continue to work when sqlite is the backing database (vs. the default DB of postgres). +""" + + +@pytest.mark.django_db +class TestMigrationSmoke: + def test_happy_path(self, migrator): + """ + This smoke test runs all the migrations. + + Example of how to use django-test-migration to invoke particular migration(s) + while weaving in object creation and assertions. + + Note that this is more than just an example. It is a smoke test because it runs ALL + the migrations. Our "normal" unit tests subvert the migrations running because it is slow. + """ + migration_nodes = all_migrations('default') + migration_tuples = nodes_to_tuples(migration_nodes) + final_migration = migration_tuples[-1] + + migrator.apply_initial_migration(('main', None)) + # I just picked a newish migration at the time of writing this. + # If someone from the future finds themselves here because the are squashing migrations + # it is fine to change the 0180_... below to some other newish migration + intermediate_state = migrator.apply_tested_migration(('main', '0180_add_hostmetric_fields')) + + Instance = intermediate_state.apps.get_model('main', 'Instance') + # Create any old object in the database + Instance.objects.create(hostname='foobar', node_type='control') + + final_state = migrator.apply_tested_migration(final_migration) + Instance = final_state.apps.get_model('main', 'Instance') + assert Instance.objects.filter(hostname='foobar').count() == 1 diff --git a/awx/main/tests/functional/test_rbac_core.py b/awx/main/tests/functional/test_rbac_core.py index 7029bbe54486..1fa0f11ed5e8 100644 --- a/awx/main/tests/functional/test_rbac_core.py +++ b/awx/main/tests/functional/test_rbac_core.py @@ -208,6 +208,6 @@ def test_auto_parenting(): @pytest.mark.django_db def test_update_parents_keeps_teams(team, project): project.update_role.parents.add(team.member_role) - assert team.member_role in project.update_role # test prep sanity check + assert list(Project.accessible_objects(team.member_role, 'update_role')) == [project] # test prep sanity check update_role_parentage_for_instance(project) - assert team.member_role in project.update_role # actual assertion + assert list(Project.accessible_objects(team.member_role, 'update_role')) == [project] # actual assertion diff --git a/awx/main/tests/functional/test_rbac_team.py b/awx/main/tests/functional/test_rbac_team.py index a18a69a94bb3..177923b2bf2c 100644 --- a/awx/main/tests/functional/test_rbac_team.py +++ b/awx/main/tests/functional/test_rbac_team.py @@ -92,7 +92,7 @@ def test_team_accessible_by(team, user, project): u = user('team_member', False) team.member_role.children.add(project.use_role) - assert team in project.read_role + assert list(Project.accessible_objects(team.member_role, 'read_role')) == [project] assert u not in project.read_role team.member_role.members.add(u) @@ -104,7 +104,7 @@ def test_team_accessible_objects(team, user, project): u = user('team_member', False) team.member_role.children.add(project.use_role) - assert len(Project.accessible_objects(team, 'read_role')) == 1 + assert len(Project.accessible_objects(team.member_role, 'read_role')) == 1 assert not Project.accessible_objects(u, 'read_role') team.member_role.members.add(u) diff --git a/awx/main/tests/functional/test_rbac_user.py b/awx/main/tests/functional/test_rbac_user.py index d5386343bd8f..54a1cd57fe07 100644 --- a/awx/main/tests/functional/test_rbac_user.py +++ b/awx/main/tests/functional/test_rbac_user.py @@ -122,25 +122,6 @@ def test_team_org_resource_role(ext_auth, organization, rando, org_admin, team): ] == [True for i in range(2)] -@pytest.mark.django_db -def test_user_accessible_objects(user, organization): - """ - We cannot directly use accessible_objects for User model because - both editing and read permissions are obligated to complex business logic - """ - admin = user('admin', False) - u = user('john', False) - access = UserAccess(admin) - assert access.get_queryset().count() == 1 # can only see himself - - organization.member_role.members.add(u) - organization.member_role.members.add(admin) - assert access.get_queryset().count() == 2 - - organization.member_role.members.remove(u) - assert access.get_queryset().count() == 1 - - @pytest.mark.django_db def test_org_admin_create_sys_auditor(org_admin): access = UserAccess(org_admin) diff --git a/awx/main/tests/unit/api/test_filters.py b/awx/main/tests/unit/api/test_filters.py index 7d6501a87161..0066fdd0f631 100644 --- a/awx/main/tests/unit/api/test_filters.py +++ b/awx/main/tests/unit/api/test_filters.py @@ -3,15 +3,13 @@ import pytest # Django -from django.core.exceptions import FieldDoesNotExist +from rest_framework.exceptions import PermissionDenied -from rest_framework.exceptions import PermissionDenied, ParseError +from ansible_base.filters.rest_framework.field_lookup_backend import FieldLookupBackend -from awx.api.filters import FieldLookupBackend, OrderByBackend, get_field_from_path from awx.main.models import ( AdHocCommand, ActivityStream, - Credential, Job, JobTemplate, SystemJob, @@ -20,88 +18,11 @@ WorkflowJob, WorkflowJobTemplate, WorkflowJobOptions, - InventorySource, - JobEvent, ) from awx.main.models.oauth import OAuth2Application from awx.main.models.jobs import JobOptions -def test_related(): - field_lookup = FieldLookupBackend() - lookup = '__'.join(['inventory', 'organization', 'pk']) - field, new_lookup = field_lookup.get_field_from_lookup(InventorySource, lookup) - print(field) - print(new_lookup) - - -def test_invalid_filter_key(): - field_lookup = FieldLookupBackend() - # FieldDoesNotExist is caught and converted to ParseError by filter_queryset - with pytest.raises(FieldDoesNotExist) as excinfo: - field_lookup.value_to_python(JobEvent, 'event_data.task_action', 'foo') - assert 'has no field named' in str(excinfo) - - -def test_invalid_field_hop(): - with pytest.raises(ParseError) as excinfo: - get_field_from_path(Credential, 'organization__description__user') - assert 'No related model for' in str(excinfo) - - -def test_invalid_order_by_key(): - field_order_by = OrderByBackend() - with pytest.raises(ParseError) as excinfo: - [f for f in field_order_by._validate_ordering_fields(JobEvent, ('event_data.task_action',))] - assert 'has no field named' in str(excinfo) - - -@pytest.mark.parametrize(u"empty_value", [u'', '']) -def test_empty_in(empty_value): - field_lookup = FieldLookupBackend() - with pytest.raises(ValueError) as excinfo: - field_lookup.value_to_python(JobTemplate, 'project__name__in', empty_value) - assert 'empty value for __in' in str(excinfo.value) - - -@pytest.mark.parametrize(u"valid_value", [u'foo', u'foo,']) -def test_valid_in(valid_value): - field_lookup = FieldLookupBackend() - value, new_lookup, _ = field_lookup.value_to_python(JobTemplate, 'project__name__in', valid_value) - assert 'foo' in value - - -def test_invalid_field(): - invalid_field = u"ヽヾ" - field_lookup = FieldLookupBackend() - with pytest.raises(ValueError) as excinfo: - field_lookup.value_to_python(WorkflowJobTemplate, invalid_field, 'foo') - assert 'is not an allowed field name. Must be ascii encodable.' in str(excinfo.value) - - -def test_valid_iexact(): - field_lookup = FieldLookupBackend() - value, new_lookup, _ = field_lookup.value_to_python(JobTemplate, 'project__name__iexact', 'foo') - assert 'foo' in value - - -def test_invalid_iexact(): - field_lookup = FieldLookupBackend() - with pytest.raises(ValueError) as excinfo: - field_lookup.value_to_python(Job, 'id__iexact', '1') - assert 'is not a text field and cannot be filtered by case-insensitive search' in str(excinfo.value) - - -@pytest.mark.parametrize('lookup_suffix', ['', 'contains', 'startswith', 'in']) -@pytest.mark.parametrize('password_field', Credential.PASSWORD_FIELDS) -def test_filter_on_password_field(password_field, lookup_suffix): - field_lookup = FieldLookupBackend() - lookup = '__'.join(filter(None, [password_field, lookup_suffix])) - with pytest.raises(PermissionDenied) as excinfo: - field, new_lookup = field_lookup.get_field_from_lookup(Credential, lookup) - assert 'not allowed' in str(excinfo.value) - - @pytest.mark.parametrize( 'model, query', [ @@ -128,10 +49,3 @@ def test_filter_sensitive_fields_and_relations(model, query): with pytest.raises(PermissionDenied) as excinfo: field, new_lookup = field_lookup.get_field_from_lookup(model, query) assert 'not allowed' in str(excinfo.value) - - -def test_looping_filters_prohibited(): - field_lookup = FieldLookupBackend() - with pytest.raises(ParseError) as loop_exc: - field_lookup.get_field_from_lookup(Job, 'job_events__job__job_events') - assert 'job_events' in str(loop_exc.value) diff --git a/awx/main/tests/unit/utils/test_common.py b/awx/main/tests/unit/utils/test_common.py index cc8f65bf9333..1d960c45db17 100644 --- a/awx/main/tests/unit/utils/test_common.py +++ b/awx/main/tests/unit/utils/test_common.py @@ -12,6 +12,8 @@ from rest_framework.exceptions import ParseError +from ansible_base.utils.models import get_type_for_model + from awx.main.utils import common from awx.api.validators import HostnameRegexValidator @@ -106,7 +108,7 @@ def test_set_environ(): # Cases relied on for scheduler dependent jobs list @pytest.mark.parametrize('model,name', TEST_MODELS) def test_get_type_for_model(model, name): - assert common.get_type_for_model(model) == name + assert get_type_for_model(model) == name def test_get_model_for_invalid_type(): diff --git a/awx/main/tests/unit/utils/test_filters.py b/awx/main/tests/unit/utils/test_filters.py index cf07b87d65fd..ad1115043f89 100644 --- a/awx/main/tests/unit/utils/test_filters.py +++ b/awx/main/tests/unit/utils/test_filters.py @@ -68,7 +68,9 @@ def __init__(self): @mock.patch('awx.main.utils.filters.get_model', return_value=mockHost()) class TestSmartFilterQueryFromString: - @mock.patch('awx.api.filters.get_fields_from_path', lambda model, path: ([model], path)) # disable field filtering, because a__b isn't a real Host field + @mock.patch( + 'ansible_base.filters.rest_framework.field_lookup_backend.get_fields_from_path', lambda model, path: ([model], path) + ) # disable field filtering, because a__b isn't a real Host field @pytest.mark.parametrize( "filter_string,q_expected", [ diff --git a/awx/main/utils/common.py b/awx/main/utils/common.py index 9066707d4db9..7ab98425847c 100644 --- a/awx/main/utils/common.py +++ b/awx/main/utils/common.py @@ -52,12 +52,10 @@ 'get_awx_http_client_headers', 'get_awx_version', 'update_scm_url', - 'get_type_for_model', 'get_model_for_type', 'copy_model_by_class', 'copy_m2m_relationships', 'prefetch_page_capabilities', - 'to_python_boolean', 'datetime_hook', 'ignore_inventory_computed_fields', 'ignore_inventory_group_removal', @@ -110,18 +108,6 @@ def get_object_or_400(klass, *args, **kwargs): raise ParseError(*e.args) -def to_python_boolean(value, allow_none=False): - value = str(value) - if value.lower() in ('true', '1', 't'): - return True - elif value.lower() in ('false', '0', 'f'): - return False - elif allow_none and value.lower() in ('none', 'null'): - return None - else: - raise ValueError(_(u'Unable to convert "%s" to boolean') % value) - - def datetime_hook(d): new_d = {} for key, value in d.items(): @@ -569,14 +555,6 @@ def copy_m2m_relationships(obj1, obj2, fields, kwargs=None): dest_field.add(*list(src_field_value.all().values_list('id', flat=True))) -def get_type_for_model(model): - """ - Return type name for a given model class. - """ - opts = model._meta.concrete_model._meta - return camelcase_to_underscore(opts.object_name) - - def get_model_for_type(type_name): """ Return model class for a given type name. diff --git a/awx/main/utils/db.py b/awx/main/utils/db.py index 4117c5274c5d..8cc6aacce9f2 100644 --- a/awx/main/utils/db.py +++ b/awx/main/utils/db.py @@ -1,27 +1,10 @@ # Copyright (c) 2017 Ansible by Red Hat # All Rights Reserved. -from itertools import chain from awx.settings.application_name import set_application_name from django.conf import settings -def get_all_field_names(model): - # Implements compatibility with _meta.get_all_field_names - # See: https://docs.djangoproject.com/en/1.11/ref/models/meta/#migrating-from-the-old-api - return list( - set( - chain.from_iterable( - (field.name, field.attname) if hasattr(field, 'attname') else (field.name,) - for field in model._meta.get_fields() - # For complete backwards compatibility, you may want to exclude - # GenericForeignKey from the results. - if not (field.many_to_one and field.related_model is None) - ) - ) - ) - - def set_connection_name(function): set_application_name(settings.DATABASES, settings.CLUSTER_HOST_ID, function=function) diff --git a/awx/main/utils/filters.py b/awx/main/utils/filters.py index 7f9724329b80..682938cb1662 100644 --- a/awx/main/utils/filters.py +++ b/awx/main/utils/filters.py @@ -161,7 +161,7 @@ def __init__(self, t): else: # detect loops and restrict access to sensitive fields # this import is intentional here to avoid a circular import - from awx.api.filters import FieldLookupBackend + from ansible_base.filters.rest_framework.field_lookup_backend import FieldLookupBackend FieldLookupBackend().get_field_from_lookup(Host, k) kwargs[k] = v diff --git a/awx/main/utils/licensing.py b/awx/main/utils/licensing.py index 13043e9075a2..4890b1015c85 100644 --- a/awx/main/utils/licensing.py +++ b/awx/main/utils/licensing.py @@ -199,6 +199,8 @@ def _can_aggregate(sub, license): license['support_level'] = attr.get('value') elif attr.get('name') == 'usage': license['usage'] = attr.get('value') + elif attr.get('name') == 'ph_product_name' and attr.get('value') == 'RHEL Developer': + license['license_type'] = 'developer' if not license: logger.error("No valid subscriptions found in manifest") @@ -322,7 +324,9 @@ def is_appropriate_sub(self, sub): def generate_license_options_from_entitlements(self, json): from dateutil.parser import parse - ValidSub = collections.namedtuple('ValidSub', 'sku name support_level end_date trial quantity pool_id satellite subscription_id account_number usage') + ValidSub = collections.namedtuple( + 'ValidSub', 'sku name support_level end_date trial developer_license quantity pool_id satellite subscription_id account_number usage' + ) valid_subs = [] for sub in json: satellite = sub.get('satellite') @@ -350,6 +354,7 @@ def generate_license_options_from_entitlements(self, json): sku = sub['productId'] trial = sku.startswith('S') # i.e.,, SER/SVC + developer_license = False support_level = '' usage = '' pool_id = sub['id'] @@ -364,9 +369,24 @@ def generate_license_options_from_entitlements(self, json): support_level = attr.get('value') elif attr.get('name') == 'usage': usage = attr.get('value') + elif attr.get('name') == 'ph_product_name' and attr.get('value') == 'RHEL Developer': + developer_license = True valid_subs.append( - ValidSub(sku, sub['productName'], support_level, end_date, trial, quantity, pool_id, satellite, subscription_id, account_number, usage) + ValidSub( + sku, + sub['productName'], + support_level, + end_date, + trial, + developer_license, + quantity, + pool_id, + satellite, + subscription_id, + account_number, + usage, + ) ) if valid_subs: @@ -381,6 +401,8 @@ def generate_license_options_from_entitlements(self, json): if sub.trial: license._attrs['trial'] = True license._attrs['license_type'] = 'trial' + if sub.developer_license: + license._attrs['license_type'] = 'developer' license._attrs['instance_count'] = min(MAX_INSTANCES, license._attrs['instance_count']) human_instances = license._attrs['instance_count'] if human_instances == MAX_INSTANCES: diff --git a/awx/main/wsrelay.py b/awx/main/wsrelay.py index 09d7dfe92bdc..1a5f727b5d85 100644 --- a/awx/main/wsrelay.py +++ b/awx/main/wsrelay.py @@ -3,6 +3,8 @@ import asyncio from typing import Dict +import ipaddress + import aiohttp from aiohttp import client_exceptions import aioredis @@ -71,7 +73,16 @@ async def connect(self): if not self.channel_layer: self.channel_layer = get_channel_layer() - uri = f"{self.protocol}://{self.remote_host}:{self.remote_port}/websocket/relay/" + # figure out if what we have is an ipaddress, IPv6 Addresses must have brackets added for uri + uri_hostname = self.remote_host + try: + # Throws ValueError if self.remote_host is a hostname like example.com, not an IPv4 or IPv6 ip address + if isinstance(ipaddress.ip_address(uri_hostname), ipaddress.IPv6Address): + uri_hostname = f"[{uri_hostname}]" + except ValueError: + pass + + uri = f"{self.protocol}://{uri_hostname}:{self.remote_port}/websocket/relay/" timeout = aiohttp.ClientTimeout(total=10) secret_val = WebsocketSecretAuthHelper.construct_secret() @@ -216,7 +227,8 @@ async def on_ws_heartbeat(self, conn): continue try: if not notif.payload or notif.channel != "web_ws_heartbeat": - return + logger.warning(f"Unexpected channel or missing payload. {notif.channel}, {notif.payload}") + continue try: payload = json.loads(notif.payload) @@ -224,13 +236,15 @@ async def on_ws_heartbeat(self, conn): logmsg = "Failed to decode message from pg_notify channel `web_ws_heartbeat`" if logger.isEnabledFor(logging.DEBUG): logmsg = "{} {}".format(logmsg, payload) - logger.warning(logmsg) - return + logger.warning(logmsg) + continue # Skip if the message comes from the same host we are running on # In this case, we'll be sharing a redis, no need to relay. if payload.get("hostname") == self.local_hostname: - return + hostname = payload.get("hostname") + logger.debug("Received a heartbeat request for {hostname}. Skipping as we use redis for local host.") + continue action = payload.get("action") @@ -239,7 +253,7 @@ async def on_ws_heartbeat(self, conn): ip = payload.get("ip") or hostname # try back to hostname if ip isn't supplied if ip is None: logger.warning(f"Received invalid {action} ws_heartbeat, missing hostname and ip: {payload}") - return + continue logger.debug(f"Web host {hostname} ({ip}) {action} heartbeat received.") if action == "online": diff --git a/awx/settings/defaults.py b/awx/settings/defaults.py index d12fa8d2238c..85bc45f7eb8f 100644 --- a/awx/settings/defaults.py +++ b/awx/settings/defaults.py @@ -11,6 +11,7 @@ # python-ldap import ldap +from split_settings.tools import include DEBUG = True @@ -131,6 +132,9 @@ # Maximum number of host that can be created in 1 bulk host create BULK_HOST_MAX_CREATE = 100 +# Maximum number of host that can be deleted in 1 bulk host delete +BULK_HOST_MAX_DELETE = 250 + SITE_ID = 1 # Make this unique, and don't share it with anybody. @@ -336,6 +340,7 @@ 'awx.ui', 'awx.sso', 'solo', + 'ansible_base', ] INTERNAL_IPS = ('127.0.0.1',) @@ -350,12 +355,6 @@ 'awx.api.authentication.LoggedBasicAuthentication', ), 'DEFAULT_PERMISSION_CLASSES': ('awx.api.permissions.ModelAccessPermission',), - 'DEFAULT_FILTER_BACKENDS': ( - 'awx.api.filters.TypeFilterBackend', - 'awx.api.filters.FieldLookupBackend', - 'rest_framework.filters.SearchFilter', - 'awx.api.filters.OrderByBackend', - ), 'DEFAULT_PARSER_CLASSES': ('awx.api.parsers.JSONParser',), 'DEFAULT_RENDERER_CLASSES': ('awx.api.renderers.DefaultJSONRenderer', 'awx.api.renderers.BrowsableAPIRenderer'), 'DEFAULT_METADATA_CLASS': 'awx.api.metadata.Metadata', @@ -1063,3 +1062,12 @@ # Host metric summary monthly task - last time of run HOST_METRIC_SUMMARY_TASK_LAST_TS = None HOST_METRIC_SUMMARY_TASK_INTERVAL = 7 # days + + +# django-ansible-base +ANSIBLE_BASE_FEATURES = {'AUTHENTICATION': False, 'SWAGGER': False, 'FILTERING': True} + +from ansible_base import settings # noqa: E402 + +settings_file = os.path.join(os.path.dirname(settings.__file__), 'dynamic_settings.py') +include(settings_file) diff --git a/awx/sso/conf.py b/awx/sso/conf.py index 301293096532..655640d9d765 100644 --- a/awx/sso/conf.py +++ b/awx/sso/conf.py @@ -1341,7 +1341,6 @@ def get_saml_entity_id(): 'SOCIAL_AUTH_SAML_SP_PUBLIC_CERT', field_class=fields.CharField, allow_blank=True, - required=True, validators=[validate_certificate], label=_('SAML Service Provider Public Certificate'), help_text=_('Create a keypair to use as a service provider (SP) and include the certificate content here.'), @@ -1353,7 +1352,6 @@ def get_saml_entity_id(): 'SOCIAL_AUTH_SAML_SP_PRIVATE_KEY', field_class=fields.CharField, allow_blank=True, - required=True, validators=[validate_private_key], label=_('SAML Service Provider Private Key'), help_text=_('Create a keypair to use as a service provider (SP) and include the private key content here.'), @@ -1365,7 +1363,6 @@ def get_saml_entity_id(): register( 'SOCIAL_AUTH_SAML_ORG_INFO', field_class=SAMLOrgInfoField, - required=True, label=_('SAML Service Provider Organization Info'), help_text=_('Provide the URL, display name, and the name of your app. Refer to the documentation for example syntax.'), category=_('SAML'), @@ -1379,7 +1376,6 @@ def get_saml_entity_id(): 'SOCIAL_AUTH_SAML_TECHNICAL_CONTACT', field_class=SAMLContactField, allow_blank=True, - required=True, label=_('SAML Service Provider Technical Contact'), help_text=_('Provide the name and email address of the technical contact for your service provider. Refer to the documentation for example syntax.'), category=_('SAML'), @@ -1391,7 +1387,6 @@ def get_saml_entity_id(): 'SOCIAL_AUTH_SAML_SUPPORT_CONTACT', field_class=SAMLContactField, allow_blank=True, - required=True, label=_('SAML Service Provider Support Contact'), help_text=_('Provide the name and email address of the support contact for your service provider. Refer to the documentation for example syntax.'), category=_('SAML'), diff --git a/awx/ui/src/components/Schedule/shared/ScheduleForm.js b/awx/ui/src/components/Schedule/shared/ScheduleForm.js index 43407d2737c2..8fbf83791cf2 100644 --- a/awx/ui/src/components/Schedule/shared/ScheduleForm.js +++ b/awx/ui/src/components/Schedule/shared/ScheduleForm.js @@ -20,6 +20,7 @@ import UnsupportedScheduleForm from './UnsupportedScheduleForm'; import parseRuleObj, { UnsupportedRRuleError } from './parseRuleObj'; import buildRuleObj from './buildRuleObj'; import buildRuleSet from './buildRuleSet'; +import mergeArraysByCredentialType from './mergeArraysByCredentialType'; const NUM_DAYS_PER_FREQUENCY = { week: 7, @@ -350,6 +351,12 @@ function ScheduleForm({ startDate: currentDate, startTime: time, timezone: schedule.timezone || now.zoneName, + credentials: mergeArraysByCredentialType( + resourceDefaultCredentials, + credentials + ), + labels: originalLabels.current, + instance_groups: originalInstanceGroups.current, }; if (hasDaysToKeepField) { diff --git a/awx/ui/src/components/Schedule/shared/mergeArraysByCredentialType.js b/awx/ui/src/components/Schedule/shared/mergeArraysByCredentialType.js new file mode 100644 index 000000000000..13935f930e51 --- /dev/null +++ b/awx/ui/src/components/Schedule/shared/mergeArraysByCredentialType.js @@ -0,0 +1,18 @@ +export default function mergeArraysByCredentialType( + defaultCredentials = [], + overrides = [] +) { + const mergedArray = [...defaultCredentials]; + + overrides.forEach((override) => { + const index = mergedArray.findIndex( + (defaultCred) => defaultCred.credential_type === override.credential_type + ); + if (index !== -1) { + mergedArray.splice(index, 1); + } + mergedArray.push(override); + }); + + return mergedArray; +} diff --git a/awx/ui/src/screens/Setting/Logging/LoggingEdit/LoggingEdit.js b/awx/ui/src/screens/Setting/Logging/LoggingEdit/LoggingEdit.js index 5fd86d883719..08b529192325 100644 --- a/awx/ui/src/screens/Setting/Logging/LoggingEdit/LoggingEdit.js +++ b/awx/ui/src/screens/Setting/Logging/LoggingEdit/LoggingEdit.js @@ -119,7 +119,7 @@ function LoggingEdit() { ...logging.LOG_AGGREGATOR_ENABLED, help_text: ( <> - {logging.LOG_AGGREGATOR_ENABLED.help_text} + {logging.LOG_AGGREGATOR_ENABLED?.help_text} {!formik.values.LOG_AGGREGATOR_ENABLED && (!formik.values.LOG_AGGREGATOR_HOST || !formik.values.LOG_AGGREGATOR_TYPE) && ( diff --git a/awx_collection/meta/runtime.yml b/awx_collection/meta/runtime.yml index 3e50a52e69ee..18fa4b592e2d 100644 --- a/awx_collection/meta/runtime.yml +++ b/awx_collection/meta/runtime.yml @@ -8,6 +8,7 @@ action_groups: - application - bulk_job_launch - bulk_host_create + - bulk_host_delete - controller_meta - credential_input_source - credential diff --git a/awx_collection/plugins/modules/bulk_host_delete.py b/awx_collection/plugins/modules/bulk_host_delete.py new file mode 100644 index 000000000000..12468e6028ff --- /dev/null +++ b/awx_collection/plugins/modules/bulk_host_delete.py @@ -0,0 +1,65 @@ +#!/usr/bin/python +# coding: utf-8 -*- + +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'} + +DOCUMENTATION = ''' +--- +module: bulk_host_delete +author: "Avi Layani (@Avilir)" +short_description: Bulk host delete in Automation Platform Controller +description: + - Single-request bulk host deletion in Automation Platform Controller. + - Provides a way to delete many hosts at once from inventories in Controller. +options: + hosts: + description: + - List of hosts id's to delete from inventory. + required: True + type: list + elements: int +extends_documentation_fragment: awx.awx.auth +''' + +EXAMPLES = ''' +- name: Bulk host delete + bulk_host_delete: + hosts: + - 1 + - 2 +''' + +from ..module_utils.controller_api import ControllerAPIModule + + +def main(): + # Any additional arguments that are not fields of the item can be added here + argument_spec = dict( + hosts=dict(required=True, type='list', elements='int'), + ) + + # Create a module for ourselves + module = ControllerAPIModule(argument_spec=argument_spec) + + # Extract our parameters + hosts = module.params.get('hosts') + + # Delete the hosts + result = module.post_endpoint("bulk/host_delete", data={"hosts": hosts}) + + if result['status_code'] != 201: + module.fail_json(msg="Failed to delete hosts, see response for details", response=result) + + module.json_output['changed'] = True + + module.exit_json(**module.json_output) + + +if __name__ == '__main__': + main() diff --git a/awx_collection/plugins/modules/credential.py b/awx_collection/plugins/modules/credential.py index f55574a0090c..b5fbfe9a4ed7 100644 --- a/awx_collection/plugins/modules/credential.py +++ b/awx_collection/plugins/modules/credential.py @@ -58,6 +58,7 @@ Insights, Machine, Microsoft Azure Key Vault, Microsoft Azure Resource Manager, Network, OpenShift or Kubernetes API Bearer Token, OpenStack, Red Hat Ansible Automation Platform, Red Hat Satellite 6, Red Hat Virtualization, Source Control, Thycotic DevOps Secrets Vault, Thycotic Secret Server, Vault, VMware vCenter, or a custom credential type + required: True type: str inputs: description: @@ -214,7 +215,7 @@ def main(): copy_from=dict(), description=dict(), organization=dict(), - credential_type=dict(), + credential_type=dict(required=True), inputs=dict(type='dict', no_log=True), update_secrets=dict(type='bool', default=True, no_log=False), user=dict(), diff --git a/awx_collection/test/awx/conftest.py b/awx_collection/test/awx/conftest.py index 626f85936352..3e6f571f4697 100644 --- a/awx_collection/test/awx/conftest.py +++ b/awx_collection/test/awx/conftest.py @@ -18,28 +18,53 @@ from ansible.module_utils.six import raise_from from awx.main.tests.functional.conftest import _request -from awx.main.models import Organization, Project, Inventory, JobTemplate, Credential, CredentialType, ExecutionEnvironment, UnifiedJob +from awx.main.tests.functional.conftest import credentialtype_scm, credentialtype_ssh # noqa: F401; pylint: disable=unused-variable +from awx.main.models import ( + Organization, + Project, + Inventory, + JobTemplate, + Credential, + CredentialType, + ExecutionEnvironment, + UnifiedJob, + WorkflowJobTemplate, + NotificationTemplate, + Schedule, +) from django.db import transaction -try: - import tower_cli # noqa - HAS_TOWER_CLI = True -except ImportError: - HAS_TOWER_CLI = False +HAS_TOWER_CLI = False +HAS_AWX_KIT = False +logger = logging.getLogger('awx.main.tests') -try: - # Because awxkit will be a directory at the root of this makefile and we are using python3, import awxkit will work even if its not installed. - # However, awxkit will not contain api whih causes a stack failure down on line 170 when we try to mock it. - # So here we are importing awxkit.api to prevent that. Then you only get an error on tests for awxkit functionality. - import awxkit.api # noqa - HAS_AWX_KIT = True -except ImportError: - HAS_AWX_KIT = False +@pytest.fixture(autouse=True) +def awxkit_path_set(monkeypatch): + """Monkey patch sys.path, insert awxkit source code so that + the package does not need to be installed. + """ + base_folder = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, os.pardir, 'awxkit')) + monkeypatch.syspath_prepend(base_folder) -logger = logging.getLogger('awx.main.tests') + +@pytest.fixture(autouse=True) +def import_awxkit(): + global HAS_TOWER_CLI + global HAS_AWX_KIT + try: + import tower_cli # noqa + HAS_TOWER_CLI = True + except ImportError: + HAS_TOWER_CLI = False + + try: + import awxkit # noqa + HAS_AWX_KIT = True + except ImportError: + HAS_AWX_KIT = False def sanitize_dict(din): @@ -123,7 +148,7 @@ def new_request(self, method, url, **kwargs): sanitize_dict(py_data) resp._content = bytes(json.dumps(django_response.data), encoding='utf8') resp.status_code = django_response.status_code - resp.headers = {'X-API-Product-Name': 'AWX', 'X-API-Product-Version': '0.0.1-devel'} + resp.headers = dict(django_response.headers) if request.config.getoption('verbose') > 0: logger.info('%s %s by %s, code:%s', method, '/api/' + url.split('/api/')[1], request_user.username, resp.status_code) @@ -236,10 +261,8 @@ def job_template(project, inventory): @pytest.fixture -def machine_credential(organization): - ssh_type = CredentialType.defaults['ssh']() - ssh_type.save() - return Credential.objects.create(credential_type=ssh_type, name='machine-cred', inputs={'username': 'test_user', 'password': 'pas4word'}) +def machine_credential(credentialtype_ssh, organization): # noqa: F811 + return Credential.objects.create(credential_type=credentialtype_ssh, name='machine-cred', inputs={'username': 'test_user', 'password': 'pas4word'}) @pytest.fixture @@ -253,9 +276,7 @@ def vault_credential(organization): def kube_credential(): ct = CredentialType.defaults['kubernetes_bearer_token']() ct.save() - return Credential.objects.create( - credential_type=ct, name='kube-cred', inputs={'host': 'my.cluster', 'bearer_token': 'my-token', 'verify_ssl': False} - ) + return Credential.objects.create(credential_type=ct, name='kube-cred', inputs={'host': 'my.cluster', 'bearer_token': 'my-token', 'verify_ssl': False}) @pytest.fixture @@ -288,3 +309,42 @@ def mock_has_unpartitioned_events(): # We mock this out to circumvent the migration query. with mock.patch.object(UnifiedJob, 'has_unpartitioned_events', new=False) as _fixture: yield _fixture + + +@pytest.fixture +def workflow_job_template(organization, inventory): + return WorkflowJobTemplate.objects.create(name='test-workflow_job_template', organization=organization, inventory=inventory) + + +@pytest.fixture +def notification_template(organization): + return NotificationTemplate.objects.create( + name='test-notification_template', + organization=organization, + notification_type="webhook", + notification_configuration=dict( + url="http://localhost", + username="", + password="", + headers={ + "Test": "Header", + }, + ), + ) + + +@pytest.fixture +def scm_credential(credentialtype_scm, organization): # noqa: F811 + return Credential.objects.create( + credential_type=credentialtype_scm, name='scm-cred', inputs={'username': 'optimus', 'password': 'prime'}, organization=organization + ) + + +@pytest.fixture +def rrule(): + return 'DTSTART:20151117T050000Z RRULE:FREQ=DAILY;INTERVAL=1;COUNT=1' + + +@pytest.fixture +def schedule(job_template, rrule): + return Schedule.objects.create(unified_job_template=job_template, name='test-sched', rrule=rrule) diff --git a/awx_collection/test/awx/test_bulk.py b/awx_collection/test/awx/test_bulk.py index e0315732dbd1..da45621dd0cf 100644 --- a/awx_collection/test/awx/test_bulk.py +++ b/awx_collection/test/awx/test_bulk.py @@ -45,3 +45,28 @@ def test_bulk_host_create(run_module, admin_user, inventory): resp_hosts = inventory.hosts.all().values_list('name', flat=True) for h in hosts: assert h['name'] in resp_hosts + + +@pytest.mark.django_db +def test_bulk_host_delete(run_module, admin_user, inventory): + hosts = [dict(name="127.0.0.1"), dict(name="foo.dns.org")] + result = run_module( + 'bulk_host_create', + { + 'inventory': inventory.name, + 'hosts': hosts, + }, + admin_user, + ) + assert not result.get('failed', False), result.get('msg', result) + assert result.get('changed'), result + resp_hosts_ids = list(inventory.hosts.all().values_list('id', flat=True)) + result = run_module( + 'bulk_host_delete', + { + 'hosts': resp_hosts_ids, + }, + admin_user, + ) + assert not result.get('failed', False), result.get('msg', result) + assert result.get('changed'), result diff --git a/awx_collection/test/awx/test_completeness.py b/awx_collection/test/awx/test_completeness.py index b4eb0ad3e4f9..b3c6e6e27f23 100644 --- a/awx_collection/test/awx/test_completeness.py +++ b/awx_collection/test/awx/test_completeness.py @@ -50,6 +50,7 @@ extra_endpoints = { 'bulk_job_launch': '/api/v2/bulk/job_launch/', 'bulk_host_create': '/api/v2/bulk/host_create/', + 'bulk_host_delete': '/api/v2/bulk/host_delete/', } # Global module parameters we can ignore diff --git a/awx_collection/test/awx/test_export.py b/awx_collection/test/awx/test_export.py new file mode 100644 index 000000000000..a70b451df461 --- /dev/null +++ b/awx_collection/test/awx/test_export.py @@ -0,0 +1,154 @@ +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +import pytest + +from awx.main.models.execution_environments import ExecutionEnvironment +from awx.main.models.jobs import JobTemplate + +from awx.main.tests.functional.conftest import user, system_auditor # noqa: F401; pylint: disable=unused-import + + +ASSETS = set([ + "users", + "organizations", + "teams", + "credential_types", + "credentials", + "notification_templates", + "projects", + "inventory", + "inventory_sources", + "job_templates", + "workflow_job_templates", + "execution_environments", + "applications", + "schedules", +]) + + +@pytest.fixture +def job_template(project, inventory, organization, machine_credential): + jt = JobTemplate.objects.create(name='test-jt', project=project, inventory=inventory, organization=organization, playbook='helloworld.yml') + jt.credentials.add(machine_credential) + jt.save() + return jt + + +@pytest.fixture +def execution_environment(organization): + return ExecutionEnvironment.objects.create(name="test-ee", description="test-ee", managed=False, organization=organization) + + +def find_by(result, name, key, value): + for c in result[name]: + if c[key] == value: + return c + values = [c.get(key, None) for c in result[name]] + raise ValueError(f"Failed to find assets['{name}'][{key}] = '{value}' valid values are {values}") + + +@pytest.mark.django_db +def test_export(run_module, admin_user): + """ + There should be nothing to export EXCEPT the admin user. + """ + result = run_module('export', dict(all=True), admin_user) + assert not result.get('failed', False), result.get('msg', result) + assets = result['assets'] + + assert set(result['assets'].keys()) == ASSETS + + u = find_by(assets, 'users', 'username', 'admin') + assert u['is_superuser'] is True + + all_assets_except_users = {k: v for k, v in assets.items() if k != 'users'} + + for k, v in all_assets_except_users.items(): + assert v == [], f"Expected resource {k} to be empty. Instead it is {v}" + + +@pytest.mark.django_db +def test_export_simple( + run_module, + organization, + project, + inventory, + job_template, + scm_credential, + machine_credential, + workflow_job_template, + execution_environment, + notification_template, + rrule, + schedule, + admin_user, +): + """ + TODO: Ensure there aren't _more_ results in each resource than we expect + """ + result = run_module('export', dict(all=True), admin_user) + assert not result.get('failed', False), result.get('msg', result) + assets = result['assets'] + + u = find_by(assets, 'users', 'username', 'admin') + assert u['is_superuser'] is True + + find_by(assets, 'organizations', 'name', 'Default') + + r = find_by(assets, 'credentials', 'name', 'scm-cred') + assert r['credential_type']['kind'] == 'scm' + assert r['credential_type']['name'] == 'Source Control' + + r = find_by(assets, 'credentials', 'name', 'machine-cred') + assert r['credential_type']['kind'] == 'ssh' + assert r['credential_type']['name'] == 'Machine' + + r = find_by(assets, 'job_templates', 'name', 'test-jt') + assert r['natural_key']['organization']['name'] == 'Default' + assert r['inventory']['name'] == 'test-inv' + assert r['project']['name'] == 'test-proj' + + find_by(r['related'], 'credentials', 'name', 'machine-cred') + + r = find_by(assets, 'inventory', 'name', 'test-inv') + assert r['organization']['name'] == 'Default' + + r = find_by(assets, 'projects', 'name', 'test-proj') + assert r['organization']['name'] == 'Default' + + r = find_by(assets, 'workflow_job_templates', 'name', 'test-workflow_job_template') + assert r['natural_key']['organization']['name'] == 'Default' + assert r['inventory']['name'] == 'test-inv' + + r = find_by(assets, 'execution_environments', 'name', 'test-ee') + assert r['organization']['name'] == 'Default' + + r = find_by(assets, 'schedules', 'name', 'test-sched') + assert r['rrule'] == rrule + + r = find_by(assets, 'notification_templates', 'name', 'test-notification_template') + assert r['organization']['name'] == 'Default' + assert r['notification_configuration']['url'] == 'http://localhost' + + +@pytest.mark.django_db +def test_export_system_auditor(run_module, schedule, system_auditor): # noqa: F811 + """ + This test illustrates that deficiency of export when ran as non-root user (i.e. system auditor). + The OPTIONS endpoint does NOT return POST for a system auditor. This is bad for the export code + because it relies on crawling the OPTIONS POST response to determine the fields to export. + """ + result = run_module('export', dict(all=True), system_auditor) + assert result.get('failed', False), result.get('msg', result) + + assert 'Failed to export assets substring not found' in result['msg'], ( + 'If you found this error then you have probably fixed a feature! The export code attempts to assertain the POST fields from the `description` field,' + ' but both the API side and the client inference code are lacking.' + ) + + # r = result['assets']['schedules'][0] + # assert r['natural_key']['name'] == 'test-sched' + + # assert 'rrule' not in r, 'If you found this error then you have probably fixed a feature! We WANT rrule to be found in the export schedule payload.' diff --git a/awx_collection/tests/integration/targets/bulk_host_delete/tasks/main.yml b/awx_collection/tests/integration/targets/bulk_host_delete/tasks/main.yml new file mode 100644 index 000000000000..5f38efe7c6b2 --- /dev/null +++ b/awx_collection/tests/integration/targets/bulk_host_delete/tasks/main.yml @@ -0,0 +1,80 @@ +--- +- name: "Generate a random string for test" + set_fact: + test_id: "{{ lookup('password', '/dev/null chars=ascii_letters length=16') }}" + when: "test_id is not defined" + +- name: "Generate a unique name" + set_fact: + bulk_inv_name: "AWX-Collection-tests-bulk_host_create-{{ test_id }}" + +- name: "Get our collection package" + controller_meta: + register: "controller_meta" + +- name: "Generate the name of our plugin" + set_fact: + plugin_name: "{{ controller_meta.prefix }}.controller_api" + +- name: "Create an inventory" + inventory: + name: "{{ bulk_inv_name }}" + organization: "Default" + state: "present" + register: "inventory_result" + +- name: "Bulk Host Create" + bulk_host_create: + hosts: + - name: "123.456.789.123" + description: "myhost1" + variables: + food: "carrot" + color: "orange" + - name: "example.dns.gg" + description: "myhost2" + enabled: "false" + inventory: "{{ bulk_inv_name }}" + register: "result" + +- assert: + that: + - "result is not failed" + +- name: "Get our collection package" + controller_meta: + register: "controller_meta" + +- name: "Generate the name of our plugin" + set_fact: + plugin_name: "{{ controller_meta.prefix }}.controller_api" + +- name: "Setting the inventory hosts endpoint" + set_fact: + endpoint: "inventories/{{ inventory_result.id }}/hosts/" + +- name: "Get hosts information from inventory" + set_fact: + hosts_created: "{{ query(plugin_name, endpoint, return_objects=True) }}" + host_id_list: [] + +- name: "Extract host IDs from hosts information" + set_fact: + host_id_list: "{{ host_id_list + [item.id] }}" + loop: "{{ hosts_created }}" + +- name: "Bulk Host Delete" + bulk_host_delete: + hosts: "{{ host_id_list }}" + register: "result" + +- assert: + that: + - "result is not failed" + +# cleanup +- name: "Delete inventory" + inventory: + name: "{{ bulk_inv_name }}" + organization: "Default" + state: "absent" diff --git a/awx_collection/tests/integration/targets/bulk_job_launch/tasks/main.yml b/awx_collection/tests/integration/targets/bulk_job_launch/tasks/main.yml index cd152a8eef29..f4a107ecfb50 100644 --- a/awx_collection/tests/integration/targets/bulk_job_launch/tasks/main.yml +++ b/awx_collection/tests/integration/targets/bulk_job_launch/tasks/main.yml @@ -60,7 +60,7 @@ - result['job_info']['skip_tags'] == "skipbaz" - result['job_info']['limit'] == "localhost" - result['job_info']['job_tags'] == "Hello World" - - result['job_info']['inventory'] == {{ inventory_id }} + - result['job_info']['inventory'] == inventory_id | int - "result['job_info']['extra_vars'] == '{\"animal\": \"bear\", \"food\": \"carrot\"}'" # cleanup diff --git a/awx_collection/tests/integration/targets/credential/tasks/main.yml b/awx_collection/tests/integration/targets/credential/tasks/main.yml index 428eab5f8b17..34dd058d97d1 100644 --- a/awx_collection/tests/integration/targets/credential/tasks/main.yml +++ b/awx_collection/tests/integration/targets/credential/tasks/main.yml @@ -71,6 +71,19 @@ that: - "result is changed" +- name: Delete a credential without credential_type + credential: + name: "{{ ssh_cred_name1 }}" + organization: Default + state: absent + register: result + ignore_errors: true + +- assert: + that: + - "result is failed" + + - name: Create an Org-specific credential with an ID with exists credential: name: "{{ ssh_cred_name1 }}" diff --git a/awx_collection/tests/integration/targets/job_list/tasks/main.yml b/awx_collection/tests/integration/targets/job_list/tasks/main.yml index 04495bfcba5a..b9e602cb4972 100644 --- a/awx_collection/tests/integration/targets/job_list/tasks/main.yml +++ b/awx_collection/tests/integration/targets/job_list/tasks/main.yml @@ -16,7 +16,7 @@ - assert: that: - - "{{ matching_jobs.count }} == 1" + - matching_jobs.count == 1 - name: List failed jobs (which don't exist) job_list: @@ -26,7 +26,7 @@ - assert: that: - - "{{ successful_jobs.count }} == 0" + - successful_jobs.count == 0 - name: Get ALL result pages! job_list: diff --git a/awx_collection/tests/integration/targets/job_wait/tasks/main.yml b/awx_collection/tests/integration/targets/job_wait/tasks/main.yml index 60a53f209a79..cc38e171d3da 100644 --- a/awx_collection/tests/integration/targets/job_wait/tasks/main.yml +++ b/awx_collection/tests/integration/targets/job_wait/tasks/main.yml @@ -99,7 +99,7 @@ that: - wait_results is failed - 'wait_results.status == "canceled"' - - "wait_results.msg == 'Job with id {{ job.id }} failed' or 'Job with id={{ job.id }} failed, error: Job failed.'" + - "'Job with id ~ job.id failed' or 'Job with id= ~ job.id failed, error: Job failed.' is in wait_results.msg" # workflow wait test - name: Generate a random string for test diff --git a/awx_collection/tests/integration/targets/lookup_api_plugin/tasks/main.yml b/awx_collection/tests/integration/targets/lookup_api_plugin/tasks/main.yml index 511dc727552b..6fac5a0bce1f 100644 --- a/awx_collection/tests/integration/targets/lookup_api_plugin/tasks/main.yml +++ b/awx_collection/tests/integration/targets/lookup_api_plugin/tasks/main.yml @@ -132,7 +132,7 @@ - name: Get the ID of the first user created and verify that it is correct assert: - that: "{{ query(plugin_name, 'users', query_params={ 'username' : user_creation_results['results'][0]['item'] }, return_ids=True)[0] }} == {{ user_creation_results['results'][0]['id'] }}" + that: "query(plugin_name, 'users', query_params={ 'username' : user_creation_results['results'][0]['item'] }, return_ids=True)[0] == user_creation_results['results'][0]['id'] | string" - name: Try to get an ID of someone who does not exist set_fact: diff --git a/awx_collection/tests/integration/targets/lookup_rruleset/tasks/main.yml b/awx_collection/tests/integration/targets/lookup_rruleset/tasks/main.yml index 6ff771749e82..28ad1da96b25 100644 --- a/awx_collection/tests/integration/targets/lookup_rruleset/tasks/main.yml +++ b/awx_collection/tests/integration/targets/lookup_rruleset/tasks/main.yml @@ -11,7 +11,7 @@ - name: Call ruleset with no rules set_fact: - complex_rule: "{{ query(ruleset_plugin_name, '2022-04-30 10:30:45') }}" + complex_rule: "{{ query(ruleset_plugin_name | string, '2022-04-30 10:30:45') }}" ignore_errors: True register: results diff --git a/awx_collection/tests/integration/targets/schedule/tasks/main.yml b/awx_collection/tests/integration/targets/schedule/tasks/main.yml index 6f9eca1b33b6..c61785d3b756 100644 --- a/awx_collection/tests/integration/targets/schedule/tasks/main.yml +++ b/awx_collection/tests/integration/targets/schedule/tasks/main.yml @@ -36,7 +36,7 @@ - assert: that: - result is failed - - "'Unable to create schedule {{ sched1 }}' in result.msg" + - "'Unable to create schedule '~ sched1 in result.msg" - name: Create with options that the JT does not support schedule: @@ -62,7 +62,7 @@ - assert: that: - result is failed - - "'Unable to create schedule {{ sched1 }}' in result.msg" + - "'Unable to create schedule '~ sched1 in result.msg" - name: Build a real schedule schedule: diff --git a/awx_collection/tests/integration/targets/schedule_rrule/tasks/main.yml b/awx_collection/tests/integration/targets/schedule_rrule/tasks/main.yml index bf416b813dc0..af2d95300172 100644 --- a/awx_collection/tests/integration/targets/schedule_rrule/tasks/main.yml +++ b/awx_collection/tests/integration/targets/schedule_rrule/tasks/main.yml @@ -9,7 +9,7 @@ - name: Test too many params (failure from validation of terms) debug: - msg: "{{ query(plugin_name, 'none', 'weekly', start_date='2020-4-16 03:45:07') }}" + msg: "{{ query(plugin_name | string, 'none', 'weekly', start_date='2020-4-16 03:45:07') }}" ignore_errors: true register: result diff --git a/awx_collection/tests/integration/targets/workflow_launch/tasks/main.yml b/awx_collection/tests/integration/targets/workflow_launch/tasks/main.yml index a328b8380183..ce41c6bb87d7 100644 --- a/awx_collection/tests/integration/targets/workflow_launch/tasks/main.yml +++ b/awx_collection/tests/integration/targets/workflow_launch/tasks/main.yml @@ -57,7 +57,7 @@ - assert: that: - result is failed - - "'Monitoring of Workflow Job - {{ wfjt_name1 }} aborted due to timeout' in result.msg" + - "'Monitoring of Workflow Job - '~ wfjt_name1 ~ ' aborted due to timeout' in result.msg" - name: Kick off a workflow and wait for it workflow_launch: diff --git a/awxkit/awxkit/cli/custom.py b/awxkit/awxkit/cli/custom.py index 431fef07e8d4..6d2be2475cb3 100644 --- a/awxkit/awxkit/cli/custom.py +++ b/awxkit/awxkit/cli/custom.py @@ -143,6 +143,26 @@ def perform(self, **kwargs): return response +class BulkHostDelete(CustomAction): + action = 'host_delete' + resource = 'bulk' + + @property + def options_endpoint(self): + return self.page.endpoint + '{}/'.format(self.action) + + def add_arguments(self, parser, resource_options_parser): + options = self.page.connection.options(self.options_endpoint) + if options.ok: + options = options.json()['actions']['POST'] + resource_options_parser.options['HOSTDELETEPOST'] = options + resource_options_parser.build_query_arguments(self.action, 'HOSTDELETEPOST') + + def perform(self, **kwargs): + response = self.page.get().host_delete.post(kwargs) + return response + + class ProjectUpdate(Launchable, CustomAction): action = 'update' resource = 'projects' diff --git a/awxkit/awxkit/cli/options.py b/awxkit/awxkit/cli/options.py index 848e4f6bf7d3..ecedf3918d23 100644 --- a/awxkit/awxkit/cli/options.py +++ b/awxkit/awxkit/cli/options.py @@ -270,6 +270,10 @@ def json_or_yaml(v, expected_type=dict): if k == 'hosts': kwargs['type'] = list_of_json_or_yaml kwargs['required'] = required = True + if method == "host_delete": + if k == 'hosts': + kwargs['type'] = list_of_json_or_yaml + kwargs['required'] = required = True if method == "job_launch": if k == 'jobs': kwargs['type'] = list_of_json_or_yaml diff --git a/docs/bulk_api.md b/docs/bulk_api.md index 493e9575ba65..5fdf94b4e2ea 100644 --- a/docs/bulk_api.md +++ b/docs/bulk_api.md @@ -3,6 +3,7 @@ Bulk API endpoints allows to perform bulk operations in single web request. There are currently following bulk api actions: - /api/v2/bulk/job_launch - /api/v2/bulk/host_create +- /api/v2/bulk/host_delete Making individual API calls in rapid succession or at high concurrency can overwhelm AWX's ability to serve web requests. When the application's ability to serve is exhausted, clients often receive 504 timeout errors. @@ -99,3 +100,20 @@ Following is an example of a post request at the /api/v2/bulk/host_create: The above will add 6 hosts in the inventory. The maximum number of hosts allowed to be added is controlled by the setting `BULK_HOST_MAX_CREATE`. The default is 100 hosts. Additionally, nginx limits the maximum payload size, which is very likely when posting a large number of hosts in one request with variable data associated with them. The maximum payload size is 1MB unless overridden in your nginx config. + + +## Bulk Host Delete + +Provides feature in the API that allows a single web request to delete multiple hosts from an inventory. + +Following is an example of a post request at the /api/v2/bulk/host_delete: + + + { + "hosts": [3, 4, 5, 6, 7 ,8, 9, 10] + } + + +The above will delete 8 hosts from the inventory. + +The maximum number of hosts allowed to be deleted is controlled by the setting `BULK_HOST_MAX_DELETE`. The default is 250 hosts. Additionally, nginx limits the maximum payload size, which is very likely when posting a large number of hosts in one request with variable data associated with them. The maximum payload size is 1MB unless overridden in your nginx config. diff --git a/docs/docsite/conf.py b/docs/docsite/conf.py index 74553d56b1ec..2a733792edd4 100644 --- a/docs/docsite/conf.py +++ b/docs/docsite/conf.py @@ -5,7 +5,7 @@ from datetime import datetime from importlib import import_module -#sys.path.insert(0, os.path.abspath('./rst/rest_api/_swagger')) +sys.path.insert(0, os.path.abspath('./rst/rest_api/_swagger')) project = u'Ansible AWX' copyright = u'2023, Red Hat' @@ -35,6 +35,7 @@ 'sphinx.ext.coverage', 'sphinx.ext.ifconfig', 'sphinx_ansible_theme', + 'swagger', ] html_theme = 'sphinx_ansible_theme' diff --git a/docs/docsite/requirements.txt b/docs/docsite/requirements.txt index 46bad56c7d28..c06e40780186 100644 --- a/docs/docsite/requirements.txt +++ b/docs/docsite/requirements.txt @@ -8,13 +8,13 @@ alabaster==0.7.13 # via sphinx ansible-pygments==0.1.1 # via sphinx-ansible-theme -babel==2.12.1 +babel==2.13.1 # via sphinx certifi==2023.7.22 # via requests -charset-normalizer==3.2.0 +charset-normalizer==3.3.2 # via requests -docutils==0.16 +docutils==0.18.1 # via # -r docs/docsite/requirements.in # sphinx @@ -23,13 +23,13 @@ idna==3.4 # via requests imagesize==1.4.1 # via sphinx -jinja2==3.0.3 +jinja2==3.1.2 # via # -r docs/docsite/requirements.in # sphinx markupsafe==2.1.3 # via jinja2 -packaging==23.1 +packaging==23.2 # via sphinx pygments==2.16.1 # via @@ -41,7 +41,7 @@ requests==2.31.0 # via sphinx snowballstemmer==2.2.0 # via sphinx -sphinx==5.1.1 +sphinx==7.2.6 # via # -r docs/docsite/requirements.in # sphinx-ansible-theme @@ -52,7 +52,7 @@ sphinx==5.1.1 # sphinxcontrib-jquery # sphinxcontrib-qthelp # sphinxcontrib-serializinghtml -sphinx-ansible-theme==0.9.1 +sphinx-ansible-theme==0.10.2 # via -r docs/docsite/requirements.in sphinx-rtd-theme==1.3.0 # via sphinx-ansible-theme @@ -70,5 +70,5 @@ sphinxcontrib-qthelp==1.0.6 # via sphinx sphinxcontrib-serializinghtml==1.1.9 # via sphinx -urllib3==2.0.4 +urllib3==2.1.0 # via requests diff --git a/docs/docsite/rst/common/images/instances_list_view.png b/docs/docsite/rst/common/images/instances_list_view.png index dd18a7da1ac3feded9cbaeff779304ef1e908601..212f7036090be825435c88391b770f33f64c8978 100644 GIT binary patch literal 131312 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º1uoZ@EvoGmX@g-5 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 z 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

)~g@Aki^WPRtQ;`y!Qt>hrD5TVt}b1pQQSkxj# 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 literal 227243 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�=#|y)}Ir71<6xg5>@5M&E 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

DbEp`I9Y$hi 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