Commit 7c3e721f authored by Kostas Papadimitriou's avatar Kostas Papadimitriou
Browse files

Allow helpdesk users to shutdown/start vms

Include an additional action to helpdesk view. Based on the current
status of the virtual machine helpdesk user is allowed to start it or
shut it down.

This comes handy since in most cases vm suspension needs to be
followed up with some kind of network cut off of the corresponding
machine. Since no such option is currently available from the
software, machine shutdown is provided as an alternative.
parent f1cb3113
......@@ -187,7 +187,8 @@ h4 i { margin-top: 4px; margin-right: 10px;}
.container-fluid { margin-left:auto; margin-right:auto; max-width:960px; }
h3.info { cursor:default; color:#2956B2; text-align:center; font-size:16px; margin-bottom:0;}
.vm-suspend-form { margin-top: 20px; text-align: right; }
.vm-suspend-form form { margin-bottom: 0px; }
.vm-suspend-form.suspended form input { background-color: #2956B2; color: #ffffff;}
.vm-suspend-form form input { background-color: #F81A23; color: #ffffff;}
.vm-actions { margin-top: 20px; text-align: right; }
.vm-action { float: right; margin-left: 10px;}
.vm-action form { margin-bottom: 0px; }
.vm-action.inactive form input { background-color: #2956B2; color: #ffffff;}
.vm-action form input { background-color: #F81A23; color: #ffffff;}
{% if vm.suspended %}
<form method="post" action="{% url helpdesk-suspend-vm-release vm_id=vm.pk %}">
<input type="hidden" name="token" value="{{ csrf_token }}" />
<input type="submit" value="RELEASE SUSPENSION" />
</form>
{% else %}
<form method="post" action="{% url helpdesk-suspend-vm vm_id=vm.pk %}">
<input type="hidden" name="token" value="{{ csrf_token }}" />
<input type="submit" value="SUSPEND" />
</form>
{% endif %}
<div class="vm-suspend-form vm-action {% if vm.suspended %}inactive{% endif %}">
{% if vm.suspended %}
<form method="post" action="{% url helpdesk-suspend-vm-release vm_id=vm.pk %}">
<input type="hidden" name="token" value="{{ token }}" />
<input type="submit" value="RELEASE SUSPENSION" />
</form>
{% else %}
<form method="post" action="{% url helpdesk-suspend-vm vm_id=vm.pk %}">
<input type="hidden" name="token" value="{{ token }}" />
<input type="submit" value="SUSPEND" />
</form>
{% endif %}
</div>
<div class="vm-shutdown-form vm-action {% if vm.operstate == 'STOPPED' %}inactive{% endif %}">
{% if vm.operstate == 'STARTED' %}
<form method="post" action="{% url helpdesk-vm-shutdown vm_id=vm.pk %}">
<input type="hidden" name="token" value="{{ token }}" />
<input type="submit" value="SHUTDOWN" />
</form>
{% endif %}
{% if vm.operstate == 'STOPPED' %}
<form method="post" action="{% url helpdesk-vm-start vm_id=vm.pk %}">
<input type="hidden" name="token" value="{{ token }}" />
<input type="submit" value="START" />
</form>
{% endif %}
</div>
......@@ -97,7 +97,7 @@
</div>
</div>
</div>
<div class="vm-suspend-form {% if vm.suspended %}suspended{% endif %}">
{% include "helpdesk/_suspend.html" %}
<div class="vm-actions clearfix">
{% include "helpdesk/_vm_actions.html" %}
</div>
</div>
......@@ -86,6 +86,10 @@ def backend_info(vm):
content = ""
backend = vm.backend
excluded = ['password_hash', 'hash', 'username']
if not vm.backend:
content = "No backend"
return content
for field in vm.backend._meta.fields:
if field.name in excluded:
continue
......
......@@ -32,6 +32,8 @@
# or implied, of GRNET S.A.
#
import mock
from django.test import TestCase, Client
from django.conf import settings
from django.core.urlresolvers import reverse
......@@ -47,6 +49,8 @@ USERS_UUIDS[USER2] = {'displayname': 'testuser2@test.com'}
USERS_DISPLAYNAMES = dict(map(lambda k: (k[1]['displayname'], {'uuid': k[0]}),
USERS_UUIDS.iteritems()))
from synnefo.db import models_factory as mfactory
class AuthClient(Client):
def request(self, **request):
......@@ -242,3 +246,34 @@ class HelpdeskTests(TestCase):
vms = r.context['vms']
self.assertEqual(r.context['account_exists'], False)
self.assertEqual(vms.count(), 0)
def test_start_shutdown(self):
from synnefo.logic import backend
self.vm1 = mfactory.VirtualMachineFactory(userid=USER1)
pk = self.vm1.pk
r = self.client.post(reverse('helpdesk-vm-shutdown', args=(pk,)))
self.assertEqual(r.status_code, 403)
r = self.client.post(reverse('helpdesk-vm-shutdown', args=(pk,)),
data={'token': '0001'})
self.assertEqual(r.status_code, 403)
backend.shutdown_instance = shutdown = mock.Mock()
self.vm1.operstate = 'STARTED'
self.vm1.save()
r = self.client.post(reverse('helpdesk-vm-shutdown', args=(pk,)),
data={'token': '0001'}, user_token='0001')
self.assertEqual(r.status_code, 302)
self.assertTrue(shutdown.called)
self.assertEqual(len(shutdown.mock_calls), 1)
backend.startup_instance = startup = mock.Mock()
self.vm1.operstate = 'STOPPED'
self.vm1.save()
r = self.client.post(reverse('helpdesk-vm-start', args=(pk,)),
data={'token': '0001'}, user_token='0001')
self.assertEqual(r.status_code, 302)
self.assertTrue(startup.called)
self.assertEqual(len(startup.mock_calls), 1)
......@@ -2,11 +2,18 @@ from django.conf.urls.defaults import patterns, url
urlpatterns = patterns('',
url(r'^$', 'synnefo.helpdesk.views.index', name='helpdesk-index'),
url(r'^suspend/(?P<vm_id>[0-9]+)$', 'synnefo.helpdesk.views.suspend_vm',
url(r'^actions/vm-suspend/(?P<vm_id>[0-9]+)$',
'synnefo.helpdesk.views.vm_suspend',
name='helpdesk-suspend-vm'),
url(r'^suspend_release/(?P<vm_id>[0-9]+)$',
'synnefo.helpdesk.views.suspend_vm_release',
url(r'^actions/vm-suspend-release/(?P<vm_id>[0-9]+)$',
'synnefo.helpdesk.views.vm_suspend_release',
name='helpdesk-suspend-vm-release'),
url(r'^actions/vm-shutdown/(?P<vm_id>[0-9]+)$',
'synnefo.helpdesk.views.vm_shutdown',
name='helpdesk-vm-shutdown'),
url(r'^actions/vm-start/(?P<vm_id>[0-9]+)$',
'synnefo.helpdesk.views.vm_start',
name='helpdesk-vm-start'),
url(r'^(?P<search_query>.*)$', 'synnefo.helpdesk.views.account',
name='helpdesk-details'),
)
......
......@@ -47,6 +47,10 @@ from synnefo.lib.astakos import get_user
from synnefo.db.models import VirtualMachine, NetworkInterface, Network
from synnefo.lib import astakos
# server actions specific imports
from synnefo.api import servers
from synnefo.logic import backend as servers_backend
logger = logging.getLogger(__name__)
IP_SEARCH_REGEX = re.compile('([0-9]+)(?:\.[0-9]+){3}')
......@@ -237,7 +241,7 @@ def account(request, search_query):
'vms': vms,
'show_deleted': show_deleted,
'account_name': account_name,
'csrf_token': request.user['auth_token'],
'token': request.user['auth_token'],
'networks': networks,
'UI_MEDIA_URL': settings.UI_MEDIA_URL
}
......@@ -248,7 +252,7 @@ def account(request, search_query):
@helpdesk_user_required
@token_check
def suspend_vm(request, vm_id):
def vm_suspend(request, vm_id):
vm = VirtualMachine.objects.get(pk=vm_id)
vm.suspended = True
vm.save()
......@@ -259,10 +263,32 @@ def suspend_vm(request, vm_id):
@helpdesk_user_required
@token_check
def suspend_vm_release(request, vm_id):
def vm_suspend_release(request, vm_id):
vm = VirtualMachine.objects.get(pk=vm_id)
vm.suspended = False
vm.save()
logging.info("VM %s unsuspended by %s", vm_id, request.user_uniq)
account = vm.userid
return HttpResponseRedirect(reverse('helpdesk-details', args=(account,)))
@helpdesk_user_required
@token_check
def vm_shutdown(request, vm_id):
logging.info("VM %s shutdown by %s", vm_id, request.user_uniq)
vm = VirtualMachine.objects.get(pk=vm_id)
servers.start_action(vm, 'STOP')
servers_backend.shutdown_instance(vm)
account = vm.userid
return HttpResponseRedirect(reverse('helpdesk-details', args=(account,)))
@helpdesk_user_required
@token_check
def vm_start(request, vm_id):
logging.info("VM %s start by %s", vm_id, request.user_uniq)
vm = VirtualMachine.objects.get(pk=vm_id)
servers.start_action(vm, 'START')
servers_backend.startup_instance(vm)
account = vm.userid
return HttpResponseRedirect(reverse('helpdesk-details', args=(account,)))
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 to comment