Port os-networks-associate plugin to v2.1(v3) infrastructure
Ports os-networks-associate extension and adapts it to the v2.1/v3 API framework. API behaviour is identical. - unittest code modified to share testing with both v2/v2.1 - Adds expected error decorators for API methods Partially implements blueprint v2-on-v3-api Change-Id: I6ccf9613abf999784c548fb058522ac60db7f052
This commit is contained in:
parent
cc452485c2
commit
0c1ad907c4
@ -0,0 +1,3 @@
|
||||
{
|
||||
"associate_host": "testHost"
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"disassociate_host": null
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"disassociate_project": null
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"disassociate": null
|
||||
}
|
@ -210,6 +210,8 @@
|
||||
"compute_extension:v3:os-networks:view": "",
|
||||
"compute_extension:v3:os-networks:discoverable": "",
|
||||
"compute_extension:networks_associate": "rule:admin_api",
|
||||
"compute_extension:v3:os-networks-associate": "rule:admin_api",
|
||||
"compute_extension:v3:os-networks-associate:discoverable": "",
|
||||
"compute_extension:v3:os-pause-server:discoverable": "",
|
||||
"compute_extension:v3:os-pause-server:pause": "rule:admin_or_owner",
|
||||
"compute_extension:v3:os-pause-server:unpause": "rule:admin_or_owner",
|
||||
|
102
nova/api/openstack/compute/plugins/v3/networks_associate.py
Normal file
102
nova/api/openstack/compute/plugins/v3/networks_associate.py
Normal file
@ -0,0 +1,102 @@
|
||||
# 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.
|
||||
|
||||
from webob import exc
|
||||
|
||||
from nova.api.openstack import extensions
|
||||
from nova.api.openstack import wsgi
|
||||
from nova import exception
|
||||
from nova.i18n import _
|
||||
from nova import network
|
||||
from nova.openstack.common import log as logging
|
||||
|
||||
ALIAS = "os-networks-associate"
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
authorize = extensions.extension_authorizer('compute', 'v3:' + ALIAS)
|
||||
|
||||
|
||||
class NetworkAssociateActionController(wsgi.Controller):
|
||||
"""Network Association API Controller."""
|
||||
|
||||
def __init__(self, network_api=None):
|
||||
self.network_api = network_api or network.API()
|
||||
|
||||
@wsgi.action("disassociate_host")
|
||||
@wsgi.response(202)
|
||||
@extensions.expected_errors((404, 501))
|
||||
def _disassociate_host_only(self, req, id, body):
|
||||
context = req.environ['nova.context']
|
||||
authorize(context)
|
||||
LOG.debug("Disassociating host with network with id %s", id)
|
||||
try:
|
||||
self.network_api.associate(context, id, host=None)
|
||||
except exception.NetworkNotFound:
|
||||
msg = _("Network not found")
|
||||
raise exc.HTTPNotFound(explanation=msg)
|
||||
except NotImplementedError:
|
||||
msg = _('Disassociate host is not implemented by the configured '
|
||||
'Network API')
|
||||
raise exc.HTTPNotImplemented(explanation=msg)
|
||||
|
||||
@wsgi.action("disassociate_project")
|
||||
@wsgi.response(202)
|
||||
@extensions.expected_errors((404, 501))
|
||||
def _disassociate_project_only(self, req, id, body):
|
||||
context = req.environ['nova.context']
|
||||
authorize(context)
|
||||
LOG.debug("Disassociating project with network with id %s", id)
|
||||
try:
|
||||
self.network_api.associate(context, id, project=None)
|
||||
except exception.NetworkNotFound:
|
||||
msg = _("Network not found")
|
||||
raise exc.HTTPNotFound(explanation=msg)
|
||||
except NotImplementedError:
|
||||
msg = _('Disassociate project is not implemented by the '
|
||||
'configured Network API')
|
||||
raise exc.HTTPNotImplemented(explanation=msg)
|
||||
|
||||
@wsgi.action("associate_host")
|
||||
@wsgi.response(202)
|
||||
@extensions.expected_errors((404, 501))
|
||||
def _associate_host(self, req, id, body):
|
||||
context = req.environ['nova.context']
|
||||
authorize(context)
|
||||
|
||||
try:
|
||||
self.network_api.associate(context, id,
|
||||
host=body['associate_host'])
|
||||
except exception.NetworkNotFound:
|
||||
msg = _("Network not found")
|
||||
raise exc.HTTPNotFound(explanation=msg)
|
||||
except NotImplementedError:
|
||||
msg = _('Associate host is not implemented by the configured '
|
||||
'Network API')
|
||||
raise exc.HTTPNotImplemented(explanation=msg)
|
||||
|
||||
|
||||
class NetworksAssociate(extensions.V3APIExtensionBase):
|
||||
"""Network association support."""
|
||||
|
||||
name = "NetworkAssociationSupport"
|
||||
alias = ALIAS
|
||||
version = 1
|
||||
|
||||
def get_controller_extensions(self):
|
||||
extension = extensions.ControllerExtension(
|
||||
self, 'os-networks', NetworkAssociateActionController())
|
||||
|
||||
return [extension]
|
||||
|
||||
def get_resources(self):
|
||||
return []
|
@ -29,6 +29,8 @@ from nova.api.openstack.compute.contrib import networks_associate
|
||||
from nova.api.openstack.compute.contrib import os_networks as networks
|
||||
from nova.api.openstack.compute.contrib import os_tenant_networks as tnet
|
||||
from nova.api.openstack.compute.plugins.v3 import networks as networks_v21
|
||||
from nova.api.openstack.compute.plugins.v3 import networks_associate as \
|
||||
networks_associate_v21
|
||||
from nova.api.openstack.compute.plugins.v3 import tenant_networks as tnet_v21
|
||||
from nova.api.openstack import extensions
|
||||
import nova.context
|
||||
@ -489,27 +491,31 @@ class NetworksTestV2(NetworksTestV21):
|
||||
self.controller.create(req, net)
|
||||
|
||||
|
||||
class NetworksAssociateTest(test.NoDBTestCase):
|
||||
class NetworksAssociateTestV21(test.NoDBTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(NetworksAssociateTest, self).setUp()
|
||||
super(NetworksAssociateTestV21, self).setUp()
|
||||
self.fake_network_api = FakeNetworkAPI()
|
||||
ext_mgr = extensions.ExtensionManager()
|
||||
ext_mgr.extensions = {'os-extended-networks': 'fake'}
|
||||
self.controller = networks.NetworkController(
|
||||
self.fake_network_api,
|
||||
ext_mgr)
|
||||
self.associate_controller = networks_associate\
|
||||
.NetworkAssociateActionController(self.fake_network_api)
|
||||
self._setup()
|
||||
fakes.stub_out_networking(self.stubs)
|
||||
fakes.stub_out_rate_limiting(self.stubs)
|
||||
|
||||
def _setup(self):
|
||||
self.controller = networks.NetworkController(self.fake_network_api)
|
||||
self.associate_controller = networks_associate_v21\
|
||||
.NetworkAssociateActionController(self.fake_network_api)
|
||||
|
||||
def _check_status(self, res, method, code):
|
||||
self.assertEqual(method.wsgi_code, code)
|
||||
|
||||
def test_network_disassociate_host_only(self):
|
||||
uuid = FAKE_NETWORKS[0]['uuid']
|
||||
req = fakes.HTTPRequest.blank('/v2/1234/os-networks/%s/action' % uuid)
|
||||
res = self.associate_controller._disassociate_host_only(
|
||||
req, uuid, {'disassociate_host': None})
|
||||
self.assertEqual(res.status_int, 202)
|
||||
self._check_status(res,
|
||||
self.associate_controller._disassociate_host_only,
|
||||
202)
|
||||
self.assertIsNotNone(self.fake_network_api.networks[0]['project_id'])
|
||||
self.assertIsNone(self.fake_network_api.networks[0]['host'])
|
||||
|
||||
@ -518,16 +524,17 @@ class NetworksAssociateTest(test.NoDBTestCase):
|
||||
req = fakes.HTTPRequest.blank('/v2/1234/os-networks/%s/action' % uuid)
|
||||
res = self.associate_controller._disassociate_project_only(
|
||||
req, uuid, {'disassociate_project': None})
|
||||
self.assertEqual(res.status_int, 202)
|
||||
self._check_status(
|
||||
res, self.associate_controller._disassociate_project_only, 202)
|
||||
self.assertIsNone(self.fake_network_api.networks[0]['project_id'])
|
||||
self.assertIsNotNone(self.fake_network_api.networks[0]['host'])
|
||||
|
||||
def test_network_associate_with_host(self):
|
||||
uuid = FAKE_NETWORKS[1]['uuid']
|
||||
req = fakes.HTTPRequest.blank('/v2/1234/os-networks/%s/action' % uuid)
|
||||
req = fakes.HTTPRequest.blank('/v2/1234//os-networks/%s/action' % uuid)
|
||||
res = self.associate_controller._associate_host(
|
||||
req, uuid, {'associate_host': "TestHost"})
|
||||
self.assertEqual(res.status_int, 202)
|
||||
self._check_status(res, self.associate_controller._associate_host, 202)
|
||||
req = fakes.HTTPRequest.blank('/v2/1234/os-networks/%s' % uuid)
|
||||
req.environ["nova.context"].is_admin = True
|
||||
res_dict = self.controller.show(req, uuid)
|
||||
@ -563,6 +570,21 @@ class NetworksAssociateTest(test.NoDBTestCase):
|
||||
req, uuid, {'disassociate_host': None})
|
||||
|
||||
|
||||
class NetworksAssociateTestV2(NetworksAssociateTestV21):
|
||||
|
||||
def _setup(self):
|
||||
ext_mgr = extensions.ExtensionManager()
|
||||
ext_mgr.extensions = {'os-extended-networks': 'fake'}
|
||||
self.controller = networks.NetworkController(
|
||||
self.fake_network_api,
|
||||
ext_mgr)
|
||||
self.associate_controller = networks_associate\
|
||||
.NetworkAssociateActionController(self.fake_network_api)
|
||||
|
||||
def _check_status(self, res, method, code):
|
||||
self.assertEqual(res.status_int, 202)
|
||||
|
||||
|
||||
class TenantNetworksTestV21(test.NoDBTestCase):
|
||||
ctrlr = tnet_v21.TenantNetworkController
|
||||
|
||||
|
@ -255,6 +255,7 @@ policy_data = """
|
||||
"compute_extension:v3:os-networks": "",
|
||||
"compute_extension:v3:os-networks:view": "",
|
||||
"compute_extension:networks_associate": "",
|
||||
"compute_extension:v3:os-networks-associate": "",
|
||||
"compute_extension:os-tenant-networks": "",
|
||||
"compute_extension:v3:os-tenant-networks": "",
|
||||
"compute_extension:v3:os-pause-server:pause": "",
|
||||
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"associate_host": "%(host)s"
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"disassociate_host": null
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"disassociate_project": null
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"disassociate": null
|
||||
}
|
76
nova/tests/integrated/v3/test_networks_associate.py
Normal file
76
nova/tests/integrated/v3/test_networks_associate.py
Normal file
@ -0,0 +1,76 @@
|
||||
# Copyright 2012 Nebula, Inc.
|
||||
# Copyright 2014 IBM Corp.
|
||||
#
|
||||
# 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.
|
||||
|
||||
from oslo.config import cfg
|
||||
|
||||
from nova.network import api as network_api
|
||||
from nova.tests.integrated.v3 import api_sample_base
|
||||
|
||||
CONF = cfg.CONF
|
||||
CONF.import_opt('osapi_compute_extension',
|
||||
'nova.api.openstack.compute.extensions')
|
||||
|
||||
|
||||
class NetworksAssociateJsonTests(api_sample_base.ApiSampleTestBaseV3):
|
||||
extension_name = "os-networks-associate"
|
||||
extra_extensions_to_load = ["os-networks"]
|
||||
|
||||
_sentinel = object()
|
||||
|
||||
def _get_flags(self):
|
||||
f = super(NetworksAssociateJsonTests, self)._get_flags()
|
||||
f['osapi_compute_extension'] = CONF.osapi_compute_extension[:]
|
||||
# Networks_associate requires Networks to be update
|
||||
f['osapi_compute_extension'].append(
|
||||
'nova.api.openstack.compute.contrib.os_networks.Os_networks')
|
||||
return f
|
||||
|
||||
def setUp(self):
|
||||
super(NetworksAssociateJsonTests, self).setUp()
|
||||
|
||||
def fake_associate(self, context, network_id,
|
||||
host=NetworksAssociateJsonTests._sentinel,
|
||||
project=NetworksAssociateJsonTests._sentinel):
|
||||
return True
|
||||
|
||||
self.stubs.Set(network_api.API, "associate", fake_associate)
|
||||
|
||||
def test_disassociate(self):
|
||||
response = self._do_post('os-networks/1/action',
|
||||
'network-disassociate-req',
|
||||
{})
|
||||
self.assertEqual(response.status_code, 202)
|
||||
self.assertEqual(response.content, "")
|
||||
|
||||
def test_disassociate_host(self):
|
||||
response = self._do_post('os-networks/1/action',
|
||||
'network-disassociate-host-req',
|
||||
{})
|
||||
self.assertEqual(response.status_code, 202)
|
||||
self.assertEqual(response.content, "")
|
||||
|
||||
def test_disassociate_project(self):
|
||||
response = self._do_post('os-networks/1/action',
|
||||
'network-disassociate-project-req',
|
||||
{})
|
||||
self.assertEqual(response.status_code, 202)
|
||||
self.assertEqual(response.content, "")
|
||||
|
||||
def test_associate_host(self):
|
||||
response = self._do_post('os-networks/1/action',
|
||||
'network-associate-host-req',
|
||||
{"host": "testHost"})
|
||||
self.assertEqual(response.status_code, 202)
|
||||
self.assertEqual(response.content, "")
|
@ -103,6 +103,7 @@ nova.api.v3.extensions =
|
||||
multinic = nova.api.openstack.compute.plugins.v3.multinic:Multinic
|
||||
multiple_create = nova.api.openstack.compute.plugins.v3.multiple_create:MultipleCreate
|
||||
networks = nova.api.openstack.compute.plugins.v3.networks:Networks
|
||||
networks_associate = nova.api.openstack.compute.plugins.v3.networks_associate:NetworksAssociate
|
||||
pause_server = nova.api.openstack.compute.plugins.v3.pause_server:PauseServer
|
||||
pci = nova.api.openstack.compute.plugins.v3.pci:Pci
|
||||
quota_sets = nova.api.openstack.compute.plugins.v3.quota_sets:QuotaSets
|
||||
|
Loading…
x
Reference in New Issue
Block a user