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,
18 from datetime
import datetime
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
44 global user_admin
, user_migrate
, superuser
47 def cluster_default_info_proxy(cluster
):
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
)
63 class TestNodeModel(TestCase
, NodeTestCaseMixin
):
67 models
.client
.GanetiRapiClient
= RapiProxy
70 VirtualMachine
.objects
.all().delete()
71 Node
.objects
.all().delete()
72 Cluster
.objects
.all().delete()
74 def test_trivial(self
):
76 Test instantiating a VirtualMachine
80 def test_non_trivial(self
):
82 Test instantiating a VirtualMachine with extra parameters
84 # Define cluster for use
85 node_hostname
='node.test.org'
86 cluster
= Cluster
.objects
.create(hostname
='test.osuosl.bak', slug
='OSL_TEST')
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
)
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
)
103 Test saving a VirtualMachine
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'
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
142 * mtime and ctime are parsed
143 * ram, virtual_cpus, and disksize are parsed
145 node
, cluster
= self
.create_node()
148 self
.assertEqual(node
.ctime
, datetime
.fromtimestamp(1285799513.4741000))
149 self
.assertEqual(node
.mtime
, datetime
.fromtimestamp(1285883187.8692000))
150 self
.assertFalse(node
.offline
)
154 Tests the Node.ram property
156 node
, c
= self
.create_node()
157 node2
, c
= self
.create_node(cluster
=c
, hostname
='two')
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')
170 self
.assertEqual(9999, ram
['total'])
171 self
.assertEqual(9420, ram
['free'])
175 Tests the Node.ram property
177 node
, c
= self
.create_node()
178 node2
, c
= self
.create_node(cluster
=c
, hostname
='two')
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')
191 self
.assertEqual(6666, disk
['total'])
192 self
.assertEqual(5064, disk
['free'])
195 class TestNodeViews(TestCase
, NodeTestCaseMixin
, UserTestMixin
, ViewTestMixin
):
198 models
.client
.GanetiRapiClient
= RapiProxy
200 node
, cluster
= self
.create_node()
201 node2
, cluster
= self
.create_node(cluster
, 'node2.osuosl.bak')
204 d
['cluster'] = cluster
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
)
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
)
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')
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
)
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
)
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')
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
)
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
)
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')
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")
328 def test(user
, response
):
329 data
= json
.loads(response
.content
)
330 self
.assertFalse('status' in data
, data
)
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
)
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