Change v3 attach_interface to v2.1
This patch changes v3 attach_interface API to v2.1 and makes v2 unit tests share between v2 and v2.1. The differences between v2 and v3 are described on the wiki page https://wiki.openstack.org/wiki/NovaAPIv2tov3. Partially implements blueprint v2-on-v3-api Change-Id: If18676604edc8fea41d7888eb6546245163e91c2
This commit is contained in:
parent
7fb7a2cbca
commit
69df608fbe
@ -1,5 +1,5 @@
|
||||
{
|
||||
"interface_attachment": {
|
||||
"interfaceAttachment": {
|
||||
"port_id": "ce531f90-199f-48c0-816c-13e38010b442"
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"interface_attachment": {
|
||||
"interfaceAttachment": {
|
||||
"fixed_ips": [
|
||||
{
|
||||
"ip_address": "192.168.1.3",
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"interface_attachments": [
|
||||
"interfaceAttachments": [
|
||||
{
|
||||
"fixed_ips": [
|
||||
{
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"interface_attachment": {
|
||||
"interfaceAttachment": {
|
||||
"fixed_ips": [
|
||||
{
|
||||
"ip_address": "192.168.1.3",
|
||||
|
@ -77,7 +77,7 @@ class InterfaceAttachmentController(object):
|
||||
if port_info['port']['device_id'] != server_id:
|
||||
raise exc.HTTPNotFound()
|
||||
|
||||
return {'interface_attachment': _translate_interface_attachment_view(
|
||||
return {'interfaceAttachment': _translate_interface_attachment_view(
|
||||
port_info['port'])}
|
||||
|
||||
@extensions.expected_errors((400, 404, 409, 500, 501))
|
||||
@ -91,7 +91,7 @@ class InterfaceAttachmentController(object):
|
||||
port_id = None
|
||||
req_ip = None
|
||||
if body:
|
||||
attachment = body['interface_attachment']
|
||||
attachment = body['interfaceAttachment']
|
||||
network_id = attachment.get('net_id', None)
|
||||
port_id = attachment.get('port_id', None)
|
||||
try:
|
||||
@ -177,7 +177,7 @@ class InterfaceAttachmentController(object):
|
||||
ports = data.get('ports', [])
|
||||
results = [entity_maker(port) for port in ports]
|
||||
|
||||
return {'interface_attachments': results}
|
||||
return {'interfaceAttachments': results}
|
||||
|
||||
|
||||
class AttachInterfaces(extensions.V3APIExtensionBase):
|
||||
|
@ -15,7 +15,7 @@
|
||||
create = {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'interface_attachment': {
|
||||
'interfaceAttachment': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'net_id': {
|
||||
|
@ -16,7 +16,10 @@
|
||||
import mock
|
||||
from oslo.config import cfg
|
||||
|
||||
from nova.api.openstack.compute.contrib import attach_interfaces
|
||||
from nova.api.openstack.compute.contrib import attach_interfaces \
|
||||
as attach_interfaces_v2
|
||||
from nova.api.openstack.compute.plugins.v3 import attach_interfaces \
|
||||
as attach_interfaces_v3
|
||||
from nova.compute import api as compute_api
|
||||
from nova import context
|
||||
from nova import exception
|
||||
@ -41,6 +44,7 @@ FAKE_PORT_ID3 = '33333333-3333-3333-3333-333333333333'
|
||||
FAKE_NET_ID1 = '44444444-4444-4444-4444-444444444444'
|
||||
FAKE_NET_ID2 = '55555555-5555-5555-5555-555555555555'
|
||||
FAKE_NET_ID3 = '66666666-6666-6666-6666-666666666666'
|
||||
FAKE_BAD_NET_ID = '00000000-0000-0000-0000-000000000000'
|
||||
|
||||
port_data1 = {
|
||||
"id": FAKE_PORT_ID1,
|
||||
@ -96,7 +100,7 @@ def fake_attach_interface(self, context, instance, network_id, port_id,
|
||||
# if no network_id is given when add a port to an instance, use the
|
||||
# first default network.
|
||||
network_id = fake_networks[0]
|
||||
if network_id == 'bad_id':
|
||||
if network_id == FAKE_BAD_NET_ID:
|
||||
raise exception.NetworkNotFound(network_id=network_id)
|
||||
if not port_id:
|
||||
port_id = ports[fake_networks.index(network_id)]['id']
|
||||
@ -118,9 +122,12 @@ def fake_get_instance(self, *args, **kwargs):
|
||||
return {}
|
||||
|
||||
|
||||
class InterfaceAttachTests(test.NoDBTestCase):
|
||||
class InterfaceAttachTestsV21(test.NoDBTestCase):
|
||||
url = '/v3/os-interfaces'
|
||||
controller_cls = attach_interfaces_v3.InterfaceAttachmentController
|
||||
|
||||
def setUp(self):
|
||||
super(InterfaceAttachTests, self).setUp()
|
||||
super(InterfaceAttachTestsV21, self).setUp()
|
||||
self.flags(auth_strategy=None, group='neutron')
|
||||
self.flags(url='http://anyhost/', group='neutron')
|
||||
self.flags(url_timeout=30, group='neutron')
|
||||
@ -135,73 +142,69 @@ class InterfaceAttachTests(test.NoDBTestCase):
|
||||
'port_state': port_data1['status'],
|
||||
'fixed_ips': port_data1['fixed_ips'],
|
||||
}}
|
||||
self.attachments = self.controller_cls()
|
||||
|
||||
@mock.patch.object(compute_api.API, 'get',
|
||||
side_effect=exception.InstanceNotFound(instance_id=''))
|
||||
def _test_instance_not_found(self, url, func, params, mock_get,
|
||||
def _test_instance_not_found(self, url, func, args, mock_get, kwargs=None,
|
||||
method='GET'):
|
||||
req = webob.Request.blank(url)
|
||||
req.method = method
|
||||
req.headers['content-type'] = 'application/json'
|
||||
req.environ['nova.context'] = self.context
|
||||
self.assertRaises(exc.HTTPNotFound, func, req, *params)
|
||||
if not kwargs:
|
||||
kwargs = {}
|
||||
self.assertRaises(exc.HTTPNotFound, func, req, *args, **kwargs)
|
||||
|
||||
def test_show_instance_not_found(self):
|
||||
attachments = attach_interfaces.InterfaceAttachmentController()
|
||||
self._test_instance_not_found('/v2/fake/os-interfaces/fake',
|
||||
attachments.show, ('fake', 'fake'))
|
||||
self._test_instance_not_found(self.url + 'fake',
|
||||
self.attachments.show, ('fake', 'fake'))
|
||||
|
||||
def test_index_instance_not_found(self):
|
||||
attachments = attach_interfaces.InterfaceAttachmentController()
|
||||
self._test_instance_not_found('/v2/fake/os-interfaces',
|
||||
attachments.index, ('fake', ))
|
||||
self._test_instance_not_found(self.url,
|
||||
self.attachments.index, ('fake', ))
|
||||
|
||||
def test_delete_instance_not_found(self):
|
||||
attachments = attach_interfaces.InterfaceAttachmentController()
|
||||
self._test_instance_not_found('/v2/fake/os-interfaces/fake',
|
||||
attachments.delete, ('fake', 'fake'),
|
||||
method='DELETE')
|
||||
def test_detach_interface_instance_not_found(self):
|
||||
self._test_instance_not_found(self.url + '/fake',
|
||||
self.attachments.delete,
|
||||
('fake', 'fake'), method='DELETE')
|
||||
|
||||
def test_create_instance_not_found(self):
|
||||
attachments = attach_interfaces.InterfaceAttachmentController()
|
||||
self._test_instance_not_found('/v2/fake/os-interfaces',
|
||||
attachments.create,
|
||||
('fake', {'interfaceAttachment': {}}),
|
||||
'POST')
|
||||
def test_attach_interface_instance_not_found(self):
|
||||
self._test_instance_not_found(
|
||||
'/v2/fake/os-interfaces', self.attachments.create, ('fake', ),
|
||||
kwargs={'body': {'interfaceAttachment': {}}}, method='POST')
|
||||
|
||||
def test_show(self):
|
||||
attachments = attach_interfaces.InterfaceAttachmentController()
|
||||
req = webob.Request.blank('/v2/fake/os-interfaces/show')
|
||||
req = webob.Request.blank(self.url + '/show')
|
||||
req.method = 'POST'
|
||||
req.body = jsonutils.dumps({})
|
||||
req.headers['content-type'] = 'application/json'
|
||||
req.environ['nova.context'] = self.context
|
||||
|
||||
result = attachments.show(req, FAKE_UUID1, FAKE_PORT_ID1)
|
||||
result = self.attachments.show(req, FAKE_UUID1, FAKE_PORT_ID1)
|
||||
self.assertEqual(self.expected_show, result)
|
||||
|
||||
def test_show_invalid(self):
|
||||
attachments = attach_interfaces.InterfaceAttachmentController()
|
||||
req = webob.Request.blank('/v2/fake/os-interfaces/show')
|
||||
req = webob.Request.blank(self.url + '/show')
|
||||
req.method = 'POST'
|
||||
req.body = jsonutils.dumps({})
|
||||
req.headers['content-type'] = 'application/json'
|
||||
req.environ['nova.context'] = self.context
|
||||
|
||||
self.assertRaises(exc.HTTPNotFound,
|
||||
attachments.show, req, FAKE_UUID2, FAKE_PORT_ID1)
|
||||
self.attachments.show, req, FAKE_UUID2,
|
||||
FAKE_PORT_ID1)
|
||||
|
||||
def test_delete(self):
|
||||
self.stubs.Set(compute_api.API, 'detach_interface',
|
||||
fake_detach_interface)
|
||||
attachments = attach_interfaces.InterfaceAttachmentController()
|
||||
req = webob.Request.blank('/v2/fake/os-interfaces/delete')
|
||||
req = webob.Request.blank(self.url + '/delete')
|
||||
req.method = 'DELETE'
|
||||
req.body = jsonutils.dumps({})
|
||||
req.headers['content-type'] = 'application/json'
|
||||
req.environ['nova.context'] = self.context
|
||||
|
||||
result = attachments.delete(req, FAKE_UUID1, FAKE_PORT_ID1)
|
||||
result = self.attachments.delete(req, FAKE_UUID1, FAKE_PORT_ID1)
|
||||
self.assertEqual('202 Accepted', result.status)
|
||||
|
||||
def test_detach_interface_instance_locked(self):
|
||||
@ -212,15 +215,14 @@ class InterfaceAttachTests(test.NoDBTestCase):
|
||||
self.stubs.Set(compute_api.API,
|
||||
'detach_interface',
|
||||
fake_detach_interface_from_locked_server)
|
||||
attachments = attach_interfaces.InterfaceAttachmentController()
|
||||
req = webob.Request.blank('/v2/fake/os-interfaces/delete')
|
||||
req = webob.Request.blank(self.url + '/delete')
|
||||
req.method = 'POST'
|
||||
req.body = jsonutils.dumps({})
|
||||
req.headers['content-type'] = 'application/json'
|
||||
req.environ['nova.context'] = self.context
|
||||
|
||||
self.assertRaises(exc.HTTPConflict,
|
||||
attachments.delete,
|
||||
self.attachments.delete,
|
||||
req,
|
||||
FAKE_UUID1,
|
||||
FAKE_PORT_ID1)
|
||||
@ -228,15 +230,14 @@ class InterfaceAttachTests(test.NoDBTestCase):
|
||||
def test_delete_interface_not_found(self):
|
||||
self.stubs.Set(compute_api.API, 'detach_interface',
|
||||
fake_detach_interface)
|
||||
attachments = attach_interfaces.InterfaceAttachmentController()
|
||||
req = webob.Request.blank('/v2/fake/os-interfaces/delete')
|
||||
req = webob.Request.blank(self.url + '/delete')
|
||||
req.method = 'DELETE'
|
||||
req.body = jsonutils.dumps({})
|
||||
req.headers['content-type'] = 'application/json'
|
||||
req.environ['nova.context'] = self.context
|
||||
|
||||
self.assertRaises(exc.HTTPNotFound,
|
||||
attachments.delete,
|
||||
self.attachments.delete,
|
||||
req,
|
||||
FAKE_UUID1,
|
||||
'invaid-port-id')
|
||||
@ -249,55 +250,53 @@ class InterfaceAttachTests(test.NoDBTestCase):
|
||||
self.stubs.Set(compute_api.API,
|
||||
'attach_interface',
|
||||
fake_attach_interface_to_locked_server)
|
||||
attachments = attach_interfaces.InterfaceAttachmentController()
|
||||
req = webob.Request.blank('/v2/fake/os-interfaces/attach')
|
||||
req = webob.Request.blank(self.url + '/attach')
|
||||
req.method = 'POST'
|
||||
req.body = jsonutils.dumps({})
|
||||
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))
|
||||
self.attachments.create, req, FAKE_UUID1,
|
||||
body=jsonutils.loads(req.body))
|
||||
|
||||
def test_attach_interface_without_network_id(self):
|
||||
self.stubs.Set(compute_api.API, 'attach_interface',
|
||||
fake_attach_interface)
|
||||
attachments = attach_interfaces.InterfaceAttachmentController()
|
||||
req = webob.Request.blank('/v2/fake/os-interfaces/attach')
|
||||
req = webob.Request.blank(self.url + '/attach')
|
||||
req.method = 'POST'
|
||||
req.body = jsonutils.dumps({})
|
||||
req.headers['content-type'] = 'application/json'
|
||||
req.environ['nova.context'] = self.context
|
||||
result = attachments.create(req, FAKE_UUID1, jsonutils.loads(req.body))
|
||||
result = self.attachments.create(req, FAKE_UUID1,
|
||||
body=jsonutils.loads(req.body))
|
||||
self.assertEqual(result['interfaceAttachment']['net_id'],
|
||||
FAKE_NET_ID1)
|
||||
|
||||
def test_attach_interface_with_network_id(self):
|
||||
self.stubs.Set(compute_api.API, 'attach_interface',
|
||||
fake_attach_interface)
|
||||
attachments = attach_interfaces.InterfaceAttachmentController()
|
||||
req = webob.Request.blank('/v2/fake/os-interfaces/attach')
|
||||
req = webob.Request.blank(self.url + '/attach')
|
||||
req.method = 'POST'
|
||||
req.body = jsonutils.dumps({'interfaceAttachment':
|
||||
{'net_id': FAKE_NET_ID2}})
|
||||
req.headers['content-type'] = 'application/json'
|
||||
req.environ['nova.context'] = self.context
|
||||
result = attachments.create(req, FAKE_UUID1, jsonutils.loads(req.body))
|
||||
result = self.attachments.create(req, FAKE_UUID1,
|
||||
body=jsonutils.loads(req.body))
|
||||
self.assertEqual(result['interfaceAttachment']['net_id'],
|
||||
FAKE_NET_ID2)
|
||||
|
||||
def _attach_interface_bad_request_case(self, body):
|
||||
self.stubs.Set(compute_api.API, 'attach_interface',
|
||||
fake_attach_interface)
|
||||
attachments = attach_interfaces.InterfaceAttachmentController()
|
||||
req = webob.Request.blank('/v2/fake/os-interfaces/attach')
|
||||
req = webob.Request.blank(self.url + '/attach')
|
||||
req.method = 'POST'
|
||||
req.body = jsonutils.dumps(body)
|
||||
req.headers['content-type'] = 'application/json'
|
||||
req.environ['nova.context'] = self.context
|
||||
self.assertRaises(exc.HTTPBadRequest,
|
||||
attachments.create, req, FAKE_UUID1,
|
||||
jsonutils.loads(req.body))
|
||||
self.attachments.create, req, FAKE_UUID1,
|
||||
body=jsonutils.loads(req.body))
|
||||
|
||||
def test_attach_interface_with_port_and_network_id(self):
|
||||
body = {
|
||||
@ -311,7 +310,7 @@ class InterfaceAttachTests(test.NoDBTestCase):
|
||||
def test_attach_interface_with_invalid_data(self):
|
||||
body = {
|
||||
'interfaceAttachment': {
|
||||
'net_id': 'bad_id'
|
||||
'net_id': FAKE_BAD_NET_ID
|
||||
}
|
||||
}
|
||||
self._attach_interface_bad_request_case(body)
|
||||
@ -324,16 +323,15 @@ class InterfaceAttachTests(test.NoDBTestCase):
|
||||
|
||||
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 = webob.Request.blank(self.url + '/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))
|
||||
self.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):
|
||||
@ -343,14 +341,13 @@ class InterfaceAttachTests(test.NoDBTestCase):
|
||||
|
||||
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 = webob.Request.blank(self.url + '/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,
|
||||
self.attachments.delete,
|
||||
req,
|
||||
FAKE_UUID1,
|
||||
FAKE_NET_ID1)
|
||||
@ -363,16 +360,53 @@ class InterfaceAttachTests(test.NoDBTestCase):
|
||||
get_mock.side_effect = fake_get_instance
|
||||
attach_mock.side_effect = exception.FixedIpAlreadyInUse(
|
||||
address='10.0.2.2', instance_uuid=FAKE_UUID1)
|
||||
attachments = attach_interfaces.InterfaceAttachmentController()
|
||||
req = webob.Request.blank('/v2/fake/os-interfaces/attach')
|
||||
req = webob.Request.blank(self.url + '/attach')
|
||||
req.method = 'POST'
|
||||
req.body = jsonutils.dumps({})
|
||||
req.headers['content-type'] = 'application/json'
|
||||
req.environ['nova.context'] = self.context
|
||||
self.assertRaises(exc.HTTPBadRequest,
|
||||
attachments.create, req, FAKE_UUID1,
|
||||
jsonutils.loads(req.body))
|
||||
self.attachments.create, req, FAKE_UUID1,
|
||||
body=jsonutils.loads(req.body))
|
||||
attach_mock.assert_called_once_with(self.context, {}, None, None, None)
|
||||
get_mock.assert_called_once_with(self.context, FAKE_UUID1,
|
||||
want_objects=True,
|
||||
expected_attrs=None)
|
||||
|
||||
def _test_attach_interface_with_invalid_parameter(self, param):
|
||||
self.stubs.Set(compute_api.API, 'attach_interface',
|
||||
fake_attach_interface)
|
||||
req = webob.Request.blank(self.url + '/attach')
|
||||
req.method = 'POST'
|
||||
req.body = jsonutils.dumps({'interface_attachment': param})
|
||||
req.headers['content-type'] = 'application/json'
|
||||
req.environ['nova.context'] = self.context
|
||||
self.assertRaises(exception.ValidationError,
|
||||
self.attachments.create, req, FAKE_UUID1,
|
||||
body=jsonutils.loads(req.body))
|
||||
|
||||
def test_attach_interface_instance_with_non_uuid_net_id(self):
|
||||
param = {'net_id': 'non_uuid'}
|
||||
self._test_attach_interface_with_invalid_parameter(param)
|
||||
|
||||
def test_attach_interface_instance_with_non_uuid_port_id(self):
|
||||
param = {'port_id': 'non_uuid'}
|
||||
self._test_attach_interface_with_invalid_parameter(param)
|
||||
|
||||
def test_attach_interface_instance_with_non_array_fixed_ips(self):
|
||||
param = {'fixed_ips': 'non_array'}
|
||||
self._test_attach_interface_with_invalid_parameter(param)
|
||||
|
||||
|
||||
class InterfaceAttachTestsV2(InterfaceAttachTestsV21):
|
||||
url = '/v2/fake/os-interfaces'
|
||||
controller_cls = attach_interfaces_v2.InterfaceAttachmentController
|
||||
|
||||
def test_attach_interface_instance_with_non_uuid_net_id(self):
|
||||
pass
|
||||
|
||||
def test_attach_interface_instance_with_non_uuid_port_id(self):
|
||||
pass
|
||||
|
||||
def test_attach_interface_instance_with_non_array_fixed_ips(self):
|
||||
pass
|
||||
|
@ -1,450 +0,0 @@
|
||||
# Copyright 2012 SINA Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import mock
|
||||
from oslo.config import cfg
|
||||
|
||||
from nova.api.openstack.compute.plugins.v3 import attach_interfaces
|
||||
from nova.compute import api as compute_api
|
||||
from nova import context
|
||||
from nova import exception
|
||||
from nova.network import api as network_api
|
||||
from nova.openstack.common import jsonutils
|
||||
from nova import test
|
||||
from nova.tests import fake_network_cache_model
|
||||
|
||||
import webob
|
||||
from webob import exc
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
FAKE_UUID1 = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'
|
||||
FAKE_UUID2 = 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb'
|
||||
|
||||
FAKE_PORT_ID1 = '11111111-1111-1111-1111-111111111111'
|
||||
FAKE_PORT_ID2 = '22222222-2222-2222-2222-222222222222'
|
||||
FAKE_PORT_ID3 = '33333333-3333-3333-3333-333333333333'
|
||||
|
||||
FAKE_NET_ID1 = '44444444-4444-4444-4444-444444444444'
|
||||
FAKE_NET_ID2 = '55555555-5555-5555-5555-555555555555'
|
||||
FAKE_NET_ID3 = '66666666-6666-6666-6666-666666666666'
|
||||
|
||||
port_data1 = {
|
||||
"id": FAKE_PORT_ID1,
|
||||
"network_id": FAKE_NET_ID1,
|
||||
"admin_state_up": True,
|
||||
"status": "ACTIVE",
|
||||
"mac_address": "aa:aa:aa:aa:aa:aa",
|
||||
"fixed_ips": ["10.0.1.2"],
|
||||
"device_id": FAKE_UUID1,
|
||||
}
|
||||
|
||||
port_data2 = {
|
||||
"id": FAKE_PORT_ID2,
|
||||
"network_id": FAKE_NET_ID2,
|
||||
"admin_state_up": True,
|
||||
"status": "ACTIVE",
|
||||
"mac_address": "bb:bb:bb:bb:bb:bb",
|
||||
"fixed_ips": ["10.0.2.2"],
|
||||
"device_id": FAKE_UUID1,
|
||||
}
|
||||
|
||||
port_data3 = {
|
||||
"id": FAKE_PORT_ID3,
|
||||
"network_id": FAKE_NET_ID3,
|
||||
"admin_state_up": True,
|
||||
"status": "ACTIVE",
|
||||
"mac_address": "bb:bb:bb:bb:bb:bb",
|
||||
"fixed_ips": ["10.0.2.2"],
|
||||
"device_id": '',
|
||||
}
|
||||
|
||||
fake_networks = [FAKE_NET_ID1, FAKE_NET_ID2]
|
||||
ports = [port_data1, port_data2, port_data3]
|
||||
|
||||
|
||||
def fake_list_ports(self, *args, **kwargs):
|
||||
result = []
|
||||
for port in ports:
|
||||
if port['device_id'] == kwargs['device_id']:
|
||||
result.append(port)
|
||||
return {'ports': result}
|
||||
|
||||
|
||||
def fake_show_port(self, context, port_id, **kwargs):
|
||||
for port in ports:
|
||||
if port['id'] == port_id:
|
||||
return {'port': port}
|
||||
|
||||
|
||||
def fake_attach_interface(self, context, instance, network_id, port_id,
|
||||
requested_ip='192.168.1.3'):
|
||||
if not network_id:
|
||||
# if no network_id is given when add a port to an instance, use the
|
||||
# first default network.
|
||||
network_id = fake_networks[0]
|
||||
if network_id == 'bad_id':
|
||||
raise exception.NetworkNotFound(network_id=network_id)
|
||||
if not port_id:
|
||||
port_id = ports[fake_networks.index(network_id)]['id']
|
||||
vif = fake_network_cache_model.new_vif()
|
||||
vif['id'] = port_id
|
||||
vif['network']['id'] = network_id
|
||||
vif['network']['subnets'][0]['ips'][0]['address'] = requested_ip
|
||||
return vif
|
||||
|
||||
|
||||
def fake_detach_interface(self, context, instance, port_id):
|
||||
for port in ports:
|
||||
if port['id'] == port_id:
|
||||
return
|
||||
raise exception.PortNotFound(port_id=port_id)
|
||||
|
||||
|
||||
def fake_get_instance(self, *args, **kwargs):
|
||||
return {}
|
||||
|
||||
|
||||
class InterfaceAttachTests(test.NoDBTestCase):
|
||||
def setUp(self):
|
||||
super(InterfaceAttachTests, self).setUp()
|
||||
self.flags(auth_strategy=None, group='neutron')
|
||||
self.flags(url='http://anyhost/', group='neutron')
|
||||
self.flags(url_timeout=30, group='neutron')
|
||||
self.stubs.Set(network_api.API, 'show_port', fake_show_port)
|
||||
self.stubs.Set(network_api.API, 'list_ports', fake_list_ports)
|
||||
self.stubs.Set(compute_api.API, 'get', fake_get_instance)
|
||||
self.context = context.get_admin_context()
|
||||
self.expected_show = {'interface_attachment':
|
||||
{'net_id': FAKE_NET_ID1,
|
||||
'port_id': FAKE_PORT_ID1,
|
||||
'mac_addr': port_data1['mac_address'],
|
||||
'port_state': port_data1['status'],
|
||||
'fixed_ips': port_data1['fixed_ips'],
|
||||
}}
|
||||
|
||||
def test_item_instance_not_found(self):
|
||||
attachments = attach_interfaces.InterfaceAttachmentController()
|
||||
req = webob.Request.blank('/v3/servers/fake/os-attach-interfaces/')
|
||||
req.method = 'GET'
|
||||
req.body = jsonutils.dumps({})
|
||||
req.headers['content-type'] = 'application/json'
|
||||
req.environ['nova.context'] = self.context
|
||||
|
||||
def fake_get_instance_exception(self, context, instance_uuid,
|
||||
**kwargs):
|
||||
raise exception.InstanceNotFound(instance_id=instance_uuid)
|
||||
|
||||
self.stubs.Set(compute_api.API, 'get', fake_get_instance_exception)
|
||||
self.assertRaises(exc.HTTPNotFound, attachments.index,
|
||||
req, 'fake')
|
||||
|
||||
def test_show(self):
|
||||
attachments = attach_interfaces.InterfaceAttachmentController()
|
||||
req = webob.Request.blank('/v3/servers/fake/os-attach-interfaces/show')
|
||||
req.method = 'POST'
|
||||
req.body = jsonutils.dumps({})
|
||||
req.headers['content-type'] = 'application/json'
|
||||
req.environ['nova.context'] = self.context
|
||||
|
||||
result = attachments.show(req, FAKE_UUID1, FAKE_PORT_ID1)
|
||||
self.assertEqual(self.expected_show, result)
|
||||
|
||||
def test_show_instance_not_found(self):
|
||||
attachments = attach_interfaces.InterfaceAttachmentController()
|
||||
req = webob.Request.blank('/v3/servers/fake/os-attach-interfaces/show')
|
||||
req.method = 'POST'
|
||||
req.body = jsonutils.dumps({})
|
||||
req.headers['content-type'] = 'application/json'
|
||||
req.environ['nova.context'] = self.context
|
||||
|
||||
def fake_get_instance_exception(self, context, instance_uuid,
|
||||
**kwargs):
|
||||
raise exception.InstanceNotFound(instance_id=instance_uuid)
|
||||
|
||||
self.stubs.Set(compute_api.API, 'get', fake_get_instance_exception)
|
||||
self.assertRaises(exc.HTTPNotFound, attachments.show,
|
||||
req, 'fake', FAKE_PORT_ID1)
|
||||
|
||||
def test_show_invalid(self):
|
||||
attachments = attach_interfaces.InterfaceAttachmentController()
|
||||
req = webob.Request.blank('/v3/servers/fake/os-attach-interfaces/show')
|
||||
req.method = 'POST'
|
||||
req.body = jsonutils.dumps({})
|
||||
req.headers['content-type'] = 'application/json'
|
||||
req.environ['nova.context'] = self.context
|
||||
|
||||
self.assertRaises(exc.HTTPNotFound,
|
||||
attachments.show, req, FAKE_UUID2, FAKE_PORT_ID1)
|
||||
|
||||
def test_delete(self):
|
||||
self.stubs.Set(compute_api.API, 'detach_interface',
|
||||
fake_detach_interface)
|
||||
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
|
||||
|
||||
result = attachments.delete(req, FAKE_UUID1, FAKE_PORT_ID1)
|
||||
self.assertEqual('202 Accepted', result.status)
|
||||
|
||||
def test_detach_interface_instance_locked(self):
|
||||
def fake_detach_interface_from_locked_server(self, context,
|
||||
instance, port_id):
|
||||
raise exception.InstanceIsLocked(instance_uuid=FAKE_UUID1)
|
||||
|
||||
self.stubs.Set(compute_api.API,
|
||||
'detach_interface',
|
||||
fake_detach_interface_from_locked_server)
|
||||
attachments = attach_interfaces.InterfaceAttachmentController()
|
||||
req = webob.Request.blank(
|
||||
'/v3/servers/fake/os-attach-interfaces/delete')
|
||||
req.method = 'POST'
|
||||
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_PORT_ID1)
|
||||
|
||||
def test_delete_interface_not_found(self):
|
||||
self.stubs.Set(compute_api.API, 'detach_interface',
|
||||
fake_detach_interface)
|
||||
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.HTTPNotFound,
|
||||
attachments.delete,
|
||||
req,
|
||||
FAKE_UUID1,
|
||||
'invaid-port-id')
|
||||
|
||||
def test_delete_instance_not_found(self):
|
||||
self.stubs.Set(compute_api.API, 'detach_interface',
|
||||
fake_detach_interface)
|
||||
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
|
||||
|
||||
def fake_get_instance_exception(self, context, instance_uuid,
|
||||
**kwargs):
|
||||
raise exception.InstanceNotFound(instance_id=instance_uuid)
|
||||
|
||||
self.stubs.Set(compute_api.API, 'get', fake_get_instance_exception)
|
||||
self.assertRaises(exc.HTTPNotFound,
|
||||
attachments.delete,
|
||||
req,
|
||||
'fake',
|
||||
'invaid-port-id')
|
||||
|
||||
def test_attach_interface_instance_locked(self):
|
||||
def fake_attach_interface_to_locked_server(self, context,
|
||||
instance, network_id, port_id, requested_ip):
|
||||
raise exception.InstanceIsLocked(instance_uuid=FAKE_UUID1)
|
||||
|
||||
self.stubs.Set(compute_api.API,
|
||||
'attach_interface',
|
||||
fake_attach_interface_to_locked_server)
|
||||
attachments = attach_interfaces.InterfaceAttachmentController()
|
||||
req = webob.Request.blank(
|
||||
'/v3/servers/fake/os-attach-interfaces/attach')
|
||||
req.method = 'POST'
|
||||
req.body = jsonutils.dumps({})
|
||||
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_attach_interface_without_network_id(self):
|
||||
self.stubs.Set(compute_api.API, 'attach_interface',
|
||||
fake_attach_interface)
|
||||
attachments = attach_interfaces.InterfaceAttachmentController()
|
||||
req = webob.Request.blank(
|
||||
'/v3/servers/fake/os-attach-interfaces/attach')
|
||||
req.method = 'POST'
|
||||
req.body = jsonutils.dumps({})
|
||||
req.headers['content-type'] = 'application/json'
|
||||
req.environ['nova.context'] = self.context
|
||||
result = attachments.create(req, FAKE_UUID1,
|
||||
body=jsonutils.loads(req.body))
|
||||
self.assertEqual(result['interface_attachment']['net_id'],
|
||||
FAKE_NET_ID1)
|
||||
|
||||
def test_attach_interface_with_network_id(self):
|
||||
self.stubs.Set(compute_api.API, 'attach_interface',
|
||||
fake_attach_interface)
|
||||
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_ID2}})
|
||||
req.headers['content-type'] = 'application/json'
|
||||
req.environ['nova.context'] = self.context
|
||||
result = attachments.create(req,
|
||||
FAKE_UUID1, body=jsonutils.loads(req.body))
|
||||
self.assertEqual(result['interface_attachment']['net_id'],
|
||||
FAKE_NET_ID2)
|
||||
|
||||
def test_attach_interface_with_port_and_network_id(self):
|
||||
self.stubs.Set(compute_api.API, 'attach_interface',
|
||||
fake_attach_interface)
|
||||
attachments = attach_interfaces.InterfaceAttachmentController()
|
||||
req = webob.Request.blank(
|
||||
'/v3/servers/fake/os-attach-interfaces/attach')
|
||||
req.method = 'POST'
|
||||
req.body = jsonutils.dumps({'interface_attachment':
|
||||
{'port_id': FAKE_PORT_ID1,
|
||||
'net_id': FAKE_NET_ID2}})
|
||||
req.headers['content-type'] = 'application/json'
|
||||
req.environ['nova.context'] = self.context
|
||||
self.assertRaises(exc.HTTPBadRequest,
|
||||
attachments.create, req, FAKE_UUID1,
|
||||
body=jsonutils.loads(req.body))
|
||||
|
||||
def test_attach_interface_instance_not_found(self):
|
||||
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_ID2}})
|
||||
req.headers['content-type'] = 'application/json'
|
||||
req.environ['nova.context'] = self.context
|
||||
|
||||
def fake_get_instance_exception(self, context, instance_uuid,
|
||||
**kwargs):
|
||||
raise exception.InstanceNotFound(instance_id=instance_uuid)
|
||||
|
||||
self.stubs.Set(compute_api.API, 'get', fake_get_instance_exception)
|
||||
self.assertRaises(exc.HTTPNotFound,
|
||||
attachments.create, req, 'fake',
|
||||
body=jsonutils.loads(req.body))
|
||||
|
||||
def _test_attach_interface_with_invalid_parameter(self, param):
|
||||
self.stubs.Set(compute_api.API, 'attach_interface',
|
||||
fake_attach_interface)
|
||||
attachments = attach_interfaces.InterfaceAttachmentController()
|
||||
req = webob.Request.blank(
|
||||
'/v3/servers/fake/os-attach-interfaces/attach')
|
||||
req.method = 'POST'
|
||||
req.body = jsonutils.dumps({'interface_attachment': param})
|
||||
req.headers['content-type'] = 'application/json'
|
||||
req.environ['nova.context'] = self.context
|
||||
self.assertRaises(exception.ValidationError,
|
||||
attachments.create, req, FAKE_UUID1,
|
||||
body=jsonutils.loads(req.body))
|
||||
|
||||
def test_attach_interface_instance_with_non_uuid_net_id(self):
|
||||
param = {'net_id': 'non_uuid'}
|
||||
self._test_attach_interface_with_invalid_parameter(param)
|
||||
|
||||
def test_attach_interface_instance_with_non_uuid_port_id(self):
|
||||
param = {'port_id': 'non_uuid'}
|
||||
self._test_attach_interface_with_invalid_parameter(param)
|
||||
|
||||
def test_attach_interface_instance_with_non_array_fixed_ips(self):
|
||||
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):
|
||||
super(InterfaceAttachTestsWithMock, self).setUp()
|
||||
self.flags(auth_strategy=None, group='neutron')
|
||||
self.flags(url='http://anyhost/', group='neutron')
|
||||
self.flags(url_timeout=30, group='neutron')
|
||||
self.context = context.get_admin_context()
|
||||
|
||||
@mock.patch.object(compute_api.API, 'get')
|
||||
@mock.patch.object(compute_api.API, 'attach_interface')
|
||||
def test_attach_interface_fixed_ip_already_in_use(self,
|
||||
attach_mock,
|
||||
get_mock):
|
||||
get_mock.side_effect = fake_get_instance
|
||||
attach_mock.side_effect = exception.FixedIpAlreadyInUse(
|
||||
address='10.0.3.2', instance_uuid=FAKE_UUID1)
|
||||
attachments = attach_interfaces.InterfaceAttachmentController()
|
||||
req = webob.Request.blank(
|
||||
'/v3/servers/fake/os-attach-interfaces/attach')
|
||||
req.method = 'POST'
|
||||
req.body = jsonutils.dumps({})
|
||||
req.headers['content-type'] = 'application/json'
|
||||
req.environ['nova.context'] = self.context
|
||||
self.assertRaises(exc.HTTPBadRequest,
|
||||
attachments.create, req, FAKE_UUID1,
|
||||
body=jsonutils.loads(req.body))
|
||||
attach_mock.assert_called_once_with(self.context, {}, None, None, None)
|
||||
get_mock.assert_called_once_with(self.context, FAKE_UUID1,
|
||||
want_objects=True,
|
||||
expected_attrs=None)
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"interface_attachment": {
|
||||
"interfaceAttachment": {
|
||||
"port_id": "ce531f90-199f-48c0-816c-13e38010b442"
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"interface_attachment": {
|
||||
"interfaceAttachment": {
|
||||
"fixed_ips": [
|
||||
{
|
||||
"ip_address": "192.168.1.3",
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"interface_attachments": [
|
||||
"interfaceAttachments": [
|
||||
{
|
||||
"fixed_ips": [
|
||||
{
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"interface_attachment": {
|
||||
"interfaceAttachment": {
|
||||
"fixed_ips": [
|
||||
{
|
||||
"ip_address": "192.168.1.3",
|
||||
|
Loading…
x
Reference in New Issue
Block a user