Commit df995e7f by Kálmán Viktor

dashboard: restart, reset and migrate buttons

parent 61cfbebd
...@@ -458,7 +458,7 @@ class TemplateForm(forms.ModelForm): ...@@ -458,7 +458,7 @@ class TemplateForm(forms.ModelForm):
template = InstanceTemplate.objects.get(pk=parent) template = InstanceTemplate.objects.get(pk=parent)
parent = template.__dict__ parent = template.__dict__
fields = ["system", "name", "num_cores", "boot_menu", "ram_size", fields = ["system", "name", "num_cores", "boot_menu", "ram_size",
"priority", "state", "access_method", "raw_data", "priority", "access_method", "raw_data",
"arch", "description"] "arch", "description"]
for f in fields: for f in fields:
self.initial[f] = parent[f] self.initial[f] = parent[f]
......
...@@ -331,3 +331,17 @@ a.hover-black { ...@@ -331,3 +331,17 @@ a.hover-black {
display: block; display: block;
} }
#vm-migrate-node-list {
list-style: none;
}
#vm-migrate-node-list li {
padding-bottom: 10px;
}
.vm-migrate-node-property {
display: block;
padding-left: 15px;
}
/* for functions in both vm list and vm detail */
$(function() {
/* vm migrate */
$('.vm-migrate').click(function(e) {
var vm = $(this).data("vm-pk");
$.ajax({
type: 'GET',
url: '/dashboard/vm/' + vm + '/migrate/',
success: function(data) {
$('body').append(data);
$('#create-modal').modal('show');
$('#create-modal').on('hidden.bs.modal', function() {
$('#create-modal').remove();
});
}
});
return false;
});
});
{% load i18n %}
{% load sizefieldtags %}
<form method="POST" action="{% url "dashboard.views.vm-migrate" pk=vm %}">
{% csrf_token %}
<ul id="vm-migrate-node-list">
{% for n in nodes %}
<li>
<strong>{{ n }}</strong>
<input type="radio" name="node" value="{{ n.pk }}" style="float: right;"/>
<span class="vm-migrate-node-property">{% trans "CPU load" %}: {{ n.cpu_usage }}</span>
<span class="vm-migrate-node-property">{% trans "RAM usage" %}: {{ n.byte_ram_usage|filesize }}/{{ n.ram_size|filesize }}</span>
<div style="clear: both;"></div>
</li>
{% endfor %}
</ul>
<button type="submit" class="btn btn-primary btn-sm"><i class="icon-truck"></i> Migrate</button>
</form>
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
<div class="page-header"> <div class="page-header">
<div class="pull-right" style="padding-top: 15px;"> <div class="pull-right" style="padding-top: 15px;">
<a title="Rename" href="#" class="btn btn-default btn-xs vm-details-rename-button"><i class="icon-pencil"></i></a> <a title="Rename" href="#" class="btn btn-default btn-xs vm-details-rename-button"><i class="icon-pencil"></i></a>
<a title="Pause == sleep?" href="#" class="btn btn-default btn-xs"><i class="icon-pause"></i></a>
<form style="display: inline;" method="POST" action="{% url "dashboard.views.detail" pk=instance.pk %}"> <form style="display: inline;" method="POST" action="{% url "dashboard.views.detail" pk=instance.pk %}">
{% csrf_token %} {% csrf_token %}
<input type="hidden" name="sleep" value="dummy"/> <input type="hidden" name="sleep" value="dummy"/>
...@@ -27,7 +26,19 @@ ...@@ -27,7 +26,19 @@
<input type="hidden" name="shut_down" value="dummy"/> <input type="hidden" name="shut_down" value="dummy"/>
<button title="{% trans "Shut down" %}" class="btn btn-default btn-xs" type="submit"><i class="icon-off"></i></button> <button title="{% trans "Shut down" %}" class="btn btn-default btn-xs" type="submit"><i class="icon-off"></i></button>
</form> </form>
<a title="Migrate" href="#" class="btn btn-default btn-xs"><i class="icon-truck"></i></a> <form style="display: inline;" method="POST" action="{% url "dashboard.views.detail" pk=instance.pk %}">
{% csrf_token %}
<input type="hidden" name="reboot" value="dummy"/>
<button title="{% trans "Reboot (ctrl + alt + del)" %}" class="btn btn-default btn-xs" type="submit"><i class="icon-refresh"></i></button>
</form>
<form style="display: inline;" method="POST" action="{% url "dashboard.views.detail" pk=instance.pk %}">
{% csrf_token %}
<input type="hidden" name="reset" value="dummy"/>
<button title="{% trans "Reset (power cycle)" %}" class="btn btn-default btn-xs" type="submit"><i class="icon-bolt"></i></button>
</form>
<a title="Migrate" data-vm-pk="{{ instance.pk }}" href="{% url "dashboard.views.vm-migrate" pk=instance.pk %}" class="btn btn-default btn-xs vm-migrate">
<i class="icon-truck"></i>
</a>
<form style="display: inline;" method="POST" action="{% url "dashboard.views.detail" pk=instance.pk %}"> <form style="display: inline;" method="POST" action="{% url "dashboard.views.detail" pk=instance.pk %}">
{% csrf_token %} {% csrf_token %}
<input type="hidden" name="save_as" value="dummy"/> <input type="hidden" name="save_as" value="dummy"/>
...@@ -137,3 +148,8 @@ ...@@ -137,3 +148,8 @@
</div> </div>
{% endblock %} {% endblock %}
{% block extra_js %}
<script src="{{ STATIC_URL }}dashboard/vm-details.js"></script>
<script src="{{ STATIC_URL }}dashboard/vm-common.js"></script>
{% endblock %}
...@@ -5,7 +5,3 @@ ...@@ -5,7 +5,3 @@
<div id="activity-timeline" class="timeline"> <div id="activity-timeline" class="timeline">
{% include "dashboard/vm-detail/_activity-timeline.html" %} {% include "dashboard/vm-detail/_activity-timeline.html" %}
</div> </div>
{% block extra_js %}
<script src="{{ STATIC_URL }}dashboard/vm-details.js"></script>
{% endblock %}
...@@ -72,5 +72,6 @@ ...@@ -72,5 +72,6 @@
{% endblock %} {% endblock %}
{% block extra_js %} {% block extra_js %}
<script src="{{ STATIC_URL}}dashboard/vm-list.js"></script> <script src="{{ STATIC_URL}}dashboard/vm-list.js"></script>
<script src="{{ STATIC_URL}}dashboard/vm-common.js"></script>
{% endblock %} {% endblock %}
<a href="{% url "dashboard.views.vm-migrate" pk=record.pk %}" class="btn btn-default btn-xs vm-migrate" data-vm-pk="{{ record.pk }}" title data-original-title="Migrate">
<a class="btn btn-default btn-xs" title data-original-title="Migrate">
<i class="icon-truck"></i> <i class="icon-truck"></i>
</a> </a>
<a id="vm-list-rename-button" class="btn btn-default btn-xs" title data-original-title="Rename"> <a id="vm-list-rename-button" class="btn btn-default btn-xs" title data-original-title="Rename">
......
...@@ -8,7 +8,7 @@ from .views import ( ...@@ -8,7 +8,7 @@ from .views import (
TemplateList, LeaseDetail, NodeCreate, LeaseCreate, TemplateCreate, TemplateList, LeaseDetail, NodeCreate, LeaseCreate, TemplateCreate,
FavouriteView, NodeStatus, GroupList, TemplateDelete, LeaseDelete, FavouriteView, NodeStatus, GroupList, TemplateDelete, LeaseDelete,
VmGraphView, TemplateAclUpdateView, GroupDetailView, GroupDelete, VmGraphView, TemplateAclUpdateView, GroupDetailView, GroupDelete,
GroupAclUpdateView, GroupUserDelete, NodeGraphView GroupAclUpdateView, GroupUserDelete, NodeGraphView, VmMigrateView,
) )
urlpatterns = patterns( urlpatterns = patterns(
...@@ -48,6 +48,8 @@ urlpatterns = patterns( ...@@ -48,6 +48,8 @@ urlpatterns = patterns(
url(r'^vm/mass-delete/', VmMassDelete.as_view(), url(r'^vm/mass-delete/', VmMassDelete.as_view(),
name='dashboard.view.mass-delete-vm'), name='dashboard.view.mass-delete-vm'),
url(r'^vm/(?P<pk>\d+)/activity/$', vm_activity), url(r'^vm/(?P<pk>\d+)/activity/$', vm_activity),
url(r'^vm/(?P<pk>\d+)/migrate/$', VmMigrateView.as_view(),
name='dashboard.views.vm-migrate'),
url(r'^node/list/$', NodeList.as_view(), name='dashboard.views.node-list'), url(r'^node/list/$', NodeList.as_view(), name='dashboard.views.node-list'),
url(r'^node/(?P<pk>\d+)/$', NodeDetailView.as_view(), url(r'^node/(?P<pk>\d+)/$', NodeDetailView.as_view(),
......
...@@ -1652,3 +1652,37 @@ class NodeGraphView(SuperuserRequiredMixin, GraphViewBase): ...@@ -1652,3 +1652,37 @@ class NodeGraphView(SuperuserRequiredMixin, GraphViewBase):
def get_object(self, request, pk): def get_object(self, request, pk):
return self.model.objects.get(id=pk) return self.model.objects.get(id=pk)
class VmMigrateView(SuperuserRequiredMixin, TemplateView):
def get_template_names(self):
if self.request.is_ajax():
return ['dashboard/modal-wrapper.html']
else:
return ['dashboard/nojs-wrapper.html']
def get(self, request, form=None, *args, **kwargs):
context = self.get_context_data(**kwargs)
vm = Instance.objects.get(pk=kwargs['pk'])
context.update({
'template': 'dashboard/_vm-migrate.html',
'box_title': _('Migrate %(name)s' % {'name': vm.name}),
'ajax_title': True,
'vm': kwargs['pk'],
'nodes': [n for n in Node.objects.filter(enabled=True)
if n.state == "ONLINE"]
})
return self.render_to_response(context)
def post(self, *args, **kwargs):
node = self.request.POST.get("node")
vm = Instance.objects.get(pk=kwargs['pk'])
if node:
node = Node.objects.get(pk=node)
vm.migrate_async(to_node=node, user=self.request.user)
else:
messages.error(self.request, _("You didn't select a node!"))
return redirect("%s#activity" % vm.get_absolute_url())
...@@ -907,14 +907,14 @@ class Instance(AclBase, VirtualMachineDescModel, TimeStampedModel): ...@@ -907,14 +907,14 @@ class Instance(AclBase, VirtualMachineDescModel, TimeStampedModel):
task_uuid=task_uuid, user=user): task_uuid=task_uuid, user=user):
queue_name = self.get_remote_queue_name('vm') queue_name = self.get_remote_queue_name('vm')
vm_tasks.restart.apply_async(args=[self.vm_name], vm_tasks.reset.apply_async(args=[self.vm_name],
queue=queue_name queue=queue_name
).get(timeout=timeout) ).get(timeout=timeout)
def reset_async(self, user=None): def reset_async(self, user=None):
"""Execute reset asynchronously. """Execute reset asynchronously.
""" """
return local_tasks.restart.apply_async(args=[self, user], return local_tasks.reset.apply_async(args=[self, user],
queue="localhost.man") queue="localhost.man")
def reboot(self, user=None, task_uuid=None, timeout=5): def reboot(self, user=None, task_uuid=None, timeout=5):
......
...@@ -235,6 +235,10 @@ class Node(TimeStampedModel): ...@@ -235,6 +235,10 @@ class Node(TimeStampedModel):
def ram_usage(self): def ram_usage(self):
return float(self.get_monitor_info()["memory.usage"]) / 100 return float(self.get_monitor_info()["memory.usage"]) / 100
@property
def byte_ram_usage(self):
return self.ram_usage * self.ram_size
def update_vm_states(self): def update_vm_states(self):
"""Update state of Instances running on this Node. """Update state of Instances running on this Node.
......
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