From 75ef0dd395fc08ef6e87a8fc03d8d90310736c08 Mon Sep 17 00:00:00 2001 From: Matthew Jones Date: Tue, 23 Feb 2016 14:19:42 -0500 Subject: [PATCH] Implement tower ui view url on models --- awx/api/views.py | 5 +++-- awx/main/models/ad_hoc_commands.py | 4 ++++ awx/main/models/inventory.py | 5 +++++ awx/main/models/jobs.py | 7 +++++++ awx/main/models/projects.py | 4 ++++ awx/main/models/unified_jobs.py | 9 ++++++++- awx/main/tasks.py | 15 ++++++++------- awx/settings/defaults.py | 9 +++++++++ 8 files changed, 48 insertions(+), 10 deletions(-) diff --git a/awx/api/views.py b/awx/api/views.py index 70532f026c..e5975c7173 100644 --- a/awx/api/views.py +++ b/awx/api/views.py @@ -268,6 +268,7 @@ class ApiV1ConfigView(APIView): # If the license is valid, write it to disk. if license_data['valid_key']: tower_settings.LICENSE = data_actual + tower_settings.TOWER_URL_BASE = "{}://{}".format(request.scheme, request.get_host()) # Spawn a task to ensure that MongoDB is started (or stopped) # as appropriate, based on whether the license uses it. @@ -3053,8 +3054,8 @@ class NotifierTest(GenericAPIView): def post(self, request, *args, **kwargs): obj = self.get_object() - notification = obj.generate_notification("Tower Notification Test {}".format(obj.id), - {"body": "Ansible Tower Test Notification {}".format(obj.id)}) + notification = obj.generate_notification("Tower Notification Test {} {}".format(obj.id, tower_settings.TOWER_URL_BASE), + {"body": "Ansible Tower Test Notification {} {}".format(obj.id, tower_settings.TOWER_URL_BASE)}) if not notification: return Response({}, status=status.HTTP_400_BAD_REQUEST) else: diff --git a/awx/main/models/ad_hoc_commands.py b/awx/main/models/ad_hoc_commands.py index 664269a188..12c4261d8b 100644 --- a/awx/main/models/ad_hoc_commands.py +++ b/awx/main/models/ad_hoc_commands.py @@ -5,6 +5,7 @@ import hmac import json import logging +from urlparse import urljoin # Django from django.conf import settings @@ -139,6 +140,9 @@ class AdHocCommand(UnifiedJob): def get_absolute_url(self): return reverse('api:ad_hoc_command_detail', args=(self.pk,)) + def get_ui_url(self): + return urljoin(tower_settings.TOWER_URL_BASE, "/#/ad_hoc_commands/{}".format(self.pk)) + @property def task_auth_token(self): '''Return temporary auth token used for task requests via API.''' diff --git a/awx/main/models/inventory.py b/awx/main/models/inventory.py index fd6dfbff76..edf03a883d 100644 --- a/awx/main/models/inventory.py +++ b/awx/main/models/inventory.py @@ -6,6 +6,7 @@ import datetime import logging import re import copy +from urlparse import urljoin # Django from django.conf import settings @@ -25,6 +26,7 @@ from awx.main.models.jobs import Job from awx.main.models.unified_jobs import * # noqa from awx.main.models.notifications import Notifier from awx.main.utils import ignore_inventory_computed_fields, _inventory_updates +from awx.main.conf import tower_settings __all__ = ['Inventory', 'Host', 'Group', 'InventorySource', 'InventoryUpdate', 'CustomInventoryScript'] @@ -1249,6 +1251,9 @@ class InventoryUpdate(UnifiedJob, InventorySourceOptions): def get_absolute_url(self): return reverse('api:inventory_update_detail', args=(self.pk,)) + def get_ui_url(self): + return urljoin(tower_settings.TOWER_URL_BASE, "/#/inventory_sync/{}".format(self.pk)) + def is_blocked_by(self, obj): if type(obj) == InventoryUpdate: if self.inventory_source.inventory == obj.inventory_source.inventory: diff --git a/awx/main/models/jobs.py b/awx/main/models/jobs.py index 2d2dc991a9..01857b8b06 100644 --- a/awx/main/models/jobs.py +++ b/awx/main/models/jobs.py @@ -6,6 +6,7 @@ import hmac import json import yaml import logging +from urlparse import urljoin # Django from django.conf import settings @@ -380,6 +381,9 @@ class Job(UnifiedJob, JobOptions): def get_absolute_url(self): return reverse('api:job_detail', args=(self.pk,)) + def get_ui_url(self): + return urljoin(tower_settings.TOWER_URL_BASE, "/#/jobs/{}".format(self.pk)) + @property def task_auth_token(self): '''Return temporary auth token used for task requests via API.''' @@ -1096,6 +1100,9 @@ class SystemJob(UnifiedJob, SystemJobOptions): def get_absolute_url(self): return reverse('api:system_job_detail', args=(self.pk,)) + def get_ui_url(self): + return urljoin(tower_settings.TOWER_URL_BASE, "/#/management_jobs/{}".format(self.pk)) + def is_blocked_by(self, obj): return True diff --git a/awx/main/models/projects.py b/awx/main/models/projects.py index 8a320e3cfc..01e4220d6d 100644 --- a/awx/main/models/projects.py +++ b/awx/main/models/projects.py @@ -24,6 +24,7 @@ from awx.main.models.jobs import Job from awx.main.models.notifications import Notifier from awx.main.models.unified_jobs import * # noqa from awx.main.utils import update_scm_url +from awx.main.conf import tower_settings __all__ = ['Project', 'ProjectUpdate'] @@ -389,6 +390,9 @@ class ProjectUpdate(UnifiedJob, ProjectOptions): def get_absolute_url(self): return reverse('api:project_update_detail', args=(self.pk,)) + def get_ui_url(self): + return urlparse.urljoin(tower_settings.TOWER_URL_BASE, "/#/scm_update/{}".format(self.pk)) + def _update_parent_instance(self): parent_instance = self._get_parent_instance() if parent_instance: diff --git a/awx/main/models/unified_jobs.py b/awx/main/models/unified_jobs.py index ed34653048..9a324048c3 100644 --- a/awx/main/models/unified_jobs.py +++ b/awx/main/models/unified_jobs.py @@ -484,6 +484,13 @@ class UnifiedJob(PolymorphicModel, PasswordFieldsModel, CommonModelNameNotUnique else: return '' + def get_ui_url(self): + real_instance = self.get_real_instance() + if real_instance != self: + return real_instance.get_ui_url() + else: + return '' + @classmethod def _get_task_class(cls): raise NotImplementedError # Implement in subclasses. @@ -734,7 +741,7 @@ class UnifiedJob(PolymorphicModel, PasswordFieldsModel, CommonModelNameNotUnique def notification_data(self): return dict(id=self.id, name=self.name, - url=self.get_absolute_url(), #TODO: Need to replace with UI job view + url=self.get_ui_url(), created_by=str(self.created_by), started=self.started.isoformat(), finished=self.finished.isoformat(), diff --git a/awx/main/tasks.py b/awx/main/tasks.py index 58e5425866..ee65490ec1 100644 --- a/awx/main/tasks.py +++ b/awx/main/tasks.py @@ -228,11 +228,11 @@ def handle_work_success(self, result, task_actual): friendly_name = "AdHoc Command" else: return - notification_subject = "{} #{} '{}' succeeded on Ansible Tower".format(friendly_name, - task_actual['id'], - instance_name) notification_body = instance.notification_data() - notification_body['friendly_name'] = friendly_name + notification_subject = "{} #{} '{}' succeeded on Ansible Tower: {}".format(friendly_name, + task_actual['id'], + instance_name, + notification_body['url']) send_notifications.delay([n.generate_notification(notification_subject, notification_body) for n in notifiers.get('success', []) + notifiers.get('any', [])], job_id=task_actual['id']) @@ -284,10 +284,11 @@ def handle_work_error(self, task_id, subtasks=None): (first_task_type, first_task_name, first_task_id) instance.save() instance.socketio_emit_status("failed") - notification_subject = "{} #{} '{}' failed on Ansible Tower".format(first_task_friendly_name, - first_task_id, - first_task_name) notification_body = first_task.notification_data() + notification_subject = "{} #{} '{}' failed on Ansible Tower: {}".format(first_task_friendly_name, + first_task_id, + first_task_name, + notification_body['url']) notification_body['friendly_name'] = first_task_friendly_name send_notifications.delay([n.generate_notification(notification_subject, notification_body).id for n in notifiers.get('error', []) + notifiers.get('any', [])], diff --git a/awx/settings/defaults.py b/awx/settings/defaults.py index 76ba79df61..465809b523 100644 --- a/awx/settings/defaults.py +++ b/awx/settings/defaults.py @@ -685,6 +685,8 @@ ORG_ADMINS_CAN_SEE_ALL_USERS = True TOWER_ADMIN_ALERTS = True +TOWER_URL_BASE = "https://towerhost" + TOWER_SETTINGS_MANIFEST = { "SCHEDULE_MAX_JOBS": { "name": "Maximum Scheduled Jobs", @@ -819,6 +821,13 @@ TOWER_SETTINGS_MANIFEST = { "type": "bool", "category": "system", }, + "TOWER_URL_BASE": { + "name": "Base URL of the Tower host", + "description": "This is used by services like Notifications to render a valid url to the Tower host", + "default": TOWER_URL_BASE, + "type": "string", + "category": "system", + }, "LICENSE": { "name": "Tower License", "description": "Controls what features and functionality is enabled in Tower.",