mirror of
https://github.com/ansible/awx.git
synced 2026-04-05 10:09:20 -02:30
Compare commits
21 Commits
23.4.0
...
feature_ad
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a689f87f1c | ||
|
|
7501ad6836 | ||
|
|
dd00bbba42 | ||
|
|
fe6bac6d9e | ||
|
|
87abbd4b10 | ||
|
|
fb04e5d9f6 | ||
|
|
478e2cb28d | ||
|
|
2ac304d289 | ||
|
|
3e5851f3af | ||
|
|
adb1b12074 | ||
|
|
8fae20c48a | ||
|
|
ec364cc60e | ||
|
|
1cfd51764e | ||
|
|
0b8fedfd04 | ||
|
|
72a8173462 | ||
|
|
873b1fbe07 | ||
|
|
1f36e84b45 | ||
|
|
8c4bff2b86 | ||
|
|
14f636af84 | ||
|
|
0057c8daf6 | ||
|
|
d8a28b3c06 |
12
.github/actions/run_awx_devel/action.yml
vendored
12
.github/actions/run_awx_devel/action.yml
vendored
@@ -43,10 +43,14 @@ runs:
|
|||||||
- name: Update default AWX password
|
- name: Update default AWX password
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
while [[ "$(curl -s -o /dev/null -w ''%{http_code}'' -k https://localhost:8043/api/v2/ping/)" != "200" ]]
|
SECONDS=0
|
||||||
do
|
while [[ "$(curl -s -o /dev/null -w ''%{http_code}'' -k https://localhost:8043/api/v2/ping/)" != "200" ]]; do
|
||||||
echo "Waiting for AWX..."
|
if [[ $SECONDS -gt 600 ]]; then
|
||||||
sleep 5
|
echo "Timing out, AWX never came up"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "Waiting for AWX..."
|
||||||
|
sleep 5
|
||||||
done
|
done
|
||||||
echo "AWX is up, updating the password..."
|
echo "AWX is up, updating the password..."
|
||||||
docker exec -i tools_awx_1 sh <<-EOSH
|
docker exec -i tools_awx_1 sh <<-EOSH
|
||||||
|
|||||||
8
.github/workflows/ci.yml
vendored
8
.github/workflows/ci.yml
vendored
@@ -11,6 +11,7 @@ jobs:
|
|||||||
common-tests:
|
common-tests:
|
||||||
name: ${{ matrix.tests.name }}
|
name: ${{ matrix.tests.name }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 60
|
||||||
permissions:
|
permissions:
|
||||||
packages: write
|
packages: write
|
||||||
contents: read
|
contents: read
|
||||||
@@ -20,6 +21,8 @@ jobs:
|
|||||||
tests:
|
tests:
|
||||||
- name: api-test
|
- name: api-test
|
||||||
command: /start_tests.sh
|
command: /start_tests.sh
|
||||||
|
- name: api-migrations
|
||||||
|
command: /start_tests.sh test_migrations
|
||||||
- name: api-lint
|
- name: api-lint
|
||||||
command: /var/lib/awx/venv/awx/bin/tox -e linters
|
command: /var/lib/awx/venv/awx/bin/tox -e linters
|
||||||
- name: api-swagger
|
- name: api-swagger
|
||||||
@@ -47,6 +50,7 @@ jobs:
|
|||||||
|
|
||||||
dev-env:
|
dev-env:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 60
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
@@ -61,6 +65,7 @@ jobs:
|
|||||||
|
|
||||||
awx-operator:
|
awx-operator:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 60
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout awx
|
- name: Checkout awx
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
@@ -110,6 +115,7 @@ jobs:
|
|||||||
collection-sanity:
|
collection-sanity:
|
||||||
name: awx_collection sanity
|
name: awx_collection sanity
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 30
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
steps:
|
steps:
|
||||||
@@ -129,6 +135,7 @@ jobs:
|
|||||||
collection-integration:
|
collection-integration:
|
||||||
name: awx_collection integration
|
name: awx_collection integration
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 60
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
@@ -180,6 +187,7 @@ jobs:
|
|||||||
collection-integration-coverage-combine:
|
collection-integration-coverage-combine:
|
||||||
name: combine awx_collection integration coverage
|
name: combine awx_collection integration coverage
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 10
|
||||||
needs:
|
needs:
|
||||||
- collection-integration
|
- collection-integration
|
||||||
strategy:
|
strategy:
|
||||||
|
|||||||
1
.github/workflows/devel_images.yml
vendored
1
.github/workflows/devel_images.yml
vendored
@@ -12,6 +12,7 @@ jobs:
|
|||||||
push:
|
push:
|
||||||
if: endsWith(github.repository, '/awx') || startsWith(github.ref, 'refs/heads/release_')
|
if: endsWith(github.repository, '/awx') || startsWith(github.ref, 'refs/heads/release_')
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 60
|
||||||
permissions:
|
permissions:
|
||||||
packages: write
|
packages: write
|
||||||
contents: read
|
contents: read
|
||||||
|
|||||||
1
.github/workflows/docs.yml
vendored
1
.github/workflows/docs.yml
vendored
@@ -6,6 +6,7 @@ jobs:
|
|||||||
docsite-build:
|
docsite-build:
|
||||||
name: docsite test build
|
name: docsite test build
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 30
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
push:
|
push:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 20
|
||||||
permissions:
|
permissions:
|
||||||
packages: write
|
packages: write
|
||||||
contents: read
|
contents: read
|
||||||
|
|||||||
2
.github/workflows/label_issue.yml
vendored
2
.github/workflows/label_issue.yml
vendored
@@ -13,6 +13,7 @@ permissions:
|
|||||||
jobs:
|
jobs:
|
||||||
triage:
|
triage:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 20
|
||||||
name: Label Issue
|
name: Label Issue
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@@ -26,6 +27,7 @@ jobs:
|
|||||||
|
|
||||||
community:
|
community:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 20
|
||||||
name: Label Issue - Community
|
name: Label Issue - Community
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
|||||||
2
.github/workflows/label_pr.yml
vendored
2
.github/workflows/label_pr.yml
vendored
@@ -14,6 +14,7 @@ permissions:
|
|||||||
jobs:
|
jobs:
|
||||||
triage:
|
triage:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 20
|
||||||
name: Label PR
|
name: Label PR
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@@ -25,6 +26,7 @@ jobs:
|
|||||||
|
|
||||||
community:
|
community:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 20
|
||||||
name: Label PR - Community
|
name: Label PR - Community
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
|||||||
1
.github/workflows/pr_body_check.yml
vendored
1
.github/workflows/pr_body_check.yml
vendored
@@ -10,6 +10,7 @@ jobs:
|
|||||||
if: github.repository_owner == 'ansible' && endsWith(github.repository, 'awx')
|
if: github.repository_owner == 'ansible' && endsWith(github.repository, 'awx')
|
||||||
name: Scan PR description for semantic versioning keywords
|
name: Scan PR description for semantic versioning keywords
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 20
|
||||||
permissions:
|
permissions:
|
||||||
packages: write
|
packages: write
|
||||||
contents: read
|
contents: read
|
||||||
|
|||||||
3
.github/workflows/promote.yml
vendored
3
.github/workflows/promote.yml
vendored
@@ -15,6 +15,7 @@ jobs:
|
|||||||
promote:
|
promote:
|
||||||
if: endsWith(github.repository, '/awx')
|
if: endsWith(github.repository, '/awx')
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 90
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout awx
|
- name: Checkout awx
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
@@ -46,7 +47,7 @@ jobs:
|
|||||||
COLLECTION_TEMPLATE_VERSION: true
|
COLLECTION_TEMPLATE_VERSION: true
|
||||||
run: |
|
run: |
|
||||||
make build_collection
|
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"; \
|
echo "Galaxy release already done"; \
|
||||||
else \
|
else \
|
||||||
ansible-galaxy collection publish \
|
ansible-galaxy collection publish \
|
||||||
|
|||||||
1
.github/workflows/stage.yml
vendored
1
.github/workflows/stage.yml
vendored
@@ -23,6 +23,7 @@ jobs:
|
|||||||
stage:
|
stage:
|
||||||
if: endsWith(github.repository, '/awx')
|
if: endsWith(github.repository, '/awx')
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 90
|
||||||
permissions:
|
permissions:
|
||||||
packages: write
|
packages: write
|
||||||
contents: write
|
contents: write
|
||||||
|
|||||||
1
.github/workflows/update_dependabot_prs.yml
vendored
1
.github/workflows/update_dependabot_prs.yml
vendored
@@ -9,6 +9,7 @@ jobs:
|
|||||||
name: Update Dependabot Prs
|
name: Update Dependabot Prs
|
||||||
if: contains(github.event.pull_request.labels.*.name, 'dependencies') && contains(github.event.pull_request.labels.*.name, 'component:ui')
|
if: contains(github.event.pull_request.labels.*.name, 'dependencies') && contains(github.event.pull_request.labels.*.name, 'component:ui')
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 20
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout branch
|
- name: Checkout branch
|
||||||
|
|||||||
1
.github/workflows/upload_schema.yml
vendored
1
.github/workflows/upload_schema.yml
vendored
@@ -13,6 +13,7 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
push:
|
push:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 60
|
||||||
permissions:
|
permissions:
|
||||||
packages: write
|
packages: write
|
||||||
contents: read
|
contents: read
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ build:
|
|||||||
3.11
|
3.11
|
||||||
commands:
|
commands:
|
||||||
- pip install --user tox
|
- 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/
|
- mkdir -p _readthedocs/html/
|
||||||
- mv docs/docsite/build/html/* _readthedocs/html/
|
- mv docs/docsite/build/html/* _readthedocs/html/
|
||||||
|
|||||||
6
Makefile
6
Makefile
@@ -324,6 +324,12 @@ test:
|
|||||||
cd awxkit && $(VENV_BASE)/awx/bin/tox -re py3
|
cd awxkit && $(VENV_BASE)/awx/bin/tox -re py3
|
||||||
awx-manage check_migrations --dry-run --check -n 'missing_migration_file'
|
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.
|
## Runs AWX_DOCKER_CMD inside a new docker container.
|
||||||
docker-runner:
|
docker-runner:
|
||||||
docker run -u $(shell id -u) --rm -v $(shell pwd):/awx_devel/:Z --workdir=/awx_devel $(DEVEL_IMAGE_NAME) $(AWX_DOCKER_CMD)
|
docker run -u $(shell id -u) --rm -v $(shell pwd):/awx_devel/:Z --workdir=/awx_devel $(DEVEL_IMAGE_NAME) $(AWX_DOCKER_CMD)
|
||||||
|
|||||||
@@ -128,6 +128,10 @@ logger = logging.getLogger('awx.api.views')
|
|||||||
|
|
||||||
|
|
||||||
def unpartitioned_event_horizon(cls):
|
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:
|
with connection.cursor() as cursor:
|
||||||
try:
|
try:
|
||||||
cursor.execute(f'SELECT MAX(id) FROM _unpartitioned_{cls._meta.db_table}')
|
cursor.execute(f'SELECT MAX(id) FROM _unpartitioned_{cls._meta.db_table}')
|
||||||
|
|||||||
@@ -79,7 +79,6 @@ __all__ = [
|
|||||||
'get_user_queryset',
|
'get_user_queryset',
|
||||||
'check_user_access',
|
'check_user_access',
|
||||||
'check_user_access_with_errors',
|
'check_user_access_with_errors',
|
||||||
'user_accessible_objects',
|
|
||||||
'consumer_access',
|
'consumer_access',
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -136,10 +135,6 @@ def register_access(model_class, access_class):
|
|||||||
access_registry[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):
|
def get_user_queryset(user, model_class):
|
||||||
"""
|
"""
|
||||||
Return a queryset for the given model_class containing only the instances
|
Return a queryset for the given model_class containing only the instances
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ from .plugin import CredentialPlugin
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from delinea.secrets.vault import PasswordGrantAuthorizer, SecretsVault
|
from delinea.secrets.vault import PasswordGrantAuthorizer, SecretsVault
|
||||||
|
from base64 import b64decode
|
||||||
|
|
||||||
dsv_inputs = {
|
dsv_inputs = {
|
||||||
'fields': [
|
'fields': [
|
||||||
@@ -44,8 +45,16 @@ dsv_inputs = {
|
|||||||
'help_text': _('The field to extract from the secret'),
|
'help_text': _('The field to extract from the secret'),
|
||||||
'type': 'string',
|
'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:
|
if settings.DEBUG:
|
||||||
@@ -67,12 +76,18 @@ def dsv_backend(**kwargs):
|
|||||||
client_secret = kwargs['client_secret']
|
client_secret = kwargs['client_secret']
|
||||||
secret_path = kwargs['path']
|
secret_path = kwargs['path']
|
||||||
secret_field = kwargs['secret_field']
|
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("."))
|
tenant_url = tenant_url_template.format(tenant_name, tenant_tld.strip("."))
|
||||||
|
|
||||||
authorizer = PasswordGrantAuthorizer(tenant_url, client_id, client_secret)
|
authorizer = PasswordGrantAuthorizer(tenant_url, client_id, client_secret)
|
||||||
dsv_secret = SecretsVault(tenant_url, authorizer).get_secret(secret_path)
|
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]
|
return dsv_secret['data'][secret_field]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ from django.conf import settings
|
|||||||
# AWX
|
# AWX
|
||||||
import awx.main.fields
|
import awx.main.fields
|
||||||
from awx.main.models import Host
|
from awx.main.models import Host
|
||||||
|
from ._sqlite_helper import dbawaremigrations
|
||||||
|
|
||||||
|
|
||||||
def replaces():
|
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.',
|
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),
|
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;',
|
reverse_sql='DROP INDEX host_ansible_facts_default_gin;',
|
||||||
|
sqlite_sql=dbawaremigrations.RunSQL.noop,
|
||||||
|
sqlite_reverse_sql=dbawaremigrations.RunSQL.noop,
|
||||||
),
|
),
|
||||||
# SCM file-based inventories
|
# SCM file-based inventories
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
|
|||||||
@@ -3,24 +3,27 @@ from __future__ import unicode_literals
|
|||||||
|
|
||||||
from django.db import migrations
|
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):
|
class Migration(migrations.Migration):
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('main', '0049_v330_validate_instance_capacity_adjustment'),
|
('main', '0049_v330_validate_instance_capacity_adjustment'),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [dbawaremigrations.RunSQL(p, sqlite_sql=s) for p, s in zip(postgres_sql, sqlite_sql)]
|
||||||
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',
|
|
||||||
)
|
|
||||||
]
|
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
from django.db import migrations, models, connection
|
from django.db import migrations, models, connection
|
||||||
|
|
||||||
|
from ._sqlite_helper import dbawaremigrations
|
||||||
|
|
||||||
|
|
||||||
def migrate_event_data(apps, schema_editor):
|
def migrate_event_data(apps, schema_editor):
|
||||||
# see: https://github.com/ansible/awx/issues/6010
|
# 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;')
|
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):
|
class FakeAlterField(migrations.AlterField):
|
||||||
def database_forwards(self, *args):
|
def database_forwards(self, *args):
|
||||||
# this is intentionally left blank, because we're
|
# this is intentionally left blank, because we're
|
||||||
@@ -37,7 +44,7 @@ class Migration(migrations.Migration):
|
|||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.RunPython(migrate_event_data),
|
dbawaremigrations.RunPython(migrate_event_data, sqlite_code=migrate_event_data_sqlite),
|
||||||
FakeAlterField(
|
FakeAlterField(
|
||||||
model_name='adhoccommandevent',
|
model_name='adhoccommandevent',
|
||||||
name='id',
|
name='id',
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
from django.db import migrations, models, connection
|
from django.db import migrations, models, connection
|
||||||
|
|
||||||
|
from ._sqlite_helper import dbawaremigrations
|
||||||
|
|
||||||
|
|
||||||
def migrate_event_data(apps, schema_editor):
|
def migrate_event_data(apps, schema_editor):
|
||||||
# see: https://github.com/ansible/awx/issues/9039
|
# 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')
|
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):
|
class FakeAddField(migrations.AddField):
|
||||||
def database_forwards(self, *args):
|
def database_forwards(self, *args):
|
||||||
# this is intentionally left blank, because we're
|
# this is intentionally left blank, because we're
|
||||||
@@ -72,7 +78,7 @@ class Migration(migrations.Migration):
|
|||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.RunPython(migrate_event_data),
|
dbawaremigrations.RunPython(migrate_event_data, sqlite_code=migrate_event_data_sqlite),
|
||||||
FakeAddField(
|
FakeAddField(
|
||||||
model_name='jobevent',
|
model_name='jobevent',
|
||||||
name='job_created',
|
name='job_created',
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
import awx.main.models.notifications
|
import awx.main.models.notifications
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
from ._sqlite_helper import dbawaremigrations
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
dependencies = [
|
dependencies = [
|
||||||
@@ -104,11 +106,12 @@ class Migration(migrations.Migration):
|
|||||||
name='deleted_actor',
|
name='deleted_actor',
|
||||||
field=models.JSONField(null=True),
|
field=models.JSONField(null=True),
|
||||||
),
|
),
|
||||||
migrations.RunSQL(
|
dbawaremigrations.RunSQL(
|
||||||
"""
|
"""
|
||||||
ALTER TABLE main_activitystream RENAME setting TO setting_old;
|
ALTER TABLE main_activitystream RENAME setting TO setting_old;
|
||||||
ALTER TABLE main_activitystream ALTER COLUMN setting_old DROP NOT NULL;
|
ALTER TABLE main_activitystream ALTER COLUMN setting_old DROP NOT NULL;
|
||||||
""",
|
""",
|
||||||
|
sqlite_sql="ALTER TABLE main_activitystream RENAME setting TO setting_old",
|
||||||
state_operations=[
|
state_operations=[
|
||||||
migrations.RemoveField(
|
migrations.RemoveField(
|
||||||
model_name='activitystream',
|
model_name='activitystream',
|
||||||
@@ -121,11 +124,12 @@ class Migration(migrations.Migration):
|
|||||||
name='setting',
|
name='setting',
|
||||||
field=models.JSONField(blank=True, default=dict),
|
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 RENAME survey_passwords TO survey_passwords_old;
|
||||||
ALTER TABLE main_job ALTER COLUMN survey_passwords_old DROP NOT NULL;
|
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=[
|
state_operations=[
|
||||||
migrations.RemoveField(
|
migrations.RemoveField(
|
||||||
model_name='job',
|
model_name='job',
|
||||||
@@ -138,11 +142,12 @@ class Migration(migrations.Migration):
|
|||||||
name='survey_passwords',
|
name='survey_passwords',
|
||||||
field=models.JSONField(blank=True, default=dict, editable=False),
|
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 RENAME char_prompts TO char_prompts_old;
|
||||||
ALTER TABLE main_joblaunchconfig ALTER COLUMN char_prompts_old DROP NOT NULL;
|
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=[
|
state_operations=[
|
||||||
migrations.RemoveField(
|
migrations.RemoveField(
|
||||||
model_name='joblaunchconfig',
|
model_name='joblaunchconfig',
|
||||||
@@ -155,11 +160,12 @@ class Migration(migrations.Migration):
|
|||||||
name='char_prompts',
|
name='char_prompts',
|
||||||
field=models.JSONField(blank=True, default=dict),
|
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 RENAME survey_passwords TO survey_passwords_old;
|
||||||
ALTER TABLE main_joblaunchconfig ALTER COLUMN survey_passwords_old DROP NOT NULL;
|
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=[
|
state_operations=[
|
||||||
migrations.RemoveField(
|
migrations.RemoveField(
|
||||||
model_name='joblaunchconfig',
|
model_name='joblaunchconfig',
|
||||||
@@ -172,11 +178,12 @@ class Migration(migrations.Migration):
|
|||||||
name='survey_passwords',
|
name='survey_passwords',
|
||||||
field=models.JSONField(blank=True, default=dict, editable=False),
|
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 RENAME body TO body_old;
|
||||||
ALTER TABLE main_notification ALTER COLUMN body_old DROP NOT NULL;
|
ALTER TABLE main_notification ALTER COLUMN body_old DROP NOT NULL;
|
||||||
""",
|
""",
|
||||||
|
sqlite_sql="ALTER TABLE main_notification RENAME body TO body_old",
|
||||||
state_operations=[
|
state_operations=[
|
||||||
migrations.RemoveField(
|
migrations.RemoveField(
|
||||||
model_name='notification',
|
model_name='notification',
|
||||||
@@ -189,11 +196,12 @@ class Migration(migrations.Migration):
|
|||||||
name='body',
|
name='body',
|
||||||
field=models.JSONField(blank=True, default=dict),
|
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 RENAME job_env TO job_env_old;
|
||||||
ALTER TABLE main_unifiedjob ALTER COLUMN job_env_old DROP NOT NULL;
|
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=[
|
state_operations=[
|
||||||
migrations.RemoveField(
|
migrations.RemoveField(
|
||||||
model_name='unifiedjob',
|
model_name='unifiedjob',
|
||||||
@@ -206,11 +214,12 @@ class Migration(migrations.Migration):
|
|||||||
name='job_env',
|
name='job_env',
|
||||||
field=models.JSONField(blank=True, default=dict, editable=False),
|
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 RENAME char_prompts TO char_prompts_old;
|
||||||
ALTER TABLE main_workflowjob ALTER COLUMN char_prompts_old DROP NOT NULL;
|
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=[
|
state_operations=[
|
||||||
migrations.RemoveField(
|
migrations.RemoveField(
|
||||||
model_name='workflowjob',
|
model_name='workflowjob',
|
||||||
@@ -223,11 +232,12 @@ class Migration(migrations.Migration):
|
|||||||
name='char_prompts',
|
name='char_prompts',
|
||||||
field=models.JSONField(blank=True, default=dict),
|
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 RENAME survey_passwords TO survey_passwords_old;
|
||||||
ALTER TABLE main_workflowjob ALTER COLUMN survey_passwords_old DROP NOT NULL;
|
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=[
|
state_operations=[
|
||||||
migrations.RemoveField(
|
migrations.RemoveField(
|
||||||
model_name='workflowjob',
|
model_name='workflowjob',
|
||||||
@@ -240,11 +250,12 @@ class Migration(migrations.Migration):
|
|||||||
name='survey_passwords',
|
name='survey_passwords',
|
||||||
field=models.JSONField(blank=True, default=dict, editable=False),
|
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 RENAME char_prompts TO char_prompts_old;
|
||||||
ALTER TABLE main_workflowjobnode ALTER COLUMN char_prompts_old DROP NOT NULL;
|
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=[
|
state_operations=[
|
||||||
migrations.RemoveField(
|
migrations.RemoveField(
|
||||||
model_name='workflowjobnode',
|
model_name='workflowjobnode',
|
||||||
@@ -257,11 +268,12 @@ class Migration(migrations.Migration):
|
|||||||
name='char_prompts',
|
name='char_prompts',
|
||||||
field=models.JSONField(blank=True, default=dict),
|
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 RENAME survey_passwords TO survey_passwords_old;
|
||||||
ALTER TABLE main_workflowjobnode ALTER COLUMN survey_passwords_old DROP NOT NULL;
|
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=[
|
state_operations=[
|
||||||
migrations.RemoveField(
|
migrations.RemoveField(
|
||||||
model_name='workflowjobnode',
|
model_name='workflowjobnode',
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ from __future__ import unicode_literals
|
|||||||
|
|
||||||
from django.db import migrations
|
from django.db import migrations
|
||||||
|
|
||||||
|
from ._sqlite_helper import dbawaremigrations
|
||||||
|
|
||||||
|
|
||||||
def delete_taggit_contenttypes(apps, schema_editor):
|
def delete_taggit_contenttypes(apps, schema_editor):
|
||||||
ContentType = apps.get_model('contenttypes', 'ContentType')
|
ContentType = apps.get_model('contenttypes', 'ContentType')
|
||||||
@@ -20,8 +22,8 @@ class Migration(migrations.Migration):
|
|||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.RunSQL("DROP TABLE IF EXISTS taggit_tag CASCADE;"),
|
dbawaremigrations.RunSQL("DROP TABLE IF EXISTS taggit_tag CASCADE;", sqlite_sql="DROP TABLE IF EXISTS taggit_tag;"),
|
||||||
migrations.RunSQL("DROP TABLE IF EXISTS taggit_taggeditem CASCADE;"),
|
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_contenttypes),
|
||||||
migrations.RunPython(delete_taggit_migration_records),
|
migrations.RunPython(delete_taggit_migration_records),
|
||||||
]
|
]
|
||||||
|
|||||||
61
awx/main/migrations/_sqlite_helper.py
Normal file
61
awx/main/migrations/_sqlite_helper.py
Normal file
@@ -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()
|
||||||
@@ -57,7 +57,6 @@ from awx.main.models.ha import ( # noqa
|
|||||||
from awx.main.models.rbac import ( # noqa
|
from awx.main.models.rbac import ( # noqa
|
||||||
Role,
|
Role,
|
||||||
batch_role_ancestor_rebuilding,
|
batch_role_ancestor_rebuilding,
|
||||||
get_roles_on_resource,
|
|
||||||
role_summary_fields_generator,
|
role_summary_fields_generator,
|
||||||
ROLE_SINGLETON_SYSTEM_ADMINISTRATOR,
|
ROLE_SINGLETON_SYSTEM_ADMINISTRATOR,
|
||||||
ROLE_SINGLETON_SYSTEM_AUDITOR,
|
ROLE_SINGLETON_SYSTEM_AUDITOR,
|
||||||
@@ -91,13 +90,12 @@ from oauth2_provider.models import Grant, RefreshToken # noqa -- needed django-
|
|||||||
|
|
||||||
# Add custom methods to User model for permissions checks.
|
# Add custom methods to User model for permissions checks.
|
||||||
from django.contrib.auth.models import User # noqa
|
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('get_queryset', get_user_queryset)
|
||||||
User.add_to_class('can_access', check_user_access)
|
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('can_access_with_errors', check_user_access_with_errors)
|
||||||
User.add_to_class('accessible_objects', user_accessible_objects)
|
|
||||||
|
|
||||||
|
|
||||||
def convert_jsonfields():
|
def convert_jsonfields():
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ from django.utils.translation import gettext_lazy as _
|
|||||||
|
|
||||||
# AWX
|
# AWX
|
||||||
from awx.main.models.base import prevent_search
|
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 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.execution_environments import get_default_execution_environment
|
||||||
from awx.main.utils.encryption import decrypt_value, get_encryption_key, is_encrypted
|
from awx.main.utils.encryption import decrypt_value, get_encryption_key, is_encrypted
|
||||||
@@ -54,10 +54,7 @@ class ResourceMixin(models.Model):
|
|||||||
Use instead of `MyModel.objects` when you want to only consider
|
Use instead of `MyModel.objects` when you want to only consider
|
||||||
resources that a user has specific permissions for. For example:
|
resources that a user has specific permissions for. For example:
|
||||||
MyModel.accessible_objects(user, 'read_role').filter(name__istartswith='bar');
|
MyModel.accessible_objects(user, 'read_role').filter(name__istartswith='bar');
|
||||||
NOTE: This should only be used for list type things. If you have a
|
NOTE: This should only be used for list type things.
|
||||||
specific resource you want to check permissions on, it is more
|
|
||||||
performant to resolve the resource in question then call
|
|
||||||
`myresource.get_permissions(user)`.
|
|
||||||
"""
|
"""
|
||||||
return ResourceMixin._accessible_objects(cls, accessor, role_field)
|
return ResourceMixin._accessible_objects(cls, accessor, role_field)
|
||||||
|
|
||||||
@@ -86,15 +83,6 @@ class ResourceMixin(models.Model):
|
|||||||
def _accessible_objects(cls, accessor, role_field):
|
def _accessible_objects(cls, accessor, role_field):
|
||||||
return cls.objects.filter(pk__in=ResourceMixin._accessible_pk_qs(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 SurveyJobTemplateMixin(models.Model):
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|||||||
44
awx/main/tests/functional/test_migrations.py
Normal file
44
awx/main/tests/functional/test_migrations.py
Normal file
@@ -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
|
||||||
@@ -122,25 +122,6 @@ def test_team_org_resource_role(ext_auth, organization, rando, org_admin, team):
|
|||||||
] == [True for i in range(2)]
|
] == [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
|
@pytest.mark.django_db
|
||||||
def test_org_admin_create_sys_auditor(org_admin):
|
def test_org_admin_create_sys_auditor(org_admin):
|
||||||
access = UserAccess(org_admin)
|
access = UserAccess(org_admin)
|
||||||
|
|||||||
@@ -199,6 +199,8 @@ class Licenser(object):
|
|||||||
license['support_level'] = attr.get('value')
|
license['support_level'] = attr.get('value')
|
||||||
elif attr.get('name') == 'usage':
|
elif attr.get('name') == 'usage':
|
||||||
license['usage'] = attr.get('value')
|
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:
|
if not license:
|
||||||
logger.error("No valid subscriptions found in manifest")
|
logger.error("No valid subscriptions found in manifest")
|
||||||
@@ -322,7 +324,9 @@ class Licenser(object):
|
|||||||
def generate_license_options_from_entitlements(self, json):
|
def generate_license_options_from_entitlements(self, json):
|
||||||
from dateutil.parser import parse
|
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 = []
|
valid_subs = []
|
||||||
for sub in json:
|
for sub in json:
|
||||||
satellite = sub.get('satellite')
|
satellite = sub.get('satellite')
|
||||||
@@ -350,6 +354,7 @@ class Licenser(object):
|
|||||||
|
|
||||||
sku = sub['productId']
|
sku = sub['productId']
|
||||||
trial = sku.startswith('S') # i.e.,, SER/SVC
|
trial = sku.startswith('S') # i.e.,, SER/SVC
|
||||||
|
developer_license = False
|
||||||
support_level = ''
|
support_level = ''
|
||||||
usage = ''
|
usage = ''
|
||||||
pool_id = sub['id']
|
pool_id = sub['id']
|
||||||
@@ -364,9 +369,24 @@ class Licenser(object):
|
|||||||
support_level = attr.get('value')
|
support_level = attr.get('value')
|
||||||
elif attr.get('name') == 'usage':
|
elif attr.get('name') == 'usage':
|
||||||
usage = attr.get('value')
|
usage = attr.get('value')
|
||||||
|
elif attr.get('name') == 'ph_product_name' and attr.get('value') == 'RHEL Developer':
|
||||||
|
developer_license = True
|
||||||
|
|
||||||
valid_subs.append(
|
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:
|
if valid_subs:
|
||||||
@@ -381,6 +401,8 @@ class Licenser(object):
|
|||||||
if sub.trial:
|
if sub.trial:
|
||||||
license._attrs['trial'] = True
|
license._attrs['trial'] = True
|
||||||
license._attrs['license_type'] = 'trial'
|
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'])
|
license._attrs['instance_count'] = min(MAX_INSTANCES, license._attrs['instance_count'])
|
||||||
human_instances = license._attrs['instance_count']
|
human_instances = license._attrs['instance_count']
|
||||||
if human_instances == MAX_INSTANCES:
|
if human_instances == MAX_INSTANCES:
|
||||||
|
|||||||
@@ -227,7 +227,8 @@ class WebSocketRelayManager(object):
|
|||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
if not notif.payload or notif.channel != "web_ws_heartbeat":
|
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:
|
try:
|
||||||
payload = json.loads(notif.payload)
|
payload = json.loads(notif.payload)
|
||||||
@@ -235,13 +236,15 @@ class WebSocketRelayManager(object):
|
|||||||
logmsg = "Failed to decode message from pg_notify channel `web_ws_heartbeat`"
|
logmsg = "Failed to decode message from pg_notify channel `web_ws_heartbeat`"
|
||||||
if logger.isEnabledFor(logging.DEBUG):
|
if logger.isEnabledFor(logging.DEBUG):
|
||||||
logmsg = "{} {}".format(logmsg, payload)
|
logmsg = "{} {}".format(logmsg, payload)
|
||||||
logger.warning(logmsg)
|
logger.warning(logmsg)
|
||||||
return
|
continue
|
||||||
|
|
||||||
# Skip if the message comes from the same host we are running on
|
# 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.
|
# In this case, we'll be sharing a redis, no need to relay.
|
||||||
if payload.get("hostname") == self.local_hostname:
|
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")
|
action = payload.get("action")
|
||||||
|
|
||||||
@@ -250,7 +253,7 @@ class WebSocketRelayManager(object):
|
|||||||
ip = payload.get("ip") or hostname # try back to hostname if ip isn't supplied
|
ip = payload.get("ip") or hostname # try back to hostname if ip isn't supplied
|
||||||
if ip is None:
|
if ip is None:
|
||||||
logger.warning(f"Received invalid {action} ws_heartbeat, missing hostname and ip: {payload}")
|
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.")
|
logger.debug(f"Web host {hostname} ({ip}) {action} heartbeat received.")
|
||||||
|
|
||||||
if action == "online":
|
if action == "online":
|
||||||
|
|||||||
@@ -336,6 +336,7 @@ INSTALLED_APPS = [
|
|||||||
'awx.ui',
|
'awx.ui',
|
||||||
'awx.sso',
|
'awx.sso',
|
||||||
'solo',
|
'solo',
|
||||||
|
'ansible_base',
|
||||||
]
|
]
|
||||||
|
|
||||||
INTERNAL_IPS = ('127.0.0.1',)
|
INTERNAL_IPS = ('127.0.0.1',)
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ options:
|
|||||||
Insights, Machine, Microsoft Azure Key Vault, Microsoft Azure Resource Manager, Network, OpenShift or Kubernetes API
|
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,
|
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
|
Thycotic DevOps Secrets Vault, Thycotic Secret Server, Vault, VMware vCenter, or a custom credential type
|
||||||
|
required: True
|
||||||
type: str
|
type: str
|
||||||
inputs:
|
inputs:
|
||||||
description:
|
description:
|
||||||
@@ -214,7 +215,7 @@ def main():
|
|||||||
copy_from=dict(),
|
copy_from=dict(),
|
||||||
description=dict(),
|
description=dict(),
|
||||||
organization=dict(),
|
organization=dict(),
|
||||||
credential_type=dict(),
|
credential_type=dict(required=True),
|
||||||
inputs=dict(type='dict', no_log=True),
|
inputs=dict(type='dict', no_log=True),
|
||||||
update_secrets=dict(type='bool', default=True, no_log=False),
|
update_secrets=dict(type='bool', default=True, no_log=False),
|
||||||
user=dict(),
|
user=dict(),
|
||||||
|
|||||||
@@ -60,7 +60,7 @@
|
|||||||
- result['job_info']['skip_tags'] == "skipbaz"
|
- result['job_info']['skip_tags'] == "skipbaz"
|
||||||
- result['job_info']['limit'] == "localhost"
|
- result['job_info']['limit'] == "localhost"
|
||||||
- result['job_info']['job_tags'] == "Hello World"
|
- 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\"}'"
|
- "result['job_info']['extra_vars'] == '{\"animal\": \"bear\", \"food\": \"carrot\"}'"
|
||||||
|
|
||||||
# cleanup
|
# cleanup
|
||||||
|
|||||||
@@ -71,6 +71,19 @@
|
|||||||
that:
|
that:
|
||||||
- "result is changed"
|
- "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
|
- name: Create an Org-specific credential with an ID with exists
|
||||||
credential:
|
credential:
|
||||||
name: "{{ ssh_cred_name1 }}"
|
name: "{{ ssh_cred_name1 }}"
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
- assert:
|
- assert:
|
||||||
that:
|
that:
|
||||||
- "{{ matching_jobs.count }} == 1"
|
- matching_jobs.count == 1
|
||||||
|
|
||||||
- name: List failed jobs (which don't exist)
|
- name: List failed jobs (which don't exist)
|
||||||
job_list:
|
job_list:
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
- assert:
|
- assert:
|
||||||
that:
|
that:
|
||||||
- "{{ successful_jobs.count }} == 0"
|
- successful_jobs.count == 0
|
||||||
|
|
||||||
- name: Get ALL result pages!
|
- name: Get ALL result pages!
|
||||||
job_list:
|
job_list:
|
||||||
|
|||||||
@@ -99,7 +99,7 @@
|
|||||||
that:
|
that:
|
||||||
- wait_results is failed
|
- wait_results is failed
|
||||||
- 'wait_results.status == "canceled"'
|
- '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
|
# workflow wait test
|
||||||
- name: Generate a random string for test
|
- name: Generate a random string for test
|
||||||
|
|||||||
@@ -132,7 +132,7 @@
|
|||||||
|
|
||||||
- name: Get the ID of the first user created and verify that it is correct
|
- name: Get the ID of the first user created and verify that it is correct
|
||||||
assert:
|
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
|
- name: Try to get an ID of someone who does not exist
|
||||||
set_fact:
|
set_fact:
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
- name: Call ruleset with no rules
|
- name: Call ruleset with no rules
|
||||||
set_fact:
|
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
|
ignore_errors: True
|
||||||
register: results
|
register: results
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
- assert:
|
- assert:
|
||||||
that:
|
that:
|
||||||
- result is failed
|
- 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
|
- name: Create with options that the JT does not support
|
||||||
schedule:
|
schedule:
|
||||||
@@ -62,7 +62,7 @@
|
|||||||
- assert:
|
- assert:
|
||||||
that:
|
that:
|
||||||
- result is failed
|
- result is failed
|
||||||
- "'Unable to create schedule {{ sched1 }}' in result.msg"
|
- "'Unable to create schedule '~ sched1 in result.msg"
|
||||||
|
|
||||||
- name: Build a real schedule
|
- name: Build a real schedule
|
||||||
schedule:
|
schedule:
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
- name: Test too many params (failure from validation of terms)
|
- name: Test too many params (failure from validation of terms)
|
||||||
debug:
|
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
|
ignore_errors: true
|
||||||
register: result
|
register: result
|
||||||
|
|
||||||
|
|||||||
@@ -57,7 +57,7 @@
|
|||||||
- assert:
|
- assert:
|
||||||
that:
|
that:
|
||||||
- result is failed
|
- 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
|
- name: Kick off a workflow and wait for it
|
||||||
workflow_launch:
|
workflow_launch:
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import shlex
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from importlib import import_module
|
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'
|
project = u'Ansible AWX'
|
||||||
copyright = u'2023, Red Hat'
|
copyright = u'2023, Red Hat'
|
||||||
@@ -35,6 +35,7 @@ extensions = [
|
|||||||
'sphinx.ext.coverage',
|
'sphinx.ext.coverage',
|
||||||
'sphinx.ext.ifconfig',
|
'sphinx.ext.ifconfig',
|
||||||
'sphinx_ansible_theme',
|
'sphinx_ansible_theme',
|
||||||
|
'swagger',
|
||||||
]
|
]
|
||||||
|
|
||||||
html_theme = 'sphinx_ansible_theme'
|
html_theme = 'sphinx_ansible_theme'
|
||||||
|
|||||||
@@ -8,13 +8,13 @@ alabaster==0.7.13
|
|||||||
# via sphinx
|
# via sphinx
|
||||||
ansible-pygments==0.1.1
|
ansible-pygments==0.1.1
|
||||||
# via sphinx-ansible-theme
|
# via sphinx-ansible-theme
|
||||||
babel==2.12.1
|
babel==2.13.1
|
||||||
# via sphinx
|
# via sphinx
|
||||||
certifi==2023.7.22
|
certifi==2023.7.22
|
||||||
# via requests
|
# via requests
|
||||||
charset-normalizer==3.2.0
|
charset-normalizer==3.3.2
|
||||||
# via requests
|
# via requests
|
||||||
docutils==0.16
|
docutils==0.18.1
|
||||||
# via
|
# via
|
||||||
# -r docs/docsite/requirements.in
|
# -r docs/docsite/requirements.in
|
||||||
# sphinx
|
# sphinx
|
||||||
@@ -23,13 +23,13 @@ idna==3.4
|
|||||||
# via requests
|
# via requests
|
||||||
imagesize==1.4.1
|
imagesize==1.4.1
|
||||||
# via sphinx
|
# via sphinx
|
||||||
jinja2==3.0.3
|
jinja2==3.1.2
|
||||||
# via
|
# via
|
||||||
# -r docs/docsite/requirements.in
|
# -r docs/docsite/requirements.in
|
||||||
# sphinx
|
# sphinx
|
||||||
markupsafe==2.1.3
|
markupsafe==2.1.3
|
||||||
# via jinja2
|
# via jinja2
|
||||||
packaging==23.1
|
packaging==23.2
|
||||||
# via sphinx
|
# via sphinx
|
||||||
pygments==2.16.1
|
pygments==2.16.1
|
||||||
# via
|
# via
|
||||||
@@ -41,7 +41,7 @@ requests==2.31.0
|
|||||||
# via sphinx
|
# via sphinx
|
||||||
snowballstemmer==2.2.0
|
snowballstemmer==2.2.0
|
||||||
# via sphinx
|
# via sphinx
|
||||||
sphinx==5.1.1
|
sphinx==7.2.6
|
||||||
# via
|
# via
|
||||||
# -r docs/docsite/requirements.in
|
# -r docs/docsite/requirements.in
|
||||||
# sphinx-ansible-theme
|
# sphinx-ansible-theme
|
||||||
@@ -52,7 +52,7 @@ sphinx==5.1.1
|
|||||||
# sphinxcontrib-jquery
|
# sphinxcontrib-jquery
|
||||||
# sphinxcontrib-qthelp
|
# sphinxcontrib-qthelp
|
||||||
# sphinxcontrib-serializinghtml
|
# sphinxcontrib-serializinghtml
|
||||||
sphinx-ansible-theme==0.9.1
|
sphinx-ansible-theme==0.10.2
|
||||||
# via -r docs/docsite/requirements.in
|
# via -r docs/docsite/requirements.in
|
||||||
sphinx-rtd-theme==1.3.0
|
sphinx-rtd-theme==1.3.0
|
||||||
# via sphinx-ansible-theme
|
# via sphinx-ansible-theme
|
||||||
@@ -70,5 +70,5 @@ sphinxcontrib-qthelp==1.0.6
|
|||||||
# via sphinx
|
# via sphinx
|
||||||
sphinxcontrib-serializinghtml==1.1.9
|
sphinxcontrib-serializinghtml==1.1.9
|
||||||
# via sphinx
|
# via sphinx
|
||||||
urllib3==2.0.4
|
urllib3==2.1.0
|
||||||
# via requests
|
# via requests
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 128 KiB |
@@ -8,5 +8,6 @@
|
|||||||
To enter the Settings window for AWX, click **Settings** from the left navigation bar. This page allows you to modify your AWX configuration, such as settings associated with authentication, jobs, system, and user interface.
|
To enter the Settings window for AWX, click **Settings** from the left navigation bar. This page allows you to modify your AWX configuration, such as settings associated with authentication, jobs, system, and user interface.
|
||||||
|
|
||||||
.. image:: ../common/images/ug-settings-menu-screen.png
|
.. image:: ../common/images/ug-settings-menu-screen.png
|
||||||
|
:alt: The main settings window for AWX.
|
||||||
|
|
||||||
For more information on configuring these settings, refer to :ref:`ag_configure_awx` section of the |ata|.
|
For more information on configuring these settings, refer to :ref:`ag_configure_awx` section of the |ata|.
|
||||||
@@ -8,11 +8,20 @@ Release Notes
|
|||||||
pair: release notes; v23.0.0
|
pair: release notes; v23.0.0
|
||||||
pair: release notes; v23.1.0
|
pair: release notes; v23.1.0
|
||||||
pair: release notes; v23.2.0
|
pair: release notes; v23.2.0
|
||||||
|
pair: release notes; v23.3.0
|
||||||
|
pair: release notes; v23.3.1
|
||||||
|
pair: release notes; v23.4.0
|
||||||
|
|
||||||
|
|
||||||
For versions older than 23.0.0, refer to `AWX Release Notes <https://github.com/ansible/awx/releases>`_.
|
For versions older than 23.0.0, refer to `AWX Release Notes <https://github.com/ansible/awx/releases>`_.
|
||||||
|
|
||||||
|
|
||||||
|
- See `What's Changed for 23.4.0 <https://github.com/ansible/awx/releases/tag/23.4.0>`_.
|
||||||
|
|
||||||
|
- See `What's Changed for 23.3.1 <https://github.com/ansible/awx/releases/tag/23.3.1>`_.
|
||||||
|
|
||||||
|
- See `What's Changed for 23.3.0 <https://github.com/ansible/awx/releases/tag/23.3.0>`_.
|
||||||
|
|
||||||
- See `What's Changed for 23.2.0 <https://github.com/ansible/awx/releases/tag/23.2.0>`_.
|
- See `What's Changed for 23.2.0 <https://github.com/ansible/awx/releases/tag/23.2.0>`_.
|
||||||
|
|
||||||
- See `What's Changed for 23.1.0 <https://github.com/ansible/awx/releases/tag/23.1.0>`_.
|
- See `What's Changed for 23.1.0 <https://github.com/ansible/awx/releases/tag/23.1.0>`_.
|
||||||
|
|||||||
13
docs/docsite/rst/rest_api/_swagger/download-json.py
Normal file
13
docs/docsite/rst/rest_api/_swagger/download-json.py
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import requests
|
||||||
|
|
||||||
|
url = "https://awx-public-ci-files.s3.amazonaws.com/community-docs/swagger.json"
|
||||||
|
swagger_json = "./docs/docsite/rst/rest_api/_swagger/swagger.json"
|
||||||
|
|
||||||
|
response = requests.get(url)
|
||||||
|
|
||||||
|
if response.status_code == 200:
|
||||||
|
with open(swagger_json, 'wb') as file:
|
||||||
|
file.write(response.content)
|
||||||
|
print(f"JSON file downloaded to {swagger_json}")
|
||||||
|
else:
|
||||||
|
print(f"Request failed with status code: {response.status_code}")
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
:orphan:
|
|
||||||
|
|
||||||
.. _api_reference:
|
.. _api_reference:
|
||||||
|
|
||||||
AWX API Reference Guide
|
AWX API Reference Guide
|
||||||
@@ -48,7 +46,7 @@ The API Reference Manual provides in-depth documentation for the AWX REST API, i
|
|||||||
<script>
|
<script>
|
||||||
window.onload = function() {
|
window.onload = function() {
|
||||||
$('head').append('<link rel="stylesheet" href="../_static/swagger-ui.css" type="text/css"></link>');
|
$('head').append('<link rel="stylesheet" href="../_static/swagger-ui.css" type="text/css"></link>');
|
||||||
$('head').append('<link rel="stylesheet" href="../_static/tower.css" type="text/css"></link>');
|
$('head').append('<link rel="stylesheet" href="../_static/awx-rest-api.css" type="text/css"></link>');
|
||||||
$('#swagger-ui').on('click', function(e) {
|
$('#swagger-ui').on('click', function(e) {
|
||||||
// By default, swagger-ui has a show/hide toggle for headers, and
|
// By default, swagger-ui has a show/hide toggle for headers, and
|
||||||
// there's no way to turn it off; this code intercepts the click event
|
// there's no way to turn it off; this code intercepts the click event
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ You can also find lots of AWX discussion and get answers to questions at `forum.
|
|||||||
access_resources
|
access_resources
|
||||||
read_only_fields
|
read_only_fields
|
||||||
authentication
|
authentication
|
||||||
.. api_ref
|
api_ref
|
||||||
|
|
||||||
.. intro
|
.. intro
|
||||||
.. auth_token
|
.. auth_token
|
||||||
|
|||||||
@@ -603,6 +603,8 @@ Extra Variables
|
|||||||
pair: workflow templates; survey extra variables
|
pair: workflow templates; survey extra variables
|
||||||
pair: surveys; extra variables
|
pair: surveys; extra variables
|
||||||
|
|
||||||
|
.. <- Comment to separate the index and the note to avoid rendering issues.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
``extra_vars`` passed to the job launch API are only honored if one of the following is true:
|
``extra_vars`` passed to the job launch API are only honored if one of the following is true:
|
||||||
|
|||||||
29
docs/rbac.md
29
docs/rbac.md
@@ -95,6 +95,12 @@ The `singleton` class method is a helper method on the `Role` model that helps i
|
|||||||
You may use the `user in some_role` syntax to check and see if the specified
|
You may use the `user in some_role` syntax to check and see if the specified
|
||||||
user is a member of the given role, **or** a member of any ancestor role.
|
user is a member of the given role, **or** a member of any ancestor role.
|
||||||
|
|
||||||
|
#### `get_roles_on_resource(resource, accessor)`
|
||||||
|
|
||||||
|
This is a static method (not bound to a class) that will efficiently return the names
|
||||||
|
of all roles that the `accessor` (a user or a team) has on a particular resource.
|
||||||
|
The resource is a python object for something like an organization, credential, or job template.
|
||||||
|
Return value is a list of strings like `["admin_role", "execute_role"]`.
|
||||||
|
|
||||||
### Fields
|
### Fields
|
||||||
|
|
||||||
@@ -126,13 +132,17 @@ By mixing in the `ResourceMixin` to your model, you are turning your model in to
|
|||||||
objects.filter(name__istartswith='december')
|
objects.filter(name__istartswith='december')
|
||||||
```
|
```
|
||||||
|
|
||||||
##### `get_permissions(self, user)`
|
##### `accessible_pk_qs(cls, user, role_field)`
|
||||||
|
|
||||||
`get_permissions` is an instance method that will give you the list of role names that the user has access to for a given object.
|
`accessible_pk_qs` returns a queryset of ids that match the same role filter as `accessible_objects`.
|
||||||
|
A key difference is that this is more performant to use in subqueries when filtering related models.
|
||||||
|
|
||||||
|
Say that another model, `YourModel` has a ForeignKey reference to `MyModel` via a field `my_model`,
|
||||||
|
and you want to return all instances of `YourModel` that have a visible related `MyModel`.
|
||||||
|
The best way to do this is:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
>>> instance.get_permissions(admin)
|
YourModel.filter(my_model=MyModel.accessible_pk_qs(user, 'admin_role'))
|
||||||
['admin_role', 'execute_role', 'read_role']
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
@@ -144,10 +154,7 @@ After exploring the _Overview_, the usage of the RBAC implementation in your cod
|
|||||||
class Document(Model, ResourceMixin):
|
class Document(Model, ResourceMixin):
|
||||||
...
|
...
|
||||||
# declare your new role
|
# declare your new role
|
||||||
readonly_role = ImplicitRoleField(
|
readonly_role = ImplicitRoleField()
|
||||||
role_name="readonly",
|
|
||||||
permissions={'read':True},
|
|
||||||
)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Now that your model is a resource and has a `Role` defined, you can begin to access the helper methods provided to you by the `ResourceMixin` for checking a user's access to your resource. Here is the output of a Python REPL session:
|
Now that your model is a resource and has a `Role` defined, you can begin to access the helper methods provided to you by the `ResourceMixin` for checking a user's access to your resource. Here is the output of a Python REPL session:
|
||||||
@@ -156,11 +163,11 @@ Now that your model is a resource and has a `Role` defined, you can begin to acc
|
|||||||
# we've created some documents and a user
|
# we've created some documents and a user
|
||||||
>>> document = Document.objects.filter(pk=1)
|
>>> document = Document.objects.filter(pk=1)
|
||||||
>>> user = User.objects.first()
|
>>> user = User.objects.first()
|
||||||
>>> user in document.read_role
|
>>> user in document.readonly_role
|
||||||
False # not accessible by default
|
False # not accessible by default
|
||||||
>>> document.readonly_role.members.add(user)
|
>>> document.readonly_role.members.add(user)
|
||||||
>>> user in document.read_role
|
>>> user in document.readonly_role
|
||||||
True # now it is accessible
|
True # now it is accessible
|
||||||
>>> user in document.admin_role
|
>>> user in document.readonly_role
|
||||||
False # my role does not have admin permission
|
False # my role does not have admin permission
|
||||||
```
|
```
|
||||||
|
|||||||
168
licenses/django-ansible-base.txt
Normal file
168
licenses/django-ansible-base.txt
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
Apache License
|
||||||
|
==============
|
||||||
|
|
||||||
|
_Version 2.0, January 2004_
|
||||||
|
_<<http://www.apache.org/licenses/>>_
|
||||||
|
|
||||||
|
### Terms and Conditions for use, reproduction, and distribution
|
||||||
|
|
||||||
|
#### 1. Definitions
|
||||||
|
|
||||||
|
“License” shall mean the terms and conditions for use, reproduction, and
|
||||||
|
distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
“Licensor” shall mean the copyright owner or entity authorized by the copyright
|
||||||
|
owner that is granting the License.
|
||||||
|
|
||||||
|
“Legal Entity” shall mean the union of the acting entity and all other entities
|
||||||
|
that control, are controlled by, or are under common control with that entity.
|
||||||
|
For the purposes of this definition, “control” means **(i)** the power, direct or
|
||||||
|
indirect, to cause the direction or management of such entity, whether by
|
||||||
|
contract or otherwise, or **(ii)** ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or **(iii)** beneficial ownership of such entity.
|
||||||
|
|
||||||
|
“You” (or “Your”) shall mean an individual or Legal Entity exercising
|
||||||
|
permissions granted by this License.
|
||||||
|
|
||||||
|
“Source” form shall mean the preferred form for making modifications, including
|
||||||
|
but not limited to software source code, documentation source, and configuration
|
||||||
|
files.
|
||||||
|
|
||||||
|
“Object” form shall mean any form resulting from mechanical transformation or
|
||||||
|
translation of a Source form, including but not limited to compiled object code,
|
||||||
|
generated documentation, and conversions to other media types.
|
||||||
|
|
||||||
|
“Work” shall mean the work of authorship, whether in Source or Object form, made
|
||||||
|
available under the License, as indicated by a copyright notice that is included
|
||||||
|
in or attached to the work (an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
“Derivative Works” shall mean any work, whether in Source or Object form, that
|
||||||
|
is based on (or derived from) the Work and for which the editorial revisions,
|
||||||
|
annotations, elaborations, or other modifications represent, as a whole, an
|
||||||
|
original work of authorship. For the purposes of this License, Derivative Works
|
||||||
|
shall not include works that remain separable from, or merely link (or bind by
|
||||||
|
name) to the interfaces of, the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
“Contribution” shall mean any work of authorship, including the original version
|
||||||
|
of the Work and any modifications or additions to that Work or Derivative Works
|
||||||
|
thereof, that is intentionally submitted to Licensor for inclusion in the Work
|
||||||
|
by the copyright owner or by an individual or Legal Entity authorized to submit
|
||||||
|
on behalf of the copyright owner. For the purposes of this definition,
|
||||||
|
“submitted” means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems, and
|
||||||
|
issue tracking systems that are managed by, or on behalf of, the Licensor for
|
||||||
|
the purpose of discussing and improving the Work, but excluding communication
|
||||||
|
that is conspicuously marked or otherwise designated in writing by the copyright
|
||||||
|
owner as “Not a Contribution.”
|
||||||
|
|
||||||
|
“Contributor” shall mean Licensor and any individual or Legal Entity on behalf
|
||||||
|
of whom a Contribution has been received by Licensor and subsequently
|
||||||
|
incorporated within the Work.
|
||||||
|
|
||||||
|
#### 2. Grant of Copyright License
|
||||||
|
|
||||||
|
Subject to the terms and conditions of this License, each Contributor hereby
|
||||||
|
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||||
|
irrevocable copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the Work and such
|
||||||
|
Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
#### 3. Grant of Patent License
|
||||||
|
|
||||||
|
Subject to the terms and conditions of this License, each Contributor hereby
|
||||||
|
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||||
|
irrevocable (except as stated in this section) patent license to make, have
|
||||||
|
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
|
||||||
|
such license applies only to those patent claims licensable by such Contributor
|
||||||
|
that are necessarily infringed by their Contribution(s) alone or by combination
|
||||||
|
of their Contribution(s) with the Work to which such Contribution(s) was
|
||||||
|
submitted. If You institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
|
||||||
|
Contribution incorporated within the Work constitutes direct or contributory
|
||||||
|
patent infringement, then any patent licenses granted to You under this License
|
||||||
|
for that Work shall terminate as of the date such litigation is filed.
|
||||||
|
|
||||||
|
#### 4. Redistribution
|
||||||
|
|
||||||
|
You may reproduce and distribute copies of the Work or Derivative Works thereof
|
||||||
|
in any medium, with or without modifications, and in Source or Object form,
|
||||||
|
provided that You meet the following conditions:
|
||||||
|
|
||||||
|
* **(a)** You must give any other recipients of the Work or Derivative Works a copy of
|
||||||
|
this License; and
|
||||||
|
* **(b)** You must cause any modified files to carry prominent notices stating that You
|
||||||
|
changed the files; and
|
||||||
|
* **(c)** You must retain, in the Source form of any Derivative Works that You distribute,
|
||||||
|
all copyright, patent, trademark, and attribution notices from the Source form
|
||||||
|
of the Work, excluding those notices that do not pertain to any part of the
|
||||||
|
Derivative Works; and
|
||||||
|
* **(d)** If the Work includes a “NOTICE” text file as part of its distribution, then any
|
||||||
|
Derivative Works that You distribute must include a readable copy of the
|
||||||
|
attribution notices contained within such NOTICE file, excluding those notices
|
||||||
|
that do not pertain to any part of the Derivative Works, in at least one of the
|
||||||
|
following places: within a NOTICE text file distributed as part of the
|
||||||
|
Derivative Works; within the Source form or documentation, if provided along
|
||||||
|
with the Derivative Works; or, within a display generated by the Derivative
|
||||||
|
Works, if and wherever such third-party notices normally appear. The contents of
|
||||||
|
the NOTICE file are for informational purposes only and do not modify the
|
||||||
|
License. You may add Your own attribution notices within Derivative Works that
|
||||||
|
You distribute, alongside or as an addendum to the NOTICE text from the Work,
|
||||||
|
provided that such additional attribution notices cannot be construed as
|
||||||
|
modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and may provide
|
||||||
|
additional or different license terms and conditions for use, reproduction, or
|
||||||
|
distribution of Your modifications, or for any such Derivative Works as a whole,
|
||||||
|
provided Your use, reproduction, and distribution of the Work otherwise complies
|
||||||
|
with the conditions stated in this License.
|
||||||
|
|
||||||
|
#### 5. Submission of Contributions
|
||||||
|
|
||||||
|
Unless You explicitly state otherwise, any Contribution intentionally submitted
|
||||||
|
for inclusion in the Work by You to the Licensor shall be under the terms and
|
||||||
|
conditions of this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify the terms of
|
||||||
|
any separate license agreement you may have executed with Licensor regarding
|
||||||
|
such Contributions.
|
||||||
|
|
||||||
|
#### 6. Trademarks
|
||||||
|
|
||||||
|
This License does not grant permission to use the trade names, trademarks,
|
||||||
|
service marks, or product names of the Licensor, except as required for
|
||||||
|
reasonable and customary use in describing the origin of the Work and
|
||||||
|
reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
#### 7. Disclaimer of Warranty
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, Licensor provides the
|
||||||
|
Work (and each Contributor provides its Contributions) on an “AS IS” BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
|
||||||
|
including, without limitation, any warranties or conditions of TITLE,
|
||||||
|
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
|
||||||
|
solely responsible for determining the appropriateness of using or
|
||||||
|
redistributing the Work and assume any risks associated with Your exercise of
|
||||||
|
permissions under this License.
|
||||||
|
|
||||||
|
#### 8. Limitation of Liability
|
||||||
|
|
||||||
|
In no event and under no legal theory, whether in tort (including negligence),
|
||||||
|
contract, or otherwise, unless required by applicable law (such as deliberate
|
||||||
|
and grossly negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special, incidental,
|
||||||
|
or consequential damages of any character arising as a result of this License or
|
||||||
|
out of the use or inability to use the Work (including but not limited to
|
||||||
|
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
|
||||||
|
any and all other commercial damages or losses), even if such Contributor has
|
||||||
|
been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
#### 9. Accepting Warranty or Additional Liability
|
||||||
|
|
||||||
|
While redistributing the Work or Derivative Works thereof, You may choose to
|
||||||
|
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
|
||||||
|
other liability obligations and/or rights consistent with this License. However,
|
||||||
|
in accepting such obligations, You may act only on Your own behalf and on Your
|
||||||
|
sole responsibility, not on behalf of any other Contributor, and only if You
|
||||||
|
agree to indemnify, defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason of your
|
||||||
|
accepting any such warranty or additional liability.
|
||||||
24
licenses/django-filter.txt
Normal file
24
licenses/django-filter.txt
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
Copyright (c) Alex Gaynor and individual contributors.
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
* The names of its contributors may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
|
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
30
licenses/drf-spectacular.txt
Normal file
30
licenses/drf-spectacular.txt
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
Copyright © 2011-present, Encode OSS Ltd.
|
||||||
|
Copyright © 2019-2021, T. Franzel <tfranzel@gmail.com>, Cashlink Technologies GmbH.
|
||||||
|
Copyright © 2021-present, T. Franzel <tfranzel@gmail.com>.
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
* Neither the name of the copyright holder nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
19
licenses/inflection.txt
Normal file
19
licenses/inflection.txt
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
Copyright (C) 2012-2020 Janne Vanhala
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
20
licenses/tabulate.txt
Normal file
20
licenses/tabulate.txt
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
Copyright (c) 2011-2020 Sergey Astanin and contributors
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
202
licenses/uritemplate.txt
Normal file
202
licenses/uritemplate.txt
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
@@ -47,8 +47,8 @@ python-tss-sdk>=1.2.1
|
|||||||
python-ldap
|
python-ldap
|
||||||
pyyaml>=6.0.1
|
pyyaml>=6.0.1
|
||||||
receptorctl
|
receptorctl
|
||||||
social-auth-core[openidconnect]==4.3.0 # see UPGRADE BLOCKERs
|
social-auth-core[openidconnect]==4.4.2 # see UPGRADE BLOCKERs
|
||||||
social-auth-app-django==5.0.0 # see UPGRADE BLOCKERs
|
social-auth-app-django==5.4.0 # see UPGRADE BLOCKERs
|
||||||
sqlparse >= 0.4.4 # Required by django https://github.com/ansible/awx/security/dependabot/96
|
sqlparse >= 0.4.4 # Required by django https://github.com/ansible/awx/security/dependabot/96
|
||||||
redis
|
redis
|
||||||
requests
|
requests
|
||||||
|
|||||||
@@ -83,6 +83,7 @@ cryptography==41.0.3
|
|||||||
# adal
|
# adal
|
||||||
# autobahn
|
# autobahn
|
||||||
# azure-keyvault
|
# azure-keyvault
|
||||||
|
# django-ansible-base
|
||||||
# jwcrypto
|
# jwcrypto
|
||||||
# pyopenssl
|
# pyopenssl
|
||||||
# service-identity
|
# service-identity
|
||||||
@@ -105,23 +106,35 @@ django==4.2.6
|
|||||||
# via
|
# via
|
||||||
# -r /awx_devel/requirements/requirements.in
|
# -r /awx_devel/requirements/requirements.in
|
||||||
# channels
|
# channels
|
||||||
|
# django-ansible-base
|
||||||
# django-auth-ldap
|
# django-auth-ldap
|
||||||
# django-cors-headers
|
# django-cors-headers
|
||||||
# django-crum
|
# django-crum
|
||||||
# django-extensions
|
# django-extensions
|
||||||
|
# django-filter
|
||||||
# django-guid
|
# django-guid
|
||||||
# django-oauth-toolkit
|
# django-oauth-toolkit
|
||||||
# django-polymorphic
|
# django-polymorphic
|
||||||
# django-solo
|
# django-solo
|
||||||
# djangorestframework
|
# djangorestframework
|
||||||
|
# drf-spectacular
|
||||||
|
# social-auth-app-django
|
||||||
|
django-ansible-base @ git+https://github.com/ansible/django-ansible-base.git@devel
|
||||||
|
# via -r /awx_devel/requirements/requirements_git.txt
|
||||||
django-auth-ldap==4.1.0
|
django-auth-ldap==4.1.0
|
||||||
# via -r /awx_devel/requirements/requirements.in
|
# via
|
||||||
|
# -r /awx_devel/requirements/requirements.in
|
||||||
|
# django-ansible-base
|
||||||
django-cors-headers==3.13.0
|
django-cors-headers==3.13.0
|
||||||
# via -r /awx_devel/requirements/requirements.in
|
# via -r /awx_devel/requirements/requirements.in
|
||||||
django-crum==0.7.9
|
django-crum==0.7.9
|
||||||
# via -r /awx_devel/requirements/requirements.in
|
# via
|
||||||
|
# -r /awx_devel/requirements/requirements.in
|
||||||
|
# django-ansible-base
|
||||||
django-extensions==3.2.1
|
django-extensions==3.2.1
|
||||||
# via -r /awx_devel/requirements/requirements.in
|
# via -r /awx_devel/requirements/requirements.in
|
||||||
|
django-filter==23.5
|
||||||
|
# via django-ansible-base
|
||||||
django-guid==3.2.1
|
django-guid==3.2.1
|
||||||
# via -r /awx_devel/requirements/requirements.in
|
# via -r /awx_devel/requirements/requirements.in
|
||||||
django-oauth-toolkit==1.7.1
|
django-oauth-toolkit==1.7.1
|
||||||
@@ -136,11 +149,16 @@ django-solo==2.0.0
|
|||||||
django-split-settings==1.0.0
|
django-split-settings==1.0.0
|
||||||
# via -r /awx_devel/requirements/requirements.in
|
# via -r /awx_devel/requirements/requirements.in
|
||||||
djangorestframework==3.14.0
|
djangorestframework==3.14.0
|
||||||
# via -r /awx_devel/requirements/requirements.in
|
# via
|
||||||
|
# -r /awx_devel/requirements/requirements.in
|
||||||
|
# django-ansible-base
|
||||||
|
# drf-spectacular
|
||||||
djangorestframework-yaml==2.0.0
|
djangorestframework-yaml==2.0.0
|
||||||
# via -r /awx_devel/requirements/requirements.in
|
# via -r /awx_devel/requirements/requirements.in
|
||||||
docutils==0.19
|
docutils==0.19
|
||||||
# via python-daemon
|
# via python-daemon
|
||||||
|
drf-spectacular==0.26.5
|
||||||
|
# via django-ansible-base
|
||||||
ecdsa==0.18.0
|
ecdsa==0.18.0
|
||||||
# via python-jose
|
# via python-jose
|
||||||
enum-compat==0.0.3
|
enum-compat==0.0.3
|
||||||
@@ -179,6 +197,10 @@ incremental==22.10.0
|
|||||||
# via twisted
|
# via twisted
|
||||||
inflect==6.0.2
|
inflect==6.0.2
|
||||||
# via jaraco-text
|
# via jaraco-text
|
||||||
|
inflection==0.5.1
|
||||||
|
# via
|
||||||
|
# django-ansible-base
|
||||||
|
# drf-spectacular
|
||||||
irc==20.1.0
|
irc==20.1.0
|
||||||
# via -r /awx_devel/requirements/requirements.in
|
# via -r /awx_devel/requirements/requirements.in
|
||||||
isodate==0.6.1
|
isodate==0.6.1
|
||||||
@@ -213,7 +235,9 @@ jmespath==1.0.1
|
|||||||
json-log-formatter==0.5.1
|
json-log-formatter==0.5.1
|
||||||
# via -r /awx_devel/requirements/requirements.in
|
# via -r /awx_devel/requirements/requirements.in
|
||||||
jsonschema==4.17.3
|
jsonschema==4.17.3
|
||||||
# via -r /awx_devel/requirements/requirements.in
|
# via
|
||||||
|
# -r /awx_devel/requirements/requirements.in
|
||||||
|
# drf-spectacular
|
||||||
jwcrypto==1.4.2
|
jwcrypto==1.4.2
|
||||||
# via django-oauth-toolkit
|
# via django-oauth-toolkit
|
||||||
kubernetes==25.3.0
|
kubernetes==25.3.0
|
||||||
@@ -328,6 +352,7 @@ python-jose==3.3.0
|
|||||||
python-ldap==3.4.3
|
python-ldap==3.4.3
|
||||||
# via
|
# via
|
||||||
# -r /awx_devel/requirements/requirements.in
|
# -r /awx_devel/requirements/requirements.in
|
||||||
|
# django-ansible-base
|
||||||
# django-auth-ldap
|
# django-auth-ldap
|
||||||
python-string-utils==1.0.0
|
python-string-utils==1.0.0
|
||||||
# via openshift
|
# via openshift
|
||||||
@@ -335,7 +360,9 @@ python-tss-sdk==1.2.1
|
|||||||
# via -r /awx_devel/requirements/requirements.in
|
# via -r /awx_devel/requirements/requirements.in
|
||||||
python3-openid==3.2.0
|
python3-openid==3.2.0
|
||||||
# via social-auth-core
|
# via social-auth-core
|
||||||
# via -r /awx_devel/requirements/requirements_git.txt
|
# via
|
||||||
|
# -r /awx_devel/requirements/requirements_git.txt
|
||||||
|
# django-ansible-base
|
||||||
pytz==2022.6
|
pytz==2022.6
|
||||||
# via
|
# via
|
||||||
# djangorestframework
|
# djangorestframework
|
||||||
@@ -347,6 +374,7 @@ pyyaml==6.0.1
|
|||||||
# -r /awx_devel/requirements/requirements.in
|
# -r /awx_devel/requirements/requirements.in
|
||||||
# ansible-runner
|
# ansible-runner
|
||||||
# djangorestframework-yaml
|
# djangorestframework-yaml
|
||||||
|
# drf-spectacular
|
||||||
# kubernetes
|
# kubernetes
|
||||||
# receptorctl
|
# receptorctl
|
||||||
receptorctl==1.4.2
|
receptorctl==1.4.2
|
||||||
@@ -406,9 +434,11 @@ slack-sdk==3.19.4
|
|||||||
# via -r /awx_devel/requirements/requirements.in
|
# via -r /awx_devel/requirements/requirements.in
|
||||||
smmap==5.0.0
|
smmap==5.0.0
|
||||||
# via gitdb
|
# via gitdb
|
||||||
social-auth-app-django==5.0.0
|
social-auth-app-django==5.4.0
|
||||||
# via -r /awx_devel/requirements/requirements.in
|
# via
|
||||||
social-auth-core[openidconnect]==4.3.0
|
# -r /awx_devel/requirements/requirements.in
|
||||||
|
# django-ansible-base
|
||||||
|
social-auth-core[openidconnect]==4.4.2
|
||||||
# via
|
# via
|
||||||
# -r /awx_devel/requirements/requirements.in
|
# -r /awx_devel/requirements/requirements.in
|
||||||
# social-auth-app-django
|
# social-auth-app-django
|
||||||
@@ -416,6 +446,8 @@ sqlparse==0.4.4
|
|||||||
# via
|
# via
|
||||||
# -r /awx_devel/requirements/requirements.in
|
# -r /awx_devel/requirements/requirements.in
|
||||||
# django
|
# django
|
||||||
|
tabulate==0.9.0
|
||||||
|
# via django-ansible-base
|
||||||
tacacs-plus==1.0
|
tacacs-plus==1.0
|
||||||
# via -r /awx_devel/requirements/requirements.in
|
# via -r /awx_devel/requirements/requirements.in
|
||||||
tempora==5.1.0
|
tempora==5.1.0
|
||||||
@@ -439,6 +471,8 @@ typing-extensions==4.4.0
|
|||||||
# setuptools-rust
|
# setuptools-rust
|
||||||
# setuptools-scm
|
# setuptools-scm
|
||||||
# twisted
|
# twisted
|
||||||
|
uritemplate==4.1.1
|
||||||
|
# via drf-spectacular
|
||||||
urllib3==1.26.13
|
urllib3==1.26.13
|
||||||
# via
|
# via
|
||||||
# botocore
|
# botocore
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
build
|
build
|
||||||
coreapi
|
coreapi
|
||||||
django-debug-toolbar==3.2.4
|
django-debug-toolbar==3.2.4
|
||||||
|
django-test-migrations
|
||||||
drf-yasg
|
drf-yasg
|
||||||
# pprofile - re-add once https://github.com/vpelletier/pprofile/issues/41 is addressed
|
# pprofile - re-add once https://github.com/vpelletier/pprofile/issues/41 is addressed
|
||||||
ipython>=7.31.1 # https://github.com/ansible/awx/security/dependabot/30
|
ipython>=7.31.1 # https://github.com/ansible/awx/security/dependabot/30
|
||||||
|
|||||||
@@ -5,3 +5,4 @@ git+https://github.com/ansible/ansible-runner.git@devel#egg=ansible-runner
|
|||||||
# specifically need https://github.com/robgolding/django-radius/pull/27
|
# specifically need https://github.com/robgolding/django-radius/pull/27
|
||||||
git+https://github.com/ansible/django-radius.git@develop#egg=django-radius
|
git+https://github.com/ansible/django-radius.git@develop#egg=django-radius
|
||||||
git+https://github.com/ansible/python3-saml.git@devel#egg=python3-saml
|
git+https://github.com/ansible/python3-saml.git@devel#egg=python3-saml
|
||||||
|
git+https://github.com/ansible/django-ansible-base.git@devel#egg=django-ansible-base
|
||||||
@@ -1,15 +1,11 @@
|
|||||||
---
|
---
|
||||||
- name: See if vault has been initialized
|
|
||||||
ansible.builtin.stat:
|
|
||||||
path: "{{ vault_file }}"
|
|
||||||
register: vault_secret_file_info
|
|
||||||
|
|
||||||
- block:
|
- block:
|
||||||
- name: Start the vault
|
- name: Start the vault
|
||||||
community.docker.docker_compose:
|
community.docker.docker_compose:
|
||||||
state: present
|
state: present
|
||||||
services: vault
|
services: vault
|
||||||
project_src: "{{ sources_dest }}"
|
project_src: "{{ sources_dest }}"
|
||||||
|
register: vault_start
|
||||||
|
|
||||||
- name: Run the initialization
|
- name: Run the initialization
|
||||||
community.docker.docker_container_exec:
|
community.docker.docker_container_exec:
|
||||||
@@ -18,6 +14,7 @@
|
|||||||
env:
|
env:
|
||||||
VAULT_ADDR: "http://127.0.0.1:1234"
|
VAULT_ADDR: "http://127.0.0.1:1234"
|
||||||
register: vault_initialization
|
register: vault_initialization
|
||||||
|
ignore_errors: true
|
||||||
|
|
||||||
- name: Write out initialization file
|
- name: Write out initialization file
|
||||||
copy:
|
copy:
|
||||||
@@ -30,6 +27,7 @@
|
|||||||
{{ vault_initialization.stdout_lines[4] | regex_replace('Unseal Key ', 'Unseal_Key_') }}
|
{{ vault_initialization.stdout_lines[4] | regex_replace('Unseal Key ', 'Unseal_Key_') }}
|
||||||
{{ vault_initialization.stdout_lines[6] | regex_replace('Initial Root Token', 'Initial_Root_Token') }}
|
{{ vault_initialization.stdout_lines[6] | regex_replace('Initial Root Token', 'Initial_Root_Token') }}
|
||||||
dest: "{{ vault_file }}"
|
dest: "{{ vault_file }}"
|
||||||
|
when: (vault_initialization.stdout_lines | length) > 0
|
||||||
|
|
||||||
- name: Unlock the vault
|
- name: Unlock the vault
|
||||||
include_role:
|
include_role:
|
||||||
@@ -58,5 +56,4 @@
|
|||||||
community.docker.docker_compose:
|
community.docker.docker_compose:
|
||||||
state: absent
|
state: absent
|
||||||
project_src: "{{ sources_dest }}"
|
project_src: "{{ sources_dest }}"
|
||||||
|
when: vault_start is defined and vault_start.changed
|
||||||
when: not vault_secret_file_info.stat.exists
|
|
||||||
|
|||||||
4
tox.ini
4
tox.ini
@@ -27,7 +27,8 @@ deps =
|
|||||||
commands =
|
commands =
|
||||||
{envpython} -m piptools compile \
|
{envpython} -m piptools compile \
|
||||||
--output-file=docs/docsite/requirements.txt \
|
--output-file=docs/docsite/requirements.txt \
|
||||||
docs/docsite/requirements.in
|
docs/docsite/requirements.in \
|
||||||
|
{posargs:--upgrade}
|
||||||
|
|
||||||
[testenv:docs]
|
[testenv:docs]
|
||||||
description = Build documentation
|
description = Build documentation
|
||||||
@@ -35,4 +36,5 @@ deps =
|
|||||||
-r{toxinidir}/docs/docsite/requirements.in
|
-r{toxinidir}/docs/docsite/requirements.in
|
||||||
-c{toxinidir}/docs/docsite/requirements.txt
|
-c{toxinidir}/docs/docsite/requirements.txt
|
||||||
commands =
|
commands =
|
||||||
|
python {toxinidir}/docs/docsite/rst/rest_api/_swagger/download-json.py
|
||||||
sphinx-build -T -E -W -n --keep-going {tty:--color} -j auto -c docs/docsite -d docs/docsite/build/doctrees -b html docs/docsite/rst docs/docsite/build/html
|
sphinx-build -T -E -W -n --keep-going {tty:--color} -j auto -c docs/docsite -d docs/docsite/build/doctrees -b html docs/docsite/rst docs/docsite/build/html
|
||||||
|
|||||||
Reference in New Issue
Block a user