Ticket #3957 (partial) - ganeti_webmgr uses ganeti python namespace:
[ganeti_webmgr.git] / ganeti_web / tests / cluster.py
bloba96c09d2bcf177709ca539718d3742ef0c7b7b69
1 # Copyright (C) 2010 Oregon State University et al.
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software
15 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
16 # USA.
19 from datetime import datetime
21 from django.conf import settings
22 from django.contrib.auth.models import User, Group
23 from django.test import TestCase
24 from django.test.client import Client
25 from django_test_tools.users import UserTestMixin
26 from django_test_tools.views import ViewTestMixin
27 from ganeti_web.models import SSHKey, Profile
29 from object_permissions import *
31 from ganeti_web.tests.rapi_proxy import RapiProxy, INFO, NODES, NODES_BULK, JOB_RUNNING, JOB
32 from ganeti_web import models
33 Cluster = models.Cluster
34 VirtualMachine = models.VirtualMachine
35 Node = models.Node
36 Quota = models.Quota
37 Job = models.Job
40 __all__ = ('TestClusterViews', 'TestClusterModel')
43 global user, user1, group, cluster_admin, superuser
44 global cluster, c
47 class TestClusterModel(TestCase):
49 def setUp(self):
50 self.tearDown()
51 models.client.GanetiRapiClient = RapiProxy
53 def tearDown(self):
54 Profile.objects.all().delete()
55 User.objects.all().delete()
56 Quota.objects.all().delete()
57 VirtualMachine.objects.all().delete()
58 Node.objects.all().delete()
59 Cluster.objects.all().delete()
61 def test_trivial(self):
62 """
63 Test creating a Cluster Object
64 """
65 Cluster()
67 def test_save(self):
68 """
69 test saving a cluster object
71 Verifies:
72 * object is saved and queryable
73 * hash is updated
74 """
75 cluster = Cluster()
76 cluster.save()
77 self.assert_(cluster.hash)
79 cluster = Cluster(hostname='foo.fake.hostname', slug='different')
80 cluster.save()
81 self.assert_(cluster.hash)
83 def test_parse_info(self):
84 """
85 Test parsing values from cached info
87 Verifies:
88 * mtime and ctime are parsed
89 * ram, virtual_cpus, and disksize are parsed
90 """
91 cluster = Cluster(hostname='foo.fake.hostname')
92 cluster.save()
93 cluster.info = INFO
95 self.assertEqual(cluster.ctime, datetime.fromtimestamp(1270685309.818239))
96 self.assertEqual(cluster.mtime, datetime.fromtimestamp(1283552454.2998919))
98 def test_get_quota(self):
99 """
100 Tests cluster.get_quota() method
102 Verifies:
103 * if no user is passed, return default quota values
104 * if user has quota, return values from Quota
105 * if user doesn't have quota, return default cluster values
107 default_quota = {'default':1, 'ram':1, 'virtual_cpus':None, 'disk':3}
108 user_quota = {'default':0, 'ram':4, 'virtual_cpus':5, 'disk':None}
110 cluster = Cluster(hostname='foo.fake.hostname')
111 cluster.__dict__.update(default_quota)
112 cluster.save()
113 user = User(username='tester')
114 user.save()
116 # default quota
117 self.assertEqual(default_quota, cluster.get_quota())
119 # user without quota, defaults to default
120 self.assertEqual(default_quota, cluster.get_quota(user.get_profile()))
122 # user with custom quota
123 quota = Quota(cluster=cluster, user=user.get_profile())
124 quota.__dict__.update(user_quota)
125 quota.save()
126 self.assertEqual(user_quota, cluster.get_quota(user.get_profile()))
128 def test_set_quota(self):
130 Tests cluster.set_quota()
132 Verifies:
133 * passing values with no quota, creates a new quota object
134 * passing values with an existing quota, updates it.
135 * passing a None with an existing quota deletes it
136 * passing a None with no quota, does nothing
138 default_quota = {'default':1,'ram':1, 'virtual_cpus':None, 'disk':3}
139 user_quota = {'default':0, 'ram':4, 'virtual_cpus':5, 'disk':None}
140 user_quota2 = {'default':0, 'ram':7, 'virtual_cpus':8, 'disk':9}
142 cluster = Cluster(hostname='foo.fake.hostname')
143 cluster.__dict__.update(default_quota)
144 cluster.save()
145 user = User(username='tester')
146 user.save()
148 # create new quota
149 cluster.set_quota(user.get_profile(), user_quota)
150 query = Quota.objects.filter(cluster=cluster, user=user.get_profile())
151 self.assert_(query.exists())
152 self.assertEqual(user_quota, cluster.get_quota(user.get_profile()))
154 # update quota with new values
155 cluster.set_quota(user.get_profile(), user_quota2)
156 query = Quota.objects.filter(cluster=cluster, user=user.get_profile())
157 self.assertEqual(1, query.count())
158 self.assertEqual(user_quota2, cluster.get_quota(user.get_profile()))
160 # delete quota
161 cluster.set_quota(user.get_profile(), None)
162 query = Quota.objects.filter(cluster=cluster, user=user.get_profile())
163 self.assertFalse(query.exists())
164 self.assertEqual(default_quota, cluster.get_quota(user.get_profile()))
166 def test_sync_virtual_machines(self):
168 Tests synchronizing cached virtuals machines (stored in db) with info
169 the ganeti cluster is storing
171 Verifies:
172 * VMs no longer in ganeti are deleted
173 * VMs missing from the database are added
175 cluster = Cluster(hostname='ganeti.osuosl.test')
176 cluster.save()
177 vm_missing = 'gimager.osuosl.bak'
178 vm_current = VirtualMachine(cluster=cluster, hostname='gimager2.osuosl.bak')
179 vm_removed = VirtualMachine(cluster=cluster, hostname='does.not.exist.org')
180 vm_current.save()
181 vm_removed.save()
183 cluster.sync_virtual_machines()
184 self.assert_(VirtualMachine.objects.get(cluster=cluster, hostname=vm_missing), 'missing vm was not created')
185 self.assert_(VirtualMachine.objects.get(cluster=cluster, hostname=vm_current.hostname), 'previously existing vm was not created')
186 self.assert_(VirtualMachine.objects.filter(cluster=cluster, hostname=vm_removed.hostname), 'vm not present in ganeti was not removed from db, even though remove flag was false')
188 cluster.sync_virtual_machines(True)
189 self.assertFalse(VirtualMachine.objects.filter(cluster=cluster, hostname=vm_removed.hostname), 'vm not present in ganeti was not removed from db')
191 def test_sync_nodes(self):
193 Tests synchronizing cached Nodes (stored in db) with info
194 the ganeti cluster is storing
196 Verifies:
197 * Node no longer in ganeti are deleted
198 * Nodes missing from the database are added
200 cluster = Cluster.objects.create(hostname='ganeti.osuosl.test')
201 node_missing = 'gtest1.osuosl.bak'
202 node_current = Node.objects.create(cluster=cluster, hostname='gtest2.osuosl.bak')
203 node_removed = Node.objects.create(cluster=cluster, hostname='does.not.exist.org')
205 cluster.sync_nodes()
206 self.assert_(Node.objects.get(cluster=cluster, hostname=node_missing), 'missing node was not created')
207 self.assert_(Node.objects.get(cluster=cluster, hostname=node_current.hostname), 'previously existing node was not created')
208 self.assert_(Node.objects.filter(cluster=cluster, hostname=node_removed.hostname), 'node not present in ganeti was not removed from db, even though remove flag was false')
210 cluster.sync_nodes(True)
211 self.assertFalse(Node.objects.filter(cluster=cluster, hostname=node_removed.hostname), 'node not present in ganeti was not removed from db')
214 def test_missing_in_database(self):
216 Tests missing_in_ganeti property
218 cluster = Cluster(hostname='ganeti.osuosl.test')
219 cluster.save()
220 vm_current = VirtualMachine(cluster=cluster, hostname='gimager2.osuosl.bak')
221 vm_removed = VirtualMachine(cluster=cluster, hostname='does.not.exist.org')
222 vm_current.save()
223 vm_removed.save()
225 self.assertEqual([u'gimager.osuosl.bak'], cluster.missing_in_db)
227 def test_missing_in_ganeti(self):
229 Tests missing_in_ganeti property
231 cluster = Cluster(hostname='ganeti.osuosl.test')
232 cluster.save()
233 vm_current = VirtualMachine(cluster=cluster, hostname='gimager2.osuosl.bak')
234 vm_removed = VirtualMachine(cluster=cluster, hostname='does.not.exist.org')
235 vm_current.save()
236 vm_removed.save()
238 self.assertEqual([u'does.not.exist.org'], cluster.missing_in_ganeti)
240 def test_available_ram(self):
242 Tests that the available_ram property returns the correct values
244 c = Cluster.objects.create(hostname='ganeti.osuosl.test')
245 c2 = Cluster.objects.create(hostname='ganeti2.osuosl.test', slug='argh')
246 node = Node.objects.create(cluster=c, hostname='node.osuosl.test')
247 node1 = Node.objects.create(cluster=c2, hostname='node1.osuosl.test')
249 VirtualMachine.objects.create(cluster=c, primary_node=node, hostname='foo', ram=123, status='running')
250 VirtualMachine.objects.create(cluster=c, primary_node=node, hostname='bar', ram=456, status='running')
251 VirtualMachine.objects.create(cluster=c, primary_node=node, hostname='xoo', ram=789, status='admin_down')
252 VirtualMachine.objects.create(cluster=c, primary_node=node, hostname='xar', ram=234, status='stopped')
253 VirtualMachine.objects.create(cluster=c, primary_node=node, hostname='boo', status='running')
254 VirtualMachine.objects.create(cluster=c2, primary_node=node1, hostname='gar', ram=888, status='running')
255 VirtualMachine.objects.create(cluster=c2, primary_node=node1, hostname='yoo', ram=999, status='admin_down')
257 # test with no nodes, should result in zeros since nodes info isn't cached yet
258 ram = c.available_ram
259 self.assertEqual(0, ram['free'])
260 self.assertEqual(0, ram['total'])
262 # force refresh of nodes and rerun test for real values
263 node.refresh()
264 node1.refresh()
265 ram = c.available_ram
266 self.assertEqual(9999, ram['total'])
267 self.assertEqual(9420, ram['free'])
270 def test_available_disk(self):
272 Tests that the available_disk property returns the correct values
274 c = Cluster.objects.create(hostname='ganeti.osuosl.test')
275 c2 = Cluster.objects.create(hostname='ganeti2.osuosl.test', slug='argh')
276 node = Node.objects.create(cluster=c, hostname='node.osuosl.test')
277 node1 = Node.objects.create(cluster=c2, hostname='node1.osuosl.test')
279 VirtualMachine.objects.create(cluster=c, primary_node=node, hostname='foo', disk_size=123, status='running')
280 VirtualMachine.objects.create(cluster=c, primary_node=node,hostname='bar', disk_size=456, status='running')
281 VirtualMachine.objects.create(cluster=c, primary_node=node, hostname='xoo', disk_size=789, status='admin_down')
282 VirtualMachine.objects.create(cluster=c, primary_node=node, hostname='xar', disk_size=234, status='stopped')
283 VirtualMachine.objects.create(cluster=c, primary_node=node, hostname='boo', status='running')
284 VirtualMachine.objects.create(cluster=c2, primary_node=node1, hostname='gar', disk_size=888, status='running')
285 VirtualMachine.objects.create(cluster=c2, primary_node=node1, hostname='yoo', disk_size=999, status='admin_down')
287 # test with no nodes, should result in zeros since nodes info isn't cached yet
288 disk = c.available_disk
289 self.assertEqual(0, disk['free'])
290 self.assertEqual(0, disk['total'])
292 # force refresh of nodes and rerun test for real values
293 node.refresh()
294 node1.refresh()
295 disk = c.available_disk
296 self.assertEqual(6666, disk['total'])
297 self.assertEqual(5064, disk['free'])
299 def test_redistribute_config(self):
301 Test Cluster.redistribute_config()
303 Verifies:
304 * job is created
305 * cache is disabled while job is running
306 * cache is reenabled when job is finished
308 cluster = Cluster.objects.create(hostname='ganeti.osuosl.test')
309 cluster.rapi.GetJobStatus.response = JOB_RUNNING
311 # redistribute_config enables ignore_cache flag
312 job_id = cluster.redistribute_config().id
313 self.assert_(Job.objects.filter(id=job_id).exists())
314 cluster = Cluster.objects.get(id=cluster.id)
315 self.assert_(cluster.ignore_cache)
316 self.assert_(cluster.last_job_id)
317 self.assert_(Job.objects.filter(id=job_id).values()[0]['ignore_cache'])
319 # finished job resets ignore_cache flag
320 cluster.rapi.GetJobStatus.response = JOB
321 cluster = Cluster.objects.get(id=cluster.id)
322 self.assertFalse(cluster.ignore_cache)
323 self.assertFalse(cluster.last_job_id)
324 self.assertFalse(Job.objects.filter(id=job_id).values()[0]['ignore_cache'])
325 self.assert_(Job.objects.get(id=job_id).finished)
328 class TestClusterViews(TestCase, ViewTestMixin, UserTestMixin):
330 def setUp(self):
331 self.tearDown()
332 models.client.GanetiRapiClient = RapiProxy
334 User(id=1, username='anonymous').save()
335 settings.ANONYMOUS_USER_ID=1
337 user = User(id=2, username='tester0')
338 user.set_password('secret')
339 user.save()
340 user1 = User(id=3, username='tester1')
341 user1.set_password('secret')
342 user1.save()
344 group = Group(name='testing_group')
345 group.save()
347 cluster = Cluster(hostname='test.osuosl.test', slug='OSL_TEST')
348 cluster.save()
350 self.create_standard_users(globals())
351 self.create_users(['cluster_admin'], globals())
352 cluster_admin.grant('admin', cluster)
354 dict_ = globals()
355 dict_['user'] = user
356 dict_['user1'] = user1
357 dict_['group'] = group
358 dict_['cluster'] = cluster
359 dict_['c'] = Client()
361 def tearDown(self):
362 VirtualMachine.objects.all().delete()
363 Quota.objects.all().delete()
364 Cluster.objects.all().delete()
365 Group.objects.all().delete()
366 User.objects.all().delete()
368 def validate_get(self, url, args, template):
369 # anonymous user
370 response = c.get(url % args, follow=True)
371 self.assertEqual(200, response.status_code)
372 self.assertTemplateUsed(response, 'registration/login.html')
374 # unauthorized user
375 self.assert_(c.login(username=user.username, password='secret'))
376 response = c.get(url % args)
377 self.assertEqual(403, response.status_code)
379 # nonexisent cluster
380 response = c.get(url % "DOES_NOT_EXIST")
381 self.assertEqual(404, response.status_code)
383 # authorized user (perm)
384 grant(user, 'admin', cluster)
385 response = c.get(url % args)
386 self.assertEqual(200, response.status_code)
387 self.assertEquals('text/html; charset=utf-8', response['content-type'])
388 self.assertTemplateUsed(response, template)
390 # authorized user (superuser)
391 user.revoke('admin', cluster)
392 user.is_superuser = True
393 user.save()
394 response = c.get(url % args)
395 self.assertEqual(200, response.status_code)
396 self.assertEquals('text/html; charset=utf-8', response['content-type'])
397 self.assertTemplateUsed(response, template)
399 def validate_get_configurable(self, url, args, template=False,
400 mimetype=False, status=False, perms=[]):
402 More configurable version of validate_get.
403 Additional arguments (only if set) affects only authorized user test.
405 @template: used template
406 @mimetype: returned mimetype
407 @status: returned Http status code
408 @perms: set of perms granted on authorized user
410 @return response content
412 # anonymous user
413 response = c.get(url % args, follow=True)
414 self.assertEqual(200, response.status_code)
415 self.assertTemplateUsed(response, 'registration/login.html')
417 # unauthorized user
418 self.assert_(c.login(username=user.username, password='secret'))
419 response = c.get(url % args)
420 self.assertEqual(403, response.status_code)
422 # nonexisent cluster
423 if args:
424 response = c.get(url % "DOES_NOT_EXIST")
425 self.assertEqual(404, response.status_code)
427 result = []
429 # authorized user (perm)
430 if perms:
431 for perm in perms:
432 grant(user, perm, cluster)
433 response = c.get(url % args)
434 if status:
435 self.assertEqual(status, response.status_code)
436 if mimetype:
437 self.assertEqual(mimetype, response['content-type'])
438 if template:
439 self.assertTemplateUsed(response, template)
441 result.append(response)
443 # authorized user (superuser)
444 user.revoke_all(cluster)
445 user.is_superuser = True
446 user.save()
447 response = c.get(url % args)
448 if status:
449 self.assertEqual(200, response.status_code)
450 if mimetype:
451 self.assertEqual(mimetype, response['content-type'])
452 if template:
453 self.assertTemplateUsed(response, template)
455 result.append(response)
457 return result
459 def test_view_list(self):
461 Tests displaying the list of clusters
463 url = '/clusters/'
465 # create extra user and tests
466 user2 = User(id=4, username='tester2', is_superuser=True)
467 user2.set_password('secret')
468 user2.save()
469 cluster1 = Cluster(hostname='cluster1', slug='cluster1')
470 cluster2 = Cluster(hostname='cluster2', slug='cluster2')
471 cluster3 = Cluster(hostname='cluster3', slug='cluster3')
472 cluster1.save()
473 cluster2.save()
474 cluster3.save()
476 # grant some perms
477 user1.grant('admin', cluster)
478 user1.grant('create_vm', cluster1)
480 # anonymous user
481 response = c.get(url, follow=True)
482 self.assertEqual(200, response.status_code)
483 self.assertTemplateUsed(response, 'registration/login.html')
485 # unauthorized user
486 self.assert_(c.login(username=user.username, password='secret'))
487 response = c.get(url)
488 self.assertEqual(200, response.status_code)
489 self.assertEquals('text/html; charset=utf-8', response['content-type'])
490 self.assertTemplateUsed(response, 'cluster/list.html')
491 clusters = response.context['cluster_list']
492 self.assertFalse(clusters)
494 # authorized permissions
495 self.assert_(c.login(username=user1.username, password='secret'))
496 response = c.get(url)
497 self.assertEqual(200, response.status_code)
498 self.assertEquals('text/html; charset=utf-8', response['content-type'])
499 self.assertTemplateUsed(response, 'cluster/list.html')
500 clusters = response.context['cluster_list']
501 self.assert_(cluster in clusters)
502 self.assert_(cluster1 not in clusters)
503 self.assertEqual(1, len(clusters))
505 # authorized (superuser)
506 self.assert_(c.login(username=user2.username, password='secret'))
507 response = c.get(url)
508 self.assertEqual(200, response.status_code)
509 self.assertEquals('text/html; charset=utf-8', response['content-type'])
510 self.assertTemplateUsed(response, 'cluster/list.html')
511 clusters = response.context['cluster_list']
512 self.assert_(cluster in clusters)
513 self.assert_(cluster1 in clusters)
514 self.assert_(cluster2 in clusters)
515 self.assert_(cluster3 in clusters)
516 self.assertEqual(4, len(clusters))
518 def test_view_add(self):
520 Tests adding a new cluster
522 url = '/cluster/add/'
524 # anonymous user
525 response = c.get(url, follow=True)
526 self.assertEqual(200, response.status_code)
527 self.assertTemplateUsed(response, 'registration/login.html')
529 # unauthorized user
530 self.assert_(c.login(username=user.username, password='secret'))
531 response = c.get(url)
532 self.assertEqual(403, response.status_code)
534 # authorized (GET)
535 user.is_superuser = True
536 user.save()
537 response = c.get(url)
538 self.assertEqual(200, response.status_code)
539 self.assertEquals('text/html; charset=utf-8', response['content-type'])
540 self.assertTemplateUsed(response, 'cluster/edit.html')
542 data = dict(hostname='new-host3.hostname',
543 slug='new-host3',
544 port=5080,
545 description='testing editing clusters',
546 username='tester',
547 password = 'secret',
548 virtual_cpus=1,
549 disk=2,
550 ram=3
553 # test required fields
554 required = ['hostname', 'port']
555 for property in required:
556 data_ = data.copy()
557 del data_[property]
558 response = c.post(url, data_)
559 self.assertEqual(200, response.status_code)
560 self.assertEquals('text/html; charset=utf-8', response['content-type'])
561 self.assertTemplateUsed(response, 'cluster/edit.html')
563 # test not-requireds
564 non_required = ['slug','description','virtual_cpus','disk','ram']
565 for property in non_required:
566 data_ = data.copy()
567 del data_[property]
568 response = c.post(url, data_, follow=True)
569 self.assertEqual(200, response.status_code)
570 self.assertEquals('text/html; charset=utf-8', response['content-type'])
571 self.assertTemplateUsed(response, 'cluster/detail.html')
572 cluster = response.context['cluster']
573 for k, v in data_.items():
574 self.assertEqual(v, getattr(cluster, k))
575 Cluster.objects.all().delete()
578 # success
579 response = c.post(url, data, follow=True)
580 self.assertEqual(200, response.status_code)
581 self.assertEquals('text/html; charset=utf-8', response['content-type'])
582 self.assertTemplateUsed(response, 'cluster/detail.html')
583 cluster = response.context['cluster']
584 for k, v in data_.items():
585 self.assertEqual(v, getattr(cluster, k))
586 Cluster.objects.all().delete()
588 # success without username or password
589 data_ = data.copy()
590 del data_['username']
591 del data_['password']
592 response = c.post(url, data_, follow=True)
593 self.assertEqual(200, response.status_code)
594 self.assertEquals('text/html; charset=utf-8', response['content-type'])
595 self.assertTemplateUsed(response, 'cluster/detail.html')
596 cluster = response.context['cluster']
597 for k, v in data_.items():
598 self.assertEqual(v, getattr(cluster, k))
599 Cluster.objects.all().delete()
601 #test username/password/confirm_password relationships
602 relation = ['username', 'password']
603 for property in relation:
604 data_ = data.copy()
605 del data_[property]
606 response = c.post(url, data_, follow=True)
607 self.assertEqual(200, response.status_code)
608 self.assertEquals('text/html; charset=utf-8', response['content-type'])
609 self.assertTemplateUsed(response, 'cluster/edit.html')
611 # test unique fields
612 response = c.post(url, data)
613 for property in ['hostname','slug']:
614 data_ = data.copy()
615 data_[property] = 'different'
616 response = c.post(url, data_)
617 self.assertEqual(200, response.status_code)
618 self.assertEquals('text/html; charset=utf-8', response['content-type'])
619 self.assertTemplateUsed(response, 'cluster/edit.html')
621 def test_view_edit(self):
623 Tests editing a cluster
625 cluster = globals()['cluster']
626 url = '/cluster/%s/edit/' % cluster.slug
628 # anonymous user
629 response = c.get(url, follow=True)
630 self.assertEqual(200, response.status_code)
631 self.assertTemplateUsed(response, 'registration/login.html')
633 # unauthorized user
634 self.assert_(c.login(username=user.username, password='secret'))
635 response = c.get(url)
636 self.assertEqual(403, response.status_code)
638 # authorized (permission)
639 user.grant('admin', cluster)
640 response = c.get(url)
641 self.assertEqual(200, response.status_code)
642 self.assertEquals('text/html; charset=utf-8', response['content-type'])
643 self.assertTemplateUsed(response, 'cluster/edit.html')
644 self.assertEqual(cluster, response.context['cluster'])
645 user.revoke('admin', cluster)
647 # authorized (GET)
648 user.is_superuser = True
649 user.save()
650 response = c.get(url)
651 self.assertEqual(200, response.status_code)
652 self.assertEquals('text/html; charset=utf-8', response['content-type'])
653 self.assertTemplateUsed(response, 'cluster/edit.html')
654 self.assertEqual(None, cluster.info)
656 data = dict(hostname='new-host-1.hostname',
657 slug='new-host-1',
658 port=5080,
659 description='testing editing clusters',
660 username='tester',
661 password = 'secret',
662 confirm_password = 'secret',
663 virtual_cpus=1,
664 disk=2,
665 ram=3
668 # success
669 data_ = data.copy()
670 response = c.post(url, data, follow=True)
671 self.assertEqual(200, response.status_code)
672 self.assertEquals('text/html; charset=utf-8', response['content-type'])
673 self.assertTemplateUsed(response, 'cluster/detail.html')
674 cluster = response.context['cluster']
675 self.assertNotEqual(None, cluster.info)
676 del data_['confirm_password']
677 for k, v in data_.items():
678 self.assertEqual(v, getattr(cluster, k))
680 def test_view_delete_anonymous(self):
682 Random people shouldn't be able to delete clusters.
685 cluster = Cluster(hostname='test.cluster.bak', slug='cluster1')
686 cluster.save()
687 url = '/cluster/%s/edit/' % cluster.slug
689 response = c.delete(url, follow=True)
690 self.assertEqual(200, response.status_code)
691 self.assertTemplateUsed(response, 'registration/login.html')
693 def test_view_delete_unauthorized(self):
695 Unauthorized people shouldn't be able to delete clusters.
698 cluster = Cluster(hostname='test.cluster.bak', slug='cluster1')
699 cluster.save()
700 url = '/cluster/%s/edit/' % cluster.slug
702 self.assert_(c.login(username=user.username, password='secret'))
703 response = c.delete(url)
704 self.assertEqual(403, response.status_code)
706 def test_view_delete_authorized(self):
708 Users with admin on the cluster should be able to delete the cluster.
711 cluster = Cluster(hostname='test.cluster.bak', slug='cluster1')
712 cluster.save()
713 url = '/cluster/%s/edit/' % cluster.slug
715 user.grant('admin', cluster)
716 self.assert_(c.login(username=user.username, password='secret'))
717 response = c.delete(url, follow=True)
718 self.assertEqual(200, response.status_code)
719 self.assertEquals('application/json', response['content-type'])
720 self.assertEquals('1', response.content)
721 self.assertFalse(Cluster.objects.all().filter(id=cluster.id).exists())
723 def test_view_delete_superuser(self):
725 Superusers can delete clusters.
728 cluster = Cluster(hostname='test.cluster.bak', slug='cluster1')
729 cluster.save()
730 url = '/cluster/%s/edit/' % cluster.slug
732 user.is_superuser = True
733 user.save()
734 self.assert_(c.login(username=user.username, password='secret'))
735 response = c.delete(url, follow=True)
736 self.assertEqual(200, response.status_code)
737 self.assertEquals('application/json', response['content-type'])
738 self.assertEquals('1', response.content)
739 self.assertFalse(Cluster.objects.all().filter(id=cluster.id).exists())
741 def test_view_detail(self):
743 Tests displaying detailed view for a Cluster
745 url = '/cluster/%s/'
746 args = cluster.slug
748 # anonymous user
749 response = c.get(url % args, follow=True)
750 self.assertEqual(200, response.status_code)
751 self.assertTemplateUsed(response, 'registration/login.html')
753 # unauthorized user
754 self.assert_(c.login(username=user.username, password='secret'))
755 response = c.get(url % args)
756 self.assertEqual(403, response.status_code)
758 # invalid cluster
759 response = c.get(url % "DoesNotExist")
760 self.assertEqual(404, response.status_code)
762 # authorized (permission)
763 grant(user, 'admin', cluster)
764 response = c.get(url % args)
765 self.assertEqual(200, response.status_code)
766 self.assertEquals('text/html; charset=utf-8', response['content-type'])
767 self.assertTemplateUsed(response, 'cluster/detail.html')
769 # authorized (superuser)
770 user.revoke('admin', cluster)
771 user.is_superuser = True
772 user.save()
773 response = c.get(url % args)
774 self.assertEqual(200, response.status_code)
775 self.assertEquals('text/html; charset=utf-8', response['content-type'])
776 self.assertTemplateUsed(response, 'cluster/detail.html')
778 def test_view_users(self):
780 Tests view for cluster users:
782 Verifies:
783 * lack of permissions returns 403
784 * nonexistent cluster returns 404
786 url = "/cluster/%s/users/"
787 args = cluster.slug
788 self.validate_get(url, args, 'cluster/users.html')
790 def test_view_virtual_machines(self):
792 Tests view for cluster users:
794 Verifies:
795 * lack of permissions returns 403
796 * nonexistent cluster returns 404
798 url = "/cluster/%s/virtual_machines/"
799 args = cluster.slug
800 self.validate_get(url, args, 'virtual_machine/table.html')
802 def test_view_nodes(self):
804 Tests view for cluster users:
806 Verifies:
807 * lack of permissions returns 403
808 * nonexistent cluster returns 404
810 url = "/cluster/%s/nodes/"
811 args = cluster.slug
812 cluster.rapi.GetNodes.response = NODES_BULK
813 self.validate_get(url, args, 'node/table.html')
814 cluster.rapi.GetNodes.response = NODES
816 def test_view_add_permissions(self):
818 Test adding permissions to a new User or Group
820 url = '/cluster/%s/permissions/'
821 args = cluster.slug
823 # anonymous user
824 response = c.get(url % args, follow=True)
825 self.assertEqual(200, response.status_code)
826 self.assertTemplateUsed(response, 'registration/login.html')
828 # unauthorized user
829 self.assert_(c.login(username=user.username, password='secret'))
830 response = c.get(url % args)
831 self.assertEqual(403, response.status_code)
833 # nonexisent cluster
834 response = c.get(url % "DOES_NOT_EXIST")
835 self.assertEqual(404, response.status_code)
837 # valid GET authorized user (perm)
838 grant(user, 'admin', cluster)
839 response = c.get(url % args)
840 self.assertEqual(200, response.status_code)
841 self.assertEquals('text/html; charset=utf-8', response['content-type'])
842 self.assertTemplateUsed(response, 'object_permissions/permissions/form.html')
844 # valid GET authorized user (superuser)
845 user.revoke('admin', cluster)
846 user.is_superuser = True
847 user.save()
848 response = c.get(url % args)
849 self.assertEqual(200, response.status_code)
850 self.assertTemplateUsed(response, 'object_permissions/permissions/form.html')
852 # no user or group
853 data = {'permissions':['admin'], 'obj':cluster.pk}
854 response = c.post(url % args, data)
855 self.assertEqual(200, response.status_code)
856 self.assertEquals('application/json', response['content-type'])
857 self.assertNotEqual('0', response.content)
859 # both user and group
860 data = {'permissions':['admin'], 'group':group.id, 'user':user1.id, 'cluster':cluster.pk}
861 response = c.post(url % args, data)
862 self.assertEqual(200, response.status_code)
863 self.assertEquals('application/json', response['content-type'])
864 self.assertNotEqual('0', response.content)
866 # no permissions specified - user
867 data = {'permissions':[], 'user':user1.id, 'obj':cluster.pk}
868 response = c.post(url % args, data)
869 self.assertEqual(200, response.status_code)
870 self.assertEquals('application/json', response['content-type'])
871 self.assertNotEqual('0', response.content)
873 # no permissions specified - group
874 data = {'permissions':[], 'group':group.id, 'obj':cluster.pk}
875 response = c.post(url % args, data)
876 self.assertEqual(200, response.status_code)
877 self.assertEquals('application/json', response['content-type'])
879 # valid POST user has permissions
880 user1.grant('create_vm', cluster)
881 data = {'permissions':['admin'], 'user':user1.id, 'obj':cluster.pk}
882 response = c.post(url % args, data)
883 self.assertEquals('text/html; charset=utf-8', response['content-type'])
884 self.assertTemplateUsed(response, 'cluster/user_row.html')
885 self.assert_(user1.has_perm('admin', cluster))
886 self.assertFalse(user1.has_perm('create_vm', cluster))
888 # valid POST group has permissions
889 group.grant('create_vm', cluster)
890 data = {'permissions':['admin'], 'group':group.id, 'obj':cluster.pk}
891 response = c.post(url % args, data)
892 self.assertEquals('text/html; charset=utf-8', response['content-type'])
893 self.assertTemplateUsed(response, 'cluster/group_row.html')
894 self.assertEqual(['admin'], group.get_perms(cluster))
896 def test_view_object_log(self):
898 Tests view for cluster object log:
900 Verifies:
901 * view can be loaded
902 * cluster specific log actions can be rendered properly
904 url = "/cluster/%s/object_log/"
905 args = (cluster.slug,)
906 self.assert_standard_fails(url, args)
907 self.assert_200(url, args, users=[superuser, cluster_admin])
909 def test_view_user_permissions(self):
911 Tests updating users permissions
913 Verifies:
914 * anonymous user returns 403
915 * lack of permissions returns 403
916 * nonexistent cluster returns 404
917 * invalid user returns 404
918 * invalid group returns 404
919 * missing user and group returns error as json
920 * GET returns html for form
921 * If user/group has permissions no html is returned
922 * If user/group has no permissions a json response of -1 is returned
924 args = (cluster.slug, user1.id)
925 args_post = cluster.slug
926 url = "/cluster/%s/permissions/user/%s"
927 url_post = "/cluster/%s/permissions/"
929 # anonymous user
930 response = c.get(url % args, follow=True)
931 self.assertEqual(200, response.status_code)
932 self.assertTemplateUsed(response, 'registration/login.html')
934 # unauthorized user
935 self.assert_(c.login(username=user.username, password='secret'))
936 response = c.get(url % args)
937 self.assertEqual(403, response.status_code)
939 # nonexisent cluster
940 response = c.get(url % ("DOES_NOT_EXIST", user1.id))
941 self.assertEqual(404, response.status_code)
943 # valid GET authorized user (perm)
944 grant(user, 'admin', cluster)
945 response = c.get(url % args)
946 self.assertEqual(200, response.status_code)
947 self.assertEquals('text/html; charset=utf-8', response['content-type'])
948 self.assertTemplateUsed(response, 'object_permissions/permissions/form.html')
950 # valid GET authorized user (superuser)
951 user.revoke('admin', cluster)
952 user.is_superuser = True
953 user.save()
954 response = c.get(url % args)
955 self.assertEqual(200, response.status_code)
956 self.assertTemplateUsed(response, 'object_permissions/permissions/form.html')
958 # invalid user
959 response = c.get(url % (cluster.slug, -1))
960 self.assertEqual(404, response.status_code)
962 # invalid user (POST)
963 user1.grant('create_vm', cluster)
964 data = {'permissions':['admin'], 'user':-1, 'obj':cluster.pk}
965 response = c.post(url_post % args_post, data)
966 self.assertEquals('application/json', response['content-type'])
967 self.assertNotEqual('0', response.content)
969 # no user (POST)
970 user1.grant('create_vm', cluster)
971 data = {'permissions':['admin'], 'obj':cluster.pk}
972 response = c.post(url_post % args_post, data)
973 self.assertEquals('application/json', response['content-type'])
974 self.assertNotEqual('0', response.content)
976 # valid POST user has permissions
977 user1.grant('create_vm', cluster)
978 data = {'permissions':['admin'], 'user':user1.id, 'obj':cluster.pk}
979 response = c.post(url_post % args_post, data)
980 self.assertEquals('text/html; charset=utf-8', response['content-type'])
981 self.assertTemplateUsed(response, 'cluster/user_row.html')
982 self.assert_(user1.has_perm('admin', cluster))
983 self.assertFalse(user1.has_perm('create_vm', cluster))
985 # add quota to the user
986 user_quota = {'default':0, 'ram':51, 'virtual_cpus':10, 'disk':3000}
987 quota = Quota(cluster=cluster, user=user1.get_profile())
988 quota.__dict__.update(user_quota)
989 quota.save()
990 self.assertEqual(user_quota, cluster.get_quota(user1.get_profile()))
992 # valid POST user has no permissions left
993 data = {'permissions':[], 'user':user1.id, 'obj':cluster.pk}
994 response = c.post(url_post % args_post, data)
995 self.assertEqual(200, response.status_code)
996 self.assertEquals('application/json', response['content-type'])
997 self.assertEqual([], get_user_perms(user, cluster))
998 self.assertEqual('"user_3"', response.content)
1000 # quota should be deleted (and showing default)
1001 self.assertEqual(1, cluster.get_quota(user1.get_profile())['default'])
1002 self.assertFalse(user1.get_profile().quotas.all().exists())
1004 # no permissions specified - user with no quota
1005 user1.grant('create_vm', cluster)
1006 cluster.set_quota(user1.get_profile(), None)
1007 data = {'permissions':[], 'user':user1.id, 'obj':cluster.pk}
1008 response = c.post(url % args, data)
1009 self.assertEqual(200, response.status_code)
1010 self.assertEquals('application/json', response['content-type'])
1011 self.assertNotEqual('0', response.content)
1013 # quota should be deleted (and showing default)
1014 self.assertEqual(1, cluster.get_quota(user1.get_profile())['default'])
1015 self.assertFalse(user1.get_profile().quotas.all().exists())
1017 def test_view_group_permissions(self):
1019 Test editing Group permissions on a Cluster
1021 args = (cluster.slug, group.id)
1022 args_post = cluster.slug
1023 url = "/cluster/%s/permissions/group/%s"
1024 url_post = "/cluster/%s/permissions/"
1026 # anonymous user
1027 response = c.get(url % args, follow=True)
1028 self.assertEqual(200, response.status_code)
1029 self.assertTemplateUsed(response, 'registration/login.html')
1031 # unauthorized user
1032 self.assert_(c.login(username=user.username, password='secret'))
1033 response = c.get(url % args)
1034 self.assertEqual(403, response.status_code)
1036 # nonexisent cluster
1037 response = c.get(url % ("DOES_NOT_EXIST", group.id))
1038 self.assertEqual(404, response.status_code)
1040 # valid GET authorized user (perm)
1041 grant(user, 'admin', cluster)
1042 response = c.get(url % args)
1043 self.assertEqual(200, response.status_code)
1044 self.assertEquals('text/html; charset=utf-8', response['content-type'])
1045 self.assertTemplateUsed(response, 'object_permissions/permissions/form.html')
1047 # valid GET authorized user (superuser)
1048 user.revoke('admin', cluster)
1049 user.is_superuser = True
1050 user.save()
1051 response = c.get(url % args)
1052 self.assertEqual(200, response.status_code)
1053 self.assertTemplateUsed(response, 'object_permissions/permissions/form.html')
1055 # invalid group
1056 response = c.get(url % (cluster.slug, 0))
1057 self.assertEqual(404, response.status_code)
1059 # invalid group (POST)
1060 data = {'permissions':['admin'], 'group':-1, 'obj':cluster.pk}
1061 response = c.post(url_post % args_post, data)
1062 self.assertEquals('application/json', response['content-type'])
1063 self.assertNotEqual('0', response.content)
1065 # no group (POST)
1066 data = {'permissions':['admin'], 'obj':cluster.pk}
1067 response = c.post(url_post % args_post, data)
1068 self.assertEquals('application/json', response['content-type'])
1069 self.assertNotEqual('0', response.content)
1071 # valid POST group has permissions
1072 group.grant('create_vm', cluster)
1073 data = {'permissions':['admin'], 'group':group.id, 'obj':cluster.pk}
1074 response = c.post(url_post % args_post, data)
1075 self.assertEquals('text/html; charset=utf-8', response['content-type'])
1076 self.assertTemplateUsed(response, 'cluster/group_row.html')
1077 self.assertEqual(['admin'], group.get_perms(cluster))
1079 # add quota to the group
1080 user_quota = {'default':0, 'ram':51, 'virtual_cpus':10, 'disk':3000}
1081 quota = Quota(cluster=cluster, user=group.organization)
1082 quota.__dict__.update(user_quota)
1083 quota.save()
1084 self.assertEqual(user_quota, cluster.get_quota(group.organization))
1086 # valid POST group has no permissions left
1087 data = {'permissions':[], 'group':group.id, 'obj':cluster.pk}
1088 response = c.post(url_post % args_post, data)
1089 self.assertEqual(200, response.status_code)
1090 self.assertEquals('application/json', response['content-type'])
1091 self.assertEqual([], group.get_perms(cluster))
1092 self.assertEqual('"group_%s"'%group.id, response.content)
1094 # quota should be deleted (and showing default)
1095 self.assertEqual(1, cluster.get_quota(group.organization)['default'])
1096 self.assertFalse(group.organization.quotas.all().exists())
1098 # no permissions specified - user with no quota
1099 group.grant('create_vm', cluster)
1100 cluster.set_quota(group.organization, None)
1101 data = {'permissions':[], 'group':group.id, 'obj':cluster.pk}
1102 response = c.post(url % args, data)
1103 self.assertEqual(200, response.status_code)
1104 self.assertEquals('application/json', response['content-type'])
1105 self.assertNotEqual('0', response.content)
1107 # quota should be deleted (and showing default)
1108 self.assertEqual(1, cluster.get_quota(group.organization)['default'])
1109 self.assertFalse(group.organization.quotas.all().exists())
1111 def validate_quota(self, cluster_user, template):
1113 Generic tests for validating quota views
1115 Verifies:
1116 * lack of permissions returns 403
1117 * nonexistent cluster returns 404
1118 * invalid user returns 404
1119 * missing user returns error as json
1120 * GET returns html for form
1121 * successful POST returns html for user row
1122 * successful DELETE removes user quota
1124 default_quota = {'default':1, 'ram':1, 'virtual_cpus':None, 'disk':3}
1125 user_quota = {'default':0, 'ram':4, 'virtual_cpus':5, 'disk':None}
1126 user_unlimited = {'default':0, 'ram':None, 'virtual_cpus':None, 'disk':None}
1127 cluster.__dict__.update(default_quota)
1128 cluster.save()
1130 args = (cluster.slug, cluster_user.id)
1131 args_post = cluster.slug
1132 url = '/cluster/%s/quota/%s'
1133 url_post = '/cluster/%s/quota/'
1135 # anonymous user
1136 response = c.get(url % args, follow=True)
1137 self.assertEqual(200, response.status_code)
1138 self.assertTemplateUsed(response, 'registration/login.html')
1140 # unauthorized user
1141 self.assert_(c.login(username=user.username, password='secret'))
1142 response = c.get(url % args)
1143 self.assertEqual(403, response.status_code)
1145 # nonexisent cluster
1146 response = c.get("/cluster/%s/user/quota/?user=%s" % ("DOES_NOT_EXIST", user1.id))
1147 self.assertEqual(404, response.status_code)
1149 # valid GET authorized user (perm)
1150 grant(user, 'admin', cluster)
1151 response = c.get(url % args)
1152 self.assertEqual(200, response.status_code)
1153 self.assertEquals('text/html; charset=utf-8', response['content-type'])
1154 self.assertTemplateUsed(response, 'cluster/quota.html')
1156 # valid GET authorized user (superuser)
1157 user.revoke('admin', cluster)
1158 user.is_superuser = True
1159 user.save()
1160 response = c.get(url % args)
1161 self.assertEqual(200, response.status_code)
1162 self.assertTemplateUsed(response, 'cluster/quota.html')
1164 # invalid user
1165 response = c.get(url % (cluster.slug, 0))
1166 self.assertEqual(404, response.status_code)
1168 # no user (GET)
1169 response = c.get(url_post % args_post)
1170 self.assertEqual(404, response.status_code)
1172 # no user (POST)
1173 data = {'ram':'', 'virtual_cpus':'', 'disk':''}
1174 response = c.post(url_post % args_post, data)
1175 self.assertEqual(200, response.status_code)
1176 self.assertEquals('application/json', response['content-type'])
1178 # valid POST - setting unlimited values (nones)
1179 data = {'user':cluster_user.id, 'ram':'', 'virtual_cpus':'', 'disk':''}
1180 response = c.post(url_post % args_post, data)
1181 self.assertEqual(200, response.status_code)
1182 self.assertEquals('text/html; charset=utf-8', response['content-type'])
1183 self.assertTemplateUsed(response, template)
1184 self.assertEqual(user_unlimited, cluster.get_quota(cluster_user))
1185 query = Quota.objects.filter(cluster=cluster, user=cluster_user)
1186 self.assert_(query.exists())
1188 # valid POST - setting values
1189 data = {'user':cluster_user.id, 'ram':4, 'virtual_cpus':5, 'disk':''}
1190 response = c.post(url_post % args_post, data)
1191 self.assertEquals('text/html; charset=utf-8', response['content-type'])
1192 self.assertTemplateUsed(response, template)
1193 self.assertEqual(user_quota, cluster.get_quota(cluster_user))
1194 self.assert_(query.exists())
1196 # valid POST - same as default values (should delete)
1197 data = {'user':cluster_user.id, 'ram':1, 'disk':3}
1198 response = c.post(url_post % args_post, data)
1199 self.assertEqual(200, response.status_code)
1200 self.assertEquals('text/html; charset=utf-8', response['content-type'])
1201 self.assertTemplateUsed(response, template)
1202 self.assertEqual(default_quota, cluster.get_quota(cluster_user))
1203 self.assertFalse(query.exists())
1205 # valid POST - same as default values (should do nothing)
1206 data = {'user':cluster_user.id, 'ram':1, 'disk':3}
1207 response = c.post(url_post % args_post, data)
1208 self.assertEqual(200, response.status_code)
1209 self.assertEquals('text/html; charset=utf-8', response['content-type'])
1210 self.assertTemplateUsed(response, template)
1211 self.assertEqual(default_quota, cluster.get_quota(cluster_user))
1212 self.assertFalse(query.exists())
1214 # valid POST - setting implicit unlimited (values are excluded)
1215 data = {'user':cluster_user.id}
1216 response = c.post(url_post % args_post, data)
1217 self.assertEqual(200, response.status_code)
1218 self.assertEquals('text/html; charset=utf-8', response['content-type'])
1219 self.assertTemplateUsed(response, template)
1220 self.assertEqual(user_unlimited, cluster.get_quota(cluster_user))
1221 self.assert_(query.exists())
1223 # valid DELETE - returns to default values
1224 data = {'user':cluster_user.id, 'delete':True}
1225 response = c.post(url_post % args_post, data)
1226 self.assertEqual(200, response.status_code)
1227 self.assertTemplateUsed(response, template)
1228 self.assertEqual(default_quota, cluster.get_quota(cluster_user))
1229 self.assertFalse(query.exists())
1231 def test_view_user_quota(self):
1233 Tests updating users quota
1235 self.validate_quota(user1.get_profile(), template='cluster/user_row.html')
1237 def test_view_group_quota(self):
1239 Tests updating a Group's quota
1241 self.validate_quota(group.organization, template='cluster/group_row.html')
1243 def test_sync_virtual_machines_in_edit_view(self):
1245 Test if sync_virtual_machines is run after editing a cluster
1246 for the second time
1248 #configuring stuff needed to test edit view
1249 user.is_superuser = True
1250 user.save()
1251 self.assert_(c.login(username=user.username, password='secret'))
1252 cluster.virtual_machines.all().delete()
1253 url = '/cluster/%s/edit/' % cluster.slug
1255 data = dict(hostname='new-host-1.hostname',
1256 slug='new-host-1',
1257 port=5080,
1258 description='testing editing clusters',
1259 username='tester',
1260 password = 'secret',
1261 virtual_cpus=1,
1262 disk=2,
1263 ram=3
1266 # run view once to create cluster
1267 c.post(url, data, follow=True)
1269 # ensure there are VMs ready for sync
1270 cluster.virtual_machines.all().delete()
1272 #run view_edit again..
1273 c.post(url, data, follow=True)
1275 # assert that no VMs were created
1276 self.assertFalse(cluster.virtual_machines.all().exists())
1278 def test_view_ssh_keys(self):
1280 Test getting SSH keys belonging to users, who have admin permission on
1281 specified cluster
1283 vm = VirtualMachine.objects.create(cluster=cluster, hostname='vm1.osuosl.bak')
1285 # add some keys
1286 SSHKey.objects.create(key="ssh-rsa test test@test", user=user)
1287 SSHKey.objects.create(key="ssh-dsa test asd@asd", user=user)
1288 SSHKey.objects.create(key="ssh-dsa test foo@bar", user=user1)
1290 # get API key
1291 import settings, json
1292 key = settings.WEB_MGR_API_KEY
1294 url = '/cluster/%s/keys/%s/'
1295 args = (cluster.slug, key)
1297 self.assert_standard_fails(url, args, login_required=False, authorized=False)
1299 # cluster without users who have admin perms
1300 response = c.get(url % args)
1301 self.assertEqual(200, response.status_code )
1302 self.assertEquals("application/json", response["content-type"])
1303 self.assertEqual(len(json.loads(response.content)), 0 )
1304 self.assertNotContains(response, "test@test")
1305 self.assertNotContains(response, "asd@asd")
1307 # vm with users who have admin perms
1308 # grant admin permission to first user
1309 user.grant("admin", vm)
1310 user1.grant("admin", cluster)
1312 response = c.get(url % args)
1313 self.assertEqual(200, response.status_code )
1314 self.assertEquals("application/json", response["content-type"])
1315 self.assertEqual(len(json.loads(response.content)), 3 )
1316 self.assertContains(response, "test@test", count=1)
1317 self.assertContains(response, "asd@asd", count=1)
1318 self.assertContains(response, "foo@bar", count=1)
1320 def test_view_redistribute_config(self):
1322 Tests cluster's config redistribution
1324 cluster = globals()['cluster']
1325 url = '/cluster/%s/redistribute-config/' % cluster.slug
1327 # anonymous user
1328 response = c.get(url, follow=True)
1329 self.assertEqual(200, response.status_code)
1330 self.assertTemplateUsed(response, 'registration/login.html')
1332 # unauthorized user
1333 self.assert_(c.login(username=user.username, password='secret'))
1334 response = c.delete(url)
1335 self.assertEqual(403, response.status_code)
1337 # authorized (permission)
1338 user.grant('admin', cluster)
1339 response = c.post(url)
1340 self.assertEqual(200, response.status_code)
1341 self.assertEquals('application/json', response['content-type'])
1342 self.assert_('status' in response.content)
1343 self.assert_(Cluster.objects.filter(id=cluster.id).exists())
1344 user.revoke('admin', cluster)
1346 # recreate cluster
1347 cluster.save()
1349 # authorized (GET)
1350 user.is_superuser = True
1351 user.save()
1352 response = c.post(url)
1353 self.assertEqual(200, response.status_code)
1354 self.assertEquals('application/json', response['content-type'])
1355 self.assert_('status' in response.content)
1356 self.assert_(Cluster.objects.filter(id=cluster.id).exists())