Revision f2080d16
b/snf-cyclades-app/synnefo/api/servers.py | ||
---|---|---|
31 | 31 |
# interpreted as representing official policies, either expressed |
32 | 32 |
# or implied, of GRNET S.A. |
33 | 33 |
|
34 |
import datetime |
|
34 | 35 |
from django import dispatch |
35 | 36 |
from django.conf import settings |
36 | 37 |
from django.conf.urls.defaults import patterns |
... | ... | |
45 | 46 |
from synnefo.api.actions import server_actions |
46 | 47 |
from synnefo.db.models import (VirtualMachine, VirtualMachineMetadata, |
47 | 48 |
NetworkInterface) |
48 |
from synnefo.logic.backend import create_instance, delete_instance |
|
49 |
from synnefo.logic.backend import (create_instance, delete_instance, |
|
50 |
process_op_status) |
|
49 | 51 |
from synnefo.logic.utils import get_rsapi_state |
50 | 52 |
from synnefo.logic.backend_allocator import BackendAllocator |
51 | 53 |
from synnefo import quotas |
... | ... | |
404 | 406 |
userid, vm, nic, backend, str(jobID)) |
405 | 407 |
except: |
406 | 408 |
# If an exception is raised, then the user will never get the VM id. |
407 |
# So, the VM must be marked as 'deleted'. We do not delete the VM row |
|
408 |
# from DB, because the job may have been enqueued to Ganeti. We must |
|
409 |
# also release the VM resources. |
|
410 |
if not vm.deleted: # just an extra check for reconciliation... |
|
411 |
vm.deleted = True |
|
412 |
vm.operstate = "ERROR" |
|
413 |
vm.backendlogmsg = "Error while enqueuing job to Ganeti." |
|
414 |
vm.save() |
|
415 |
# The following call performs commit. |
|
416 |
quotas.issue_and_accept_commission(vm, delete=True) |
|
409 |
# In order to delete it from DB and release it's resources, we |
|
410 |
# mock a successful OP_INSTANCE_REMOVE job. |
|
411 |
process_op_status(vm=vm, |
|
412 |
etime=datetime.datetime.now(), |
|
413 |
jobid=-0, |
|
414 |
opcode="OP_INSTANCE_REMOVE", |
|
415 |
status="success", |
|
416 |
logmsg="Reconciled eventd: VM creation failed.") |
|
417 | 417 |
raise |
418 | 418 |
|
419 | 419 |
return vm |
b/snf-cyclades-app/synnefo/api/test/servers.py | ||
---|---|---|
40 | 40 |
from synnefo.cyclades_settings import cyclades_services |
41 | 41 |
from synnefo.lib.services import get_service_path |
42 | 42 |
from synnefo.lib import join_urls |
43 |
from synnefo.logic.rapi import GanetiApiError |
|
43 | 44 |
|
44 | 45 |
from mock import patch |
45 | 46 |
|
... | ... | |
303 | 304 |
json.dumps(request), 'json') |
304 | 305 |
self.assertItemNotFound(response) |
305 | 306 |
|
307 |
def test_create_server_error(self, mrapi, mimage): |
|
308 |
"""Test if the create server call returns the expected response |
|
309 |
if a valid request has been speficied.""" |
|
310 |
mimage.return_value = {'location': 'pithos://foo', |
|
311 |
'checksum': '1234', |
|
312 |
"id": 1, |
|
313 |
"name": "test_image", |
|
314 |
'disk_format': 'diskdump'} |
|
315 |
mrapi().CreateInstance.side_effect = GanetiApiError("..ganeti is down") |
|
316 |
flavor = mfactory.FlavorFactory() |
|
317 |
# Create public network and backend |
|
318 |
network = mfactory.NetworkFactory(public=True) |
|
319 |
backend = mfactory.BackendFactory() |
|
320 |
mfactory.BackendNetworkFactory(network=network, backend=backend) |
|
321 |
|
|
322 |
request = { |
|
323 |
"server": { |
|
324 |
"name": "new-server-test", |
|
325 |
"userid": "test_user", |
|
326 |
"imageRef": 1, |
|
327 |
"flavorRef": flavor.id, |
|
328 |
"metadata": { |
|
329 |
"My Server Name": "Apache1" |
|
330 |
}, |
|
331 |
"personality": [] |
|
332 |
} |
|
333 |
} |
|
334 |
with mocked_quotaholder(): |
|
335 |
response = self.mypost('servers', 'test_user', |
|
336 |
json.dumps(request), 'json') |
|
337 |
self.assertEqual(response.status_code, 500) |
|
338 |
mrapi().CreateInstance.assert_called_once() |
|
339 |
vm = VirtualMachine.objects.get() |
|
340 |
# The VM has been deleted |
|
341 |
self.assertTrue(vm.deleted) |
|
342 |
# and it has no nics |
|
343 |
self.assertEqual(len(vm.nics.all()), 0) |
|
344 |
self.assertEqual(vm.backendjobid, 0) |
|
345 |
|
|
306 | 346 |
|
307 | 347 |
@patch('synnefo.logic.rapi_pool.GanetiRapiClient') |
308 | 348 |
class ServerDestroyAPITest(ComputeAPITest): |
b/snf-django-lib/snf_django/utils/testing.py | ||
---|---|---|
140 | 140 |
def mocked_quotaholder(success=True): |
141 | 141 |
with patch("synnefo.quotas.Quotaholder.get") as astakos: |
142 | 142 |
global serial |
143 |
serial += 1 |
|
144 |
astakos.return_value.issue_one_commission.return_value = serial |
|
143 |
serial += 10 |
|
144 |
|
|
145 |
def foo(*args, **kwargs): |
|
146 |
return (len(astakos.return_value.issue_one_commission.mock_calls) + |
|
147 |
serial) |
|
148 |
astakos.return_value.issue_one_commission.side_effect = foo |
|
145 | 149 |
astakos.return_value.resolve_commissions.return_value = {"failed": []} |
146 | 150 |
yield |
147 | 151 |
|
Also available in: Unified diff