Commit 6658f290 by Őry Máté

Merge branch 'feature-renew-op-rebased' into 'master'

Feature Renew Op

🆗 refactor renew to an operation
🆗 token+operation
🆗 view
🆗 Lease acl views @kviktor
parents a245f33d 31295e76
...@@ -59,10 +59,10 @@ def create_levels(app, created_models, verbosity, db=DEFAULT_DB_ALIAS, ...@@ -59,10 +59,10 @@ def create_levels(app, created_models, verbosity, db=DEFAULT_DB_ALIAS,
] ]
Level.objects.using(db).bulk_create(levels) Level.objects.using(db).bulk_create(levels)
if verbosity >= 2: if verbosity >= 2:
print("Adding levels [%s]." % ", ".join(levels)) print("Adding levels [%s]." % ", ".join(unicode(l) for l in levels))
print("Searched: [%s]." % ", ".join( print("Searched: [%s]." % ", ".join(
[unicode(l) for l in searched_levels])) unicode(l) for l in searched_levels))
print("All: [%s]." % ", ".join([unicode(l) for l in all_levels])) print("All: [%s]." % ", ".join(unicode(l) for l in all_levels))
# set weights # set weights
for ctype, codename, weight in level_weights: for ctype, codename, weight in level_weights:
......
...@@ -46,8 +46,9 @@ CACHES = { ...@@ -46,8 +46,9 @@ CACHES = {
LOGGING['loggers']['djangosaml2'] = {'handlers': ['console'], LOGGING['loggers']['djangosaml2'] = {'handlers': ['console'],
'level': 'CRITICAL'} 'level': 'CRITICAL'}
LOGGING['handlers']['console'] = {'level': 'WARNING', level = environ.get('LOGLEVEL', 'CRITICAL')
LOGGING['handlers']['console'] = {'level': level,
'class': 'logging.StreamHandler', 'class': 'logging.StreamHandler',
'formatter': 'simple'} 'formatter': 'simple'}
for i in LOCAL_APPS: for i in LOCAL_APPS:
LOGGING['loggers'][i] = {'handlers': ['console'], 'level': 'CRITICAL'} LOGGING['loggers'][i] = {'handlers': ['console'], 'level': level}
...@@ -59,6 +59,8 @@ class Operation(object): ...@@ -59,6 +59,8 @@ class Operation(object):
skip_auth_check = auxargs.pop('system') skip_auth_check = auxargs.pop('system')
user = auxargs.pop('user') user = auxargs.pop('user')
parent_activity = auxargs.pop('parent_activity') parent_activity = auxargs.pop('parent_activity')
if parent_activity and user is None and not skip_auth_check:
user = parent_activity.user
# check for unexpected keyword arguments # check for unexpected keyword arguments
argspec = getargspec(self._operation) argspec = getargspec(self._operation)
......
...@@ -612,6 +612,9 @@ class TemplateForm(forms.ModelForm): ...@@ -612,6 +612,9 @@ class TemplateForm(forms.ModelForm):
self.instance.ram_size = 512 self.instance.ram_size = 512
self.instance.num_cores = 2 self.instance.num_cores = 2
self.fields["lease"].queryset = Lease.get_objects_with_level(
"operator", self.user)
def clean_owner(self): def clean_owner(self):
if self.instance.pk is not None: if self.instance.pk is not None:
return User.objects.get(pk=self.instance.owner.pk) return User.objects.get(pk=self.instance.owner.pk)
...@@ -888,6 +891,27 @@ class LeaseForm(forms.ModelForm): ...@@ -888,6 +891,27 @@ class LeaseForm(forms.ModelForm):
model = Lease model = Lease
class VmRenewForm(forms.Form):
def __init__(self, *args, **kwargs):
choices = kwargs.pop('choices')
default = kwargs.pop('default')
super(VmRenewForm, self).__init__(*args, **kwargs)
self.fields['lease'] = forms.ModelChoiceField(queryset=choices,
initial=default,
required=True,
label=_('Length'))
if len(choices) < 2:
self.fields['lease'].widget = HiddenInput()
@property
def helper(self):
helper = FormHelper(self)
helper.form_tag = False
return helper
class VmCreateDiskForm(forms.Form): class VmCreateDiskForm(forms.Form):
name = forms.CharField(max_length=100, label=_("Name")) name = forms.CharField(max_length=100, label=_("Name"))
size = forms.CharField( size = forms.CharField(
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
{% block content %} {% block content %}
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-7">
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
<a class="pull-right btn btn-default btn-xs" href="{% url "dashboard.views.template-list" %}">{% trans "Back" %}</a> <a class="pull-right btn btn-default btn-xs" href="{% url "dashboard.views.template-list" %}">{% trans "Back" %}</a>
...@@ -20,6 +20,85 @@ ...@@ -20,6 +20,85 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col-md-5">
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="no-margin"><i class="icon-group"></i> {% trans "Manage access" %}</h4>
</div>
<div class="panel-body">
<form action="{% url "dashboard.views.lease-acl" pk=object.pk %}" method="post">{% csrf_token %}
<table class="table table-striped table-with-form-fields" id="template-access-table">
<thead>
<tr>
<th></th>
<th>{% trans "Who" %}</th>
<th>{% trans "What" %}</th>
<th><i class="icon-remove"></i></th>
</tr>
</thead>
<tbody>
{% for i in acl.users %}
<tr>
<td>
<i class="icon-user"></i>
</td>
<td>
<a href="{% url "dashboard.views.profile" username=i.user.username %}"
title="{{ i.user.username }}">
{% include "dashboard/_display-name.html" with user=i.user show_org=True %}
</a>
</td>
<td>
<select class="form-control" name="perm-u-{{i.user.id}}">
{% for id, name in acl.levels %}
<option{%if id = i.level%} selected="selected"{%endif%} value="{{id}}">{{name}}</option>
{% endfor %}
</select>
</td>
<td>
<input type="checkbox" name="remove-u-{{i.user.id}}" title="{% trans "Remove" %}"/>
</td>
</tr>
{% endfor %}
{% for i in acl.groups %}
<tr>
<td><i class="icon-group"></i></td>
<td>
<a href="{% url "dashboard.views.group-detail" pk=i.group.pk %}">
{{i.group}}
</a>
</td>
<td>
<select class="form-control" name="perm-g-{{i.group.id}}">
{% for id, name in acl.levels %}
<option{%if id = i.level%} selected="selected"{%endif%} value="{{id}}">{{name}}</option>
{% endfor %}
</select>
</td>
<td>
<input type="checkbox" name="remove-g-{{i.group.id}}" title="{% trans "Remove" %}"/>
</td>
</tr>
{% endfor %}
<tr><td><i class="icon-plus"></i></td>
<td><input type="text" class="form-control" name="perm-new-name"
placeholder="{% trans "Name of group or user" %}"></td>
<td><select class="form-control" name="perm-new">
{% for id, name in acl.levels %}
<option value="{{id}}">{{name}}</option>
{% endfor %}
</select></td><td></td>
</tr>
</tbody>
</table>
<div class="form-actions">
<button type="submit" class="btn btn-success">{% trans "Save" %}</button>
</div>
</form>
</div>
</div>
</div>
</div> </div>
{% endblock %} {% endblock %}
...@@ -26,9 +26,11 @@ ...@@ -26,9 +26,11 @@
<div class="col-md-6"> <div class="col-md-6">
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
{% if perms.vm.create_leases %}
<a href="{% url "dashboard.views.lease-create" %}" class="pull-right btn btn-success btn-xs" style="margin-right: 10px;"> <a href="{% url "dashboard.views.lease-create" %}" class="pull-right btn btn-success btn-xs" style="margin-right: 10px;">
<i class="icon-plus"></i> {% trans "new lease" %} <i class="icon-plus"></i> {% trans "new lease" %}
</a> </a>
{% endif %}
<h3 class="no-margin"><i class="icon-time"></i> {% trans "Leases" %}</h3> <h3 class="no-margin"><i class="icon-time"></i> {% trans "Leases" %}</h3>
</div> </div>
<div class="panel-body"> <div class="panel-body">
......
...@@ -47,7 +47,12 @@ ...@@ -47,7 +47,12 @@
</dl> </dl>
<h4>{% trans "Expiration" %} {% if instance.is_expiring %}<i class="icon-warning-sign text-danger"></i>{% endif %} <h4>{% trans "Expiration" %} {% if instance.is_expiring %}<i class="icon-warning-sign text-danger"></i>{% endif %}
<a href="{% url "dashboard.views.vm-renew" instance.pk "" %}" class="btn btn-success btn-xs pull-right">{% trans "renew" %}</a> {% with op=op.renew %}
<a href="{{op.get_url}}" class="btn btn-success btn-xs
operation operation-{{op.op}} btn btn-default">
<i class="icon-{{op.icon}}"></i>
{{op.name}} </a>
{% endwith %}
</h4> </h4>
<dl> <dl>
<dt>{% trans "Suspended at:" %}</dt> <dt>{% trans "Suspended at:" %}</dt>
......
...@@ -16,13 +16,15 @@ ...@@ -16,13 +16,15 @@
# with CIRCLE. If not, see <http://www.gnu.org/licenses/>. # with CIRCLE. If not, see <http://www.gnu.org/licenses/>.
import unittest import unittest
import warnings
from factory import Factory, Sequence from factory import Factory, Sequence
from mock import patch, MagicMock from mock import patch, MagicMock
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from django.core.signing import TimestampSigner, JSONSerializer, b64_encode from django.core.signing import TimestampSigner, JSONSerializer, b64_encode
from django.http import HttpRequest, Http404 from django.http import HttpRequest, Http404, QueryDict
from django.utils import baseconv from django.utils import baseconv
from ..models import Profile from ..models import Profile
...@@ -142,7 +144,7 @@ class VmOperationViewTestCase(unittest.TestCase): ...@@ -142,7 +144,7 @@ class VmOperationViewTestCase(unittest.TestCase):
view.as_view()(request, pk=1234).render() view.as_view()(request, pk=1234).render()
def test_migrate(self): def test_migrate(self):
request = FakeRequestFactory(POST={'node': 1}) request = FakeRequestFactory(POST={'node': 1}, superuser=True)
view = vm_ops['migrate'] view = vm_ops['migrate']
with patch.object(view, 'get_object') as go, \ with patch.object(view, 'get_object') as go, \
...@@ -176,7 +178,24 @@ class VmOperationViewTestCase(unittest.TestCase): ...@@ -176,7 +178,24 @@ class VmOperationViewTestCase(unittest.TestCase):
assert view.as_view()(request, pk=1234)['location'] assert view.as_view()(request, pk=1234)['location']
assert msg.error.called assert msg.error.called
def test_migrate_wo_permission(self):
request = FakeRequestFactory(POST={'node': 1}, superuser=False)
view = vm_ops['migrate']
with patch.object(view, 'get_object') as go, \
patch('dashboard.views.get_object_or_404') as go4:
inst = MagicMock(spec=Instance)
inst._meta.object_name = "Instance"
inst.migrate = Instance._ops['migrate'](inst)
inst.migrate.async = MagicMock()
inst.has_level.return_value = True
go.return_value = inst
go4.return_value = MagicMock()
with self.assertRaises(PermissionDenied):
assert view.as_view()(request, pk=1234)['location']
def test_migrate_template(self): def test_migrate_template(self):
"""check if GET dialog's template can be rendered"""
request = FakeRequestFactory(superuser=True) request = FakeRequestFactory(superuser=True)
view = vm_ops['migrate'] view = vm_ops['migrate']
...@@ -207,7 +226,8 @@ class VmOperationViewTestCase(unittest.TestCase): ...@@ -207,7 +226,8 @@ class VmOperationViewTestCase(unittest.TestCase):
assert not msg.error.called assert not msg.error.called
def test_save_as_w_name(self): def test_save_as_w_name(self):
request = FakeRequestFactory(POST={'name': 'foobar'}) request = FakeRequestFactory(POST={'name': 'foobar'},
has_perms_mock=True)
view = vm_ops['save_as_template'] view = vm_ops['save_as_template']
with patch.object(view, 'get_object') as go, \ with patch.object(view, 'get_object') as go, \
...@@ -238,26 +258,204 @@ class VmOperationViewTestCase(unittest.TestCase): ...@@ -238,26 +258,204 @@ class VmOperationViewTestCase(unittest.TestCase):
self.assertEquals(rend.status_code, 200) self.assertEquals(rend.status_code, 200)
def FakeRequestFactory(*args, **kwargs): class RenewViewTest(unittest.TestCase):
def test_renew_template(self):
request = FakeRequestFactory(has_perms_mock=True)
view = vm_ops['renew']
with patch.object(view, 'get_object') as go:
inst = MagicMock(spec=Instance)
inst._meta.object_name = "Instance"
inst.name = 'foo'
inst.renew = Instance._ops['renew'](inst)
inst.has_level.return_value = True
go.return_value = inst
rend = view.as_view()(request, pk=1234).render()
self.assertEquals(rend.status_code, 200)
def test_renew_by_owner_wo_param(self):
request = FakeRequestFactory(POST={}, has_perms_mock=True)
view = vm_ops['renew']
with patch.object(view, 'get_object') as go, \
patch('dashboard.views.get_object_or_404') as go4:
inst = MagicMock(spec=Instance)
inst._meta.object_name = "Instance"
inst.renew = Instance._ops['renew'](inst)
inst.renew.async = MagicMock()
inst.has_level.return_value = True
go.return_value = inst
go4.return_value = MagicMock()
assert view.as_view()(request, pk=1234).render().status_code == 200
# success would redirect
def test_renew_by_owner_w_param(self):
request = FakeRequestFactory(POST={'length': 1}, has_perms_mock=True)
view = vm_ops['renew']
with patch.object(view, 'get_object') as go, \
patch('dashboard.views.messages') as msg, \
patch('dashboard.views.get_object_or_404') as go4:
inst = MagicMock(spec=Instance)
inst._meta.object_name = "Instance"
inst.renew = Instance._ops['renew'](inst)
inst.renew.async = MagicMock()
inst.has_level.return_value = True
go.return_value = inst
go4.return_value = MagicMock()
assert view.as_view()(request, pk=1234)
assert not msg.error.called
def test_renew_get_by_anon_wo_key(self):
request = FakeRequestFactory(authenticated=False)
view = vm_ops['renew']
with patch.object(view, 'get_object') as go, \
patch('dashboard.views.get_object_or_404') as go4:
inst = MagicMock(spec=Instance)
inst._meta.object_name = "Instance"
inst.renew = Instance._ops['renew'](inst)
inst.renew.async = MagicMock()
inst.has_level.return_value = False
go.return_value = inst
go4.return_value = MagicMock()
self.assertIn('login',
view.as_view()(request, pk=1234)['location'])
def test_renew_get_by_nonowner_wo_key(self):
request = FakeRequestFactory(has_perms_mock=True)
view = vm_ops['renew']
with patch.object(view, 'get_object') as go, \
patch('dashboard.views.get_object_or_404') as go4:
inst = MagicMock(spec=Instance)
inst._meta.object_name = "Instance"
inst.renew = Instance._ops['renew'](inst)
inst.renew.async = MagicMock()
inst.has_level.return_value = False
go.return_value = inst
go4.return_value = MagicMock()
with self.assertRaises(PermissionDenied):
assert view.as_view()(request, pk=1234)
def test_renew_post_by_nonowner_wo_key(self):
request = FakeRequestFactory(POST={'length': 1}, has_perms_mock=True)
view = vm_ops['renew']
with patch.object(view, 'get_object') as go, \
patch('dashboard.views.get_object_or_404') as go4:
inst = MagicMock(spec=Instance, pk=11)
inst._meta.object_name = "Instance"
inst.renew = Instance._ops['renew'](inst)
inst.renew.async = MagicMock()
inst.has_level.return_value = False
go.return_value = inst
go4.return_value = MagicMock()
with self.assertRaises(PermissionDenied):
assert view.as_view()(request, pk=1234)
def test_renew_get_by_nonowner_w_key(self):
user = FakeRequestFactory(superuser=True).user
view = vm_ops['renew']
inst = MagicMock(spec=Instance, pk=11)
inst._meta.object_name = "Instance"
inst.renew = Instance._ops['renew'](inst)
inst.renew.async = MagicMock()
key = view.get_token_url(inst, user).split('?')[1].split('=')[1]
request = FakeRequestFactory(GET={'k': key}) # other user!
with patch.object(view, 'get_object') as go, \
patch('dashboard.views.User.objects') as gu, \
patch('dashboard.views.Lease.get_objects_with_level') as gol:
gol.return_value = views.Lease.objects.all()
gu.get.return_value = user
go.return_value = inst
assert view.as_view()(request, pk=1234).render().status_code == 200
def test_renew_post_by_anon_w_key(self):
user = FakeRequestFactory(authenticated=True).user
view = vm_ops['renew']
inst = MagicMock(spec=Instance, pk=11)
inst._meta.object_name = "Instance"
inst.renew = Instance._ops['renew'](inst)
inst.renew.async = MagicMock()
inst.has_level = lambda user, level: user.is_authenticated()
key = view.get_token_url(inst, user).split('?')[1].split('=')[1]
request = FakeRequestFactory(GET={'k': key}, authenticated=False)
with patch.object(view, 'get_object') as go, \
patch('dashboard.views.Lease.get_objects_with_level') as gol:
go.return_value = inst
gol.return_value = views.Lease.objects.all()
assert view.as_view()(request, pk=1234).render().status_code == 200
def test_renew_post_by_anon_w_invalid_key(self):
view = vm_ops['renew']
key = "invalid"
inst = MagicMock(spec=Instance, pk=11)
inst._meta.object_name = "Instance"
inst.renew = Instance._ops['renew'](inst)
inst.renew.async = MagicMock()
inst.has_level.return_value = False
request = FakeRequestFactory(GET={'k': key}, authenticated=False)
with patch.object(view, 'get_object') as go:
go.return_value = inst
self.assertIn('login',
view.as_view()(request, pk=1234)['location'])
def test_renew_post_by_anon_w_expired_key(self):
def side(max_age=None, *args, **kwargs):
if max_age:
raise views.signing.BadSignature
user = FakeRequestFactory(authenticated=False).user
view = vm_ops['renew']
inst = MagicMock(spec=Instance, pk=11)
inst._meta.object_name = "Instance"
inst.renew = Instance._ops['renew'](inst)
inst.renew.async = MagicMock()
inst.has_level.return_value = False
key = view.get_token_url(inst, user).split('?')[1].split('=')[1]
with patch('dashboard.views.signing.loads') as loader, \
patch.object(view, 'get_object') as go:
loader.return_value = (inst.pk, user.pk)
loader.side_effect = side
request = FakeRequestFactory(GET={'k': key}, user=user)
go.return_value = inst
self.assertIn('login',
view.as_view()(request, pk=1234)['location'])
def FakeRequestFactory(user=None, **kwargs):
''' FakeRequestFactory, FakeMessages and FakeRequestContext are good for ''' FakeRequestFactory, FakeMessages and FakeRequestContext are good for
mocking out django views; they are MUCH faster than the Django test client. mocking out django views; they are MUCH faster than the Django test client.
''' '''
user = UserFactory() if user is None:
user.is_authenticated = lambda: kwargs.get('authenticated', True) user = UserFactory()
user.is_superuser = kwargs.get('superuser', False) user.is_authenticated = lambda: kwargs.pop('authenticated', True)
if kwargs.get('has_perms_mock', False): user.is_superuser = kwargs.pop('superuser', False)
user.has_perms = MagicMock(return_value=True) if kwargs.pop('has_perms_mock', False):
user.has_perms = MagicMock(return_value=True)
user.save()
request = HttpRequest() request = HttpRequest()
request.user = user request.user = user
request.session = kwargs.get('session', {}) request.session = kwargs.pop('session', {})
if kwargs.get('POST') is not None: if kwargs.get('POST') is not None:
request.method = 'POST' request.method = 'POST'
request.POST = kwargs.get('POST') request.POST = QueryDict('', mutable=True)
request.POST.update(kwargs.pop('POST'))
else: else:
request.method = 'GET' request.method = 'GET'
request.GET = kwargs.get('GET', {}) request.GET = QueryDict('', mutable=True)
request.GET.update(kwargs.pop('GET', {}))
if len(kwargs):
warnings.warn("FakeRequestFactory kwargs unused: " + unicode(kwargs))
return request return request
......
...@@ -21,14 +21,12 @@ import json ...@@ -21,14 +21,12 @@ import json
from django.test import TestCase from django.test import TestCase
from django.test.client import Client from django.test.client import Client
from django.contrib.auth.models import User, Group from django.contrib.auth.models import User, Group
from django.core.urlresolvers import reverse
from django.contrib.auth.models import Permission from django.contrib.auth.models import Permission
from django.contrib.auth import authenticate from django.contrib.auth import authenticate
from vm.models import Instance, InstanceTemplate, Lease, Node, Trait from vm.models import Instance, InstanceTemplate, Lease, Node, Trait
from vm.operations import WakeUpOperation from vm.operations import WakeUpOperation
from ..models import Profile from ..models import Profile
from ..views import VmRenewView
from storage.models import Disk from storage.models import Disk
from firewall.models import Vlan, Host, VlanGroup from firewall.models import Vlan, Host, VlanGroup
from mock import Mock, patch from mock import Mock, patch
...@@ -568,10 +566,8 @@ class VmDetailTest(LoginMixin, TestCase): ...@@ -568,10 +566,8 @@ class VmDetailTest(LoginMixin, TestCase):
inst = Instance.objects.get(pk=1) inst = Instance.objects.get(pk=1)
inst.manual_state_change('SUSPENDED') inst.manual_state_change('SUSPENDED')
inst.set_level(self.u2, 'user') inst.set_level(self.u2, 'user')
with patch('dashboard.views.messages') as msg: response = c.post("/dashboard/vm/1/op/wake_up/")
response = c.post("/dashboard/vm/1/op/wake_up/") self.assertEqual(response.status_code, 403)
assert msg.error.called
self.assertEqual(response.status_code, 302)
inst = Instance.objects.get(pk=1) inst = Instance.objects.get(pk=1)
self.assertEqual(inst.status, 'SUSPENDED') self.assertEqual(inst.status, 'SUSPENDED')
...@@ -1631,100 +1627,6 @@ class TransferOwnershipViewTest(LoginMixin, TestCase): ...@@ -1631,100 +1627,6 @@ class TransferOwnershipViewTest(LoginMixin, TestCase):
self.assertEquals(Instance.objects.get(pk=1).owner.pk, self.u2.pk) self.assertEquals(Instance.objects.get(pk=1).owner.pk, self.u2.pk)
class RenewViewTest(LoginMixin, TestCase):
fixtures = ['test-vm-fixture.json']
def setUp(self):
self.u1 = User.objects.create(username='user1')
self.u1.set_password('password')
self.u1.save()
Profile.objects.create(user=self.u1)
self.u2 = User.objects.create(username='user2', is_staff=True)
self.u2.set_password('password')
self.u2.save()
Profile.objects.create(user=self.u2)
self.us = User.objects.create(username='superuser', is_superuser=True)
self.us.set_password('password')
self.us.save()
Profile.objects.create(user=self.us)
inst = Instance.objects.get(pk=1)
inst.owner = self.u1
inst.save()
def test_renew_by_owner(self):
c = Client()
ct = Instance.objects.get(pk=1).activity_log.\
filter(activity_code__endswith='renew').count()
self.login(c, 'user1')
response = c.get('/dashboard/vm/1/renew/')
self.assertEquals(response.status_code, 200)
response = c.post('/dashboard/vm/1/renew/')
self.assertEquals(response.status_code, 302)
ct2 = Instance.objects.get(pk=1).activity_log.\
filter(activity_code__endswith='renew').count()
self.assertEquals(ct + 1, ct2)
def test_renew_get_by_nonowner_wo_key(self):
c = Client()
self.login(c, 'user2')
response = c.get('/dashboard/vm/1/renew/')
self.assertEquals(response.status_code, 403)
def test_renew_post_by_nonowner_wo_key(self):
c = Client()
self.login(c, 'user2')
response = c.post('/dashboard/vm/1/renew/')
self.assertEquals(response.status_code, 403)
def test_renew_get_by_nonowner_w_key(self):
key = VmRenewView.get_token_url(Instance.objects.get(pk=1), self.u2)
c = Client()
response = c.get(key)
self.assertEquals(response.status_code, 200)
def test_renew_post_by_anon_w_key(self):
key = VmRenewView.get_token_url(Instance.objects.get(pk=1), self.u2)
ct = Instance.objects.get(pk=1).activity_log.\
filter(activity_code__endswith='renew').count()
c = Client()
response = c.post(key)
self.assertEquals(response.status_code, 302)
ct2 = Instance.objects.get(pk=1).activity_log.\
filter(activity_code__endswith='renew').count()
self.assertEquals(ct + 1, ct2)
def test_renew_post_by_anon_w_invalid_key(self):
class Mockinst(object):
pk = 2
key = VmRenewView.get_token_url(Mockinst(), self.u2)
ct = Instance.objects.get(pk=1).activity_log.\
filter(activity_code__endswith='renew').count()
c = Client()
self.login(c, 'user2')
response = c.get(key)
self.assertEquals(response.status_code, 404)
response = c.post(key)
self.assertEquals(response.status_code, 404)
ct2 = Instance.objects.get(pk=1).activity_log.\
filter(activity_code__endswith='renew').count()
self.assertEquals(ct, ct2)
def test_renew_post_by_anon_w_expired_key(self):
key = reverse(VmRenewView.url_name, args=(
12, 'WzEyLDFd:1WLbSi:2zIb8SUNAIRIOMTmSmKSSit2gpY'))
ct = Instance.objects.get(pk=12).activity_log.\
filter(activity_code__endswith='renew').count()
c = Client()
self.login(c, 'user2')
response = c.get(key)
self.assertEquals(response.status_code, 302)
response = c.post(key)
self.assertEquals(response.status_code, 403)
ct2 = Instance.objects.get(pk=12).activity_log.\
filter(activity_code__endswith='renew').count()
self.assertEquals(ct, ct2)
class IndexViewTest(LoginMixin, TestCase): class IndexViewTest(LoginMixin, TestCase):
fixtures = ['test-vm-fixture.json', 'node.json'] fixtures = ['test-vm-fixture.json', 'node.json']
......
...@@ -29,7 +29,7 @@ from .views import ( ...@@ -29,7 +29,7 @@ from .views import (
TemplateDelete, TemplateDetail, TemplateList, TransferOwnershipConfirmView, TemplateDelete, TemplateDetail, TemplateList, TransferOwnershipConfirmView,
TransferOwnershipView, vm_activity, VmCreate, VmDelete, VmDetailView, TransferOwnershipView, vm_activity, VmCreate, VmDelete, VmDetailView,
VmDetailVncTokenView, VmGraphView, VmList, VmMassDelete, VmDetailVncTokenView, VmGraphView, VmList, VmMassDelete,
VmRenewView, DiskRemoveView, get_disk_download_status, InterfaceDeleteView, DiskRemoveView, get_disk_download_status, InterfaceDeleteView,
GroupRemoveAclUserView, GroupRemoveAclGroupView, GroupRemoveUserView, GroupRemoveAclUserView, GroupRemoveAclGroupView, GroupRemoveUserView,
GroupRemoveFutureUserView, GroupRemoveFutureUserView,
GroupCreate, GroupProfileUpdate, GroupCreate, GroupProfileUpdate,
...@@ -40,6 +40,7 @@ from .views import ( ...@@ -40,6 +40,7 @@ from .views import (
UserKeyDelete, UserKeyDetail, UserKeyCreate, UserKeyDelete, UserKeyDetail, UserKeyCreate,
VmTraitsUpdate, VmRawDataUpdate, VmTraitsUpdate, VmRawDataUpdate,
GroupPermissionsView, GroupPermissionsView,
LeaseAclUpdateView,
) )
urlpatterns = patterns(