mirror of
https://github.com/ansible/awx.git
synced 2026-04-05 10:09:20 -02:30
Compare commits
12 Commits
24.1.0
...
dmzoneill-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ca017d359 | ||
|
|
4b6f7e0ebe | ||
|
|
370c567be1 | ||
|
|
9be64f3de5 | ||
|
|
30500e5a95 | ||
|
|
bb323c5710 | ||
|
|
7571df49d5 | ||
|
|
1559c21033 | ||
|
|
d9b81731e9 | ||
|
|
2034cca3a9 | ||
|
|
0b5e59d9cb | ||
|
|
f48b2d1ae5 |
8
.github/PULL_REQUEST_TEMPLATE.md
vendored
8
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -7,6 +7,14 @@ commit message and your description; but you should still explain what
|
|||||||
the change does.
|
the change does.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
##### Depends on
|
||||||
|
<!---
|
||||||
|
Please provide links to any other PR dependanices.
|
||||||
|
Indicating these should be merged first prior to this PR.
|
||||||
|
-->
|
||||||
|
- #12345
|
||||||
|
- https://github.com/xxx/yyy/pulls/1234
|
||||||
|
|
||||||
##### ISSUE TYPE
|
##### ISSUE TYPE
|
||||||
<!--- Pick one below and delete the rest: -->
|
<!--- Pick one below and delete the rest: -->
|
||||||
- Breaking Change
|
- Breaking Change
|
||||||
|
|||||||
@@ -191,6 +191,7 @@ SUMMARIZABLE_FK_FIELDS = {
|
|||||||
'webhook_credential': DEFAULT_SUMMARY_FIELDS + ('kind', 'cloud', 'credential_type_id'),
|
'webhook_credential': DEFAULT_SUMMARY_FIELDS + ('kind', 'cloud', 'credential_type_id'),
|
||||||
'approved_or_denied_by': ('id', 'username', 'first_name', 'last_name'),
|
'approved_or_denied_by': ('id', 'username', 'first_name', 'last_name'),
|
||||||
'credential_type': DEFAULT_SUMMARY_FIELDS,
|
'credential_type': DEFAULT_SUMMARY_FIELDS,
|
||||||
|
'resource': ('ansible_id', 'resource_type'),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ from django.utils.decorators import method_decorator
|
|||||||
from django.views.decorators.csrf import ensure_csrf_cookie
|
from django.views.decorators.csrf import ensure_csrf_cookie
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from django.urls import reverse as django_reverse
|
||||||
|
|
||||||
from rest_framework.permissions import AllowAny, IsAuthenticated
|
from rest_framework.permissions import AllowAny, IsAuthenticated
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
@@ -130,6 +131,7 @@ class ApiVersionRootView(APIView):
|
|||||||
data['mesh_visualizer'] = reverse('api:mesh_visualizer_view', request=request)
|
data['mesh_visualizer'] = reverse('api:mesh_visualizer_view', request=request)
|
||||||
data['bulk'] = reverse('api:bulk', request=request)
|
data['bulk'] = reverse('api:bulk', request=request)
|
||||||
data['analytics'] = reverse('api:analytics_root_view', request=request)
|
data['analytics'] = reverse('api:analytics_root_view', request=request)
|
||||||
|
data['service_index'] = django_reverse('service-index-root')
|
||||||
return Response(data)
|
return Response(data)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -639,7 +639,10 @@ class UserAccess(BaseAccess):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
model = User
|
model = User
|
||||||
prefetch_related = ('profile',)
|
prefetch_related = (
|
||||||
|
'profile',
|
||||||
|
'resource',
|
||||||
|
)
|
||||||
|
|
||||||
def filtered_queryset(self):
|
def filtered_queryset(self):
|
||||||
if settings.ORG_ADMINS_CAN_SEE_ALL_USERS and (self.user.admin_of_organizations.exists() or self.user.auditor_of_organizations.exists()):
|
if settings.ORG_ADMINS_CAN_SEE_ALL_USERS and (self.user.admin_of_organizations.exists() or self.user.auditor_of_organizations.exists()):
|
||||||
@@ -835,6 +838,7 @@ class OrganizationAccess(NotificationAttachMixin, BaseAccess):
|
|||||||
prefetch_related = (
|
prefetch_related = (
|
||||||
'created_by',
|
'created_by',
|
||||||
'modified_by',
|
'modified_by',
|
||||||
|
'resource', # dab_resource_registry
|
||||||
)
|
)
|
||||||
# organization admin_role is not a parent of organization auditor_role
|
# organization admin_role is not a parent of organization auditor_role
|
||||||
notification_attach_roles = ['admin_role', 'auditor_role']
|
notification_attach_roles = ['admin_role', 'auditor_role']
|
||||||
@@ -1303,6 +1307,7 @@ class TeamAccess(BaseAccess):
|
|||||||
'created_by',
|
'created_by',
|
||||||
'modified_by',
|
'modified_by',
|
||||||
'organization',
|
'organization',
|
||||||
|
'resource', # dab_resource_registry
|
||||||
)
|
)
|
||||||
|
|
||||||
def filtered_queryset(self):
|
def filtered_queryset(self):
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ from django.conf import settings # noqa
|
|||||||
from django.db import connection
|
from django.db import connection
|
||||||
from django.db.models.signals import pre_delete # noqa
|
from django.db.models.signals import pre_delete # noqa
|
||||||
|
|
||||||
|
# django-ansible-base
|
||||||
|
from ansible_base.resource_registry.fields import AnsibleResourceField
|
||||||
from ansible_base.lib.utils.models import prevent_search
|
from ansible_base.lib.utils.models import prevent_search
|
||||||
|
|
||||||
# AWX
|
# AWX
|
||||||
@@ -99,6 +101,7 @@ from awx.main.access import get_user_queryset, check_user_access, check_user_acc
|
|||||||
User.add_to_class('get_queryset', get_user_queryset)
|
User.add_to_class('get_queryset', get_user_queryset)
|
||||||
User.add_to_class('can_access', check_user_access)
|
User.add_to_class('can_access', check_user_access)
|
||||||
User.add_to_class('can_access_with_errors', check_user_access_with_errors)
|
User.add_to_class('can_access_with_errors', check_user_access_with_errors)
|
||||||
|
User.add_to_class('resource', AnsibleResourceField(primary_key_field="id"))
|
||||||
|
|
||||||
|
|
||||||
def convert_jsonfields():
|
def convert_jsonfields():
|
||||||
|
|||||||
@@ -498,7 +498,7 @@ class JobNotificationMixin(object):
|
|||||||
# Body should have at least 2 CRLF, some clients will interpret
|
# Body should have at least 2 CRLF, some clients will interpret
|
||||||
# the email incorrectly with blank body. So we will check that
|
# the email incorrectly with blank body. So we will check that
|
||||||
|
|
||||||
if len(body.strip().splitlines()) <= 2:
|
if len(body.strip().splitlines()) < 1:
|
||||||
# blank body
|
# blank body
|
||||||
body = '\r\n'.join(
|
body = '\r\n'.join(
|
||||||
[
|
[
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ from django.contrib.sessions.models import Session
|
|||||||
from django.utils.timezone import now as tz_now
|
from django.utils.timezone import now as tz_now
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
# django-ansible-base
|
||||||
|
from ansible_base.resource_registry.fields import AnsibleResourceField
|
||||||
|
|
||||||
# AWX
|
# AWX
|
||||||
from awx.api.versioning import reverse
|
from awx.api.versioning import reverse
|
||||||
@@ -103,6 +105,7 @@ class Organization(CommonModel, NotificationFieldsModel, ResourceMixin, CustomVi
|
|||||||
approval_role = ImplicitRoleField(
|
approval_role = ImplicitRoleField(
|
||||||
parent_role='admin_role',
|
parent_role='admin_role',
|
||||||
)
|
)
|
||||||
|
resource = AnsibleResourceField(primary_key_field="id")
|
||||||
|
|
||||||
def get_absolute_url(self, request=None):
|
def get_absolute_url(self, request=None):
|
||||||
return reverse('api:organization_detail', kwargs={'pk': self.pk}, request=request)
|
return reverse('api:organization_detail', kwargs={'pk': self.pk}, request=request)
|
||||||
@@ -151,6 +154,7 @@ class Team(CommonModelNameNotUnique, ResourceMixin):
|
|||||||
read_role = ImplicitRoleField(
|
read_role = ImplicitRoleField(
|
||||||
parent_role=['organization.auditor_role', 'member_role'],
|
parent_role=['organization.auditor_role', 'member_role'],
|
||||||
)
|
)
|
||||||
|
resource = AnsibleResourceField(primary_key_field="id")
|
||||||
|
|
||||||
def get_absolute_url(self, request=None):
|
def get_absolute_url(self, request=None):
|
||||||
return reverse('api:team_detail', kwargs={'pk': self.pk}, request=request)
|
return reverse('api:team_detail', kwargs={'pk': self.pk}, request=request)
|
||||||
|
|||||||
@@ -49,6 +49,70 @@ class ReceptorConnectionType(Enum):
|
|||||||
STREAMTLS = 2
|
STREAMTLS = 2
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
Translate receptorctl messages that come in over stdout into
|
||||||
|
structured messages. Currently, these are error messages.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class ReceptorErrorBase:
|
||||||
|
_MESSAGE = 'Receptor Error'
|
||||||
|
|
||||||
|
def __init__(self, node: str = 'N/A', state_name: str = 'N/A'):
|
||||||
|
self.node = node
|
||||||
|
self.state_name = state_name
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.__class__.__name__} '{self._MESSAGE}' on node '{self.node}' with state '{self.state_name}'"
|
||||||
|
|
||||||
|
|
||||||
|
class WorkUnitError(ReceptorErrorBase):
|
||||||
|
_MESSAGE = 'unknown work unit '
|
||||||
|
|
||||||
|
def __init__(self, work_unit_id: str, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.work_unit_id = work_unit_id
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{super().__str__()} work unit id '{self.work_unit_id}'"
|
||||||
|
|
||||||
|
|
||||||
|
class WorkUnitCancelError(WorkUnitError):
|
||||||
|
_MESSAGE = 'error cancelling remote unit: unknown work unit '
|
||||||
|
|
||||||
|
|
||||||
|
class WorkUnitResultsError(WorkUnitError):
|
||||||
|
_MESSAGE = 'Failed to get results: unknown work unit '
|
||||||
|
|
||||||
|
|
||||||
|
class UnknownError(ReceptorErrorBase):
|
||||||
|
_MESSAGE = 'Unknown receptor ctl error'
|
||||||
|
|
||||||
|
def __init__(self, msg, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self._MESSAGE = msg
|
||||||
|
|
||||||
|
|
||||||
|
class FuzzyError:
|
||||||
|
def __new__(self, e: RuntimeError, node: str, state_name: str):
|
||||||
|
"""
|
||||||
|
At the time of writing this comment all of the sub-classes detection
|
||||||
|
is centralized in this parent class. It's like a Router().
|
||||||
|
Someone may find it better to push down the error detection logic into
|
||||||
|
each sub-class.
|
||||||
|
"""
|
||||||
|
msg = e.args[0]
|
||||||
|
|
||||||
|
common_startswith = (WorkUnitCancelError, WorkUnitResultsError, WorkUnitError)
|
||||||
|
|
||||||
|
for klass in common_startswith:
|
||||||
|
if msg.startswith(klass._MESSAGE):
|
||||||
|
work_unit_id = msg[len(klass._MESSAGE) :]
|
||||||
|
return klass(work_unit_id, node=node, state_name=state_name)
|
||||||
|
|
||||||
|
return UnknownError(msg, node=node, state_name=state_name)
|
||||||
|
|
||||||
|
|
||||||
def read_receptor_config():
|
def read_receptor_config():
|
||||||
# for K8S deployments, getting a lock is necessary as another process
|
# for K8S deployments, getting a lock is necessary as another process
|
||||||
# may be re-writing the config at this time
|
# may be re-writing the config at this time
|
||||||
@@ -185,6 +249,7 @@ def run_until_complete(node, timing_data=None, **kwargs):
|
|||||||
timing_data['transmit_timing'] = run_start - transmit_start
|
timing_data['transmit_timing'] = run_start - transmit_start
|
||||||
run_timing = 0.0
|
run_timing = 0.0
|
||||||
stdout = ''
|
stdout = ''
|
||||||
|
state_name = 'local var never set'
|
||||||
|
|
||||||
try:
|
try:
|
||||||
resultfile = receptor_ctl.get_work_results(unit_id)
|
resultfile = receptor_ctl.get_work_results(unit_id)
|
||||||
@@ -205,13 +270,33 @@ def run_until_complete(node, timing_data=None, **kwargs):
|
|||||||
stdout = resultfile.read()
|
stdout = resultfile.read()
|
||||||
stdout = str(stdout, encoding='utf-8')
|
stdout = str(stdout, encoding='utf-8')
|
||||||
|
|
||||||
|
except RuntimeError as e:
|
||||||
|
receptor_e = FuzzyError(e, node, state_name)
|
||||||
|
if type(receptor_e) in (
|
||||||
|
WorkUnitError,
|
||||||
|
WorkUnitResultsError,
|
||||||
|
):
|
||||||
|
logger.warning(f'While consuming job results: {receptor_e}')
|
||||||
|
else:
|
||||||
|
raise
|
||||||
finally:
|
finally:
|
||||||
if settings.RECEPTOR_RELEASE_WORK:
|
if settings.RECEPTOR_RELEASE_WORK:
|
||||||
res = receptor_ctl.simple_command(f"work release {unit_id}")
|
try:
|
||||||
if res != {'released': unit_id}:
|
res = receptor_ctl.simple_command(f"work release {unit_id}")
|
||||||
logger.warning(f'Could not confirm release of receptor work unit id {unit_id} from {node}, data: {res}')
|
|
||||||
|
|
||||||
receptor_ctl.close()
|
if res != {'released': unit_id}:
|
||||||
|
logger.warning(f'Could not confirm release of receptor work unit id {unit_id} from {node}, data: {res}')
|
||||||
|
|
||||||
|
receptor_ctl.close()
|
||||||
|
except RuntimeError as e:
|
||||||
|
receptor_e = FuzzyError(e, node, state_name)
|
||||||
|
if type(receptor_e) in (
|
||||||
|
WorkUnitError,
|
||||||
|
WorkUnitCancelError,
|
||||||
|
):
|
||||||
|
logger.warning(f"While releasing work: {receptor_e}")
|
||||||
|
else:
|
||||||
|
logger.error(f"While releasing work: {receptor_e}")
|
||||||
|
|
||||||
if state_name.lower() == 'failed':
|
if state_name.lower() == 'failed':
|
||||||
work_detail = status.get('Detail', '')
|
work_detail = status.get('Detail', '')
|
||||||
@@ -275,7 +360,7 @@ def _convert_args_to_cli(vargs):
|
|||||||
args = ['cleanup']
|
args = ['cleanup']
|
||||||
for option in ('exclude_strings', 'remove_images'):
|
for option in ('exclude_strings', 'remove_images'):
|
||||||
if vargs.get(option):
|
if vargs.get(option):
|
||||||
args.append('--{}={}'.format(option.replace('_', '-'), ' '.join(vargs.get(option))))
|
args.append('--{}="{}"'.format(option.replace('_', '-'), ' '.join(vargs.get(option))))
|
||||||
for option in ('file_pattern', 'image_prune', 'process_isolation_executable', 'grace_period'):
|
for option in ('file_pattern', 'image_prune', 'process_isolation_executable', 'grace_period'):
|
||||||
if vargs.get(option) is True:
|
if vargs.get(option) is True:
|
||||||
args.append('--{}'.format(option.replace('_', '-')))
|
args.append('--{}'.format(option.replace('_', '-')))
|
||||||
|
|||||||
@@ -3,5 +3,5 @@
|
|||||||
hosts: all
|
hosts: all
|
||||||
tasks:
|
tasks:
|
||||||
- name: Hello Message
|
- name: Hello Message
|
||||||
debug:
|
ansible.builtin.debug:
|
||||||
msg: "Hello World!"
|
msg: "Hello World!"
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from ansible_base.resource_registry.models import Resource
|
||||||
|
|
||||||
|
from awx.api.versioning import reverse
|
||||||
|
|
||||||
|
|
||||||
|
def assert_has_resource(list_response, obj=None):
|
||||||
|
data = list_response.data
|
||||||
|
assert 'resource' in data['results'][0]['summary_fields']
|
||||||
|
resource_data = data['results'][0]['summary_fields']['resource']
|
||||||
|
assert resource_data['ansible_id']
|
||||||
|
resource = Resource.objects.filter(ansible_id=resource_data['ansible_id']).first()
|
||||||
|
assert resource
|
||||||
|
assert resource.content_object
|
||||||
|
if obj:
|
||||||
|
objects = [Resource.objects.get(ansible_id=entry['summary_fields']['resource']['ansible_id']).content_object for entry in data['results']]
|
||||||
|
assert obj in objects
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_organization_ansible_id(organization, admin_user, get):
|
||||||
|
url = reverse('api:organization_list')
|
||||||
|
response = get(url=url, user=admin_user, expect=200)
|
||||||
|
assert_has_resource(response, obj=organization)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_team_ansible_id(team, admin_user, get):
|
||||||
|
url = reverse('api:team_list')
|
||||||
|
response = get(url=url, user=admin_user, expect=200)
|
||||||
|
assert_has_resource(response, obj=team)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_user_ansible_id(rando, admin_user, get):
|
||||||
|
url = reverse('api:user_list')
|
||||||
|
response = get(url=url, user=admin_user, expect=200)
|
||||||
|
assert_has_resource(response, obj=rando)
|
||||||
@@ -3,7 +3,7 @@ from awx.main.tasks.receptor import _convert_args_to_cli
|
|||||||
|
|
||||||
def test_file_cleanup_scenario():
|
def test_file_cleanup_scenario():
|
||||||
args = _convert_args_to_cli({'exclude_strings': ['awx_423_', 'awx_582_'], 'file_pattern': '/tmp/awx_*_*'})
|
args = _convert_args_to_cli({'exclude_strings': ['awx_423_', 'awx_582_'], 'file_pattern': '/tmp/awx_*_*'})
|
||||||
assert ' '.join(args) == 'cleanup --exclude-strings=awx_423_ awx_582_ --file-pattern=/tmp/awx_*_*'
|
assert ' '.join(args) == 'cleanup --exclude-strings="awx_423_ awx_582_" --file-pattern=/tmp/awx_*_*'
|
||||||
|
|
||||||
|
|
||||||
def test_image_cleanup_scenario():
|
def test_image_cleanup_scenario():
|
||||||
@@ -17,5 +17,5 @@ def test_image_cleanup_scenario():
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
assert (
|
assert (
|
||||||
' '.join(args) == 'cleanup --remove-images=quay.invalid/foo/bar:latest quay.invalid/foo/bar:devel --image-prune --process-isolation-executable=podman'
|
' '.join(args) == 'cleanup --remove-images="quay.invalid/foo/bar:latest quay.invalid/foo/bar:devel" --image-prune --process-isolation-executable=podman'
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -324,6 +324,7 @@ class WebSocketRelayManager(object):
|
|||||||
port=database_conf['PORT'],
|
port=database_conf['PORT'],
|
||||||
**database_conf.get("OPTIONS", {}),
|
**database_conf.get("OPTIONS", {}),
|
||||||
)
|
)
|
||||||
|
await async_conn.set_autocommit(True)
|
||||||
|
|
||||||
task = event_loop.create_task(self.on_ws_heartbeat(async_conn), name="on_ws_heartbeat")
|
task = event_loop.create_task(self.on_ws_heartbeat(async_conn), name="on_ws_heartbeat")
|
||||||
logger.info("Creating `on_ws_heartbeat` task in event loop.")
|
logger.info("Creating `on_ws_heartbeat` task in event loop.")
|
||||||
|
|||||||
@@ -1131,3 +1131,6 @@ include(settings_file)
|
|||||||
# example if set to '' API pattern will be /api
|
# example if set to '' API pattern will be /api
|
||||||
# example if set to 'controller' API pattern will be /api AND /api/controller
|
# example if set to 'controller' API pattern will be /api AND /api/controller
|
||||||
OPTIONAL_API_URLPATTERN_PREFIX = ''
|
OPTIONAL_API_URLPATTERN_PREFIX = ''
|
||||||
|
|
||||||
|
# Use AWX base view, to give 401 on unauthenticated requests
|
||||||
|
ANSIBLE_BASE_CUSTOM_VIEW_PARENT = 'awx.api.generics.APIView'
|
||||||
|
|||||||
@@ -39,7 +39,7 @@
|
|||||||
{% else %}
|
{% else %}
|
||||||
<li><a href="{% url 'api:login' %}?next={{ request.get_full_path }}" data-toggle="tooltip" data-placement="bottom" data-delay="1000" title="Log in"><span class="glyphicon glyphicon-log-in"></span>Log in</a></li>
|
<li><a href="{% url 'api:login' %}?next={{ request.get_full_path }}" data-toggle="tooltip" data-placement="bottom" data-delay="1000" title="Log in"><span class="glyphicon glyphicon-log-in"></span>Log in</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<li><a href="//docs.ansible.com/ansible-tower/{{short_tower_version}}/html/towerapi/index.html" target="_blank" data-toggle="tooltip" data-placement="bottom" data-delay="1000" title="{% trans 'API Guide' %}"><span class="glyphicon glyphicon-question-sign"></span><span class="visible-xs-inline">{% trans 'API Guide' %}</span></a></li>
|
<li><a href="//ansible.readthedocs.io/projects/awx/en/latest/rest_api/index.html" target="_blank" data-toggle="tooltip" data-placement="bottom" data-delay="1000" title="{% trans 'API Guide' %}"><span class="glyphicon glyphicon-question-sign"></span><span class="visible-xs-inline">{% trans 'API Guide' %}</span></a></li>
|
||||||
<li><a href="/" data-toggle="tooltip" data-placement="bottom" data-delay="1000" title="{% trans 'Back to application' %}"><span class="glyphicon glyphicon-circle-arrow-left"></span><span class="visible-xs-inline">{% trans 'Back to application' %}</span></a></li>
|
<li><a href="/" data-toggle="tooltip" data-placement="bottom" data-delay="1000" title="{% trans 'Back to application' %}"><span class="glyphicon glyphicon-circle-arrow-left"></span><span class="visible-xs-inline">{% trans 'Back to application' %}</span></a></li>
|
||||||
<li class="hidden-xs"><a href="#" class="resize" data-toggle="tooltip" data-placement="bottom" data-delay="1000" title="{% trans 'Resize' %}"><span class="glyphicon glyphicon-resize-full"></span></a></li>
|
<li class="hidden-xs"><a href="#" class="resize" data-toggle="tooltip" data-placement="bottom" data-delay="1000" title="{% trans 'Resize' %}"><span class="glyphicon glyphicon-resize-full"></span></a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -147,8 +147,12 @@ def main():
|
|||||||
if redirect_uris is not None:
|
if redirect_uris is not None:
|
||||||
application_fields['redirect_uris'] = ' '.join(redirect_uris)
|
application_fields['redirect_uris'] = ' '.join(redirect_uris)
|
||||||
|
|
||||||
# If the state was present and we can let the module build or update the existing application, this will return on its own
|
response = module.create_or_update_if_needed(application, application_fields, endpoint='applications', item_type='application', auto_exit=False)
|
||||||
module.create_or_update_if_needed(application, application_fields, endpoint='applications', item_type='application')
|
if 'client_id' in response:
|
||||||
|
module.json_output['client_id'] = response['client_id']
|
||||||
|
if 'client_secret' in response:
|
||||||
|
module.json_output['client_secret'] = response['client_secret']
|
||||||
|
module.exit_json(**module.json_output)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -155,4 +155,4 @@ def test_build_notification_message_undefined(run_module, admin_user, organizati
|
|||||||
nt = NotificationTemplate.objects.get(id=result['id'])
|
nt = NotificationTemplate.objects.get(id=result['id'])
|
||||||
|
|
||||||
body = job.build_notification_message(nt, 'running')
|
body = job.build_notification_message(nt, 'running')
|
||||||
assert 'The template rendering return a blank body' in body[1]
|
assert '{"started_by": "My Placeholder"}' in body[1]
|
||||||
|
|||||||
@@ -1,63 +1,63 @@
|
|||||||
---
|
---
|
||||||
- name: Generate a random string for test
|
- name: Generate a random string for test
|
||||||
set_fact:
|
ansible.builtin.set_fact:
|
||||||
test_id: "{{ lookup('password', '/dev/null chars=ascii_letters length=16') }}"
|
test_id: "{{ lookup('password', '/dev/null chars=ascii_letters length=16') }}"
|
||||||
when: test_id is not defined
|
when: test_id is not defined
|
||||||
|
|
||||||
- name: Generate names
|
- name: Generate names
|
||||||
set_fact:
|
ansible.builtin.set_fact:
|
||||||
inv_name: "AWX-Collection-tests-ad_hoc_command_cancel-inventory-{{ test_id }}"
|
inv_name: "AWX-Collection-tests-ad_hoc_command_cancel-inventory-{{ test_id }}"
|
||||||
ssh_cred_name: "AWX-Collection-tests-ad_hoc_command_cancel-ssh-cred-{{ test_id }}"
|
ssh_cred_name: "AWX-Collection-tests-ad_hoc_command_cancel-ssh-cred-{{ test_id }}"
|
||||||
org_name: "AWX-Collection-tests-ad_hoc_command_cancel-org-{{ test_id }}"
|
org_name: "AWX-Collection-tests-ad_hoc_command_cancel-org-{{ test_id }}"
|
||||||
|
|
||||||
- name: Create a New Organization
|
- name: Create a New Organization
|
||||||
organization:
|
awx.awx.organization:
|
||||||
name: "{{ org_name }}"
|
name: "{{ org_name }}"
|
||||||
|
|
||||||
- name: Create an Inventory
|
- name: Create an Inventory
|
||||||
inventory:
|
awx.awx.inventory:
|
||||||
name: "{{ inv_name }}"
|
name: "{{ inv_name }}"
|
||||||
organization: "{{ org_name }}"
|
organization: "{{ org_name }}"
|
||||||
state: present
|
state: present
|
||||||
|
|
||||||
- name: Add localhost to the Inventory
|
- name: Add localhost to the Inventory
|
||||||
host:
|
awx.awx.host:
|
||||||
name: localhost
|
name: localhost
|
||||||
inventory: "{{ inv_name }}"
|
inventory: "{{ inv_name }}"
|
||||||
variables:
|
variables:
|
||||||
ansible_connection: local
|
ansible_connection: local
|
||||||
|
|
||||||
- name: Create a Credential
|
- name: Create a Credential
|
||||||
credential:
|
awx.awx.credential:
|
||||||
name: "{{ ssh_cred_name }}"
|
name: "{{ ssh_cred_name }}"
|
||||||
organization: "{{ org_name }}"
|
organization: "{{ org_name }}"
|
||||||
credential_type: 'Machine'
|
credential_type: 'Machine'
|
||||||
state: present
|
state: present
|
||||||
|
|
||||||
- name: Launch an Ad Hoc Command
|
- name: Launch an Ad Hoc Command
|
||||||
ad_hoc_command:
|
awx.awx.ad_hoc_command:
|
||||||
inventory: "{{ inv_name }}"
|
inventory: "{{ inv_name }}"
|
||||||
credential: "{{ ssh_cred_name }}"
|
credential: "{{ ssh_cred_name }}"
|
||||||
module_name: "command"
|
module_name: "command"
|
||||||
module_args: "sleep 100"
|
module_args: "sleep 100"
|
||||||
register: command
|
register: command
|
||||||
|
|
||||||
- assert:
|
- ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- "command is changed"
|
- "command is changed"
|
||||||
|
|
||||||
- name: Cancel the command
|
- name: Cancel the command
|
||||||
ad_hoc_command_cancel:
|
awx.awx.ad_hoc_command_cancel:
|
||||||
command_id: "{{ command.id }}"
|
command_id: "{{ command.id }}"
|
||||||
request_timeout: 60
|
request_timeout: 60
|
||||||
register: results
|
register: results
|
||||||
|
|
||||||
- assert:
|
- ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- results is changed
|
- results is changed
|
||||||
|
|
||||||
- name: "Wait for up to a minute until the job enters the can_cancel: False state"
|
- name: "Wait for up to a minute until the job enters the can_cancel: False state"
|
||||||
debug:
|
ansible.builtin.debug:
|
||||||
msg: "The job can_cancel status has transitioned into False, we can proceed with testing"
|
msg: "The job can_cancel status has transitioned into False, we can proceed with testing"
|
||||||
until: not job_status
|
until: not job_status
|
||||||
retries: 6
|
retries: 6
|
||||||
@@ -66,51 +66,51 @@
|
|||||||
job_status: "{{ lookup('awx.awx.controller_api', 'ad_hoc_commands/'+ command.id | string +'/cancel')['can_cancel'] }}"
|
job_status: "{{ lookup('awx.awx.controller_api', 'ad_hoc_commands/'+ command.id | string +'/cancel')['can_cancel'] }}"
|
||||||
|
|
||||||
- name: Cancel the command with hard error if it's not running
|
- name: Cancel the command with hard error if it's not running
|
||||||
ad_hoc_command_cancel:
|
awx.awx.ad_hoc_command_cancel:
|
||||||
command_id: "{{ command.id }}"
|
command_id: "{{ command.id }}"
|
||||||
fail_if_not_running: true
|
fail_if_not_running: true
|
||||||
register: results
|
register: results
|
||||||
ignore_errors: true
|
ignore_errors: true
|
||||||
|
|
||||||
- assert:
|
- ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- results is failed
|
- results is failed
|
||||||
|
|
||||||
- name: Cancel an already canceled command (assert failure)
|
- name: Cancel an already canceled command (assert failure)
|
||||||
ad_hoc_command_cancel:
|
awx.awx.ad_hoc_command_cancel:
|
||||||
command_id: "{{ command.id }}"
|
command_id: "{{ command.id }}"
|
||||||
fail_if_not_running: true
|
fail_if_not_running: true
|
||||||
register: results
|
register: results
|
||||||
ignore_errors: true
|
ignore_errors: true
|
||||||
|
|
||||||
- assert:
|
- ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- results is failed
|
- results is failed
|
||||||
|
|
||||||
- name: Check module fails with correct msg
|
- name: Check module fails with correct msg
|
||||||
ad_hoc_command_cancel:
|
awx.awx.ad_hoc_command_cancel:
|
||||||
command_id: 9999999999
|
command_id: 9999999999
|
||||||
register: result
|
register: result
|
||||||
ignore_errors: true
|
ignore_errors: true
|
||||||
|
|
||||||
- assert:
|
- ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- "result.msg == 'Unable to find command with id 9999999999'"
|
- "result.msg == 'Unable to find command with id 9999999999'"
|
||||||
|
|
||||||
- name: Delete the Credential
|
- name: Delete the Credential
|
||||||
credential:
|
awx.awx.credential:
|
||||||
name: "{{ ssh_cred_name }}"
|
name: "{{ ssh_cred_name }}"
|
||||||
organization: "{{ org_name }}"
|
organization: "{{ org_name }}"
|
||||||
credential_type: 'Machine'
|
credential_type: 'Machine'
|
||||||
state: absent
|
state: absent
|
||||||
|
|
||||||
- name: Delete the Inventory
|
- name: Delete the Inventory
|
||||||
inventory:
|
awx.awx.inventory:
|
||||||
name: "{{ inv_name }}"
|
name: "{{ inv_name }}"
|
||||||
organization: "{{ org_name }}"
|
organization: "{{ org_name }}"
|
||||||
state: absent
|
state: absent
|
||||||
|
|
||||||
- name: Remove the Organization
|
- name: Remove the Organization
|
||||||
organization:
|
awx.awx.organization:
|
||||||
name: "{{ org_name }}"
|
name: "{{ org_name }}"
|
||||||
state: absent
|
state: absent
|
||||||
|
|||||||
@@ -103,6 +103,7 @@
|
|||||||
- assert:
|
- assert:
|
||||||
that:
|
that:
|
||||||
- "result is changed"
|
- "result is changed"
|
||||||
|
- "'client_secret' in result"
|
||||||
|
|
||||||
- name: Rename an inventory
|
- name: Rename an inventory
|
||||||
application:
|
application:
|
||||||
|
|||||||
@@ -1,23 +1,23 @@
|
|||||||
---
|
---
|
||||||
- name: Generate a test ID
|
- name: Generate a test ID
|
||||||
set_fact:
|
ansible.builtin.set_fact:
|
||||||
test_id: "{{ lookup('password', '/dev/null chars=ascii_letters length=16') }}"
|
test_id: "{{ lookup('password', '/dev/null chars=ascii_letters length=16') }}"
|
||||||
when: test_id is not defined
|
when: test_id is not defined
|
||||||
|
|
||||||
- name: Generate hostnames
|
- name: Generate hostnames
|
||||||
set_fact:
|
ansible.builtin.set_fact:
|
||||||
hostname1: "AWX-Collection-tests-instance1.{{ test_id }}.example.com"
|
hostname1: "AWX-Collection-tests-instance1.{{ test_id }}.example.com"
|
||||||
hostname2: "AWX-Collection-tests-instance2.{{ test_id }}.example.com"
|
hostname2: "AWX-Collection-tests-instance2.{{ test_id }}.example.com"
|
||||||
hostname3: "AWX-Collection-tests-instance3.{{ test_id }}.example.com"
|
hostname3: "AWX-Collection-tests-instance3.{{ test_id }}.example.com"
|
||||||
register: facts
|
register: facts
|
||||||
|
|
||||||
- name: Get the k8s setting
|
- name: Get the k8s setting
|
||||||
set_fact:
|
ansible.builtin.set_fact:
|
||||||
IS_K8S: "{{ controller_settings['IS_K8S'] | default(False) }}"
|
IS_K8S: "{{ controller_settings['IS_K8S'] | default(False) }}"
|
||||||
vars:
|
vars:
|
||||||
controller_settings: "{{ lookup('awx.awx.controller_api', 'settings/all') }}"
|
controller_settings: "{{ lookup('awx.awx.controller_api', 'settings/all') }}"
|
||||||
|
|
||||||
- debug:
|
- ansible.builtin.debug:
|
||||||
msg: "Skipping instance test since this is instance is not running on a K8s platform"
|
msg: "Skipping instance test since this is instance is not running on a K8s platform"
|
||||||
when: not IS_K8S
|
when: not IS_K8S
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
- "{{ hostname2 }}"
|
- "{{ hostname2 }}"
|
||||||
register: result
|
register: result
|
||||||
|
|
||||||
- assert:
|
- ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- result is changed
|
- result is changed
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
capacity_adjustment: 0.4
|
capacity_adjustment: 0.4
|
||||||
register: result
|
register: result
|
||||||
|
|
||||||
- assert:
|
- ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- result is changed
|
- result is changed
|
||||||
|
|
||||||
@@ -54,7 +54,7 @@
|
|||||||
capacity_adjustment: 0.7
|
capacity_adjustment: 0.7
|
||||||
register: result
|
register: result
|
||||||
|
|
||||||
- assert:
|
- ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- result is changed
|
- result is changed
|
||||||
|
|
||||||
@@ -78,7 +78,7 @@
|
|||||||
node_state: installed
|
node_state: installed
|
||||||
register: result
|
register: result
|
||||||
|
|
||||||
- assert:
|
- ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- result is changed
|
- result is changed
|
||||||
|
|
||||||
@@ -89,7 +89,7 @@
|
|||||||
node_state: installed
|
node_state: installed
|
||||||
register: result
|
register: result
|
||||||
|
|
||||||
- assert:
|
- ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- result is changed
|
- result is changed
|
||||||
|
|
||||||
@@ -103,7 +103,7 @@
|
|||||||
- "{{ hostname2 }}"
|
- "{{ hostname2 }}"
|
||||||
register: result
|
register: result
|
||||||
|
|
||||||
- assert:
|
- ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- result is changed
|
- result is changed
|
||||||
|
|
||||||
@@ -115,7 +115,7 @@
|
|||||||
peers: []
|
peers: []
|
||||||
register: result
|
register: result
|
||||||
|
|
||||||
- assert:
|
- ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- result is changed
|
- result is changed
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
---
|
---
|
||||||
- name: Generate a random string for test
|
- name: Generate a random string for test
|
||||||
set_fact:
|
ansible.builtin.set_fact:
|
||||||
test_id: "{{ lookup('password', '/dev/null chars=ascii_letters length=16') }}"
|
test_id: "{{ lookup('password', '/dev/null chars=ascii_letters length=16') }}"
|
||||||
when: test_id is not defined
|
when: test_id is not defined
|
||||||
|
|
||||||
- name: Generate usernames
|
- name: Generate usernames
|
||||||
set_fact:
|
ansible.builtin.set_fact:
|
||||||
usernames:
|
usernames:
|
||||||
- "AWX-Collection-tests-api_lookup-user1-{{ test_id }}"
|
- "AWX-Collection-tests-api_lookup-user1-{{ test_id }}"
|
||||||
- "AWX-Collection-tests-api_lookup-user2-{{ test_id }}"
|
- "AWX-Collection-tests-api_lookup-user2-{{ test_id }}"
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
register: controller_meta
|
register: controller_meta
|
||||||
|
|
||||||
- name: Generate the name of our plugin
|
- name: Generate the name of our plugin
|
||||||
set_fact:
|
ansible.builtin.set_fact:
|
||||||
plugin_name: "{{ controller_meta.prefix }}.controller_api"
|
plugin_name: "{{ controller_meta.prefix }}.controller_api"
|
||||||
|
|
||||||
- name: Create all of our users
|
- name: Create all of our users
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
register: results
|
register: results
|
||||||
ignore_errors: true
|
ignore_errors: true
|
||||||
|
|
||||||
- assert:
|
- ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- "'dne' in (results.msg | lower)"
|
- "'dne' in (results.msg | lower)"
|
||||||
|
|
||||||
@@ -49,48 +49,48 @@
|
|||||||
loop: "{{ hosts }}"
|
loop: "{{ hosts }}"
|
||||||
|
|
||||||
- name: Test too many params (failure from validation of terms)
|
- name: Test too many params (failure from validation of terms)
|
||||||
set_fact:
|
ansible.builtin.set_fact:
|
||||||
junk: "{{ query(plugin_name, 'users', 'teams', query_params={}, ) }}"
|
junk: "{{ query(plugin_name, 'users', 'teams', query_params={}, ) }}"
|
||||||
ignore_errors: true
|
ignore_errors: true
|
||||||
register: result
|
register: result
|
||||||
|
|
||||||
- assert:
|
- ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- result is failed
|
- result is failed
|
||||||
- "'You must pass exactly one endpoint to query' in result.msg"
|
- "'You must pass exactly one endpoint to query' in result.msg"
|
||||||
|
|
||||||
- name: Try to load invalid endpoint
|
- name: Try to load invalid endpoint
|
||||||
set_fact:
|
ansible.builtin.set_fact:
|
||||||
junk: "{{ query(plugin_name, 'john', query_params={}, ) }}"
|
junk: "{{ query(plugin_name, 'john', query_params={}, ) }}"
|
||||||
ignore_errors: true
|
ignore_errors: true
|
||||||
register: result
|
register: result
|
||||||
|
|
||||||
- assert:
|
- ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- result is failed
|
- result is failed
|
||||||
- "'The requested object could not be found at' in result.msg"
|
- "'The requested object could not be found at' in result.msg"
|
||||||
|
|
||||||
- name: Load user of a specific name without promoting objects
|
- name: Load user of a specific name without promoting objects
|
||||||
set_fact:
|
ansible.builtin.set_fact:
|
||||||
users_list: "{{ lookup(plugin_name, 'users', query_params={ 'username' : user_creation_results['results'][0]['item'] }, return_objects=False) }}"
|
users_list: "{{ lookup(plugin_name, 'users', query_params={ 'username' : user_creation_results['results'][0]['item'] }, return_objects=False) }}"
|
||||||
|
|
||||||
- assert:
|
- ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- users_list['results'] | length() == 1
|
- users_list['results'] | length() == 1
|
||||||
- users_list['count'] == 1
|
- users_list['count'] == 1
|
||||||
- users_list['results'][0]['id'] == user_creation_results['results'][0]['id']
|
- users_list['results'][0]['id'] == user_creation_results['results'][0]['id']
|
||||||
|
|
||||||
- name: Load user of a specific name with promoting objects
|
- name: Load user of a specific name with promoting objects
|
||||||
set_fact:
|
ansible.builtin.set_fact:
|
||||||
user_objects: "{{ query(plugin_name, 'users', query_params={ 'username' : user_creation_results['results'][0]['item'] }, return_objects=True ) }}"
|
user_objects: "{{ query(plugin_name, 'users', query_params={ 'username' : user_creation_results['results'][0]['item'] }, return_objects=True ) }}"
|
||||||
|
|
||||||
- assert:
|
- ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- user_objects | length() == 1
|
- user_objects | length() == 1
|
||||||
- users_list['results'][0]['id'] == user_objects[0]['id']
|
- users_list['results'][0]['id'] == user_objects[0]['id']
|
||||||
|
|
||||||
- name: Loop over one user with the loop syntax
|
- name: Loop over one user with the loop syntax
|
||||||
assert:
|
ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- item['id'] == user_creation_results['results'][0]['id']
|
- item['id'] == user_creation_results['results'][0]['id']
|
||||||
loop: "{{ query(plugin_name, 'users', query_params={ 'username' : user_creation_results['results'][0]['item'] } ) }}"
|
loop: "{{ query(plugin_name, 'users', query_params={ 'username' : user_creation_results['results'][0]['item'] } ) }}"
|
||||||
@@ -98,91 +98,91 @@
|
|||||||
label: "{{ item.id }}"
|
label: "{{ item.id }}"
|
||||||
|
|
||||||
- name: Get a page of users as just ids
|
- name: Get a page of users as just ids
|
||||||
set_fact:
|
ansible.builtin.set_fact:
|
||||||
users: "{{ query(plugin_name, 'users', query_params={ 'username__endswith': test_id, 'page_size': 2 }, return_ids=True ) }}"
|
users: "{{ query(plugin_name, 'users', query_params={ 'username__endswith': test_id, 'page_size': 2 }, return_ids=True ) }}"
|
||||||
|
|
||||||
- debug:
|
- debug:
|
||||||
msg: "{{ users }}"
|
msg: "{{ users }}"
|
||||||
|
|
||||||
- name: Assert that user list has 2 ids only and that they are strings, not ints
|
- name: assert that user list has 2 ids only and that they are strings, not ints
|
||||||
assert:
|
ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- users | length() == 2
|
- users | length() == 2
|
||||||
- user_creation_results['results'][0]['id'] not in users
|
- user_creation_results['results'][0]['id'] not in users
|
||||||
- user_creation_results['results'][0]['id'] | string in users
|
- user_creation_results['results'][0]['id'] | string in users
|
||||||
|
|
||||||
- name: Get all users of a system through next attribute
|
- name: Get all users of a system through next attribute
|
||||||
set_fact:
|
ansible.builtin.set_fact:
|
||||||
users: "{{ query(plugin_name, 'users', query_params={ 'username__endswith': test_id, 'page_size': 1 }, return_all=true ) }}"
|
users: "{{ query(plugin_name, 'users', query_params={ 'username__endswith': test_id, 'page_size': 1 }, return_all=true ) }}"
|
||||||
|
|
||||||
- assert:
|
- ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- users | length() >= 3
|
- users | length() >= 3
|
||||||
|
|
||||||
- name: Get all of the users created with a max_objects of 1
|
- name: Get all of the users created with a max_objects of 1
|
||||||
set_fact:
|
ansible.builtin.set_fact:
|
||||||
users: "{{ lookup(plugin_name, 'users', query_params={ 'username__endswith': test_id, 'page_size': 1 }, return_all=true, max_objects=1 ) }}"
|
users: "{{ lookup(plugin_name, 'users', query_params={ 'username__endswith': test_id, 'page_size': 1 }, return_all=true, max_objects=1 ) }}"
|
||||||
ignore_errors: true
|
ignore_errors: true
|
||||||
register: max_user_errors
|
register: max_user_errors
|
||||||
|
|
||||||
- assert:
|
- ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- max_user_errors is failed
|
- max_user_errors is failed
|
||||||
- "'List view at users returned 3 objects, which is more than the maximum allowed by max_objects' in max_user_errors.msg"
|
- "'List view at users returned 3 objects, which is more than the maximum allowed by max_objects' in max_user_errors.msg"
|
||||||
|
|
||||||
- name: Get the ID of the first user created and verify that it is correct
|
- name: Get the ID of the first user created and verify that it is correct
|
||||||
assert:
|
ansible.builtin.assert:
|
||||||
that: "query(plugin_name, 'users', query_params={ 'username' : user_creation_results['results'][0]['item'] }, return_ids=True)[0] == user_creation_results['results'][0]['id'] | string"
|
that: "query(plugin_name, 'users', query_params={ 'username' : user_creation_results['results'][0]['item'] }, return_ids=True)[0] == user_creation_results['results'][0]['id'] | string"
|
||||||
|
|
||||||
- name: Try to get an ID of someone who does not exist
|
- name: Try to get an ID of someone who does not exist
|
||||||
set_fact:
|
ansible.builtin.set_fact:
|
||||||
failed_user_id: "{{ query(plugin_name, 'users', query_params={ 'username': 'john jacob jingleheimer schmidt' }, expect_one=True) }}"
|
failed_user_id: "{{ query(plugin_name, 'users', query_params={ 'username': 'john jacob jingleheimer schmidt' }, expect_one=True) }}"
|
||||||
register: result
|
register: result
|
||||||
ignore_errors: true
|
ignore_errors: true
|
||||||
|
|
||||||
- assert:
|
- ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- result is failed
|
- result is failed
|
||||||
- "'Expected one object from endpoint users' in result['msg']"
|
- "'Expected one object from endpoint users' in result['msg']"
|
||||||
|
|
||||||
- name: Lookup too many users
|
- name: Lookup too many users
|
||||||
set_fact:
|
ansible.builtin.set_fact:
|
||||||
too_many_user_ids: " {{ query(plugin_name, 'users', query_params={ 'username__endswith': test_id }, expect_one=True) }}"
|
too_many_user_ids: " {{ query(plugin_name, 'users', query_params={ 'username__endswith': test_id }, expect_one=True) }}"
|
||||||
register: results
|
register: results
|
||||||
ignore_errors: true
|
ignore_errors: true
|
||||||
|
|
||||||
- assert:
|
- ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- results is failed
|
- results is failed
|
||||||
- "'Expected one object from endpoint users, but obtained 3' in results['msg']"
|
- "'Expected one object from endpoint users, but obtained 3' in results['msg']"
|
||||||
|
|
||||||
- name: Get the ping page
|
- name: Get the ping page
|
||||||
set_fact:
|
ansible.builtin.set_fact:
|
||||||
ping_data: "{{ lookup(plugin_name, 'ping' ) }}"
|
ping_data: "{{ lookup(plugin_name, 'ping' ) }}"
|
||||||
register: results
|
register: results
|
||||||
|
|
||||||
- assert:
|
- ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- results is succeeded
|
- results is succeeded
|
||||||
- "'active_node' in ping_data"
|
- "'active_node' in ping_data"
|
||||||
|
|
||||||
- name: "Make sure that expect_objects fails on an API page"
|
- name: "Make sure that expect_objects fails on an API page"
|
||||||
set_fact:
|
ansible.builtin.set_fact:
|
||||||
my_var: "{{ lookup(plugin_name, 'settings/ui', expect_objects=True) }}"
|
my_var: "{{ lookup(plugin_name, 'settings/ui', expect_objects=True) }}"
|
||||||
ignore_errors: true
|
ignore_errors: true
|
||||||
register: results
|
register: results
|
||||||
|
|
||||||
- assert:
|
- ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- results is failed
|
- results is failed
|
||||||
- "'Did not obtain a list or detail view at settings/ui, and expect_objects or expect_one is set to True' in results.msg"
|
- "'Did not obtain a list or detail view at settings/ui, and expect_objects or expect_one is set to True' in results.msg"
|
||||||
|
|
||||||
# DOCS Example Tests
|
# DOCS Example Tests
|
||||||
- name: Load the UI settings
|
- name: Load the UI settings
|
||||||
set_fact:
|
ansible.builtin.set_fact:
|
||||||
controller_settings: "{{ lookup('awx.awx.controller_api', 'settings/ui') }}"
|
controller_settings: "{{ lookup('awx.awx.controller_api', 'settings/ui') }}"
|
||||||
|
|
||||||
- assert:
|
- ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- "'CUSTOM_LOGO' in controller_settings"
|
- "'CUSTOM_LOGO' in controller_settings"
|
||||||
|
|
||||||
@@ -191,7 +191,7 @@
|
|||||||
msg: "Admin users: {{ query('awx.awx.controller_api', 'users', query_params={ 'is_superuser': true }) | map(attribute='username') | join(', ') }}"
|
msg: "Admin users: {{ query('awx.awx.controller_api', 'users', query_params={ 'is_superuser': true }) | map(attribute='username') | join(', ') }}"
|
||||||
register: results
|
register: results
|
||||||
|
|
||||||
- assert:
|
- ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- "'admin' in results.msg"
|
- "'admin' in results.msg"
|
||||||
|
|
||||||
@@ -211,7 +211,7 @@
|
|||||||
register: role_revoke
|
register: role_revoke
|
||||||
when: "query('awx.awx.controller_api', 'users', query_params={ 'username': 'DNE_TESTING' }) | length == 1"
|
when: "query('awx.awx.controller_api', 'users', query_params={ 'username': 'DNE_TESTING' }) | length == 1"
|
||||||
|
|
||||||
- assert:
|
- ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- role_revoke is skipped
|
- role_revoke is skipped
|
||||||
|
|
||||||
@@ -227,7 +227,7 @@
|
|||||||
) | map(attribute='name') | list }}
|
) | map(attribute='name') | list }}
|
||||||
register: group_creation
|
register: group_creation
|
||||||
|
|
||||||
- assert:
|
- ansible.builtin.assert:
|
||||||
that: group_creation is changed
|
that: group_creation is changed
|
||||||
|
|
||||||
always:
|
always:
|
||||||
|
|||||||
@@ -1,50 +1,50 @@
|
|||||||
---
|
---
|
||||||
- name: Get our collection package
|
- name: Get our collection package
|
||||||
controller_meta:
|
awx.awx.controller_meta:
|
||||||
register: controller_meta
|
register: controller_meta
|
||||||
|
|
||||||
- name: Generate the name of our plugin
|
- name: Generate the name of our plugin
|
||||||
set_fact:
|
ansible.builtin.set_fact:
|
||||||
plugin_name: "{{ controller_meta.prefix }}.schedule_rrule"
|
plugin_name: "{{ controller_meta.prefix }}.schedule_rrule"
|
||||||
|
|
||||||
- name: Test too many params (failure from validation of terms)
|
- name: Test too many params (failure from validation of terms)
|
||||||
debug:
|
ansible.builtin.debug:
|
||||||
msg: "{{ query(plugin_name | string, 'none', 'weekly', start_date='2020-4-16 03:45:07') }}"
|
msg: "{{ query(plugin_name | string, 'none', 'weekly', start_date='2020-4-16 03:45:07') }}"
|
||||||
ignore_errors: true
|
ignore_errors: true
|
||||||
register: result
|
register: result
|
||||||
|
|
||||||
- assert:
|
- ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- result is failed
|
- result is failed
|
||||||
- "'You may only pass one schedule type in at a time' in result.msg"
|
- "'You may only pass one schedule type in at a time' in result.msg"
|
||||||
|
|
||||||
- name: Test invalid frequency (failure from validation of term)
|
- name: Test invalid frequency (failure from validation of term)
|
||||||
debug:
|
ansible.builtin.debug:
|
||||||
msg: "{{ query(plugin_name, 'john', start_date='2020-4-16 03:45:07') }}"
|
msg: "{{ query(plugin_name, 'john', start_date='2020-4-16 03:45:07') }}"
|
||||||
ignore_errors: true
|
ignore_errors: true
|
||||||
register: result
|
register: result
|
||||||
|
|
||||||
- assert:
|
- ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- result is failed
|
- result is failed
|
||||||
- "'Frequency of john is invalid' in result.msg"
|
- "'Frequency of john is invalid' in result.msg"
|
||||||
|
|
||||||
- name: Test an invalid start date (generic failure case from get_rrule)
|
- name: Test an invalid start date (generic failure case from get_rrule)
|
||||||
debug:
|
ansible.builtin.debug:
|
||||||
msg: "{{ query(plugin_name, 'none', start_date='invalid') }}"
|
msg: "{{ query(plugin_name, 'none', start_date='invalid') }}"
|
||||||
ignore_errors: true
|
ignore_errors: true
|
||||||
register: result
|
register: result
|
||||||
|
|
||||||
- assert:
|
- ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- result is failed
|
- result is failed
|
||||||
- "'Parameter start_date must be in the format YYYY-MM-DD' in result.msg"
|
- "'Parameter start_date must be in the format YYYY-MM-DD' in result.msg"
|
||||||
|
|
||||||
- name: Test end_on as count (generic success case)
|
- name: Test end_on as count (generic success case)
|
||||||
debug:
|
ansible.builtin.debug:
|
||||||
msg: "{{ query(plugin_name, 'minute', start_date='2020-4-16 03:45:07', end_on='2') }}"
|
msg: "{{ query(plugin_name, 'minute', start_date='2020-4-16 03:45:07', end_on='2') }}"
|
||||||
register: result
|
register: result
|
||||||
|
|
||||||
- assert:
|
- ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- result.msg == 'DTSTART;TZID=America/New_York:20200416T034507 RRULE:FREQ=MINUTELY;COUNT=2;INTERVAL=1'
|
- result.msg == 'DTSTART;TZID=America/New_York:20200416T034507 RRULE:FREQ=MINUTELY;COUNT=2;INTERVAL=1'
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
register: result
|
register: result
|
||||||
|
|
||||||
- name: Changing setting to true should have changed the value
|
- name: Changing setting to true should have changed the value
|
||||||
assert:
|
ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- "result is changed"
|
- "result is changed"
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
register: result
|
register: result
|
||||||
|
|
||||||
- name: Changing setting to true again should not change the value
|
- name: Changing setting to true again should not change the value
|
||||||
assert:
|
ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- "result is not changed"
|
- "result is not changed"
|
||||||
|
|
||||||
@@ -33,17 +33,17 @@
|
|||||||
register: result
|
register: result
|
||||||
|
|
||||||
- name: Changing setting back to false should have changed the value
|
- name: Changing setting back to false should have changed the value
|
||||||
assert:
|
ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- "result is changed"
|
- "result is changed"
|
||||||
|
|
||||||
- name: Set the value of AWX_ISOLATION_SHOW_PATHS to a baseline
|
- name: Set the value of AWX_ISOLATION_SHOW_PATHS to a baseline
|
||||||
settings:
|
awx.awx.settings:
|
||||||
name: AWX_ISOLATION_SHOW_PATHS
|
name: AWX_ISOLATION_SHOW_PATHS
|
||||||
value: '["/var/lib/awx/projects/"]'
|
value: '["/var/lib/awx/projects/"]'
|
||||||
|
|
||||||
- name: Set the value of AWX_ISOLATION_SHOW_PATHS to get an error back from the controller
|
- name: Set the value of AWX_ISOLATION_SHOW_PATHS to get an error back from the controller
|
||||||
settings:
|
awx.awx.settings:
|
||||||
settings:
|
settings:
|
||||||
AWX_ISOLATION_SHOW_PATHS:
|
AWX_ISOLATION_SHOW_PATHS:
|
||||||
'not': 'a valid'
|
'not': 'a valid'
|
||||||
@@ -51,75 +51,75 @@
|
|||||||
register: result
|
register: result
|
||||||
ignore_errors: true
|
ignore_errors: true
|
||||||
|
|
||||||
- assert:
|
- ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- "result is failed"
|
- "result is failed"
|
||||||
|
|
||||||
- name: Set the value of AWX_ISOLATION_SHOW_PATHS
|
- name: Set the value of AWX_ISOLATION_SHOW_PATHS
|
||||||
settings:
|
awx.awx.settings:
|
||||||
name: AWX_ISOLATION_SHOW_PATHS
|
name: AWX_ISOLATION_SHOW_PATHS
|
||||||
value: '["/var/lib/awx/projects/", "/tmp"]'
|
value: '["/var/lib/awx/projects/", "/tmp"]'
|
||||||
register: result
|
register: result
|
||||||
|
|
||||||
- assert:
|
- ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- "result is changed"
|
- "result is changed"
|
||||||
|
|
||||||
- name: Attempt to set the value of AWX_ISOLATION_BASE_PATH to what it already is
|
- name: Attempt to set the value of AWX_ISOLATION_BASE_PATH to what it already is
|
||||||
settings:
|
awx.awx.settings:
|
||||||
name: AWX_ISOLATION_BASE_PATH
|
name: AWX_ISOLATION_BASE_PATH
|
||||||
value: /tmp
|
value: /tmp
|
||||||
register: result
|
register: result
|
||||||
|
|
||||||
- debug:
|
- ansible.builtin.debug:
|
||||||
msg: "{{ result }}"
|
msg: "{{ result }}"
|
||||||
|
|
||||||
- assert:
|
- ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- "result is not changed"
|
- "result is not changed"
|
||||||
|
|
||||||
- name: Apply a single setting via settings
|
- name: Apply a single setting via settings
|
||||||
settings:
|
awx.awx.settings:
|
||||||
name: AWX_ISOLATION_SHOW_PATHS
|
name: AWX_ISOLATION_SHOW_PATHS
|
||||||
value: '["/var/lib/awx/projects/", "/var/tmp"]'
|
value: '["/var/lib/awx/projects/", "/var/tmp"]'
|
||||||
register: result
|
register: result
|
||||||
|
|
||||||
- assert:
|
- ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- "result is changed"
|
- "result is changed"
|
||||||
|
|
||||||
- name: Apply multiple setting via settings with no change
|
- name: Apply multiple setting via settings with no change
|
||||||
settings:
|
awx.awx.settings:
|
||||||
settings:
|
settings:
|
||||||
AWX_ISOLATION_BASE_PATH: /tmp
|
AWX_ISOLATION_BASE_PATH: /tmp
|
||||||
AWX_ISOLATION_SHOW_PATHS: ["/var/lib/awx/projects/", "/var/tmp"]
|
AWX_ISOLATION_SHOW_PATHS: ["/var/lib/awx/projects/", "/var/tmp"]
|
||||||
register: result
|
register: result
|
||||||
|
|
||||||
- debug:
|
- ansible.builtin.debug:
|
||||||
msg: "{{ result }}"
|
msg: "{{ result }}"
|
||||||
|
|
||||||
- assert:
|
- ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- "result is not changed"
|
- "result is not changed"
|
||||||
|
|
||||||
- name: Apply multiple setting via settings with change
|
- name: Apply multiple setting via settings with change
|
||||||
settings:
|
awx.awx.settings:
|
||||||
settings:
|
settings:
|
||||||
AWX_ISOLATION_BASE_PATH: /tmp
|
AWX_ISOLATION_BASE_PATH: /tmp
|
||||||
AWX_ISOLATION_SHOW_PATHS: []
|
AWX_ISOLATION_SHOW_PATHS: []
|
||||||
register: result
|
register: result
|
||||||
|
|
||||||
- assert:
|
- ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- "result is changed"
|
- "result is changed"
|
||||||
|
|
||||||
- name: Handle an omit value
|
- name: Handle an omit value
|
||||||
settings:
|
awx.awx.settings:
|
||||||
name: AWX_ISOLATION_BASE_PATH
|
name: AWX_ISOLATION_BASE_PATH
|
||||||
value: '{{ junk_var | default(omit) }}'
|
value: '{{ junk_var | default(omit) }}'
|
||||||
register: result
|
register: result
|
||||||
ignore_errors: true
|
ignore_errors: true
|
||||||
|
|
||||||
- assert:
|
- ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- "'Unable to update settings' in result.msg"
|
- "'Unable to update settings' in result.msg"
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
test: ad_hoc_command,host,role
|
test: ad_hoc_command,host,role
|
||||||
tasks:
|
tasks:
|
||||||
- name: DEBUG - make sure variables are what we expect
|
- name: DEBUG - make sure variables are what we expect
|
||||||
debug:
|
ansible.builtin.debug:
|
||||||
msg: |
|
msg: |
|
||||||
Running tests at location:
|
Running tests at location:
|
||||||
{{ loc_tests }}
|
{{ loc_tests }}
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
{{ test | trim | split(',') }}
|
{{ test | trim | split(',') }}
|
||||||
|
|
||||||
- name: "Include test targets"
|
- name: "Include test targets"
|
||||||
include_tasks: "{{ loc_tests }}{{ test_name }}/tasks/main.yml"
|
ansible.builtin.include_tasks: "{{ loc_tests }}{{ test_name }}/tasks/main.yml"
|
||||||
loop: "{{ test | trim | split(',') }}"
|
loop: "{{ test | trim | split(',') }}"
|
||||||
loop_control:
|
loop_control:
|
||||||
loop_var: test_name
|
loop_var: test_name
|
||||||
|
|||||||
@@ -149,15 +149,32 @@ This workflow will take the generated images and promote them to quay.io.
|
|||||||

|

|
||||||
|
|
||||||
## Send notifications
|
## Send notifications
|
||||||
|
|
||||||
Send notifications to the following groups:
|
Send notifications to the following groups:
|
||||||
|
|
||||||
* [Ansible Community forum](https://forum.ansible.com/)
|
* [Ansible Community forum](https://forum.ansible.com/)
|
||||||
* #social:ansible.com IRC (@newsbot for inclusion in bullhorn)
|
* [#social:ansible.com](https://matrix.to/#/#social:ansible.com) `@newsbot` for inclusion in The Bullhorn)
|
||||||
* #awx:ansible.com (no @newsbot in this room)
|
* [#awx:ansible.com](https://forum.ansible.com/g/AWX/members)
|
||||||
* #aap-controller slack channel
|
* #aap-controller Slack channel
|
||||||
|
|
||||||
These messages are templated out for you in the output of `get_next_release.yml`.
|
These messages are templated out for you in the output of `get_next_release.yml`.
|
||||||
|
|
||||||
Note: the slack message is the same as the IRC message.
|
Note: The Slack message is the same as the Matrix message.
|
||||||
|
|
||||||
|
### Announcements
|
||||||
|
|
||||||
|
* Provide enough information for the reader
|
||||||
|
* Include:
|
||||||
|
* **What:** What is this, why should someone care
|
||||||
|
* **Why:** Why is this important
|
||||||
|
* **How:** How do I use this (docs, config options)
|
||||||
|
* **Call to action:** What type of feedback are we looking for
|
||||||
|
* Link to PR(s) for larger features
|
||||||
|
* `@newsbot` supports [Markdown](https://www.markdownguide.org/cheat-sheet/), so use formatted links, bullet points
|
||||||
|
* Release Manager posts into social Matrix Channel
|
||||||
|
* Appears in next weeks [Bulhorn](https://forum.ansible.com/c/news/bullhorn)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Create operator hub PRs.
|
## Create operator hub PRs.
|
||||||
Operator hub PRs are generated via an Ansible Playbook. See someone on the AWX team for the location of the playbooks and instructions on how to run them.
|
Operator hub PRs are generated via an Ansible Playbook. See someone on the AWX team for the location of the playbooks and instructions on how to run them.
|
||||||
|
|||||||
@@ -1,27 +1,27 @@
|
|||||||
---
|
---
|
||||||
- name: Include pre-flight checks
|
- name: Include pre-flight checks
|
||||||
include_tasks: preflight.yml
|
ansible.builtin.include_tasks: preflight.yml
|
||||||
|
|
||||||
- name: Create _sources directory
|
- name: Create _sources directory
|
||||||
file:
|
ansible.builtin.file:
|
||||||
path: "{{ sources_dest }}"
|
path: "{{ sources_dest }}"
|
||||||
state: 'directory'
|
state: 'directory'
|
||||||
mode: '0700'
|
mode: '0700'
|
||||||
|
|
||||||
- name: debug minikube_setup
|
- name: debug minikube_setup
|
||||||
debug:
|
ansible.builtin.debug:
|
||||||
var: minikube_setup
|
var: minikube_setup
|
||||||
|
|
||||||
# Linux block
|
# Linux block
|
||||||
- block:
|
- block:
|
||||||
- name: Download Minikube
|
- name: Download Minikube
|
||||||
get_url:
|
ansible.builtin.get_url:
|
||||||
url: "{{ minikube_url_linux }}"
|
url: "{{ minikube_url_linux }}"
|
||||||
dest: "{{ sources_dest }}/minikube"
|
dest: "{{ sources_dest }}/minikube"
|
||||||
mode: 0755
|
mode: 0755
|
||||||
|
|
||||||
- name: Download Kubectl
|
- name: Download Kubectl
|
||||||
get_url:
|
ansible.builtin.get_url:
|
||||||
url: "{{ kubectl_url_linux }}"
|
url: "{{ kubectl_url_linux }}"
|
||||||
dest: "{{ sources_dest }}/kubectl"
|
dest: "{{ sources_dest }}/kubectl"
|
||||||
mode: 0755
|
mode: 0755
|
||||||
@@ -33,13 +33,13 @@
|
|||||||
# MacOS block
|
# MacOS block
|
||||||
- block:
|
- block:
|
||||||
- name: Download Minikube
|
- name: Download Minikube
|
||||||
get_url:
|
ansible.builtin.get_url:
|
||||||
url: "{{ minikube_url_macos }}"
|
url: "{{ minikube_url_macos }}"
|
||||||
dest: "{{ sources_dest }}/minikube"
|
dest: "{{ sources_dest }}/minikube"
|
||||||
mode: 0755
|
mode: 0755
|
||||||
|
|
||||||
- name: Download Kubectl
|
- name: Download Kubectl
|
||||||
get_url:
|
ansible.builtin.get_url:
|
||||||
url: "{{ kubectl_url_macos }}"
|
url: "{{ kubectl_url_macos }}"
|
||||||
dest: "{{ sources_dest }}/kubectl"
|
dest: "{{ sources_dest }}/kubectl"
|
||||||
mode: 0755
|
mode: 0755
|
||||||
@@ -50,18 +50,18 @@
|
|||||||
|
|
||||||
- block:
|
- block:
|
||||||
- name: Starting Minikube
|
- name: Starting Minikube
|
||||||
shell: "{{ sources_dest }}/minikube start --driver={{ driver }} --install-addons=true --addons={{ addons | join(',') }}"
|
ansible.builtin.shell: "{{ sources_dest }}/minikube start --driver={{ driver }} --install-addons=true --addons={{ addons | join(',') }}"
|
||||||
register: minikube_stdout
|
register: minikube_stdout
|
||||||
|
|
||||||
- name: Enable Ingress Controller on Minikube
|
- name: Enable Ingress Controller on Minikube
|
||||||
shell: "{{ sources_dest }}/minikube addons enable ingress"
|
ansible.builtin.shell: "{{ sources_dest }}/minikube addons enable ingress"
|
||||||
when:
|
when:
|
||||||
- minikube_stdout.rc == 0
|
- minikube_stdout.rc == 0
|
||||||
register: _minikube_ingress
|
register: _minikube_ingress
|
||||||
ignore_errors: true
|
ignore_errors: true
|
||||||
|
|
||||||
- name: Show Minikube Ingress known-issue 7332 warning
|
- name: Show Minikube Ingress known-issue 7332 warning
|
||||||
pause:
|
ansible.builtin.pause:
|
||||||
seconds: 5
|
seconds: 5
|
||||||
prompt: "The Minikube Ingress addon has been disabled since it looks like you are hitting https://github.com/kubernetes/minikube/issues/7332"
|
prompt: "The Minikube Ingress addon has been disabled since it looks like you are hitting https://github.com/kubernetes/minikube/issues/7332"
|
||||||
when:
|
when:
|
||||||
@@ -90,13 +90,13 @@
|
|||||||
register: _service_account_secret
|
register: _service_account_secret
|
||||||
|
|
||||||
- name: Load Minikube Bearer Token
|
- name: Load Minikube Bearer Token
|
||||||
set_fact:
|
ansible.builtin.set_fact:
|
||||||
service_account_token: '{{ _service_account_secret["resources"][0]["data"]["token"] | b64decode }}'
|
service_account_token: '{{ _service_account_secret["resources"][0]["data"]["token"] | b64decode }}'
|
||||||
when:
|
when:
|
||||||
- _service_account_secret["resources"][0]["data"] | length
|
- _service_account_secret["resources"][0]["data"] | length
|
||||||
|
|
||||||
- name: Render minikube credential JSON template
|
- name: Render minikube credential JSON template
|
||||||
template:
|
ansible.builtin.template:
|
||||||
src: bootstrap_minikube.py.j2
|
src: bootstrap_minikube.py.j2
|
||||||
dest: "{{ sources_dest }}/bootstrap_minikube.py"
|
dest: "{{ sources_dest }}/bootstrap_minikube.py"
|
||||||
mode: '0600'
|
mode: '0600'
|
||||||
|
|||||||
@@ -13,12 +13,12 @@
|
|||||||
cert_subject: "/C=US/ST=NC/L=Durham/O=awx/CN="
|
cert_subject: "/C=US/ST=NC/L=Durham/O=awx/CN="
|
||||||
tasks:
|
tasks:
|
||||||
- name: Generate certificates for keycloak
|
- name: Generate certificates for keycloak
|
||||||
command: 'openssl req -new -x509 -days 365 -nodes -out {{ public_key_file }} -keyout {{ private_key_file }} -subj "{{ cert_subject }}"'
|
ansible.builtin.command: 'openssl req -new -x509 -days 365 -nodes -out {{ public_key_file }} -keyout {{ private_key_file }} -subj "{{ cert_subject }}"'
|
||||||
args:
|
args:
|
||||||
creates: "{{ public_key_file }}"
|
creates: "{{ public_key_file }}"
|
||||||
|
|
||||||
- name: Load certs, existing and new SAML settings
|
- name: Load certs, existing and new SAML settings
|
||||||
set_fact:
|
ansible.builtin.set_fact:
|
||||||
private_key: "{{ private_key_content }}"
|
private_key: "{{ private_key_content }}"
|
||||||
public_key: "{{ public_key_content }}"
|
public_key: "{{ public_key_content }}"
|
||||||
public_key_trimmed: "{{ public_key_content | regex_replace('-----BEGIN CERTIFICATE-----\\\\n', '') | regex_replace('\\\\n-----END CERTIFICATE-----', '') }}"
|
public_key_trimmed: "{{ public_key_content | regex_replace('-----BEGIN CERTIFICATE-----\\\\n', '') | regex_replace('\\\\n-----END CERTIFICATE-----', '') }}"
|
||||||
@@ -32,18 +32,18 @@
|
|||||||
private_key_content: "{{ lookup('file', private_key_file) | regex_replace('\n', '\\\\n') }}"
|
private_key_content: "{{ lookup('file', private_key_file) | regex_replace('\n', '\\\\n') }}"
|
||||||
|
|
||||||
- name: Displauy existing SAML configuration
|
- name: Displauy existing SAML configuration
|
||||||
debug:
|
ansible.builtin.debug:
|
||||||
msg:
|
msg:
|
||||||
- "Here is your existing SAML configuration for reference:"
|
- "Here is your existing SAML configuration for reference:"
|
||||||
- "{{ existing_saml }}"
|
- "{{ existing_saml }}"
|
||||||
- "Here is your existing OIDC configuration for reference:"
|
- "Here is your existing OIDC configuration for reference:"
|
||||||
- "{{ existing_oidc }}"
|
- "{{ existing_oidc }}"
|
||||||
|
|
||||||
- pause:
|
- ansible.builtin.pause:
|
||||||
prompt: "Continuing to run this will replace your existing saml and OIDC settings (displayed above). They will all be captured except for your private key. Be sure that is backed up before continuing"
|
prompt: "Continuing to run this will replace your existing saml and OIDC settings (displayed above). They will all be captured except for your private key. Be sure that is backed up before continuing"
|
||||||
|
|
||||||
- name: Write out the existing content
|
- name: Write out the existing content
|
||||||
copy:
|
ansible.builtin.copy:
|
||||||
dest: "../_sources/{{ item.filename }}"
|
dest: "../_sources/{{ item.filename }}"
|
||||||
content: "{{ item.content }}"
|
content: "{{ item.content }}"
|
||||||
loop:
|
loop:
|
||||||
@@ -65,7 +65,7 @@
|
|||||||
validate_certs: False
|
validate_certs: False
|
||||||
|
|
||||||
- name: Get a keycloak token
|
- name: Get a keycloak token
|
||||||
uri:
|
ansible.builtin.uri:
|
||||||
url: "https://localhost:8443/auth/realms/master/protocol/openid-connect/token"
|
url: "https://localhost:8443/auth/realms/master/protocol/openid-connect/token"
|
||||||
method: POST
|
method: POST
|
||||||
body_format: form-urlencoded
|
body_format: form-urlencoded
|
||||||
@@ -78,12 +78,12 @@
|
|||||||
register: keycloak_response
|
register: keycloak_response
|
||||||
|
|
||||||
- name: Template the AWX realm
|
- name: Template the AWX realm
|
||||||
template:
|
ansible.builtin.template:
|
||||||
src: keycloak.awx.realm.json.j2
|
src: keycloak.awx.realm.json.j2
|
||||||
dest: "{{ keycloak_realm_template }}"
|
dest: "{{ keycloak_realm_template }}"
|
||||||
|
|
||||||
- name: Create the AWX realm
|
- name: Create the AWX realm
|
||||||
uri:
|
ansible.builtin.uri:
|
||||||
url: "https://localhost:8443/auth/admin/realms"
|
url: "https://localhost:8443/auth/admin/realms"
|
||||||
method: POST
|
method: POST
|
||||||
body_format: json
|
body_format: json
|
||||||
|
|||||||
@@ -7,21 +7,21 @@
|
|||||||
awx_host: "https://localhost:8043"
|
awx_host: "https://localhost:8043"
|
||||||
tasks:
|
tasks:
|
||||||
- name: Load existing and new LDAP settings
|
- name: Load existing and new LDAP settings
|
||||||
set_fact:
|
ansible.builtin.set_fact:
|
||||||
existing_ldap: "{{ lookup('awx.awx.controller_api', 'settings/ldap', host=awx_host, verify_ssl=false) }}"
|
existing_ldap: "{{ lookup('awx.awx.controller_api', 'settings/ldap', host=awx_host, verify_ssl=false) }}"
|
||||||
new_ldap: "{{ lookup('template', 'ldap_settings.json.j2') }}"
|
new_ldap: "{{ lookup('template', 'ldap_settings.json.j2') }}"
|
||||||
|
|
||||||
- name: Display existing LDAP configuration
|
- name: Display existing LDAP configuration
|
||||||
debug:
|
ansible.builtin.debug:
|
||||||
msg:
|
msg:
|
||||||
- "Here is your existing LDAP configuration for reference:"
|
- "Here is your existing LDAP configuration for reference:"
|
||||||
- "{{ existing_ldap }}"
|
- "{{ existing_ldap }}"
|
||||||
|
|
||||||
- pause:
|
- ansible.builtin.pause:
|
||||||
prompt: "Continuing to run this will replace your existing ldap settings (displayed above). They will all be captured. Be sure that is backed up before continuing"
|
prompt: "Continuing to run this will replace your existing ldap settings (displayed above). They will all be captured. Be sure that is backed up before continuing"
|
||||||
|
|
||||||
- name: Write out the existing content
|
- name: Write out the existing content
|
||||||
copy:
|
ansible.builtin.copy:
|
||||||
dest: "../_sources/existing_ldap_adapter_settings.json"
|
dest: "../_sources/existing_ldap_adapter_settings.json"
|
||||||
content: "{{ existing_ldap }}"
|
content: "{{ existing_ldap }}"
|
||||||
|
|
||||||
|
|||||||
@@ -26,21 +26,21 @@
|
|||||||
ansible_connection: httpapi
|
ansible_connection: httpapi
|
||||||
|
|
||||||
- name: Load existing and new Logging settings
|
- name: Load existing and new Logging settings
|
||||||
set_fact:
|
ansible.builtin.set_fact:
|
||||||
existing_logging: "{{ lookup('awx.awx.controller_api', 'settings/logging', host=awx_host, verify_ssl=false) }}"
|
existing_logging: "{{ lookup('awx.awx.controller_api', 'settings/logging', host=awx_host, verify_ssl=false) }}"
|
||||||
new_logging: "{{ lookup('template', 'logging.json.j2') }}"
|
new_logging: "{{ lookup('template', 'logging.json.j2') }}"
|
||||||
|
|
||||||
- name: Display existing Logging configuration
|
- name: Display existing Logging configuration
|
||||||
debug:
|
ansible.builtin.debug:
|
||||||
msg:
|
msg:
|
||||||
- "Here is your existing SAML configuration for reference:"
|
- "Here is your existing SAML configuration for reference:"
|
||||||
- "{{ existing_logging }}"
|
- "{{ existing_logging }}"
|
||||||
|
|
||||||
- pause:
|
- pause:
|
||||||
prompt: "Continuing to run this will replace your existing logging settings (displayed above). They will all be captured except for your connection password. Be sure that is backed up before continuing"
|
ansible.builtin.prompt: "Continuing to run this will replace your existing logging settings (displayed above). They will all be captured except for your connection password. Be sure that is backed up before continuing"
|
||||||
|
|
||||||
- name: Write out the existing content
|
- name: Write out the existing content
|
||||||
copy:
|
ansible.builtin.copy:
|
||||||
dest: "../_sources/existing_logging.json"
|
dest: "../_sources/existing_logging.json"
|
||||||
content: "{{ existing_logging }}"
|
content: "{{ existing_logging }}"
|
||||||
|
|
||||||
|
|||||||
@@ -7,21 +7,21 @@
|
|||||||
awx_host: "https://localhost:8043"
|
awx_host: "https://localhost:8043"
|
||||||
tasks:
|
tasks:
|
||||||
- name: Load existing and new tacacs+ settings
|
- name: Load existing and new tacacs+ settings
|
||||||
set_fact:
|
ansible.builtin.set_fact:
|
||||||
existing_tacacs: "{{ lookup('awx.awx.controller_api', 'settings/tacacsplus', host=awx_host, verify_ssl=false) }}"
|
existing_tacacs: "{{ lookup('awx.awx.controller_api', 'settings/tacacsplus', host=awx_host, verify_ssl=false) }}"
|
||||||
new_tacacs: "{{ lookup('template', 'tacacsplus_settings.json.j2') }}"
|
new_tacacs: "{{ lookup('template', 'tacacsplus_settings.json.j2') }}"
|
||||||
|
|
||||||
- name: Display existing tacacs+ configuration
|
- name: Display existing tacacs+ configuration
|
||||||
debug:
|
ansible.builtin.debug:
|
||||||
msg:
|
msg:
|
||||||
- "Here is your existing tacacsplus configuration for reference:"
|
- "Here is your existing tacacsplus configuration for reference:"
|
||||||
- "{{ existing_tacacs }}"
|
- "{{ existing_tacacs }}"
|
||||||
|
|
||||||
- pause:
|
- ansible.builtin.pause:
|
||||||
prompt: "Continuing to run this will replace your existing tacacs settings (displayed above). They will all be captured. Be sure that is backed up before continuing"
|
prompt: "Continuing to run this will replace your existing tacacs settings (displayed above). They will all be captured. Be sure that is backed up before continuing"
|
||||||
|
|
||||||
- name: Write out the existing content
|
- name: Write out the existing content
|
||||||
copy:
|
ansible.builtin.copy:
|
||||||
dest: "../_sources/existing_tacacsplus_adapter_settings.json"
|
dest: "../_sources/existing_tacacsplus_adapter_settings.json"
|
||||||
content: "{{ existing_tacacs }}"
|
content: "{{ existing_tacacs }}"
|
||||||
|
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
gather_facts: False
|
gather_facts: False
|
||||||
tasks:
|
tasks:
|
||||||
- name: Unseal the vault
|
- name: Unseal the vault
|
||||||
include_role:
|
ansible.builtin.include_role:
|
||||||
name: vault
|
name: vault
|
||||||
tasks_from: unseal
|
tasks_from: unseal
|
||||||
|
|
||||||
- name: Display root token
|
- name: Display root token
|
||||||
debug:
|
ansible.builtin.debug:
|
||||||
var: Initial_Root_Token
|
var: Initial_Root_Token
|
||||||
|
|||||||
Reference in New Issue
Block a user