diff --git a/.dockerignore b/.dockerignore
index f5faf1f0e3..46c83b0467 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -1,2 +1 @@
-.git
awx/ui/node_modules
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index bd3da38b51..e311ecfa1c 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -85,7 +85,7 @@ If you're not using Docker for Mac, or Docker for Windows, you may need, or choo
#### Frontend Development
-See [the ui development documentation](awx/ui/README.md).
+See [the ui development documentation](awx/ui_next/CONTRIBUTING.md).
### Build the environment
@@ -158,7 +158,7 @@ $ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
44251b476f98 gcr.io/ansible-tower-engineering/awx_devel:devel "/entrypoint.sh /bin…" 27 seconds ago Up 23 seconds 0.0.0.0:6899->6899/tcp, 0.0.0.0:7899-7999->7899-7999/tcp, 0.0.0.0:8013->8013/tcp, 0.0.0.0:8043->8043/tcp, 0.0.0.0:8080->8080/tcp, 22/tcp, 0.0.0.0:8888->8888/tcp tools_awx_run_9e820694d57e
40de380e3c2e redis:latest "docker-entrypoint.s…" 28 seconds ago Up 26 seconds
-b66a506d3007 postgres:10 "docker-entrypoint.s…" 28 seconds ago Up 26 seconds 0.0.0.0:5432->5432/tcp tools_postgres_1
+b66a506d3007 postgres:12 "docker-entrypoint.s…" 28 seconds ago Up 26 seconds 0.0.0.0:5432->5432/tcp tools_postgres_1
```
**NOTE**
diff --git a/Makefile b/Makefile
index 783547930f..9c7ccd028b 100644
--- a/Makefile
+++ b/Makefile
@@ -19,7 +19,8 @@ PYCURL_SSL_LIBRARY ?= openssl
COMPOSE_TAG ?= $(GIT_BRANCH)
COMPOSE_HOST ?= $(shell hostname)
-VENV_BASE ?= /venv
+VENV_BASE ?= /var/lib/awx/venv/
+COLLECTION_BASE ?= /var/lib/awx/vendor/awx_ansible_collections
SCL_PREFIX ?=
CELERY_SCHEDULE_FILE ?= /var/lib/awx/beat.db
@@ -270,7 +271,7 @@ uwsgi: collectstatic
@if [ "$(VENV_BASE)" ]; then \
. $(VENV_BASE)/awx/bin/activate; \
fi; \
- uwsgi -b 32768 --socket 127.0.0.1:8050 --module=awx.wsgi:application --home=/venv/awx --chdir=/awx_devel/ --vacuum --processes=5 --harakiri=120 --master --no-orphans --py-autoreload 1 --max-requests=1000 --stats /tmp/stats.socket --lazy-apps --logformat "%(addr) %(method) %(uri) - %(proto) %(status)" --hook-accepting1="exec:supervisorctl restart tower-processes:awx-dispatcher tower-processes:awx-receiver"
+ uwsgi -b 32768 --socket 127.0.0.1:8050 --module=awx.wsgi:application --home=/var/lib/awx/venv/awx --chdir=/awx_devel/ --vacuum --processes=5 --harakiri=120 --master --no-orphans --py-autoreload 1 --max-requests=1000 --stats /tmp/stats.socket --lazy-apps --logformat "%(addr) %(method) %(uri) - %(proto) %(status)" --hook-accepting1="exec:supervisorctl restart tower-processes:awx-dispatcher tower-processes:awx-receiver"
daphne:
@if [ "$(VENV_BASE)" ]; then \
@@ -340,7 +341,7 @@ check: flake8 pep8 # pyflakes pylint
awx-link:
[ -d "/awx_devel/awx.egg-info" ] || python3 /awx_devel/setup.py egg_info_dev
- cp -f /tmp/awx.egg-link /venv/awx/lib/python$(PYTHON_VERSION)/site-packages/awx.egg-link
+ cp -f /tmp/awx.egg-link /var/lib/awx/venv/awx/lib/python$(PYTHON_VERSION)/site-packages/awx.egg-link
TEST_DIRS ?= awx/main/tests/unit awx/main/tests/functional awx/conf/tests awx/sso/tests
@@ -618,7 +619,10 @@ clean-elk:
docker rm tools_kibana_1
psql-container:
- docker run -it --net tools_default --rm postgres:10 sh -c 'exec psql -h "postgres" -p "5432" -U postgres'
+ docker run -it --net tools_default --rm postgres:12 sh -c 'exec psql -h "postgres" -p "5432" -U postgres'
VERSION:
@echo "awx: $(VERSION)"
+
+Dockerfile: installer/roles/image_build/templates/Dockerfile.j2
+ ansible localhost -m template -a "src=installer/roles/image_build/templates/Dockerfile.j2 dest=Dockerfile"
diff --git a/README.md b/README.md
index 23249c35e6..e24e851ce1 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,5 @@
[](https://ansible.softwarefactory-project.io/zuul/status)
-
-
AWX provides a web-based user interface, REST API, and task engine built on top of [Ansible](https://github.com/ansible/ansible). It is the upstream project for [Tower](https://www.ansible.com/tower), a commercial derivative of AWX.
To install AWX, please view the [Install guide](./INSTALL.md).
diff --git a/awx/conf/settings.py b/awx/conf/settings.py
index d2733ce879..4b18e3d9f6 100644
--- a/awx/conf/settings.py
+++ b/awx/conf/settings.py
@@ -4,6 +4,7 @@ import logging
import sys
import threading
import time
+import os
# Django
from django.conf import LazySettings
@@ -247,6 +248,7 @@ class SettingsWrapper(UserSettingsHolder):
# These values have to be stored via self.__dict__ in this way to get
# around the magic __setattr__ method on this class (which is used to
# store API-assigned settings in the database).
+ self.__dict__['__forks__'] = {}
self.__dict__['default_settings'] = default_settings
self.__dict__['_awx_conf_settings'] = self
self.__dict__['_awx_conf_preload_expires'] = None
@@ -255,6 +257,26 @@ class SettingsWrapper(UserSettingsHolder):
self.__dict__['cache'] = EncryptedCacheProxy(cache, registry)
self.__dict__['registry'] = registry
+ # record the current pid so we compare it post-fork for
+ # processes like the dispatcher and callback receiver
+ self.__dict__['pid'] = os.getpid()
+
+ def __clean_on_fork__(self):
+ pid = os.getpid()
+ # if the current pid does *not* match the value on self, it means
+ # that value was copied on fork, and we're now in a *forked* process;
+ # the *first* time we enter this code path (on setting access),
+ # forcibly close DB/cache sockets and set a marker so we don't run
+ # this code again _in this process_
+ #
+ if pid != self.__dict__['pid'] and pid not in self.__dict__['__forks__']:
+ self.__dict__['__forks__'][pid] = True
+ # It's important to close these post-fork, because we
+ # don't want the forked processes to inherit the open sockets
+ # for the DB and cache connections (that way lies race conditions)
+ connection.close()
+ django_cache.close()
+
@cached_property
def all_supported_settings(self):
return self.registry.get_registered_settings()
@@ -330,6 +352,7 @@ class SettingsWrapper(UserSettingsHolder):
self.cache.set_many(settings_to_cache, timeout=SETTING_CACHE_TIMEOUT)
def _get_local(self, name, validate=True):
+ self.__clean_on_fork__()
self._preload_cache()
cache_key = Setting.get_cache_key(name)
try:
diff --git a/awx/locale/django.pot b/awx/locale/django.pot
index 3d2cf41999..e5fbe05390 100644
--- a/awx/locale/django.pot
+++ b/awx/locale/django.pot
@@ -3354,6 +3354,15 @@ msgid ""
"common scenarios."
msgstr ""
+#: awx/main/models/credential/__init__.py:824
+msgid "Region Name"
+msgstr ""
+
+#: awx/main/models/credential/__init__.py:826
+msgid ""
+"For some cloud providers, like OVH, region must be specified."
+msgstr ""
+
#: awx/main/models/credential/__init__.py:824
#: awx/main/models/credential/__init__.py:1131
#: awx/main/models/credential/__init__.py:1166
diff --git a/awx/locale/en-us/LC_MESSAGES/django.po b/awx/locale/en-us/LC_MESSAGES/django.po
index 3d2cf41999..e5fbe05390 100644
--- a/awx/locale/en-us/LC_MESSAGES/django.po
+++ b/awx/locale/en-us/LC_MESSAGES/django.po
@@ -3354,6 +3354,15 @@ msgid ""
"common scenarios."
msgstr ""
+#: awx/main/models/credential/__init__.py:824
+msgid "Region Name"
+msgstr ""
+
+#: awx/main/models/credential/__init__.py:826
+msgid ""
+"For some cloud providers, like OVH, region must be specified."
+msgstr ""
+
#: awx/main/models/credential/__init__.py:824
#: awx/main/models/credential/__init__.py:1131
#: awx/main/models/credential/__init__.py:1166
diff --git a/awx/locale/fr/LC_MESSAGES/django.po b/awx/locale/fr/LC_MESSAGES/django.po
index 62c2ba7292..bcb54c548b 100644
--- a/awx/locale/fr/LC_MESSAGES/django.po
+++ b/awx/locale/fr/LC_MESSAGES/django.po
@@ -3294,6 +3294,16 @@ msgid ""
"common scenarios."
msgstr "Les domaines OpenStack définissent les limites administratives. Ils sont nécessaires uniquement pour les URL d’authentification Keystone v3. Voir la documentation Ansible Tower pour les scénarios courants."
+#: awx/main/models/credential/__init__.py:824
+msgid "Region Name"
+msgstr "Nom de la region"
+
+#: awx/main/models/credential/__init__.py:826
+msgid ""
+"For some cloud providers, like OVH, region must be specified."
+msgstr ""
+"Chez certains fournisseurs, comme OVH, vous devez spécifier le nom de la région"
+
#: awx/main/models/credential/__init__.py:812
#: awx/main/models/credential/__init__.py:1110
#: awx/main/models/credential/__init__.py:1144
diff --git a/awx/main/isolated/manager.py b/awx/main/isolated/manager.py
index 1c0978f432..de4783e277 100644
--- a/awx/main/isolated/manager.py
+++ b/awx/main/isolated/manager.py
@@ -7,6 +7,7 @@ import tempfile
import time
import logging
import yaml
+import datetime
from django.conf import settings
import ansible_runner
@@ -123,6 +124,7 @@ class IsolatedManager(object):
dir=private_data_dir
)
params = self.runner_params.copy()
+ params.get('envvars', dict())['ANSIBLE_CALLBACK_WHITELIST'] = 'profile_tasks'
params['playbook'] = playbook
params['private_data_dir'] = iso_dir
if idle_timeout:
@@ -168,7 +170,8 @@ class IsolatedManager(object):
extravars = {
'src': self.private_data_dir,
'dest': settings.AWX_PROOT_BASE_PATH,
- 'ident': self.ident
+ 'ident': self.ident,
+ 'job_id': self.instance.id,
}
if playbook:
extravars['playbook'] = playbook
@@ -204,7 +207,10 @@ class IsolatedManager(object):
:param interval: an interval (in seconds) to wait between status polls
"""
interval = interval if interval is not None else settings.AWX_ISOLATED_CHECK_INTERVAL
- extravars = {'src': self.private_data_dir}
+ extravars = {
+ 'src': self.private_data_dir,
+ 'job_id': self.instance.id
+ }
status = 'failed'
rc = None
last_check = time.time()
@@ -220,9 +226,13 @@ class IsolatedManager(object):
logger.warning('Isolated job {} was manually canceled.'.format(self.instance.id))
logger.debug('Checking on isolated job {} with `check_isolated.yml`.'.format(self.instance.id))
+ time_start = datetime.datetime.now()
runner_obj = self.run_management_playbook('check_isolated.yml',
self.private_data_dir,
extravars=extravars)
+ time_end = datetime.datetime.now()
+ time_diff = time_end - time_start
+ logger.debug('Finished checking on isolated job {} with `check_isolated.yml` took {} seconds.'.format(self.instance.id, time_diff.total_seconds()))
status, rc = runner_obj.status, runner_obj.rc
if self.check_callback is not None and not self.captured_command_artifact:
diff --git a/awx/main/management/commands/inventory_import.py b/awx/main/management/commands/inventory_import.py
index 30529cdf72..a86cc3db48 100644
--- a/awx/main/management/commands/inventory_import.py
+++ b/awx/main/management/commands/inventory_import.py
@@ -133,7 +133,7 @@ class AnsibleInventoryLoader(object):
# NOTE: why do we add "python" to the start of these args?
# the script that runs ansible-inventory specifies a python interpreter
# that makes no sense in light of the fact that we put all the dependencies
- # inside of /venv/ansible, so we override the specified interpreter
+ # inside of /var/lib/awx/venv/ansible, so we override the specified interpreter
# https://github.com/ansible/ansible/issues/50714
bargs = ['python', ansible_inventory_path, '-i', self.source]
bargs.extend(['--playbook-dir', functioning_dir(self.source)])
diff --git a/awx/main/models/credential/__init__.py b/awx/main/models/credential/__init__.py
index 66db962430..e8a2884083 100644
--- a/awx/main/models/credential/__init__.py
+++ b/awx/main/models/credential/__init__.py
@@ -819,6 +819,11 @@ ManagedCredentialType(
'It is only needed for Keystone v3 authentication '
'URLs. Refer to Ansible Tower documentation for '
'common scenarios.')
+ }, {
+ 'id': 'region',
+ 'label': ugettext_noop('Region Name'),
+ 'type': 'string',
+ 'help_text': ugettext_noop('For some cloud providers, like OVH, region must be specified'),
}, {
'id': 'verify_ssl',
'label': ugettext_noop('Verify SSL'),
diff --git a/awx/main/models/credential/injectors.py b/awx/main/models/credential/injectors.py
index 75d1f17bfe..ef30b91945 100644
--- a/awx/main/models/credential/injectors.py
+++ b/awx/main/models/credential/injectors.py
@@ -82,6 +82,7 @@ def _openstack_data(cred):
if cred.has_input('domain'):
openstack_auth['domain_name'] = cred.get_input('domain', default='')
verify_state = cred.get_input('verify_ssl', default=True)
+
openstack_data = {
'clouds': {
'devstack': {
@@ -90,6 +91,10 @@ def _openstack_data(cred):
},
},
}
+
+ if cred.has_input('project_region_name'):
+ openstack_data['clouds']['devstack']['region_name'] = cred.get_input('project_region_name', default='')
+
return openstack_data
diff --git a/awx/main/models/notifications.py b/awx/main/models/notifications.py
index 11d97c7690..33562e7fca 100644
--- a/awx/main/models/notifications.py
+++ b/awx/main/models/notifications.py
@@ -12,7 +12,7 @@ from django.core.mail.message import EmailMessage
from django.db import connection
from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import smart_str, force_text
-from jinja2 import sandbox
+from jinja2 import sandbox, ChainableUndefined
from jinja2.exceptions import TemplateSyntaxError, UndefinedError, SecurityError
# AWX
@@ -429,7 +429,7 @@ class JobNotificationMixin(object):
raise RuntimeError("Define me")
def build_notification_message(self, nt, status):
- env = sandbox.ImmutableSandboxedEnvironment()
+ env = sandbox.ImmutableSandboxedEnvironment(undefined=ChainableUndefined)
from awx.api.serializers import UnifiedJobSerializer
job_serialization = UnifiedJobSerializer(self).to_representation(self)
diff --git a/awx/main/tasks.py b/awx/main/tasks.py
index 3bf67d9e65..1fb7d62cef 100644
--- a/awx/main/tasks.py
+++ b/awx/main/tasks.py
@@ -378,6 +378,7 @@ def gather_analytics():
from awx.conf.models import Setting
from rest_framework.fields import DateTimeField
+ from awx.main.signals import disable_activity_stream
if not settings.INSIGHTS_TRACKING_STATE:
return
if not (settings.AUTOMATION_ANALYTICS_URL and settings.REDHAT_USERNAME and settings.REDHAT_PASSWORD):
@@ -414,7 +415,8 @@ def gather_analytics():
if not _gather_and_ship(incremental_collectors, since=start, until=until):
break
start = until
- settings.AUTOMATION_ANALYTICS_LAST_GATHER = until
+ with disable_activity_stream():
+ settings.AUTOMATION_ANALYTICS_LAST_GATHER = until
if subset:
_gather_and_ship(subset, since=since, until=gather_time)
diff --git a/awx/main/tests/functional/models/test_job.py b/awx/main/tests/functional/models/test_job.py
index ac8912506f..c6c4d2d6e6 100644
--- a/awx/main/tests/functional/models/test_job.py
+++ b/awx/main/tests/functional/models/test_job.py
@@ -16,7 +16,7 @@ def test_awx_virtualenv_from_settings(inventory, project, machine_credential):
)
jt.credentials.add(machine_credential)
job = jt.create_unified_job()
- assert job.ansible_virtualenv_path == '/venv/ansible'
+ assert job.ansible_virtualenv_path == '/var/lib/awx/venv/ansible'
@pytest.mark.django_db
@@ -43,28 +43,28 @@ def test_awx_custom_virtualenv(inventory, project, machine_credential, organizat
jt.credentials.add(machine_credential)
job = jt.create_unified_job()
- job.organization.custom_virtualenv = '/venv/fancy-org'
+ job.organization.custom_virtualenv = '/var/lib/awx/venv/fancy-org'
job.organization.save()
- assert job.ansible_virtualenv_path == '/venv/fancy-org'
+ assert job.ansible_virtualenv_path == '/var/lib/awx/venv/fancy-org'
- job.project.custom_virtualenv = '/venv/fancy-proj'
+ job.project.custom_virtualenv = '/var/lib/awx/venv/fancy-proj'
job.project.save()
- assert job.ansible_virtualenv_path == '/venv/fancy-proj'
+ assert job.ansible_virtualenv_path == '/var/lib/awx/venv/fancy-proj'
- job.job_template.custom_virtualenv = '/venv/fancy-jt'
+ job.job_template.custom_virtualenv = '/var/lib/awx/venv/fancy-jt'
job.job_template.save()
- assert job.ansible_virtualenv_path == '/venv/fancy-jt'
+ assert job.ansible_virtualenv_path == '/var/lib/awx/venv/fancy-jt'
@pytest.mark.django_db
def test_awx_custom_virtualenv_without_jt(project):
- project.custom_virtualenv = '/venv/fancy-proj'
+ project.custom_virtualenv = '/var/lib/awx/venv/fancy-proj'
project.save()
job = Job(project=project)
job.save()
job = Job.objects.get(pk=job.id)
- assert job.ansible_virtualenv_path == '/venv/fancy-proj'
+ assert job.ansible_virtualenv_path == '/var/lib/awx/venv/fancy-proj'
@pytest.mark.django_db
diff --git a/awx/main/tests/unit/test_tasks.py b/awx/main/tests/unit/test_tasks.py
index f94c70c739..166ea95f19 100644
--- a/awx/main/tests/unit/test_tasks.py
+++ b/awx/main/tests/unit/test_tasks.py
@@ -180,7 +180,7 @@ def test_openstack_client_config_generation(mocker, source, expected, private_da
'source_vars_dict': {},
'get_cloud_credential': mocker.Mock(return_value=credential),
'get_extra_credentials': lambda x: [],
- 'ansible_virtualenv_path': '/venv/foo'
+ 'ansible_virtualenv_path': '/var/lib/awx/venv/foo'
})
cloud_config = update.build_private_data(inventory_update, private_data_dir)
cloud_credential = yaml.safe_load(
@@ -224,6 +224,52 @@ def test_openstack_client_config_generation_with_project_domain_name(mocker, sou
'source_vars_dict': {},
'get_cloud_credential': mocker.Mock(return_value=credential),
'get_extra_credentials': lambda x: [],
+ 'ansible_virtualenv_path': '/var/lib/awx/venv/foo'
+ })
+ cloud_config = update.build_private_data(inventory_update, private_data_dir)
+ cloud_credential = yaml.safe_load(
+ cloud_config.get('credentials')[credential]
+ )
+ assert cloud_credential['clouds'] == {
+ 'devstack': {
+ 'auth': {
+ 'auth_url': 'https://keystone.openstack.example.org',
+ 'password': 'secrete',
+ 'project_name': 'demo-project',
+ 'username': 'demo',
+ 'domain_name': 'my-demo-domain',
+ 'project_domain_name': 'project-domain',
+ },
+ 'verify': expected,
+ 'private': True,
+ }
+ }
+
+
+@pytest.mark.parametrize("source,expected", [
+ (None, True), (False, False), (True, True)
+])
+def test_openstack_client_config_generation_with_project_region_name(mocker, source, expected, private_data_dir):
+ update = tasks.RunInventoryUpdate()
+ credential_type = CredentialType.defaults['openstack']()
+ inputs = {
+ 'host': 'https://keystone.openstack.example.org',
+ 'username': 'demo',
+ 'password': 'secrete',
+ 'project': 'demo-project',
+ 'domain': 'my-demo-domain',
+ 'project_domain_name': 'project-domain',
+ 'project_region_name': 'region-name',
+ }
+ if source is not None:
+ inputs['verify_ssl'] = source
+ credential = Credential(pk=1, credential_type=credential_type, inputs=inputs)
+
+ inventory_update = mocker.Mock(**{
+ 'source': 'openstack',
+ 'source_vars_dict': {},
+ 'get_cloud_credential': mocker.Mock(return_value=credential),
+ 'get_extra_credentials': lambda x: [],
'ansible_virtualenv_path': '/venv/foo'
})
cloud_config = update.build_private_data(inventory_update, private_data_dir)
@@ -242,6 +288,7 @@ def test_openstack_client_config_generation_with_project_domain_name(mocker, sou
},
'verify': expected,
'private': True,
+ 'region_name': 'region-name',
}
}
@@ -267,7 +314,7 @@ def test_openstack_client_config_generation_with_private_source_vars(mocker, sou
'source_vars_dict': {'private': source},
'get_cloud_credential': mocker.Mock(return_value=credential),
'get_extra_credentials': lambda x: [],
- 'ansible_virtualenv_path': '/venv/foo'
+ 'ansible_virtualenv_path': '/var/lib/awx/venv/foo'
})
cloud_config = update.build_private_data(inventory_update, private_data_dir)
cloud_credential = yaml.load(
@@ -625,13 +672,13 @@ class TestGenericRun():
def test_invalid_custom_virtualenv(self, patch_Job, private_data_dir):
job = Job(project=Project(), inventory=Inventory())
- job.project.custom_virtualenv = '/venv/missing'
+ job.project.custom_virtualenv = '/var/lib/awx/venv/missing'
task = tasks.RunJob()
with pytest.raises(tasks.InvalidVirtualenvError) as e:
task.build_env(job, private_data_dir)
- assert 'Invalid virtual environment selected: /venv/missing' == str(e.value)
+ assert 'Invalid virtual environment selected: /var/lib/awx/venv/missing' == str(e.value)
class TestAdhocRun(TestJobExecution):
diff --git a/awx/playbooks/check_isolated.yml b/awx/playbooks/check_isolated.yml
index 18b3305846..472b772fbb 100644
--- a/awx/playbooks/check_isolated.yml
+++ b/awx/playbooks/check_isolated.yml
@@ -9,6 +9,9 @@
- ansible.posix
tasks:
+ - name: "Output job the playbook is running for"
+ debug:
+ msg: "Checking on job {{ job_id }}"
- name: Determine if daemon process is alive.
shell: "ansible-runner is-alive {{src}}"
diff --git a/awx/playbooks/run_isolated.yml b/awx/playbooks/run_isolated.yml
index 4e3b7b54ee..76ea42d17c 100644
--- a/awx/playbooks/run_isolated.yml
+++ b/awx/playbooks/run_isolated.yml
@@ -13,6 +13,10 @@
- ansible.posix
tasks:
+ - name: "Output job the playbook is running for"
+ debug:
+ msg: "Checking on job {{ job_id }}"
+
- name: synchronize job environment with isolated host
synchronize:
copy_links: true
diff --git a/awx/settings/defaults.py b/awx/settings/defaults.py
index b9e7ecddb7..05c8a42f20 100644
--- a/awx/settings/defaults.py
+++ b/awx/settings/defaults.py
@@ -116,7 +116,7 @@ LOGIN_URL = '/api/login/'
# Absolute filesystem path to the directory to host projects (with playbooks).
# This directory should not be web-accessible.
-PROJECTS_ROOT = os.path.join(BASE_DIR, 'projects')
+PROJECTS_ROOT = '/var/lib/awx/projects/'
# Absolute filesystem path to the directory to host collections for
# running inventory imports, isolated playbooks
@@ -125,10 +125,10 @@ AWX_ANSIBLE_COLLECTIONS_PATHS = os.path.join(BASE_DIR, 'vendor', 'awx_ansible_co
# Absolute filesystem path to the directory for job status stdout (default for
# development and tests, default for production defined in production.py). This
# directory should not be web-accessible
-JOBOUTPUT_ROOT = os.path.join(BASE_DIR, 'job_output')
+JOBOUTPUT_ROOT = '/var/lib/awx/job_status/'
# Absolute filesystem path to the directory to store logs
-LOG_ROOT = os.path.join(BASE_DIR)
+LOG_ROOT = '/var/log/tower/'
# The heartbeat file for the tower scheduler
SCHEDULE_METADATA_LOCATION = os.path.join(BASE_DIR, '.tower_cycle')
@@ -932,6 +932,14 @@ LOGGING = {
'backupCount': 5,
'formatter':'simple',
},
+ 'isolated_manager': {
+ 'level': 'WARNING',
+ 'class':'logging.handlers.RotatingFileHandler',
+ 'filename': os.path.join(LOG_ROOT, 'isolated_manager.log'),
+ 'maxBytes': 1024 * 1024 * 5, # 5 MB
+ 'backupCount': 5,
+ 'formatter':'simple',
+ },
},
'loggers': {
'django': {
@@ -981,6 +989,11 @@ LOGGING = {
'awx.main.wsbroadcast': {
'handlers': ['wsbroadcast'],
},
+ 'awx.isolated.manager': {
+ 'level': 'WARNING',
+ 'handlers': ['console', 'file', 'isolated_manager'],
+ 'propagate': True
+ },
'awx.isolated.manager.playbooks': {
'handlers': ['management_playbooks'],
'propagate': False
diff --git a/awx/settings/development.py b/awx/settings/development.py
index 108767b98c..9846705fa5 100644
--- a/awx/settings/development.py
+++ b/awx/settings/development.py
@@ -148,9 +148,9 @@ include(optional('/etc/tower/settings.py'), scope=locals())
include(optional('/etc/tower/conf.d/*.py'), scope=locals())
# Installed differently in Dockerfile compared to production versions
-AWX_ANSIBLE_COLLECTIONS_PATHS = '/vendor/awx_ansible_collections'
+AWX_ANSIBLE_COLLECTIONS_PATHS = '/var/lib/awx/vendor/awx_ansible_collections'
-BASE_VENV_PATH = "/venv/"
+BASE_VENV_PATH = "/var/lib/awx/venv/"
ANSIBLE_VENV_PATH = os.path.join(BASE_VENV_PATH, "ansible")
AWX_VENV_PATH = os.path.join(BASE_VENV_PATH, "awx")
diff --git a/awx/settings/local_settings.py.docker_compose b/awx/settings/local_settings.py.docker_compose
index 213f4efe4b..88ef90fd64 100644
--- a/awx/settings/local_settings.py.docker_compose
+++ b/awx/settings/local_settings.py.docker_compose
@@ -48,56 +48,12 @@ if "pytest" in sys.modules:
}
}
-# Absolute filesystem path to the directory to host projects (with playbooks).
-# This directory should NOT be web-accessible.
-PROJECTS_ROOT = '/var/lib/awx/projects/'
-
# Location for cross-development of inventory plugins
-AWX_ANSIBLE_COLLECTIONS_PATHS = '/vendor/awx_ansible_collections'
-
-# Absolute filesystem path to the directory for job status stdout
-# This directory should not be web-accessible
-JOBOUTPUT_ROOT = os.path.join(BASE_DIR, 'job_status')
+AWX_ANSIBLE_COLLECTIONS_PATHS = '/var/lib/awx/vendor/awx_ansible_collections'
# The UUID of the system, for HA.
SYSTEM_UUID = '00000000-0000-0000-0000-000000000000'
-# Local time zone for this installation. Choices can be found here:
-# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
-# although not all choices may be available on all operating systems.
-# On Unix systems, a value of None will cause Django to use the same
-# timezone as the operating system.
-# If running in a Windows environment this must be set to the same as your
-# system time zone.
-USE_TZ = True
-TIME_ZONE = 'UTC'
-
-# Language code for this installation. All choices can be found here:
-# http://www.i18nguy.com/unicode/language-identifiers.html
-LANGUAGE_CODE = 'en-us'
-
-# SECURITY WARNING: keep the secret key used in production secret!
-# Hardcoded values can leak through source control. Consider loading
-# the secret key from an environment variable or a file instead.
-SECRET_KEY = 'p7z7g1ql4%6+(6nlebb6hdk7sd^&fnjpal308%n%+p^_e6vo1y'
-
-# 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.
-REMOTE_HOST_HEADERS = ['REMOTE_ADDR', 'REMOTE_HOST']
-
-# If Tower is behind a reverse proxy/load balancer, use this setting to
-# whitelist the proxy IP addresses from which Tower should trust custom
-# REMOTE_HOST_HEADERS header values
-# REMOTE_HOST_HEADERS = ['HTTP_X_FORWARDED_FOR', ''REMOTE_ADDR', 'REMOTE_HOST']
-# PROXY_IP_WHITELIST = ['10.0.1.100', '10.0.1.101']
-# If this setting is an empty list (the default), the headers specified by
-# REMOTE_HOST_HEADERS will be trusted unconditionally')
-PROXY_IP_WHITELIST = []
-
-# Define additional environment variables to be passed to ansible subprocesses
-#AWX_TASK_ENV['FOO'] = 'BAR'
-
# If set, use -vvv for project updates instead of -v for more output.
# PROJECT_UPDATE_VVV=True
@@ -108,40 +64,6 @@ PROXY_IP_WHITELIST = []
# Enable logging to syslog. Setting level to ERROR captures 500 errors,
# WARNING also logs 4xx responses.
-LOGGING['handlers']['syslog'] = {
- 'level': 'WARNING',
- 'filters': ['require_debug_false'],
- 'class': 'logging.NullHandler',
- 'formatter': 'simple',
-}
-
-LOGGING['loggers']['django.request']['handlers'] = ['console']
-LOGGING['loggers']['rest_framework.request']['handlers'] = ['console']
-LOGGING['loggers']['awx']['handlers'] = ['console', 'external_logger']
-LOGGING['loggers']['awx.main.commands.run_callback_receiver']['handlers'] = [] # propogates to awx
-LOGGING['loggers']['awx.main.tasks']['handlers'] = ['console', 'external_logger']
-LOGGING['loggers']['awx.main.scheduler']['handlers'] = ['console', 'external_logger']
-LOGGING['loggers']['django_auth_ldap']['handlers'] = ['console']
-LOGGING['loggers']['social']['handlers'] = ['console']
-LOGGING['loggers']['system_tracking_migrations']['handlers'] = ['console']
-LOGGING['loggers']['rbac_migrations']['handlers'] = ['console']
-LOGGING['loggers']['awx.isolated.manager.playbooks']['handlers'] = ['console']
-LOGGING['handlers']['callback_receiver'] = {'class': 'logging.NullHandler'}
-LOGGING['handlers']['fact_receiver'] = {'class': 'logging.NullHandler'}
-LOGGING['handlers']['task_system'] = {'class': 'logging.NullHandler'}
-LOGGING['handlers']['tower_warnings'] = {'class': 'logging.NullHandler'}
-LOGGING['handlers']['rbac_migrations'] = {'class': 'logging.NullHandler'}
-LOGGING['handlers']['system_tracking_migrations'] = {'class': 'logging.NullHandler'}
-LOGGING['handlers']['management_playbooks'] = {'class': 'logging.NullHandler'}
-
-
-# Enable the following lines to also log to a file.
-#LOGGING['handlers']['file'] = {
-# 'class': 'logging.FileHandler',
-# 'filename': os.path.join(BASE_DIR, 'awx.log'),
-# 'formatter': 'simple',
-#}
-
# Enable the following lines to turn on lots of permissions-related logging.
#LOGGING['loggers']['awx.main.access']['level'] = 'DEBUG'
#LOGGING['loggers']['awx.main.signals']['level'] = 'DEBUG'
@@ -154,74 +76,6 @@ LOGGING['handlers']['management_playbooks'] = {'class': 'logging.NullHandler'}
#LOGGING['loggers']['django_auth_ldap']['handlers'] = ['console']
#LOGGING['loggers']['django_auth_ldap']['level'] = 'DEBUG'
-###############################################################################
-# SCM TEST SETTINGS
-###############################################################################
-
-# Define these variables to enable more complete testing of project support for
-# SCM updates. The test repositories listed do not have to contain any valid
-# playbooks.
-
-try:
- path = os.path.expanduser(os.path.expandvars('~/.ssh/id_rsa'))
- TEST_SSH_KEY_DATA = open(path, 'rb').read()
-except IOError:
- TEST_SSH_KEY_DATA = ''
-
-TEST_GIT_USERNAME = ''
-TEST_GIT_PASSWORD = ''
-TEST_GIT_KEY_DATA = TEST_SSH_KEY_DATA
-TEST_GIT_PUBLIC_HTTPS = 'https://github.com/ansible/ansible.github.com.git'
-TEST_GIT_PRIVATE_HTTPS = 'https://github.com/ansible/product-docs.git'
-TEST_GIT_PRIVATE_SSH = 'git@github.com:ansible/product-docs.git'
-
-TEST_SVN_USERNAME = ''
-TEST_SVN_PASSWORD = ''
-TEST_SVN_PUBLIC_HTTPS = 'https://github.com/ansible/ansible.github.com'
-TEST_SVN_PRIVATE_HTTPS = 'https://github.com/ansible/product-docs'
-
-# To test repo access via SSH login to localhost.
-import getpass
-try:
- TEST_SSH_LOOPBACK_USERNAME = getpass.getuser()
-except KeyError:
- TEST_SSH_LOOPBACK_USERNAME = 'root'
-TEST_SSH_LOOPBACK_PASSWORD = ''
-
-###############################################################################
-# INVENTORY IMPORT TEST SETTINGS
-###############################################################################
-
-# Define these variables to enable more complete testing of inventory import
-# from cloud providers.
-
-# EC2 credentials
-TEST_AWS_ACCESS_KEY_ID = ''
-TEST_AWS_SECRET_ACCESS_KEY = ''
-TEST_AWS_REGIONS = 'all'
-# Check IAM STS credentials
-TEST_AWS_SECURITY_TOKEN = ''
-
-# Rackspace credentials
-TEST_RACKSPACE_USERNAME = ''
-TEST_RACKSPACE_API_KEY = ''
-TEST_RACKSPACE_REGIONS = 'all'
-
-# VMware credentials
-TEST_VMWARE_HOST = ''
-TEST_VMWARE_USER = ''
-TEST_VMWARE_PASSWORD = ''
-
-# OpenStack credentials
-TEST_OPENSTACK_HOST = ''
-TEST_OPENSTACK_USER = ''
-TEST_OPENSTACK_PASSWORD = ''
-TEST_OPENSTACK_PROJECT = ''
-
-# Azure credentials.
-TEST_AZURE_USERNAME = ''
-TEST_AZURE_KEY_DATA = ''
-
BROADCAST_WEBSOCKET_SECRET = '🤖starscream🤖'
BROADCAST_WEBSOCKET_PORT = 8013
BROADCAST_WEBSOCKET_VERIFY_CERT = False
diff --git a/awx/settings/local_settings.py.example b/awx/settings/local_settings.py.example
deleted file mode 100644
index 59f3bdfa6a..0000000000
--- a/awx/settings/local_settings.py.example
+++ /dev/null
@@ -1,192 +0,0 @@
-# Copyright (c) 2015 Ansible, Inc. (formerly AnsibleWorks, Inc.)
-# All Rights Reserved.
-
-# Local Django settings for AWX project. Rename to "local_settings.py" and
-# edit as needed for your development environment.
-
-# All variables defined in awx/settings/development.py will already be loaded
-# into the global namespace before this file is loaded, to allow for reading
-# and updating the default settings as needed.
-
-###############################################################################
-# MISC PROJECT SETTINGS
-###############################################################################
-
-# Database settings to use PostgreSQL for development.
-DATABASES = {
- 'default': {
- 'ENGINE': 'django.db.backends.postgresql_psycopg2',
- 'NAME': 'awx-dev',
- 'USER': 'awx-dev',
- 'PASSWORD': 'AWXsome1',
- 'HOST': 'localhost',
- 'PORT': '',
- }
-}
-
-# Use SQLite for unit tests instead of PostgreSQL. If the lines below are
-# commented out, Django will create the test_awx-dev database in PostgreSQL to
-# run unit tests.
-if is_testing(sys.argv):
- DATABASES = {
- 'default': {
- 'ENGINE': 'django.db.backends.sqlite3',
- 'NAME': os.path.join(BASE_DIR, 'awx.sqlite3'),
- 'TEST': {
- # Test database cannot be :memory: for tests.
- 'NAME': os.path.join(BASE_DIR, 'awx_test.sqlite3'),
- },
- }
- }
-
-# AMQP configuration.
-BROKER_URL = 'amqp://guest:guest@localhost:5672'
-
-# Absolute filesystem path to the directory to host projects (with playbooks).
-# This directory should NOT be web-accessible.
-PROJECTS_ROOT = os.path.join(BASE_DIR, 'projects')
-
-# Absolute filesystem path to the directory for job status stdout
-# This directory should not be web-accessible
-JOBOUTPUT_ROOT = os.path.join(BASE_DIR, 'job_status')
-
-# The UUID of the system, for HA.
-SYSTEM_UUID = '00000000-0000-0000-0000-000000000000'
-
-# Local time zone for this installation. Choices can be found here:
-# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
-# although not all choices may be available on all operating systems.
-# On Unix systems, a value of None will cause Django to use the same
-# timezone as the operating system.
-# If running in a Windows environment this must be set to the same as your
-# system time zone.
-TIME_ZONE = None
-
-# Language code for this installation. All choices can be found here:
-# http://www.i18nguy.com/unicode/language-identifiers.html
-LANGUAGE_CODE = 'en-us'
-
-# SECURITY WARNING: keep the secret key used in production secret!
-# Hardcoded values can leak through source control. Consider loading
-# the secret key from an environment variable or a file instead.
-SECRET_KEY = 'p7z7g1ql4%6+(6nlebb6hdk7sd^&fnjpal308%n%+p^_e6vo1y'
-
-# 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.
-REMOTE_HOST_HEADERS = ['REMOTE_ADDR', 'REMOTE_HOST']
-
-# If Tower is behind a reverse proxy/load balancer, use this setting to
-# whitelist the proxy IP addresses from which Tower should trust custom
-# REMOTE_HOST_HEADERS header values
-# REMOTE_HOST_HEADERS = ['HTTP_X_FORWARDED_FOR', ''REMOTE_ADDR', 'REMOTE_HOST']
-# PROXY_IP_WHITELIST = ['10.0.1.100', '10.0.1.101']
-# If this setting is an empty list (the default), the headers specified by
-# REMOTE_HOST_HEADERS will be trusted unconditionally')
-PROXY_IP_WHITELIST = []
-
-# Define additional environment variables to be passed to ansible subprocesses
-#AWX_TASK_ENV['FOO'] = 'BAR'
-
-# If set, use -vvv for project updates instead of -v for more output.
-# PROJECT_UPDATE_VVV=True
-
-###############################################################################
-# LOGGING SETTINGS
-###############################################################################
-
-# Enable logging to syslog. Setting level to ERROR captures 500 errors,
-# WARNING also logs 4xx responses.
-LOGGING['handlers']['syslog'] = {
- 'level': 'WARNING',
- 'filters': [],
- 'class': 'logging.handlers.SysLogHandler',
- 'address': '/dev/log',
- 'facility': 'local0',
- 'formatter': 'simple',
-}
-
-# Enable the following lines to also log to a file.
-#LOGGING['handlers']['file'] = {
-# 'class': 'logging.FileHandler',
-# 'filename': os.path.join(BASE_DIR, 'awx.log'),
-# 'formatter': 'simple',
-#}
-
-# Enable the following lines to turn on lots of permissions-related logging.
-#LOGGING['loggers']['awx.main.access']['level'] = 'DEBUG'
-#LOGGING['loggers']['awx.main.signals']['level'] = 'DEBUG'
-#LOGGING['loggers']['awx.main.permissions']['level'] = 'DEBUG'
-
-# Enable the following line to turn on database settings logging.
-#LOGGING['loggers']['awx.conf']['level'] = 'DEBUG'
-
-# Enable the following lines to turn on LDAP auth logging.
-#LOGGING['loggers']['django_auth_ldap']['handlers'] = ['console']
-#LOGGING['loggers']['django_auth_ldap']['level'] = 'DEBUG'
-
-###############################################################################
-# SCM TEST SETTINGS
-###############################################################################
-
-# Define these variables to enable more complete testing of project support for
-# SCM updates. The test repositories listed do not have to contain any valid
-# playbooks.
-
-try:
- path = os.path.expanduser(os.path.expandvars('~/.ssh/id_rsa'))
- TEST_SSH_KEY_DATA = file(path, 'rb').read()
-except IOError:
- TEST_SSH_KEY_DATA = ''
-
-TEST_GIT_USERNAME = ''
-TEST_GIT_PASSWORD = ''
-TEST_GIT_KEY_DATA = TEST_SSH_KEY_DATA
-TEST_GIT_PUBLIC_HTTPS = 'https://github.com/ansible/ansible.github.com.git'
-TEST_GIT_PRIVATE_HTTPS = 'https://github.com/ansible/product-docs.git'
-TEST_GIT_PRIVATE_SSH = 'git@github.com:ansible/product-docs.git'
-
-TEST_SVN_USERNAME = ''
-TEST_SVN_PASSWORD = ''
-TEST_SVN_PUBLIC_HTTPS = 'https://github.com/ansible/ansible.github.com'
-TEST_SVN_PRIVATE_HTTPS = 'https://github.com/ansible/product-docs'
-
-# To test repo access via SSH login to localhost.
-import getpass
-TEST_SSH_LOOPBACK_USERNAME = getpass.getuser()
-TEST_SSH_LOOPBACK_PASSWORD = ''
-
-###############################################################################
-# INVENTORY IMPORT TEST SETTINGS
-###############################################################################
-
-# Define these variables to enable more complete testing of inventory import
-# from cloud providers.
-
-# EC2 credentials
-TEST_AWS_ACCESS_KEY_ID = ''
-TEST_AWS_SECRET_ACCESS_KEY = ''
-TEST_AWS_REGIONS = 'all'
-# Check IAM STS credentials
-TEST_AWS_SECURITY_TOKEN = ''
-
-
-# Rackspace credentials
-TEST_RACKSPACE_USERNAME = ''
-TEST_RACKSPACE_API_KEY = ''
-TEST_RACKSPACE_REGIONS = 'all'
-
-# VMware credentials
-TEST_VMWARE_HOST = ''
-TEST_VMWARE_USER = ''
-TEST_VMWARE_PASSWORD = ''
-
-# OpenStack credentials
-TEST_OPENSTACK_HOST = ''
-TEST_OPENSTACK_USER = ''
-TEST_OPENSTACK_PASSWORD = ''
-TEST_OPENSTACK_PROJECT = ''
-
-# Azure credentials.
-TEST_AZURE_USERNAME = ''
-TEST_AZURE_KEY_DATA = ''
diff --git a/awx/settings/production.py b/awx/settings/production.py
index fb24b7087f..02681265e6 100644
--- a/awx/settings/production.py
+++ b/awx/settings/production.py
@@ -30,10 +30,6 @@ SECRET_KEY = None
# See https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts
ALLOWED_HOSTS = []
-# Absolute filesystem path to the directory for job status stdout
-# This directory should not be web-accessible
-JOBOUTPUT_ROOT = '/var/lib/awx/job_status/'
-
# The heartbeat file for the tower scheduler
SCHEDULE_METADATA_LOCATION = '/var/lib/awx/.tower_cycle'
@@ -46,15 +42,6 @@ AWX_VENV_PATH = os.path.join(BASE_VENV_PATH, "awx")
AWX_ISOLATED_USERNAME = 'awx'
-LOGGING['handlers']['tower_warnings']['filename'] = '/var/log/tower/tower.log' # noqa
-LOGGING['handlers']['callback_receiver']['filename'] = '/var/log/tower/callback_receiver.log' # noqa
-LOGGING['handlers']['dispatcher']['filename'] = '/var/log/tower/dispatcher.log' # noqa
-LOGGING['handlers']['wsbroadcast']['filename'] = '/var/log/tower/wsbroadcast.log' # noqa
-LOGGING['handlers']['task_system']['filename'] = '/var/log/tower/task_system.log' # noqa
-LOGGING['handlers']['management_playbooks']['filename'] = '/var/log/tower/management_playbooks.log' # noqa
-LOGGING['handlers']['system_tracking_migrations']['filename'] = '/var/log/tower/tower_system_tracking_migrations.log' # noqa
-LOGGING['handlers']['rbac_migrations']['filename'] = '/var/log/tower/tower_rbac_migrations.log' # noqa
-
# Store a snapshot of default settings at this point before loading any
# customizable config files.
DEFAULTS_SNAPSHOT = {}
diff --git a/awx/ui_next/CONTRIBUTING.md b/awx/ui_next/CONTRIBUTING.md
index 575e08e913..c0a3eaefc4 100644
--- a/awx/ui_next/CONTRIBUTING.md
+++ b/awx/ui_next/CONTRIBUTING.md
@@ -57,7 +57,7 @@ The UI is built using [ReactJS](https://reactjs.org/docs/getting-started.html) a
The AWX UI requires the following:
-- Node 10.x LTS
+- Node 14.x LTS
- NPM 6.x LTS
Run the following to install all the dependencies:
diff --git a/awx/ui_next/package-lock.json b/awx/ui_next/package-lock.json
index aa83635125..a64e834f55 100644
--- a/awx/ui_next/package-lock.json
+++ b/awx/ui_next/package-lock.json
@@ -3387,12 +3387,18 @@
"dev": true
},
"axios": {
- "version": "0.18.1",
- "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.1.tgz",
- "integrity": "sha512-0BfJq4NSfQXd+SkFdrvFbG7addhYSBA2mQwISr46pD6E5iqkWg02RAs8vyTT/j0RTnoYmeXauBuSv1qKwR179g==",
+ "version": "0.21.1",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
+ "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
"requires": {
- "follow-redirects": "1.5.10",
- "is-buffer": "^2.0.2"
+ "follow-redirects": "^1.10.0"
+ },
+ "dependencies": {
+ "follow-redirects": {
+ "version": "1.13.1",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.1.tgz",
+ "integrity": "sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg=="
+ }
}
},
"axobject-query": {
@@ -4195,6 +4201,16 @@
"integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==",
"dev": true
},
+ "bindings": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
+ "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "file-uri-to-path": "1.0.0"
+ }
+ },
"bluebird": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
@@ -5961,6 +5977,7 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+ "dev": true,
"requires": {
"ms": "2.0.0"
}
@@ -7911,6 +7928,13 @@
}
}
},
+ "file-uri-to-path": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
+ "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
+ "dev": true,
+ "optional": true
+ },
"filesize": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/filesize/-/filesize-6.0.1.tgz",
@@ -8110,6 +8134,7 @@
"version": "1.5.10",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz",
"integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==",
+ "dev": true,
"requires": {
"debug": "=3.1.0"
}
@@ -9500,11 +9525,6 @@
"call-bind": "^1.0.0"
}
},
- "is-buffer": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz",
- "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ=="
- },
"is-callable": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz",
@@ -10315,7 +10335,11 @@
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
"integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
"dev": true,
- "optional": true
+ "optional": true,
+ "requires": {
+ "bindings": "^1.5.0",
+ "nan": "^2.12.1"
+ }
},
"is-buffer": {
"version": "1.1.6",
@@ -11731,7 +11755,8 @@
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
},
"multicast-dns": {
"version": "6.2.3",
@@ -11755,6 +11780,13 @@
"integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=",
"dev": true
},
+ "nan": {
+ "version": "2.14.2",
+ "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz",
+ "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==",
+ "dev": true,
+ "optional": true
+ },
"nanomatch": {
"version": "1.2.13",
"resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
@@ -17683,7 +17715,11 @@
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
"integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
"dev": true,
- "optional": true
+ "optional": true,
+ "requires": {
+ "bindings": "^1.5.0",
+ "nan": "^2.12.1"
+ }
},
"glob-parent": {
"version": "3.1.0",
@@ -18364,7 +18400,11 @@
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
"integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
"dev": true,
- "optional": true
+ "optional": true,
+ "requires": {
+ "bindings": "^1.5.0",
+ "nan": "^2.12.1"
+ }
},
"glob-parent": {
"version": "3.1.0",
diff --git a/awx/ui_next/package.json b/awx/ui_next/package.json
index 551f0cb543..b052a3183f 100644
--- a/awx/ui_next/package.json
+++ b/awx/ui_next/package.json
@@ -12,7 +12,7 @@
"@patternfly/react-icons": "4.7.22",
"@patternfly/react-table": "^4.19.15",
"ansi-to-html": "^0.6.11",
- "axios": "^0.18.1",
+ "axios": "^0.21.1",
"codemirror": "^5.47.0",
"d3": "^5.12.0",
"dagre": "^0.8.4",
diff --git a/awx/ui_next/src/api/models/Jobs.js b/awx/ui_next/src/api/models/Jobs.js
index 9c43509f9e..fc9bbb2334 100644
--- a/awx/ui_next/src/api/models/Jobs.js
+++ b/awx/ui_next/src/api/models/Jobs.js
@@ -36,6 +36,10 @@ class Jobs extends RelaunchMixin(Base) {
return this.http.post(`/api/v2${getBaseURL(type)}${id}/cancel/`);
}
+ readCredentials(id, type) {
+ return this.http.get(`/api/v2${getBaseURL(type)}${id}/credentials/`);
+ }
+
readDetail(id, type) {
return this.http.get(`/api/v2${getBaseURL(type)}${id}/`);
}
diff --git a/awx/ui_next/src/components/AdHocCommands/AdHocCommands.jsx b/awx/ui_next/src/components/AdHocCommands/AdHocCommands.jsx
index 48fc566e2c..89387b9e8b 100644
--- a/awx/ui_next/src/components/AdHocCommands/AdHocCommands.jsx
+++ b/awx/ui_next/src/components/AdHocCommands/AdHocCommands.jsx
@@ -57,7 +57,7 @@ function AdHocCommands({ adHocItems, i18n, hasListItems }) {
fetchData();
}, [fetchData]);
const {
- isloading: isLaunchLoading,
+ isLoading: isLaunchLoading,
error: launchError,
request: launchAdHocCommands,
} = useRequest(
diff --git a/awx/ui_next/src/components/AdHocCommands/AdHocCredentialStep.jsx b/awx/ui_next/src/components/AdHocCommands/AdHocCredentialStep.jsx
index fa6f931c24..e95f0b05cb 100644
--- a/awx/ui_next/src/components/AdHocCommands/AdHocCredentialStep.jsx
+++ b/awx/ui_next/src/components/AdHocCommands/AdHocCredentialStep.jsx
@@ -58,7 +58,7 @@ function AdHocCredentialStep({ i18n, credentialTypeId, onEnableLaunch }) {
return