mirror of
https://github.com/ansible/awx.git
synced 2026-01-09 23:12:08 -03:30
Merge branch 'devel' into collection-existential-state-for-credential-module
This commit is contained in:
commit
d57f549a4c
4
.github/workflows/label_issue.yml
vendored
4
.github/workflows/label_issue.yml
vendored
@ -6,6 +6,10 @@ on:
|
||||
- opened
|
||||
- reopened
|
||||
|
||||
permissions:
|
||||
contents: read # to fetch code
|
||||
issues: write # to label issues
|
||||
|
||||
jobs:
|
||||
triage:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
4
.github/workflows/label_pr.yml
vendored
4
.github/workflows/label_pr.yml
vendored
@ -7,6 +7,10 @@ on:
|
||||
- reopened
|
||||
- synchronize
|
||||
|
||||
permissions:
|
||||
contents: read # to determine modified files (actions/labeler)
|
||||
pull-requests: write # to add labels to PRs (actions/labeler)
|
||||
|
||||
jobs:
|
||||
triage:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
3
.github/workflows/promote.yml
vendored
3
.github/workflows/promote.yml
vendored
@ -8,6 +8,9 @@ on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
permissions:
|
||||
contents: read # to fetch code (actions/checkout)
|
||||
|
||||
jobs:
|
||||
promote:
|
||||
if: endsWith(github.repository, '/awx')
|
||||
|
||||
6
Makefile
6
Makefile
@ -37,6 +37,8 @@ SPLUNK ?= false
|
||||
PROMETHEUS ?= false
|
||||
# If set to true docker-compose will also start a grafana instance
|
||||
GRAFANA ?= false
|
||||
# If set to true docker-compose will also start a tacacs+ instance
|
||||
TACACS ?= false
|
||||
|
||||
VENV_BASE ?= /var/lib/awx/venv
|
||||
|
||||
@ -519,7 +521,9 @@ docker-compose-sources: .git/hooks/pre-commit
|
||||
-e enable_ldap=$(LDAP) \
|
||||
-e enable_splunk=$(SPLUNK) \
|
||||
-e enable_prometheus=$(PROMETHEUS) \
|
||||
-e enable_grafana=$(GRAFANA) $(EXTRA_SOURCES_ANSIBLE_OPTS)
|
||||
-e enable_grafana=$(GRAFANA) \
|
||||
-e enable_tacacs=$(TACACS) \
|
||||
$(EXTRA_SOURCES_ANSIBLE_OPTS)
|
||||
|
||||
docker-compose: awx/projects docker-compose-sources
|
||||
$(DOCKER_COMPOSE) -f tools/docker-compose/_sources/docker-compose.yml $(COMPOSE_OPTS) up $(COMPOSE_UP_OPTS) --remove-orphans
|
||||
|
||||
@ -25,6 +25,7 @@ __all__ = [
|
||||
'UserPermission',
|
||||
'IsSystemAdminOrAuditor',
|
||||
'WorkflowApprovalPermission',
|
||||
'AnalyticsPermission',
|
||||
]
|
||||
|
||||
|
||||
@ -250,3 +251,16 @@ class IsSystemAdminOrAuditor(permissions.BasePermission):
|
||||
class WebhookKeyPermission(permissions.BasePermission):
|
||||
def has_object_permission(self, request, view, obj):
|
||||
return request.user.can_access(view.model, 'admin', obj, request.data)
|
||||
|
||||
|
||||
class AnalyticsPermission(permissions.BasePermission):
|
||||
"""
|
||||
Allows GET/POST/OPTIONS to system admins and system auditors.
|
||||
"""
|
||||
|
||||
def has_permission(self, request, view):
|
||||
if not (request.user and request.user.is_authenticated):
|
||||
return False
|
||||
if request.method in ["GET", "POST", "OPTIONS"]:
|
||||
return request.user.is_superuser or request.user.is_system_auditor
|
||||
return request.user.is_superuser
|
||||
|
||||
@ -995,6 +995,24 @@ class UserSerializer(BaseSerializer):
|
||||
django_validate_password(value)
|
||||
if not self.instance and value in (None, ''):
|
||||
raise serializers.ValidationError(_('Password required for new User.'))
|
||||
|
||||
# Check if a password is too long
|
||||
password_max_length = User._meta.get_field('password').max_length
|
||||
if len(value) > password_max_length:
|
||||
raise serializers.ValidationError(_('Password max length is {}'.format(password_max_length)))
|
||||
if getattr(settings, 'LOCAL_PASSWORD_MIN_LENGTH', 0) and len(value) < getattr(settings, 'LOCAL_PASSWORD_MIN_LENGTH'):
|
||||
raise serializers.ValidationError(_('Password must be at least {} characters long.'.format(getattr(settings, 'LOCAL_PASSWORD_MIN_LENGTH'))))
|
||||
if getattr(settings, 'LOCAL_PASSWORD_MIN_DIGITS', 0) and sum(c.isdigit() for c in value) < getattr(settings, 'LOCAL_PASSWORD_MIN_DIGITS'):
|
||||
raise serializers.ValidationError(_('Password must contain at least {} digits.'.format(getattr(settings, 'LOCAL_PASSWORD_MIN_DIGITS'))))
|
||||
if getattr(settings, 'LOCAL_PASSWORD_MIN_UPPER', 0) and sum(c.isupper() for c in value) < getattr(settings, 'LOCAL_PASSWORD_MIN_UPPER'):
|
||||
raise serializers.ValidationError(
|
||||
_('Password must contain at least {} uppercase characters.'.format(getattr(settings, 'LOCAL_PASSWORD_MIN_UPPER')))
|
||||
)
|
||||
if getattr(settings, 'LOCAL_PASSWORD_MIN_SPECIAL', 0) and sum(not c.isalnum() for c in value) < getattr(settings, 'LOCAL_PASSWORD_MIN_SPECIAL'):
|
||||
raise serializers.ValidationError(
|
||||
_('Password must contain at least {} special characters.'.format(getattr(settings, 'LOCAL_PASSWORD_MIN_SPECIAL')))
|
||||
)
|
||||
|
||||
return value
|
||||
|
||||
def _update_password(self, obj, new_password):
|
||||
|
||||
@ -7,10 +7,9 @@ from django.utils.translation import gettext_lazy as _
|
||||
from django.utils import translation
|
||||
|
||||
from awx.api.generics import APIView, Response
|
||||
from awx.api.permissions import IsSystemAdminOrAuditor
|
||||
from awx.api.permissions import AnalyticsPermission
|
||||
from awx.api.versioning import reverse
|
||||
from awx.main.utils import get_awx_version
|
||||
from rest_framework.permissions import AllowAny
|
||||
from rest_framework import status
|
||||
|
||||
from collections import OrderedDict
|
||||
@ -43,7 +42,7 @@ class GetNotAllowedMixin(object):
|
||||
|
||||
|
||||
class AnalyticsRootView(APIView):
|
||||
permission_classes = (AllowAny,)
|
||||
permission_classes = (AnalyticsPermission,)
|
||||
name = _('Automation Analytics')
|
||||
swagger_topic = 'Automation Analytics'
|
||||
|
||||
@ -99,7 +98,7 @@ class AnalyticsGenericView(APIView):
|
||||
return Response(response.json(), status=response.status_code)
|
||||
"""
|
||||
|
||||
permission_classes = (IsSystemAdminOrAuditor,)
|
||||
permission_classes = (AnalyticsPermission,)
|
||||
|
||||
@staticmethod
|
||||
def _request_headers(request):
|
||||
|
||||
@ -131,7 +131,7 @@ def _identify_lower(key, since, until, last_gather):
|
||||
return lower, last_entries
|
||||
|
||||
|
||||
@register('config', '1.5', description=_('General platform configuration.'))
|
||||
@register('config', '1.6', description=_('General platform configuration.'))
|
||||
def config(since, **kwargs):
|
||||
license_info = get_license()
|
||||
install_type = 'traditional'
|
||||
@ -155,10 +155,13 @@ def config(since, **kwargs):
|
||||
'subscription_name': license_info.get('subscription_name'),
|
||||
'sku': license_info.get('sku'),
|
||||
'support_level': license_info.get('support_level'),
|
||||
'usage': license_info.get('usage'),
|
||||
'product_name': license_info.get('product_name'),
|
||||
'valid_key': license_info.get('valid_key'),
|
||||
'satellite': license_info.get('satellite'),
|
||||
'pool_id': license_info.get('pool_id'),
|
||||
'subscription_id': license_info.get('subscription_id'),
|
||||
'account_number': license_info.get('account_number'),
|
||||
'current_instances': license_info.get('current_instances'),
|
||||
'automated_instances': license_info.get('automated_instances'),
|
||||
'automated_since': license_info.get('automated_since'),
|
||||
|
||||
@ -298,11 +298,13 @@ class Metrics:
|
||||
try:
|
||||
current_time = time.time()
|
||||
if current_time - self.previous_send_metrics.decode(self.conn) > self.send_metrics_interval:
|
||||
serialized_metrics = self.serialize_local_metrics()
|
||||
payload = {
|
||||
'instance': self.instance_name,
|
||||
'metrics': self.serialize_local_metrics(),
|
||||
'metrics': serialized_metrics,
|
||||
}
|
||||
|
||||
# store the serialized data locally as well, so that load_other_metrics will read it
|
||||
self.conn.set(root_key + '_instance_' + self.instance_name, serialized_metrics)
|
||||
emit_channel_notification("metrics", payload)
|
||||
|
||||
self.previous_send_metrics.set(current_time)
|
||||
|
||||
@ -54,6 +54,12 @@ aim_inputs = {
|
||||
'help_text': _('Lookup query for the object. Ex: Safe=TestSafe;Object=testAccountName123'),
|
||||
},
|
||||
{'id': 'object_query_format', 'label': _('Object Query Format'), 'type': 'string', 'default': 'Exact', 'choices': ['Exact', 'Regexp']},
|
||||
{
|
||||
'id': 'object_property',
|
||||
'label': _('Object Property'),
|
||||
'type': 'string',
|
||||
'help_text': _('The property of the object to return. Default: Content Ex: Username, Address, etc.'),
|
||||
},
|
||||
{
|
||||
'id': 'reason',
|
||||
'label': _('Reason'),
|
||||
@ -74,6 +80,7 @@ def aim_backend(**kwargs):
|
||||
app_id = kwargs['app_id']
|
||||
object_query = kwargs['object_query']
|
||||
object_query_format = kwargs['object_query_format']
|
||||
object_property = kwargs.get('object_property', '')
|
||||
reason = kwargs.get('reason', None)
|
||||
if webservice_id == '':
|
||||
webservice_id = 'AIMWebService'
|
||||
@ -98,7 +105,18 @@ def aim_backend(**kwargs):
|
||||
allow_redirects=False,
|
||||
)
|
||||
raise_for_status(res)
|
||||
return res.json()['Content']
|
||||
# CCP returns the property name capitalized, username is camel case
|
||||
# so we need to handle that case
|
||||
if object_property == '':
|
||||
object_property = 'Content'
|
||||
elif object_property.lower() == 'username':
|
||||
object_property = 'UserName'
|
||||
elif object_property not in res:
|
||||
raise KeyError('Property {} not found in object'.format(object_property))
|
||||
else:
|
||||
object_property = object_property.capitalize()
|
||||
|
||||
return res.json()[object_property]
|
||||
|
||||
|
||||
aim_plugin = CredentialPlugin('CyberArk Central Credential Provider Lookup', inputs=aim_inputs, backend=aim_backend)
|
||||
|
||||
@ -35,8 +35,14 @@ dsv_inputs = {
|
||||
'type': 'string',
|
||||
'help_text': _('The secret path e.g. /test/secret1'),
|
||||
},
|
||||
{
|
||||
'id': 'secret_field',
|
||||
'label': _('Secret Field'),
|
||||
'help_text': _('The field to extract from the secret'),
|
||||
'type': 'string',
|
||||
},
|
||||
],
|
||||
'required': ['tenant', 'client_id', 'client_secret', 'path'],
|
||||
'required': ['tenant', 'client_id', 'client_secret', 'path', 'secret_field'],
|
||||
}
|
||||
|
||||
if settings.DEBUG:
|
||||
@ -52,5 +58,5 @@ if settings.DEBUG:
|
||||
dsv_plugin = CredentialPlugin(
|
||||
'Thycotic DevOps Secrets Vault',
|
||||
dsv_inputs,
|
||||
lambda **kwargs: SecretsVault(**{k: v for (k, v) in kwargs.items() if k in [field['id'] for field in dsv_inputs['fields']]}).get_secret(kwargs['path']),
|
||||
lambda **kwargs: SecretsVault(**{k: v for (k, v) in kwargs.items() if k in [field['id'] for field in dsv_inputs['fields']]}).get_secret(kwargs['path'])['data'][kwargs['secret_field']], # fmt: skip
|
||||
)
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
from .plugin import CredentialPlugin
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from thycotic.secrets.server import PasswordGrantAuthorizer, SecretServer, ServerSecret
|
||||
from thycotic.secrets.server import DomainPasswordGrantAuthorizer, PasswordGrantAuthorizer, SecretServer, ServerSecret
|
||||
|
||||
tss_inputs = {
|
||||
'fields': [
|
||||
@ -17,6 +17,12 @@ tss_inputs = {
|
||||
'help_text': _('The (Application) user username'),
|
||||
'type': 'string',
|
||||
},
|
||||
{
|
||||
'id': 'domain',
|
||||
'label': _('Domain'),
|
||||
'help_text': _('The (Application) user domain'),
|
||||
'type': 'string',
|
||||
},
|
||||
{
|
||||
'id': 'password',
|
||||
'label': _('Password'),
|
||||
@ -44,7 +50,10 @@ tss_inputs = {
|
||||
|
||||
|
||||
def tss_backend(**kwargs):
|
||||
authorizer = PasswordGrantAuthorizer(kwargs['server_url'], kwargs['username'], kwargs['password'])
|
||||
if 'domain' in kwargs:
|
||||
authorizer = DomainPasswordGrantAuthorizer(kwargs['server_url'], kwargs['username'], kwargs['password'], kwargs['domain'])
|
||||
else:
|
||||
authorizer = PasswordGrantAuthorizer(kwargs['server_url'], kwargs['username'], kwargs['password'])
|
||||
secret_server = SecretServer(kwargs['server_url'], authorizer)
|
||||
secret_dict = secret_server.get_secret(kwargs['secret_id'])
|
||||
secret = ServerSecret(**secret_dict)
|
||||
|
||||
@ -4,6 +4,8 @@ import select
|
||||
|
||||
from contextlib import contextmanager
|
||||
|
||||
from awx.settings.application_name import get_application_name
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import connection as pg_connection
|
||||
|
||||
@ -83,10 +85,11 @@ def pg_bus_conn(new_connection=False):
|
||||
'''
|
||||
|
||||
if new_connection:
|
||||
conf = settings.DATABASES['default']
|
||||
conn = psycopg2.connect(
|
||||
dbname=conf['NAME'], host=conf['HOST'], user=conf['USER'], password=conf['PASSWORD'], port=conf['PORT'], **conf.get("OPTIONS", {})
|
||||
)
|
||||
conf = settings.DATABASES['default'].copy()
|
||||
conf['OPTIONS'] = conf.get('OPTIONS', {}).copy()
|
||||
# Modify the application name to distinguish from other connections the process might use
|
||||
conf['OPTIONS']['application_name'] = get_application_name(settings.CLUSTER_HOST_ID, function='listener')
|
||||
conn = psycopg2.connect(dbname=conf['NAME'], host=conf['HOST'], user=conf['USER'], password=conf['PASSWORD'], port=conf['PORT'], **conf['OPTIONS'])
|
||||
# Django connection.cursor().connection doesn't have autocommit=True on by default
|
||||
conn.set_session(autocommit=True)
|
||||
else:
|
||||
|
||||
@ -10,6 +10,7 @@ from django_guid import set_guid
|
||||
from django_guid.utils import generate_guid
|
||||
|
||||
from awx.main.dispatch.worker import TaskWorker
|
||||
from awx.main.utils.db import set_connection_name
|
||||
|
||||
logger = logging.getLogger('awx.main.dispatch.periodic')
|
||||
|
||||
@ -21,6 +22,9 @@ class Scheduler(Scheduler):
|
||||
def run():
|
||||
ppid = os.getppid()
|
||||
logger.warning('periodic beat started')
|
||||
|
||||
set_connection_name('periodic') # set application_name to distinguish from other dispatcher processes
|
||||
|
||||
while True:
|
||||
if os.getppid() != ppid:
|
||||
# if the parent PID changes, this process has been orphaned
|
||||
|
||||
@ -18,6 +18,7 @@ from django.conf import settings
|
||||
from awx.main.dispatch.pool import WorkerPool
|
||||
from awx.main.dispatch import pg_bus_conn
|
||||
from awx.main.utils.common import log_excess_runtime
|
||||
from awx.main.utils.db import set_connection_name
|
||||
|
||||
if 'run_callback_receiver' in sys.argv:
|
||||
logger = logging.getLogger('awx.main.commands.run_callback_receiver')
|
||||
@ -219,6 +220,7 @@ class BaseWorker(object):
|
||||
def work_loop(self, queue, finished, idx, *args):
|
||||
ppid = os.getppid()
|
||||
signal_handler = WorkerSignalHandler()
|
||||
set_connection_name('worker') # set application_name to distinguish from other dispatcher processes
|
||||
while not signal_handler.kill_now:
|
||||
# if the parent PID changes, this process has been orphaned
|
||||
# via e.g., segfault or sigkill, we should exit too
|
||||
|
||||
@ -98,6 +98,7 @@ class Command(BaseCommand):
|
||||
try:
|
||||
executor = MigrationExecutor(connection)
|
||||
migrating = bool(executor.migration_plan(executor.loader.graph.leaf_nodes()))
|
||||
connection.close() # Because of async nature, main loop will use new connection, so close this
|
||||
except Exception as exc:
|
||||
logger.warning(f'Error on startup of run_wsrelay (error: {exc}), retry in 10s...')
|
||||
time.sleep(10)
|
||||
|
||||
@ -153,3 +153,13 @@ def test_post_org_approval_notification(get, post, admin, notification_template,
|
||||
response = get(url, admin)
|
||||
assert response.status_code == 200
|
||||
assert len(response.data['results']) == 1
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_post_wfj_notification(get, post, admin, workflow_job, notification):
|
||||
workflow_job.notifications.add(notification)
|
||||
workflow_job.save()
|
||||
url = reverse("api:workflow_job_notifications_list", kwargs={'pk': workflow_job.pk})
|
||||
response = get(url, admin)
|
||||
assert response.status_code == 200
|
||||
assert len(response.data['results']) == 1
|
||||
|
||||
75
awx/main/tests/functional/api/test_serializers.py
Normal file
75
awx/main/tests/functional/api/test_serializers.py
Normal file
@ -0,0 +1,75 @@
|
||||
import pytest
|
||||
|
||||
from django.test.utils import override_settings
|
||||
|
||||
from rest_framework.serializers import ValidationError
|
||||
|
||||
from awx.api.serializers import UserSerializer
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"password,min_length,min_digits,min_upper,min_special,expect_error",
|
||||
[
|
||||
# Test length
|
||||
("a", 1, 0, 0, 0, False),
|
||||
("a", 2, 0, 0, 0, True),
|
||||
("aa", 2, 0, 0, 0, False),
|
||||
("aaabcDEF123$%^", 2, 0, 0, 0, False),
|
||||
# Test digits
|
||||
("a", 0, 1, 0, 0, True),
|
||||
("1", 0, 1, 0, 0, False),
|
||||
("1", 0, 2, 0, 0, True),
|
||||
("12", 0, 2, 0, 0, False),
|
||||
("12abcDEF123$%^", 0, 2, 0, 0, False),
|
||||
# Test upper
|
||||
("a", 0, 0, 1, 0, True),
|
||||
("A", 0, 0, 1, 0, False),
|
||||
("A", 0, 0, 2, 0, True),
|
||||
("AB", 0, 0, 2, 0, False),
|
||||
("ABabcDEF123$%^", 0, 0, 2, 0, False),
|
||||
# Test special
|
||||
("a", 0, 0, 0, 1, True),
|
||||
("!", 0, 0, 0, 1, False),
|
||||
("!", 0, 0, 0, 2, True),
|
||||
("!@", 0, 0, 0, 2, False),
|
||||
("!@abcDEF123$%^", 0, 0, 0, 2, False),
|
||||
],
|
||||
)
|
||||
@pytest.mark.django_db
|
||||
def test_validate_password_rules(password, min_length, min_digits, min_upper, min_special, expect_error):
|
||||
user_serializer = UserSerializer()
|
||||
|
||||
# First test password with no params, this should always pass
|
||||
try:
|
||||
user_serializer.validate_password(password)
|
||||
except ValidationError:
|
||||
assert False, f"Password {password} should not have validation issue if no params are used"
|
||||
|
||||
with override_settings(
|
||||
LOCAL_PASSWORD_MIN_LENGTH=min_length, LOCAL_PASSWORD_MIN_DIGITS=min_digits, LOCAL_PASSWORD_MIN_UPPER=min_upper, LOCAL_PASSWORD_MIN_SPECIAL=min_special
|
||||
):
|
||||
if expect_error:
|
||||
with pytest.raises(ValidationError):
|
||||
user_serializer.validate_password(password)
|
||||
else:
|
||||
try:
|
||||
user_serializer.validate_password(password)
|
||||
except ValidationError:
|
||||
assert False, "validate_password raised an unexpected exception"
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_validate_password_too_long():
|
||||
password_max_length = User._meta.get_field('password').max_length
|
||||
password = "x" * password_max_length
|
||||
|
||||
user_serializer = UserSerializer()
|
||||
try:
|
||||
user_serializer.validate_password(password)
|
||||
except ValidationError:
|
||||
assert False, f"Password {password} should not have validation"
|
||||
|
||||
password = f"{password}x"
|
||||
with pytest.raises(ValidationError):
|
||||
user_serializer.validate_password(password)
|
||||
54
awx/main/tests/functional/api/test_workflow_job.py
Normal file
54
awx/main/tests/functional/api/test_workflow_job.py
Normal file
@ -0,0 +1,54 @@
|
||||
import pytest
|
||||
|
||||
|
||||
from awx.api.versioning import reverse
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize(
|
||||
"is_admin, status",
|
||||
[
|
||||
[True, 201],
|
||||
[False, 403],
|
||||
], # if they're a WFJ admin, they get a 201 # if they're not a WFJ *nor* org admin, they get a 403
|
||||
)
|
||||
def test_workflow_job_relaunch(workflow_job, post, admin_user, alice, is_admin, status):
|
||||
url = reverse("api:workflow_job_relaunch", kwargs={'pk': workflow_job.pk})
|
||||
if is_admin:
|
||||
post(url, user=admin_user, expect=status)
|
||||
else:
|
||||
post(url, user=alice, expect=status)
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_workflow_job_relaunch_failure(workflow_job, post, admin_user):
|
||||
workflow_job.is_sliced_job = True
|
||||
workflow_job.job_template = None
|
||||
workflow_job.save()
|
||||
url = reverse("api:workflow_job_relaunch", kwargs={'pk': workflow_job.pk})
|
||||
post(url, user=admin_user, expect=400)
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_workflow_job_relaunch_not_inventory_failure(workflow_job, post, admin_user):
|
||||
workflow_job.is_sliced_job = True
|
||||
workflow_job.inventory = None
|
||||
workflow_job.save()
|
||||
url = reverse("api:workflow_job_relaunch", kwargs={'pk': workflow_job.pk})
|
||||
post(url, user=admin_user, expect=400)
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize(
|
||||
"is_admin, status",
|
||||
[
|
||||
[True, 202],
|
||||
[False, 403],
|
||||
], # if they're a WFJ admin, they get a 202 # if they're not a WFJ *nor* org admin, they get a 403
|
||||
)
|
||||
def test_workflow_job_cancel(workflow_job, post, admin_user, alice, is_admin, status):
|
||||
url = reverse("api:workflow_job_cancel", kwargs={'pk': workflow_job.pk})
|
||||
if is_admin:
|
||||
post(url, user=admin_user, expect=status)
|
||||
else:
|
||||
post(url, user=alice, expect=status)
|
||||
@ -743,6 +743,30 @@ def system_job_factory(system_job_template, admin):
|
||||
return factory
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def wfjt(workflow_job_template_factory, organization):
|
||||
objects = workflow_job_template_factory('test_workflow', organization=organization, persisted=True)
|
||||
return objects.workflow_job_template
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def wfjt_with_nodes(workflow_job_template_factory, organization, job_template):
|
||||
objects = workflow_job_template_factory(
|
||||
'test_workflow', organization=organization, workflow_job_template_nodes=[{'unified_job_template': job_template}], persisted=True
|
||||
)
|
||||
return objects.workflow_job_template
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def wfjt_node(wfjt_with_nodes):
|
||||
return wfjt_with_nodes.workflow_job_template_nodes.all()[0]
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def workflow_job(wfjt):
|
||||
return wfjt.workflow_jobs.create(name='test_workflow')
|
||||
|
||||
|
||||
def dumps(value):
|
||||
return DjangoJSONEncoder().encode(value)
|
||||
|
||||
|
||||
@ -123,6 +123,24 @@ def test_inventory_copy(inventory, group_factory, post, get, alice, organization
|
||||
assert set(group_2_2_copy.hosts.all()) == set()
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize(
|
||||
"is_admin, can_copy, status",
|
||||
[
|
||||
[True, True, 200],
|
||||
[False, False, 200],
|
||||
],
|
||||
)
|
||||
def test_workflow_job_template_copy_access(get, admin_user, alice, workflow_job_template, is_admin, can_copy, status):
|
||||
url = reverse('api:workflow_job_template_copy', kwargs={'pk': workflow_job_template.pk})
|
||||
if is_admin:
|
||||
response = get(url, user=admin_user, expect=status)
|
||||
else:
|
||||
workflow_job_template.organization.auditor_role.members.add(alice)
|
||||
response = get(url, user=alice, expect=status)
|
||||
assert response.data['can_copy'] == can_copy
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_workflow_job_template_copy(workflow_job_template, post, get, admin, organization):
|
||||
'''
|
||||
|
||||
@ -218,3 +218,31 @@ def test_webhook_notification_pointed_to_a_redirect_launch_endpoint(post, admin,
|
||||
)
|
||||
|
||||
assert n1.send("", n1.messages.get("success").get("body")) == 1
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_update_notification_template(admin, notification_template):
|
||||
notification_template.messages['workflow_approval'] = {
|
||||
"running": {
|
||||
"message": None,
|
||||
"body": None,
|
||||
}
|
||||
}
|
||||
notification_template.save()
|
||||
|
||||
workflow_approval_message = {
|
||||
"approved": {
|
||||
"message": None,
|
||||
"body": None,
|
||||
},
|
||||
"running": {
|
||||
"message": "test-message",
|
||||
"body": None,
|
||||
},
|
||||
}
|
||||
notification_template.messages['workflow_approval'] = workflow_approval_message
|
||||
notification_template.save()
|
||||
|
||||
subevents = sorted(notification_template.messages["workflow_approval"].keys())
|
||||
assert subevents == ["approved", "running"]
|
||||
assert notification_template.messages['workflow_approval'] == workflow_approval_message
|
||||
|
||||
@ -13,30 +13,6 @@ from rest_framework.exceptions import PermissionDenied
|
||||
from awx.main.models import InventorySource, JobLaunchConfig
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def wfjt(workflow_job_template_factory, organization):
|
||||
objects = workflow_job_template_factory('test_workflow', organization=organization, persisted=True)
|
||||
return objects.workflow_job_template
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def wfjt_with_nodes(workflow_job_template_factory, organization, job_template):
|
||||
objects = workflow_job_template_factory(
|
||||
'test_workflow', organization=organization, workflow_job_template_nodes=[{'unified_job_template': job_template}], persisted=True
|
||||
)
|
||||
return objects.workflow_job_template
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def wfjt_node(wfjt_with_nodes):
|
||||
return wfjt_with_nodes.workflow_job_template_nodes.all()[0]
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def workflow_job(wfjt):
|
||||
return wfjt.workflow_jobs.create(name='test_workflow')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
class TestWorkflowJobTemplateAccess:
|
||||
def test_random_user_no_edit(self, wfjt, rando):
|
||||
|
||||
@ -3,6 +3,9 @@
|
||||
|
||||
from itertools import chain
|
||||
|
||||
from awx.settings.application_name import set_application_name
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
def get_all_field_names(model):
|
||||
# Implements compatibility with _meta.get_all_field_names
|
||||
@ -18,3 +21,7 @@ def get_all_field_names(model):
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def set_connection_name(function):
|
||||
set_application_name(settings.DATABASES, settings.CLUSTER_HOST_ID, function=function)
|
||||
|
||||
@ -170,6 +170,8 @@ class Licenser(object):
|
||||
|
||||
license.setdefault('sku', sub['pool']['productId'])
|
||||
license.setdefault('subscription_name', sub['pool']['productName'])
|
||||
license.setdefault('subscription_id', sub['pool']['subscriptionId'])
|
||||
license.setdefault('account_number', sub['pool']['accountNumber'])
|
||||
license.setdefault('pool_id', sub['pool']['id'])
|
||||
license.setdefault('product_name', sub['pool']['productName'])
|
||||
license.setdefault('valid_key', True)
|
||||
@ -185,6 +187,14 @@ class Licenser(object):
|
||||
license['instance_count'] = license.get('instance_count', 0) + instances
|
||||
license['subscription_name'] = re.sub(r'[\d]* Managed Nodes', '%d Managed Nodes' % license['instance_count'], license['subscription_name'])
|
||||
|
||||
license['support_level'] = ''
|
||||
license['usage'] = ''
|
||||
for attr in sub['pool'].get('productAttributes', []):
|
||||
if attr.get('name') == 'support_level':
|
||||
license['support_level'] = attr.get('value')
|
||||
elif attr.get('name') == 'usage':
|
||||
license['usage'] = attr.get('value')
|
||||
|
||||
if not license:
|
||||
logger.error("No valid subscriptions found in manifest")
|
||||
self._attrs.update(license)
|
||||
@ -277,7 +287,10 @@ class Licenser(object):
|
||||
license['productId'] = sub['product_id']
|
||||
license['quantity'] = int(sub['quantity'])
|
||||
license['support_level'] = sub['support_level']
|
||||
license['usage'] = sub['usage']
|
||||
license['subscription_name'] = sub['name']
|
||||
license['subscriptionId'] = sub['subscription_id']
|
||||
license['accountNumber'] = sub['account_number']
|
||||
license['id'] = sub['upstream_pool_id']
|
||||
license['endDate'] = sub['end_date']
|
||||
license['productName'] = "Red Hat Ansible Automation"
|
||||
@ -304,7 +317,7 @@ class Licenser(object):
|
||||
def generate_license_options_from_entitlements(self, json):
|
||||
from dateutil.parser import parse
|
||||
|
||||
ValidSub = collections.namedtuple('ValidSub', 'sku name support_level end_date trial quantity pool_id satellite')
|
||||
ValidSub = collections.namedtuple('ValidSub', 'sku name support_level end_date trial quantity pool_id satellite subscription_id account_number usage')
|
||||
valid_subs = []
|
||||
for sub in json:
|
||||
satellite = sub.get('satellite')
|
||||
@ -333,15 +346,23 @@ class Licenser(object):
|
||||
sku = sub['productId']
|
||||
trial = sku.startswith('S') # i.e.,, SER/SVC
|
||||
support_level = ''
|
||||
usage = ''
|
||||
pool_id = sub['id']
|
||||
subscription_id = sub['subscriptionId']
|
||||
account_number = sub['accountNumber']
|
||||
if satellite:
|
||||
support_level = sub['support_level']
|
||||
usage = sub['usage']
|
||||
else:
|
||||
for attr in sub.get('productAttributes', []):
|
||||
if attr.get('name') == 'support_level':
|
||||
support_level = attr.get('value')
|
||||
elif attr.get('name') == 'usage':
|
||||
usage = attr.get('value')
|
||||
|
||||
valid_subs.append(ValidSub(sku, sub['productName'], support_level, end_date, trial, quantity, pool_id, satellite))
|
||||
valid_subs.append(
|
||||
ValidSub(sku, sub['productName'], support_level, end_date, trial, quantity, pool_id, satellite, subscription_id, account_number, usage)
|
||||
)
|
||||
|
||||
if valid_subs:
|
||||
licenses = []
|
||||
@ -350,6 +371,7 @@ class Licenser(object):
|
||||
license._attrs['instance_count'] = int(sub.quantity)
|
||||
license._attrs['sku'] = sub.sku
|
||||
license._attrs['support_level'] = sub.support_level
|
||||
license._attrs['usage'] = sub.usage
|
||||
license._attrs['license_type'] = 'enterprise'
|
||||
if sub.trial:
|
||||
license._attrs['trial'] = True
|
||||
@ -364,6 +386,8 @@ class Licenser(object):
|
||||
license._attrs['valid_key'] = True
|
||||
license.update(license_date=int(sub.end_date.strftime('%s')))
|
||||
license.update(pool_id=sub.pool_id)
|
||||
license.update(subscription_id=sub.subscription_id)
|
||||
license.update(account_number=sub.account_number)
|
||||
licenses.append(license._attrs.copy())
|
||||
return licenses
|
||||
|
||||
|
||||
31
awx/settings/application_name.py
Normal file
31
awx/settings/application_name.py
Normal file
@ -0,0 +1,31 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def get_service_name(argv):
|
||||
'''
|
||||
Return best-effort guess as to the name of this service
|
||||
'''
|
||||
for arg in argv:
|
||||
if arg == '-m':
|
||||
continue
|
||||
if 'python' in arg:
|
||||
continue
|
||||
if 'manage' in arg:
|
||||
continue
|
||||
if arg.startswith('run_'):
|
||||
return arg[len('run_') :]
|
||||
return arg
|
||||
|
||||
|
||||
def get_application_name(CLUSTER_HOST_ID, function=''):
|
||||
if function:
|
||||
function = f'_{function}'
|
||||
return f'awx-{os.getpid()}-{get_service_name(sys.argv)}{function}-{CLUSTER_HOST_ID}'[:63]
|
||||
|
||||
|
||||
def set_application_name(DATABASES, CLUSTER_HOST_ID, function=''):
|
||||
if 'sqlite3' in DATABASES['default']['ENGINE']:
|
||||
return
|
||||
options_dict = DATABASES['default'].setdefault('OPTIONS', dict())
|
||||
options_dict['application_name'] = get_application_name(CLUSTER_HOST_ID, function)
|
||||
@ -734,10 +734,10 @@ CONTROLLER_INSTANCE_ID_VAR = 'remote_tower_id'
|
||||
# ---------------------
|
||||
# ----- Foreman -----
|
||||
# ---------------------
|
||||
SATELLITE6_ENABLED_VAR = 'foreman_enabled'
|
||||
SATELLITE6_ENABLED_VAR = 'foreman_enabled,foreman.enabled'
|
||||
SATELLITE6_ENABLED_VALUE = 'True'
|
||||
SATELLITE6_EXCLUDE_EMPTY_GROUPS = True
|
||||
SATELLITE6_INSTANCE_ID_VAR = 'foreman_id'
|
||||
SATELLITE6_INSTANCE_ID_VAR = 'foreman_id,foreman.id'
|
||||
# SATELLITE6_GROUP_PREFIX and SATELLITE6_GROUP_PATTERNS defined in source vars
|
||||
|
||||
# ----------------
|
||||
|
||||
@ -105,8 +105,11 @@ AWX_CALLBACK_PROFILE = True
|
||||
AWX_DISABLE_TASK_MANAGERS = False
|
||||
# ======================!!!!!!! FOR DEVELOPMENT ONLY !!!!!!!=================================
|
||||
|
||||
if 'sqlite3' not in DATABASES['default']['ENGINE']: # noqa
|
||||
DATABASES['default'].setdefault('OPTIONS', dict()).setdefault('application_name', f'{CLUSTER_HOST_ID}-{os.getpid()}-{" ".join(sys.argv)}'[:63]) # noqa
|
||||
from .application_name import set_application_name
|
||||
|
||||
set_application_name(DATABASES, CLUSTER_HOST_ID)
|
||||
|
||||
del set_application_name
|
||||
|
||||
# If any local_*.py files are present in awx/settings/, use them to override
|
||||
# default settings for development. If not present, we can still run using
|
||||
|
||||
@ -100,6 +100,8 @@ except IOError:
|
||||
|
||||
# The below runs AFTER all of the custom settings are imported.
|
||||
|
||||
DATABASES.setdefault('default', dict()).setdefault('OPTIONS', dict()).setdefault(
|
||||
'application_name', f'{CLUSTER_HOST_ID}-{os.getpid()}-{" ".join(sys.argv)}'[:63] # NOQA
|
||||
) # noqa
|
||||
from .application_name import set_application_name
|
||||
|
||||
set_application_name(DATABASES, CLUSTER_HOST_ID) # NOQA
|
||||
|
||||
del set_application_name
|
||||
|
||||
@ -1603,6 +1603,50 @@ register(
|
||||
],
|
||||
)
|
||||
|
||||
register(
|
||||
'LOCAL_PASSWORD_MIN_LENGTH',
|
||||
field_class=fields.IntegerField,
|
||||
min_value=0,
|
||||
default=0,
|
||||
label=_('Minimum number of characters in local password'),
|
||||
help_text=_('Minimum number of characters required in a local password. 0 means no minimum'),
|
||||
category=_('Authentication'),
|
||||
category_slug='authentication',
|
||||
)
|
||||
|
||||
register(
|
||||
'LOCAL_PASSWORD_MIN_DIGITS',
|
||||
field_class=fields.IntegerField,
|
||||
min_value=0,
|
||||
default=0,
|
||||
label=_('Minimum number of digit characters in local password'),
|
||||
help_text=_('Minimum number of digit characters required in a local password. 0 means no minimum'),
|
||||
category=_('Authentication'),
|
||||
category_slug='authentication',
|
||||
)
|
||||
|
||||
register(
|
||||
'LOCAL_PASSWORD_MIN_UPPER',
|
||||
field_class=fields.IntegerField,
|
||||
min_value=0,
|
||||
default=0,
|
||||
label=_('Minimum number of uppercase characters in local password'),
|
||||
help_text=_('Minimum number of uppercase characters required in a local password. 0 means no minimum'),
|
||||
category=_('Authentication'),
|
||||
category_slug='authentication',
|
||||
)
|
||||
|
||||
register(
|
||||
'LOCAL_PASSWORD_MIN_SPECIAL',
|
||||
field_class=fields.IntegerField,
|
||||
min_value=0,
|
||||
default=0,
|
||||
label=_('Minimum number of special characters in local password'),
|
||||
help_text=_('Minimum number of special characters required in a local password. 0 means no minimum'),
|
||||
category=_('Authentication'),
|
||||
category_slug='authentication',
|
||||
)
|
||||
|
||||
|
||||
def tacacs_validate(serializer, attrs):
|
||||
if not serializer.instance or not hasattr(serializer.instance, 'TACACSPLUS_HOST') or not hasattr(serializer.instance, 'TACACSPLUS_SECRET'):
|
||||
|
||||
@ -28,7 +28,7 @@ import { getLanguageWithoutRegionCode } from 'util/language';
|
||||
import Metrics from 'screens/Metrics';
|
||||
import SubscriptionEdit from 'screens/Setting/Subscription/SubscriptionEdit';
|
||||
import useTitle from 'hooks/useTitle';
|
||||
import { dynamicActivate } from './i18nLoader';
|
||||
import { dynamicActivate, locales } from './i18nLoader';
|
||||
import getRouteConfig from './routeConfig';
|
||||
import { SESSION_REDIRECT_URL } from './constants';
|
||||
|
||||
@ -142,9 +142,15 @@ function App() {
|
||||
const searchParams = Object.fromEntries(new URLSearchParams(search));
|
||||
const pseudolocalization =
|
||||
searchParams.pseudolocalization === 'true' || false;
|
||||
const language =
|
||||
let language =
|
||||
searchParams.lang || getLanguageWithoutRegionCode(navigator) || 'en';
|
||||
|
||||
if (!Object.keys(locales).includes(language)) {
|
||||
// If there isn't a string catalog available for the browser's
|
||||
// preferred language, default to one that has strings.
|
||||
language = 'en';
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
dynamicActivate(language, pseudolocalization);
|
||||
}, [language, pseudolocalization]);
|
||||
|
||||
@ -54,7 +54,11 @@ function MiscAuthenticationEdit() {
|
||||
'SOCIAL_AUTH_ORGANIZATION_MAP',
|
||||
'SOCIAL_AUTH_TEAM_MAP',
|
||||
'SOCIAL_AUTH_USER_FIELDS',
|
||||
'SOCIAL_AUTH_USERNAME_IS_FULL_EMAIL'
|
||||
'SOCIAL_AUTH_USERNAME_IS_FULL_EMAIL',
|
||||
'LOCAL_PASSWORD_MIN_LENGTH',
|
||||
'LOCAL_PASSWORD_MIN_DIGITS',
|
||||
'LOCAL_PASSWORD_MIN_UPPER',
|
||||
'LOCAL_PASSWORD_MIN_SPECIAL'
|
||||
);
|
||||
|
||||
const authenticationData = {
|
||||
@ -247,6 +251,30 @@ function MiscAuthenticationEdit() {
|
||||
name="SOCIAL_AUTH_USERNAME_IS_FULL_EMAIL"
|
||||
config={authentication.SOCIAL_AUTH_USERNAME_IS_FULL_EMAIL}
|
||||
/>
|
||||
<InputField
|
||||
name="LOCAL_PASSWORD_MIN_LENGTH"
|
||||
config={authentication.LOCAL_PASSWORD_MIN_LENGTH}
|
||||
type="number"
|
||||
isRequired
|
||||
/>
|
||||
<InputField
|
||||
name="LOCAL_PASSWORD_MIN_DIGITS"
|
||||
config={authentication.LOCAL_PASSWORD_MIN_DIGITS}
|
||||
type="number"
|
||||
isRequired
|
||||
/>
|
||||
<InputField
|
||||
name="LOCAL_PASSWORD_MIN_UPPER"
|
||||
config={authentication.LOCAL_PASSWORD_MIN_UPPER}
|
||||
type="number"
|
||||
isRequired
|
||||
/>
|
||||
<InputField
|
||||
name="LOCAL_PASSWORD_MIN_SPECIAL"
|
||||
config={authentication.LOCAL_PASSWORD_MIN_SPECIAL}
|
||||
type="number"
|
||||
isRequired
|
||||
/>
|
||||
{submitError && <FormSubmitError error={submitError} />}
|
||||
{revertError && <FormSubmitError error={revertError} />}
|
||||
</FormColumnLayout>
|
||||
|
||||
@ -33,6 +33,10 @@ const authenticationData = {
|
||||
SOCIAL_AUTH_TEAM_MAP: null,
|
||||
SOCIAL_AUTH_USER_FIELDS: null,
|
||||
SOCIAL_AUTH_USERNAME_IS_FULL_EMAIL: false,
|
||||
LOCAL_PASSWORD_MIN_LENGTH: 0,
|
||||
LOCAL_PASSWORD_MIN_DIGITS: 0,
|
||||
LOCAL_PASSWORD_MIN_UPPER: 0,
|
||||
LOCAL_PASSWORD_MIN_SPECIAL: 0,
|
||||
};
|
||||
|
||||
describe('<MiscAuthenticationEdit />', () => {
|
||||
|
||||
@ -204,7 +204,7 @@
|
||||
"type": "list",
|
||||
"required": false,
|
||||
"label": "Paths to expose to isolated jobs",
|
||||
"help_text": "List of paths that would otherwise be hidden to expose to isolated jobs. Enter one path per line.",
|
||||
"help_text": "List of paths that would otherwise be hidden to expose to isolated jobs. Enter one path per line. Volumes will be mounted from the execution node to the container. The supported format is HOST-DIR[:CONTAINER-DIR[:OPTIONS]]. ",
|
||||
"category": "Jobs",
|
||||
"category_slug": "jobs",
|
||||
"default": [],
|
||||
@ -231,26 +231,36 @@
|
||||
"read_only": false
|
||||
}
|
||||
},
|
||||
"AWX_RUNNER_KEEPALIVE_SECONDS": {
|
||||
"type": "integer",
|
||||
"required": true,
|
||||
"label": "K8S Ansible Runner Keep-Alive Message Interval",
|
||||
"help_text": "Only applies to jobs running in a Container Group. If not 0, send a message every so-many seconds to keep connection open.",
|
||||
"category": "Jobs",
|
||||
"category_slug": "jobs",
|
||||
"placeholder": 240,
|
||||
"default": 0
|
||||
},
|
||||
"GALAXY_TASK_ENV": {
|
||||
"type": "nested object",
|
||||
"required": true,
|
||||
"required": true,
|
||||
"label": "Environment Variables for Galaxy Commands",
|
||||
"help_text": "Additional environment variables set for invocations of ansible-galaxy within project updates. Useful if you must use a proxy server for ansible-galaxy but not git.",
|
||||
"category": "Jobs",
|
||||
"category_slug": "jobs",
|
||||
"placeholder": {
|
||||
"HTTP_PROXY": "myproxy.local:8080"
|
||||
},
|
||||
"default": {
|
||||
"ANSIBLE_FORCE_COLOR": "false",
|
||||
"GIT_SSH_COMMAND": "ssh -o StrictHostKeyChecking=no"
|
||||
"help_text": "Additional environment variables set for invocations of ansible-galaxy within project updates. Useful if you must use a proxy server for ansible-galaxy but not git.",
|
||||
"category": "Jobs",
|
||||
"category_slug": "jobs",
|
||||
"placeholder": {
|
||||
"HTTP_PROXY": "myproxy.local:8080"
|
||||
},
|
||||
"child": {
|
||||
"type": "string",
|
||||
"required": true,
|
||||
"read_only": false
|
||||
"default": {
|
||||
"ANSIBLE_FORCE_COLOR": "false",
|
||||
"GIT_SSH_COMMAND": "ssh -o StrictHostKeyChecking=no"
|
||||
},
|
||||
"child": {
|
||||
"type": "string",
|
||||
"required": true,
|
||||
"read_only": false
|
||||
}
|
||||
},
|
||||
},
|
||||
"INSIGHTS_TRACKING_STATE": {
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
@ -334,6 +344,16 @@
|
||||
"category_slug": "jobs",
|
||||
"default": 1024
|
||||
},
|
||||
"MAX_WEBSOCKET_EVENT_RATE": {
|
||||
"type": "integer",
|
||||
"required": false,
|
||||
"label": "Job Event Maximum Websocket Messages Per Second",
|
||||
"help_text": "Maximum number of messages to update the UI live job output with per second. Value of 0 means no limit.",
|
||||
"min_value": 0,
|
||||
"category": "Jobs",
|
||||
"category_slug": "jobs",
|
||||
"default": 30
|
||||
},
|
||||
"SCHEDULE_MAX_JOBS": {
|
||||
"type": "integer",
|
||||
"required": true,
|
||||
@ -344,16 +364,6 @@
|
||||
"category_slug": "jobs",
|
||||
"default": 10
|
||||
},
|
||||
"AWX_RUNNER_KEEPALIVE_SECONDS": {
|
||||
"type": "integer",
|
||||
"required": true,
|
||||
"label": "K8S Ansible Runner Keep-Alive Message Interval",
|
||||
"help_text": "Only applies to K8S deployments and container_group jobs. If not 0, send a message every so-many seconds to keep connection open.",
|
||||
"category": "Jobs",
|
||||
"category_slug": "jobs",
|
||||
"placeholder": 240,
|
||||
"default": 0
|
||||
},
|
||||
"AWX_ANSIBLE_CALLBACK_PLUGINS": {
|
||||
"type": "list",
|
||||
"required": false,
|
||||
@ -383,7 +393,7 @@
|
||||
"type": "integer",
|
||||
"required": false,
|
||||
"label": "Default Job Idle Timeout",
|
||||
"help_text": "If no output is detected from ansible in this number of seconds the execution will be terminated. Use value of 0 to used default idle_timeout is 600s.",
|
||||
"help_text": "If no output is detected from ansible in this number of seconds the execution will be terminated. Use value of 0 to indicate that no idle timeout should be imposed.",
|
||||
"min_value": 0,
|
||||
"category": "Jobs",
|
||||
"category_slug": "jobs",
|
||||
@ -489,10 +499,16 @@
|
||||
"type": "list",
|
||||
"required": false,
|
||||
"label": "Loggers Sending Data to Log Aggregator Form",
|
||||
"help_text": "List of loggers that will send HTTP logs to the collector, these can include any or all of: \nawx - service logs\nactivity_stream - activity stream records\njob_events - callback data from Ansible job events\nsystem_tracking - facts gathered from scan jobs.",
|
||||
"help_text": "List of loggers that will send HTTP logs to the collector, these can include any or all of: \nawx - service logs\nactivity_stream - activity stream records\njob_events - callback data from Ansible job events\nsystem_tracking - facts gathered from scan jobs\nbroadcast_websocket - errors pertaining to websockets broadcast metrics\n",
|
||||
"category": "Logging",
|
||||
"category_slug": "logging",
|
||||
"default": ["awx", "activity_stream", "job_events", "system_tracking"],
|
||||
"default": [
|
||||
"awx",
|
||||
"activity_stream",
|
||||
"job_events",
|
||||
"system_tracking",
|
||||
"broadcast_websocket"
|
||||
],
|
||||
"child": {
|
||||
"type": "string",
|
||||
"required": true,
|
||||
@ -639,15 +655,51 @@
|
||||
"unit": "seconds",
|
||||
"default": 14400
|
||||
},
|
||||
"BULK_JOB_MAX_LAUNCH": {
|
||||
"type": "integer",
|
||||
"required": false,
|
||||
"label": "Max jobs to allow bulk jobs to launch",
|
||||
"help_text": "Max jobs to allow bulk jobs to launch",
|
||||
"category": "Bulk Actions",
|
||||
"category_slug": "bulk",
|
||||
"default": 100
|
||||
},
|
||||
"BULK_HOST_MAX_CREATE": {
|
||||
"type": "integer",
|
||||
"required": false,
|
||||
"label": "Max number of hosts to allow to be created in a single bulk action",
|
||||
"help_text": "Max number of hosts to allow to be created in a single bulk action",
|
||||
"category": "Bulk Actions",
|
||||
"category_slug": "bulk",
|
||||
"default": 100
|
||||
},
|
||||
"UI_NEXT": {
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"label": "Enable Preview of New User Interface",
|
||||
"help_text": "'Enable preview of new user interface.",
|
||||
"help_text": "Enable preview of new user interface.",
|
||||
"category": "System",
|
||||
"category_slug": "system",
|
||||
"default": true
|
||||
},
|
||||
"SUBSCRIPTION_USAGE_MODEL": {
|
||||
"type": "choice",
|
||||
"required": false,
|
||||
"label": "Defines subscription usage model and shows Host Metrics",
|
||||
"category": "System",
|
||||
"category_slug": "system",
|
||||
"default": "",
|
||||
"choices": [
|
||||
[
|
||||
"",
|
||||
"Default model for AWX - no subscription. Deletion of host_metrics will not be considered for purposes of managed host counting"
|
||||
],
|
||||
[
|
||||
"unique_managed_hosts",
|
||||
"Usage based on unique managed nodes in a large historical time frame and delete functionality for no longer used managed nodes"
|
||||
]
|
||||
]
|
||||
},
|
||||
"SESSION_COOKIE_AGE": {
|
||||
"type": "integer",
|
||||
"required": true,
|
||||
@ -740,6 +792,15 @@
|
||||
["detailed", "Detailed"]
|
||||
]
|
||||
},
|
||||
"ALLOW_METRICS_FOR_ANONYMOUS_USERS": {
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"label": "Allow anonymous users to poll metrics",
|
||||
"help_text": "If true, anonymous users are allowed to poll metrics.",
|
||||
"category": "Authentication",
|
||||
"category_slug": "authentication",
|
||||
"default": false
|
||||
},
|
||||
"CUSTOM_LOGIN_INFO": {
|
||||
"type": "string",
|
||||
"required": false,
|
||||
@ -782,7 +843,7 @@
|
||||
"type": "nested object",
|
||||
"required": false,
|
||||
"label": "Social Auth Organization Map",
|
||||
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which organizations based on their\nusername and email address. Configuration details are available in the \ndocumentation.",
|
||||
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which organizations based on their\nusername and email address. Configuration details are available in the\ndocumentation.",
|
||||
"category": "Authentication",
|
||||
"category_slug": "authentication",
|
||||
"placeholder": {
|
||||
@ -868,39 +929,6 @@
|
||||
"category_slug": "authentication",
|
||||
"default": false
|
||||
},
|
||||
"SOCIAL_AUTH_OIDC_KEY": {
|
||||
"type": "string",
|
||||
"label": "OIDC Key",
|
||||
"help_text": "The OIDC key (Client ID) from your IDP.",
|
||||
"category": "Generic OIDC",
|
||||
"category_slug": "oidc",
|
||||
"default": ""
|
||||
},
|
||||
"SOCIAL_AUTH_OIDC_SECRET": {
|
||||
"type": "string",
|
||||
"label": "OIDC Secret",
|
||||
"help_text": "The OIDC secret (Client Secret) from your IDP.",
|
||||
"category": "Generic OIDC",
|
||||
"category_slug": "oidc",
|
||||
"default": ""
|
||||
},
|
||||
"SOCIAL_AUTH_OIDC_OIDC_ENDPOINT": {
|
||||
"type": "string",
|
||||
"label": "OIDC Provider URL",
|
||||
"help_text": "The URL for your OIDC provider, e.g.: http(s)://hostname/.",
|
||||
"category": "Generic OIDC",
|
||||
"category_slug": "oidc",
|
||||
"default": ""
|
||||
},
|
||||
"SOCIAL_AUTH_OIDC_VERIFY_SSL": {
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"label": "Verify OIDC Provider Certificate",
|
||||
"help_text": "Verify the OIDC provider ssl certificate.",
|
||||
"category": "Generic OIDC",
|
||||
"category_slug": "oidc",
|
||||
"default": true
|
||||
},
|
||||
"AUTH_LDAP_SERVER_URI": {
|
||||
"type": "string",
|
||||
"required": false,
|
||||
@ -2726,7 +2754,7 @@
|
||||
"type": "nested object",
|
||||
"required": false,
|
||||
"label": "Google OAuth2 Organization Map",
|
||||
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which organizations based on their\nusername and email address. Configuration details are available in the \ndocumentation.",
|
||||
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which organizations based on their\nusername and email address. Configuration details are available in the\ndocumentation.",
|
||||
"category": "Google OAuth2",
|
||||
"category_slug": "google-oauth2",
|
||||
"placeholder": {
|
||||
@ -2810,7 +2838,7 @@
|
||||
"type": "nested object",
|
||||
"required": false,
|
||||
"label": "GitHub OAuth2 Organization Map",
|
||||
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which organizations based on their\nusername and email address. Configuration details are available in the \ndocumentation.",
|
||||
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which organizations based on their\nusername and email address. Configuration details are available in the\ndocumentation.",
|
||||
"category": "GitHub OAuth2",
|
||||
"category_slug": "github",
|
||||
"placeholder": {
|
||||
@ -2903,7 +2931,7 @@
|
||||
"type": "nested object",
|
||||
"required": false,
|
||||
"label": "GitHub Organization OAuth2 Organization Map",
|
||||
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which organizations based on their\nusername and email address. Configuration details are available in the \ndocumentation.",
|
||||
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which organizations based on their\nusername and email address. Configuration details are available in the\ndocumentation.",
|
||||
"category": "GitHub Organization OAuth2",
|
||||
"category_slug": "github-org",
|
||||
"placeholder": {
|
||||
@ -2996,7 +3024,7 @@
|
||||
"type": "nested object",
|
||||
"required": false,
|
||||
"label": "GitHub Team OAuth2 Organization Map",
|
||||
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which organizations based on their\nusername and email address. Configuration details are available in the \ndocumentation.",
|
||||
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which organizations based on their\nusername and email address. Configuration details are available in the\ndocumentation.",
|
||||
"category": "GitHub Team OAuth2",
|
||||
"category_slug": "github-team",
|
||||
"placeholder": {
|
||||
@ -3098,7 +3126,7 @@
|
||||
"type": "nested object",
|
||||
"required": false,
|
||||
"label": "GitHub Enterprise OAuth2 Organization Map",
|
||||
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which organizations based on their\nusername and email address. Configuration details are available in the \ndocumentation.",
|
||||
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which organizations based on their\nusername and email address. Configuration details are available in the\ndocumentation.",
|
||||
"category": "GitHub Enterprise OAuth2",
|
||||
"category_slug": "github-enterprise",
|
||||
"placeholder": {
|
||||
@ -3209,7 +3237,7 @@
|
||||
"type": "nested object",
|
||||
"required": false,
|
||||
"label": "GitHub Enterprise Organization OAuth2 Organization Map",
|
||||
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which organizations based on their\nusername and email address. Configuration details are available in the \ndocumentation.",
|
||||
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which organizations based on their\nusername and email address. Configuration details are available in the\ndocumentation.",
|
||||
"category": "GitHub Enterprise Organization OAuth2",
|
||||
"category_slug": "github-enterprise-org",
|
||||
"placeholder": {
|
||||
@ -3320,7 +3348,7 @@
|
||||
"type": "nested object",
|
||||
"required": false,
|
||||
"label": "GitHub Enterprise Team OAuth2 Organization Map",
|
||||
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which organizations based on their\nusername and email address. Configuration details are available in the \ndocumentation.",
|
||||
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which organizations based on their\nusername and email address. Configuration details are available in the\ndocumentation.",
|
||||
"category": "GitHub Enterprise Team OAuth2",
|
||||
"category_slug": "github-enterprise-team",
|
||||
"placeholder": {
|
||||
@ -3404,7 +3432,7 @@
|
||||
"type": "nested object",
|
||||
"required": false,
|
||||
"label": "Azure AD OAuth2 Organization Map",
|
||||
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which organizations based on their\nusername and email address. Configuration details are available in the \ndocumentation.",
|
||||
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which organizations based on their\nusername and email address. Configuration details are available in the\ndocumentation.",
|
||||
"category": "Azure AD OAuth2",
|
||||
"category_slug": "azuread-oauth2",
|
||||
"placeholder": {
|
||||
@ -3466,6 +3494,42 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"SOCIAL_AUTH_OIDC_KEY": {
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"label": "OIDC Key",
|
||||
"help_text": "The OIDC key (Client ID) from your IDP.",
|
||||
"category": "Generic OIDC",
|
||||
"category_slug": "oidc",
|
||||
"default": null
|
||||
},
|
||||
"SOCIAL_AUTH_OIDC_SECRET": {
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"label": "OIDC Secret",
|
||||
"help_text": "The OIDC secret (Client Secret) from your IDP.",
|
||||
"category": "Generic OIDC",
|
||||
"category_slug": "oidc",
|
||||
"default": ""
|
||||
},
|
||||
"SOCIAL_AUTH_OIDC_OIDC_ENDPOINT": {
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"label": "OIDC Provider URL",
|
||||
"help_text": "The URL for your OIDC provider including the path up to /.well-known/openid-configuration",
|
||||
"category": "Generic OIDC",
|
||||
"category_slug": "oidc",
|
||||
"default": ""
|
||||
},
|
||||
"SOCIAL_AUTH_OIDC_VERIFY_SSL": {
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"label": "Verify OIDC Provider Certificate",
|
||||
"help_text": "Verify the OIDC provider ssl certificate.",
|
||||
"category": "Generic OIDC",
|
||||
"category_slug": "oidc",
|
||||
"default": true
|
||||
},
|
||||
"SAML_AUTO_CREATE_OBJECTS": {
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
@ -3678,7 +3742,7 @@
|
||||
"type": "nested object",
|
||||
"required": false,
|
||||
"label": "SAML Organization Map",
|
||||
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which organizations based on their\nusername and email address. Configuration details are available in the \ndocumentation.",
|
||||
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which organizations based on their\nusername and email address. Configuration details are available in the\ndocumentation.",
|
||||
"category": "SAML",
|
||||
"category_slug": "saml",
|
||||
"placeholder": {
|
||||
@ -3813,20 +3877,62 @@
|
||||
"help_text": "Used to map super users and system auditors from SAML.",
|
||||
"category": "SAML",
|
||||
"category_slug": "saml",
|
||||
"placeholder": {
|
||||
"is_superuser_attr": "saml_attr",
|
||||
"is_superuser_value": "value",
|
||||
"is_superuser_role": "saml_role",
|
||||
"is_system_auditor_attr": "saml_attr",
|
||||
"is_system_auditor_value": "value",
|
||||
"is_system_auditor_role": "saml_role"
|
||||
},
|
||||
"placeholder": [
|
||||
["is_superuser_attr", "saml_attr"],
|
||||
["is_superuser_value", ["value"]],
|
||||
["is_superuser_role", ["saml_role"]],
|
||||
["remove_superusers", true],
|
||||
["is_system_auditor_attr", "saml_attr"],
|
||||
["is_system_auditor_value", ["value"]],
|
||||
["is_system_auditor_role", ["saml_role"]],
|
||||
["remove_system_auditors", true]
|
||||
],
|
||||
"default": {},
|
||||
"child": {
|
||||
"type": "field",
|
||||
"required": true,
|
||||
"read_only": false
|
||||
}
|
||||
},
|
||||
"LOCAL_PASSWORD_MIN_LENGTH": {
|
||||
"type": "integer",
|
||||
"required": false,
|
||||
"label": "Minimum number of characters in local password",
|
||||
"help_text": "Minimum number of characters required in a local password. 0 means no minimum",
|
||||
"min_value": 0,
|
||||
"category": "Authentication",
|
||||
"category_slug": "authentication",
|
||||
"default": 0
|
||||
},
|
||||
"LOCAL_PASSWORD_MIN_DIGITS": {
|
||||
"type": "integer",
|
||||
"required": false,
|
||||
"label": "Minimum number of digit characters in local password",
|
||||
"help_text": "Minimum number of digit characters required in a local password. 0 means no minimum",
|
||||
"min_value": 0,
|
||||
"category": "Authentication",
|
||||
"category_slug": "authentication",
|
||||
"default": 0
|
||||
},
|
||||
"LOCAL_PASSWORD_MIN_UPPER": {
|
||||
"type": "integer",
|
||||
"required": false,
|
||||
"label": "Minimum number of uppercase characters in local password",
|
||||
"help_text": "Minimum number of uppercase characters required in a local password. 0 means no minimum",
|
||||
"min_value": 0,
|
||||
"category": "Authentication",
|
||||
"category_slug": "authentication",
|
||||
"default": 0
|
||||
},
|
||||
"LOCAL_PASSWORD_MIN_SPECIAL": {
|
||||
"type": "integer",
|
||||
"required": false,
|
||||
"label": "Minimum number of special characters in local password",
|
||||
"help_text": "Minimum number of special characters required in a local password. 0 means no minimum",
|
||||
"min_value": 0,
|
||||
"category": "Authentication",
|
||||
"category_slug": "authentication",
|
||||
"default": 0
|
||||
}
|
||||
},
|
||||
"GET": {
|
||||
@ -3873,7 +3979,7 @@
|
||||
"REMOTE_HOST_HEADERS": {
|
||||
"type": "list",
|
||||
"label": "Remote Host Headers",
|
||||
"help_text": "HTTP headers and meta keys to search to determine remote host name or IP. Add additional items to this list, such as \"HTTP_X_FORWARDED_FOR\", if behind a reverse proxy. See the \"Proxy Support\" section of the Adminstrator guide for more details.",
|
||||
"help_text": "HTTP headers and meta keys to search to determine remote host name or IP. Add additional items to this list, such as \"HTTP_X_FORWARDED_FOR\", if behind a reverse proxy. See the \"Proxy Support\" section of the AAP Installation guide for more details.",
|
||||
"category": "System",
|
||||
"category_slug": "system",
|
||||
"defined_in_file": false,
|
||||
@ -3950,6 +4056,20 @@
|
||||
"category_slug": "system",
|
||||
"defined_in_file": false
|
||||
},
|
||||
"DEFAULT_CONTROL_PLANE_QUEUE_NAME": {
|
||||
"type": "string",
|
||||
"label": "The instance group where control plane tasks run",
|
||||
"category": "System",
|
||||
"category_slug": "system",
|
||||
"defined_in_file": false
|
||||
},
|
||||
"DEFAULT_EXECUTION_QUEUE_NAME": {
|
||||
"type": "string",
|
||||
"label": "The instance group where user jobs run (currently only on non-VM installs)",
|
||||
"category": "System",
|
||||
"category_slug": "system",
|
||||
"defined_in_file": false
|
||||
},
|
||||
"DEFAULT_EXECUTION_ENVIRONMENT": {
|
||||
"type": "field",
|
||||
"label": "Global default execution environment",
|
||||
@ -4004,7 +4124,7 @@
|
||||
"AWX_ISOLATION_SHOW_PATHS": {
|
||||
"type": "list",
|
||||
"label": "Paths to expose to isolated jobs",
|
||||
"help_text": "List of paths that would otherwise be hidden to expose to isolated jobs. Enter one path per line.",
|
||||
"help_text": "List of paths that would otherwise be hidden to expose to isolated jobs. Enter one path per line. Volumes will be mounted from the execution node to the container. The supported format is HOST-DIR[:CONTAINER-DIR[:OPTIONS]]. ",
|
||||
"category": "Jobs",
|
||||
"category_slug": "jobs",
|
||||
"defined_in_file": false,
|
||||
@ -4023,26 +4143,25 @@
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"AWX_RUNNER_KEEPALIVE_SECONDS": {
|
||||
"type": "integer",
|
||||
"label": "K8S Ansible Runner Keep-Alive Message Interval",
|
||||
"help_text": "Only applies to jobs running in a Container Group. If not 0, send a message every so-many seconds to keep connection open.",
|
||||
"category": "Jobs",
|
||||
"category_slug": "jobs",
|
||||
"defined_in_file": false
|
||||
},
|
||||
"GALAXY_TASK_ENV": {
|
||||
"type": "nested object",
|
||||
"required": true,
|
||||
"label": "Environment Variables for Galaxy Commands",
|
||||
"help_text": "Additional environment variables set for invocations of ansible-galaxy within project updates. Useful if you must use a proxy server for ansible-galaxy but not git.",
|
||||
"category": "Jobs",
|
||||
"category_slug": "jobs",
|
||||
"placeholder": {
|
||||
"HTTP_PROXY": "myproxy.local:8080"
|
||||
},
|
||||
"default": {
|
||||
"ANSIBLE_FORCE_COLOR": "false",
|
||||
"GIT_SSH_COMMAND": "ssh -o StrictHostKeyChecking=no"
|
||||
},
|
||||
"child": {
|
||||
"type": "string",
|
||||
"required": true,
|
||||
"read_only": false
|
||||
"help_text": "Additional environment variables set for invocations of ansible-galaxy within project updates. Useful if you must use a proxy server for ansible-galaxy but not git.",
|
||||
"category": "Jobs",
|
||||
"category_slug": "jobs",
|
||||
"defined_in_file": false,
|
||||
"child": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
},
|
||||
"INSIGHTS_TRACKING_STATE": {
|
||||
"type": "boolean",
|
||||
"label": "Gather data for Automation Analytics",
|
||||
@ -4117,6 +4236,15 @@
|
||||
"category_slug": "jobs",
|
||||
"defined_in_file": false
|
||||
},
|
||||
"MAX_WEBSOCKET_EVENT_RATE": {
|
||||
"type": "integer",
|
||||
"label": "Job Event Maximum Websocket Messages Per Second",
|
||||
"help_text": "Maximum number of messages to update the UI live job output with per second. Value of 0 means no limit.",
|
||||
"min_value": 0,
|
||||
"category": "Jobs",
|
||||
"category_slug": "jobs",
|
||||
"defined_in_file": false
|
||||
},
|
||||
"SCHEDULE_MAX_JOBS": {
|
||||
"type": "integer",
|
||||
"label": "Maximum Scheduled Jobs",
|
||||
@ -4126,15 +4254,6 @@
|
||||
"category_slug": "jobs",
|
||||
"defined_in_file": false
|
||||
},
|
||||
"AWX_RUNNER_KEEPALIVE_SECONDS": {
|
||||
"type": "integer",
|
||||
"label": "K8S Ansible Runner Keep-Alive Message Interval",
|
||||
"help_text": "Only applies to K8S deployments and container_group jobs. If not 0, send a message every so-many seconds to keep connection open.",
|
||||
"category": "Jobs",
|
||||
"category_slug": "jobs",
|
||||
"placeholder": 240,
|
||||
"default": 0
|
||||
},
|
||||
"AWX_ANSIBLE_CALLBACK_PLUGINS": {
|
||||
"type": "list",
|
||||
"label": "Ansible Callback Plugins",
|
||||
@ -4159,7 +4278,7 @@
|
||||
"DEFAULT_JOB_IDLE_TIMEOUT": {
|
||||
"type": "integer",
|
||||
"label": "Default Job Idle Timeout",
|
||||
"help_text": "If no output is detected from ansible in this number of seconds the execution will be terminated. Use value of 0 to used default idle_timeout is 600s.",
|
||||
"help_text": "If no output is detected from ansible in this number of seconds the execution will be terminated. Use value of 0 to indicate that no idle timeout should be imposed.",
|
||||
"min_value": 0,
|
||||
"category": "Jobs",
|
||||
"category_slug": "jobs",
|
||||
@ -4255,7 +4374,7 @@
|
||||
"LOG_AGGREGATOR_LOGGERS": {
|
||||
"type": "list",
|
||||
"label": "Loggers Sending Data to Log Aggregator Form",
|
||||
"help_text": "List of loggers that will send HTTP logs to the collector, these can include any or all of: \nawx - service logs\nactivity_stream - activity stream records\njob_events - callback data from Ansible job events\nsystem_tracking - facts gathered from scan jobs.",
|
||||
"help_text": "List of loggers that will send HTTP logs to the collector, these can include any or all of: \nawx - service logs\nactivity_stream - activity stream records\njob_events - callback data from Ansible job events\nsystem_tracking - facts gathered from scan jobs\nbroadcast_websocket - errors pertaining to websockets broadcast metrics\n",
|
||||
"category": "Logging",
|
||||
"category_slug": "logging",
|
||||
"defined_in_file": false,
|
||||
@ -4359,12 +4478,11 @@
|
||||
},
|
||||
"API_400_ERROR_LOG_FORMAT": {
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"label": "Log Format For API 4XX Errors",
|
||||
"help_text": "The format of logged messages when an API 4XX error occurs, the following variables will be substituted: \nstatus_code - The HTTP status code of the error\nuser_name - The user name attempting to use the API\nurl_path - The URL path to the API endpoint called\nremote_addr - The remote address seen for the user\nerror - The error set by the api endpoint\nVariables need to be in the format {<variable name>}.",
|
||||
"category": "Logging",
|
||||
"category_slug": "logging",
|
||||
"default": "status {status_code} received by user {user_name} attempting to access {url_path} from {remote_addr}"
|
||||
"defined_in_file": false
|
||||
},
|
||||
"AUTOMATION_ANALYTICS_LAST_GATHER": {
|
||||
"type": "datetime",
|
||||
@ -4390,6 +4508,30 @@
|
||||
"defined_in_file": false,
|
||||
"unit": "seconds"
|
||||
},
|
||||
"IS_K8S": {
|
||||
"type": "boolean",
|
||||
"label": "Is k8s",
|
||||
"help_text": "Indicates whether the instance is part of a kubernetes-based deployment.",
|
||||
"category": "System",
|
||||
"category_slug": "system",
|
||||
"defined_in_file": false
|
||||
},
|
||||
"BULK_JOB_MAX_LAUNCH": {
|
||||
"type": "integer",
|
||||
"label": "Max jobs to allow bulk jobs to launch",
|
||||
"help_text": "Max jobs to allow bulk jobs to launch",
|
||||
"category": "Bulk Actions",
|
||||
"category_slug": "bulk",
|
||||
"defined_in_file": false
|
||||
},
|
||||
"BULK_HOST_MAX_CREATE": {
|
||||
"type": "integer",
|
||||
"label": "Max number of hosts to allow to be created in a single bulk action",
|
||||
"help_text": "Max number of hosts to allow to be created in a single bulk action",
|
||||
"category": "Bulk Actions",
|
||||
"category_slug": "bulk",
|
||||
"defined_in_file": false
|
||||
},
|
||||
"UI_NEXT": {
|
||||
"type": "boolean",
|
||||
"label": "Enable Preview of New User Interface",
|
||||
@ -4398,6 +4540,23 @@
|
||||
"category_slug": "system",
|
||||
"defined_in_file": false
|
||||
},
|
||||
"SUBSCRIPTION_USAGE_MODEL": {
|
||||
"type": "choice",
|
||||
"label": "Defines subscription usage model and shows Host Metrics",
|
||||
"category": "System",
|
||||
"category_slug": "system",
|
||||
"defined_in_file": false,
|
||||
"choices": [
|
||||
[
|
||||
"",
|
||||
"Default model for AWX - no subscription. Deletion of host_metrics will not be considered for purposes of managed host counting"
|
||||
],
|
||||
[
|
||||
"unique_managed_hosts",
|
||||
"Usage based on unique managed nodes in a large historical time frame and delete functionality for no longer used managed nodes"
|
||||
]
|
||||
]
|
||||
},
|
||||
"SESSION_COOKIE_AGE": {
|
||||
"type": "integer",
|
||||
"label": "Idle Time Force Log Out",
|
||||
@ -4463,6 +4622,14 @@
|
||||
"category_slug": "authentication",
|
||||
"defined_in_file": false
|
||||
},
|
||||
"ALLOW_METRICS_FOR_ANONYMOUS_USERS": {
|
||||
"type": "boolean",
|
||||
"label": "Allow anonymous users to poll metrics",
|
||||
"help_text": "If true, anonymous users are allowed to poll metrics.",
|
||||
"category": "Authentication",
|
||||
"category_slug": "authentication",
|
||||
"defined_in_file": false
|
||||
},
|
||||
"PENDO_TRACKING_STATE": {
|
||||
"type": "choice",
|
||||
"label": "User Analytics Tracking State",
|
||||
@ -4523,7 +4690,7 @@
|
||||
"SOCIAL_AUTH_ORGANIZATION_MAP": {
|
||||
"type": "nested object",
|
||||
"label": "Social Auth Organization Map",
|
||||
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which organizations based on their\nusername and email address. Configuration details are available in the \ndocumentation.",
|
||||
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which organizations based on their\nusername and email address. Configuration details are available in the\ndocumentation.",
|
||||
"category": "Authentication",
|
||||
"category_slug": "authentication",
|
||||
"defined_in_file": false,
|
||||
@ -4569,39 +4736,7 @@
|
||||
"help_text": "Enabling this setting will tell social auth to use the full Email as username instead of the full name",
|
||||
"category": "Authentication",
|
||||
"category_slug": "authentication",
|
||||
"default": false
|
||||
},
|
||||
"SOCIAL_AUTH_OIDC_KEY": {
|
||||
"type": "string",
|
||||
"label": "OIDC Key",
|
||||
"help_text": "The OIDC key (Client ID) from your IDP.",
|
||||
"category": "Generic OIDC",
|
||||
"category_slug": "oidc",
|
||||
"default": ""
|
||||
},
|
||||
"SOCIAL_AUTH_OIDC_SECRET": {
|
||||
"type": "string",
|
||||
"label": "OIDC Secret",
|
||||
"help_text": "The OIDC secret (Client Secret) from your IDP.",
|
||||
"category": "Generic OIDC",
|
||||
"category_slug": "oidc",
|
||||
"default": ""
|
||||
},
|
||||
"SOCIAL_AUTH_OIDC_OIDC_ENDPOINT": {
|
||||
"type": "string",
|
||||
"label": "OIDC Provider URL",
|
||||
"help_text": "The URL for your OIDC provider, e.g.: http(s)://hostname/.",
|
||||
"category": "Generic OIDC",
|
||||
"category_slug": "oidc",
|
||||
"default": ""
|
||||
},
|
||||
"SOCIAL_AUTH_OIDC_VERIFY_SSL": {
|
||||
"type": "boolean",
|
||||
"label": "Verify OIDC Provider Certificate",
|
||||
"help_text": "Verify the OIDC provider ssl certificate.",
|
||||
"category": "Generic OIDC",
|
||||
"category_slug": "oidc",
|
||||
"default": true
|
||||
"defined_in_file": false
|
||||
},
|
||||
"AUTH_LDAP_SERVER_URI": {
|
||||
"type": "string",
|
||||
@ -5830,7 +5965,7 @@
|
||||
"SOCIAL_AUTH_GOOGLE_OAUTH2_ORGANIZATION_MAP": {
|
||||
"type": "nested object",
|
||||
"label": "Google OAuth2 Organization Map",
|
||||
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which organizations based on their\nusername and email address. Configuration details are available in the \ndocumentation.",
|
||||
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which organizations based on their\nusername and email address. Configuration details are available in the\ndocumentation.",
|
||||
"category": "Google OAuth2",
|
||||
"category_slug": "google-oauth2",
|
||||
"defined_in_file": false,
|
||||
@ -5886,7 +6021,7 @@
|
||||
"SOCIAL_AUTH_GITHUB_ORGANIZATION_MAP": {
|
||||
"type": "nested object",
|
||||
"label": "GitHub OAuth2 Organization Map",
|
||||
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which organizations based on their\nusername and email address. Configuration details are available in the \ndocumentation.",
|
||||
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which organizations based on their\nusername and email address. Configuration details are available in the\ndocumentation.",
|
||||
"category": "GitHub OAuth2",
|
||||
"category_slug": "github",
|
||||
"defined_in_file": false,
|
||||
@ -5950,7 +6085,7 @@
|
||||
"SOCIAL_AUTH_GITHUB_ORG_ORGANIZATION_MAP": {
|
||||
"type": "nested object",
|
||||
"label": "GitHub Organization OAuth2 Organization Map",
|
||||
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which organizations based on their\nusername and email address. Configuration details are available in the \ndocumentation.",
|
||||
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which organizations based on their\nusername and email address. Configuration details are available in the\ndocumentation.",
|
||||
"category": "GitHub Organization OAuth2",
|
||||
"category_slug": "github-org",
|
||||
"defined_in_file": false,
|
||||
@ -6014,7 +6149,7 @@
|
||||
"SOCIAL_AUTH_GITHUB_TEAM_ORGANIZATION_MAP": {
|
||||
"type": "nested object",
|
||||
"label": "GitHub Team OAuth2 Organization Map",
|
||||
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which organizations based on their\nusername and email address. Configuration details are available in the \ndocumentation.",
|
||||
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which organizations based on their\nusername and email address. Configuration details are available in the\ndocumentation.",
|
||||
"category": "GitHub Team OAuth2",
|
||||
"category_slug": "github-team",
|
||||
"defined_in_file": false,
|
||||
@ -6086,7 +6221,7 @@
|
||||
"SOCIAL_AUTH_GITHUB_ENTERPRISE_ORGANIZATION_MAP": {
|
||||
"type": "nested object",
|
||||
"label": "GitHub Enterprise OAuth2 Organization Map",
|
||||
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which organizations based on their\nusername and email address. Configuration details are available in the \ndocumentation.",
|
||||
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which organizations based on their\nusername and email address. Configuration details are available in the\ndocumentation.",
|
||||
"category": "GitHub Enterprise OAuth2",
|
||||
"category_slug": "github-enterprise",
|
||||
"defined_in_file": false,
|
||||
@ -6166,7 +6301,7 @@
|
||||
"SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_ORGANIZATION_MAP": {
|
||||
"type": "nested object",
|
||||
"label": "GitHub Enterprise Organization OAuth2 Organization Map",
|
||||
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which organizations based on their\nusername and email address. Configuration details are available in the \ndocumentation.",
|
||||
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which organizations based on their\nusername and email address. Configuration details are available in the\ndocumentation.",
|
||||
"category": "GitHub Enterprise Organization OAuth2",
|
||||
"category_slug": "github-enterprise-org",
|
||||
"defined_in_file": false,
|
||||
@ -6246,7 +6381,7 @@
|
||||
"SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_ORGANIZATION_MAP": {
|
||||
"type": "nested object",
|
||||
"label": "GitHub Enterprise Team OAuth2 Organization Map",
|
||||
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which organizations based on their\nusername and email address. Configuration details are available in the \ndocumentation.",
|
||||
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which organizations based on their\nusername and email address. Configuration details are available in the\ndocumentation.",
|
||||
"category": "GitHub Enterprise Team OAuth2",
|
||||
"category_slug": "github-enterprise-team",
|
||||
"defined_in_file": false,
|
||||
@ -6302,7 +6437,7 @@
|
||||
"SOCIAL_AUTH_AZUREAD_OAUTH2_ORGANIZATION_MAP": {
|
||||
"type": "nested object",
|
||||
"label": "Azure AD OAuth2 Organization Map",
|
||||
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which organizations based on their\nusername and email address. Configuration details are available in the \ndocumentation.",
|
||||
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which organizations based on their\nusername and email address. Configuration details are available in the\ndocumentation.",
|
||||
"category": "Azure AD OAuth2",
|
||||
"category_slug": "azuread-oauth2",
|
||||
"defined_in_file": false,
|
||||
@ -6331,6 +6466,38 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"SOCIAL_AUTH_OIDC_KEY": {
|
||||
"type": "string",
|
||||
"label": "OIDC Key",
|
||||
"help_text": "The OIDC key (Client ID) from your IDP.",
|
||||
"category": "Generic OIDC",
|
||||
"category_slug": "oidc",
|
||||
"defined_in_file": false
|
||||
},
|
||||
"SOCIAL_AUTH_OIDC_SECRET": {
|
||||
"type": "string",
|
||||
"label": "OIDC Secret",
|
||||
"help_text": "The OIDC secret (Client Secret) from your IDP.",
|
||||
"category": "Generic OIDC",
|
||||
"category_slug": "oidc",
|
||||
"defined_in_file": false
|
||||
},
|
||||
"SOCIAL_AUTH_OIDC_OIDC_ENDPOINT": {
|
||||
"type": "string",
|
||||
"label": "OIDC Provider URL",
|
||||
"help_text": "The URL for your OIDC provider including the path up to /.well-known/openid-configuration",
|
||||
"category": "Generic OIDC",
|
||||
"category_slug": "oidc",
|
||||
"defined_in_file": false
|
||||
},
|
||||
"SOCIAL_AUTH_OIDC_VERIFY_SSL": {
|
||||
"type": "boolean",
|
||||
"label": "Verify OIDC Provider Certificate",
|
||||
"help_text": "Verify the OIDC provider ssl certificate.",
|
||||
"category": "Generic OIDC",
|
||||
"category_slug": "oidc",
|
||||
"defined_in_file": false
|
||||
},
|
||||
"SAML_AUTO_CREATE_OBJECTS": {
|
||||
"type": "boolean",
|
||||
"label": "Automatically Create Organizations and Teams on SAML Login",
|
||||
@ -6469,7 +6636,7 @@
|
||||
"SOCIAL_AUTH_SAML_ORGANIZATION_MAP": {
|
||||
"type": "nested object",
|
||||
"label": "SAML Organization Map",
|
||||
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which organizations based on their\nusername and email address. Configuration details are available in the \ndocumentation.",
|
||||
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which organizations based on their\nusername and email address. Configuration details are available in the\ndocumentation.",
|
||||
"category": "SAML",
|
||||
"category_slug": "saml",
|
||||
"defined_in_file": false,
|
||||
@ -6522,7 +6689,7 @@
|
||||
},
|
||||
"SOCIAL_AUTH_SAML_USER_FLAGS_BY_ATTR": {
|
||||
"type": "nested object",
|
||||
"label": "SAML User Flags Attribute Mapping",
|
||||
"label": "SAML User Flags Attribute Mapping",
|
||||
"help_text": "Used to map super users and system auditors from SAML.",
|
||||
"category": "SAML",
|
||||
"category_slug": "saml",
|
||||
@ -6531,6 +6698,42 @@
|
||||
"type": "field"
|
||||
}
|
||||
},
|
||||
"LOCAL_PASSWORD_MIN_LENGTH": {
|
||||
"type": "integer",
|
||||
"label": "Minimum number of characters in local password",
|
||||
"help_text": "Minimum number of characters required in a local password. 0 means no minimum",
|
||||
"min_value": 0,
|
||||
"category": "Authentication",
|
||||
"category_slug": "authentication",
|
||||
"defined_in_file": false
|
||||
},
|
||||
"LOCAL_PASSWORD_MIN_DIGITS": {
|
||||
"type": "integer",
|
||||
"label": "Minimum number of digit characters in local password",
|
||||
"help_text": "Minimum number of digit characters required in a local password. 0 means no minimum",
|
||||
"min_value": 0,
|
||||
"category": "Authentication",
|
||||
"category_slug": "authentication",
|
||||
"defined_in_file": false
|
||||
},
|
||||
"LOCAL_PASSWORD_MIN_UPPER": {
|
||||
"type": "integer",
|
||||
"label": "Minimum number of uppercase characters in local password",
|
||||
"help_text": "Minimum number of uppercase characters required in a local password. 0 means no minimum",
|
||||
"min_value": 0,
|
||||
"category": "Authentication",
|
||||
"category_slug": "authentication",
|
||||
"defined_in_file": false
|
||||
},
|
||||
"LOCAL_PASSWORD_MIN_SPECIAL": {
|
||||
"type": "integer",
|
||||
"label": "Minimum number of special characters in local password",
|
||||
"help_text": "Minimum number of special characters required in a local password. 0 means no minimum",
|
||||
"min_value": 0,
|
||||
"category": "Authentication",
|
||||
"category_slug": "authentication",
|
||||
"defined_in_file": false
|
||||
},
|
||||
"NAMED_URL_FORMATS": {
|
||||
"type": "nested object",
|
||||
"label": "Formats of all available named urls",
|
||||
|
||||
@ -1,19 +1,19 @@
|
||||
{
|
||||
"ACTIVITY_STREAM_ENABLED":true,
|
||||
"ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC":false,
|
||||
"ORG_ADMINS_CAN_SEE_ALL_USERS":true,
|
||||
"MANAGE_ORGANIZATION_AUTH":true,
|
||||
"DISABLE_LOCAL_AUTH":false,
|
||||
"TOWER_URL_BASE":"https://localhost:3000",
|
||||
"REMOTE_HOST_HEADERS":["REMOTE_ADDR","REMOTE_HOST"],
|
||||
"PROXY_IP_ALLOWED_LIST":[],
|
||||
"LICENSE":{},
|
||||
"REDHAT_USERNAME":"",
|
||||
"REDHAT_PASSWORD":"",
|
||||
"AUTOMATION_ANALYTICS_URL":"https://example.com",
|
||||
"INSTALL_UUID":"3f5a4d68-3a94-474c-a3c0-f23a33122ce6",
|
||||
"CUSTOM_VENV_PATHS":[],
|
||||
"AD_HOC_COMMANDS":[
|
||||
"ACTIVITY_STREAM_ENABLED": true,
|
||||
"ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC": false,
|
||||
"ORG_ADMINS_CAN_SEE_ALL_USERS": true,
|
||||
"MANAGE_ORGANIZATION_AUTH": true,
|
||||
"DISABLE_LOCAL_AUTH": false,
|
||||
"TOWER_URL_BASE": "https://localhost:3000",
|
||||
"REMOTE_HOST_HEADERS": ["REMOTE_ADDR", "REMOTE_HOST"],
|
||||
"PROXY_IP_ALLOWED_LIST": [],
|
||||
"LICENSE": {},
|
||||
"REDHAT_USERNAME": "",
|
||||
"REDHAT_PASSWORD": "",
|
||||
"AUTOMATION_ANALYTICS_URL": "https://example.com",
|
||||
"INSTALL_UUID": "3f5a4d68-3a94-474c-a3c0-f23a33122ce6",
|
||||
"CUSTOM_VENV_PATHS": [],
|
||||
"AD_HOC_COMMANDS": [
|
||||
"command",
|
||||
"shell",
|
||||
"yum",
|
||||
@ -34,278 +34,360 @@
|
||||
"win_group",
|
||||
"win_user"
|
||||
],
|
||||
"ALLOW_JINJA_IN_EXTRA_VARS":"template",
|
||||
"AWX_ISOLATION_BASE_PATH":"/tmp",
|
||||
"AWX_ISOLATION_SHOW_PATHS":[],
|
||||
"AWX_TASK_ENV":{},
|
||||
"ALLOW_JINJA_IN_EXTRA_VARS": "template",
|
||||
"AWX_ISOLATION_BASE_PATH": "/tmp",
|
||||
"AWX_ISOLATION_SHOW_PATHS": [],
|
||||
"AWX_TASK_ENV": {},
|
||||
"GALAXY_TASK_ENV": {
|
||||
"ANSIBLE_FORCE_COLOR": "false",
|
||||
"GIT_SSH_COMMAND": "ssh -o StrictHostKeyChecking=no"
|
||||
},
|
||||
"INSIGHTS_TRACKING_STATE":false,
|
||||
"PROJECT_UPDATE_VVV":false,
|
||||
"AWX_ROLES_ENABLED":true,
|
||||
"AWX_COLLECTIONS_ENABLED":true,
|
||||
"AWX_SHOW_PLAYBOOK_LINKS":false,
|
||||
"GALAXY_IGNORE_CERTS":false,
|
||||
"STDOUT_MAX_BYTES_DISPLAY":1048576,
|
||||
"EVENT_STDOUT_MAX_BYTES_DISPLAY":1024,
|
||||
"SCHEDULE_MAX_JOBS":10,
|
||||
"AWX_RUNNER_KEEPALIVE_SECONDS": 0,
|
||||
"AWX_ANSIBLE_CALLBACK_PLUGINS":[],
|
||||
"DEFAULT_JOB_TIMEOUT":0,
|
||||
"DEFAULT_JOB_IDLE_TIMEOUT":0,
|
||||
"DEFAULT_INVENTORY_UPDATE_TIMEOUT":0,
|
||||
"DEFAULT_PROJECT_UPDATE_TIMEOUT":0,
|
||||
"ANSIBLE_FACT_CACHE_TIMEOUT":0,
|
||||
"MAX_FORKS":200,
|
||||
"LOG_AGGREGATOR_HOST":null,
|
||||
"LOG_AGGREGATOR_PORT":null,
|
||||
"LOG_AGGREGATOR_TYPE":null,
|
||||
"LOG_AGGREGATOR_USERNAME":"",
|
||||
"LOG_AGGREGATOR_PASSWORD":"",
|
||||
"LOG_AGGREGATOR_LOGGERS":["awx","activity_stream","job_events","system_tracking"],
|
||||
"LOG_AGGREGATOR_INDIVIDUAL_FACTS":false,
|
||||
"LOG_AGGREGATOR_ENABLED":true,
|
||||
"LOG_AGGREGATOR_TOWER_UUID":"",
|
||||
"LOG_AGGREGATOR_PROTOCOL":"https",
|
||||
"LOG_AGGREGATOR_TCP_TIMEOUT":5,
|
||||
"LOG_AGGREGATOR_VERIFY_CERT":true,
|
||||
"LOG_AGGREGATOR_LEVEL":"INFO",
|
||||
"LOG_AGGREGATOR_MAX_DISK_USAGE_GB":1,
|
||||
"LOG_AGGREGATOR_MAX_DISK_USAGE_PATH":"/var/lib/awx",
|
||||
"LOG_AGGREGATOR_RSYSLOGD_DEBUG":false,
|
||||
"API_400_ERROR_LOG_FORMAT":"status {status_code} received by user {user_name} attempting to access {url_path} from {remote_addr}",
|
||||
"AUTOMATION_ANALYTICS_LAST_GATHER":null,
|
||||
"AUTOMATION_ANALYTICS_GATHER_INTERVAL":14400,
|
||||
"SESSION_COOKIE_AGE":1800,
|
||||
"SESSIONS_PER_USER":-1,
|
||||
"AUTH_BASIC_ENABLED":true,
|
||||
"OAUTH2_PROVIDER":{
|
||||
"ACCESS_TOKEN_EXPIRE_SECONDS":31536000000,
|
||||
"REFRESH_TOKEN_EXPIRE_SECONDS":2628000,
|
||||
"AUTHORIZATION_CODE_EXPIRE_SECONDS":600
|
||||
},
|
||||
"ALLOW_OAUTH2_FOR_EXTERNAL_USERS":false,
|
||||
"LOGIN_REDIRECT_OVERRIDE":"",
|
||||
"PENDO_TRACKING_STATE":"off",
|
||||
"CUSTOM_LOGIN_INFO":"",
|
||||
"CUSTOM_LOGO":"",
|
||||
"MAX_UI_JOB_EVENTS":4000,
|
||||
"UI_LIVE_UPDATES_ENABLED":true,
|
||||
"AUTHENTICATION_BACKENDS":[
|
||||
"INSIGHTS_TRACKING_STATE": false,
|
||||
"PROJECT_UPDATE_VVV": false,
|
||||
"AWX_ROLES_ENABLED": true,
|
||||
"AWX_COLLECTIONS_ENABLED": true,
|
||||
"AWX_SHOW_PLAYBOOK_LINKS": false,
|
||||
"GALAXY_IGNORE_CERTS": false,
|
||||
"STDOUT_MAX_BYTES_DISPLAY": 1048576,
|
||||
"EVENT_STDOUT_MAX_BYTES_DISPLAY": 1024,
|
||||
"SCHEDULE_MAX_JOBS": 10,
|
||||
"AWX_RUNNER_KEEPALIVE_SECONDS": 0,
|
||||
"AWX_ANSIBLE_CALLBACK_PLUGINS": [],
|
||||
"DEFAULT_JOB_TIMEOUT": 0,
|
||||
"DEFAULT_JOB_IDLE_TIMEOUT": 0,
|
||||
"DEFAULT_INVENTORY_UPDATE_TIMEOUT": 0,
|
||||
"DEFAULT_PROJECT_UPDATE_TIMEOUT": 0,
|
||||
"ANSIBLE_FACT_CACHE_TIMEOUT": 0,
|
||||
"MAX_FORKS": 200,
|
||||
"LOG_AGGREGATOR_HOST": null,
|
||||
"LOG_AGGREGATOR_PORT": null,
|
||||
"LOG_AGGREGATOR_TYPE": null,
|
||||
"LOG_AGGREGATOR_USERNAME": "",
|
||||
"LOG_AGGREGATOR_PASSWORD": "",
|
||||
"LOG_AGGREGATOR_LOGGERS": [
|
||||
"awx",
|
||||
"activity_stream",
|
||||
"job_events",
|
||||
"system_tracking"
|
||||
],
|
||||
"LOG_AGGREGATOR_INDIVIDUAL_FACTS": false,
|
||||
"LOG_AGGREGATOR_ENABLED": true,
|
||||
"LOG_AGGREGATOR_TOWER_UUID": "",
|
||||
"LOG_AGGREGATOR_PROTOCOL": "https",
|
||||
"LOG_AGGREGATOR_TCP_TIMEOUT": 5,
|
||||
"LOG_AGGREGATOR_VERIFY_CERT": true,
|
||||
"LOG_AGGREGATOR_LEVEL": "INFO",
|
||||
"LOG_AGGREGATOR_MAX_DISK_USAGE_GB": 1,
|
||||
"LOG_AGGREGATOR_MAX_DISK_USAGE_PATH": "/var/lib/awx",
|
||||
"LOG_AGGREGATOR_RSYSLOGD_DEBUG": false,
|
||||
"API_400_ERROR_LOG_FORMAT": "status {status_code} received by user {user_name} attempting to access {url_path} from {remote_addr}",
|
||||
"AUTOMATION_ANALYTICS_LAST_GATHER": null,
|
||||
"AUTOMATION_ANALYTICS_GATHER_INTERVAL": 14400,
|
||||
"SESSION_COOKIE_AGE": 1800,
|
||||
"SESSIONS_PER_USER": -1,
|
||||
"AUTH_BASIC_ENABLED": true,
|
||||
"OAUTH2_PROVIDER": {
|
||||
"ACCESS_TOKEN_EXPIRE_SECONDS": 31536000000,
|
||||
"REFRESH_TOKEN_EXPIRE_SECONDS": 2628000,
|
||||
"AUTHORIZATION_CODE_EXPIRE_SECONDS": 600
|
||||
},
|
||||
"ALLOW_OAUTH2_FOR_EXTERNAL_USERS": false,
|
||||
"LOGIN_REDIRECT_OVERRIDE": "",
|
||||
"PENDO_TRACKING_STATE": "off",
|
||||
"CUSTOM_LOGIN_INFO": "",
|
||||
"CUSTOM_LOGO": "",
|
||||
"MAX_UI_JOB_EVENTS": 4000,
|
||||
"UI_LIVE_UPDATES_ENABLED": true,
|
||||
"AUTHENTICATION_BACKENDS": [
|
||||
"awx.sso.backends.LDAPBackend",
|
||||
"awx.sso.backends.RADIUSBackend",
|
||||
"awx.sso.backends.TACACSPlusBackend",
|
||||
"social_core.backends.github.GithubTeamOAuth2",
|
||||
"django.contrib.auth.backends.ModelBackend"
|
||||
],
|
||||
"SOCIAL_AUTH_ORGANIZATION_MAP":null,
|
||||
"SOCIAL_AUTH_TEAM_MAP":null,
|
||||
"SOCIAL_AUTH_USER_FIELDS":null,
|
||||
"SOCIAL_AUTH_USERNAME_IS_FULL_EMAIL":false,
|
||||
"AUTH_LDAP_SERVER_URI":"ldap://ldap.example.com",
|
||||
"AUTH_LDAP_BIND_DN":"cn=eng_user1",
|
||||
"AUTH_LDAP_BIND_PASSWORD":"$encrypted$",
|
||||
"AUTH_LDAP_START_TLS":false,
|
||||
"AUTH_LDAP_CONNECTION_OPTIONS":{"OPT_REFERRALS":0,"OPT_NETWORK_TIMEOUT":30},
|
||||
"AUTH_LDAP_USER_SEARCH":[],
|
||||
"AUTH_LDAP_USER_DN_TEMPLATE":"uid=%(user)s,OU=Users,DC=example,DC=com",
|
||||
"AUTH_LDAP_USER_ATTR_MAP":{},
|
||||
"AUTH_LDAP_GROUP_SEARCH":["DC=example,DC=com","SCOPE_SUBTREE","(objectClass=group)"],
|
||||
"AUTH_LDAP_GROUP_TYPE":"MemberDNGroupType",
|
||||
"AUTH_LDAP_GROUP_TYPE_PARAMS":{"name_attr":"cn","member_attr":"member"},
|
||||
"AUTH_LDAP_REQUIRE_GROUP":"CN=Service Users,OU=Users,DC=example,DC=com",
|
||||
"AUTH_LDAP_DENY_GROUP":null,
|
||||
"AUTH_LDAP_USER_FLAGS_BY_GROUP":{"is_superuser":["cn=superusers"]},
|
||||
"AUTH_LDAP_ORGANIZATION_MAP":{},
|
||||
"AUTH_LDAP_TEAM_MAP":{},
|
||||
"AUTH_LDAP_1_SERVER_URI":"",
|
||||
"AUTH_LDAP_1_BIND_DN":"",
|
||||
"AUTH_LDAP_1_BIND_PASSWORD":"",
|
||||
"AUTH_LDAP_1_START_TLS":true,
|
||||
"AUTH_LDAP_1_CONNECTION_OPTIONS":{"OPT_REFERRALS":0,"OPT_NETWORK_TIMEOUT":30},
|
||||
"AUTH_LDAP_1_USER_SEARCH":[],
|
||||
"AUTH_LDAP_1_USER_DN_TEMPLATE":null,
|
||||
"AUTH_LDAP_1_USER_ATTR_MAP":{},
|
||||
"AUTH_LDAP_1_GROUP_SEARCH":[],
|
||||
"AUTH_LDAP_1_GROUP_TYPE":"MemberDNGroupType",
|
||||
"AUTH_LDAP_1_GROUP_TYPE_PARAMS":{"member_attr":"member","name_attr":"cn"},
|
||||
"AUTH_LDAP_1_REQUIRE_GROUP":null,
|
||||
"AUTH_LDAP_1_DENY_GROUP":"CN=Disabled1",
|
||||
"AUTH_LDAP_1_USER_FLAGS_BY_GROUP":{},
|
||||
"AUTH_LDAP_1_ORGANIZATION_MAP":{},
|
||||
"AUTH_LDAP_1_TEAM_MAP":{},
|
||||
"AUTH_LDAP_2_SERVER_URI":"",
|
||||
"AUTH_LDAP_2_BIND_DN":"",
|
||||
"AUTH_LDAP_2_BIND_PASSWORD":"",
|
||||
"AUTH_LDAP_2_START_TLS":false,
|
||||
"AUTH_LDAP_2_CONNECTION_OPTIONS":{"OPT_REFERRALS":0,"OPT_NETWORK_TIMEOUT":30},
|
||||
"AUTH_LDAP_2_USER_SEARCH":[],
|
||||
"AUTH_LDAP_2_USER_DN_TEMPLATE":null,
|
||||
"AUTH_LDAP_2_USER_ATTR_MAP":{},
|
||||
"AUTH_LDAP_2_GROUP_SEARCH":[],
|
||||
"AUTH_LDAP_2_GROUP_TYPE":"MemberDNGroupType",
|
||||
"AUTH_LDAP_2_GROUP_TYPE_PARAMS":{"member_attr":"member","name_attr":"cn"},
|
||||
"AUTH_LDAP_2_REQUIRE_GROUP":null,
|
||||
"AUTH_LDAP_2_DENY_GROUP":"CN=Disabled2",
|
||||
"AUTH_LDAP_2_USER_FLAGS_BY_GROUP":{},
|
||||
"AUTH_LDAP_2_ORGANIZATION_MAP":{},
|
||||
"AUTH_LDAP_2_TEAM_MAP":{},
|
||||
"AUTH_LDAP_3_SERVER_URI":"",
|
||||
"AUTH_LDAP_3_BIND_DN":"",
|
||||
"AUTH_LDAP_3_BIND_PASSWORD":"",
|
||||
"AUTH_LDAP_3_START_TLS":false,
|
||||
"AUTH_LDAP_3_CONNECTION_OPTIONS":{"OPT_REFERRALS":0,"OPT_NETWORK_TIMEOUT":30},
|
||||
"AUTH_LDAP_3_USER_SEARCH":[],
|
||||
"AUTH_LDAP_3_USER_DN_TEMPLATE":null,
|
||||
"AUTH_LDAP_3_USER_ATTR_MAP":{},
|
||||
"AUTH_LDAP_3_GROUP_SEARCH":[],
|
||||
"AUTH_LDAP_3_GROUP_TYPE":"MemberDNGroupType",
|
||||
"AUTH_LDAP_3_GROUP_TYPE_PARAMS":{"member_attr":"member","name_attr":"cn"},
|
||||
"AUTH_LDAP_3_REQUIRE_GROUP":null,
|
||||
"AUTH_LDAP_3_DENY_GROUP":null,
|
||||
"AUTH_LDAP_3_USER_FLAGS_BY_GROUP":{},
|
||||
"AUTH_LDAP_3_ORGANIZATION_MAP":{},
|
||||
"AUTH_LDAP_3_TEAM_MAP":{},
|
||||
"AUTH_LDAP_4_SERVER_URI":"",
|
||||
"AUTH_LDAP_4_BIND_DN":"",
|
||||
"AUTH_LDAP_4_BIND_PASSWORD":"",
|
||||
"AUTH_LDAP_4_START_TLS":false,
|
||||
"AUTH_LDAP_4_CONNECTION_OPTIONS":{"OPT_REFERRALS":0,"OPT_NETWORK_TIMEOUT":30},
|
||||
"AUTH_LDAP_4_USER_SEARCH":[],
|
||||
"AUTH_LDAP_4_USER_DN_TEMPLATE":null,
|
||||
"AUTH_LDAP_4_USER_ATTR_MAP":{},
|
||||
"AUTH_LDAP_4_GROUP_SEARCH":[],
|
||||
"AUTH_LDAP_4_GROUP_TYPE":"MemberDNGroupType",
|
||||
"AUTH_LDAP_4_GROUP_TYPE_PARAMS":{"member_attr":"member","name_attr":"cn"},
|
||||
"AUTH_LDAP_4_REQUIRE_GROUP":null,
|
||||
"AUTH_LDAP_4_DENY_GROUP":null,
|
||||
"AUTH_LDAP_4_USER_FLAGS_BY_GROUP":{},
|
||||
"AUTH_LDAP_4_ORGANIZATION_MAP":{},
|
||||
"AUTH_LDAP_4_TEAM_MAP":{},
|
||||
"AUTH_LDAP_5_SERVER_URI":"",
|
||||
"AUTH_LDAP_5_BIND_DN":"",
|
||||
"AUTH_LDAP_5_BIND_PASSWORD":"",
|
||||
"AUTH_LDAP_5_START_TLS":false,
|
||||
"AUTH_LDAP_5_CONNECTION_OPTIONS":{"OPT_REFERRALS":0,"OPT_NETWORK_TIMEOUT":30},
|
||||
"AUTH_LDAP_5_USER_SEARCH":[],
|
||||
"AUTH_LDAP_5_USER_DN_TEMPLATE":null,
|
||||
"AUTH_LDAP_5_USER_ATTR_MAP":{},
|
||||
"AUTH_LDAP_5_GROUP_SEARCH":[],
|
||||
"AUTH_LDAP_5_GROUP_TYPE":"MemberDNGroupType",
|
||||
"AUTH_LDAP_5_GROUP_TYPE_PARAMS":{"member_attr":"member","name_attr":"cn"},
|
||||
"AUTH_LDAP_5_REQUIRE_GROUP":null,
|
||||
"AUTH_LDAP_5_DENY_GROUP":null,
|
||||
"AUTH_LDAP_5_USER_FLAGS_BY_GROUP":{},
|
||||
"AUTH_LDAP_5_ORGANIZATION_MAP":{},
|
||||
"AUTH_LDAP_5_TEAM_MAP":{},
|
||||
"RADIUS_SERVER":"example.org",
|
||||
"RADIUS_PORT":1812,
|
||||
"RADIUS_SECRET":"$encrypted$",
|
||||
"TACACSPLUS_HOST":"",
|
||||
"TACACSPLUS_PORT":49,
|
||||
"TACACSPLUS_SECRET":"",
|
||||
"TACACSPLUS_SESSION_TIMEOUT":5,
|
||||
"TACACSPLUS_AUTH_PROTOCOL":"ascii",
|
||||
"SOCIAL_AUTH_GOOGLE_OAUTH2_CALLBACK_URL":"https://localhost:3000/sso/complete/google-oauth2/",
|
||||
"SOCIAL_AUTH_GOOGLE_OAUTH2_KEY":"",
|
||||
"SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET":"",
|
||||
"SOCIAL_AUTH_GOOGLE_OAUTH2_WHITELISTED_DOMAINS":[],
|
||||
"SOCIAL_AUTH_GOOGLE_OAUTH2_AUTH_EXTRA_ARGUMENTS":{},
|
||||
"SOCIAL_AUTH_GOOGLE_OAUTH2_ORGANIZATION_MAP":null,
|
||||
"SOCIAL_AUTH_GOOGLE_OAUTH2_TEAM_MAP":null,
|
||||
"SOCIAL_AUTH_GITHUB_CALLBACK_URL":"https://localhost:3000/sso/complete/github/",
|
||||
"SOCIAL_AUTH_GITHUB_KEY":"",
|
||||
"SOCIAL_AUTH_GITHUB_SECRET":"",
|
||||
"SOCIAL_AUTH_GITHUB_ORGANIZATION_MAP":null,
|
||||
"SOCIAL_AUTH_GITHUB_TEAM_MAP":null,
|
||||
"SOCIAL_AUTH_GITHUB_ORG_CALLBACK_URL":"https://localhost:3000/sso/complete/github-org/",
|
||||
"SOCIAL_AUTH_GITHUB_ORG_KEY":"",
|
||||
"SOCIAL_AUTH_GITHUB_ORG_SECRET":"",
|
||||
"SOCIAL_AUTH_GITHUB_ORG_NAME":"",
|
||||
"SOCIAL_AUTH_GITHUB_ORG_ORGANIZATION_MAP":null,
|
||||
"SOCIAL_AUTH_GITHUB_ORG_TEAM_MAP":null,
|
||||
"SOCIAL_AUTH_GITHUB_TEAM_CALLBACK_URL":"https://localhost:3000/sso/complete/github-team/",
|
||||
"SOCIAL_AUTH_GITHUB_TEAM_KEY":"OAuth2 key (Client ID)",
|
||||
"SOCIAL_AUTH_GITHUB_TEAM_SECRET":"$encrypted$",
|
||||
"SOCIAL_AUTH_GITHUB_TEAM_ID":"team_id",
|
||||
"SOCIAL_AUTH_GITHUB_TEAM_ORGANIZATION_MAP":{},
|
||||
"SOCIAL_AUTH_GITHUB_TEAM_TEAM_MAP":{},
|
||||
"SOCIAL_AUTH_AZUREAD_OAUTH2_CALLBACK_URL":"https://localhost:3000/sso/complete/azuread-oauth2/",
|
||||
"SOCIAL_AUTH_AZUREAD_OAUTH2_KEY":"",
|
||||
"SOCIAL_AUTH_AZUREAD_OAUTH2_SECRET":"",
|
||||
"SOCIAL_AUTH_AZUREAD_OAUTH2_ORGANIZATION_MAP":null,
|
||||
"SOCIAL_AUTH_AZUREAD_OAUTH2_TEAM_MAP":null,
|
||||
"SAML_AUTO_CREATE_OBJECTS":true,
|
||||
"SOCIAL_AUTH_SAML_CALLBACK_URL":"https://localhost:3000/sso/complete/saml/",
|
||||
"SOCIAL_AUTH_SAML_METADATA_URL":"https://localhost:3000/sso/metadata/saml/",
|
||||
"SOCIAL_AUTH_SAML_SP_ENTITY_ID":"",
|
||||
"SOCIAL_AUTH_SAML_SP_PUBLIC_CERT":"",
|
||||
"SOCIAL_AUTH_SAML_SP_PRIVATE_KEY":"",
|
||||
"SOCIAL_AUTH_SAML_ORG_INFO":{},
|
||||
"SOCIAL_AUTH_SAML_TECHNICAL_CONTACT":{},
|
||||
"SOCIAL_AUTH_SAML_SUPPORT_CONTACT":{},
|
||||
"SOCIAL_AUTH_SAML_ENABLED_IDPS":{},
|
||||
"SOCIAL_AUTH_SAML_SECURITY_CONFIG":{"requestedAuthnContext":false},
|
||||
"SOCIAL_AUTH_SAML_SP_EXTRA":null,
|
||||
"SOCIAL_AUTH_SAML_EXTRA_DATA":null,
|
||||
"SOCIAL_AUTH_SAML_ORGANIZATION_MAP":null,
|
||||
"SOCIAL_AUTH_SAML_TEAM_MAP":null,
|
||||
"SOCIAL_AUTH_SAML_ORGANIZATION_ATTR":{},
|
||||
"SOCIAL_AUTH_SAML_TEAM_ATTR":{},
|
||||
"SOCIAL_AUTH_SAML_USER_FLAGS_BY_ATTR":{},
|
||||
"SOCIAL_AUTH_OIDC_KEY":"",
|
||||
"SOCIAL_AUTH_OIDC_SECRET":"",
|
||||
"SOCIAL_AUTH_OIDC_OIDC_ENDPOINT":"",
|
||||
"SOCIAL_AUTH_OIDC_VERIFY_SSL":true,
|
||||
"NAMED_URL_FORMATS":{
|
||||
"organizations":"<name>",
|
||||
"teams":"<name>++<organization.name>",
|
||||
"credential_types":"<name>+<kind>",
|
||||
"credentials":"<name>++<credential_type.name>+<credential_type.kind>++<organization.name>",
|
||||
"notification_templates":"<name>++<organization.name>",
|
||||
"job_templates":"<name>++<organization.name>",
|
||||
"projects":"<name>++<organization.name>",
|
||||
"inventories":"<name>++<organization.name>",
|
||||
"hosts":"<name>++<inventory.name>++<organization.name>",
|
||||
"groups":"<name>++<inventory.name>++<organization.name>",
|
||||
"inventory_sources":"<name>++<inventory.name>++<organization.name>",
|
||||
"inventory_scripts":"<name>++<organization.name>",
|
||||
"instance_groups":"<name>",
|
||||
"labels":"<name>++<organization.name>",
|
||||
"workflow_job_templates":"<name>++<organization.name>",
|
||||
"workflow_job_template_nodes":"<identifier>++<workflow_job_template.name>++<organization.name>",
|
||||
"applications":"<name>++<organization.name>",
|
||||
"users":"<username>",
|
||||
"instances":"<hostname>"
|
||||
"SOCIAL_AUTH_ORGANIZATION_MAP": null,
|
||||
"SOCIAL_AUTH_TEAM_MAP": null,
|
||||
"SOCIAL_AUTH_USER_FIELDS": null,
|
||||
"SOCIAL_AUTH_USERNAME_IS_FULL_EMAIL": false,
|
||||
"AUTH_LDAP_SERVER_URI": "ldap://ldap.example.com",
|
||||
"AUTH_LDAP_BIND_DN": "cn=eng_user1",
|
||||
"AUTH_LDAP_BIND_PASSWORD": "$encrypted$",
|
||||
"AUTH_LDAP_START_TLS": false,
|
||||
"AUTH_LDAP_CONNECTION_OPTIONS": {
|
||||
"OPT_REFERRALS": 0,
|
||||
"OPT_NETWORK_TIMEOUT": 30
|
||||
},
|
||||
"NAMED_URL_GRAPH_NODES":{
|
||||
"organizations":{"fields":["name"],"adj_list":[]},
|
||||
"teams":{"fields":["name"],"adj_list":[["organization","organizations"]]},
|
||||
"credential_types":{"fields":["name","kind"],"adj_list":[]},
|
||||
"credentials":{
|
||||
"fields":["name"],
|
||||
"adj_list":[["credential_type","credential_types"],["organization","organizations"]]
|
||||
"AUTH_LDAP_USER_SEARCH": [],
|
||||
"AUTH_LDAP_USER_DN_TEMPLATE": "uid=%(user)s,OU=Users,DC=example,DC=com",
|
||||
"AUTH_LDAP_USER_ATTR_MAP": {},
|
||||
"AUTH_LDAP_GROUP_SEARCH": [
|
||||
"DC=example,DC=com",
|
||||
"SCOPE_SUBTREE",
|
||||
"(objectClass=group)"
|
||||
],
|
||||
"AUTH_LDAP_GROUP_TYPE": "MemberDNGroupType",
|
||||
"AUTH_LDAP_GROUP_TYPE_PARAMS": { "name_attr": "cn", "member_attr": "member" },
|
||||
"AUTH_LDAP_REQUIRE_GROUP": "CN=Service Users,OU=Users,DC=example,DC=com",
|
||||
"AUTH_LDAP_DENY_GROUP": null,
|
||||
"AUTH_LDAP_USER_FLAGS_BY_GROUP": { "is_superuser": ["cn=superusers"] },
|
||||
"AUTH_LDAP_ORGANIZATION_MAP": {},
|
||||
"AUTH_LDAP_TEAM_MAP": {},
|
||||
"AUTH_LDAP_1_SERVER_URI": "",
|
||||
"AUTH_LDAP_1_BIND_DN": "",
|
||||
"AUTH_LDAP_1_BIND_PASSWORD": "",
|
||||
"AUTH_LDAP_1_START_TLS": true,
|
||||
"AUTH_LDAP_1_CONNECTION_OPTIONS": {
|
||||
"OPT_REFERRALS": 0,
|
||||
"OPT_NETWORK_TIMEOUT": 30
|
||||
},
|
||||
"AUTH_LDAP_1_USER_SEARCH": [],
|
||||
"AUTH_LDAP_1_USER_DN_TEMPLATE": null,
|
||||
"AUTH_LDAP_1_USER_ATTR_MAP": {},
|
||||
"AUTH_LDAP_1_GROUP_SEARCH": [],
|
||||
"AUTH_LDAP_1_GROUP_TYPE": "MemberDNGroupType",
|
||||
"AUTH_LDAP_1_GROUP_TYPE_PARAMS": {
|
||||
"member_attr": "member",
|
||||
"name_attr": "cn"
|
||||
},
|
||||
"AUTH_LDAP_1_REQUIRE_GROUP": null,
|
||||
"AUTH_LDAP_1_DENY_GROUP": "CN=Disabled1",
|
||||
"AUTH_LDAP_1_USER_FLAGS_BY_GROUP": {},
|
||||
"AUTH_LDAP_1_ORGANIZATION_MAP": {},
|
||||
"AUTH_LDAP_1_TEAM_MAP": {},
|
||||
"AUTH_LDAP_2_SERVER_URI": "",
|
||||
"AUTH_LDAP_2_BIND_DN": "",
|
||||
"AUTH_LDAP_2_BIND_PASSWORD": "",
|
||||
"AUTH_LDAP_2_START_TLS": false,
|
||||
"AUTH_LDAP_2_CONNECTION_OPTIONS": {
|
||||
"OPT_REFERRALS": 0,
|
||||
"OPT_NETWORK_TIMEOUT": 30
|
||||
},
|
||||
"AUTH_LDAP_2_USER_SEARCH": [],
|
||||
"AUTH_LDAP_2_USER_DN_TEMPLATE": null,
|
||||
"AUTH_LDAP_2_USER_ATTR_MAP": {},
|
||||
"AUTH_LDAP_2_GROUP_SEARCH": [],
|
||||
"AUTH_LDAP_2_GROUP_TYPE": "MemberDNGroupType",
|
||||
"AUTH_LDAP_2_GROUP_TYPE_PARAMS": {
|
||||
"member_attr": "member",
|
||||
"name_attr": "cn"
|
||||
},
|
||||
"AUTH_LDAP_2_REQUIRE_GROUP": null,
|
||||
"AUTH_LDAP_2_DENY_GROUP": "CN=Disabled2",
|
||||
"AUTH_LDAP_2_USER_FLAGS_BY_GROUP": {},
|
||||
"AUTH_LDAP_2_ORGANIZATION_MAP": {},
|
||||
"AUTH_LDAP_2_TEAM_MAP": {},
|
||||
"AUTH_LDAP_3_SERVER_URI": "",
|
||||
"AUTH_LDAP_3_BIND_DN": "",
|
||||
"AUTH_LDAP_3_BIND_PASSWORD": "",
|
||||
"AUTH_LDAP_3_START_TLS": false,
|
||||
"AUTH_LDAP_3_CONNECTION_OPTIONS": {
|
||||
"OPT_REFERRALS": 0,
|
||||
"OPT_NETWORK_TIMEOUT": 30
|
||||
},
|
||||
"AUTH_LDAP_3_USER_SEARCH": [],
|
||||
"AUTH_LDAP_3_USER_DN_TEMPLATE": null,
|
||||
"AUTH_LDAP_3_USER_ATTR_MAP": {},
|
||||
"AUTH_LDAP_3_GROUP_SEARCH": [],
|
||||
"AUTH_LDAP_3_GROUP_TYPE": "MemberDNGroupType",
|
||||
"AUTH_LDAP_3_GROUP_TYPE_PARAMS": {
|
||||
"member_attr": "member",
|
||||
"name_attr": "cn"
|
||||
},
|
||||
"AUTH_LDAP_3_REQUIRE_GROUP": null,
|
||||
"AUTH_LDAP_3_DENY_GROUP": null,
|
||||
"AUTH_LDAP_3_USER_FLAGS_BY_GROUP": {},
|
||||
"AUTH_LDAP_3_ORGANIZATION_MAP": {},
|
||||
"AUTH_LDAP_3_TEAM_MAP": {},
|
||||
"AUTH_LDAP_4_SERVER_URI": "",
|
||||
"AUTH_LDAP_4_BIND_DN": "",
|
||||
"AUTH_LDAP_4_BIND_PASSWORD": "",
|
||||
"AUTH_LDAP_4_START_TLS": false,
|
||||
"AUTH_LDAP_4_CONNECTION_OPTIONS": {
|
||||
"OPT_REFERRALS": 0,
|
||||
"OPT_NETWORK_TIMEOUT": 30
|
||||
},
|
||||
"AUTH_LDAP_4_USER_SEARCH": [],
|
||||
"AUTH_LDAP_4_USER_DN_TEMPLATE": null,
|
||||
"AUTH_LDAP_4_USER_ATTR_MAP": {},
|
||||
"AUTH_LDAP_4_GROUP_SEARCH": [],
|
||||
"AUTH_LDAP_4_GROUP_TYPE": "MemberDNGroupType",
|
||||
"AUTH_LDAP_4_GROUP_TYPE_PARAMS": {
|
||||
"member_attr": "member",
|
||||
"name_attr": "cn"
|
||||
},
|
||||
"AUTH_LDAP_4_REQUIRE_GROUP": null,
|
||||
"AUTH_LDAP_4_DENY_GROUP": null,
|
||||
"AUTH_LDAP_4_USER_FLAGS_BY_GROUP": {},
|
||||
"AUTH_LDAP_4_ORGANIZATION_MAP": {},
|
||||
"AUTH_LDAP_4_TEAM_MAP": {},
|
||||
"AUTH_LDAP_5_SERVER_URI": "",
|
||||
"AUTH_LDAP_5_BIND_DN": "",
|
||||
"AUTH_LDAP_5_BIND_PASSWORD": "",
|
||||
"AUTH_LDAP_5_START_TLS": false,
|
||||
"AUTH_LDAP_5_CONNECTION_OPTIONS": {
|
||||
"OPT_REFERRALS": 0,
|
||||
"OPT_NETWORK_TIMEOUT": 30
|
||||
},
|
||||
"AUTH_LDAP_5_USER_SEARCH": [],
|
||||
"AUTH_LDAP_5_USER_DN_TEMPLATE": null,
|
||||
"AUTH_LDAP_5_USER_ATTR_MAP": {},
|
||||
"AUTH_LDAP_5_GROUP_SEARCH": [],
|
||||
"AUTH_LDAP_5_GROUP_TYPE": "MemberDNGroupType",
|
||||
"AUTH_LDAP_5_GROUP_TYPE_PARAMS": {
|
||||
"member_attr": "member",
|
||||
"name_attr": "cn"
|
||||
},
|
||||
"AUTH_LDAP_5_REQUIRE_GROUP": null,
|
||||
"AUTH_LDAP_5_DENY_GROUP": null,
|
||||
"AUTH_LDAP_5_USER_FLAGS_BY_GROUP": {},
|
||||
"AUTH_LDAP_5_ORGANIZATION_MAP": {},
|
||||
"AUTH_LDAP_5_TEAM_MAP": {},
|
||||
"RADIUS_SERVER": "example.org",
|
||||
"RADIUS_PORT": 1812,
|
||||
"RADIUS_SECRET": "$encrypted$",
|
||||
"TACACSPLUS_HOST": "",
|
||||
"TACACSPLUS_PORT": 49,
|
||||
"TACACSPLUS_SECRET": "",
|
||||
"TACACSPLUS_SESSION_TIMEOUT": 5,
|
||||
"TACACSPLUS_AUTH_PROTOCOL": "ascii",
|
||||
"SOCIAL_AUTH_GOOGLE_OAUTH2_CALLBACK_URL": "https://localhost:3000/sso/complete/google-oauth2/",
|
||||
"SOCIAL_AUTH_GOOGLE_OAUTH2_KEY": "",
|
||||
"SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET": "",
|
||||
"SOCIAL_AUTH_GOOGLE_OAUTH2_WHITELISTED_DOMAINS": [],
|
||||
"SOCIAL_AUTH_GOOGLE_OAUTH2_AUTH_EXTRA_ARGUMENTS": {},
|
||||
"SOCIAL_AUTH_GOOGLE_OAUTH2_ORGANIZATION_MAP": null,
|
||||
"SOCIAL_AUTH_GOOGLE_OAUTH2_TEAM_MAP": null,
|
||||
"SOCIAL_AUTH_GITHUB_CALLBACK_URL": "https://localhost:3000/sso/complete/github/",
|
||||
"SOCIAL_AUTH_GITHUB_KEY": "",
|
||||
"SOCIAL_AUTH_GITHUB_SECRET": "",
|
||||
"SOCIAL_AUTH_GITHUB_ORGANIZATION_MAP": null,
|
||||
"SOCIAL_AUTH_GITHUB_TEAM_MAP": null,
|
||||
"SOCIAL_AUTH_GITHUB_ORG_CALLBACK_URL": "https://localhost:3000/sso/complete/github-org/",
|
||||
"SOCIAL_AUTH_GITHUB_ORG_KEY": "",
|
||||
"SOCIAL_AUTH_GITHUB_ORG_SECRET": "",
|
||||
"SOCIAL_AUTH_GITHUB_ORG_NAME": "",
|
||||
"SOCIAL_AUTH_GITHUB_ORG_ORGANIZATION_MAP": null,
|
||||
"SOCIAL_AUTH_GITHUB_ORG_TEAM_MAP": null,
|
||||
"SOCIAL_AUTH_GITHUB_TEAM_CALLBACK_URL": "https://localhost:3000/sso/complete/github-team/",
|
||||
"SOCIAL_AUTH_GITHUB_TEAM_KEY": "OAuth2 key (Client ID)",
|
||||
"SOCIAL_AUTH_GITHUB_TEAM_SECRET": "$encrypted$",
|
||||
"SOCIAL_AUTH_GITHUB_TEAM_ID": "team_id",
|
||||
"SOCIAL_AUTH_GITHUB_TEAM_ORGANIZATION_MAP": {},
|
||||
"SOCIAL_AUTH_GITHUB_TEAM_TEAM_MAP": {},
|
||||
"SOCIAL_AUTH_AZUREAD_OAUTH2_CALLBACK_URL": "https://localhost:3000/sso/complete/azuread-oauth2/",
|
||||
"SOCIAL_AUTH_AZUREAD_OAUTH2_KEY": "",
|
||||
"SOCIAL_AUTH_AZUREAD_OAUTH2_SECRET": "",
|
||||
"SOCIAL_AUTH_AZUREAD_OAUTH2_ORGANIZATION_MAP": null,
|
||||
"SOCIAL_AUTH_AZUREAD_OAUTH2_TEAM_MAP": null,
|
||||
"SAML_AUTO_CREATE_OBJECTS": true,
|
||||
"SOCIAL_AUTH_SAML_CALLBACK_URL": "https://localhost:3000/sso/complete/saml/",
|
||||
"SOCIAL_AUTH_SAML_METADATA_URL": "https://localhost:3000/sso/metadata/saml/",
|
||||
"SOCIAL_AUTH_SAML_SP_ENTITY_ID": "",
|
||||
"SOCIAL_AUTH_SAML_SP_PUBLIC_CERT": "",
|
||||
"SOCIAL_AUTH_SAML_SP_PRIVATE_KEY": "",
|
||||
"SOCIAL_AUTH_SAML_ORG_INFO": {},
|
||||
"SOCIAL_AUTH_SAML_TECHNICAL_CONTACT": {},
|
||||
"SOCIAL_AUTH_SAML_SUPPORT_CONTACT": {},
|
||||
"SOCIAL_AUTH_SAML_ENABLED_IDPS": {},
|
||||
"SOCIAL_AUTH_SAML_SECURITY_CONFIG": { "requestedAuthnContext": false },
|
||||
"SOCIAL_AUTH_SAML_SP_EXTRA": null,
|
||||
"SOCIAL_AUTH_SAML_EXTRA_DATA": null,
|
||||
"SOCIAL_AUTH_SAML_ORGANIZATION_MAP": null,
|
||||
"SOCIAL_AUTH_SAML_TEAM_MAP": null,
|
||||
"SOCIAL_AUTH_SAML_ORGANIZATION_ATTR": {},
|
||||
"SOCIAL_AUTH_SAML_TEAM_ATTR": {},
|
||||
"SOCIAL_AUTH_SAML_USER_FLAGS_BY_ATTR": {},
|
||||
"SOCIAL_AUTH_OIDC_KEY": "",
|
||||
"SOCIAL_AUTH_OIDC_SECRET": "",
|
||||
"SOCIAL_AUTH_OIDC_OIDC_ENDPOINT": "",
|
||||
"SOCIAL_AUTH_OIDC_VERIFY_SSL": true,
|
||||
"NAMED_URL_FORMATS": {
|
||||
"organizations": "<name>",
|
||||
"teams": "<name>++<organization.name>",
|
||||
"credential_types": "<name>+<kind>",
|
||||
"credentials": "<name>++<credential_type.name>+<credential_type.kind>++<organization.name>",
|
||||
"notification_templates": "<name>++<organization.name>",
|
||||
"job_templates": "<name>++<organization.name>",
|
||||
"projects": "<name>++<organization.name>",
|
||||
"inventories": "<name>++<organization.name>",
|
||||
"hosts": "<name>++<inventory.name>++<organization.name>",
|
||||
"groups": "<name>++<inventory.name>++<organization.name>",
|
||||
"inventory_sources": "<name>++<inventory.name>++<organization.name>",
|
||||
"inventory_scripts": "<name>++<organization.name>",
|
||||
"instance_groups": "<name>",
|
||||
"labels": "<name>++<organization.name>",
|
||||
"workflow_job_templates": "<name>++<organization.name>",
|
||||
"workflow_job_template_nodes": "<identifier>++<workflow_job_template.name>++<organization.name>",
|
||||
"applications": "<name>++<organization.name>",
|
||||
"users": "<username>",
|
||||
"instances": "<hostname>"
|
||||
},
|
||||
"LOCAL_PASSWORD_MIN_LENGTH": 0,
|
||||
"LOCAL_PASSWORD_MIN_DIGITS": 0,
|
||||
"LOCAL_PASSWORD_MIN_UPPER": 0,
|
||||
"LOCAL_PASSWORD_MIN_SPECIAL": 0,
|
||||
"NAMED_URL_GRAPH_NODES": {
|
||||
"organizations": { "fields": ["name"], "adj_list": [] },
|
||||
"teams": {
|
||||
"fields": ["name"],
|
||||
"adj_list": [["organization", "organizations"]]
|
||||
},
|
||||
"notification_templates":{"fields":["name"],"adj_list":[["organization","organizations"]]},
|
||||
"job_templates":{"fields":["name"],"adj_list":[["organization","organizations"]]},
|
||||
"projects":{"fields":["name"],"adj_list":[["organization","organizations"]]},
|
||||
"inventories":{"fields":["name"],"adj_list":[["organization","organizations"]]},
|
||||
"hosts":{"fields":["name"],"adj_list":[["inventory","inventories"]]},
|
||||
"groups":{"fields":["name"],"adj_list":[["inventory","inventories"]]},
|
||||
"inventory_sources":{"fields":["name"],"adj_list":[["inventory","inventories"]]},
|
||||
"inventory_scripts":{"fields":["name"],"adj_list":[["organization","organizations"]]},
|
||||
"instance_groups":{"fields":["name"],"adj_list":[]},
|
||||
"labels":{"fields":["name"],"adj_list":[["organization","organizations"]]},
|
||||
"workflow_job_templates":{"fields":["name"],"adj_list":[["organization","organizations"]]},
|
||||
"workflow_job_template_nodes":{
|
||||
"fields":["identifier"],
|
||||
"adj_list":[["workflow_job_template","workflow_job_templates"]]
|
||||
"credential_types": { "fields": ["name", "kind"], "adj_list": [] },
|
||||
"credentials": {
|
||||
"fields": ["name"],
|
||||
"adj_list": [
|
||||
["credential_type", "credential_types"],
|
||||
["organization", "organizations"]
|
||||
]
|
||||
},
|
||||
"applications":{"fields":["name"],"adj_list":[["organization","organizations"]]},
|
||||
"users":{"fields":["username"],"adj_list":[]},
|
||||
"instances":{"fields":["hostname"],"adj_list":[]}
|
||||
"notification_templates": {
|
||||
"fields": ["name"],
|
||||
"adj_list": [["organization", "organizations"]]
|
||||
},
|
||||
"job_templates": {
|
||||
"fields": ["name"],
|
||||
"adj_list": [["organization", "organizations"]]
|
||||
},
|
||||
"projects": {
|
||||
"fields": ["name"],
|
||||
"adj_list": [["organization", "organizations"]]
|
||||
},
|
||||
"inventories": {
|
||||
"fields": ["name"],
|
||||
"adj_list": [["organization", "organizations"]]
|
||||
},
|
||||
"hosts": { "fields": ["name"], "adj_list": [["inventory", "inventories"]] },
|
||||
"groups": {
|
||||
"fields": ["name"],
|
||||
"adj_list": [["inventory", "inventories"]]
|
||||
},
|
||||
"inventory_sources": {
|
||||
"fields": ["name"],
|
||||
"adj_list": [["inventory", "inventories"]]
|
||||
},
|
||||
"inventory_scripts": {
|
||||
"fields": ["name"],
|
||||
"adj_list": [["organization", "organizations"]]
|
||||
},
|
||||
"instance_groups": { "fields": ["name"], "adj_list": [] },
|
||||
"labels": {
|
||||
"fields": ["name"],
|
||||
"adj_list": [["organization", "organizations"]]
|
||||
},
|
||||
"workflow_job_templates": {
|
||||
"fields": ["name"],
|
||||
"adj_list": [["organization", "organizations"]]
|
||||
},
|
||||
"workflow_job_template_nodes": {
|
||||
"fields": ["identifier"],
|
||||
"adj_list": [["workflow_job_template", "workflow_job_templates"]]
|
||||
},
|
||||
"applications": {
|
||||
"fields": ["name"],
|
||||
"adj_list": [["organization", "organizations"]]
|
||||
},
|
||||
"users": { "fields": ["username"], "adj_list": [] },
|
||||
"instances": { "fields": ["hostname"], "adj_list": [] }
|
||||
},
|
||||
"DEFAULT_EXECUTION_ENVIRONMENT": 1,
|
||||
"AWX_MOUNT_ISOLATED_PATHS_ON_K8S": false,
|
||||
|
||||
@ -186,6 +186,9 @@ EXAMPLES = '''
|
||||
food: carrot
|
||||
color: orange
|
||||
limit: bar
|
||||
credentials:
|
||||
- "My Credential"
|
||||
- "suplementary cred"
|
||||
extra_vars: # these override / extend extra_data at the job level
|
||||
food: grape
|
||||
animal: owl
|
||||
|
||||
@ -159,7 +159,7 @@ def main():
|
||||
# Here we are going to setup a dict of values to export
|
||||
export_args = {}
|
||||
for resource in EXPORTABLE_RESOURCES:
|
||||
if module.params.get('all') or module.params.get(resource) == 'all':
|
||||
if module.params.get('all') or module.params.get(resource) == ['all']:
|
||||
# If we are exporting everything or we got the keyword "all" we pass in an empty string for this asset type
|
||||
export_args[resource] = ''
|
||||
else:
|
||||
|
||||
@ -151,7 +151,9 @@ EXAMPLES = '''
|
||||
job_launch:
|
||||
job_template: "My Job Template"
|
||||
inventory: "My Inventory"
|
||||
credential: "My Credential"
|
||||
credentials:
|
||||
- "My Credential"
|
||||
- "suplementary cred"
|
||||
register: job
|
||||
- name: Wait for job max 120s
|
||||
job_wait:
|
||||
|
||||
@ -337,6 +337,7 @@ EXAMPLES = '''
|
||||
playbook: "ping.yml"
|
||||
credentials:
|
||||
- "Local"
|
||||
- "2nd credential"
|
||||
state: "present"
|
||||
controller_config_file: "~/tower_cli.cfg"
|
||||
survey_enabled: yes
|
||||
|
||||
@ -461,7 +461,9 @@ EXAMPLES = '''
|
||||
failure_nodes:
|
||||
- identifier: node201
|
||||
always_nodes: []
|
||||
credentials: []
|
||||
credentials:
|
||||
- local_cred
|
||||
- suplementary cred
|
||||
- identifier: node201
|
||||
unified_job_template:
|
||||
organization:
|
||||
|
||||
@ -91,7 +91,6 @@ EXAMPLES = '''
|
||||
'''
|
||||
|
||||
from ..module_utils.controller_api import ControllerAPIModule
|
||||
import json
|
||||
|
||||
|
||||
def main():
|
||||
@ -116,15 +115,18 @@ def main():
|
||||
name = module.params.get('name')
|
||||
organization = module.params.get('organization')
|
||||
inventory = module.params.get('inventory')
|
||||
optional_args['limit'] = module.params.get('limit')
|
||||
wait = module.params.get('wait')
|
||||
interval = module.params.get('interval')
|
||||
timeout = module.params.get('timeout')
|
||||
|
||||
# Special treatment of extra_vars parameter
|
||||
extra_vars = module.params.get('extra_vars')
|
||||
if extra_vars is not None:
|
||||
optional_args['extra_vars'] = json.dumps(extra_vars)
|
||||
for field_name in (
|
||||
'limit',
|
||||
'extra_vars',
|
||||
'scm_branch',
|
||||
):
|
||||
field_val = module.params.get(field_name)
|
||||
if field_val is not None:
|
||||
optional_args[field_name] = field_val
|
||||
|
||||
# Create a datastructure to pass into our job launch
|
||||
post_data = {}
|
||||
|
||||
@ -76,3 +76,28 @@ Wait a few minutes for the periodic AWX task to do a health check against the ne
|
||||
## Removing instances
|
||||
|
||||
You can remove an instance by clicking "Remove" in the Instances page, or by setting the instance `node_state` to "deprovisioning" via the API.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Fact cache not working
|
||||
|
||||
Make sure the system timezone on the execution node matches `settings.TIME_ZONE` (default is 'UTC') on AWX.
|
||||
Fact caching relies on comparing modified times of artifact files, and these modified times are not timezone-aware. Therefore, it is critical that the timezones of the execution nodes match AWX's timezone setting.
|
||||
|
||||
To set the system timezone to UTC
|
||||
|
||||
`ln -s /usr/share/zoneinfo/Etc/UTC /etc/localtime`
|
||||
|
||||
### Permission denied errors
|
||||
|
||||
Jobs may fail with the following error
|
||||
```
|
||||
"msg":"exec container process `/usr/local/bin/entrypoint`: Permission denied"
|
||||
```
|
||||
or similar
|
||||
|
||||
For RHEL based machines, this could due to SELinux that is enabled on the system.
|
||||
|
||||
You can pass these `extra_settings` container options to override SELinux protections.
|
||||
|
||||
`DEFAULT_CONTAINER_RUN_OPTIONS = ['--network', 'slirp4netns:enable_ipv6=true', '--security-opt', 'label=disable']`
|
||||
@ -149,9 +149,8 @@ frozenlist==1.3.3
|
||||
# via
|
||||
# aiohttp
|
||||
# aiosignal
|
||||
# via
|
||||
# -r /awx_devel/requirements/requirements_git.txt
|
||||
# django-radius
|
||||
future==0.18.3
|
||||
# via django-radius
|
||||
gitdb==4.0.10
|
||||
# via gitpython
|
||||
gitpython==3.1.30
|
||||
|
||||
@ -2,6 +2,6 @@ git+https://github.com/ansible/system-certifi.git@devel#egg=certifi
|
||||
# Remove pbr from requirements.in when moving ansible-runner to requirements.in
|
||||
git+https://github.com/ansible/ansible-runner.git@devel#egg=ansible-runner
|
||||
# django-radius has an aggressive pin of future==0.16.0, see https://github.com/robgolding/django-radius/pull/25
|
||||
# There is a PR against django-radius that would fix this: https://github.com/robgolding/django-radius/pull/27
|
||||
git+https://github.com/ansible/django-radius.git@develop#egg=django-radius
|
||||
git+https://github.com/PythonCharmers/python-future@master#egg=future
|
||||
git+https://github.com/ansible/python3-saml.git@devel#egg=python3-saml
|
||||
|
||||
@ -244,6 +244,7 @@ $ make docker-compose
|
||||
- [SAML and OIDC Integration](#saml-and-oidc-integration)
|
||||
- [OpenLDAP Integration](#openldap-integration)
|
||||
- [Splunk Integration](#splunk-integration)
|
||||
- [tacacs+ Integration](#tacacs+-integration)
|
||||
|
||||
### Start a Shell
|
||||
|
||||
@ -472,6 +473,29 @@ ansible-playbook tools/docker-compose/ansible/plumb_splunk.yml
|
||||
|
||||
Once the playbook is done running Splunk should now be setup in your development environment. You can log into the admin console (see above for username/password) and click on "Searching and Reporting" in the left hand navigation. In the search box enter `source="http:tower_logging_collections"` and click search.
|
||||
|
||||
### - tacacs+ Integration
|
||||
|
||||
tacacs+ is an networking protocol that provides external authentication which can be used with AWX. This section describes how to build a reference tacacs+ instance and plumb it with your AWX for testing purposes.
|
||||
|
||||
First, be sure that you have the awx.awx collection installed by running `make install_collection`.
|
||||
|
||||
Anytime you want to run a tacacs+ instance alongside AWX we can start docker-compose with the TACACS option to get a containerized instance with the command:
|
||||
```bash
|
||||
TACACS=true make docker-compose
|
||||
```
|
||||
|
||||
Once the containers come up a new port (49) should be exposed and the tacacs+ server should be running on those ports.
|
||||
|
||||
Now we are ready to configure and plumb tacacs+ with AWX. To do this we have provided a playbook which will:
|
||||
* Backup and configure the tacacsplus adapter in AWX. NOTE: this will back up your existing settings but the password fields can not be backed up through the API, you need a DB backup to recover this.
|
||||
|
||||
```bash
|
||||
export CONTROLLER_USERNAME=<your username>
|
||||
export CONTROLLER_PASSWORD=<your password>
|
||||
ansible-playbook tools/docker-compose/ansible/plumb_tacacs.yml
|
||||
```
|
||||
|
||||
Once the playbook is done running tacacs+ should now be setup in your development environment. This server has the accounts listed on https://hub.docker.com/r/dchidell/docker-tacacs
|
||||
|
||||
### Prometheus and Grafana integration
|
||||
|
||||
|
||||
32
tools/docker-compose/ansible/plumb_tacacs.yml
Normal file
32
tools/docker-compose/ansible/plumb_tacacs.yml
Normal file
@ -0,0 +1,32 @@
|
||||
---
|
||||
- name: Plumb a tacacs+ instance
|
||||
hosts: localhost
|
||||
connection: local
|
||||
gather_facts: False
|
||||
vars:
|
||||
awx_host: "https://localhost:8043"
|
||||
tasks:
|
||||
- name: Load existing and new tacacs+ settings
|
||||
set_fact:
|
||||
existing_tacacs: "{{ lookup('awx.awx.controller_api', 'settings/tacacsplus', host=awx_host, verify_ssl=false) }}"
|
||||
new_tacacs: "{{ lookup('template', 'tacacsplus_settings.json.j2') }}"
|
||||
|
||||
- name: Display existing tacacs+ configuration
|
||||
debug:
|
||||
msg:
|
||||
- "Here is your existing tacacsplus configuration for reference:"
|
||||
- "{{ existing_tacacs }}"
|
||||
|
||||
- pause:
|
||||
prompt: "Continuing to run this will replace your existing tacacs settings (displayed above). They will all be captured. Be sure that is backed up before continuing"
|
||||
|
||||
- name: Write out the existing content
|
||||
copy:
|
||||
dest: "../_sources/existing_tacacsplus_adapter_settings.json"
|
||||
content: "{{ existing_tacacs }}"
|
||||
|
||||
- name: Configure AWX tacacs+ adapter
|
||||
awx.awx.settings:
|
||||
settings: "{{ new_tacacs }}"
|
||||
controller_host: "{{ awx_host }}"
|
||||
validate_certs: False
|
||||
@ -174,6 +174,14 @@ services:
|
||||
- prometheus
|
||||
depends_on:
|
||||
- prometheus
|
||||
{% endif %}
|
||||
{% if enable_tacacs|bool %}
|
||||
tacacs:
|
||||
image: dchidell/docker-tacacs
|
||||
container_name: tools_tacacs_1
|
||||
hostname: tacacs
|
||||
ports:
|
||||
- "49:49"
|
||||
{% endif %}
|
||||
# A useful container that simply passes through log messages to the console
|
||||
# helpful for testing awx/tower logging
|
||||
|
||||
@ -0,0 +1,7 @@
|
||||
{
|
||||
"TACACSPLUS_HOST": "tacacs",
|
||||
"TACACSPLUS_PORT": 49,
|
||||
"TACACSPLUS_SECRET": "ciscotacacskey",
|
||||
"TACACSPLUS_SESSION_TIMEOUT": 5,
|
||||
"TACACSPLUS_AUTH_PROTOCOL": "ascii"
|
||||
}
|
||||
@ -101,7 +101,7 @@ stdout_events_enabled = true
|
||||
stderr_events_enabled = true
|
||||
|
||||
[group:tower-processes]
|
||||
programs=awx-dispatcher,awx-receiver,awx-uwsgi,awx-daphne,awx-nginx,awx-wsrelay,awx-rsyslogd,awx-heartbeet, awx-rsyslog-configurer
|
||||
programs=awx-dispatcher,awx-receiver,awx-uwsgi,awx-daphne,awx-nginx,awx-wsrelay,awx-rsyslogd,awx-heartbeet,awx-rsyslog-configurer,awx-cache-clear
|
||||
priority=5
|
||||
|
||||
[program:awx-autoreload]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user