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
20 from django
.test
import TestCase
21 from django
.test
.client
import Client
23 from util
import client
24 from ganeti_web
.tests
.call_proxy
import CallProxy
25 from ganeti_web
.tests
.rapi_proxy
import RapiProxy
26 from django
.contrib
.auth
.models
import User
27 from ganeti_web
import models
29 VirtualMachine
= models
.VirtualMachine
30 Cluster
= models
.Cluster
31 GanetiError
= models
.GanetiError
32 GanetiErrorManager
= models
.GanetiErrorManager
34 __all__
= ('TestGanetiErrorModel','TestErrorViews')
36 class TestGanetiErrorBase():
38 Class for testing ganeti error storage.
43 models
.client
.GanetiRapiClient
= RapiProxy
46 VirtualMachine
.objects
.all().delete()
47 Cluster
.objects
.all().delete()
48 GanetiError
.objects
.all().delete()
49 RapiProxy
.error
= None
51 def create_model(self
, class_
, *args
, **kwargs
):
53 create an instance of the model being tested, this will instrument
54 some methods of the model to check if they have been called
56 obj
= class_
.objects
.create(*args
, **kwargs
)
59 CallProxy
.patch(obj
, 'parse_transient_info')
60 CallProxy
.patch(obj
, 'parse_persistent_info')
61 CallProxy
.patch(obj
, '_refresh')
62 CallProxy
.patch(obj
, 'load_info')
63 CallProxy
.patch(obj
, 'save')
67 class TestGanetiErrorModel(TestGanetiErrorBase
, TestCase
):
69 Class for testing ganeti error storage.
72 # TODO: add tests for clusters/vms in get_errors
73 # TODO: maybe split into individual tests? Not sure
74 def test_manager_methods(self
):
76 Test useful GanetiErrorManager methods:
84 * all those methods are free of errors
86 cluster0
= self
.create_model(Cluster
, hostname
="test0", slug
="OSL_TEST0")
87 cluster1
= self
.create_model(Cluster
, hostname
="test1", slug
="OSL_TEST1")
88 cluster2
= self
.create_model(Cluster
, hostname
="test2", slug
="OSL_TEST2")
89 vm0
= self
.create_model(VirtualMachine
,cluster
=cluster0
, hostname
="vm0.test.org")
90 vm1
= self
.create_model(VirtualMachine
,cluster
=cluster1
, hostname
="vm1.test.org")
92 msg
= client
.GanetiApiError("Simulating an error", 777)
96 store_error
= GanetiError
.objects
.store_error
97 store_error(str(msg
), obj
=cluster0
, code
=msg
.code
)
98 store_error(str(msg
), obj
=cluster1
, code
=msg
.code
)
99 store_error(str(msg
), obj
=cluster2
, code
=msg
.code
)
100 store_error(str(msg
), obj
=vm0
, code
=msg
.code
)
101 store_error(str(msg
), obj
=vm1
, code
=msg
.code
)
104 get_errors
= GanetiError
.objects
.get_errors
106 errors
= get_errors(msg
=str(msg
))
107 self
.assertEqual(len(errors
), 5)
108 errors
= get_errors(msg
=str(msg
) + "NOTHING")
109 self
.assertEqual(len(errors
), 0)
111 errors
= get_errors(code
=msg
.code
)
112 self
.assertEqual(len(errors
), 5)
113 errors
= get_errors(code
=msg
.code
+ 123)
114 self
.assertEqual(len(errors
), 0)
116 errors
= get_errors(obj
=cluster0
)
117 self
.assertEqual(len(errors
), 2)
118 errors
= get_errors(obj
=cluster1
)
119 self
.assertEqual(len(errors
), 2)
120 errors
= get_errors(obj
=cluster2
)
121 self
.assertEqual(len(errors
), 1)
123 errors
= get_errors(obj
=vm0
)
124 self
.assertEqual(len(errors
), 1)
125 errors
= get_errors(obj
=vm1
)
126 self
.assertEqual(len(errors
), 1)
128 errors
= get_errors(obj
=Cluster
.objects
.all())
129 self
.assertEqual(len(errors
), 5)
130 errors
= get_errors(obj
=VirtualMachine
.objects
.all())
131 self
.assertEqual(len(errors
), 2)
133 # test clear_error(s)
134 clear_error
= GanetiError
.objects
.clear_error
135 clear_errors
= GanetiError
.objects
.clear_errors
137 errors
= get_errors()
138 self
.assertEqual(len(errors
), 5)
139 errors
= get_errors(cleared
=False).order_by("id")
140 self
.assertEqual(len(errors
), 5)
142 clear_error(errors
[0].id)
143 errors
= get_errors()
144 self
.assertEqual(len(errors
), 5)
145 errors
= get_errors(cleared
=False)
146 self
.assertEqual(len(errors
), 4)
148 clear_errors(obj
=cluster2
)
149 errors
= get_errors()
150 self
.assertEqual(len(errors
), 5)
151 errors
= get_errors(cleared
=False)
152 self
.assertEqual(len(errors
), 3)
154 clear_errors(obj
=vm1
)
155 errors
= get_errors()
156 self
.assertEqual(len(errors
), 5)
157 errors
= get_errors(cleared
=False)
158 self
.assertEqual(len(errors
), 2)
160 clear_errors(msg
=str(msg
))
161 errors
= get_errors()
162 self
.assertEqual(len(errors
), 5)
163 errors
= get_errors(cleared
=False)
164 self
.assertEqual(len(errors
), 0)
167 remove_errors
= GanetiError
.objects
.remove_errors
169 errors
= get_errors()
170 self
.assertEqual(len(errors
), 5)
172 remove_errors(obj
=cluster2
)
173 errors
= get_errors()
174 self
.assertEqual(len(errors
), 4)
176 remove_errors(obj
=vm1
)
177 errors
= get_errors()
178 self
.assertEqual(len(errors
), 3)
180 remove_errors(msg
=str(msg
))
181 errors
= get_errors()
182 self
.assertEqual(len(errors
), 0)
184 def test_specified_code_values(self
):
186 Test if errors with code in (401, 404) are stored in a proper way.
187 See tickets #2877, #2883.
190 * Manager store_error works properly for specific code numbers
192 cluster0
= self
.create_model(Cluster
, hostname
="test0", slug
="OSL_TEST0")
193 vm0
= self
.create_model(VirtualMachine
,cluster
=cluster0
, hostname
="vm0.test.org")
195 msg0
= client
.GanetiApiError("Simulating 401 error", 401)
196 msg1
= client
.GanetiApiError("Simulating 404 error", 404)
197 RapiProxy
.error
= msg0
199 store_error
= GanetiError
.objects
.store_error
200 get_errors
= GanetiError
.objects
.get_errors
201 remove_errors
= GanetiError
.objects
.remove_errors
204 store_error(str(msg0
), obj
=cluster0
, code
=msg0
.code
)
205 errors
= get_errors(obj
=cluster0
)
206 self
.assertEqual(len(errors
), 1)
207 errors
= get_errors(obj
=vm0
)
208 self
.assertEqual(len(errors
), 0)
209 remove_errors(obj
=cluster0
)
212 store_error(str(msg0
), obj
=vm0
, code
=msg0
.code
)
213 errors
= get_errors(obj
=cluster0
)
214 self
.assertEqual(len(errors
), 1)
215 errors
= get_errors(obj
=vm0
)
216 self
.assertEqual(len(errors
), 0)
217 remove_errors(obj
=cluster0
)
218 remove_errors(obj
=vm0
)
221 store_error(str(msg1
), obj
=vm0
, code
=msg1
.code
)
222 errors
= get_errors(obj
=cluster0
)
223 self
.assertEqual(len(errors
), 1)
224 errors
= get_errors(obj
=vm0
)
225 self
.assertEqual(len(errors
), 1)
226 remove_errors(obj
=cluster0
)
227 remove_errors(obj
=vm0
)
230 store_error(str(msg1
), obj
=cluster0
, code
=msg1
.code
)
231 errors
= get_errors(obj
=cluster0
)
232 self
.assertEqual(len(errors
), 1)
233 errors
= get_errors(obj
=vm0
)
234 self
.assertEqual(len(errors
), 0)
236 # 404 - VM, but error is really with cluster
237 store_error(str(msg1
), obj
=vm0
, code
=msg1
.code
)
238 errors
= get_errors(obj
=cluster0
)
239 self
.assertEqual(len(errors
), 1)
240 errors
= get_errors(obj
=vm0
)
241 self
.assertEqual(len(errors
), 0)
242 remove_errors(obj
=cluster0
)
244 def refresh(self
, object):
246 NOTE: this test is borrowed from TestCachedClusterObject.
248 Test forced refresh of cached data
251 * Object specific refresh is called
254 * Cache time is updated
259 object._refresh
.assertCalled(self
)
260 object.parse_transient_info
.assertCalled(self
)
261 object.parse_persistent_info
.assertCalled(self
)
262 self
.assertEqual(1, len(object.parse_persistent_info
.calls
))
263 self
.assert_(object.id)
264 self
.assertNotEqual(None, object.cached
)
265 self
.assert_(now
< object.cached
, "Cache time should be newer")
267 def test_refresh_error(self
):
269 Test an error during refresh
272 * error will be saved as GanetiError object
273 * successful refresh after will clear error
275 cluster0
= self
.create_model(Cluster
, hostname
="test0", slug
="OSL_TEST0")
276 cluster1
= self
.create_model(Cluster
, hostname
="test1", slug
="OSL_TEST1")
277 vm0
= self
.create_model(VirtualMachine
,cluster
=cluster0
, hostname
="vm0.test.org")
278 vm1
= self
.create_model(VirtualMachine
,cluster
=cluster1
, hostname
="vm1.test.org")
280 msg
= client
.GanetiApiError("Simulating an error", 777)
281 RapiProxy
.error
= msg
283 # force an error on all objects to test its capture
284 for i
in (cluster0
, cluster1
, vm0
, vm1
):
286 self
.assertEqual(str(msg
), i
.error
)
288 # get errors for object
289 # TODO: check log format
290 if isinstance(i
, VirtualMachine
):
291 errors
= GanetiError
.objects
.get_errors(obj
=i
.cluster
)
292 self
.assertEqual(2, len(errors
))
293 self
.assertEqual(errors
[0].cleared
, False)
294 self
.assertEqual(errors
[1].cleared
, False)
295 self
.assertEqual(errors
[0].msg
, str(msg
))
296 self
.assertEqual(errors
[1].msg
, str(msg
))
297 self
.assertEqual(errors
[0].code
, msg
.code
)
298 self
.assertEqual(errors
[1].code
, msg
.code
)
300 cleared
= GanetiError
.objects
.get_errors(obj
=i
.cluster
, cleared
=True)
301 self
.assertEqual(0, len(cleared
))
304 errors
= GanetiError
.objects
.get_errors(obj
=i
)
305 self
.assertEqual(1, len(errors
))
306 self
.assertEqual(errors
[0].cleared
, False)
307 self
.assertEqual(errors
[0].msg
, str(msg
))
308 self
.assertEqual(errors
[0].code
, msg
.code
)
310 cleared
= GanetiError
.objects
.get_errors(obj
=i
, cleared
=True)
311 self
.assertEqual(0, len(cleared
))
313 # set all errors as cleared and test if it was a success
314 for i
in (cluster0
, cluster1
, vm0
, vm1
):
315 if isinstance(i
, VirtualMachine
):
316 GanetiError
.objects
.clear_errors(obj
=i
.cluster
)
318 cleared
= GanetiError
.objects
.get_errors(obj
=i
.cluster
, cleared
=True)
319 self
.assertEqual(2, len(cleared
))
320 self
.assertEqual(cleared
[0].cleared
, True)
321 self
.assertEqual(cleared
[1].cleared
, True)
322 self
.assertEqual(cleared
[0].msg
, str(msg
))
323 self
.assertEqual(cleared
[1].msg
, str(msg
))
324 self
.assertEqual(cleared
[0].code
, msg
.code
)
325 self
.assertEqual(cleared
[1].code
, msg
.code
)
328 GanetiError
.objects
.clear_errors(obj
=i
)
330 cleared
= GanetiError
.objects
.get_errors(obj
=i
, cleared
=True)
331 self
.assertEqual(2, len(cleared
))
332 self
.assertEqual(cleared
[0].cleared
, True)
333 self
.assertEqual(cleared
[1].cleared
, True)
334 self
.assertEqual(cleared
[0].msg
, str(msg
))
335 self
.assertEqual(cleared
[1].msg
, str(msg
))
336 self
.assertEqual(cleared
[0].code
, msg
.code
)
337 self
.assertEqual(cleared
[1].code
, msg
.code
)
339 # clear the error and retry
340 RapiProxy
.error
= None
342 for i
in (cluster0
, cluster1
, vm0
, vm1
):
344 self
.assertEqual(None, i
.error
)
347 class TestErrorViews(TestGanetiErrorBase
, TestCase
):
350 super(TestErrorViews
, self
).setUp()
352 user
= User(id=2, username
='tester0')
353 user
.set_password('secret')
358 d
['cluster'] = self
.create_model(Cluster
, hostname
="test0", slug
="OSL_TEST0")
359 d
['vm'] = self
.create_model(VirtualMachine
,cluster
=cluster
, hostname
="vm0.test.org")
363 super(TestErrorViews
, self
).tearDown()
364 User
.objects
.all().delete()
366 def test_clear_error(self
):
368 url
= '/error/clear/%s'
371 msg
= client
.GanetiApiError("Simulating an error", 777)
372 RapiProxy
.error
= msg
375 store_error
= GanetiError
.objects
.store_error
376 c_error
= store_error(str(msg
), obj
=cluster
, code
=msg
.code
)
377 c_error
= GanetiError
.objects
.get(pk
=c_error
.pk
)
378 self
.assertFalse(c_error
.cleared
)
380 vm_error
= store_error(str(msg
), obj
=vm
, code
=msg
.code
)
381 vm_error
= GanetiError
.objects
.get(pk
=vm_error
.pk
)
382 self
.assertFalse(vm_error
.cleared
)
385 response
= c
.post(url
% vm_error
.id, follow
=True)
386 self
.assertEqual(200, response
.status_code
)
387 self
.assertTemplateUsed(response
, 'registration/login.html')
388 vm_error
= GanetiError
.objects
.get(pk
=vm_error
.pk
)
389 self
.assertFalse(vm_error
.cleared
)
392 self
.assert_(c
.login(username
=user
.username
, password
='secret'))
393 response
= c
.post(url
% vm_error
.id)
394 self
.assertEqual(403, response
.status_code
)
395 vm_error
= GanetiError
.objects
.get(pk
=vm_error
.pk
)
396 self
.assertFalse(vm_error
.cleared
)
399 response
= c
.post(url
% -1)
400 self
.assertEqual(404, response
.status_code
)
402 # authorized for cluster (cluster admin)
403 user
.grant('admin', cluster
)
404 response
= c
.post(url
% c_error
.id)
405 self
.assertEqual(200, response
.status_code
)
406 c_error
= GanetiError
.objects
.get(pk
=c_error
.pk
)
407 self
.assert_(c_error
.cleared
)
408 GanetiError
.objects
.all().update(cleared
=False)
410 # authorized for vm (cluster admin)
411 response
= c
.post(url
% vm_error
.id)
412 self
.assertEqual(200, response
.status_code
)
413 vm_error
= GanetiError
.objects
.get(pk
=vm_error
.pk
)
414 self
.assert_(vm_error
.cleared
)
415 GanetiError
.objects
.all().update(cleared
=False)
416 user
.revoke_all(cluster
)
418 # authorized for vm (vm owner)
419 vm
.owner
= user
.get_profile()
421 response
= c
.post(url
% vm_error
.id)
422 self
.assertEqual(200, response
.status_code
)
423 vm_error
= GanetiError
.objects
.get(pk
=vm_error
.pk
)
424 self
.assert_(vm_error
.cleared
)
425 GanetiError
.objects
.all().update(cleared
=False)
429 # authorized for vm (superuser)
430 user
.is_superuser
= True
432 response
= c
.post(url
% vm_error
.id)
433 self
.assertEqual(200, response
.status_code
)
434 vm_error
= GanetiError
.objects
.get(pk
=vm_error
.pk
)
435 self
.assert_(vm_error
.cleared
)
436 GanetiError
.objects
.all().update(cleared
=False)