Changelog: updated for 0.7
[ganeti_webmgr.git] / ganeti_web / tests / node.py
blob437eb8b8f063f117d296335b60e87326479bc0d9
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.
18 from datetime import datetime
19 import json
22 from django.contrib.auth.models import User
23 from django.test import TestCase
25 from django_test_tools.users import UserTestMixin
26 from django_test_tools.views import ViewTestMixin
28 from ganeti_web.tests.rapi_proxy import RapiProxy, NODE
29 from ganeti_web import models
30 from util.client import GanetiApiError
32 from ganeti_web.views import node as view_node
34 VirtualMachine = models.VirtualMachine
35 Cluster = models.Cluster
36 Node = models.Node
39 __all__ = (
40 'TestNodeModel',
41 'TestNodeViews',
44 global user_admin, user_migrate, superuser
45 global cluster, node
47 def cluster_default_info_proxy(cluster):
48 return {
49 'iallocator':'foo'
52 view_node.cluster_default_info = cluster_default_info_proxy
55 class NodeTestCaseMixin():
56 def create_node(self, cluster=None, hostname='node1.osuosl.bak'):
57 cluster = cluster if cluster else Cluster.objects \
58 .create(hostname='test.osuosl.bak', slug='OSL_TEST')
59 node = Node.objects.create(cluster=cluster, hostname=hostname)
60 return node, cluster
63 class TestNodeModel(TestCase, NodeTestCaseMixin):
65 def setUp(self):
66 self.tearDown()
67 models.client.GanetiRapiClient = RapiProxy
69 def tearDown(self):
70 VirtualMachine.objects.all().delete()
71 Node.objects.all().delete()
72 Cluster.objects.all().delete()
74 def test_trivial(self):
75 """
76 Test instantiating a VirtualMachine
77 """
78 Node()
80 def test_non_trivial(self):
81 """
82 Test instantiating a VirtualMachine with extra parameters
83 """
84 # Define cluster for use
85 node_hostname='node.test.org'
86 cluster = Cluster.objects.create(hostname='test.osuosl.bak', slug='OSL_TEST')
88 # Cluster
89 node = Node.objects.create(cluster=cluster, hostname=node_hostname)
90 self.assertTrue(node.id)
91 self.assertEqual('node.test.org', node.hostname)
92 self.assertFalse(node.error)
93 node.delete()
95 # Multiple
96 node = Node.objects.create(cluster=cluster, hostname=node_hostname)
97 self.assertTrue(node.id)
98 self.assertEqual('node.test.org', node.hostname)
99 self.assertFalse(node.error)
101 def test_save(self):
103 Test saving a VirtualMachine
105 Verify:
106 * Node can be saved
107 * Node can be loaded
108 * Hash is copied from cluster
110 node, cluster = self.create_node()
111 self.assert_(node.id)
112 self.assertFalse(node.error)
113 self.assertEqual(node.cluster_hash, cluster.hash)
115 node = Node.objects.get(id=node.id)
116 self.assert_(node.info)
117 self.assertFalse(node.error)
119 def test_hash_update(self):
121 When cluster is saved hash for its VirtualMachines should be updated
123 node0, cluster = self.create_node()
124 node1, cluster = self.create_node(cluster, 'test2.osuosl.bak')
126 self.assertEqual(node0.cluster_hash, cluster.hash)
127 self.assertEqual(node1.cluster_hash, cluster.hash)
129 # change cluster's hash
130 cluster.hostname = 'SomethingDifferent'
131 cluster.save()
132 node0 = Node.objects.get(pk=node0.id)
133 node1 = Node.objects.get(pk=node1.id)
134 self.assertEqual(node0.cluster_hash, cluster.hash, 'VirtualMachine does not have updated cache')
135 self.assertEqual(node1.cluster_hash, cluster.hash, 'VirtualMachine does not have updated cache')
137 def test_parse_info(self):
139 Test parsing values from cached info
141 Verifies:
142 * mtime and ctime are parsed
143 * ram, virtual_cpus, and disksize are parsed
145 node, cluster = self.create_node()
146 node.info = NODE
148 self.assertEqual(node.ctime, datetime.fromtimestamp(1285799513.4741000))
149 self.assertEqual(node.mtime, datetime.fromtimestamp(1285883187.8692000))
150 self.assertFalse(node.offline)
152 def test_ram(self):
154 Tests the Node.ram property
156 node, c = self.create_node()
157 node2, c = self.create_node(cluster=c, hostname='two')
158 node.refresh()
159 node2.refresh()
161 VirtualMachine.objects.create(cluster=c, primary_node=node, hostname='foo', ram=123, status='running')
162 VirtualMachine.objects.create(cluster=c, secondary_node=node, hostname='bar', ram=456, status='running')
163 VirtualMachine.objects.create(cluster=c, primary_node=node, hostname='xoo', ram=789, status='admin_down')
164 VirtualMachine.objects.create(cluster=c, secondary_node=node, hostname='xar', ram=234, status='stopped')
165 VirtualMachine.objects.create(cluster=c, primary_node=node, hostname='boo', status='running')
166 VirtualMachine.objects.create(cluster=c, primary_node=node2, hostname='gar', ram=888, status='running')
167 VirtualMachine.objects.create(cluster=c, primary_node=node2, hostname='yoo', ram=999, status='admin_down')
169 ram = node.ram
170 self.assertEqual(9999, ram['total'])
171 self.assertEqual(9420, ram['free'])
173 def test_disk(self):
175 Tests the Node.ram property
177 node, c = self.create_node()
178 node2, c = self.create_node(cluster=c, hostname='two')
179 node.refresh()
180 node2.refresh()
182 VirtualMachine.objects.create(cluster=c, primary_node=node, hostname='foo', disk_size=123, status='running')
183 VirtualMachine.objects.create(cluster=c, secondary_node=node, hostname='bar', disk_size=456, status='running')
184 VirtualMachine.objects.create(cluster=c, primary_node=node, hostname='xoo', disk_size=789, status='admin_down')
185 VirtualMachine.objects.create(cluster=c, secondary_node=node, hostname='xar', disk_size=234, status='stopped')
186 VirtualMachine.objects.create(cluster=c, primary_node=node, hostname='boo', status='running')
187 VirtualMachine.objects.create(cluster=c, primary_node=node2, hostname='gar', disk_size=888, status='running')
188 VirtualMachine.objects.create(cluster=c, primary_node=node2, hostname='yoo', disk_size=999, status='admin_down')
190 disk = node.disk
191 self.assertEqual(6666, disk['total'])
192 self.assertEqual(5064, disk['free'])
195 class TestNodeViews(TestCase, NodeTestCaseMixin, UserTestMixin, ViewTestMixin):
197 def setUp(self):
198 models.client.GanetiRapiClient = RapiProxy
200 node, cluster = self.create_node()
201 node2, cluster = self.create_node(cluster, 'node2.osuosl.bak')
203 d = globals()
204 d['cluster'] = cluster
205 d['node'] = node
207 self.create_standard_users(d)
208 self.create_users(['user_migrate', 'user_admin'], d)
210 user_migrate.grant('migrate', cluster)
211 user_admin.grant('admin', cluster)
213 def tearDown(self):
214 VirtualMachine.objects.all().delete()
215 Node.objects.all().delete()
216 Cluster.objects.all().delete()
217 User.objects.all().delete()
219 def test_detail(self):
220 args = (cluster.slug, node.hostname)
221 url = '/cluster/%s/node/%s/'
222 users = [superuser, user_migrate, user_admin]
223 self.assert_standard_fails(url, args)
224 self.assert_200(url, args, users, 'node/detail.html')
226 def test_primary_vms(self):
227 args = (cluster.slug, node.hostname)
228 url = '/cluster/%s/node/%s/primary'
229 users = [superuser, user_migrate, user_admin]
230 self.assert_standard_fails(url, args)
231 self.assert_200(url, args, users, 'virtual_machine/table.html')
233 def test_secondary_vms(self):
234 args = (cluster.slug, node.hostname)
235 url = '/cluster/%s/node/%s/secondary'
236 users = [superuser, user_migrate, user_admin]
237 self.assert_standard_fails(url, args)
238 self.assert_200(url, args, users, 'virtual_machine/table.html')
240 def test_object_log(self):
241 args = (cluster.slug, node.hostname)
242 url = '/cluster/%s/node/%s/object_log'
243 users = [superuser, user_migrate, user_admin]
244 self.assert_standard_fails(url, args)
245 self.assert_200(url, args, users)
247 def test_role(self):
248 args = (cluster.slug, node.hostname)
249 url = '/cluster/%s/node/%s/role'
250 users = [superuser, user_migrate, user_admin]
251 self.assert_standard_fails(url, args)
252 self.assert_200(url, args, users, 'node/role.html')
254 # test posts
255 def test(user, response):
256 data = json.loads(response.content)
257 self.assertTrue('opstatus' in data)
258 data = {'role':'master-candidate'}
259 self.assert_200(url, args, users, method='post', data=data, mime='application/json', tests=test)
261 #test form error
262 def test(user, response):
263 data = json.loads(response.content)
264 self.assertFalse('opstatus' in data)
265 self.assert_200(url, args, [superuser], method='post', \
266 mime='application/json', data={}, tests=test)
268 #test ganeti error
269 def test(user, response):
270 data = json.loads(response.content)
271 self.assertFalse('opstatus' in data)
272 node.rapi.SetNodeRole.error = GanetiApiError("Testing Error")
273 self.assert_200(url, args, [superuser], method='post', mime='application/json', data=data, tests=test)
274 node.rapi.SetNodeRole.error = None
276 def test_migrate(self):
277 args = (cluster.slug, node.hostname)
278 url = '/cluster/%s/node/%s/migrate'
279 users = [superuser, user_migrate, user_admin]
280 self.assert_standard_fails(url, args)
281 self.assert_200(url, args, users, 'node/migrate.html')
283 #test posts
284 def test(user, response):
285 data = json.loads(response.content)
286 self.assertTrue('opstatus' in data)
287 data = {'mode':'live'}
288 self.assert_200(url, args, users, method='post', data=data, mime='application/json', tests=test)
290 #test form error
291 def test(user, response):
292 data = json.loads(response.content)
293 self.assertFalse('opstatus' in data)
294 self.assert_200(url, args, [superuser], method='post', \
295 mime='application/json', data={}, tests=test)
297 #test ganeti error
298 def test(user, response):
299 data = json.loads(response.content)
300 self.assertFalse('opstatus' in data)
301 node.rapi.MigrateNode.error = GanetiApiError("Testing Error")
302 self.assert_200(url, args, [superuser], method='post', mime='application/json', data=data, tests=test)
303 node.rapi.MigrateNode.error = None
305 def test_evacuate(self):
306 args = (cluster.slug, node.hostname)
307 url = '/cluster/%s/node/%s/evacuate'
308 users = [superuser, user_migrate, user_admin]
310 self.assert_standard_fails(url, args, method='post')
311 self.assert_200(url, args, users, template='node/evacuate.html')
313 # Test iallocator
314 data = {'iallocator':True, 'iallocator_hostname':'foo', 'node':''}
315 def tests(user, response):
316 data = json.loads(response.content)
317 self.assertTrue('status' in data, data)
318 self.assertEqual('1', data['id'], data)
319 self.assert_200(url, args, users, method='post', data=data, \
320 tests=tests, mime="application/json")
322 # Test node selection
323 data = {'iallocator':False, 'iallocator_hostname':'foo', 'node':'node2.osuosl.bak'}
324 self.assert_200(url, args, users, method='post', data=data, \
325 tests=tests, mime="application/json")
327 # Test form errors
328 def test(user, response):
329 data = json.loads(response.content)
330 self.assertFalse('status' in data, data)
332 errors = [
333 {'iallocator':False, 'iallocator_hostname':'foo', 'node':''} # must choose iallocator or a node
335 self.assert_view_values(url, args, data, errors, mime='application/json', tests=test)
337 # Test GanetiError
338 def test(user, response):
339 data = json.loads(response.content)
340 self.assertFalse('opstatus' in data)
341 node.rapi.EvacuateNode.error = GanetiApiError("Testing Error")
342 self.assert_200(url, args, [superuser], data=data, method='post', mime='application/json', tests=test)
343 node.rapi.EvacuateNode.error = None