Commit 8540bead by Kálmán Viktor

Merge branch 'feature-node-pimp' into 'master'

Feature node pimp



See merge request !377
parents 5ea451a2 871de94e
...@@ -232,6 +232,14 @@ class ActivityModel(TimeStampedModel): ...@@ -232,6 +232,14 @@ class ActivityModel(TimeStampedModel):
else: else:
return code return code
def get_status_id(self):
if self.succeeded is None:
return 'wait'
elif self.succeeded:
return 'success'
else:
return 'failed'
@celery.task() @celery.task()
def compute_cached(method, instance, memcached_seconds, def compute_cached(method, instance, memcached_seconds,
......
...@@ -5,10 +5,11 @@ ...@@ -5,10 +5,11 @@
{% for a in activities %} {% for a in activities %}
<div class="activity" data-activity-id="{{ a.pk }}"> <div class="activity" data-activity-id="{{ a.pk }}">
<span class="timeline-icon{% if a.has_failed %} timeline-icon-failed{% endif %}"> <span class="timeline-icon{% if a.has_failed %} timeline-icon-failed{% endif %}">
<i class="fa {% if not a.finished %}fa-refresh fa-spin {% else %}fa-plus{% endif %}"></i> <i class="fa {% if not a.finished %}fa-refresh fa-spin {% else %}fa-{{a.icon}}{% endif %}"></i>
</span> </span>
<strong title="{{ a.result.get_admin_text }}"> <strong title="{{ a.result.get_admin_text }}">
{{ a.readable_name.get_admin_text|capfirst }} <a href="{{ a.get_absolute_url }}">
{{ a.readable_name.get_admin_text|capfirst }}</a>
</strong> </strong>
<span title="{{ a.started }}">{{ a.started|arrowfilter:LANGUAGE_CODE }}</span>{% if a.user %}, {{ a.user }}{% endif %} <span title="{{ a.started }}">{{ a.started|arrowfilter:LANGUAGE_CODE }}</span>{% if a.user %}, {{ a.user }}{% endif %}
...@@ -19,7 +20,8 @@ ...@@ -19,7 +20,8 @@
<div data-activity-id="{{ s.pk }}" <div data-activity-id="{{ s.pk }}"
class="sub-activity{% if s.has_failed %} sub-activity-failed{% endif %}"> class="sub-activity{% if s.has_failed %} sub-activity-failed{% endif %}">
<span title="{{ s.result.get_admin_text }}"> <span title="{{ s.result.get_admin_text }}">
{{ s.readable_name|get_text:user }} <a href="{{ s.get_absolute_url }}">
{{ s.readable_name|get_text:user }}</a>
</span> </span>
&ndash; &ndash;
{% if s.finished %} {% if s.finished %}
......
{% extends "dashboard/base.html" %}
{% load i18n %}
{% load hro %}
{% block content %}
<div class="body-content">
<div class="page-header">
<h1>
<div class="pull-right" id="vm-activity-state">
<span class="label label-{% if object.get_status_id == 'wait' %}info{% else %}{% if object.succeeded %}success{% else %}danger{% endif %}{% endif %}">
<span>{{ object.get_status_id|upper }}</span>
</span>
</div>
<i class="fa fa-{{icon}}"></i>
{{ object.node.name }}: {{object.readable_name|get_text:user}}
</h1>
</div>
<div class="row">
<div class="col-md-6" id="vm-info-pane">
{% include "dashboard/vm-detail/_activity-timeline.html" with active=object %}
</div>
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-body">
<dl>
<dt>{% trans "activity code" %}</dt>
<dd>{{object.activity_code}}</dd>
<dt>{% trans "node" %}</dt>
<dd><a href="{{object.node.get_absolute_url}}">{{object.node}}</a></dd>
<dt>{% trans "time" %}</dt>
<dd>{{object.started|default:'n/a'}} → {{object.finished|default:'n/a'}}</dd>
<dt>{% trans "user" %}</dt>
<dd>
<a href="{{ object.user.profile.get_absolute_url }}">
{{object.user|default:'(system)'}}</a></dd>
<dt>{% trans "type" %}</dt>
<dd>
{% if object.parent %}
{% blocktrans with url=object.parent.get_absolute_url name=object.parent %}
subactivity of <a href="{{url}}">{{name}}</a>
{% endblocktrans %}
{% else %}{% trans "top level activity" %}{% endif %}
</dd>
<dt>{% trans "task uuid" %}</dt>
<dd>{{ object.task_uuid|default:'n/a' }}</dd>
<dt>{% trans "status" %}</dt>
<dd id="activity_status">{{ object.get_status_id }}</dd>
<dt>{% trans "result" %}</dt>
<dd><textarea class="form-control" id="activity_result_text">{{object.result|get_text:user}}</textarea></dd>
<dt>{% trans "subactivities" %}</dt>
{% for s in object.children.all %}
<dd>
<span{% if s.result %} title="{{ s.result|get_text:user }}"{% endif %}>
<a href="{{ s.get_absolute_url }}">
{{ s.readable_name|get_text:user|capfirst }}</a></span> &ndash;
{% if s.finished %}
{{ s.finished|time:"H:i:s" }}
{% else %}
<i class="fa fa-refresh fa-spin" class="sub-activity-loading-icon"></i>
{% endif %}
{% if s.has_failed %}
<div class="label label-danger">{% trans "failed" %}</div>
{% endif %}
</dd>
{% empty %}
<dd>{% trans "none" %}</dd>
{% endfor %}
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
...@@ -25,7 +25,7 @@ from .views import ( ...@@ -25,7 +25,7 @@ from .views import (
GroupDetailView, GroupList, IndexView, GroupDetailView, GroupList, IndexView,
InstanceActivityDetail, LeaseCreate, LeaseDelete, LeaseDetail, InstanceActivityDetail, LeaseCreate, LeaseDelete, LeaseDetail,
MyPreferencesView, NodeAddTraitView, NodeCreate, NodeDelete, MyPreferencesView, NodeAddTraitView, NodeCreate, NodeDelete,
NodeDetailView, NodeList, NodeDetailView, NodeList, NodeActivityDetail,
NotificationView, TemplateAclUpdateView, TemplateCreate, NotificationView, TemplateAclUpdateView, TemplateCreate,
TemplateDelete, TemplateDetail, TemplateList, TemplateDelete, TemplateDetail, TemplateList,
vm_activity, VmCreate, VmDetailView, vm_activity, VmCreate, VmDetailView,
...@@ -133,6 +133,8 @@ urlpatterns = patterns( ...@@ -133,6 +133,8 @@ urlpatterns = patterns(
name='dashboard.views.node-activity-list'), name='dashboard.views.node-activity-list'),
url(r'^node/create/$', NodeCreate.as_view(), url(r'^node/create/$', NodeCreate.as_view(),
name='dashboard.views.node-create'), name='dashboard.views.node-create'),
url(r'^node/activity/(?P<pk>\d+)/$', NodeActivityDetail.as_view(),
name='dashboard.views.node-activity'),
url(r'^favourite/$', FavouriteView.as_view(), url(r'^favourite/$', FavouriteView.as_view(),
name='dashboard.views.favourite'), name='dashboard.views.favourite'),
......
...@@ -82,6 +82,20 @@ node_ops = OrderedDict([ ...@@ -82,6 +82,20 @@ node_ops = OrderedDict([
]) ])
def _get_activity_icon(act):
op = act.get_operation()
if op and op.id in node_ops:
return node_ops[op.id].icon
else:
return "cog"
def _format_activities(acts):
for i in acts:
i.icon = _get_activity_icon(i)
return acts
class NodeDetailView(LoginRequiredMixin, class NodeDetailView(LoginRequiredMixin,
GraphMixin, DetailView): GraphMixin, DetailView):
template_name = "dashboard/node-detail.html" template_name = "dashboard/node-detail.html"
...@@ -104,7 +118,7 @@ class NodeDetailView(LoginRequiredMixin, ...@@ -104,7 +118,7 @@ class NodeDetailView(LoginRequiredMixin,
context['ops'] = get_operations(self.object, self.request.user) context['ops'] = get_operations(self.object, self.request.user)
context['op'] = {i.op: i for i in context['ops']} context['op'] = {i.op: i for i in context['ops']}
context['show_show_all'] = len(na) > 10 context['show_show_all'] = len(na) > 10
context['activities'] = na[:10] context['activities'] = _format_activities(na[:10])
context['trait_form'] = form context['trait_form'] = form
context['graphite_enabled'] = ( context['graphite_enabled'] = (
settings.GRAPHITE_URL is not None) settings.GRAPHITE_URL is not None)
...@@ -306,8 +320,8 @@ class NodeActivityView(LoginRequiredMixin, SuperuserRequiredMixin, View): ...@@ -306,8 +320,8 @@ class NodeActivityView(LoginRequiredMixin, SuperuserRequiredMixin, View):
show_all = request.GET.get("show_all", "false") == "true" show_all = request.GET.get("show_all", "false") == "true"
node = Node.objects.get(pk=pk) node = Node.objects.get(pk=pk)
activities = NodeActivity.objects.filter( activities = _format_activities(NodeActivity.objects.filter(
node=node, parent=None).order_by('-started').select_related() node=node, parent=None).order_by('-started').select_related())
show_show_all = len(activities) > 10 show_show_all = len(activities) > 10
if not show_all: if not show_all:
...@@ -324,3 +338,18 @@ class NodeActivityView(LoginRequiredMixin, SuperuserRequiredMixin, View): ...@@ -324,3 +338,18 @@ class NodeActivityView(LoginRequiredMixin, SuperuserRequiredMixin, View):
json.dumps(response), json.dumps(response),
content_type="application/json" content_type="application/json"
) )
class NodeActivityDetail(LoginRequiredMixin, SuperuserRequiredMixin,
DetailView):
model = NodeActivity
context_object_name = 'nodeactivity' # much simpler to mock object
template_name = 'dashboard/nodeactivity_detail.html'
def get_context_data(self, **kwargs):
ctx = super(NodeActivityDetail, self).get_context_data(**kwargs)
ctx['activities'] = _format_activities(NodeActivity.objects.filter(
node=self.object.node, parent=None
).order_by('-started').select_related())
ctx['icon'] = _get_activity_icon(self.object)
return ctx
...@@ -135,14 +135,6 @@ class InstanceActivity(ActivityModel): ...@@ -135,14 +135,6 @@ class InstanceActivity(ActivityModel):
def get_absolute_url(self): def get_absolute_url(self):
return reverse('dashboard.views.vm-activity', args=[self.pk]) return reverse('dashboard.views.vm-activity', args=[self.pk])
def get_status_id(self):
if self.succeeded is None:
return 'wait'
elif self.succeeded:
return 'success'
else:
return 'failed'
def has_percentage(self): def has_percentage(self):
op = self.instance.get_operation_from_activity_code(self.activity_code) op = self.instance.get_operation_from_activity_code(self.activity_code)
return (self.task_uuid and op and op.has_percentage and return (self.task_uuid and op and op.has_percentage and
...@@ -215,6 +207,13 @@ class NodeActivity(ActivityModel): ...@@ -215,6 +207,13 @@ class NodeActivity(ActivityModel):
app_label = 'vm' app_label = 'vm'
db_table = 'vm_nodeactivity' db_table = 'vm_nodeactivity'
def get_operation(self):
return self.node.get_operation_from_activity_code(
self.activity_code)
def get_absolute_url(self):
return reverse('dashboard.views.node-activity', args=[self.pk])
def __unicode__(self): def __unicode__(self):
if self.parent: if self.parent:
return '{}({})->{}'.format(self.parent.activity_code, return '{}({})->{}'.format(self.parent.activity_code,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment