mirror of
https://github.com/ansible/awx.git
synced 2026-05-22 00:07:40 -02:30
* AAP-12516 [option 2] Handle nested workflow artifacts via root node `ancestor_artifacts` (#16381) * Add new test for artfact precedence upstream node vs outer workflow * Fix bugs, upstream artifacts come first for precedence * Track nested artifacts path through ancestor_artifacts on root nodes * Fix case where first root node did not get the vars * touchup comment * Prevent conflict with sliced jobs hack * Reorder URLs so that Django debug toolbar can work (#16352) * Reorder URLs so that Django debug toolbar can work * Move comment with URL move * feat: support for oidc credential /test endpoint (#16370) Adds support for testing external credentials that use OIDC workload identity tokens. When FEATURE_OIDC_WORKLOAD_IDENTITY_ENABLED is enabled, the /test endpoints return JWT payload details alongside test results. - Add OIDC credential test endpoints with job template selection - Return JWT payload and secret value in test response - Maintain backward compatibility (detail field for errors) - Add comprehensive unit and functional tests - Refactor shared error handling logic Co-authored-by: Daniel Finca <dfinca@redhat.com> Co-authored-by: melissalkelly <melissalkelly1@gmail.com> * Bind the install bundle to the ansible.receptor collection 2.0.8 version (#16396) * [Devel] Config Endpoint Optimization (#16389) * Improved performance of the config endpoint by reducing database queries in GET /api/controller/v2/config/ * Fix OIDC workload identity for inventory sync (#16390) The cloud credential used by inventory updates was not going through the OIDC workload identity token flow because it lives outside the normal _credentials list. This overrides populate_workload_identity_tokens in RunInventoryUpdate to include the cloud credential as an additional_credentials argument to the base implementation, and patches get_cloud_credential on the instance so the injector picks up the credential with OIDC context intact. Co-authored-by: Alan Rominger <arominge@redhat.com> Co-authored-by: Dave Mulford <dmulford@redhat.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: integrate awx-tui to the awx_devel image (#16399) * Aap 45980 (#16395) * support bitbucket_dc webhooks * add test * update docs * fix import for refactored method (#16394) retrieve_workload_identity_jwt_with_claims is now in a separate utility file, not in jobs.py Signed-off-by: Seth Foster <fosterbseth@gmail.com> * AAP-70257 controller collection should retry transient HTTP errors with exponential backoff. (#16415) controller collection should retry transient HTTP errors with exponential backoff * AAP-71844 Fix rrule fast-forward across DST boundaries (#16407) Fix rrule fast-forward producing wrong occurrences across DST boundaries The UTC round-trip in _fast_forward_rrule shifts the dtstart's local hour when the original and fast-forwarded times are in different DST periods. Since dateutil generates HOURLY occurrences by stepping in local time, the shifted hour changes the set of reachable hours. With BYHOUR constraints this causes a ValueError crash; without BYHOUR, occurrences are silently shifted by 1 hour. Fix by performing all arithmetic in the dtstart's original timezone. Python aware-datetime subtraction already computes absolute elapsed time regardless of timezone, so the UTC conversion was unnecessary for correctness and actively harmful during fall-back ambiguity. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Correctly restrict push actions to ownership repos (#16398) * Correctly restrict push actions to ownership repos * Use standard action to see if push actions should run * Run spec job for 2.6 and higher * Be even more restrictve, do not push if on a fork * [Devel] Performance Optimization for Select Hosts Query (#16413) * Fixed black reformating * Make test simulate 500k hosts in real world scenario * feat: improve unauthorized response on aap deployments (#16422) * fix: do not include secret values in the credentials test endpoint an… (#16425) fix: do not include secret values in the credentials test endpoint and add a guard to make sure credentials are testable * [devel backport] AAP-41742: Fix workflow node update failing when JT has unprompted labels (#16426) * AAP-41742: Fix workflow node update failing when JT has unprompted labels PATCH extra_data on a workflow node fails with {"labels":["Field is not configured to prompt on launch."]} when the node has labels associated but the JT has ask_labels_on_launch=False. The serializer was passing all persisted M2M state from prompts_dict() to _accept_or_ignore_job_kwargs() on every PATCH, re-validating unchanged fields. Fix scopes validation to only the fields in the request; full re-validation still occurs when unified_job_template is being changed. * Capture attrs keys before _build_mock_obj mutates them _build_mock_obj() pops pseudo-fields (limit, scm_branch, job_tags, etc.) from attrs. Computing requested_prompt_fields after the pop would miss those fields and skip their ask_on_launch validation. * Include survey_passwords when validating extra_vars prompts prompts_dict() emits survey_passwords alongside extra_vars. _accept_or_ignore_job_kwargs uses it to decrypt encrypted survey values before validation. Without it, encrypted password blobs are validated as-is against the survey spec. --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * feat: add test to ensure credential secret values are not returned (#16434) * AAP-68024 perf: derive last_job_host_summary from query instead of denormalized FK (#16332) * perf: stop eagerly updating Host.last_job_host_summary on every job completion The playbook_on_stats wrapup path bulk-updates last_job_host_summary_id on every host touched by a job. In the Q4CY25 scale lab this query had a median execution time of 75 seconds due to index churn on main_host. Replace all reads of the denormalized FK with a new classmethod JobHostSummary.latest_for_host(host_id) that queries for the most recent summary on demand. This eliminates the write-side bulk_update of last_job_host_summary_id entirely. Changes: - Add JobHostSummary.latest_for_host() classmethod - Serializer: use latest_for_host() instead of obj.last_job_host_summary - Dashboard view: use subquery instead of FK traversal for failed hosts - Inventory.update_computed_fields: use subquery for failed host count - events.py: remove last_job_host_summary_id from bulk_update - signals.py: simplify _update_host_last_jhs to only update last_job - access.py/managers.py: remove select_related/defer through the FK The FK field on Host is left in place for now (removal requires a migration) but is no longer written to. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix .pk AttributeError, add job_template annotations, annotate host sublists - Add 'pk' to AnnotatedSummary dynamic type (fixes AttributeError in get_related) - Add job_template_id and job_template_name to subquery annotations so list views include these fields in summary_fields.last_job (matching detail views) - Traverse job__ FK from JobHostSummary instead of using separate UnifiedJob subquery with OuterRef on another annotation (cleaner SQL, avoids alias issue) - Annotate all host sublist views (InventoryHostsList, GroupHostsList, GroupAllHostsList, InventorySourceHostsList) to prevent N+1 queries Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Update test_events to use JobHostSummary.latest_for_host instead of stale FKs Tests were asserting host.last_job_id and host.last_job_host_summary_id which are no longer updated. Use JobHostSummary.latest_for_host() to derive the same data, matching the new read-time derivation approach. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Remove stale failures_url from deprecated DashboardView The failures_url linked to ?last_job_host_summary__failed=True which filters on the now-stale FK. The dashboard count itself was already fixed to use a subquery annotation. Since DashboardView is deprecated and has_active_failures is a SerializerMethodField (not filterable), remove the failures_url entirely rather than creating a custom filter. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Apply black formatting to changed files Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Refactor: replace 10 subquery annotations with bulk prefetch Instead of annotating every host queryset with 10 correlated subqueries (summary + job + job_template fields), annotate only _latest_summary_id and bulk-fetch the full JobHostSummary objects after pagination via select_related('job', 'job__job_template'). This reduces the SQL from 10 correlated subqueries to 1 subquery + 1 IN query, addressing review feedback about annotation overhead on host list views. - _annotate_host_latest_summary: only annotates _latest_summary_id - _prefetch_latest_summaries: bulk-fetches and attaches to host objects - HostSummaryPrefetchMixin: hooks into list() after pagination - Serializer uses real JobHostSummary objects (no more AnnotatedSummary) - to_representation always overwrites stale FK values Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Refactor: move latest summary to QuerySet._fetch_all + Host.latest_summary Per review feedback, replace the view-level HostSummaryPrefetchMixin with a custom QuerySet that bulk-attaches summaries at evaluation time (like prefetch_related), and a Host.latest_summary property as the single access point. - HostLatestSummaryQuerySet: overrides _fetch_all() to bulk-fetch JobHostSummary objects with select_related after queryset evaluation - HostManager now inherits from the custom queryset via from_queryset() - Host.latest_summary property: uses cache if available, falls back to individual query - Remove _annotate_host_latest_summary, _prefetch_latest_summaries, HostSummaryPrefetchMixin from views — no more list() override needed - Remove last_job/last_job_host_summary from SUMMARIZABLE_FK_FIELDS - Serializer uses obj.latest_summary and DEFAULT_SUMMARY_FIELDS loop Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix: scope annotation to views, restore license_error/canceled_on - Remove with_latest_summary_id() from HostManager.get_queryset() to avoid applying the correlated subquery to every Host query globally (count, exists, internal relations) - Apply with_latest_summary_id() in get_queryset() of the 6 host-serving views only - Restore license_error and canceled_on to last_job summary fields to avoid breaking API change Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Guard _fetch_all() to skip bulk-attach on non-annotated querysets Without this guard, _fetch_all() would set _latest_summary_cache=None on every host in non-annotated querysets (e.g. Host.objects.filter()), masking the per-object fallback query in Host.latest_summary. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Remove name from last_job_host_summary and canceled_on from last_job summary Per reviewer feedback: these fields were not in the original API contract via SUMMARIZABLE_FK_FIELDS and their addition would be an API change. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add functional tests for HostLatestSummaryQuerySet and Host.latest_summary Tests cover: - with_latest_summary_id() annotation and most-recent selection - _fetch_all() bulk-attach behavior on annotated querysets - _fetch_all() skips non-annotated querysets (preserves fallback) - .count() and .exists() do NOT trigger _fetch_all - Host.latest_summary cache hits (zero queries) and fallback - Host.latest_job property - select_related on bulk-attached summaries (no N+1) - Chaining preserves annotation - Multiple jobs / partial host coverage Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Apply black formatting to test_host_queryset.py Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ben Thomasson <bthomass@redhat.com> * Fix flake8 F841: remove unused job1/job2 variables in tests Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ben Thomasson <bthomass@redhat.com> * Add comment explaining why Prefetch was not used for host latest summary Django Prefetch cannot handle latest per group -- [:1] slicing fetches 1 record globally, not per host (Django ticket #26780). The custom _fetch_all override uses the same 2-query pattern as prefetch_related internally, customized for this use case. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix null handling to keep old behavior --------- Signed-off-by: Ben Thomasson <bthomass@redhat.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: AlanCoding <arominge@redhat.com> * [AAP-72722] Use url instead of jwt_aud for workload identity audience (#16432) * [AAP-72722] Use url instead of jwt_aud for workload identity audience The OIDC credential plugin's jwt_aud field is being removed. Use the plugin's url field as the audience when requesting workload identity tokens, since the target service URL is the appropriate audience value. Assisted-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * [Devel] Optimize host_list_rbac query (#16408) * Defer ansible_facts in HostManager to avoid fetching large JSON column in host list queries (AAP-68023) The host list endpoint (GET /api/v2/hosts/) fetches the ansible_facts JSON column unnecessarily, contributing to the 7.8s median query time at scale. This column can be very large and is not used by the list serializer. Changes: - HostManager.get_queryset() now defers ansible_facts - finish_fact_cache call site uses .only(*HOST_FACTS_FIELDS) to eagerly load ansible_facts when actually needed, avoiding N+1 queries - Unit test mocks updated to support .only() queryset chaining - Points DAB dependency at the RBAC query optimization branch for combined testing Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- * fix: constructed inventories no longer increase the host count (#16433) * Fix version worktree (#16431) * git worktree friendly precomit install * worktrees don't have a .git directory. Before, docker-compose would trigger pre-commit install and fail. * make docker-compose work in git worktree * AWX tries to discover the version via info stored in .git/ dir. setuptools-scm is capable of finding the .git/ dir, starting from a worktree, but is unable because only the worktree is mapped into the container, not the .git/ dir itself. Thus, we have to detect and pass the version into the container from outside. That is why this change landed in the Makefile. * fix: as_user() gateway session cookie fallback (#16437) Add a fallback that checks for `gateway_sessionid` when no cookie matches `session_cookie_name`, mirroring the existing fallback in `Connection.login()`. The finally block now cleans up whichever cookie name was actually used. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * Pass setting to dispatcherd so it can be configured (#16438) * fix: allow blank password field to fix OpenAPI schema validation (#16440) Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * first pass porting over metrics * move settings to defaults * add more unit tests * update unit tests * lint fixes * more lint fixes * refactor and address feedback * remove the api views * remove model and move helper functions out of licensing * add settings to API, fix tests, refactoring * fix circular import * update tests * remove duplicate code, handle edge cases, use clearer naming, add test coverage * update test for changes in ship() * remove unneeded setting * _discover_org should account for verify-tls=False * directly assign settings, detect url, update tests * log errors close to occurance * rename function for clarity, focus on critical tests * rename for clarity, lint fixes * fix test params, priority for org discovery * fix test failures and linting --------- Signed-off-by: Seth Foster <fosterbseth@gmail.com> Signed-off-by: Ben Thomasson <bthomass@redhat.com> Co-authored-by: Alan Rominger <arominge@redhat.com> Co-authored-by: Daniel Finca <dfinca@redhat.com> Co-authored-by: melissalkelly <melissalkelly1@gmail.com> Co-authored-by: Tong He <68936428+unnecessary-username@users.noreply.github.com> Co-authored-by: Stevenson Michel <iamstevensonmichel@outlook.com> Co-authored-by: Seth Foster <fosterseth@users.noreply.github.com> Co-authored-by: Dave Mulford <dmulford@redhat.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Adrià Sala <22398818+adrisala@users.noreply.github.com> Co-authored-by: Peter Braun <pbraun@redhat.com> Co-authored-by: Sean Sullivan <ssulliva@redhat.com> Co-authored-by: Dirk Julich <djulich@redhat.com> Co-authored-by: Ben Thomasson <bthomass@redhat.com> Co-authored-by: Dan Leehr <dleehr@users.noreply.github.com> Co-authored-by: Lila Yasin <lyasin@redhat.com> Co-authored-by: Chris Meyers <chrismeyersfsu@users.noreply.github.com>
1224 lines
38 KiB
Python
1224 lines
38 KiB
Python
# Python
|
|
import logging
|
|
|
|
# Django
|
|
from django.core.checks import Error
|
|
from django.utils.translation import gettext_lazy as _
|
|
|
|
# Django REST Framework
|
|
from rest_framework import serializers
|
|
|
|
# AWX
|
|
from awx.conf import fields, register, register_validate
|
|
from awx.main.models import ExecutionEnvironment
|
|
from awx.main.constants import SUBSCRIPTION_USAGE_MODEL_UNIQUE_HOSTS
|
|
from awx.main.tasks.policy import OPA_AUTH_TYPES
|
|
|
|
logger = logging.getLogger('awx.main.conf')
|
|
|
|
register(
|
|
'ACTIVITY_STREAM_ENABLED',
|
|
field_class=fields.BooleanField,
|
|
label=_('Enable Activity Stream'),
|
|
help_text=_('Enable capturing activity for the activity stream.'),
|
|
category=_('System'),
|
|
category_slug='system',
|
|
)
|
|
|
|
register(
|
|
'ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC',
|
|
field_class=fields.BooleanField,
|
|
label=_('Enable Activity Stream for Inventory Sync'),
|
|
help_text=_('Enable capturing activity for the activity stream when running inventory sync.'),
|
|
category=_('System'),
|
|
category_slug='system',
|
|
)
|
|
|
|
register(
|
|
'ORG_ADMINS_CAN_SEE_ALL_USERS',
|
|
field_class=fields.BooleanField,
|
|
label=_('All Users Visible to Organization Admins'),
|
|
help_text=_('Controls whether any Organization Admin can view all users and teams, even those not associated with their Organization.'),
|
|
category=_('System'),
|
|
category_slug='system',
|
|
)
|
|
|
|
register(
|
|
'MANAGE_ORGANIZATION_AUTH',
|
|
field_class=fields.BooleanField,
|
|
label=_('Organization Admins Can Manage Users and Teams'),
|
|
help_text=_('Controls whether any Organization Admin has the privileges to create and manage users and teams.'),
|
|
category=_('System'),
|
|
category_slug='system',
|
|
)
|
|
|
|
register(
|
|
'TOWER_URL_BASE',
|
|
field_class=fields.URLField,
|
|
schemes=('http', 'https'),
|
|
allow_plain_hostname=True, # Allow hostname only without TLD.
|
|
label=_('Base URL of the service'),
|
|
help_text=_('This setting is used by services like notifications to render a valid url to the service.'),
|
|
category=_('System'),
|
|
category_slug='system',
|
|
)
|
|
|
|
register(
|
|
'REMOTE_HOST_HEADERS',
|
|
field_class=fields.StringListField,
|
|
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 AAP Installation guide '
|
|
'for more details.'
|
|
),
|
|
category=_('System'),
|
|
category_slug='system',
|
|
)
|
|
|
|
register(
|
|
'PROXY_IP_ALLOWED_LIST',
|
|
field_class=fields.StringListField,
|
|
label=_('Proxy IP Allowed List'),
|
|
help_text=_(
|
|
"If the service is behind a reverse proxy/load balancer, use this setting "
|
|
"to configure the proxy IP addresses from which the service should trust "
|
|
"custom REMOTE_HOST_HEADERS header values. "
|
|
"If this setting is an empty list (the default), the headers specified by "
|
|
"REMOTE_HOST_HEADERS will be trusted unconditionally')"
|
|
),
|
|
category=_('System'),
|
|
category_slug='system',
|
|
)
|
|
|
|
register(
|
|
'CSRF_TRUSTED_ORIGINS',
|
|
default=[],
|
|
field_class=fields.StringListField,
|
|
label=_('CSRF Trusted Origins List'),
|
|
help_text=_(
|
|
"If the service is behind a reverse proxy/load balancer, use this setting "
|
|
"to configure the schema://addresses from which the service should trust "
|
|
"Origin header values. "
|
|
),
|
|
category=_('System'),
|
|
category_slug='system',
|
|
hidden=True,
|
|
)
|
|
|
|
register(
|
|
'LICENSE',
|
|
field_class=fields.DictField,
|
|
default=lambda: {},
|
|
label=_('License'),
|
|
help_text=_('The license controls which features and functionality are enabled. Use /api/v2/config/ to update or change the license.'),
|
|
category=_('System'),
|
|
category_slug='system',
|
|
)
|
|
|
|
register(
|
|
'REDHAT_USERNAME',
|
|
field_class=fields.CharField,
|
|
default='',
|
|
allow_blank=True,
|
|
encrypted=False,
|
|
read_only=False,
|
|
label=_('Red Hat Client ID for Analytics'),
|
|
help_text=_('Client ID used to send data to Automation Analytics'),
|
|
category=_('System'),
|
|
category_slug='system',
|
|
)
|
|
|
|
register(
|
|
'REDHAT_PASSWORD',
|
|
field_class=fields.CharField,
|
|
default='',
|
|
allow_blank=True,
|
|
encrypted=True,
|
|
read_only=False,
|
|
label=_('Red Hat Client Secret for Analytics'),
|
|
help_text=_('Client secret used to send data to Automation Analytics'),
|
|
category=_('System'),
|
|
category_slug='system',
|
|
)
|
|
|
|
register(
|
|
'SUBSCRIPTIONS_USERNAME',
|
|
field_class=fields.CharField,
|
|
default='',
|
|
allow_blank=True,
|
|
encrypted=False,
|
|
read_only=False,
|
|
label=_('Red Hat Username for Subscriptions'),
|
|
help_text=_('Username used to retrieve subscription and content information'), # noqa
|
|
category=_('System'),
|
|
category_slug='system',
|
|
hidden=True,
|
|
)
|
|
|
|
register(
|
|
'SUBSCRIPTIONS_PASSWORD',
|
|
field_class=fields.CharField,
|
|
default='',
|
|
allow_blank=True,
|
|
encrypted=True,
|
|
read_only=False,
|
|
label=_('Red Hat Password for Subscriptions'),
|
|
help_text=_('Password used to retrieve subscription and content information'), # noqa
|
|
category=_('System'),
|
|
category_slug='system',
|
|
hidden=True,
|
|
)
|
|
|
|
|
|
register(
|
|
'SUBSCRIPTIONS_CLIENT_ID',
|
|
field_class=fields.CharField,
|
|
default='',
|
|
allow_blank=True,
|
|
encrypted=False,
|
|
read_only=False,
|
|
label=_('Red Hat Client ID for Subscriptions'),
|
|
help_text=_('Client ID used to retrieve subscription and content information'), # noqa
|
|
category=_('System'),
|
|
category_slug='system',
|
|
hidden=True,
|
|
)
|
|
|
|
register(
|
|
'SUBSCRIPTIONS_CLIENT_SECRET',
|
|
field_class=fields.CharField,
|
|
default='',
|
|
allow_blank=True,
|
|
encrypted=True,
|
|
read_only=False,
|
|
label=_('Red Hat Client Secret for Subscriptions'),
|
|
help_text=_('Client secret used to retrieve subscription and content information'), # noqa
|
|
category=_('System'),
|
|
category_slug='system',
|
|
hidden=True,
|
|
)
|
|
|
|
register(
|
|
'AUTOMATION_ANALYTICS_URL',
|
|
field_class=fields.URLField,
|
|
default='https://example.com',
|
|
schemes=('http', 'https'),
|
|
allow_plain_hostname=True, # Allow hostname only without TLD.
|
|
label=_('Automation Analytics upload URL'),
|
|
help_text=_('This setting is used to to configure the upload URL for data collection for Automation Analytics.'),
|
|
category=_('System'),
|
|
category_slug='system',
|
|
)
|
|
|
|
register(
|
|
'AWX_ANALYTICS_CANDLEPIN_CA',
|
|
field_class=fields.CharField,
|
|
default='/etc/rhsm/ca/redhat-uep.pem',
|
|
allow_blank=True,
|
|
label=_('Candlepin CA Certificate Path'),
|
|
help_text=_('Path to the CA certificate file for verifying TLS connections to Candlepin. Leave blank to use system certificates.'),
|
|
category=_('System'),
|
|
category_slug='system',
|
|
)
|
|
|
|
register(
|
|
'AWX_ANALYTICS_CANDLEPIN_RENEWAL_THRESHOLD_DAYS',
|
|
field_class=fields.IntegerField,
|
|
default=90,
|
|
min_value=1,
|
|
label=_('Candlepin Certificate Renewal Threshold'),
|
|
help_text=_('Number of days before certificate expiry to trigger automatic renewal of Candlepin identity certificates.'),
|
|
category=_('System'),
|
|
category_slug='system',
|
|
unit=_('days'),
|
|
)
|
|
|
|
register(
|
|
'AWX_ANALYTICS_CANDLEPIN_PROXY_URL',
|
|
field_class=fields.CharField,
|
|
default='',
|
|
allow_blank=True,
|
|
label=_('Candlepin Proxy URL'),
|
|
help_text=_('HTTP/HTTPS proxy URL for Candlepin API requests (e.g., http://proxy.example.com:8080). Leave blank for no proxy.'),
|
|
category=_('System'),
|
|
category_slug='system',
|
|
)
|
|
|
|
register(
|
|
'INSTALL_UUID',
|
|
field_class=fields.CharField,
|
|
label=_('Unique identifier for an installation'),
|
|
category=_('System'),
|
|
category_slug='system',
|
|
read_only=True,
|
|
)
|
|
|
|
register(
|
|
'DEFAULT_CONTROL_PLANE_QUEUE_NAME',
|
|
field_class=fields.CharField,
|
|
label=_('The instance group where control plane tasks run'),
|
|
category=_('System'),
|
|
category_slug='system',
|
|
read_only=True,
|
|
)
|
|
|
|
register(
|
|
'DEFAULT_EXECUTION_QUEUE_NAME',
|
|
field_class=fields.CharField,
|
|
label=_('The instance group where user jobs run (currently only on non-VM installs)'),
|
|
category=_('System'),
|
|
category_slug='system',
|
|
read_only=True,
|
|
)
|
|
|
|
register(
|
|
'DEFAULT_EXECUTION_ENVIRONMENT',
|
|
field_class=fields.PrimaryKeyRelatedField,
|
|
allow_null=True,
|
|
default=None,
|
|
queryset=ExecutionEnvironment.objects.all(),
|
|
label=_('Global default execution environment'),
|
|
help_text=_('The Execution Environment to be used when one has not been configured for a job template.'),
|
|
category=_('System'),
|
|
category_slug='system',
|
|
)
|
|
|
|
register(
|
|
'CUSTOM_VENV_PATHS',
|
|
field_class=fields.StringListPathField,
|
|
label=_('Custom virtual environment paths'),
|
|
help_text=_('Paths where Tower will look for custom virtual environments (in addition to /var/lib/awx/venv/). Enter one path per line.'),
|
|
category=_('System'),
|
|
category_slug='system',
|
|
default=[],
|
|
)
|
|
|
|
register(
|
|
'AD_HOC_COMMANDS',
|
|
field_class=fields.StringListField,
|
|
label=_('Ansible Modules Allowed for Ad Hoc Jobs'),
|
|
help_text=_('List of modules allowed to be used by ad-hoc jobs.'),
|
|
category=_('Jobs'),
|
|
category_slug='jobs',
|
|
)
|
|
|
|
register(
|
|
'ALLOW_JINJA_IN_EXTRA_VARS',
|
|
field_class=fields.ChoiceField,
|
|
choices=[
|
|
('always', _('Always')),
|
|
('never', _('Never')),
|
|
('template', _('Only On Job Template Definitions')),
|
|
],
|
|
label=_('When can extra variables contain Jinja templates?'),
|
|
help_text=_(
|
|
'Ansible allows variable substitution via the Jinja2 templating '
|
|
'language for --extra-vars. This poses a potential security '
|
|
'risk where users with the ability to specify extra vars at job '
|
|
'launch time can use Jinja2 templates to run arbitrary Python. It is '
|
|
'recommended that this value be set to "template" or "never".'
|
|
),
|
|
category=_('Jobs'),
|
|
category_slug='jobs',
|
|
)
|
|
|
|
register(
|
|
'AWX_ISOLATION_BASE_PATH',
|
|
field_class=fields.CharField,
|
|
label=_('Job execution path'),
|
|
help_text=_('The directory in which the service will create new temporary directories for job execution and isolation (such as credential files).'),
|
|
category=_('Jobs'),
|
|
category_slug='jobs',
|
|
)
|
|
|
|
register(
|
|
'AWX_ISOLATION_SHOW_PATHS',
|
|
field_class=fields.StringListIsolatedPathField,
|
|
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. '
|
|
'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',
|
|
)
|
|
|
|
register(
|
|
'AWX_TASK_ENV',
|
|
field_class=fields.KeyValueField,
|
|
default={},
|
|
label=_('Extra Environment Variables'),
|
|
help_text=_('Additional environment variables set for playbook runs, inventory updates, project updates, and notification sending.'),
|
|
category=_('Jobs'),
|
|
category_slug='jobs',
|
|
placeholder={'HTTP_PROXY': 'myproxy.local:8080'},
|
|
)
|
|
|
|
register(
|
|
'AWX_RUNNER_KEEPALIVE_SECONDS',
|
|
field_class=fields.IntegerField,
|
|
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, # intended to be under common 5 minute idle timeout
|
|
)
|
|
|
|
register(
|
|
'GALAXY_TASK_ENV',
|
|
field_class=fields.KeyValueField,
|
|
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'},
|
|
)
|
|
|
|
register(
|
|
'INSIGHTS_TRACKING_STATE',
|
|
field_class=fields.BooleanField,
|
|
default=False,
|
|
label=_('Gather data for Automation Analytics'),
|
|
help_text=_('Enables the service to gather data on automation and send it to Automation Analytics.'),
|
|
category=_('System'),
|
|
category_slug='system',
|
|
)
|
|
|
|
register(
|
|
'PROJECT_UPDATE_VVV',
|
|
field_class=fields.BooleanField,
|
|
label=_('Run Project Updates With Higher Verbosity'),
|
|
help_text=_('Adds the CLI -vvv flag to ansible-playbook runs of project_update.yml used for project updates.'),
|
|
category=_('Jobs'),
|
|
category_slug='jobs',
|
|
)
|
|
|
|
register(
|
|
'AWX_ROLES_ENABLED',
|
|
field_class=fields.BooleanField,
|
|
default=True,
|
|
label=_('Enable Role Download'),
|
|
help_text=_('Allows roles to be dynamically downloaded from a requirements.yml file for SCM projects.'),
|
|
category=_('Jobs'),
|
|
category_slug='jobs',
|
|
)
|
|
|
|
register(
|
|
'AWX_COLLECTIONS_ENABLED',
|
|
field_class=fields.BooleanField,
|
|
default=True,
|
|
label=_('Enable Collection(s) Download'),
|
|
help_text=_('Allows collections to be dynamically downloaded from a requirements.yml file for SCM projects.'),
|
|
category=_('Jobs'),
|
|
category_slug='jobs',
|
|
)
|
|
|
|
register(
|
|
'AWX_SHOW_PLAYBOOK_LINKS',
|
|
field_class=fields.BooleanField,
|
|
default=False,
|
|
label=_('Follow symlinks'),
|
|
help_text=_(
|
|
'Follow symbolic links when scanning for playbooks. Be aware that setting this to True can lead '
|
|
'to infinite recursion if a link points to a parent directory of itself.'
|
|
),
|
|
category=_('Jobs'),
|
|
category_slug='jobs',
|
|
)
|
|
|
|
register(
|
|
'AWX_MOUNT_ISOLATED_PATHS_ON_K8S',
|
|
field_class=fields.BooleanField,
|
|
default=False,
|
|
label=_('Expose host paths for Container Groups'),
|
|
help_text=_(
|
|
'Expose paths via hostPath for the Pods created by a Container Group. '
|
|
'HostPath volumes present many security risks, and it is a best practice to avoid the use of HostPaths when possible. '
|
|
),
|
|
category=_('Jobs'),
|
|
category_slug='jobs',
|
|
)
|
|
|
|
register(
|
|
'GALAXY_IGNORE_CERTS',
|
|
field_class=fields.BooleanField,
|
|
default=False,
|
|
label=_('Ignore Ansible Galaxy SSL Certificate Verification'),
|
|
help_text=_('If set to true, certificate validation will not be done when installing content from any Galaxy server.'),
|
|
category=_('Jobs'),
|
|
category_slug='jobs',
|
|
)
|
|
|
|
register(
|
|
'STDOUT_MAX_BYTES_DISPLAY',
|
|
field_class=fields.IntegerField,
|
|
min_value=0,
|
|
label=_('Standard Output Maximum Display Size'),
|
|
help_text=_('Maximum Size of Standard Output in bytes to display before requiring the output be downloaded.'),
|
|
category=_('Jobs'),
|
|
category_slug='jobs',
|
|
)
|
|
|
|
register(
|
|
'EVENT_STDOUT_MAX_BYTES_DISPLAY',
|
|
field_class=fields.IntegerField,
|
|
min_value=0,
|
|
label=_('Job Event Standard Output Maximum Display Size'),
|
|
help_text=_(
|
|
u'Maximum Size of Standard Output in bytes to display for a single job or ad hoc command event. `stdout` will end with `\u2026` when truncated.'
|
|
),
|
|
category=_('Jobs'),
|
|
category_slug='jobs',
|
|
)
|
|
|
|
register(
|
|
'MAX_WEBSOCKET_EVENT_RATE',
|
|
field_class=fields.IntegerField,
|
|
min_value=0,
|
|
default=30,
|
|
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.'),
|
|
category=_('Jobs'),
|
|
category_slug='jobs',
|
|
)
|
|
|
|
register(
|
|
'SCHEDULE_MAX_JOBS',
|
|
field_class=fields.IntegerField,
|
|
min_value=1,
|
|
label=_('Maximum Scheduled Jobs'),
|
|
help_text=_('Maximum number of the same job template that can be waiting to run when launching from a schedule before no more are created.'),
|
|
category=_('Jobs'),
|
|
category_slug='jobs',
|
|
)
|
|
|
|
register(
|
|
'AWX_ANSIBLE_CALLBACK_PLUGINS',
|
|
field_class=fields.StringListField,
|
|
label=_('Ansible Callback Plugins'),
|
|
help_text=_('List of paths to search for extra callback plugins to be used when running jobs. Enter one path per line.'),
|
|
category=_('Jobs'),
|
|
category_slug='jobs',
|
|
)
|
|
|
|
register(
|
|
'DEFAULT_JOB_TIMEOUT',
|
|
field_class=fields.IntegerField,
|
|
min_value=0,
|
|
default=0,
|
|
label=_('Default Job Timeout'),
|
|
help_text=_(
|
|
'Maximum time in seconds to allow jobs to run. Use value of 0 to indicate that no '
|
|
'timeout should be imposed. A timeout set on an individual job template will override this.'
|
|
),
|
|
category=_('Jobs'),
|
|
category_slug='jobs',
|
|
unit=_('seconds'),
|
|
)
|
|
|
|
register(
|
|
'DEFAULT_JOB_IDLE_TIMEOUT',
|
|
field_class=fields.IntegerField,
|
|
min_value=0,
|
|
default=0,
|
|
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 indicate that no idle timeout should be imposed.'
|
|
),
|
|
category=_('Jobs'),
|
|
category_slug='jobs',
|
|
unit=_('seconds'),
|
|
)
|
|
|
|
register(
|
|
'DEFAULT_INVENTORY_UPDATE_TIMEOUT',
|
|
field_class=fields.IntegerField,
|
|
min_value=0,
|
|
default=0,
|
|
label=_('Default Inventory Update Timeout'),
|
|
help_text=_(
|
|
'Maximum time in seconds to allow inventory updates to run. Use value of 0 to indicate that no '
|
|
'timeout should be imposed. A timeout set on an individual inventory source will override this.'
|
|
),
|
|
category=_('Jobs'),
|
|
category_slug='jobs',
|
|
unit=_('seconds'),
|
|
)
|
|
|
|
register(
|
|
'DEFAULT_PROJECT_UPDATE_TIMEOUT',
|
|
field_class=fields.IntegerField,
|
|
min_value=0,
|
|
default=0,
|
|
label=_('Default Project Update Timeout'),
|
|
help_text=_(
|
|
'Maximum time in seconds to allow project updates to run. Use value of 0 to indicate that no '
|
|
'timeout should be imposed. A timeout set on an individual project will override this.'
|
|
),
|
|
category=_('Jobs'),
|
|
category_slug='jobs',
|
|
unit=_('seconds'),
|
|
)
|
|
|
|
register(
|
|
'ANSIBLE_FACT_CACHE_TIMEOUT',
|
|
field_class=fields.IntegerField,
|
|
min_value=0,
|
|
default=0,
|
|
label=_('Per-Host Ansible Fact Cache Timeout'),
|
|
help_text=_(
|
|
'Maximum time, in seconds, that stored Ansible facts are considered valid since '
|
|
'the last time they were modified. Only valid, non-stale, facts will be accessible by '
|
|
'a playbook. Note, this does not influence the deletion of ansible_facts from the database. '
|
|
'Use a value of 0 to indicate that no timeout should be imposed.'
|
|
),
|
|
category=_('Jobs'),
|
|
category_slug='jobs',
|
|
unit=_('seconds'),
|
|
)
|
|
|
|
register(
|
|
'MAX_FORKS',
|
|
field_class=fields.IntegerField,
|
|
allow_null=False,
|
|
default=200,
|
|
label=_('Maximum number of forks per job'),
|
|
help_text=_('Saving a Job Template with more than this number of forks will result in an error. When set to 0, no limit is applied.'),
|
|
category=_('Jobs'),
|
|
category_slug='jobs',
|
|
)
|
|
|
|
register(
|
|
'LOG_AGGREGATOR_HOST',
|
|
field_class=fields.CharField,
|
|
allow_null=True,
|
|
default=None,
|
|
label=_('Logging Aggregator'),
|
|
help_text=_('Hostname/IP where external logs will be sent to.'),
|
|
category=_('Logging'),
|
|
category_slug='logging',
|
|
)
|
|
register(
|
|
'LOG_AGGREGATOR_PORT',
|
|
field_class=fields.IntegerField,
|
|
allow_null=True,
|
|
default=None,
|
|
label=_('Logging Aggregator Port'),
|
|
help_text=_('Port on Logging Aggregator to send logs to (if required and not provided in Logging Aggregator).'),
|
|
category=_('Logging'),
|
|
category_slug='logging',
|
|
)
|
|
register(
|
|
'LOG_AGGREGATOR_TYPE',
|
|
field_class=fields.ChoiceField,
|
|
choices=['logstash', 'splunk', 'loggly', 'sumologic', 'other'],
|
|
allow_null=True,
|
|
default=None,
|
|
label=_('Logging Aggregator Type'),
|
|
help_text=_('Format messages for the chosen log aggregator.'),
|
|
category=_('Logging'),
|
|
category_slug='logging',
|
|
)
|
|
register(
|
|
'LOG_AGGREGATOR_USERNAME',
|
|
field_class=fields.CharField,
|
|
allow_blank=True,
|
|
default='',
|
|
label=_('Logging Aggregator Username'),
|
|
help_text=_('Username for external log aggregator (if required; HTTP/s only).'),
|
|
category=_('Logging'),
|
|
category_slug='logging',
|
|
)
|
|
register(
|
|
'LOG_AGGREGATOR_PASSWORD',
|
|
field_class=fields.CharField,
|
|
allow_blank=True,
|
|
default='',
|
|
encrypted=True,
|
|
label=_('Logging Aggregator Password/Token'),
|
|
help_text=_('Password or authentication token for external log aggregator (if required; HTTP/s only).'),
|
|
category=_('Logging'),
|
|
category_slug='logging',
|
|
)
|
|
register(
|
|
'LOG_AGGREGATOR_LOGGERS',
|
|
field_class=fields.StringListField,
|
|
default=['awx', 'activity_stream', 'job_events', 'system_tracking', 'broadcast_websocket', 'job_lifecycle'],
|
|
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: \n'
|
|
'awx - service logs\n'
|
|
'activity_stream - activity stream records\n'
|
|
'job_events - callback data from Ansible job events\n'
|
|
'system_tracking - facts gathered from scan jobs\n'
|
|
'broadcast_websocket - errors pertaining to websockets broadcast metrics\n'
|
|
'job_lifecycle - logs related to processing of a job\n'
|
|
),
|
|
category=_('Logging'),
|
|
category_slug='logging',
|
|
)
|
|
register(
|
|
'LOG_AGGREGATOR_INDIVIDUAL_FACTS',
|
|
field_class=fields.BooleanField,
|
|
default=False,
|
|
label=_('Log System Tracking Facts Individually'),
|
|
help_text=_(
|
|
'If set, system tracking facts will be sent for each package, service, or '
|
|
'other item found in a scan, allowing for greater search query granularity. '
|
|
'If unset, facts will be sent as a single dictionary, allowing for greater '
|
|
'efficiency in fact processing.'
|
|
),
|
|
category=_('Logging'),
|
|
category_slug='logging',
|
|
)
|
|
register(
|
|
'LOG_AGGREGATOR_ENABLED',
|
|
field_class=fields.BooleanField,
|
|
default=False,
|
|
label=_('Enable External Logging'),
|
|
help_text=_('Enable sending logs to external log aggregator.'),
|
|
category=_('Logging'),
|
|
category_slug='logging',
|
|
)
|
|
register(
|
|
'LOG_AGGREGATOR_TOWER_UUID',
|
|
field_class=fields.CharField,
|
|
allow_blank=True,
|
|
default='',
|
|
label=_('Cluster-wide unique identifier.'),
|
|
help_text=_('Useful to uniquely identify instances.'),
|
|
category=_('Logging'),
|
|
category_slug='logging',
|
|
)
|
|
register(
|
|
'LOG_AGGREGATOR_PROTOCOL',
|
|
field_class=fields.ChoiceField,
|
|
choices=[('https', 'HTTPS/HTTP'), ('tcp', 'TCP'), ('udp', 'UDP')],
|
|
default='https',
|
|
label=_('Logging Aggregator Protocol'),
|
|
help_text=_(
|
|
'Protocol used to communicate with log aggregator. '
|
|
'HTTPS/HTTP assumes HTTPS unless http:// is explicitly used in '
|
|
'the Logging Aggregator hostname.'
|
|
),
|
|
category=_('Logging'),
|
|
category_slug='logging',
|
|
)
|
|
register(
|
|
'LOG_AGGREGATOR_TCP_TIMEOUT',
|
|
field_class=fields.IntegerField,
|
|
default=5,
|
|
label=_('TCP Connection Timeout'),
|
|
help_text=_('Number of seconds for a TCP connection to external log aggregator to timeout. Applies to HTTPS and TCP log aggregator protocols.'),
|
|
category=_('Logging'),
|
|
category_slug='logging',
|
|
unit=_('seconds'),
|
|
)
|
|
register(
|
|
'LOG_AGGREGATOR_VERIFY_CERT',
|
|
field_class=fields.BooleanField,
|
|
default=True,
|
|
label=_('Enable/disable HTTPS certificate verification'),
|
|
help_text=_(
|
|
'Flag to control enable/disable of certificate verification'
|
|
' when LOG_AGGREGATOR_PROTOCOL is "https". If enabled, the'
|
|
' log handler will verify certificate sent by external log aggregator'
|
|
' before establishing connection.'
|
|
),
|
|
category=_('Logging'),
|
|
category_slug='logging',
|
|
)
|
|
register(
|
|
'LOG_AGGREGATOR_LEVEL',
|
|
field_class=fields.ChoiceField,
|
|
choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'],
|
|
default='WARNING',
|
|
label=_('Logging Aggregator Level Threshold'),
|
|
help_text=_(
|
|
'Level threshold used by log handler. Severities from lowest to highest'
|
|
' are DEBUG, INFO, WARNING, ERROR, CRITICAL. Messages less severe '
|
|
'than the threshold will be ignored by log handler. (messages under category '
|
|
'awx.anlytics ignore this setting)'
|
|
),
|
|
category=_('Logging'),
|
|
category_slug='logging',
|
|
)
|
|
register(
|
|
'LOG_AGGREGATOR_ACTION_QUEUE_SIZE',
|
|
field_class=fields.IntegerField,
|
|
default=131072,
|
|
min_value=1,
|
|
label=_('Maximum number of messages that can be stored in the log action queue'),
|
|
help_text=_(
|
|
'Defines how large the rsyslog action queue can grow in number of messages '
|
|
'stored. This can have an impact on memory utilization. When the queue '
|
|
'reaches 75% of this number, the queue will start writing to disk '
|
|
'(queue.highWatermark in rsyslog). When it reaches 90%, NOTICE, INFO, and '
|
|
'DEBUG messages will start to be discarded (queue.discardMark with '
|
|
'queue.discardSeverity=5).'
|
|
),
|
|
category=_('Logging'),
|
|
category_slug='logging',
|
|
)
|
|
register(
|
|
'LOG_AGGREGATOR_ACTION_MAX_DISK_USAGE_GB',
|
|
field_class=fields.IntegerField,
|
|
default=1,
|
|
min_value=1,
|
|
label=_('Maximum disk persistence for rsyslogd action queuing (in GB)'),
|
|
help_text=_(
|
|
'Amount of data to store (in gigabytes) if an rsyslog action takes time '
|
|
'to process an incoming message (defaults to 1). '
|
|
'Equivalent to the rsyslogd queue.maxdiskspace setting on the action (e.g. omhttp). '
|
|
'It stores files in the directory specified by LOG_AGGREGATOR_MAX_DISK_USAGE_PATH.'
|
|
),
|
|
category=_('Logging'),
|
|
category_slug='logging',
|
|
)
|
|
register(
|
|
'LOG_AGGREGATOR_MAX_DISK_USAGE_PATH',
|
|
field_class=fields.CharField,
|
|
default='/var/lib/awx',
|
|
label=_('File system location for rsyslogd disk persistence'),
|
|
help_text=_(
|
|
'Location to persist logs that should be retried after an outage '
|
|
'of the external log aggregator (defaults to /var/lib/awx). '
|
|
'Equivalent to the rsyslogd queue.spoolDirectory setting.'
|
|
),
|
|
category=_('Logging'),
|
|
category_slug='logging',
|
|
)
|
|
register(
|
|
'LOG_AGGREGATOR_RSYSLOGD_DEBUG',
|
|
field_class=fields.BooleanField,
|
|
default=False,
|
|
label=_('Enable rsyslogd debugging'),
|
|
help_text=_('Enabled high verbosity debugging for rsyslogd. Useful for debugging connection issues for external log aggregation.'),
|
|
category=_('Logging'),
|
|
category_slug='logging',
|
|
)
|
|
register(
|
|
'API_400_ERROR_LOG_FORMAT',
|
|
field_class=fields.CharField,
|
|
default='status {status_code} received by user {user_name} attempting to access {url_path} from {remote_addr}',
|
|
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: \n'
|
|
'status_code - The HTTP status code of the error\n'
|
|
'user_name - The user name attempting to use the API\n'
|
|
'url_path - The URL path to the API endpoint called\n'
|
|
'remote_addr - The remote address seen for the user\n'
|
|
'error - The error set by the api endpoint\n'
|
|
'Variables need to be in the format {<variable name>}.'
|
|
),
|
|
category=_('Logging'),
|
|
category_slug='logging',
|
|
)
|
|
|
|
|
|
register(
|
|
'AUTOMATION_ANALYTICS_LAST_GATHER',
|
|
field_class=fields.DateTimeField,
|
|
label=_('Last gather date for Automation Analytics.'),
|
|
allow_null=True,
|
|
category=_('System'),
|
|
category_slug='system',
|
|
hidden=True,
|
|
)
|
|
register(
|
|
'AUTOMATION_ANALYTICS_LAST_ENTRIES',
|
|
field_class=fields.CharField,
|
|
label=_('Last gathered entries from the data collection service of Automation Analytics'),
|
|
default='',
|
|
allow_blank=True,
|
|
category=_('System'),
|
|
category_slug='system',
|
|
)
|
|
|
|
|
|
register(
|
|
'AUTOMATION_ANALYTICS_GATHER_INTERVAL',
|
|
field_class=fields.IntegerField,
|
|
label=_('Automation Analytics Gather Interval'),
|
|
help_text=_('Interval (in seconds) between data gathering.'),
|
|
default=14400, # every 4 hours
|
|
min_value=1800, # every 30 minutes
|
|
category=_('System'),
|
|
category_slug='system',
|
|
unit=_('seconds'),
|
|
)
|
|
|
|
register(
|
|
'CANDLEPIN_CONSUMER_UUID',
|
|
field_class=fields.CharField,
|
|
default='',
|
|
allow_blank=True,
|
|
encrypted=False,
|
|
label=_('Candlepin Consumer UUID'),
|
|
help_text=_('UUID of the registered Candlepin consumer for this AAP instance.'),
|
|
category=_('System'),
|
|
category_slug='system',
|
|
hidden=True,
|
|
)
|
|
|
|
register(
|
|
'CANDLEPIN_CERT_PEM',
|
|
field_class=fields.CharField,
|
|
default='',
|
|
allow_blank=True,
|
|
encrypted=True,
|
|
label=_('Candlepin Identity Certificate'),
|
|
help_text=_('PEM-encoded Candlepin identity certificate for mTLS authentication.'),
|
|
category=_('System'),
|
|
category_slug='system',
|
|
hidden=True,
|
|
)
|
|
|
|
register(
|
|
'CANDLEPIN_KEY_PEM',
|
|
field_class=fields.CharField,
|
|
default='',
|
|
allow_blank=True,
|
|
encrypted=True,
|
|
label=_('Candlepin Identity Key'),
|
|
help_text=_('PEM-encoded private key for Candlepin identity certificate.'),
|
|
category=_('System'),
|
|
category_slug='system',
|
|
hidden=True,
|
|
)
|
|
|
|
register(
|
|
'CANDLEPIN_SERIAL_NUMBER',
|
|
field_class=fields.CharField,
|
|
default='',
|
|
allow_blank=True,
|
|
encrypted=False,
|
|
label=_('Candlepin Certificate Serial Number'),
|
|
help_text=_('Serial number of the Candlepin identity certificate for tracking.'),
|
|
category=_('System'),
|
|
category_slug='system',
|
|
hidden=True,
|
|
)
|
|
|
|
register(
|
|
'IS_K8S',
|
|
field_class=fields.BooleanField,
|
|
read_only=True,
|
|
category=_('System'),
|
|
category_slug='system',
|
|
help_text=_('Indicates whether the instance is part of a kubernetes-based deployment.'),
|
|
)
|
|
|
|
register(
|
|
'BULK_JOB_MAX_LAUNCH',
|
|
field_class=fields.IntegerField,
|
|
default=100,
|
|
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',
|
|
hidden=True,
|
|
)
|
|
|
|
register(
|
|
'BULK_HOST_MAX_CREATE',
|
|
field_class=fields.IntegerField,
|
|
default=100,
|
|
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',
|
|
hidden=True,
|
|
)
|
|
|
|
register(
|
|
'BULK_HOST_MAX_DELETE',
|
|
field_class=fields.IntegerField,
|
|
default=250,
|
|
label=_('Max number of hosts to allow to be deleted in a single bulk action'),
|
|
help_text=_('Max number of hosts to allow to be deleted in a single bulk action'),
|
|
category=_('Bulk Actions'),
|
|
category_slug='bulk',
|
|
hidden=True,
|
|
)
|
|
|
|
|
|
register(
|
|
'SUBSCRIPTION_USAGE_MODEL',
|
|
field_class=fields.ChoiceField,
|
|
choices=[
|
|
('', _('No subscription. Deletion of host_metrics will not be considered for purposes of managed host counting')),
|
|
(
|
|
SUBSCRIPTION_USAGE_MODEL_UNIQUE_HOSTS,
|
|
_('Usage based on unique managed nodes in a large historical time frame and delete functionality for no longer used managed nodes'),
|
|
),
|
|
],
|
|
default='',
|
|
allow_blank=True,
|
|
label=_('Defines subscription usage model and shows Host Metrics'),
|
|
category=_('System'),
|
|
category_slug='system',
|
|
)
|
|
|
|
register(
|
|
'CLEANUP_HOST_METRICS_LAST_TS',
|
|
field_class=fields.DateTimeField,
|
|
label=_('Last cleanup date for HostMetrics'),
|
|
allow_null=True,
|
|
category=_('System'),
|
|
category_slug='system',
|
|
hidden=True,
|
|
)
|
|
|
|
register(
|
|
'HOST_METRIC_SUMMARY_TASK_LAST_TS',
|
|
field_class=fields.DateTimeField,
|
|
label=_('Last computing date of HostMetricSummaryMonthly'),
|
|
allow_null=True,
|
|
category=_('System'),
|
|
category_slug='system',
|
|
hidden=True,
|
|
)
|
|
|
|
register(
|
|
'AWX_CLEANUP_PATHS',
|
|
field_class=fields.BooleanField,
|
|
label=_('Enable or Disable tmp dir cleanup'),
|
|
default=True,
|
|
help_text=_('Enable or Disable TMP Dir cleanup'),
|
|
category=('Debug'),
|
|
category_slug='debug',
|
|
)
|
|
|
|
register(
|
|
'AWX_REQUEST_PROFILE',
|
|
field_class=fields.BooleanField,
|
|
label=_('Debug Web Requests'),
|
|
default=False,
|
|
help_text=_('Debug web request python timing'),
|
|
category=('Debug'),
|
|
category_slug='debug',
|
|
)
|
|
|
|
register(
|
|
'DEFAULT_CONTAINER_RUN_OPTIONS',
|
|
field_class=fields.StringListField,
|
|
label=_('Container Run Options'),
|
|
default=['--network', 'slirp4netns:enable_ipv6=true'],
|
|
help_text=_("List of options to pass to podman run example: ['--network', 'slirp4netns:enable_ipv6=true', '--log-level', 'debug']"),
|
|
category=('Jobs'),
|
|
category_slug='jobs',
|
|
)
|
|
|
|
register(
|
|
'RECEPTOR_RELEASE_WORK',
|
|
field_class=fields.BooleanField,
|
|
label=_('Release Receptor Work'),
|
|
default=True,
|
|
help_text=_('Release receptor work'),
|
|
category=('Debug'),
|
|
category_slug='debug',
|
|
)
|
|
|
|
register(
|
|
'RECEPTOR_KEEP_WORK_ON_ERROR',
|
|
field_class=fields.BooleanField,
|
|
label=_('Keep receptor work on error'),
|
|
default=False,
|
|
help_text=_('Prevent receptor work from being released on when error is detected'),
|
|
category=('Debug'),
|
|
category_slug='debug',
|
|
)
|
|
|
|
|
|
def logging_validate(serializer, attrs):
|
|
if not serializer.instance or not hasattr(serializer.instance, 'LOG_AGGREGATOR_HOST') or not hasattr(serializer.instance, 'LOG_AGGREGATOR_TYPE'):
|
|
return attrs
|
|
errors = []
|
|
if attrs.get('LOG_AGGREGATOR_ENABLED', False):
|
|
if (
|
|
not serializer.instance.LOG_AGGREGATOR_HOST
|
|
and not attrs.get('LOG_AGGREGATOR_HOST', None)
|
|
or serializer.instance.LOG_AGGREGATOR_HOST
|
|
and not attrs.get('LOG_AGGREGATOR_HOST', True)
|
|
):
|
|
errors.append('Cannot enable log aggregator without providing host.')
|
|
if (
|
|
not serializer.instance.LOG_AGGREGATOR_TYPE
|
|
and not attrs.get('LOG_AGGREGATOR_TYPE', None)
|
|
or serializer.instance.LOG_AGGREGATOR_TYPE
|
|
and not attrs.get('LOG_AGGREGATOR_TYPE', True)
|
|
):
|
|
errors.append('Cannot enable log aggregator without providing type.')
|
|
if errors:
|
|
raise serializers.ValidationError(_('\n'.join(errors)))
|
|
return attrs
|
|
|
|
|
|
register_validate('logging', logging_validate)
|
|
|
|
|
|
def csrf_trusted_origins_validate(serializer, attrs):
|
|
if not serializer.instance or not hasattr(serializer.instance, 'CSRF_TRUSTED_ORIGINS'):
|
|
return attrs
|
|
if 'CSRF_TRUSTED_ORIGINS' not in attrs:
|
|
return attrs
|
|
errors = []
|
|
for origin in attrs['CSRF_TRUSTED_ORIGINS']:
|
|
if "://" not in origin:
|
|
errors.append(
|
|
Error(
|
|
"As of Django 4.0, the values in the CSRF_TRUSTED_ORIGINS "
|
|
"setting must start with a scheme (usually http:// or "
|
|
"https://) but found %s. See the release notes for details." % origin,
|
|
)
|
|
)
|
|
if errors:
|
|
error_messages = [error.msg for error in errors]
|
|
raise serializers.ValidationError(_('\n'.join(error_messages)))
|
|
return attrs
|
|
|
|
|
|
register_validate('system', csrf_trusted_origins_validate)
|
|
|
|
|
|
register(
|
|
'OPA_HOST',
|
|
field_class=fields.CharField,
|
|
label=_('OPA server hostname'),
|
|
default='',
|
|
help_text=_('The hostname used to connect to the OPA server. If empty, policy enforcement will be disabled.'),
|
|
category=('PolicyAsCode'),
|
|
category_slug='policyascode',
|
|
allow_blank=True,
|
|
)
|
|
|
|
register(
|
|
'OPA_PORT',
|
|
field_class=fields.IntegerField,
|
|
label=_('OPA server port'),
|
|
default=8181,
|
|
help_text=_('The port used to connect to the OPA server. Defaults to 8181.'),
|
|
category=('PolicyAsCode'),
|
|
category_slug='policyascode',
|
|
)
|
|
|
|
register(
|
|
'OPA_SSL',
|
|
field_class=fields.BooleanField,
|
|
label=_('Use SSL for OPA connection'),
|
|
default=False,
|
|
help_text=_('Enable or disable the use of SSL to connect to the OPA server. Defaults to false.'),
|
|
category=('PolicyAsCode'),
|
|
category_slug='policyascode',
|
|
)
|
|
|
|
register(
|
|
'OPA_AUTH_TYPE',
|
|
field_class=fields.ChoiceField,
|
|
label=_('OPA authentication type'),
|
|
choices=[OPA_AUTH_TYPES.NONE, OPA_AUTH_TYPES.TOKEN, OPA_AUTH_TYPES.CERTIFICATE],
|
|
default=OPA_AUTH_TYPES.NONE,
|
|
help_text=_('The authentication type that will be used to connect to the OPA server: "None", "Token", or "Certificate".'),
|
|
category=('PolicyAsCode'),
|
|
category_slug='policyascode',
|
|
)
|
|
|
|
register(
|
|
'OPA_AUTH_TOKEN',
|
|
field_class=fields.CharField,
|
|
label=_('OPA authentication token'),
|
|
default='',
|
|
help_text=_(
|
|
'The token for authentication to the OPA server. Required when OPA_AUTH_TYPE is "Token". If an authorization header is defined in OPA_AUTH_CUSTOM_HEADERS, it will be overridden by OPA_AUTH_TOKEN.'
|
|
),
|
|
category=('PolicyAsCode'),
|
|
category_slug='policyascode',
|
|
allow_blank=True,
|
|
encrypted=True,
|
|
)
|
|
|
|
register(
|
|
'OPA_AUTH_CLIENT_CERT',
|
|
field_class=fields.CharField,
|
|
label=_('OPA client certificate content'),
|
|
default='',
|
|
help_text=_('The content of the client certificate file for mTLS authentication to the OPA server. Required when OPA_AUTH_TYPE is "Certificate".'),
|
|
category=('PolicyAsCode'),
|
|
category_slug='policyascode',
|
|
allow_blank=True,
|
|
)
|
|
|
|
register(
|
|
'OPA_AUTH_CLIENT_KEY',
|
|
field_class=fields.CharField,
|
|
label=_('OPA client key content'),
|
|
default='',
|
|
help_text=_('The content of the client key for mTLS authentication to the OPA server. Required when OPA_AUTH_TYPE is "Certificate".'),
|
|
category=('PolicyAsCode'),
|
|
category_slug='policyascode',
|
|
allow_blank=True,
|
|
encrypted=True,
|
|
)
|
|
|
|
register(
|
|
'OPA_AUTH_CA_CERT',
|
|
field_class=fields.CharField,
|
|
label=_('OPA CA certificate content'),
|
|
default='',
|
|
help_text=_('The content of the CA certificate for mTLS authentication to the OPA server. Required when OPA_AUTH_TYPE is "Certificate".'),
|
|
category=('PolicyAsCode'),
|
|
category_slug='policyascode',
|
|
allow_blank=True,
|
|
)
|
|
|
|
register(
|
|
'OPA_AUTH_CUSTOM_HEADERS',
|
|
field_class=fields.DictField,
|
|
label=_('OPA custom authentication headers'),
|
|
default={},
|
|
help_text=_('Optional custom headers included in requests to the OPA server. Defaults to empty dictionary ({}).'),
|
|
category=('PolicyAsCode'),
|
|
category_slug='policyascode',
|
|
)
|
|
|
|
register(
|
|
'OPA_REQUEST_TIMEOUT',
|
|
field_class=fields.FloatField,
|
|
label=_('OPA request timeout'),
|
|
default=1.5,
|
|
help_text=_('The number of seconds after which the connection to the OPA server will time out. Defaults to 1.5 seconds.'),
|
|
category=('PolicyAsCode'),
|
|
category_slug='policyascode',
|
|
)
|
|
|
|
register(
|
|
'OPA_REQUEST_RETRIES',
|
|
field_class=fields.IntegerField,
|
|
label=_('OPA request retry count'),
|
|
default=2,
|
|
help_text=_('The number of retry attempts for connecting to the OPA server. Default is 2.'),
|
|
category=('PolicyAsCode'),
|
|
category_slug='policyascode',
|
|
)
|
|
|
|
|
|
def policy_as_code_validate(serializer, attrs):
|
|
opa_host = attrs.get('OPA_HOST', '')
|
|
if opa_host and (opa_host.startswith('http://') or opa_host.startswith('https://')):
|
|
raise serializers.ValidationError({'OPA_HOST': _("OPA_HOST should not include 'http://' or 'https://' prefixes. Please enter only the hostname.")})
|
|
return attrs
|
|
|
|
|
|
register_validate('policyascode', policy_as_code_validate)
|