Merge "Check instance state before attach/detach interface"
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
import webob
|
||||
from webob import exc
|
||||
|
||||
from nova.api.openstack import common
|
||||
from nova.api.openstack import extensions
|
||||
from nova import compute
|
||||
from nova import exception
|
||||
@@ -122,6 +123,9 @@ class InterfaceAttachmentController(object):
|
||||
LOG.exception(e)
|
||||
msg = _("Failed to attach interface")
|
||||
raise webob.exc.HTTPInternalServerError(explanation=msg)
|
||||
except exception.InstanceInvalidState as state_error:
|
||||
common.raise_http_conflict_for_instance_invalid_state(state_error,
|
||||
'attach_interface')
|
||||
|
||||
return self.show(req, server_id, vif['id'])
|
||||
|
||||
@@ -153,6 +157,9 @@ class InterfaceAttachmentController(object):
|
||||
except NotImplementedError:
|
||||
msg = _("Network driver does not support this function.")
|
||||
raise webob.exc.HTTPNotImplemented(explanation=msg)
|
||||
except exception.InstanceInvalidState as state_error:
|
||||
common.raise_http_conflict_for_instance_invalid_state(state_error,
|
||||
'detach_interface')
|
||||
|
||||
return webob.Response(status_int=202)
|
||||
|
||||
|
||||
@@ -123,6 +123,9 @@ class InterfaceAttachmentController(object):
|
||||
LOG.exception(e)
|
||||
raise webob.exc.HTTPInternalServerError(
|
||||
explanation=e.format_message())
|
||||
except exception.InstanceInvalidState as state_error:
|
||||
common.raise_http_conflict_for_instance_invalid_state(state_error,
|
||||
'attach_interface')
|
||||
|
||||
return self.show(req, server_id, vif['id'])
|
||||
|
||||
@@ -149,6 +152,9 @@ class InterfaceAttachmentController(object):
|
||||
raise exc.HTTPConflict(explanation=e.format_message())
|
||||
except NotImplementedError as e:
|
||||
raise webob.exc.HTTPNotImplemented(explanation=e.format_message())
|
||||
except exception.InstanceInvalidState as state_error:
|
||||
common.raise_http_conflict_for_instance_invalid_state(state_error,
|
||||
'detach_interface')
|
||||
|
||||
return webob.Response(status_int=202)
|
||||
|
||||
|
||||
@@ -2880,6 +2880,9 @@ class API(base.Base):
|
||||
|
||||
@wrap_check_policy
|
||||
@check_instance_lock
|
||||
@check_instance_state(vm_state=[vm_states.ACTIVE, vm_states.PAUSED,
|
||||
vm_states.STOPPED],
|
||||
task_state=[None])
|
||||
def attach_interface(self, context, instance, network_id, port_id,
|
||||
requested_ip):
|
||||
"""Use hotplug to add an network adapter to an instance."""
|
||||
@@ -2889,6 +2892,9 @@ class API(base.Base):
|
||||
|
||||
@wrap_check_policy
|
||||
@check_instance_lock
|
||||
@check_instance_state(vm_state=[vm_states.ACTIVE, vm_states.PAUSED,
|
||||
vm_states.STOPPED],
|
||||
task_state=[None])
|
||||
def detach_interface(self, context, instance, port_id):
|
||||
"""Detach an network adapter from an instance."""
|
||||
self.compute_rpcapi.detach_interface(context, instance=instance,
|
||||
|
||||
@@ -282,6 +282,45 @@ class InterfaceAttachTests(test.NoDBTestCase):
|
||||
attachments.create, req, FAKE_UUID1,
|
||||
jsonutils.loads(req.body))
|
||||
|
||||
def test_attach_interface_with_invalid_state(self):
|
||||
def fake_attach_interface_invalid_state(*args, **kwargs):
|
||||
raise exception.InstanceInvalidState(
|
||||
instance_uuid='', attr='', state='',
|
||||
method='attach_interface')
|
||||
|
||||
self.stubs.Set(compute_api.API, 'attach_interface',
|
||||
fake_attach_interface_invalid_state)
|
||||
attachments = attach_interfaces.InterfaceAttachmentController()
|
||||
req = webob.Request.blank('/v2/fake/os-interfaces/attach')
|
||||
req.method = 'POST'
|
||||
req.body = jsonutils.dumps({'interfaceAttachment':
|
||||
{'net_id': FAKE_NET_ID1}})
|
||||
req.headers['content-type'] = 'application/json'
|
||||
req.environ['nova.context'] = self.context
|
||||
self.assertRaises(exc.HTTPConflict,
|
||||
attachments.create, req, FAKE_UUID1,
|
||||
jsonutils.loads(req.body))
|
||||
|
||||
def test_detach_interface_with_invalid_state(self):
|
||||
def fake_detach_interface_invalid_state(*args, **kwargs):
|
||||
raise exception.InstanceInvalidState(
|
||||
instance_uuid='', attr='', state='',
|
||||
method='detach_interface')
|
||||
|
||||
self.stubs.Set(compute_api.API, 'detach_interface',
|
||||
fake_detach_interface_invalid_state)
|
||||
attachments = attach_interfaces.InterfaceAttachmentController()
|
||||
req = webob.Request.blank('/v2/fake/os-interfaces/attach')
|
||||
req.method = 'DELETE'
|
||||
req.body = jsonutils.dumps({})
|
||||
req.headers['content-type'] = 'application/json'
|
||||
req.environ['nova.context'] = self.context
|
||||
self.assertRaises(exc.HTTPConflict,
|
||||
attachments.delete,
|
||||
req,
|
||||
FAKE_UUID1,
|
||||
FAKE_NET_ID1)
|
||||
|
||||
|
||||
class InterfaceAttachTestsWithMock(test.NoDBTestCase):
|
||||
def setUp(self):
|
||||
|
||||
@@ -376,6 +376,47 @@ class InterfaceAttachTests(test.NoDBTestCase):
|
||||
param = {'fixed_ips': 'non_array'}
|
||||
self._test_attach_interface_with_invalid_parameter(param)
|
||||
|
||||
def test_attach_interface_with_invalid_state(self):
|
||||
def fake_attach_interface_invalid_state(*args, **kwargs):
|
||||
raise exception.InstanceInvalidState(
|
||||
instance_uuid='', attr='', state='',
|
||||
method='attach_interface')
|
||||
|
||||
self.stubs.Set(compute_api.API, 'attach_interface',
|
||||
fake_attach_interface_invalid_state)
|
||||
attachments = attach_interfaces.InterfaceAttachmentController()
|
||||
req = webob.Request.blank(
|
||||
'/v3/servers/fake/os-attach-interfaces/attach')
|
||||
req.method = 'POST'
|
||||
req.body = jsonutils.dumps({'interface_attachment':
|
||||
{'net_id': FAKE_NET_ID1}})
|
||||
req.headers['content-type'] = 'application/json'
|
||||
req.environ['nova.context'] = self.context
|
||||
self.assertRaises(exc.HTTPConflict,
|
||||
attachments.create, req, FAKE_UUID1,
|
||||
body=jsonutils.loads(req.body))
|
||||
|
||||
def test_detach_interface_with_invalid_state(self):
|
||||
def fake_detach_interface_invalid_state(*args, **kwargs):
|
||||
raise exception.InstanceInvalidState(
|
||||
instance_uuid='', attr='', state='',
|
||||
method='detach_interface')
|
||||
|
||||
self.stubs.Set(compute_api.API, 'detach_interface',
|
||||
fake_detach_interface_invalid_state)
|
||||
attachments = attach_interfaces.InterfaceAttachmentController()
|
||||
req = webob.Request.blank(
|
||||
'/v3/servers/fake/os-attach-interfaces/delete')
|
||||
req.method = 'DELETE'
|
||||
req.body = jsonutils.dumps({})
|
||||
req.headers['content-type'] = 'application/json'
|
||||
req.environ['nova.context'] = self.context
|
||||
self.assertRaises(exc.HTTPConflict,
|
||||
attachments.delete,
|
||||
req,
|
||||
FAKE_UUID1,
|
||||
FAKE_NET_ID1)
|
||||
|
||||
|
||||
class InterfaceAttachTestsWithMock(test.NoDBTestCase):
|
||||
def setUp(self):
|
||||
|
||||
@@ -2214,6 +2214,36 @@ class _ComputeAPIUnitTestMixIn(object):
|
||||
|
||||
do_test()
|
||||
|
||||
def _test_attach_interface_invalid_state(self, state):
|
||||
instance = self._create_instance_obj(
|
||||
params={'vm_state': state})
|
||||
self.assertRaises(exception.InstanceInvalidState,
|
||||
self.compute_api.attach_interface,
|
||||
self.context, instance, '', '', '', [])
|
||||
|
||||
def test_attach_interface_invalid_state(self):
|
||||
for state in [vm_states.BUILDING, vm_states.DELETED,
|
||||
vm_states.ERROR, vm_states.RESCUED,
|
||||
vm_states.RESIZED, vm_states.SOFT_DELETED,
|
||||
vm_states.SUSPENDED, vm_states.SHELVED,
|
||||
vm_states.SHELVED_OFFLOADED]:
|
||||
self._test_attach_interface_invalid_state(state)
|
||||
|
||||
def _test_detach_interface_invalid_state(self, state):
|
||||
instance = self._create_instance_obj(
|
||||
params={'vm_state': state})
|
||||
self.assertRaises(exception.InstanceInvalidState,
|
||||
self.compute_api.detach_interface,
|
||||
self.context, instance, '', '', '', [])
|
||||
|
||||
def test_detach_interface_invalid_state(self):
|
||||
for state in [vm_states.BUILDING, vm_states.DELETED,
|
||||
vm_states.ERROR, vm_states.RESCUED,
|
||||
vm_states.RESIZED, vm_states.SOFT_DELETED,
|
||||
vm_states.SUSPENDED, vm_states.SHELVED,
|
||||
vm_states.SHELVED_OFFLOADED]:
|
||||
self._test_detach_interface_invalid_state(state)
|
||||
|
||||
|
||||
class ComputeAPIUnitTestCase(_ComputeAPIUnitTestMixIn, test.NoDBTestCase):
|
||||
def setUp(self):
|
||||
|
||||
@@ -59,6 +59,9 @@ policy_data = """
|
||||
"compute:attach_volume": "",
|
||||
"compute:detach_volume": "",
|
||||
|
||||
"compute:attach_interface": "",
|
||||
"compute:detach_interface": "",
|
||||
|
||||
"compute:set_admin_password": "",
|
||||
|
||||
"compute:rescue": "",
|
||||
|
||||
Reference in New Issue
Block a user