2015-04-07 15:14:49 +00:00
|
|
|
from django.contrib import admin, messages
|
2014-05-08 16:59:35 +00:00
|
|
|
from django.utils.html import escape
|
2015-04-07 15:14:49 +00:00
|
|
|
from django.utils.safestring import mark_safe
|
2023-10-24 16:59:02 +00:00
|
|
|
from django.utils.translation import gettext_lazy as _
|
2014-05-08 16:59:35 +00:00
|
|
|
|
2016-02-15 13:08:49 +00:00
|
|
|
from orchestra.admin import ExtendedModelAdmin, ChangeViewActionsMixin
|
2015-06-22 14:14:16 +00:00
|
|
|
from orchestra.admin.utils import admin_link, admin_date, admin_colored, display_mono, display_code
|
2015-10-05 12:09:11 +00:00
|
|
|
from orchestra.plugins.admin import display_plugin_field
|
2014-05-08 16:59:35 +00:00
|
|
|
|
2015-04-23 19:46:23 +00:00
|
|
|
from . import settings, helpers
|
2016-07-15 12:44:38 +00:00
|
|
|
from .actions import retry_backend, orchestrate
|
2014-11-11 12:05:47 +00:00
|
|
|
from .backends import ServiceBackend
|
2015-06-04 14:15:17 +00:00
|
|
|
from .forms import RouteForm
|
2014-05-08 16:59:35 +00:00
|
|
|
from .models import Server, Route, BackendLog, BackendOperation
|
2016-02-04 12:09:09 +00:00
|
|
|
from .utils import retrieve_state
|
2015-03-04 21:06:16 +00:00
|
|
|
from .widgets import RouteBackendSelect
|
2014-05-08 16:59:35 +00:00
|
|
|
|
2015-03-10 21:51:10 +00:00
|
|
|
|
2014-05-08 16:59:35 +00:00
|
|
|
STATE_COLORS = {
|
|
|
|
BackendLog.RECEIVED: 'darkorange',
|
|
|
|
BackendLog.TIMEOUT: 'red',
|
|
|
|
BackendLog.STARTED: 'blue',
|
|
|
|
BackendLog.SUCCESS: 'green',
|
|
|
|
BackendLog.FAILURE: 'red',
|
|
|
|
BackendLog.ERROR: 'red',
|
|
|
|
BackendLog.REVOKED: 'magenta',
|
2015-05-05 19:42:55 +00:00
|
|
|
BackendLog.NOTHING: 'green',
|
2014-05-08 16:59:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-01-26 13:05:02 +00:00
|
|
|
@admin.register(Route)
|
2015-05-14 13:28:54 +00:00
|
|
|
class RouteAdmin(ExtendedModelAdmin):
|
2015-04-16 13:15:21 +00:00
|
|
|
list_display = (
|
2021-03-30 10:51:12 +00:00
|
|
|
'display_backend', 'host', 'match', 'display_model', 'display_actions', 'run_async',
|
2015-10-05 12:09:11 +00:00
|
|
|
'is_active'
|
2015-04-16 13:15:21 +00:00
|
|
|
)
|
2021-03-30 10:51:12 +00:00
|
|
|
list_editable = ('host', 'match', 'run_async', 'is_active')
|
|
|
|
list_filter = ('host', 'is_active', 'run_async', 'backend')
|
2015-09-22 10:24:04 +00:00
|
|
|
list_prefetch_related = ('host',)
|
2015-04-04 17:44:07 +00:00
|
|
|
ordering = ('backend',)
|
2021-03-30 10:51:12 +00:00
|
|
|
add_fields = ('backend', 'host', 'match', 'run_async', 'is_active')
|
2015-05-14 13:28:54 +00:00
|
|
|
change_form = RouteForm
|
2016-07-15 12:44:38 +00:00
|
|
|
actions = (orchestrate,)
|
2016-07-19 22:45:04 +00:00
|
|
|
change_view_actions = actions
|
2021-03-30 10:51:12 +00:00
|
|
|
|
2015-04-23 19:46:23 +00:00
|
|
|
BACKEND_HELP_TEXT = helpers.get_backends_help_text(ServiceBackend.get_backends())
|
2015-03-04 21:06:16 +00:00
|
|
|
DEFAULT_MATCH = {
|
2015-04-14 14:29:22 +00:00
|
|
|
backend.get_name(): backend.default_route_match for backend in ServiceBackend.get_backends()
|
2015-03-04 21:06:16 +00:00
|
|
|
}
|
2021-03-30 10:51:12 +00:00
|
|
|
|
2015-10-05 12:09:11 +00:00
|
|
|
display_backend = display_plugin_field('backend')
|
2021-03-30 10:51:12 +00:00
|
|
|
|
2024-01-26 13:05:02 +00:00
|
|
|
@admin.display(
|
|
|
|
description=_("model")
|
|
|
|
)
|
2014-05-08 16:59:35 +00:00
|
|
|
def display_model(self, route):
|
|
|
|
try:
|
2021-05-21 08:47:27 +00:00
|
|
|
return route.backend_class.model
|
2014-05-08 16:59:35 +00:00
|
|
|
except KeyError:
|
2021-05-21 08:47:27 +00:00
|
|
|
return mark_safe("<span style='color: red;'>NOT AVAILABLE</span>")
|
2021-03-30 10:51:12 +00:00
|
|
|
|
2024-01-26 13:05:02 +00:00
|
|
|
@admin.display(
|
|
|
|
description=_("actions")
|
|
|
|
)
|
2021-05-21 08:47:27 +00:00
|
|
|
@mark_safe
|
2014-07-09 16:17:43 +00:00
|
|
|
def display_actions(self, route):
|
|
|
|
try:
|
2015-03-29 16:10:07 +00:00
|
|
|
return '<br>'.join(route.backend_class.get_actions())
|
2014-07-09 16:17:43 +00:00
|
|
|
except KeyError:
|
|
|
|
return "<span style='color: red;'>NOT AVAILABLE</span>"
|
2021-03-30 10:51:12 +00:00
|
|
|
|
2014-11-11 12:05:47 +00:00
|
|
|
def formfield_for_dbfield(self, db_field, **kwargs):
|
|
|
|
""" Provides dynamic help text on backend form field """
|
|
|
|
if db_field.name == 'backend':
|
2015-10-05 12:09:11 +00:00
|
|
|
kwargs['widget'] = RouteBackendSelect(
|
|
|
|
'this.id', self.BACKEND_HELP_TEXT, self.DEFAULT_MATCH)
|
2015-09-22 10:24:04 +00:00
|
|
|
field = super(RouteAdmin, self).formfield_for_dbfield(db_field, **kwargs)
|
|
|
|
if db_field.name == 'host':
|
|
|
|
# Cache host choices
|
|
|
|
request = kwargs['request']
|
|
|
|
choices = getattr(request, '_host_choices_cache', None)
|
|
|
|
if choices is None:
|
|
|
|
request._host_choices_cache = choices = list(field.choices)
|
|
|
|
field.choices = choices
|
|
|
|
return field
|
2021-03-30 10:51:12 +00:00
|
|
|
|
2014-11-11 12:05:47 +00:00
|
|
|
def get_form(self, request, obj=None, **kwargs):
|
|
|
|
""" Include dynamic help text for existing objects """
|
2015-03-26 16:00:30 +00:00
|
|
|
form = super(RouteAdmin, self).get_form(request, obj, **kwargs)
|
2014-11-11 12:05:47 +00:00
|
|
|
if obj:
|
2015-03-12 14:05:23 +00:00
|
|
|
form.base_fields['backend'].help_text = self.BACKEND_HELP_TEXT.get(obj.backend, '')
|
2014-11-11 12:05:47 +00:00
|
|
|
return form
|
2021-03-30 10:51:12 +00:00
|
|
|
|
2015-04-07 15:14:49 +00:00
|
|
|
def show_orchestration_disabled(self, request):
|
|
|
|
if settings.ORCHESTRATION_DISABLE_EXECUTION:
|
|
|
|
msg = _("Orchestration execution is disabled by <tt>ORCHESTRATION_DISABLE_EXECUTION</tt> setting.")
|
|
|
|
self.message_user(request, mark_safe(msg), messages.WARNING)
|
2021-03-30 10:51:12 +00:00
|
|
|
|
2015-04-07 15:14:49 +00:00
|
|
|
def changelist_view(self, request, extra_context=None):
|
|
|
|
self.show_orchestration_disabled(request)
|
|
|
|
return super(RouteAdmin, self).changelist_view(request, extra_context)
|
2021-03-30 10:51:12 +00:00
|
|
|
|
2015-04-07 15:14:49 +00:00
|
|
|
def changeform_view(self, request, object_id=None, form_url='', extra_context=None):
|
|
|
|
self.show_orchestration_disabled(request)
|
2015-10-07 11:44:30 +00:00
|
|
|
return super(RouteAdmin, self).changeform_view(
|
|
|
|
request, object_id, form_url, extra_context)
|
2014-05-08 16:59:35 +00:00
|
|
|
|
|
|
|
|
|
|
|
class BackendOperationInline(admin.TabularInline):
|
|
|
|
model = BackendOperation
|
2014-10-10 17:17:20 +00:00
|
|
|
fields = ('action', 'instance_link')
|
|
|
|
readonly_fields = ('action', 'instance_link')
|
2014-05-08 16:59:35 +00:00
|
|
|
extra = 0
|
|
|
|
can_delete = False
|
2021-03-30 10:51:12 +00:00
|
|
|
|
2014-05-08 16:59:35 +00:00
|
|
|
class Media:
|
|
|
|
css = {
|
|
|
|
'all': ('orchestra/css/hide-inline-id.css',)
|
|
|
|
}
|
2021-03-30 10:51:12 +00:00
|
|
|
|
2024-01-26 13:05:02 +00:00
|
|
|
@admin.display(
|
|
|
|
description=_("Instance")
|
|
|
|
)
|
2014-10-10 17:17:20 +00:00
|
|
|
def instance_link(self, operation):
|
2015-05-13 12:16:51 +00:00
|
|
|
link = admin_link('instance')(self, operation)
|
2015-06-03 12:49:30 +00:00
|
|
|
if link == '---':
|
2015-05-13 12:16:51 +00:00
|
|
|
return _("Deleted {0}").format(operation.instance_repr or '-'.join(
|
|
|
|
(escape(operation.content_type), escape(operation.object_id))))
|
|
|
|
return link
|
2021-03-30 10:51:12 +00:00
|
|
|
|
2014-05-08 16:59:35 +00:00
|
|
|
def has_add_permission(self, *args, **kwargs):
|
|
|
|
return False
|
2021-03-30 10:51:12 +00:00
|
|
|
|
2014-09-10 16:53:09 +00:00
|
|
|
def get_queryset(self, request):
|
|
|
|
queryset = super(BackendOperationInline, self).get_queryset(request)
|
2014-10-10 17:17:20 +00:00
|
|
|
return queryset.prefetch_related('instance')
|
2014-05-08 16:59:35 +00:00
|
|
|
|
|
|
|
|
2024-01-26 13:05:02 +00:00
|
|
|
@admin.register(BackendLog)
|
2016-02-15 13:08:49 +00:00
|
|
|
class BackendLogAdmin(ChangeViewActionsMixin, admin.ModelAdmin):
|
2014-05-08 16:59:35 +00:00
|
|
|
list_display = (
|
2014-07-14 14:56:48 +00:00
|
|
|
'id', 'backend', 'server_link', 'display_state', 'exit_code',
|
|
|
|
'display_created', 'execution_time',
|
2014-05-08 16:59:35 +00:00
|
|
|
)
|
|
|
|
list_display_links = ('id', 'backend')
|
2016-07-15 08:41:38 +00:00
|
|
|
list_filter = ('state', 'server', 'backend', 'operations__action')
|
2015-08-31 11:58:59 +00:00
|
|
|
search_fields = ('script',)
|
2015-06-04 14:15:17 +00:00
|
|
|
date_hierarchy = 'created_at'
|
2015-05-01 18:05:34 +00:00
|
|
|
inlines = (BackendOperationInline,)
|
|
|
|
fields = (
|
2015-06-22 14:14:16 +00:00
|
|
|
'backend', 'server_link', 'state', 'display_script', 'mono_stdout',
|
2014-07-25 15:17:50 +00:00
|
|
|
'mono_stderr', 'mono_traceback', 'exit_code', 'task_id', 'display_created',
|
2014-10-03 17:37:36 +00:00
|
|
|
'execution_time'
|
2015-05-01 18:05:34 +00:00
|
|
|
)
|
2014-07-14 14:56:48 +00:00
|
|
|
readonly_fields = fields
|
2016-02-15 13:08:49 +00:00
|
|
|
actions = (retry_backend,)
|
|
|
|
change_view_actions = actions
|
2021-03-30 10:51:12 +00:00
|
|
|
|
2014-07-21 15:43:36 +00:00
|
|
|
server_link = admin_link('server')
|
2014-10-03 17:37:36 +00:00
|
|
|
display_created = admin_date('created_at', short_description=_("Created"))
|
2014-07-24 09:53:34 +00:00
|
|
|
display_state = admin_colored('state', colors=STATE_COLORS)
|
2015-06-22 14:14:16 +00:00
|
|
|
display_script = display_code('script')
|
2014-07-28 17:28:00 +00:00
|
|
|
mono_stdout = display_mono('stdout')
|
|
|
|
mono_stderr = display_mono('stderr')
|
|
|
|
mono_traceback = display_mono('traceback')
|
2021-03-30 10:51:12 +00:00
|
|
|
|
2015-06-22 14:14:16 +00:00
|
|
|
class Media:
|
|
|
|
css = {
|
|
|
|
'all': ('orchestra/css/pygments/github.css',)
|
|
|
|
}
|
2021-03-30 10:51:12 +00:00
|
|
|
|
2014-07-08 15:19:15 +00:00
|
|
|
def get_queryset(self, request):
|
2014-05-08 16:59:35 +00:00
|
|
|
""" Order by structured name and imporve performance """
|
2014-07-08 15:19:15 +00:00
|
|
|
qs = super(BackendLogAdmin, self).get_queryset(request)
|
2014-09-10 16:53:09 +00:00
|
|
|
return qs.select_related('server').defer('script', 'stdout')
|
2021-03-30 10:51:12 +00:00
|
|
|
|
2014-09-26 15:05:20 +00:00
|
|
|
def has_add_permission(self, *args, **kwargs):
|
|
|
|
return False
|
2014-05-08 16:59:35 +00:00
|
|
|
|
|
|
|
|
2024-01-26 13:05:02 +00:00
|
|
|
@admin.register(Server)
|
2016-07-19 22:45:04 +00:00
|
|
|
class ServerAdmin(ExtendedModelAdmin):
|
2016-02-04 12:09:09 +00:00
|
|
|
list_display = ('name', 'address', 'os', 'display_ping', 'display_uptime')
|
2014-05-08 16:59:35 +00:00
|
|
|
list_filter = ('os',)
|
2016-07-15 12:44:38 +00:00
|
|
|
actions = (orchestrate,)
|
2016-07-19 22:45:04 +00:00
|
|
|
change_view_actions = actions
|
2021-03-30 10:51:12 +00:00
|
|
|
|
2024-01-26 13:05:02 +00:00
|
|
|
@admin.display(
|
|
|
|
description=_("Ping")
|
|
|
|
)
|
2016-02-04 12:09:09 +00:00
|
|
|
def display_ping(self, instance):
|
2021-05-17 11:20:18 +00:00
|
|
|
return mark_safe(self._remote_state[instance.pk][0])
|
2021-03-30 10:51:12 +00:00
|
|
|
|
2024-01-26 13:05:02 +00:00
|
|
|
@admin.display(
|
|
|
|
description=_("Uptime")
|
|
|
|
)
|
2016-02-04 12:09:09 +00:00
|
|
|
def display_uptime(self, instance):
|
2021-05-17 11:20:18 +00:00
|
|
|
return mark_safe(self._remote_state[instance.pk][1])
|
2021-03-30 10:51:12 +00:00
|
|
|
|
2016-02-04 12:09:09 +00:00
|
|
|
def get_queryset(self, request):
|
|
|
|
""" Order by structured name and imporve performance """
|
|
|
|
qs = super(ServerAdmin, self).get_queryset(request)
|
|
|
|
if request.method == 'GET' and request.resolver_match.func.__name__ == 'changelist_view':
|
|
|
|
self._remote_state = retrieve_state(qs)
|
|
|
|
return qs
|
2014-05-08 16:59:35 +00:00
|
|
|
|