mirror of
https://github.com/ansible/awx.git
synced 2026-02-05 11:34:43 -03:30
Compare commits
70 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4f829ab93f | ||
|
|
5ce78b383d | ||
|
|
2404faa5d8 | ||
|
|
e72b2fac6d | ||
|
|
11b36982cd | ||
|
|
d438a93fd2 | ||
|
|
dfa8d44eb8 | ||
|
|
4470e9ca26 | ||
|
|
cf0fe729f5 | ||
|
|
913e06b865 | ||
|
|
4d7c49372c | ||
|
|
5c338e582a | ||
|
|
eacf819caf | ||
|
|
273415b9aa | ||
|
|
e612a167e2 | ||
|
|
0a7d6e603e | ||
|
|
f05bed6366 | ||
|
|
cbe6c5bd3b | ||
|
|
e9ac44f561 | ||
|
|
aab29bef5b | ||
|
|
9f42d9426c | ||
|
|
b369609f07 | ||
|
|
01d31231c0 | ||
|
|
c46be3e718 | ||
|
|
38aedcdd48 | ||
|
|
59bec99f4c | ||
|
|
b0249a9a8b | ||
|
|
acb6d9c4d1 | ||
|
|
78912d20f7 | ||
|
|
52712a0d9a | ||
|
|
a7c787af02 | ||
|
|
e269634afc | ||
|
|
4daf574899 | ||
|
|
067ba7f8fe | ||
|
|
7d77727a60 | ||
|
|
47560fdf7c | ||
|
|
2882f4afb5 | ||
|
|
aaceccc426 | ||
|
|
1f3242900a | ||
|
|
e6232957b4 | ||
|
|
1a72ff4c47 | ||
|
|
c585c3d07d | ||
|
|
1413c1be7b | ||
|
|
a5c057cc18 | ||
|
|
9c06dc7106 | ||
|
|
fe850dff38 | ||
|
|
40840e3789 | ||
|
|
e3750f541e | ||
|
|
5d49fe2170 | ||
|
|
ca0e8102fd | ||
|
|
164d305b51 | ||
|
|
4d33e484d0 | ||
|
|
69502bc133 | ||
|
|
17c89ed412 | ||
|
|
f5b6bd65cf | ||
|
|
c6f1806a23 | ||
|
|
c65e6ba30b | ||
|
|
d511d63a5a | ||
|
|
30741e762a | ||
|
|
7687eddf6d | ||
|
|
9cfed6f2a8 | ||
|
|
95896b1acd | ||
|
|
68fe23d8b7 | ||
|
|
dd372548a9 | ||
|
|
8d6e1f0927 | ||
|
|
98fa1fc813 | ||
|
|
8ec97235e3 | ||
|
|
468e79a754 | ||
|
|
d8bd72054d | ||
|
|
ae9032ce03 |
4
Makefile
4
Makefile
@@ -124,8 +124,8 @@ virtualenv_ansible:
|
||||
if [ ! -d "$(VENV_BASE)/ansible" ]; then \
|
||||
virtualenv -p python --system-site-packages $(VENV_BASE)/ansible && \
|
||||
$(VENV_BASE)/ansible/bin/pip install $(PIP_OPTIONS) --ignore-installed six packaging appdirs && \
|
||||
$(VENV_BASE)/ansible/bin/pip install $(PIP_OPTIONS) --ignore-installed setuptools==41.0.1 && \
|
||||
$(VENV_BASE)/ansible/bin/pip install $(PIP_OPTIONS) --ignore-installed pip==19.1.1; \
|
||||
$(VENV_BASE)/ansible/bin/pip install $(PIP_OPTIONS) --ignore-installed setuptools==36.0.1 && \
|
||||
$(VENV_BASE)/ansible/bin/pip install $(PIP_OPTIONS) --ignore-installed pip==9.0.1; \
|
||||
fi; \
|
||||
fi
|
||||
|
||||
|
||||
@@ -1246,7 +1246,7 @@ class OrganizationSerializer(BaseSerializer):
|
||||
applications = self.reverse('api:organization_applications_list', kwargs={'pk': obj.pk}),
|
||||
activity_stream = self.reverse('api:organization_activity_stream_list', kwargs={'pk': obj.pk}),
|
||||
notification_templates = self.reverse('api:organization_notification_templates_list', kwargs={'pk': obj.pk}),
|
||||
notification_templates_any = self.reverse('api:organization_notification_templates_any_list', kwargs={'pk': obj.pk}),
|
||||
notification_templates_started = self.reverse('api:organization_notification_templates_started_list', kwargs={'pk': obj.pk}),
|
||||
notification_templates_success = self.reverse('api:organization_notification_templates_success_list', kwargs={'pk': obj.pk}),
|
||||
notification_templates_error = self.reverse('api:organization_notification_templates_error_list', kwargs={'pk': obj.pk}),
|
||||
object_roles = self.reverse('api:organization_object_roles_list', kwargs={'pk': obj.pk}),
|
||||
@@ -1352,7 +1352,7 @@ class ProjectSerializer(UnifiedJobTemplateSerializer, ProjectOptionsSerializer):
|
||||
scm_inventory_sources = self.reverse('api:project_scm_inventory_sources', kwargs={'pk': obj.pk}),
|
||||
schedules = self.reverse('api:project_schedules_list', kwargs={'pk': obj.pk}),
|
||||
activity_stream = self.reverse('api:project_activity_stream_list', kwargs={'pk': obj.pk}),
|
||||
notification_templates_any = self.reverse('api:project_notification_templates_any_list', kwargs={'pk': obj.pk}),
|
||||
notification_templates_started = self.reverse('api:project_notification_templates_started_list', kwargs={'pk': obj.pk}),
|
||||
notification_templates_success = self.reverse('api:project_notification_templates_success_list', kwargs={'pk': obj.pk}),
|
||||
notification_templates_error = self.reverse('api:project_notification_templates_error_list', kwargs={'pk': obj.pk}),
|
||||
access_list = self.reverse('api:project_access_list', kwargs={'pk': obj.pk}),
|
||||
@@ -1943,6 +1943,25 @@ class InventorySourceOptionsSerializer(BaseSerializer):
|
||||
|
||||
return super(InventorySourceOptionsSerializer, self).validate(attrs)
|
||||
|
||||
# TODO: remove when old 'credential' fields are removed
|
||||
def get_summary_fields(self, obj):
|
||||
summary_fields = super(InventorySourceOptionsSerializer, self).get_summary_fields(obj)
|
||||
all_creds = []
|
||||
if 'credential' in summary_fields:
|
||||
cred = obj.get_cloud_credential()
|
||||
if cred:
|
||||
summarized_cred = {
|
||||
'id': cred.id, 'name': cred.name, 'description': cred.description,
|
||||
'kind': cred.kind, 'cloud': True
|
||||
}
|
||||
summary_fields['credential'] = summarized_cred
|
||||
all_creds.append(summarized_cred)
|
||||
summary_fields['credential']['credential_type_id'] = cred.credential_type_id
|
||||
else:
|
||||
summary_fields.pop('credential')
|
||||
summary_fields['credentials'] = all_creds
|
||||
return summary_fields
|
||||
|
||||
|
||||
class InventorySourceSerializer(UnifiedJobTemplateSerializer, InventorySourceOptionsSerializer):
|
||||
|
||||
@@ -1970,7 +1989,7 @@ class InventorySourceSerializer(UnifiedJobTemplateSerializer, InventorySourceOpt
|
||||
activity_stream = self.reverse('api:inventory_source_activity_stream_list', kwargs={'pk': obj.pk}),
|
||||
hosts = self.reverse('api:inventory_source_hosts_list', kwargs={'pk': obj.pk}),
|
||||
groups = self.reverse('api:inventory_source_groups_list', kwargs={'pk': obj.pk}),
|
||||
notification_templates_any = self.reverse('api:inventory_source_notification_templates_any_list', kwargs={'pk': obj.pk}),
|
||||
notification_templates_started = self.reverse('api:inventory_source_notification_templates_started_list', kwargs={'pk': obj.pk}),
|
||||
notification_templates_success = self.reverse('api:inventory_source_notification_templates_success_list', kwargs={'pk': obj.pk}),
|
||||
notification_templates_error = self.reverse('api:inventory_source_notification_templates_error_list', kwargs={'pk': obj.pk}),
|
||||
))
|
||||
@@ -2792,7 +2811,7 @@ class JobTemplateSerializer(JobTemplateMixin, UnifiedJobTemplateSerializer, JobO
|
||||
schedules = self.reverse('api:job_template_schedules_list', kwargs={'pk': obj.pk}),
|
||||
activity_stream = self.reverse('api:job_template_activity_stream_list', kwargs={'pk': obj.pk}),
|
||||
launch = self.reverse('api:job_template_launch', kwargs={'pk': obj.pk}),
|
||||
notification_templates_any = self.reverse('api:job_template_notification_templates_any_list', kwargs={'pk': obj.pk}),
|
||||
notification_templates_started = self.reverse('api:job_template_notification_templates_started_list', kwargs={'pk': obj.pk}),
|
||||
notification_templates_success = self.reverse('api:job_template_notification_templates_success_list', kwargs={'pk': obj.pk}),
|
||||
notification_templates_error = self.reverse('api:job_template_notification_templates_error_list', kwargs={'pk': obj.pk}),
|
||||
access_list = self.reverse('api:job_template_access_list', kwargs={'pk': obj.pk}),
|
||||
@@ -3204,7 +3223,7 @@ class SystemJobTemplateSerializer(UnifiedJobTemplateSerializer):
|
||||
jobs = self.reverse('api:system_job_template_jobs_list', kwargs={'pk': obj.pk}),
|
||||
schedules = self.reverse('api:system_job_template_schedules_list', kwargs={'pk': obj.pk}),
|
||||
launch = self.reverse('api:system_job_template_launch', kwargs={'pk': obj.pk}),
|
||||
notification_templates_any = self.reverse('api:system_job_template_notification_templates_any_list', kwargs={'pk': obj.pk}),
|
||||
notification_templates_started = self.reverse('api:system_job_template_notification_templates_started_list', kwargs={'pk': obj.pk}),
|
||||
notification_templates_success = self.reverse('api:system_job_template_notification_templates_success_list', kwargs={'pk': obj.pk}),
|
||||
notification_templates_error = self.reverse('api:system_job_template_notification_templates_error_list', kwargs={'pk': obj.pk}),
|
||||
|
||||
@@ -3271,7 +3290,7 @@ class WorkflowJobTemplateSerializer(JobTemplateMixin, LabelsListMixin, UnifiedJo
|
||||
workflow_nodes = self.reverse('api:workflow_job_template_workflow_nodes_list', kwargs={'pk': obj.pk}),
|
||||
labels = self.reverse('api:workflow_job_template_label_list', kwargs={'pk': obj.pk}),
|
||||
activity_stream = self.reverse('api:workflow_job_template_activity_stream_list', kwargs={'pk': obj.pk}),
|
||||
notification_templates_any = self.reverse('api:workflow_job_template_notification_templates_any_list', kwargs={'pk': obj.pk}),
|
||||
notification_templates_started = self.reverse('api:workflow_job_template_notification_templates_started_list', kwargs={'pk': obj.pk}),
|
||||
notification_templates_success = self.reverse('api:workflow_job_template_notification_templates_success_list', kwargs={'pk': obj.pk}),
|
||||
notification_templates_error = self.reverse('api:workflow_job_template_notification_templates_error_list', kwargs={'pk': obj.pk}),
|
||||
access_list = self.reverse('api:workflow_job_template_access_list', kwargs={'pk': obj.pk}),
|
||||
|
||||
@@ -13,8 +13,8 @@ from awx.api.views import (
|
||||
InventorySourceCredentialsList,
|
||||
InventorySourceGroupsList,
|
||||
InventorySourceHostsList,
|
||||
InventorySourceNotificationTemplatesAnyList,
|
||||
InventorySourceNotificationTemplatesErrorList,
|
||||
InventorySourceNotificationTemplatesStartedList,
|
||||
InventorySourceNotificationTemplatesSuccessList,
|
||||
)
|
||||
|
||||
@@ -29,8 +29,8 @@ urls = [
|
||||
url(r'^(?P<pk>[0-9]+)/credentials/$', InventorySourceCredentialsList.as_view(), name='inventory_source_credentials_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/groups/$', InventorySourceGroupsList.as_view(), name='inventory_source_groups_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/hosts/$', InventorySourceHostsList.as_view(), name='inventory_source_hosts_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/notification_templates_any/$', InventorySourceNotificationTemplatesAnyList.as_view(),
|
||||
name='inventory_source_notification_templates_any_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/notification_templates_started/$', InventorySourceNotificationTemplatesStartedList.as_view(),
|
||||
name='inventory_source_notification_templates_started_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/notification_templates_error/$', InventorySourceNotificationTemplatesErrorList.as_view(),
|
||||
name='inventory_source_notification_templates_error_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/notification_templates_success/$', InventorySourceNotificationTemplatesSuccessList.as_view(),
|
||||
|
||||
@@ -13,8 +13,8 @@ from awx.api.views import (
|
||||
JobTemplateSchedulesList,
|
||||
JobTemplateSurveySpec,
|
||||
JobTemplateActivityStreamList,
|
||||
JobTemplateNotificationTemplatesAnyList,
|
||||
JobTemplateNotificationTemplatesErrorList,
|
||||
JobTemplateNotificationTemplatesStartedList,
|
||||
JobTemplateNotificationTemplatesSuccessList,
|
||||
JobTemplateInstanceGroupsList,
|
||||
JobTemplateAccessList,
|
||||
@@ -34,8 +34,8 @@ urls = [
|
||||
url(r'^(?P<pk>[0-9]+)/schedules/$', JobTemplateSchedulesList.as_view(), name='job_template_schedules_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/survey_spec/$', JobTemplateSurveySpec.as_view(), name='job_template_survey_spec'),
|
||||
url(r'^(?P<pk>[0-9]+)/activity_stream/$', JobTemplateActivityStreamList.as_view(), name='job_template_activity_stream_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/notification_templates_any/$', JobTemplateNotificationTemplatesAnyList.as_view(),
|
||||
name='job_template_notification_templates_any_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/notification_templates_started/$', JobTemplateNotificationTemplatesStartedList.as_view(),
|
||||
name='job_template_notification_templates_started_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/notification_templates_error/$', JobTemplateNotificationTemplatesErrorList.as_view(),
|
||||
name='job_template_notification_templates_error_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/notification_templates_success/$', JobTemplateNotificationTemplatesSuccessList.as_view(),
|
||||
|
||||
@@ -15,8 +15,8 @@ from awx.api.views import (
|
||||
OrganizationCredentialList,
|
||||
OrganizationActivityStreamList,
|
||||
OrganizationNotificationTemplatesList,
|
||||
OrganizationNotificationTemplatesAnyList,
|
||||
OrganizationNotificationTemplatesErrorList,
|
||||
OrganizationNotificationTemplatesStartedList,
|
||||
OrganizationNotificationTemplatesSuccessList,
|
||||
OrganizationInstanceGroupsList,
|
||||
OrganizationObjectRolesList,
|
||||
@@ -25,7 +25,7 @@ from awx.api.views import (
|
||||
)
|
||||
|
||||
|
||||
urls = [
|
||||
urls = [
|
||||
url(r'^$', OrganizationList.as_view(), name='organization_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/$', OrganizationDetail.as_view(), name='organization_detail'),
|
||||
url(r'^(?P<pk>[0-9]+)/users/$', OrganizationUsersList.as_view(), name='organization_users_list'),
|
||||
@@ -37,8 +37,8 @@ urls = [
|
||||
url(r'^(?P<pk>[0-9]+)/credentials/$', OrganizationCredentialList.as_view(), name='organization_credential_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/activity_stream/$', OrganizationActivityStreamList.as_view(), name='organization_activity_stream_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/notification_templates/$', OrganizationNotificationTemplatesList.as_view(), name='organization_notification_templates_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/notification_templates_any/$', OrganizationNotificationTemplatesAnyList.as_view(),
|
||||
name='organization_notification_templates_any_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/notification_templates_started/$', OrganizationNotificationTemplatesStartedList.as_view(),
|
||||
name='organization_notification_templates_started_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/notification_templates_error/$', OrganizationNotificationTemplatesErrorList.as_view(),
|
||||
name='organization_notification_templates_error_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/notification_templates_success/$', OrganizationNotificationTemplatesSuccessList.as_view(),
|
||||
|
||||
@@ -14,8 +14,8 @@ from awx.api.views import (
|
||||
ProjectUpdatesList,
|
||||
ProjectActivityStreamList,
|
||||
ProjectSchedulesList,
|
||||
ProjectNotificationTemplatesAnyList,
|
||||
ProjectNotificationTemplatesErrorList,
|
||||
ProjectNotificationTemplatesStartedList,
|
||||
ProjectNotificationTemplatesSuccessList,
|
||||
ProjectObjectRolesList,
|
||||
ProjectAccessList,
|
||||
@@ -34,10 +34,11 @@ urls = [
|
||||
url(r'^(?P<pk>[0-9]+)/project_updates/$', ProjectUpdatesList.as_view(), name='project_updates_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/activity_stream/$', ProjectActivityStreamList.as_view(), name='project_activity_stream_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/schedules/$', ProjectSchedulesList.as_view(), name='project_schedules_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/notification_templates_any/$', ProjectNotificationTemplatesAnyList.as_view(), name='project_notification_templates_any_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/notification_templates_error/$', ProjectNotificationTemplatesErrorList.as_view(), name='project_notification_templates_error_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/notification_templates_success/$', ProjectNotificationTemplatesSuccessList.as_view(),
|
||||
name='project_notification_templates_success_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/notification_templates_started/$', ProjectNotificationTemplatesStartedList.as_view(),
|
||||
name='project_notification_templates_started_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/object_roles/$', ProjectObjectRolesList.as_view(), name='project_object_roles_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/access_list/$', ProjectAccessList.as_view(), name='project_access_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/copy/$', ProjectCopy.as_view(), name='project_copy'),
|
||||
|
||||
@@ -9,8 +9,8 @@ from awx.api.views import (
|
||||
SystemJobTemplateLaunch,
|
||||
SystemJobTemplateJobsList,
|
||||
SystemJobTemplateSchedulesList,
|
||||
SystemJobTemplateNotificationTemplatesAnyList,
|
||||
SystemJobTemplateNotificationTemplatesErrorList,
|
||||
SystemJobTemplateNotificationTemplatesStartedList,
|
||||
SystemJobTemplateNotificationTemplatesSuccessList,
|
||||
)
|
||||
|
||||
@@ -21,8 +21,8 @@ urls = [
|
||||
url(r'^(?P<pk>[0-9]+)/launch/$', SystemJobTemplateLaunch.as_view(), name='system_job_template_launch'),
|
||||
url(r'^(?P<pk>[0-9]+)/jobs/$', SystemJobTemplateJobsList.as_view(), name='system_job_template_jobs_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/schedules/$', SystemJobTemplateSchedulesList.as_view(), name='system_job_template_schedules_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/notification_templates_any/$', SystemJobTemplateNotificationTemplatesAnyList.as_view(),
|
||||
name='system_job_template_notification_templates_any_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/notification_templates_started/$', SystemJobTemplateNotificationTemplatesStartedList.as_view(),
|
||||
name='system_job_template_notification_templates_started_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/notification_templates_error/$', SystemJobTemplateNotificationTemplatesErrorList.as_view(),
|
||||
name='system_job_template_notification_templates_error_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/notification_templates_success/$', SystemJobTemplateNotificationTemplatesSuccessList.as_view(),
|
||||
|
||||
@@ -13,8 +13,8 @@ from awx.api.views import (
|
||||
WorkflowJobTemplateSurveySpec,
|
||||
WorkflowJobTemplateWorkflowNodesList,
|
||||
WorkflowJobTemplateActivityStreamList,
|
||||
WorkflowJobTemplateNotificationTemplatesAnyList,
|
||||
WorkflowJobTemplateNotificationTemplatesErrorList,
|
||||
WorkflowJobTemplateNotificationTemplatesStartedList,
|
||||
WorkflowJobTemplateNotificationTemplatesSuccessList,
|
||||
WorkflowJobTemplateAccessList,
|
||||
WorkflowJobTemplateObjectRolesList,
|
||||
@@ -32,8 +32,8 @@ urls = [
|
||||
url(r'^(?P<pk>[0-9]+)/survey_spec/$', WorkflowJobTemplateSurveySpec.as_view(), name='workflow_job_template_survey_spec'),
|
||||
url(r'^(?P<pk>[0-9]+)/workflow_nodes/$', WorkflowJobTemplateWorkflowNodesList.as_view(), name='workflow_job_template_workflow_nodes_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/activity_stream/$', WorkflowJobTemplateActivityStreamList.as_view(), name='workflow_job_template_activity_stream_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/notification_templates_any/$', WorkflowJobTemplateNotificationTemplatesAnyList.as_view(),
|
||||
name='workflow_job_template_notification_templates_any_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/notification_templates_started/$', WorkflowJobTemplateNotificationTemplatesStartedList.as_view(),
|
||||
name='workflow_job_template_notification_templates_started_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/notification_templates_error/$', WorkflowJobTemplateNotificationTemplatesErrorList.as_view(),
|
||||
name='workflow_job_template_notification_templates_error_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/notification_templates_success/$', WorkflowJobTemplateNotificationTemplatesSuccessList.as_view(),
|
||||
|
||||
@@ -116,6 +116,7 @@ from awx.api.views.organization import ( # noqa
|
||||
OrganizationNotificationTemplatesList,
|
||||
OrganizationNotificationTemplatesAnyList,
|
||||
OrganizationNotificationTemplatesErrorList,
|
||||
OrganizationNotificationTemplatesStartedList,
|
||||
OrganizationNotificationTemplatesSuccessList,
|
||||
OrganizationInstanceGroupsList,
|
||||
OrganizationAccessList,
|
||||
@@ -747,22 +748,20 @@ class ProjectNotificationTemplatesAnyList(SubListCreateAttachDetachAPIView):
|
||||
model = models.NotificationTemplate
|
||||
serializer_class = serializers.NotificationTemplateSerializer
|
||||
parent_model = models.Project
|
||||
relationship = 'notification_templates_any'
|
||||
|
||||
|
||||
class ProjectNotificationTemplatesErrorList(SubListCreateAttachDetachAPIView):
|
||||
class ProjectNotificationTemplatesStartedList(ProjectNotificationTemplatesAnyList):
|
||||
|
||||
relationship = 'notification_templates_started'
|
||||
|
||||
|
||||
class ProjectNotificationTemplatesErrorList(ProjectNotificationTemplatesAnyList):
|
||||
|
||||
model = models.NotificationTemplate
|
||||
serializer_class = serializers.NotificationTemplateSerializer
|
||||
parent_model = models.Project
|
||||
relationship = 'notification_templates_error'
|
||||
|
||||
|
||||
class ProjectNotificationTemplatesSuccessList(SubListCreateAttachDetachAPIView):
|
||||
class ProjectNotificationTemplatesSuccessList(ProjectNotificationTemplatesAnyList):
|
||||
|
||||
model = models.NotificationTemplate
|
||||
serializer_class = serializers.NotificationTemplateSerializer
|
||||
parent_model = models.Project
|
||||
relationship = 'notification_templates_success'
|
||||
|
||||
|
||||
@@ -2102,7 +2101,6 @@ class InventorySourceNotificationTemplatesAnyList(SubListCreateAttachDetachAPIVi
|
||||
model = models.NotificationTemplate
|
||||
serializer_class = serializers.NotificationTemplateSerializer
|
||||
parent_model = models.InventorySource
|
||||
relationship = 'notification_templates_any'
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
parent = self.get_parent_object()
|
||||
@@ -2113,6 +2111,11 @@ class InventorySourceNotificationTemplatesAnyList(SubListCreateAttachDetachAPIVi
|
||||
return super(InventorySourceNotificationTemplatesAnyList, self).post(request, *args, **kwargs)
|
||||
|
||||
|
||||
class InventorySourceNotificationTemplatesStartedList(InventorySourceNotificationTemplatesAnyList):
|
||||
|
||||
relationship = 'notification_templates_started'
|
||||
|
||||
|
||||
class InventorySourceNotificationTemplatesErrorList(InventorySourceNotificationTemplatesAnyList):
|
||||
|
||||
relationship = 'notification_templates_error'
|
||||
@@ -2626,22 +2629,20 @@ class JobTemplateNotificationTemplatesAnyList(SubListCreateAttachDetachAPIView):
|
||||
model = models.NotificationTemplate
|
||||
serializer_class = serializers.NotificationTemplateSerializer
|
||||
parent_model = models.JobTemplate
|
||||
relationship = 'notification_templates_any'
|
||||
|
||||
|
||||
class JobTemplateNotificationTemplatesErrorList(SubListCreateAttachDetachAPIView):
|
||||
class JobTemplateNotificationTemplatesStartedList(JobTemplateNotificationTemplatesAnyList):
|
||||
|
||||
relationship = 'notification_templates_started'
|
||||
|
||||
|
||||
class JobTemplateNotificationTemplatesErrorList(JobTemplateNotificationTemplatesAnyList):
|
||||
|
||||
model = models.NotificationTemplate
|
||||
serializer_class = serializers.NotificationTemplateSerializer
|
||||
parent_model = models.JobTemplate
|
||||
relationship = 'notification_templates_error'
|
||||
|
||||
|
||||
class JobTemplateNotificationTemplatesSuccessList(SubListCreateAttachDetachAPIView):
|
||||
class JobTemplateNotificationTemplatesSuccessList(JobTemplateNotificationTemplatesAnyList):
|
||||
|
||||
model = models.NotificationTemplate
|
||||
serializer_class = serializers.NotificationTemplateSerializer
|
||||
parent_model = models.JobTemplate
|
||||
relationship = 'notification_templates_success'
|
||||
|
||||
|
||||
@@ -3234,22 +3235,20 @@ class WorkflowJobTemplateNotificationTemplatesAnyList(SubListCreateAttachDetachA
|
||||
model = models.NotificationTemplate
|
||||
serializer_class = serializers.NotificationTemplateSerializer
|
||||
parent_model = models.WorkflowJobTemplate
|
||||
relationship = 'notification_templates_any'
|
||||
|
||||
|
||||
class WorkflowJobTemplateNotificationTemplatesErrorList(SubListCreateAttachDetachAPIView):
|
||||
class WorkflowJobTemplateNotificationTemplatesStartedList(WorkflowJobTemplateNotificationTemplatesAnyList):
|
||||
|
||||
relationship = 'notification_templates_started'
|
||||
|
||||
|
||||
class WorkflowJobTemplateNotificationTemplatesErrorList(WorkflowJobTemplateNotificationTemplatesAnyList):
|
||||
|
||||
model = models.NotificationTemplate
|
||||
serializer_class = serializers.NotificationTemplateSerializer
|
||||
parent_model = models.WorkflowJobTemplate
|
||||
relationship = 'notification_templates_error'
|
||||
|
||||
|
||||
class WorkflowJobTemplateNotificationTemplatesSuccessList(SubListCreateAttachDetachAPIView):
|
||||
class WorkflowJobTemplateNotificationTemplatesSuccessList(WorkflowJobTemplateNotificationTemplatesAnyList):
|
||||
|
||||
model = models.NotificationTemplate
|
||||
serializer_class = serializers.NotificationTemplateSerializer
|
||||
parent_model = models.WorkflowJobTemplate
|
||||
relationship = 'notification_templates_success'
|
||||
|
||||
|
||||
@@ -3411,22 +3410,20 @@ class SystemJobTemplateNotificationTemplatesAnyList(SubListCreateAttachDetachAPI
|
||||
model = models.NotificationTemplate
|
||||
serializer_class = serializers.NotificationTemplateSerializer
|
||||
parent_model = models.SystemJobTemplate
|
||||
relationship = 'notification_templates_any'
|
||||
|
||||
|
||||
class SystemJobTemplateNotificationTemplatesErrorList(SubListCreateAttachDetachAPIView):
|
||||
class SystemJobTemplateNotificationTemplatesStartedList(SystemJobTemplateNotificationTemplatesAnyList):
|
||||
|
||||
relationship = 'notification_templates_started'
|
||||
|
||||
|
||||
class SystemJobTemplateNotificationTemplatesErrorList(SystemJobTemplateNotificationTemplatesAnyList):
|
||||
|
||||
model = models.NotificationTemplate
|
||||
serializer_class = serializers.NotificationTemplateSerializer
|
||||
parent_model = models.SystemJobTemplate
|
||||
relationship = 'notification_templates_error'
|
||||
|
||||
|
||||
class SystemJobTemplateNotificationTemplatesSuccessList(SubListCreateAttachDetachAPIView):
|
||||
class SystemJobTemplateNotificationTemplatesSuccessList(SystemJobTemplateNotificationTemplatesAnyList):
|
||||
|
||||
model = models.NotificationTemplate
|
||||
serializer_class = serializers.NotificationTemplateSerializer
|
||||
parent_model = models.SystemJobTemplate
|
||||
relationship = 'notification_templates_success'
|
||||
|
||||
|
||||
|
||||
@@ -178,22 +178,20 @@ class OrganizationNotificationTemplatesAnyList(SubListCreateAttachDetachAPIView)
|
||||
model = NotificationTemplate
|
||||
serializer_class = NotificationTemplateSerializer
|
||||
parent_model = Organization
|
||||
relationship = 'notification_templates_any'
|
||||
|
||||
|
||||
class OrganizationNotificationTemplatesErrorList(SubListCreateAttachDetachAPIView):
|
||||
class OrganizationNotificationTemplatesStartedList(OrganizationNotificationTemplatesAnyList):
|
||||
|
||||
relationship = 'notification_templates_started'
|
||||
|
||||
|
||||
class OrganizationNotificationTemplatesErrorList(OrganizationNotificationTemplatesAnyList):
|
||||
|
||||
model = NotificationTemplate
|
||||
serializer_class = NotificationTemplateSerializer
|
||||
parent_model = Organization
|
||||
relationship = 'notification_templates_error'
|
||||
|
||||
|
||||
class OrganizationNotificationTemplatesSuccessList(SubListCreateAttachDetachAPIView):
|
||||
class OrganizationNotificationTemplatesSuccessList(OrganizationNotificationTemplatesAnyList):
|
||||
|
||||
model = NotificationTemplate
|
||||
serializer_class = NotificationTemplateSerializer
|
||||
parent_model = Organization
|
||||
relationship = 'notification_templates_success'
|
||||
|
||||
|
||||
|
||||
@@ -1265,7 +1265,7 @@ class TeamAccess(BaseAccess):
|
||||
(self.user.admin_of_organizations.exists() or self.user.auditor_of_organizations.exists()):
|
||||
return self.model.objects.all()
|
||||
return self.model.objects.filter(
|
||||
Q(organization=Organization.accessible_pk_qs(self.user, 'member_role')) |
|
||||
Q(organization__in=Organization.accessible_pk_qs(self.user, 'member_role')) |
|
||||
Q(pk__in=self.model.accessible_pk_qs(self.user, 'read_role'))
|
||||
)
|
||||
|
||||
|
||||
@@ -153,10 +153,16 @@ def projects_by_scm_type(since):
|
||||
return counts
|
||||
|
||||
|
||||
def _get_isolated_datetime(last_check):
|
||||
if last_check:
|
||||
return last_check.isoformat()
|
||||
return last_check
|
||||
|
||||
|
||||
@register('instance_info')
|
||||
def instance_info(since):
|
||||
info = {}
|
||||
instances = models.Instance.objects.values_list('hostname').annotate().values(
|
||||
instances = models.Instance.objects.values_list('hostname').values(
|
||||
'uuid', 'version', 'capacity', 'cpu', 'memory', 'managed_by_policy', 'hostname', 'last_isolated_check', 'enabled')
|
||||
for instance in instances:
|
||||
instance_info = {
|
||||
@@ -166,7 +172,7 @@ def instance_info(since):
|
||||
'cpu': instance['cpu'],
|
||||
'memory': instance['memory'],
|
||||
'managed_by_policy': instance['managed_by_policy'],
|
||||
'last_isolated_check': instance['last_isolated_check'],
|
||||
'last_isolated_check': _get_isolated_datetime(instance['last_isolated_check']),
|
||||
'enabled': instance['enabled']
|
||||
}
|
||||
info[instance['uuid']] = instance_info
|
||||
@@ -187,12 +193,12 @@ def job_counts(since):
|
||||
def job_instance_counts(since):
|
||||
counts = {}
|
||||
job_types = models.UnifiedJob.objects.exclude(launch_type='sync').values_list(
|
||||
'execution_node', 'launch_type').annotate(job_launch_type=Count('launch_type'))
|
||||
'execution_node', 'launch_type').annotate(job_launch_type=Count('launch_type')).order_by()
|
||||
for job in job_types:
|
||||
counts.setdefault(job[0], {}).setdefault('launch_type', {})[job[1]] = job[2]
|
||||
|
||||
job_statuses = models.UnifiedJob.objects.exclude(launch_type='sync').values_list(
|
||||
'execution_node', 'status').annotate(job_status=Count('status'))
|
||||
'execution_node', 'status').annotate(job_status=Count('status')).order_by()
|
||||
for job in job_statuses:
|
||||
counts.setdefault(job[0], {}).setdefault('status', {})[job[1]] = job[2]
|
||||
return counts
|
||||
|
||||
@@ -119,24 +119,28 @@ def ship(path):
|
||||
"""
|
||||
Ship gathered metrics via the Insights agent
|
||||
"""
|
||||
agent = 'insights-client'
|
||||
if shutil.which(agent) is None:
|
||||
logger.error('could not find {} on PATH'.format(agent))
|
||||
return
|
||||
logger.debug('shipping analytics file: {}'.format(path))
|
||||
try:
|
||||
cmd = [
|
||||
agent, '--payload', path, '--content-type', settings.INSIGHTS_AGENT_MIME
|
||||
]
|
||||
output = smart_str(subprocess.check_output(cmd, timeout=60 * 5))
|
||||
logger.debug(output)
|
||||
# reset the `last_run` when data is shipped
|
||||
run_now = now()
|
||||
state = TowerAnalyticsState.get_solo()
|
||||
state.last_run = run_now
|
||||
state.save()
|
||||
agent = 'insights-client'
|
||||
if shutil.which(agent) is None:
|
||||
logger.error('could not find {} on PATH'.format(agent))
|
||||
return
|
||||
logger.debug('shipping analytics file: {}'.format(path))
|
||||
try:
|
||||
cmd = [
|
||||
agent, '--payload', path, '--content-type', settings.INSIGHTS_AGENT_MIME
|
||||
]
|
||||
output = smart_str(subprocess.check_output(cmd, timeout=60 * 5))
|
||||
logger.debug(output)
|
||||
# reset the `last_run` when data is shipped
|
||||
run_now = now()
|
||||
state = TowerAnalyticsState.get_solo()
|
||||
state.last_run = run_now
|
||||
state.save()
|
||||
|
||||
except subprocess.CalledProcessError:
|
||||
logger.exception('{} failure:'.format(cmd))
|
||||
except subprocess.TimeoutExpired:
|
||||
logger.exception('{} timeout:'.format(cmd))
|
||||
except subprocess.CalledProcessError:
|
||||
logger.exception('{} failure:'.format(cmd))
|
||||
except subprocess.TimeoutExpired:
|
||||
logger.exception('{} timeout:'.format(cmd))
|
||||
finally:
|
||||
# cleanup tar.gz
|
||||
os.remove(path)
|
||||
|
||||
@@ -10,6 +10,7 @@ from django.core.management.base import BaseCommand
|
||||
from django.db import connection as django_connection, connections
|
||||
from kombu import Exchange, Queue
|
||||
|
||||
from awx.main.utils.handlers import AWXProxyHandler
|
||||
from awx.main.dispatch import get_local_queuename, reaper
|
||||
from awx.main.dispatch.control import Control
|
||||
from awx.main.dispatch.kombu import Connection
|
||||
@@ -121,6 +122,12 @@ class Command(BaseCommand):
|
||||
|
||||
reaper.reap()
|
||||
consumer = None
|
||||
|
||||
# don't ship external logs inside the dispatcher's parent process
|
||||
# this exists to work around a race condition + deadlock bug on fork
|
||||
# in cpython itself:
|
||||
# https://bugs.python.org/issue37429
|
||||
AWXProxyHandler.disable()
|
||||
with Connection(settings.BROKER_URL) as conn:
|
||||
try:
|
||||
bcast = 'tower_broadcast_all'
|
||||
|
||||
51
awx/main/migrations/0081_v360_notify_on_start.py
Normal file
51
awx/main/migrations/0081_v360_notify_on_start.py
Normal file
@@ -0,0 +1,51 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.20 on 2019-05-30 20:35
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
def forwards_split_unified_job_template_any(apps, schema_editor):
|
||||
UnifiedJobTemplate = apps.get_model('main', 'unifiedjobtemplate')
|
||||
for ujt in UnifiedJobTemplate.objects.all():
|
||||
for ujt_notification in ujt.notification_templates_any.all():
|
||||
ujt.notification_templates_success.add(ujt_notification)
|
||||
ujt.notification_templates_error.add(ujt_notification)
|
||||
|
||||
def forwards_split_organization_any(apps, schema_editor):
|
||||
Organization = apps.get_model('main', 'organization')
|
||||
for org in Organization.objects.all():
|
||||
for org_notification in org.notification_templates_any.all():
|
||||
org.notification_templates_success.add(org_notification)
|
||||
org.notification_templates_error.add(org_notification)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('main', '0080_v360_replace_job_origin'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='organization',
|
||||
name='notification_templates_started',
|
||||
field=models.ManyToManyField(blank=True, related_name='organization_notification_templates_for_started', to='main.NotificationTemplate'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='unifiedjobtemplate',
|
||||
name='notification_templates_started',
|
||||
field=models.ManyToManyField(blank=True, related_name='unifiedjobtemplate_notification_templates_for_started', to='main.NotificationTemplate'),
|
||||
),
|
||||
# Separate out "any" notifications into "success" and "error" before the "any" state gets deleted.
|
||||
migrations.RunPython(forwards_split_unified_job_template_any, None),
|
||||
migrations.RunPython(forwards_split_organization_any, None),
|
||||
migrations.RemoveField(
|
||||
model_name='organization',
|
||||
name='notification_templates_any',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='unifiedjobtemplate',
|
||||
name='notification_templates_any',
|
||||
),
|
||||
]
|
||||
@@ -163,18 +163,18 @@ class AdHocCommand(UnifiedJob, JobNotificationMixin):
|
||||
all_orgs.add(h.inventory.organization)
|
||||
active_templates = dict(error=set(),
|
||||
success=set(),
|
||||
any=set())
|
||||
started=set())
|
||||
base_notification_templates = NotificationTemplate.objects
|
||||
for org in all_orgs:
|
||||
for templ in base_notification_templates.filter(organization_notification_templates_for_errors=org):
|
||||
active_templates['error'].add(templ)
|
||||
for templ in base_notification_templates.filter(organization_notification_templates_for_success=org):
|
||||
active_templates['success'].add(templ)
|
||||
for templ in base_notification_templates.filter(organization_notification_templates_for_any=org):
|
||||
active_templates['any'].add(templ)
|
||||
for templ in base_notification_templates.filter(organization_notification_templates_for_started=org):
|
||||
active_templates['started'].add(templ)
|
||||
active_templates['error'] = list(active_templates['error'])
|
||||
active_templates['any'] = list(active_templates['any'])
|
||||
active_templates['success'] = list(active_templates['success'])
|
||||
active_templates['started'] = list(active_templates['started'])
|
||||
return active_templates
|
||||
|
||||
def get_passwords_needed_to_start(self):
|
||||
|
||||
@@ -386,14 +386,13 @@ class NotificationFieldsModel(BaseModel):
|
||||
related_name='%(class)s_notification_templates_for_success'
|
||||
)
|
||||
|
||||
notification_templates_any = models.ManyToManyField(
|
||||
notification_templates_started = models.ManyToManyField(
|
||||
"NotificationTemplate",
|
||||
blank=True,
|
||||
related_name='%(class)s_notification_templates_for_any'
|
||||
related_name='%(class)s_notification_templates_for_started'
|
||||
)
|
||||
|
||||
|
||||
|
||||
def prevent_search(relation):
|
||||
"""
|
||||
Used to mark a model field or relation as "restricted from filtering"
|
||||
|
||||
@@ -1619,20 +1619,20 @@ class InventorySource(UnifiedJobTemplate, InventorySourceOptions, CustomVirtualE
|
||||
base_notification_templates = NotificationTemplate.objects
|
||||
error_notification_templates = list(base_notification_templates
|
||||
.filter(unifiedjobtemplate_notification_templates_for_errors__in=[self]))
|
||||
started_notification_templates = list(base_notification_templates
|
||||
.filter(unifiedjobtemplate_notification_templates_for_started__in=[self]))
|
||||
success_notification_templates = list(base_notification_templates
|
||||
.filter(unifiedjobtemplate_notification_templates_for_success__in=[self]))
|
||||
any_notification_templates = list(base_notification_templates
|
||||
.filter(unifiedjobtemplate_notification_templates_for_any__in=[self]))
|
||||
if self.inventory.organization is not None:
|
||||
error_notification_templates = set(error_notification_templates + list(base_notification_templates
|
||||
.filter(organization_notification_templates_for_errors=self.inventory.organization)))
|
||||
started_notification_templates = set(started_notification_templates + list(base_notification_templates
|
||||
.filter(organization_notification_templates_for_started=self.inventory.organization)))
|
||||
success_notification_templates = set(success_notification_templates + list(base_notification_templates
|
||||
.filter(organization_notification_templates_for_success=self.inventory.organization)))
|
||||
any_notification_templates = set(any_notification_templates + list(base_notification_templates
|
||||
.filter(organization_notification_templates_for_any=self.inventory.organization)))
|
||||
return dict(error=list(error_notification_templates),
|
||||
success=list(success_notification_templates),
|
||||
any=list(any_notification_templates))
|
||||
started=list(started_notification_templates),
|
||||
success=list(success_notification_templates))
|
||||
|
||||
def clean_source(self): # TODO: remove in 3.3
|
||||
source = self.source
|
||||
|
||||
@@ -435,19 +435,21 @@ class JobTemplate(UnifiedJobTemplate, JobOptions, SurveyJobTemplateMixin, Resour
|
||||
base_notification_templates = NotificationTemplate.objects
|
||||
error_notification_templates = list(base_notification_templates.filter(
|
||||
unifiedjobtemplate_notification_templates_for_errors__in=[self, self.project]))
|
||||
started_notification_templates = list(base_notification_templates.filter(
|
||||
unifiedjobtemplate_notification_templates_for_started__in=[self, self.project]))
|
||||
success_notification_templates = list(base_notification_templates.filter(
|
||||
unifiedjobtemplate_notification_templates_for_success__in=[self, self.project]))
|
||||
any_notification_templates = list(base_notification_templates.filter(
|
||||
unifiedjobtemplate_notification_templates_for_any__in=[self, self.project]))
|
||||
# Get Organization NotificationTemplates
|
||||
if self.project is not None and self.project.organization is not None:
|
||||
error_notification_templates = set(error_notification_templates + list(base_notification_templates.filter(
|
||||
organization_notification_templates_for_errors=self.project.organization)))
|
||||
started_notification_templates = set(started_notification_templates + list(base_notification_templates.filter(
|
||||
organization_notification_templates_for_started=self.project.organization)))
|
||||
success_notification_templates = set(success_notification_templates + list(base_notification_templates.filter(
|
||||
organization_notification_templates_for_success=self.project.organization)))
|
||||
any_notification_templates = set(any_notification_templates + list(base_notification_templates.filter(
|
||||
organization_notification_templates_for_any=self.project.organization)))
|
||||
return dict(error=list(error_notification_templates), success=list(success_notification_templates), any=list(any_notification_templates))
|
||||
return dict(error=list(error_notification_templates),
|
||||
started=list(started_notification_templates),
|
||||
success=list(success_notification_templates))
|
||||
|
||||
'''
|
||||
RelatedJobsMixin
|
||||
@@ -1133,13 +1135,13 @@ class SystemJobTemplate(UnifiedJobTemplate, SystemJobOptions):
|
||||
base_notification_templates = NotificationTemplate.objects.all()
|
||||
error_notification_templates = list(base_notification_templates
|
||||
.filter(unifiedjobtemplate_notification_templates_for_errors__in=[self]))
|
||||
started_notification_templates = list(base_notification_templates
|
||||
.filter(unifiedjobtemplate_notification_templates_for_started__in=[self]))
|
||||
success_notification_templates = list(base_notification_templates
|
||||
.filter(unifiedjobtemplate_notification_templates_for_success__in=[self]))
|
||||
any_notification_templates = list(base_notification_templates
|
||||
.filter(unifiedjobtemplate_notification_templates_for_any__in=[self]))
|
||||
return dict(error=list(error_notification_templates),
|
||||
success=list(success_notification_templates),
|
||||
any=list(any_notification_templates))
|
||||
started=list(started_notification_templates),
|
||||
success=list(success_notification_templates))
|
||||
|
||||
def _accept_or_ignore_job_kwargs(self, _exclude_errors=None, **kwargs):
|
||||
extra_data = kwargs.pop('extra_vars', {})
|
||||
|
||||
@@ -7,6 +7,7 @@ import logging
|
||||
from django.db import models
|
||||
from django.conf import settings
|
||||
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
|
||||
|
||||
@@ -129,7 +130,7 @@ class NotificationTemplate(CommonModelNameNotUnique):
|
||||
if field not in notification_configuration:
|
||||
if 'default' in params:
|
||||
notification_configuration[field] = params['default']
|
||||
backend_obj = self.notification_class(**notification_configuration)
|
||||
backend_obj = self.notification_class(**notification_configuration)
|
||||
notification_obj = EmailMessage(subject, backend_obj.format_body(body), sender, recipients)
|
||||
with set_environ(**settings.AWX_TASK_ENV):
|
||||
return backend_obj.send_messages([notification_obj])
|
||||
@@ -221,10 +222,13 @@ class JobNotificationMixin(object):
|
||||
def build_notification_failed_message(self):
|
||||
return self._build_notification_message('failed')
|
||||
|
||||
def build_notification_running_message(self):
|
||||
return self._build_notification_message('running')
|
||||
|
||||
def send_notification_templates(self, status_str):
|
||||
from awx.main.tasks import send_notifications # avoid circular import
|
||||
if status_str not in ['succeeded', 'failed']:
|
||||
raise ValueError(_("status_str must be either succeeded or failed"))
|
||||
if status_str not in ['succeeded', 'failed', 'running']:
|
||||
raise ValueError(_("status_str must be either running, succeeded or failed"))
|
||||
try:
|
||||
notification_templates = self.get_notification_templates()
|
||||
except Exception:
|
||||
@@ -233,14 +237,19 @@ class JobNotificationMixin(object):
|
||||
if notification_templates:
|
||||
if status_str == 'succeeded':
|
||||
notification_template_type = 'success'
|
||||
elif status_str == 'running':
|
||||
notification_template_type = 'started'
|
||||
else:
|
||||
notification_template_type = 'error'
|
||||
all_notification_templates = set(notification_templates.get(notification_template_type, []) + notification_templates.get('any', []))
|
||||
all_notification_templates = set(notification_templates.get(notification_template_type, []))
|
||||
if len(all_notification_templates):
|
||||
try:
|
||||
(notification_subject, notification_body) = getattr(self, 'build_notification_%s_message' % status_str)()
|
||||
except AttributeError:
|
||||
raise NotImplementedError("build_notification_%s_message() does not exist" % status_str)
|
||||
send_notifications.delay([n.generate_notification(notification_subject, notification_body).id
|
||||
for n in all_notification_templates],
|
||||
job_id=self.id)
|
||||
|
||||
def send_it():
|
||||
send_notifications.delay([n.generate_notification(notification_subject, notification_body).id
|
||||
for n in all_notification_templates],
|
||||
job_id=self.id)
|
||||
connection.on_commit(send_it)
|
||||
|
||||
@@ -411,24 +411,24 @@ class Project(UnifiedJobTemplate, ProjectOptions, ResourceMixin, CustomVirtualEn
|
||||
base_notification_templates = NotificationTemplate.objects
|
||||
error_notification_templates = list(base_notification_templates
|
||||
.filter(unifiedjobtemplate_notification_templates_for_errors=self))
|
||||
started_notification_templates = list(base_notification_templates
|
||||
.filter(unifiedjobtemplate_notification_templates_for_started=self))
|
||||
success_notification_templates = list(base_notification_templates
|
||||
.filter(unifiedjobtemplate_notification_templates_for_success=self))
|
||||
any_notification_templates = list(base_notification_templates
|
||||
.filter(unifiedjobtemplate_notification_templates_for_any=self))
|
||||
# Get Organization NotificationTemplates
|
||||
if self.organization is not None:
|
||||
error_notification_templates = set(error_notification_templates +
|
||||
list(base_notification_templates
|
||||
.filter(organization_notification_templates_for_errors=self.organization)))
|
||||
started_notification_templates = set(started_notification_templates +
|
||||
list(base_notification_templates
|
||||
.filter(organization_notification_templates_for_started=self.organization)))
|
||||
success_notification_templates = set(success_notification_templates +
|
||||
list(base_notification_templates
|
||||
.filter(organization_notification_templates_for_success=self.organization)))
|
||||
any_notification_templates = set(any_notification_templates +
|
||||
list(base_notification_templates
|
||||
.filter(organization_notification_templates_for_any=self.organization)))
|
||||
return dict(error=list(error_notification_templates),
|
||||
success=list(success_notification_templates),
|
||||
any=list(any_notification_templates))
|
||||
started=list(started_notification_templates),
|
||||
success=list(success_notification_templates))
|
||||
|
||||
def get_absolute_url(self, request=None):
|
||||
return reverse('api:project_detail', kwargs={'pk': self.pk}, request=request)
|
||||
@@ -567,5 +567,3 @@ class ProjectUpdate(UnifiedJob, ProjectOptions, JobNotificationMixin, TaskManage
|
||||
if not selected_groups:
|
||||
return self.global_instance_groups
|
||||
return selected_groups
|
||||
|
||||
|
||||
|
||||
@@ -419,13 +419,13 @@ class WorkflowJobTemplate(UnifiedJobTemplate, WorkflowJobOptions, SurveyJobTempl
|
||||
base_notification_templates = NotificationTemplate.objects.all()
|
||||
error_notification_templates = list(base_notification_templates
|
||||
.filter(unifiedjobtemplate_notification_templates_for_errors__in=[self]))
|
||||
started_notification_templates = list(base_notification_templates
|
||||
.filter(unifiedjobtemplate_notification_templates_for_started__in=[self]))
|
||||
success_notification_templates = list(base_notification_templates
|
||||
.filter(unifiedjobtemplate_notification_templates_for_success__in=[self]))
|
||||
any_notification_templates = list(base_notification_templates
|
||||
.filter(unifiedjobtemplate_notification_templates_for_any__in=[self]))
|
||||
return dict(error=list(error_notification_templates),
|
||||
success=list(success_notification_templates),
|
||||
any=list(any_notification_templates))
|
||||
started=list(started_notification_templates),
|
||||
success=list(success_notification_templates))
|
||||
|
||||
def create_unified_job(self, **kwargs):
|
||||
workflow_job = super(WorkflowJobTemplate, self).create_unified_job(**kwargs)
|
||||
|
||||
@@ -193,6 +193,8 @@ class TaskManager():
|
||||
status_changed = True
|
||||
if status_changed:
|
||||
workflow_job.websocket_emit_status(workflow_job.status)
|
||||
# Operations whose queries rely on modifications made during the atomic scheduling session
|
||||
workflow_job.send_notification_templates('succeeded' if workflow_job.status == 'successful' else 'failed')
|
||||
if workflow_job.spawned_by_workflow:
|
||||
schedule_task_manager()
|
||||
return result
|
||||
@@ -233,6 +235,7 @@ class TaskManager():
|
||||
else:
|
||||
if type(task) is WorkflowJob:
|
||||
task.status = 'running'
|
||||
task.send_notification_templates('running')
|
||||
logger.debug('Transitioning %s to running status.', task.log_format)
|
||||
schedule_task_manager()
|
||||
elif not task.supports_isolation() and rampart_group.controller_id:
|
||||
@@ -581,10 +584,5 @@ class TaskManager():
|
||||
logger.debug("Not running scheduler, another task holds lock")
|
||||
return
|
||||
logger.debug("Starting Scheduler")
|
||||
|
||||
with task_manager_bulk_reschedule():
|
||||
finished_wfjs = self._schedule()
|
||||
|
||||
# Operations whose queries rely on modifications made during the atomic scheduling session
|
||||
for wfj in WorkflowJob.objects.filter(id__in=finished_wfjs):
|
||||
wfj.send_notification_templates('succeeded' if wfj.status == 'successful' else 'failed')
|
||||
self._schedule()
|
||||
|
||||
@@ -602,25 +602,26 @@ def update_inventory_computed_fields(inventory_id, should_update_hosts=True):
|
||||
|
||||
|
||||
def update_smart_memberships_for_inventory(smart_inventory):
|
||||
current = set(SmartInventoryMembership.objects.filter(inventory=smart_inventory).values_list('host_id', flat=True))
|
||||
new = set(smart_inventory.hosts.values_list('id', flat=True))
|
||||
additions = new - current
|
||||
removals = current - new
|
||||
if additions or removals:
|
||||
with transaction.atomic():
|
||||
if removals:
|
||||
SmartInventoryMembership.objects.filter(inventory=smart_inventory, host_id__in=removals).delete()
|
||||
if additions:
|
||||
add_for_inventory = [
|
||||
SmartInventoryMembership(inventory_id=smart_inventory.id, host_id=host_id)
|
||||
for host_id in additions
|
||||
]
|
||||
SmartInventoryMembership.objects.bulk_create(add_for_inventory)
|
||||
logger.debug('Smart host membership cached for {}, {} additions, {} removals, {} total count.'.format(
|
||||
smart_inventory.pk, len(additions), len(removals), len(new)
|
||||
))
|
||||
return True # changed
|
||||
return False
|
||||
with advisory_lock('update_smart_memberships_for_inventory-{}'.format(smart_inventory.id)):
|
||||
current = set(SmartInventoryMembership.objects.filter(inventory=smart_inventory).values_list('host_id', flat=True))
|
||||
new = set(smart_inventory.hosts.values_list('id', flat=True))
|
||||
additions = new - current
|
||||
removals = current - new
|
||||
if additions or removals:
|
||||
with transaction.atomic():
|
||||
if removals:
|
||||
SmartInventoryMembership.objects.filter(inventory=smart_inventory, host_id__in=removals).delete()
|
||||
if additions:
|
||||
add_for_inventory = [
|
||||
SmartInventoryMembership(inventory_id=smart_inventory.id, host_id=host_id)
|
||||
for host_id in additions
|
||||
]
|
||||
SmartInventoryMembership.objects.bulk_create(add_for_inventory)
|
||||
logger.debug('Smart host membership cached for {}, {} additions, {} removals, {} total count.'.format(
|
||||
smart_inventory.pk, len(additions), len(removals), len(new)
|
||||
))
|
||||
return True # changed
|
||||
return False
|
||||
|
||||
|
||||
@task()
|
||||
@@ -1131,6 +1132,7 @@ class BaseTask(object):
|
||||
|
||||
try:
|
||||
isolated = self.instance.is_isolated()
|
||||
self.instance.send_notification_templates("running")
|
||||
self.pre_run_hook(self.instance)
|
||||
if self.instance.cancel_flag:
|
||||
self.instance = self.update_model(self.instance.pk, status='canceled')
|
||||
|
||||
@@ -91,7 +91,7 @@ class TestSwaggerGeneration():
|
||||
# The number of API endpoints changes over time, but let's just check
|
||||
# for a reasonable number here; if this test starts failing, raise/lower the bounds
|
||||
paths = JSON['paths']
|
||||
assert 250 < len(paths) < 300
|
||||
assert 250 < len(paths) < 350
|
||||
assert list(paths['/api/'].keys()) == ['get']
|
||||
assert list(paths['/api/v2/'].keys()) == ['get']
|
||||
assert list(sorted(
|
||||
|
||||
@@ -42,10 +42,6 @@ def test_inventory_source_notification_on_cloud_only(get, post, inventory_source
|
||||
|
||||
not_is = inventory_source_factory("not_ec2")
|
||||
|
||||
url = reverse('api:inventory_source_notification_templates_any_list', kwargs={'pk': cloud_is.id})
|
||||
response = post(url, dict(id=notification_template.id), u)
|
||||
assert response.status_code == 204
|
||||
|
||||
url = reverse('api:inventory_source_notification_templates_success_list', kwargs={'pk': not_is.id})
|
||||
response = post(url, dict(id=notification_template.id), u)
|
||||
assert response.status_code == 400
|
||||
|
||||
129
awx/main/tests/functional/api/test_notifications.py
Normal file
129
awx/main/tests/functional/api/test_notifications.py
Normal file
@@ -0,0 +1,129 @@
|
||||
import pytest
|
||||
|
||||
from awx.api.versioning import reverse
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_get_org_running_notification(get, admin, organization):
|
||||
url = reverse('api:organization_notification_templates_started_list', kwargs={'pk': organization.pk})
|
||||
response = get(url, admin)
|
||||
assert response.status_code == 200
|
||||
assert len(response.data['results']) == 0
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_post_org_running_notification(get, post, admin, notification_template, organization):
|
||||
url = reverse('api:organization_notification_templates_started_list', kwargs={'pk': organization.pk})
|
||||
response = post(url,
|
||||
dict(id=notification_template.id,
|
||||
associate=True),
|
||||
admin)
|
||||
assert response.status_code == 204
|
||||
response = get(url, admin)
|
||||
assert response.status_code == 200
|
||||
assert len(response.data['results']) == 1
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_get_project_running_notification(get, admin, project):
|
||||
url = reverse('api:project_notification_templates_started_list', kwargs={'pk': project.pk})
|
||||
response = get(url, admin)
|
||||
assert response.status_code == 200
|
||||
assert len(response.data['results']) == 0
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_post_project_running_notification(get, post, admin, notification_template, project):
|
||||
url = reverse('api:project_notification_templates_started_list', kwargs={'pk': project.pk})
|
||||
response = post(url,
|
||||
dict(id=notification_template.id,
|
||||
associate=True),
|
||||
admin)
|
||||
assert response.status_code == 204
|
||||
response = get(url, admin)
|
||||
assert response.status_code == 200
|
||||
assert len(response.data['results']) == 1
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_get_inv_src_running_notification(get, admin, inventory_source):
|
||||
url = reverse('api:inventory_source_notification_templates_started_list', kwargs={'pk': inventory_source.pk})
|
||||
response = get(url, admin)
|
||||
assert response.status_code == 200
|
||||
assert len(response.data['results']) == 0
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_post_inv_src_running_notification(get, post, admin, notification_template, inventory_source):
|
||||
url = reverse('api:inventory_source_notification_templates_started_list', kwargs={'pk': inventory_source.pk})
|
||||
response = post(url,
|
||||
dict(id=notification_template.id,
|
||||
associate=True),
|
||||
admin)
|
||||
assert response.status_code == 204
|
||||
response = get(url, admin)
|
||||
assert response.status_code == 200
|
||||
assert len(response.data['results']) == 1
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_get_jt_running_notification(get, admin, job_template):
|
||||
url = reverse('api:job_template_notification_templates_started_list', kwargs={'pk': job_template.pk})
|
||||
response = get(url, admin)
|
||||
assert response.status_code == 200
|
||||
assert len(response.data['results']) == 0
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_post_jt_running_notification(get, post, admin, notification_template, job_template):
|
||||
url = reverse('api:job_template_notification_templates_started_list', kwargs={'pk': job_template.pk})
|
||||
response = post(url,
|
||||
dict(id=notification_template.id,
|
||||
associate=True),
|
||||
admin)
|
||||
assert response.status_code == 204
|
||||
response = get(url, admin)
|
||||
assert response.status_code == 200
|
||||
assert len(response.data['results']) == 1
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_get_sys_jt_running_notification(get, admin, system_job_template):
|
||||
url = reverse('api:system_job_template_notification_templates_started_list', kwargs={'pk': system_job_template.pk})
|
||||
response = get(url, admin)
|
||||
assert response.status_code == 200
|
||||
assert len(response.data['results']) == 0
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_post_sys_jt_running_notification(get, post, admin, notification_template, system_job_template):
|
||||
url = reverse('api:system_job_template_notification_templates_started_list', kwargs={'pk': system_job_template.pk})
|
||||
response = post(url,
|
||||
dict(id=notification_template.id,
|
||||
associate=True),
|
||||
admin)
|
||||
assert response.status_code == 204
|
||||
response = get(url, admin)
|
||||
assert response.status_code == 200
|
||||
assert len(response.data['results']) == 1
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_get_wfjt_running_notification(get, admin, workflow_job_template):
|
||||
url = reverse('api:workflow_job_template_notification_templates_started_list', kwargs={'pk': workflow_job_template.pk})
|
||||
response = get(url, admin)
|
||||
assert response.status_code == 200
|
||||
assert len(response.data['results']) == 0
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_post_wfjt_running_notification(get, post, admin, notification_template, workflow_job_template):
|
||||
url = reverse('api:workflow_job_template_notification_templates_started_list', kwargs={'pk': workflow_job_template.pk})
|
||||
response = post(url,
|
||||
dict(id=notification_template.id,
|
||||
associate=True),
|
||||
admin)
|
||||
assert response.status_code == 204
|
||||
response = get(url, admin)
|
||||
assert response.status_code == 200
|
||||
assert len(response.data['results']) == 1
|
||||
@@ -92,27 +92,7 @@ def test_inherited_notification_templates(get, post, user, organization, project
|
||||
isrc.save()
|
||||
jt = JobTemplate.objects.create(name='test', inventory=i, project=project, playbook='debug.yml')
|
||||
jt.save()
|
||||
url = reverse('api:organization_notification_templates_any_list', kwargs={'pk': organization.id})
|
||||
response = post(url, dict(id=notification_templates[0]), u)
|
||||
assert response.status_code == 204
|
||||
url = reverse('api:project_notification_templates_any_list', kwargs={'pk': project.id})
|
||||
response = post(url, dict(id=notification_templates[1]), u)
|
||||
assert response.status_code == 204
|
||||
url = reverse('api:job_template_notification_templates_any_list', kwargs={'pk': jt.id})
|
||||
response = post(url, dict(id=notification_templates[2]), u)
|
||||
assert response.status_code == 204
|
||||
assert len(jt.notification_templates['any']) == 3
|
||||
assert len(project.notification_templates['any']) == 2
|
||||
assert len(isrc.notification_templates['any']) == 1
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_notification_template_merging(get, post, user, organization, project, notification_template):
|
||||
user('admin-poster', True)
|
||||
organization.notification_templates_any.add(notification_template)
|
||||
project.notification_templates_any.add(notification_template)
|
||||
assert len(project.notification_templates['any']) == 1
|
||||
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_notification_template_simple_patch(patch, notification_template, admin):
|
||||
|
||||
@@ -71,7 +71,7 @@ class TestInventorySourceSerializerGetRelated(object):
|
||||
'activity_stream',
|
||||
'notification_templates_error',
|
||||
'notification_templates_success',
|
||||
'notification_templates_any',
|
||||
'notification_templates_started',
|
||||
'inventory_updates',
|
||||
'update',
|
||||
'hosts',
|
||||
|
||||
@@ -50,7 +50,7 @@ class TestJobTemplateSerializerGetRelated():
|
||||
'schedules',
|
||||
'activity_stream',
|
||||
'launch',
|
||||
'notification_templates_any',
|
||||
'notification_templates_started',
|
||||
'notification_templates_success',
|
||||
'notification_templates_error',
|
||||
'survey_spec',
|
||||
|
||||
@@ -378,6 +378,7 @@ class TestGenericRun():
|
||||
job.status = 'running'
|
||||
job.cancel_flag = True
|
||||
job.websocket_emit_status = mock.Mock()
|
||||
job.send_notification_templates = mock.Mock()
|
||||
|
||||
task = tasks.RunJob()
|
||||
task.update_model = mock.Mock(wraps=update_model_wrapper)
|
||||
@@ -536,6 +537,7 @@ class TestAdhocRun(TestJobExecution):
|
||||
def test_options_jinja_usage(self, adhoc_job, adhoc_update_model_wrapper):
|
||||
adhoc_job.module_args = '{{ ansible_ssh_pass }}'
|
||||
adhoc_job.websocket_emit_status = mock.Mock()
|
||||
adhoc_job.send_notification_templates = mock.Mock()
|
||||
|
||||
task = tasks.RunAdHocCommand()
|
||||
task.update_model = mock.Mock(wraps=adhoc_update_model_wrapper)
|
||||
|
||||
@@ -6,6 +6,7 @@ import logging
|
||||
import json
|
||||
import requests
|
||||
import time
|
||||
import threading
|
||||
import socket
|
||||
import select
|
||||
from urllib import parse as urlparse
|
||||
@@ -286,6 +287,8 @@ class AWXProxyHandler(logging.Handler):
|
||||
Parameters match same parameters in the actualized handler classes.
|
||||
'''
|
||||
|
||||
thread_local = threading.local()
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
# TODO: process 'level' kwarg
|
||||
super(AWXProxyHandler, self).__init__(**kwargs)
|
||||
@@ -322,8 +325,9 @@ class AWXProxyHandler(logging.Handler):
|
||||
return self._handler
|
||||
|
||||
def emit(self, record):
|
||||
actual_handler = self.get_handler()
|
||||
return actual_handler.emit(record)
|
||||
if AWXProxyHandler.thread_local.enabled:
|
||||
actual_handler = self.get_handler()
|
||||
return actual_handler.emit(record)
|
||||
|
||||
def perform_test(self, custom_settings):
|
||||
"""
|
||||
@@ -353,6 +357,13 @@ class AWXProxyHandler(logging.Handler):
|
||||
except RequestException as e:
|
||||
raise LoggingConnectivityException(str(e))
|
||||
|
||||
@classmethod
|
||||
def disable(cls):
|
||||
cls.thread_local.enabled = False
|
||||
|
||||
|
||||
AWXProxyHandler.thread_local.enabled = True
|
||||
|
||||
|
||||
ColorHandler = logging.StreamHandler
|
||||
|
||||
|
||||
@@ -1,14 +1,20 @@
|
||||
# Copyright (c) 2015 Ansible, Inc.
|
||||
# All Rights Reserved.
|
||||
|
||||
import json
|
||||
|
||||
# Django
|
||||
from django.http import HttpResponse
|
||||
from django.shortcuts import render
|
||||
from django.utils.html import format_html
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
|
||||
# Django REST Framework
|
||||
from rest_framework import exceptions, permissions, views
|
||||
|
||||
import logging
|
||||
|
||||
|
||||
def _force_raising_exception(view_obj, request, format=None):
|
||||
raise view_obj.exception_class()
|
||||
@@ -84,3 +90,10 @@ def handle_500(request):
|
||||
'content': _('A server error has occurred.'),
|
||||
}
|
||||
return handle_error(request, 500, **kwargs)
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
def handle_csp_violation(request):
|
||||
logger = logging.getLogger('awx')
|
||||
logger.error(json.loads(request.body))
|
||||
return HttpResponse(content=None)
|
||||
|
||||
@@ -65,15 +65,9 @@ import sys
|
||||
|
||||
from collections import defaultdict
|
||||
|
||||
try:
|
||||
import ConfigParser as configparser
|
||||
except ImportError:
|
||||
import configparser
|
||||
from ansible.module_utils.six.moves import configparser
|
||||
|
||||
try:
|
||||
import json
|
||||
except ImportError:
|
||||
import simplejson as json
|
||||
import json
|
||||
|
||||
try:
|
||||
import ovirtsdk4 as sdk
|
||||
@@ -127,7 +121,7 @@ def create_connection():
|
||||
'ovirt_url': os.environ.get('OVIRT_URL'),
|
||||
'ovirt_username': os.environ.get('OVIRT_USERNAME'),
|
||||
'ovirt_password': os.environ.get('OVIRT_PASSWORD'),
|
||||
'ovirt_ca_file': os.environ.get('OVIRT_CAFILE'),
|
||||
'ovirt_ca_file': os.environ.get('OVIRT_CAFILE', ''),
|
||||
}
|
||||
)
|
||||
if not config.has_section('ovirt'):
|
||||
@@ -139,8 +133,8 @@ def create_connection():
|
||||
url=config.get('ovirt', 'ovirt_url'),
|
||||
username=config.get('ovirt', 'ovirt_username'),
|
||||
password=config.get('ovirt', 'ovirt_password', raw=True),
|
||||
ca_file=config.get('ovirt', 'ovirt_ca_file'),
|
||||
insecure=config.get('ovirt', 'ovirt_ca_file') is None,
|
||||
ca_file=config.get('ovirt', 'ovirt_ca_file') or None,
|
||||
insecure=not config.get('ovirt', 'ovirt_ca_file'),
|
||||
)
|
||||
|
||||
|
||||
@@ -179,7 +173,7 @@ def get_dict_of_struct(connection, vm):
|
||||
if vm.name in [vm.name for vm in connection.follow_link(group.vms)]
|
||||
],
|
||||
'statistics': dict(
|
||||
(stat.name, stat.values[0].datum) for stat in stats
|
||||
(stat.name, stat.values[0].datum) for stat in stats if stat.values
|
||||
),
|
||||
'devices': dict(
|
||||
(device.name, [ip.address for ip in device.ips]) for device in devices if device.ips
|
||||
@@ -258,5 +252,6 @@ def main():
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
# All Rights Reserved.
|
||||
|
||||
# Python
|
||||
from collections import OrderedDict
|
||||
import logging
|
||||
import uuid
|
||||
|
||||
@@ -54,6 +55,20 @@ class LDAPSettings(BaseLDAPSettings):
|
||||
options[ldap.OPT_NETWORK_TIMEOUT] = 30
|
||||
self.CONNECTION_OPTIONS = options
|
||||
|
||||
# when specifying `.set_option()` calls for TLS in python-ldap, the
|
||||
# *order* in which you invoke them *matters*, particularly in Python3,
|
||||
# where dictionary insertion order is persisted
|
||||
#
|
||||
# specifically, it is *critical* that `ldap.OPT_X_TLS_NEWCTX` be set *last*
|
||||
# this manual sorting puts `OPT_X_TLS_NEWCTX` *after* other TLS-related
|
||||
# options
|
||||
#
|
||||
# see: https://github.com/python-ldap/python-ldap/issues/55
|
||||
newctx_option = self.CONNECTION_OPTIONS.pop(ldap.OPT_X_TLS_NEWCTX, None)
|
||||
self.CONNECTION_OPTIONS = OrderedDict(self.CONNECTION_OPTIONS)
|
||||
if newctx_option:
|
||||
self.CONNECTION_OPTIONS[ldap.OPT_X_TLS_NEWCTX] = newctx_option
|
||||
|
||||
|
||||
class LDAPBackend(BaseLDAPBackend):
|
||||
'''
|
||||
|
||||
@@ -18,9 +18,7 @@ def test_ldap_default_network_timeout(mocker):
|
||||
from_db = mocker.Mock(**{'order_by.return_value': []})
|
||||
with mocker.patch('awx.conf.models.Setting.objects.filter', return_value=from_db):
|
||||
settings = LDAPSettings()
|
||||
assert settings.CONNECTION_OPTIONS == {
|
||||
ldap.OPT_NETWORK_TIMEOUT: 30
|
||||
}
|
||||
assert settings.CONNECTION_OPTIONS[ldap.OPT_NETWORK_TIMEOUT] == 30
|
||||
|
||||
|
||||
def test_ldap_filter_validator():
|
||||
|
||||
@@ -41,14 +41,13 @@ export default {
|
||||
name: {
|
||||
key: true,
|
||||
label: 'Name',
|
||||
columnClass: 'col-lg-2 col-md-3 col-sm-4 col-xs-4',
|
||||
columnClass: 'col-sm-6',
|
||||
awToolTip: '{{application.description | sanitize}}',
|
||||
dataPlacement: 'top'
|
||||
},
|
||||
organization: {
|
||||
label: 'Organization',
|
||||
columnClass: 'col-lg-2 col-md-3 col-sm-4 col-xs-4',
|
||||
modalColumnClass: 'col-lg-2 col-md-3 col-sm-4 col-xs-4',
|
||||
columnClass: 'col-sm-6',
|
||||
key: false,
|
||||
ngBind: 'application.summary_fields.organization.name',
|
||||
sourceModel: 'organization',
|
||||
|
||||
@@ -260,7 +260,7 @@
|
||||
|
||||
.at-RowItem--labels {
|
||||
line-height: @at-line-height-list-row-item-labels;
|
||||
display: inline-block;
|
||||
display: inline-flex;
|
||||
|
||||
* {
|
||||
font-size: 10px;
|
||||
|
||||
@@ -35,6 +35,18 @@ export default ['i18n', 'templateUrl', function(i18n, templateUrl){
|
||||
excludeModal: true,
|
||||
columnClass: 'd-none d-sm-flex col-md-4 col-sm-3'
|
||||
},
|
||||
notification_templates_started: {
|
||||
label: i18n._("Start"),
|
||||
flag: 'notification_templates_started',
|
||||
type: "toggle",
|
||||
ngClick: "toggleNotification($event, notification.id, \"notification_templates_started\")",
|
||||
ngDisabled: "!sufficientRoleForNotifToggle",
|
||||
awToolTip: "{{ schedule.play_tip }}",
|
||||
dataTipWatch: "schedule.play_tip",
|
||||
dataPlacement: "right",
|
||||
nosort: true,
|
||||
columnClass: 'd-none d-md-flex justify-content-start col-md-1'
|
||||
},
|
||||
notification_templates_success: {
|
||||
label: i18n._('Success'),
|
||||
flag: 'notification_templates_success',
|
||||
@@ -45,11 +57,11 @@ export default ['i18n', 'templateUrl', function(i18n, templateUrl){
|
||||
dataTipWatch: "schedule.play_tip",
|
||||
dataPlacement: "right",
|
||||
nosort: true,
|
||||
columnClass: 'd-none d-md-flex justify-content-start col-md-2'
|
||||
columnClass: 'd-none d-md-flex justify-content-start col-md-1'
|
||||
},
|
||||
notification_templates_error: {
|
||||
label: i18n._('Failure'),
|
||||
columnClass: 'd-none d-md-flex justify-content-start col-md-2 NotifierList-lastColumn',
|
||||
columnClass: 'd-none d-md-flex justify-content-start col-md-1 NotifierList-lastColumn',
|
||||
flag: 'notification_templates_error',
|
||||
type: "toggle",
|
||||
ngClick: "toggleNotification($event, notification.id, \"notification_templates_error\")",
|
||||
|
||||
@@ -49,7 +49,7 @@ export default ['Wait', 'GetBasePath', 'ProcessErrors', 'Rest', 'GetChoices',
|
||||
scope.relatednotificationsRemove();
|
||||
}
|
||||
scope.relatednotificationsRemove = scope.$on('relatednotifications', function () {
|
||||
var columns = ['/notification_templates_success/', '/notification_templates_error/'];
|
||||
var columns = ['/notification_templates_started/', '/notification_templates_success/', '/notification_templates_error/'];
|
||||
|
||||
GetChoices({
|
||||
scope: scope,
|
||||
@@ -64,7 +64,10 @@ export default ['Wait', 'GetBasePath', 'ProcessErrors', 'Rest', 'GetChoices',
|
||||
Rest.setUrl(notifier_url);
|
||||
Rest.get()
|
||||
.then(function(response) {
|
||||
var type = (response.config.url.indexOf('success')>0) ? "notification_templates_success" : "notification_templates_error";
|
||||
let checkForSuccessOrError = response.config.url.indexOf('success') > 0 ? "notification_templates_success" : "notification_templates_error";
|
||||
|
||||
let type = response.config.url.indexOf('started') > 0 ? "notification_templates_started" : checkForSuccessOrError;
|
||||
|
||||
if (response.data.results) {
|
||||
_.forEach(response.data.results, function(result){
|
||||
_.forEach(scope.notifications, function(notification){
|
||||
|
||||
@@ -21,7 +21,7 @@ export default ['Wait', 'ProcessErrors', 'Rest',
|
||||
notifier = params.notifier,
|
||||
notifier_id = params.notifier.id,
|
||||
callback = params.callback,
|
||||
column = params.column, // notification_template_success/notification_template__error
|
||||
column = params.column, // notification_template_success/notification_template__error/notification_template_started
|
||||
url = params.url + "/" + column + '/';
|
||||
|
||||
if(!notifier[column]){
|
||||
|
||||
@@ -42,14 +42,14 @@ export default ['NotificationsList', 'i18n', function(NotificationsList, i18n) {
|
||||
label: i18n._('Name'),
|
||||
type: 'text',
|
||||
required: true,
|
||||
ngDisabled: '!(workflow_job_template_obj.summary_fields.user_capabilities.edit || canAddWorkflowJobTemplate)',
|
||||
ngDisabled: '!(workflow_job_template_obj.summary_fields.user_capabilities.edit || canAddOrEdit)',
|
||||
column: 1
|
||||
},
|
||||
description: {
|
||||
label: i18n._('Description'),
|
||||
type: 'text',
|
||||
column: 1,
|
||||
ngDisabled: '!(workflow_job_template_obj.summary_fields.user_capabilities.edit || canAddWorkflowJobTemplate)'
|
||||
ngDisabled: '!(workflow_job_template_obj.summary_fields.user_capabilities.edit || canAddOrEdit)'
|
||||
},
|
||||
organization: {
|
||||
label: i18n._('Organization'),
|
||||
@@ -65,8 +65,8 @@ export default ['NotificationsList', 'i18n', function(NotificationsList, i18n) {
|
||||
reqExpression: '!current_user.is_superuser'
|
||||
},
|
||||
column: 1,
|
||||
ngDisabled: '!(workflow_job_template_obj.summary_fields.user_capabilities.edit || canAddWorkflowJobTemplate) || !canEditOrg',
|
||||
awLookupWhen: '(workflow_job_template_obj.summary_fields.user_capabilities.edit || canAddWorkflowJobTemplate) && canEditOrg'
|
||||
ngDisabled: '!(workflow_job_template_obj.summary_fields.user_capabilities.edit || canAddOrEdit) || !canEditOrg',
|
||||
awLookupWhen: '(workflow_job_template_obj.summary_fields.user_capabilities.edit || canAddOrEdit) && canEditOrg'
|
||||
},
|
||||
inventory: {
|
||||
label: i18n._('Inventory'),
|
||||
@@ -87,7 +87,7 @@ export default ['NotificationsList', 'i18n', function(NotificationsList, i18n) {
|
||||
ngChange: 'workflow_job_template_form.inventory_name.$validate()',
|
||||
text: i18n._('Prompt on launch')
|
||||
},
|
||||
ngDisabled: '!(workflow_job_template_obj.summary_fields.user_capabilities.edit || canAddWorkflowJobTemplate) || !canEditInventory',
|
||||
ngDisabled: '!(workflow_job_template_obj.summary_fields.user_capabilities.edit || canAddOrEdit) || !canEditInventory',
|
||||
},
|
||||
labels: {
|
||||
label: i18n._('Labels'),
|
||||
@@ -102,7 +102,7 @@ export default ['NotificationsList', 'i18n', function(NotificationsList, i18n) {
|
||||
ngShow: 'workflow_job_template_labels_isValid !== true',
|
||||
text: i18n._('Max 512 characters per label.'),
|
||||
},
|
||||
ngDisabled: '!(workflow_job_template_obj.summary_fields.user_capabilities.edit || canAddWorkflowJobTemplate)'
|
||||
ngDisabled: '!(workflow_job_template_obj.summary_fields.user_capabilities.edit || canAddOrEdit)'
|
||||
},
|
||||
variables: {
|
||||
label: i18n._('Extra Variables'),
|
||||
@@ -119,7 +119,7 @@ export default ['NotificationsList', 'i18n', function(NotificationsList, i18n) {
|
||||
variable: 'ask_variables_on_launch',
|
||||
text: i18n._('Prompt on launch')
|
||||
},
|
||||
ngDisabled: '!(workflow_job_template_obj.summary_fields.user_capabilities.edit || canAddWorkflowJobTemplate)' // TODO: get working
|
||||
ngDisabled: '!(workflow_job_template_obj.summary_fields.user_capabilities.edit || canAddOrEdit)' // TODO: get working
|
||||
},
|
||||
checkbox_group: {
|
||||
label: i18n._('Options'),
|
||||
@@ -133,7 +133,7 @@ export default ['NotificationsList', 'i18n', function(NotificationsList, i18n) {
|
||||
dataPlacement: 'right',
|
||||
dataTitle: i18n._('Enable Concurrent Jobs'),
|
||||
dataContainer: "body",
|
||||
ngDisabled: '!(workflow_job_template_obj.summary_fields.user_capabilities.edit || canAddWorkflowJobTemplate)'
|
||||
ngDisabled: '!(workflow_job_template_obj.summary_fields.user_capabilities.edit || canAddOrEdit)'
|
||||
}]
|
||||
}
|
||||
},
|
||||
@@ -142,22 +142,22 @@ export default ['NotificationsList', 'i18n', function(NotificationsList, i18n) {
|
||||
launch: {
|
||||
component: 'at-launch-template',
|
||||
templateObj: 'workflow_job_template_obj',
|
||||
ngShow: '(workflow_job_template_obj.summary_fields.user_capabilities.start || canAddWorkflowJobTemplate)',
|
||||
ngShow: '(workflow_job_template_obj.summary_fields.user_capabilities.start || canAddOrEdit)',
|
||||
ngDisabled: 'disableLaunch || workflow_job_template_form.$dirty',
|
||||
showTextButton: 'true'
|
||||
},
|
||||
cancel: {
|
||||
ngClick: 'formCancel()',
|
||||
ngShow: '(workflow_job_template_obj.summary_fields.user_capabilities.edit || canAddWorkflowJobTemplate)'
|
||||
ngShow: '(workflow_job_template_obj.summary_fields.user_capabilities.edit || canAddOrEdit)'
|
||||
},
|
||||
close: {
|
||||
ngClick: 'formCancel()',
|
||||
ngShow: '!(workflow_job_template_obj.summary_fields.user_capabilities.edit || canAddWorkflowJobTemplate)'
|
||||
ngShow: '!(workflow_job_template_obj.summary_fields.user_capabilities.edit || canAddOrEdit)'
|
||||
},
|
||||
save: {
|
||||
ngClick: 'formSave()', //$scope.function to call on click, optional
|
||||
ngDisabled: "workflow_job_template_form.$invalid || can_edit!==true", //Disable when $pristine or $invalid, optional and when can_edit = false, for permission reasons
|
||||
ngShow: '(workflow_job_template_obj.summary_fields.user_capabilities.edit || canAddWorkflowJobTemplate)'
|
||||
ngShow: '(workflow_job_template_obj.summary_fields.user_capabilities.edit || canAddOrEdit)'
|
||||
}
|
||||
},
|
||||
|
||||
@@ -183,7 +183,7 @@ export default ['NotificationsList', 'i18n', function(NotificationsList, i18n) {
|
||||
awToolTip: i18n._('Add a permission'),
|
||||
actionClass: 'at-Button--add',
|
||||
actionId: 'button-add',
|
||||
ngShow: '(workflow_job_template_obj.summary_fields.user_capabilities.edit || canAddWorkflowJobTemplate)'
|
||||
ngShow: '(workflow_job_template_obj.summary_fields.user_capabilities.edit || canAddOrEdit)'
|
||||
}
|
||||
},
|
||||
|
||||
@@ -226,7 +226,7 @@ export default ['NotificationsList', 'i18n', function(NotificationsList, i18n) {
|
||||
relatedButtons: {
|
||||
view_survey: {
|
||||
ngClick: 'editSurvey()',
|
||||
ngShow: '($state.is(\'templates.addWorkflowJobTemplate\') || $state.is(\'templates.editWorkflowJobTemplate\') || $state.is(\'templates.editWorkflowJobTemplate.workflowMaker\')) && survey_exists && !(workflow_job_template_obj.summary_fields.user_capabilities.edit || canAddWorkflowJobTemplate)',
|
||||
ngShow: '($state.is(\'templates.addWorkflowJobTemplate\') || $state.is(\'templates.editWorkflowJobTemplate\') || $state.is(\'templates.editWorkflowJobTemplate.workflowMaker\')) && survey_exists && !(workflow_job_template_obj.summary_fields.user_capabilities.edit || canAddOrEdit)',
|
||||
label: i18n._('View Survey'),
|
||||
class: 'Form-primaryButton'
|
||||
},
|
||||
|
||||
@@ -20,7 +20,7 @@ export default [
|
||||
|
||||
const workflowTemplate = resolvedModels[1];
|
||||
|
||||
$scope.canAddOrEdit = workflowTemplate.options('actions.POST');
|
||||
$scope.canAddOrEdit = workflowTemplate.options('actions.POST') ? true : false;
|
||||
|
||||
$scope.canEditOrg = true;
|
||||
$scope.canEditInventory = true;
|
||||
|
||||
@@ -137,6 +137,6 @@
|
||||
</div>
|
||||
<div class="WorkflowMaker-buttonHolder">
|
||||
<button type="button" class="btn btn-sm WorkflowMaker-cancelButton" ng-click="closeDialog()"> {{:: strings.get('CLOSE') }}</button>
|
||||
<button type="button" class="btn btn-sm WorkflowMaker-saveButton" ng-click="saveWorkflowMaker()" ng-show="workflowJobTemplateObj.summary_fields.user_capabilities.edit || canAddWorkflowJobTemplate" ng-disabled="formState.showNodeForm || formState.showLinkForm"> {{:: strings.get('SAVE') }}</button>
|
||||
<button type="button" class="btn btn-sm WorkflowMaker-saveButton" ng-click="saveWorkflowMaker()" ng-show="workflowJobTemplateObj.summary_fields.user_capabilities.edit || canAddOrEdit" ng-disabled="formState.showNodeForm || formState.showLinkForm"> {{:: strings.get('SAVE') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -367,7 +367,6 @@
|
||||
<workflow-chart
|
||||
graph-state="graphState"
|
||||
workflow-zoomed="workflowZoomed(zoom)"
|
||||
can-add-workflow-job-template="canAddWorkflowJobTemplate"
|
||||
mode="details"
|
||||
read-only="readOnly"
|
||||
class="WorkflowMaker-chart">
|
||||
|
||||
@@ -8,6 +8,7 @@ from awx.main.views import (
|
||||
handle_403,
|
||||
handle_404,
|
||||
handle_500,
|
||||
handle_csp_violation,
|
||||
)
|
||||
|
||||
|
||||
@@ -20,6 +21,7 @@ urlpatterns = [
|
||||
url(r'^(?:api/)?403.html$', handle_403),
|
||||
url(r'^(?:api/)?404.html$', handle_404),
|
||||
url(r'^(?:api/)?500.html$', handle_500),
|
||||
url(r'^csp-violation/', handle_csp_violation),
|
||||
]
|
||||
|
||||
if settings.SETTINGS_MODULE == 'awx.settings.development':
|
||||
|
||||
@@ -22,9 +22,9 @@ Notification templates assigned at certain levels will inherit notifications def
|
||||
|
||||
## Workflow
|
||||
|
||||
When a job succeeds or fails, the error or success handler will pull a list of relevant notifications using the procedure defined above. It will then create a Notification object for each one containing relevant details about the job and then **sends** it to the destination (email addresses, slack channel(s), SMS numbers, etc.). These Notification objects are available as related resources on job types (Jobs, Inventory Updates, Project Updates), and also at `/api/v2/notifications`. You may also see what notifications have been sent from a notifications by examining its related resources.
|
||||
When a job starts, succeeds or fails, the running, success or error handler, respectively, will pull a list of relevant notifications using the procedure defined above. It then creates a Notification Object for each one containing relevant details about the job and then **sends** it to the destination (email addresses, Slack channel(s), SMS numbers, etc.). These Notification objects are available as related resources on job types (Jobs, Inventory Updates, Project Updates), and also at `/api/v2/notifications`. You may also see what notifications have been sent by examining its related resources.
|
||||
|
||||
Notifications can succeed or fail but that will not cause its associated job to succeed or fail. The status of the notification can be viewed at its detail endpoint: `/api/v2/notifications/<n>`
|
||||
Notifications can succeed or fail but that will _not_ cause its associated job to succeed or fail. The status of the notification can be viewed at its detail endpoint: `/api/v2/notifications/<n>`
|
||||
|
||||
## Testing Notifications Before Using Them
|
||||
|
||||
|
||||
@@ -26,6 +26,12 @@ dockerhub_base=ansible
|
||||
# pg_cpu_limit=1000
|
||||
# pg_mem_limit=2
|
||||
|
||||
# Kubernetes Ingress Annotations
|
||||
# You can use the variables below to pass annotations to Kubernetes Ingress
|
||||
# The example below shows an annotation to be used with Traefik but other Ingress controllers are also supported.
|
||||
#kubernetes_ingress_hostname=awx.example.org
|
||||
#kubernetes_ingress_annotations={'kubernetes.io/ingress.class': 'traefik', 'traefik.ingress.kubernetes.io/redirect-entry-point': 'https'}
|
||||
|
||||
# Kubernetes and Openshift Install Resource Requests
|
||||
# These are the request and limit values for a pod's container for task/web/rabbitmq/memcached/management.
|
||||
# The total amount of requested resources for a pod is the sum of all
|
||||
@@ -133,7 +139,6 @@ secret_key=awxsecret
|
||||
# CA Trust directory. If you need to provide custom CA certificates, supplying
|
||||
# this variable causes this directory on the host to be bind mounted over
|
||||
# /etc/pki/ca-trust in the awx_task and awx_web containers.
|
||||
# NOTE: only obeyed in local_docker install
|
||||
#ca_trust_dir=/etc/pki/ca-trust/source/anchors
|
||||
|
||||
# Include /etc/nginx/awx_extra.conf
|
||||
|
||||
@@ -61,6 +61,8 @@ http {
|
||||
|
||||
# HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months)
|
||||
add_header Strict-Transport-Security max-age=15768000;
|
||||
add_header Content-Security-Policy "default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' cdn.pendo.io; report-uri /csp-violation/";
|
||||
add_header X-Content-Security-Policy "default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' cdn.pendo.io; report-uri /csp-violation/";
|
||||
|
||||
# Protect against click-jacking https://www.owasp.org/index.php/Testing_for_Clickjacking_(OTG-CLIENT-009)
|
||||
add_header X-Frame-Options "DENY";
|
||||
|
||||
@@ -141,6 +141,16 @@ spec:
|
||||
ports:
|
||||
- containerPort: 8052
|
||||
volumeMounts:
|
||||
{% if ca_trust_dir is defined %}
|
||||
- name: {{ kubernetes_deployment_name }}-ca-trust-dir
|
||||
mountPath: "/etc/pki/ca-trust/source/anchors/"
|
||||
readOnly: true
|
||||
{% endif %}
|
||||
{% if project_data_dir is defined %}
|
||||
- name: {{ kubernetes_deployment_name }}-project-data-dir
|
||||
mountPath: "/var/lib/awx/projects"
|
||||
readOnly: false
|
||||
{% endif %}
|
||||
- name: {{ kubernetes_deployment_name }}-application-config
|
||||
mountPath: "/etc/tower/settings.py"
|
||||
subPath: settings.py
|
||||
@@ -176,6 +186,11 @@ spec:
|
||||
- /usr/bin/launch_awx_task.sh
|
||||
imagePullPolicy: Always
|
||||
volumeMounts:
|
||||
{% if ca_trust_dir is defined %}
|
||||
- name: {{ kubernetes_deployment_name }}-ca-trust-dir
|
||||
mountPath: "/etc/pki/ca-trust/source/anchors/"
|
||||
readOnly: true
|
||||
{% endif %}
|
||||
- name: {{ kubernetes_deployment_name }}-application-config
|
||||
mountPath: "/etc/tower/settings.py"
|
||||
subPath: settings.py
|
||||
@@ -274,6 +289,18 @@ spec:
|
||||
cpu: "{{ memcached_cpu_limit }}m"
|
||||
{% endif %}
|
||||
volumes:
|
||||
{% if ca_trust_dir is defined %}
|
||||
- name: {{ kubernetes_deployment_name }}-ca-trust-dir
|
||||
hostPath:
|
||||
path: "{{ ca_trust_dir }}"
|
||||
type: Directory
|
||||
{% endif %}
|
||||
{% if project_data_dir is defined %}
|
||||
- name: {{ kubernetes_deployment_name }}-project-data-dir
|
||||
hostPath:
|
||||
path: "{{ project_data_dir }}"
|
||||
type: Directory
|
||||
{% endif %}
|
||||
- name: {{ kubernetes_deployment_name }}-application-config
|
||||
configMap:
|
||||
name: {{ kubernetes_deployment_name }}-config
|
||||
@@ -346,11 +373,28 @@ kind: Ingress
|
||||
metadata:
|
||||
name: {{ kubernetes_deployment_name }}-web-svc
|
||||
namespace: {{ kubernetes_namespace }}
|
||||
{% if kubernetes_ingress_annotations is defined %}
|
||||
annotations:
|
||||
{% for key, value in kubernetes_ingress_annotations.items() %}
|
||||
{{ key }}: {{ value }}
|
||||
{% endfor %}
|
||||
|
||||
spec:
|
||||
rules:
|
||||
- host: {{ kubernetes_ingress_hostname }}
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
backend:
|
||||
serviceName: {{ kubernetes_deployment_name }}-web-svc
|
||||
servicePort: 80
|
||||
{% else %}
|
||||
spec:
|
||||
backend:
|
||||
serviceName: {{ kubernetes_deployment_name }}-web-svc
|
||||
servicePort: 80
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if openshift_host is defined %}
|
||||
---
|
||||
apiVersion: v1
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
register: awx_secret_key
|
||||
|
||||
- name: Start the containers
|
||||
docker_service:
|
||||
docker_compose:
|
||||
project_src: "{{ docker_compose_dir }}"
|
||||
restarted: "{{ awx_compose_config is changed or awx_secret_key is changed }}"
|
||||
register: awx_compose_start
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
The requirements.txt and requirements_ansible.txt files are generated from requirements.in and requirements_ansible.in, respectively, using `pip-tools` `pip-compile`. The following commands should do this if ran inside the tools_awx container.
|
||||
|
||||
Run these commands from the root of the awx repo. This will produce python 3 requirements files.
|
||||
If you do not wish to upgrade dependencies generally (such as adding a specific dependency
|
||||
needed for a feature) then do not use the `-U` flag.
|
||||
|
||||
```
|
||||
python3 -m venv /buildit
|
||||
|
||||
@@ -45,5 +45,5 @@ tacacs_plus==1.0
|
||||
twilio==6.10.4
|
||||
uWSGI==2.0.17
|
||||
uwsgitop==0.10.0
|
||||
pip==19.1.1
|
||||
setuptools==41.0.1
|
||||
pip==9.0.1
|
||||
setuptools==36.0.1
|
||||
|
||||
@@ -122,5 +122,5 @@ xmlsec==1.3.3 # via python3-saml
|
||||
zope.interface==4.6.0 # via twisted
|
||||
|
||||
# The following packages are considered to be unsafe in a requirements file:
|
||||
pip==19.1.1
|
||||
setuptools==41.0.1
|
||||
pip==9.0.1
|
||||
setuptools==36.0.1
|
||||
|
||||
@@ -47,14 +47,14 @@ ncclient==0.6.3
|
||||
# netaddr filter
|
||||
netaddr
|
||||
# oVirt/RHV
|
||||
ovirt-engine-sdk-python==4.2.4 # minimum set inside Ansible facts module requirements
|
||||
ovirt-engine-sdk-python==4.3.0 # minimum set inside Ansible facts module requirements
|
||||
pycurl==7.43.0.1 # higher versions will not install without SSL backend specified
|
||||
# AWX usage
|
||||
pexpect==4.6.0 # same as AWX requirement
|
||||
psutil==5.4.3 # same as AWX requirement
|
||||
ptyprocess==0.5.2 # via pexpect, but needs to be pinned. Read the blame.
|
||||
pip==19.1.1
|
||||
setuptools==41.0.1
|
||||
setuptools==36.0.1
|
||||
pip==9.0.1
|
||||
# VMware
|
||||
pyvmomi==6.5
|
||||
# WinRM
|
||||
|
||||
@@ -83,7 +83,7 @@ ntlm-auth==1.3.0 # via requests-credssp, requests-ntlm
|
||||
oauthlib==3.0.1 # via requests-oauthlib
|
||||
openstacksdk==0.23.0
|
||||
os-service-types==1.6.0 # via keystoneauth1, openstacksdk
|
||||
ovirt-engine-sdk-python==4.2.4
|
||||
ovirt-engine-sdk-python==4.3.0
|
||||
packaging==19.0
|
||||
paramiko==2.4.2 # via azure-cli-core, ncclient
|
||||
pbr==5.2.0 # via keystoneauth1, openstacksdk, os-service-types, stevedore
|
||||
@@ -122,5 +122,5 @@ wheel==0.30.0 # via azure-cli-core
|
||||
xmltodict==0.12.0 # via pywinrm
|
||||
|
||||
# The following packages are considered to be unsafe in a requirements file:
|
||||
pip==19.1.1
|
||||
setuptools==41.0.1
|
||||
pip==9.0.1
|
||||
setuptools==36.0.1
|
||||
|
||||
@@ -29,6 +29,7 @@ services:
|
||||
# - sync
|
||||
# volumes_from:
|
||||
# - sync
|
||||
working_dir: "/awx_devel"
|
||||
volumes:
|
||||
- "../:/awx_devel"
|
||||
privileged: true
|
||||
|
||||
@@ -22,6 +22,8 @@ server {
|
||||
|
||||
# HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months)
|
||||
add_header Strict-Transport-Security max-age=15768000;
|
||||
add_header Content-Security-Policy "default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' cdn.pendo.io; report-uri /csp-violation/";
|
||||
add_header X-Content-Security-Policy "default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' cdn.pendo.io; report-uri /csp-violation/";
|
||||
|
||||
location /static/ {
|
||||
root /awx_devel;
|
||||
@@ -82,6 +84,8 @@ server {
|
||||
|
||||
# HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months)
|
||||
add_header Strict-Transport-Security max-age=15768000;
|
||||
add_header Content-Security-Policy "default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' cdn.pendo.io; report-uri /csp-violation/";
|
||||
add_header X-Content-Security-Policy "default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' cdn.pendo.io; report-uri /csp-violation/";
|
||||
|
||||
location /static/ {
|
||||
root /awx_devel;
|
||||
|
||||
Reference in New Issue
Block a user