Port floating_ips extension to v2.1
This patch ports floating_ips extension from v2 to v2.1, and have v2 unit test cases shared between v2.1 and v2. Partially implements blueprint v2-on-v3-api Change-Id: Ib06c0d6c7ff123f09a99ed94f4b0009695897602
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"pool": "nova"
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"floating_ip": {
|
||||
"fixed_ip": null,
|
||||
"id": 1,
|
||||
"instance_id": null,
|
||||
"ip": "10.10.10.1",
|
||||
"pool": "nova"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"floating_ip": {
|
||||
"fixed_ip": null,
|
||||
"id": 1,
|
||||
"instance_id": null,
|
||||
"ip": "10.10.10.1",
|
||||
"pool": "nova"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"floating_ips": []
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"floating_ips": [
|
||||
{
|
||||
"fixed_ip": null,
|
||||
"id": 1,
|
||||
"instance_id": null,
|
||||
"ip": "10.10.10.1",
|
||||
"pool": "nova"
|
||||
},
|
||||
{
|
||||
"fixed_ip": null,
|
||||
"id": 2,
|
||||
"instance_id": null,
|
||||
"ip": "10.10.10.2",
|
||||
"pool": "nova"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -163,6 +163,8 @@
|
||||
"compute_extension:v3:os-floating-ip-pools": "",
|
||||
"compute_extension:v3:os-floating-ip-pools:discoverable": "",
|
||||
"compute_extension:floating_ips": "",
|
||||
"compute_extension:v3:os-floating-ips": "",
|
||||
"compute_extension:v3:os-floating-ips:discoverable": "",
|
||||
"compute_extension:floating_ips_bulk": "rule:admin_api",
|
||||
"compute_extension:v3:os-floating-ips-bulk": "rule:admin_api",
|
||||
"compute_extension:v3:os-floating-ips-bulk:discoverable": "",
|
||||
|
||||
@@ -0,0 +1,300 @@
|
||||
# Copyright 2011 OpenStack Foundation
|
||||
# Copyright (c) 2011 X.commerce, a business unit of eBay Inc.
|
||||
# Copyright 2011 Grid Dynamics
|
||||
# Copyright 2011 Eldar Nugaev, Kirill Shileev, Ilya Alekseyev
|
||||
#
|
||||
# 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 webob
|
||||
|
||||
from nova.api.openstack import common
|
||||
from nova.api.openstack import extensions
|
||||
from nova.api.openstack import wsgi
|
||||
from nova import compute
|
||||
from nova.compute import utils as compute_utils
|
||||
from nova import exception
|
||||
from nova.i18n import _
|
||||
from nova.i18n import _LW
|
||||
from nova import network
|
||||
from nova.openstack.common import log as logging
|
||||
from nova.openstack.common import uuidutils
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
ALIAS = 'os-floating-ips'
|
||||
authorize = extensions.extension_authorizer('compute', 'v3:' + ALIAS)
|
||||
|
||||
|
||||
def _translate_floating_ip_view(floating_ip):
|
||||
result = {
|
||||
'id': floating_ip['id'],
|
||||
'ip': floating_ip['address'],
|
||||
'pool': floating_ip['pool'],
|
||||
}
|
||||
try:
|
||||
result['fixed_ip'] = floating_ip['fixed_ip']['address']
|
||||
except (TypeError, KeyError, AttributeError):
|
||||
result['fixed_ip'] = None
|
||||
try:
|
||||
result['instance_id'] = floating_ip['fixed_ip']['instance_uuid']
|
||||
except (TypeError, KeyError, AttributeError):
|
||||
result['instance_id'] = None
|
||||
return {'floating_ip': result}
|
||||
|
||||
|
||||
def _translate_floating_ips_view(floating_ips):
|
||||
return {'floating_ips': [_translate_floating_ip_view(ip)['floating_ip']
|
||||
for ip in floating_ips]}
|
||||
|
||||
|
||||
def get_instance_by_floating_ip_addr(self, context, address):
|
||||
snagiibfa = self.network_api.get_instance_id_by_floating_address
|
||||
instance_id = snagiibfa(context, address)
|
||||
if instance_id:
|
||||
return common.get_instance(self.compute_api, context, instance_id,
|
||||
want_objects=True)
|
||||
|
||||
|
||||
def disassociate_floating_ip(self, context, instance, address):
|
||||
try:
|
||||
self.network_api.disassociate_floating_ip(context, instance, address)
|
||||
except exception.Forbidden:
|
||||
raise webob.exc.HTTPForbidden()
|
||||
except exception.CannotDisassociateAutoAssignedFloatingIP:
|
||||
msg = _('Cannot disassociate auto assigned floating ip')
|
||||
raise webob.exc.HTTPForbidden(explanation=msg)
|
||||
|
||||
|
||||
class FloatingIPController(object):
|
||||
"""The Floating IPs API controller for the OpenStack API."""
|
||||
|
||||
def __init__(self):
|
||||
self.compute_api = compute.API()
|
||||
self.network_api = network.API()
|
||||
super(FloatingIPController, self).__init__()
|
||||
|
||||
@extensions.expected_errors(404)
|
||||
def show(self, req, id):
|
||||
"""Return data about the given floating ip."""
|
||||
context = req.environ['nova.context']
|
||||
authorize(context)
|
||||
|
||||
try:
|
||||
floating_ip = self.network_api.get_floating_ip(context, id)
|
||||
except (exception.NotFound, exception.InvalidID):
|
||||
msg = _("Floating ip not found for id %s") % id
|
||||
raise webob.exc.HTTPNotFound(explanation=msg)
|
||||
|
||||
return _translate_floating_ip_view(floating_ip)
|
||||
|
||||
@extensions.expected_errors(())
|
||||
def index(self, req):
|
||||
"""Return a list of floating ips allocated to a project."""
|
||||
context = req.environ['nova.context']
|
||||
authorize(context)
|
||||
|
||||
floating_ips = self.network_api.get_floating_ips_by_project(context)
|
||||
|
||||
return _translate_floating_ips_view(floating_ips)
|
||||
|
||||
@extensions.expected_errors((403, 404))
|
||||
def create(self, req, body=None):
|
||||
context = req.environ['nova.context']
|
||||
authorize(context)
|
||||
|
||||
pool = None
|
||||
if body and 'pool' in body:
|
||||
pool = body['pool']
|
||||
try:
|
||||
address = self.network_api.allocate_floating_ip(context, pool)
|
||||
ip = self.network_api.get_floating_ip_by_address(context, address)
|
||||
except exception.NoMoreFloatingIps:
|
||||
if pool:
|
||||
msg = _("No more floating ips in pool %s.") % pool
|
||||
else:
|
||||
msg = _("No more floating ips available.")
|
||||
raise webob.exc.HTTPNotFound(explanation=msg)
|
||||
except exception.FloatingIpLimitExceeded:
|
||||
if pool:
|
||||
msg = _("IP allocation over quota in pool %s.") % pool
|
||||
else:
|
||||
msg = _("IP allocation over quota.")
|
||||
raise webob.exc.HTTPForbidden(explanation=msg)
|
||||
except exception.FloatingIpPoolNotFound as e:
|
||||
raise webob.exc.HTTPNotFound(explanation=e.format_message())
|
||||
|
||||
return _translate_floating_ip_view(ip)
|
||||
|
||||
@wsgi.response(202)
|
||||
@extensions.expected_errors((400, 403, 404))
|
||||
def delete(self, req, id):
|
||||
context = req.environ['nova.context']
|
||||
authorize(context)
|
||||
|
||||
# get the floating ip object
|
||||
try:
|
||||
floating_ip = self.network_api.get_floating_ip(context, id)
|
||||
except (exception.NotFound, exception.InvalidID):
|
||||
msg = _("Floating ip not found for id %s") % id
|
||||
raise webob.exc.HTTPNotFound(explanation=msg)
|
||||
address = floating_ip['address']
|
||||
|
||||
# get the associated instance object (if any)
|
||||
instance = get_instance_by_floating_ip_addr(self, context, address)
|
||||
try:
|
||||
self.network_api.disassociate_and_release_floating_ip(
|
||||
context, instance, floating_ip)
|
||||
except exception.Forbidden:
|
||||
raise webob.exc.HTTPForbidden()
|
||||
except exception.CannotDisassociateAutoAssignedFloatingIP:
|
||||
msg = _('Cannot disassociate auto assigned floating ip')
|
||||
raise webob.exc.HTTPForbidden(explanation=msg)
|
||||
|
||||
|
||||
class FloatingIPActionController(wsgi.Controller):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(FloatingIPActionController, self).__init__(*args, **kwargs)
|
||||
self.compute_api = compute.API()
|
||||
self.network_api = network.API()
|
||||
|
||||
@extensions.expected_errors((400, 403, 404))
|
||||
@wsgi.action('addFloatingIp')
|
||||
def _add_floating_ip(self, req, id, body):
|
||||
"""Associate floating_ip to an instance."""
|
||||
context = req.environ['nova.context']
|
||||
authorize(context)
|
||||
|
||||
try:
|
||||
address = body['addFloatingIp']['address']
|
||||
except TypeError:
|
||||
msg = _("Missing parameter dict")
|
||||
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||
except KeyError:
|
||||
msg = _("Address not specified")
|
||||
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||
|
||||
instance = common.get_instance(self.compute_api, context, id,
|
||||
want_objects=True)
|
||||
cached_nwinfo = compute_utils.get_nw_info_for_instance(instance)
|
||||
if not cached_nwinfo:
|
||||
msg = _('No nw_info cache associated with instance')
|
||||
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||
|
||||
fixed_ips = cached_nwinfo.fixed_ips()
|
||||
if not fixed_ips:
|
||||
msg = _('No fixed ips associated to instance')
|
||||
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||
|
||||
fixed_address = None
|
||||
if 'fixed_address' in body['addFloatingIp']:
|
||||
fixed_address = body['addFloatingIp']['fixed_address']
|
||||
for fixed in fixed_ips:
|
||||
if fixed['address'] == fixed_address:
|
||||
break
|
||||
else:
|
||||
msg = _('Specified fixed address not assigned to instance')
|
||||
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||
|
||||
if not fixed_address:
|
||||
fixed_address = fixed_ips[0]['address']
|
||||
if len(fixed_ips) > 1:
|
||||
LOG.warning(_LW('multiple fixed_ips exist, using the first: '
|
||||
'%s'), fixed_address)
|
||||
|
||||
try:
|
||||
self.network_api.associate_floating_ip(context, instance,
|
||||
floating_address=address,
|
||||
fixed_address=fixed_address)
|
||||
except exception.FloatingIpAssociated:
|
||||
msg = _('floating ip is already associated')
|
||||
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||
except exception.NoFloatingIpInterface:
|
||||
msg = _('l3driver call to add floating ip failed')
|
||||
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||
except exception.FloatingIpNotFoundForAddress:
|
||||
msg = _('floating ip not found')
|
||||
raise webob.exc.HTTPNotFound(explanation=msg)
|
||||
except exception.Forbidden as e:
|
||||
raise webob.exc.HTTPForbidden(explanation=e.format_message())
|
||||
except Exception as e:
|
||||
msg = _('Unable to associate floating ip %(address)s to '
|
||||
'fixed ip %(fixed_address)s for instance %(id)s. '
|
||||
'Error: %(error)s') % (
|
||||
{'address': address, 'fixed_address': fixed_address,
|
||||
'id': id, 'error': e})
|
||||
LOG.exception(msg)
|
||||
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||
|
||||
return webob.Response(status_int=202)
|
||||
|
||||
@extensions.expected_errors((400, 403, 404, 422))
|
||||
@wsgi.action('removeFloatingIp')
|
||||
def _remove_floating_ip(self, req, id, body):
|
||||
"""Dissociate floating_ip from an instance."""
|
||||
context = req.environ['nova.context']
|
||||
authorize(context)
|
||||
|
||||
try:
|
||||
address = body['removeFloatingIp']['address']
|
||||
except TypeError:
|
||||
msg = _("Missing parameter dict")
|
||||
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||
except KeyError:
|
||||
msg = _("Address not specified")
|
||||
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||
|
||||
# get the floating ip object
|
||||
try:
|
||||
floating_ip = self.network_api.get_floating_ip_by_address(context,
|
||||
address)
|
||||
except exception.FloatingIpNotFoundForAddress:
|
||||
msg = _("floating ip not found")
|
||||
raise webob.exc.HTTPNotFound(explanation=msg)
|
||||
|
||||
# get the associated instance object (if any)
|
||||
instance = get_instance_by_floating_ip_addr(self, context, address)
|
||||
|
||||
# disassociate if associated
|
||||
if (instance and
|
||||
floating_ip.get('fixed_ip_id') and
|
||||
(uuidutils.is_uuid_like(id) and
|
||||
[instance['uuid'] == id] or
|
||||
[instance['id'] == id])[0]):
|
||||
try:
|
||||
disassociate_floating_ip(self, context, instance, address)
|
||||
except exception.FloatingIpNotAssociated:
|
||||
msg = _('Floating ip is not associated')
|
||||
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||
return webob.Response(status_int=202)
|
||||
else:
|
||||
msg = _("Floating ip %(address)s is not associated with instance "
|
||||
"%(id)s.") % {'address': address, 'id': id}
|
||||
raise webob.exc.HTTPUnprocessableEntity(explanation=msg)
|
||||
|
||||
|
||||
class FloatingIps(extensions.V3APIExtensionBase):
|
||||
"""Floating IPs support."""
|
||||
|
||||
name = "FloatingIps"
|
||||
alias = ALIAS
|
||||
version = 1
|
||||
|
||||
def get_resources(self):
|
||||
resource = [extensions.ResourceExtension(ALIAS,
|
||||
FloatingIPController())]
|
||||
return resource
|
||||
|
||||
def get_controller_extensions(self):
|
||||
controller = FloatingIPActionController()
|
||||
extension = extensions.ControllerExtension(self, 'servers', controller)
|
||||
return [extension]
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"pool": "%(pool)s"
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"floating_ip": {
|
||||
"fixed_ip": null,
|
||||
"id": 1,
|
||||
"instance_id": null,
|
||||
"ip": "10.10.10.1",
|
||||
"pool": "nova"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"floating_ip": {
|
||||
"fixed_ip": null,
|
||||
"id": 1,
|
||||
"instance_id": null,
|
||||
"ip": "10.10.10.1",
|
||||
"pool": "nova"
|
||||
}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"floating_ips": []
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"floating_ips": [
|
||||
{
|
||||
"fixed_ip": null,
|
||||
"id": 1,
|
||||
"instance_id": null,
|
||||
"ip": "10.10.10.1",
|
||||
"pool": "nova"
|
||||
},
|
||||
{
|
||||
"fixed_ip": null,
|
||||
"id": 2,
|
||||
"instance_id": null,
|
||||
"ip": "10.10.10.2",
|
||||
"pool": "nova"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
# 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 import context
|
||||
from nova.tests.functional.v3 import api_sample_base
|
||||
|
||||
CONF = cfg.CONF
|
||||
CONF.import_opt('default_floating_pool', 'nova.network.floating_ips')
|
||||
CONF.import_opt('public_interface', 'nova.network.linux_net')
|
||||
|
||||
|
||||
class FloatingIpsTest(api_sample_base.ApiSampleTestBaseV3):
|
||||
extension_name = "os-floating-ips"
|
||||
|
||||
def setUp(self):
|
||||
super(FloatingIpsTest, self).setUp()
|
||||
pool = CONF.default_floating_pool
|
||||
interface = CONF.public_interface
|
||||
|
||||
self.ip_pool = [
|
||||
{
|
||||
'address': "10.10.10.1",
|
||||
'pool': pool,
|
||||
'interface': interface
|
||||
},
|
||||
{
|
||||
'address': "10.10.10.2",
|
||||
'pool': pool,
|
||||
'interface': interface
|
||||
},
|
||||
{
|
||||
'address': "10.10.10.3",
|
||||
'pool': pool,
|
||||
'interface': interface
|
||||
},
|
||||
]
|
||||
self.compute.db.floating_ip_bulk_create(
|
||||
context.get_admin_context(), self.ip_pool)
|
||||
|
||||
def tearDown(self):
|
||||
self.compute.db.floating_ip_bulk_destroy(
|
||||
context.get_admin_context(), self.ip_pool)
|
||||
super(FloatingIpsTest, self).tearDown()
|
||||
|
||||
def test_floating_ips_list_empty(self):
|
||||
response = self._do_get('os-floating-ips')
|
||||
|
||||
subs = self._get_regexes()
|
||||
self._verify_response('floating-ips-list-empty-resp',
|
||||
subs, response, 200)
|
||||
|
||||
def test_floating_ips_list(self):
|
||||
self._do_post('os-floating-ips',
|
||||
'floating-ips-create-nopool-req',
|
||||
{})
|
||||
self._do_post('os-floating-ips',
|
||||
'floating-ips-create-nopool-req',
|
||||
{})
|
||||
|
||||
response = self._do_get('os-floating-ips')
|
||||
subs = self._get_regexes()
|
||||
self._verify_response('floating-ips-list-resp',
|
||||
subs, response, 200)
|
||||
|
||||
def test_floating_ips_create_nopool(self):
|
||||
response = self._do_post('os-floating-ips',
|
||||
'floating-ips-create-nopool-req',
|
||||
{})
|
||||
subs = self._get_regexes()
|
||||
self._verify_response('floating-ips-create-resp',
|
||||
subs, response, 200)
|
||||
|
||||
def test_floating_ips_create(self):
|
||||
response = self._do_post('os-floating-ips',
|
||||
'floating-ips-create-req',
|
||||
{"pool": CONF.default_floating_pool})
|
||||
subs = self._get_regexes()
|
||||
self._verify_response('floating-ips-create-resp', subs, response, 200)
|
||||
|
||||
def test_floating_ips_get(self):
|
||||
self.test_floating_ips_create()
|
||||
# NOTE(sdague): the first floating ip will always have 1 as an id,
|
||||
# but it would be better if we could get this from the create
|
||||
response = self._do_get('os-floating-ips/%d' % 1)
|
||||
subs = self._get_regexes()
|
||||
self._verify_response('floating-ips-get-resp', subs, response, 200)
|
||||
|
||||
def test_floating_ips_delete(self):
|
||||
self.test_floating_ips_create()
|
||||
response = self._do_delete('os-floating-ips/%d' % 1)
|
||||
self.assertEqual(response.status_code, 202)
|
||||
self.assertEqual(response.content, "")
|
||||
@@ -22,7 +22,8 @@ import mock
|
||||
from oslo.serialization import jsonutils
|
||||
import webob
|
||||
|
||||
from nova.api.openstack.compute.contrib import floating_ips
|
||||
from nova.api.openstack.compute.contrib import floating_ips as fips_v2
|
||||
from nova.api.openstack.compute.plugins.v3 import floating_ips as fips_v21
|
||||
from nova.api.openstack import extensions
|
||||
from nova import compute
|
||||
from nova.compute import utils as compute_utils
|
||||
@@ -105,18 +106,16 @@ def get_instance_by_floating_ip_addr(self, context, address):
|
||||
return None
|
||||
|
||||
|
||||
class FloatingIpTestNeutron(test.NoDBTestCase):
|
||||
class FloatingIpTestNeutronV21(test.NoDBTestCase):
|
||||
floating_ips = fips_v21
|
||||
|
||||
def setUp(self):
|
||||
super(FloatingIpTestNeutron, self).setUp()
|
||||
super(FloatingIpTestNeutronV21, self).setUp()
|
||||
self.flags(network_api_class='nova.network.neutronv2.api.API')
|
||||
self.controller = floating_ips.FloatingIPController()
|
||||
|
||||
def _get_fake_request(self):
|
||||
return fakes.HTTPRequest.blank('/v2/fake/os-floating-ips/1')
|
||||
self.controller = self.floating_ips.FloatingIPController()
|
||||
|
||||
def test_floatingip_delete(self):
|
||||
req = self._get_fake_request()
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/os-floating-ips/1')
|
||||
fip_val = {'address': '1.1.1.1', 'fixed_ip_id': '192.168.1.2'}
|
||||
with contextlib.nested(
|
||||
mock.patch.object(self.controller.network_api,
|
||||
@@ -140,9 +139,15 @@ class FloatingIpTestNeutron(test.NoDBTestCase):
|
||||
self.assertTrue(dis_and_del.called)
|
||||
|
||||
|
||||
class FloatingIpTest(test.TestCase):
|
||||
class FloatingIpTestNeutronV2(FloatingIpTestNeutronV21):
|
||||
floating_ips = fips_v2
|
||||
|
||||
|
||||
class FloatingIpTestV21(test.TestCase):
|
||||
floating_ip = "10.10.10.10"
|
||||
floating_ip_2 = "10.10.10.11"
|
||||
floating_ips = fips_v21
|
||||
url = '/v2/fake/servers/test_inst/action'
|
||||
|
||||
def _create_floating_ips(self, floating_ips=None):
|
||||
"""Create a floating ip object."""
|
||||
@@ -169,11 +174,11 @@ class FloatingIpTest(test.TestCase):
|
||||
def _get_fake_server_request(self):
|
||||
return fakes.HTTPRequest.blank('/v2/fake/servers/test_inst/action')
|
||||
|
||||
def _get_fake_response(self, req, init_only):
|
||||
return req.get_response(fakes.wsgi_app(init_only=(init_only,)))
|
||||
def _get_fake_app(self):
|
||||
return fakes.wsgi_app_v21(init_only=('servers', 'os-floating-ips'))
|
||||
|
||||
def setUp(self):
|
||||
super(FloatingIpTest, self).setUp()
|
||||
super(FloatingIpTestV21, self).setUp()
|
||||
self.stubs.Set(compute.api.API, "get",
|
||||
compute_api_get)
|
||||
self.stubs.Set(network.api.API, "get_floating_ip",
|
||||
@@ -200,17 +205,14 @@ class FloatingIpTest(test.TestCase):
|
||||
|
||||
self.ext_mgr = extensions.ExtensionManager()
|
||||
self.ext_mgr.extensions = {}
|
||||
self.controller = floating_ips.FloatingIPController()
|
||||
self.manager = floating_ips.FloatingIPActionController(self.ext_mgr)
|
||||
|
||||
self.flags(
|
||||
osapi_compute_extension=[
|
||||
'nova.api.openstack.compute.contrib.select_extensions'],
|
||||
osapi_compute_ext_list=['Floating_ips'])
|
||||
self.controller = self.floating_ips.FloatingIPController()
|
||||
self.manager = self.floating_ips.\
|
||||
FloatingIPActionController(self.ext_mgr)
|
||||
self.app = self._get_fake_app()
|
||||
|
||||
def tearDown(self):
|
||||
self._delete_floating_ip()
|
||||
super(FloatingIpTest, self).tearDown()
|
||||
super(FloatingIpTestV21, self).tearDown()
|
||||
|
||||
def test_floatingip_delete(self):
|
||||
req = self._get_fake_fip_request('1')
|
||||
@@ -237,7 +239,7 @@ class FloatingIpTest(test.TestCase):
|
||||
floating_ip_address)
|
||||
# NOTE(vish): network_get uses the id not the address
|
||||
floating_ip = db.floating_ip_get(self.context, floating_ip['id'])
|
||||
view = floating_ips._translate_floating_ip_view(floating_ip)
|
||||
view = self.floating_ips._translate_floating_ip_view(floating_ip)
|
||||
self.assertIn('floating_ip', view)
|
||||
self.assertTrue(view['floating_ip']['id'])
|
||||
self.assertEqual(view['floating_ip']['ip'], self.floating_ip)
|
||||
@@ -247,7 +249,7 @@ class FloatingIpTest(test.TestCase):
|
||||
def test_translate_floating_ip_view_dict(self):
|
||||
floating_ip = {'id': 0, 'address': '10.0.0.10', 'pool': 'nova',
|
||||
'fixed_ip': None}
|
||||
view = floating_ips._translate_floating_ip_view(floating_ip)
|
||||
view = self.floating_ips._translate_floating_ip_view(floating_ip)
|
||||
self.assertIn('floating_ip', view)
|
||||
|
||||
def test_floating_ips_list(self):
|
||||
@@ -275,7 +277,7 @@ class FloatingIpTest(test.TestCase):
|
||||
|
||||
req = self._get_fake_fip_request('9876')
|
||||
req.method = 'DELETE'
|
||||
res = self._get_fake_response(req, 'os-floating-ips')
|
||||
res = req.get_response(self.app)
|
||||
self.assertEqual(res.status_int, 404)
|
||||
expected_msg = ('{"itemNotFound": {"message": "Floating ip not found '
|
||||
'for id 9876", "code": 404}}')
|
||||
@@ -293,14 +295,14 @@ class FloatingIpTest(test.TestCase):
|
||||
|
||||
self.stubs.Set(network.api.API, "get_floating_ip",
|
||||
fake_get_floating_ip)
|
||||
self.stubs.Set(floating_ips, "get_instance_by_floating_ip_addr",
|
||||
self.stubs.Set(self.floating_ips, "get_instance_by_floating_ip_addr",
|
||||
fake_get_instance_by_floating_ip_addr)
|
||||
self.stubs.Set(floating_ips, "disassociate_floating_ip",
|
||||
self.stubs.Set(self.floating_ips, "disassociate_floating_ip",
|
||||
fake_disassociate_floating_ip)
|
||||
|
||||
req = self._get_fake_fip_request('1')
|
||||
req.method = 'DELETE'
|
||||
res = self._get_fake_response(req, 'os-floating-ips')
|
||||
res = req.get_response(self.app)
|
||||
self.assertEqual(res.status_int, 202)
|
||||
|
||||
def test_floating_ip_show(self):
|
||||
@@ -319,7 +321,7 @@ class FloatingIpTest(test.TestCase):
|
||||
fake_get_floating_ip)
|
||||
|
||||
req = self._get_fake_fip_request('9876')
|
||||
res = self._get_fake_response(req, 'os-floating-ips')
|
||||
res = req.get_response(self.app)
|
||||
self.assertEqual(res.status_int, 404)
|
||||
expected_msg = ('{"itemNotFound": {"message": "Floating ip not found '
|
||||
'for id 9876", "code": 404}}')
|
||||
@@ -475,25 +477,6 @@ class FloatingIpTest(test.TestCase):
|
||||
self.manager._add_floating_ip, req, 'test_inst',
|
||||
body)
|
||||
|
||||
def test_not_extended_floating_ip_associate_fixed(self):
|
||||
# Check that fixed_address is ignored if os-extended-floating-ips
|
||||
# is not loaded
|
||||
fixed_address_requested = '192.168.1.101'
|
||||
fixed_address_allocated = '192.168.1.100'
|
||||
|
||||
def fake_associate_floating_ip(*args, **kwargs):
|
||||
self.assertEqual(fixed_address_allocated,
|
||||
kwargs['fixed_address'])
|
||||
|
||||
self.stubs.Set(network.api.API, "associate_floating_ip",
|
||||
fake_associate_floating_ip)
|
||||
body = dict(addFloatingIp=dict(address=self.floating_ip,
|
||||
fixed_address=fixed_address_requested))
|
||||
|
||||
req = self._get_fake_server_request()
|
||||
rsp = self.manager._add_floating_ip(req, 'test_inst', body)
|
||||
self.assertEqual(202, rsp.status_int)
|
||||
|
||||
def test_associate_not_allocated_floating_ip_to_instance(self):
|
||||
def fake_associate_floating_ip(self, context, instance,
|
||||
floating_address, fixed_address,
|
||||
@@ -504,11 +487,11 @@ class FloatingIpTest(test.TestCase):
|
||||
fake_associate_floating_ip)
|
||||
floating_ip = '10.10.10.11'
|
||||
body = dict(addFloatingIp=dict(address=floating_ip))
|
||||
req = self._get_fake_server_request()
|
||||
req = webob.Request.blank(self.url)
|
||||
req.method = "POST"
|
||||
req.body = jsonutils.dumps(body)
|
||||
req.headers["content-type"] = "application/json"
|
||||
resp = self._get_fake_response(req, 'servers')
|
||||
resp = req.get_response(self.app)
|
||||
res_dict = jsonutils.loads(resp.body)
|
||||
self.assertEqual(resp.status_int, 404)
|
||||
self.assertEqual(res_dict['itemNotFound']['message'],
|
||||
@@ -701,9 +684,43 @@ class FloatingIpTest(test.TestCase):
|
||||
body)
|
||||
|
||||
|
||||
class ExtendedFloatingIpTest(test.TestCase):
|
||||
class FloatingIpTestV2(FloatingIpTestV21):
|
||||
floating_ips = fips_v2
|
||||
|
||||
def _get_fake_app(self):
|
||||
return fakes.wsgi_app(init_only=('servers', 'os-floating-ips'))
|
||||
|
||||
def setUp(self):
|
||||
super(FloatingIpTestV2, self).setUp()
|
||||
self.flags(
|
||||
osapi_compute_extension=[
|
||||
'nova.api.openstack.compute.contrib.select_extensions'],
|
||||
osapi_compute_ext_list=['Floating_ips'])
|
||||
|
||||
def test_not_extended_floating_ip_associate_fixed(self):
|
||||
# Check that fixed_address is ignored if os-extended-floating-ips
|
||||
# is not loaded
|
||||
fixed_address_requested = '192.168.1.101'
|
||||
fixed_address_allocated = '192.168.1.100'
|
||||
|
||||
def fake_associate_floating_ip(*args, **kwargs):
|
||||
self.assertEqual(fixed_address_allocated,
|
||||
kwargs['fixed_address'])
|
||||
|
||||
self.stubs.Set(network.api.API, "associate_floating_ip",
|
||||
fake_associate_floating_ip)
|
||||
body = dict(addFloatingIp=dict(address=self.floating_ip,
|
||||
fixed_address=fixed_address_requested))
|
||||
|
||||
req = self._get_fake_server_request()
|
||||
rsp = self.manager._add_floating_ip(req, 'test_inst', body)
|
||||
self.assertEqual(202, rsp.status_int)
|
||||
|
||||
|
||||
class ExtendedFloatingIpTestV21(test.TestCase):
|
||||
floating_ip = "10.10.10.10"
|
||||
floating_ip_2 = "10.10.10.11"
|
||||
floating_ips = fips_v21
|
||||
|
||||
def _create_floating_ips(self, floating_ips=None):
|
||||
"""Create a floating ip object."""
|
||||
@@ -727,11 +744,11 @@ class ExtendedFloatingIpTest(test.TestCase):
|
||||
def _get_fake_request(self):
|
||||
return fakes.HTTPRequest.blank('/v2/fake/servers/test_inst/action')
|
||||
|
||||
def _get_fake_response(self, req, init_only):
|
||||
return req.get_response(fakes.wsgi_app(init_only=(init_only,)))
|
||||
def _get_fake_app(self):
|
||||
return fakes.wsgi_app_v21(init_only=('servers', 'os-floating-ips'))
|
||||
|
||||
def setUp(self):
|
||||
super(ExtendedFloatingIpTest, self).setUp()
|
||||
super(ExtendedFloatingIpTestV21, self).setUp()
|
||||
self.stubs.Set(compute.api.API, "get",
|
||||
compute_api_get)
|
||||
self.stubs.Set(network.api.API, "get_floating_ip",
|
||||
@@ -760,16 +777,14 @@ class ExtendedFloatingIpTest(test.TestCase):
|
||||
self.ext_mgr.extensions = {}
|
||||
self.ext_mgr.extensions['os-floating-ips'] = True
|
||||
self.ext_mgr.extensions['os-extended-floating-ips'] = True
|
||||
self.controller = floating_ips.FloatingIPController()
|
||||
self.manager = floating_ips.FloatingIPActionController(self.ext_mgr)
|
||||
self.flags(
|
||||
osapi_compute_extension=[
|
||||
'nova.api.openstack.compute.contrib.select_extensions'],
|
||||
osapi_compute_ext_list=['Floating_ips', 'Extended_floating_ips'])
|
||||
self.controller = self.floating_ips.FloatingIPController()
|
||||
self.manager = self.floating_ips.\
|
||||
FloatingIPActionController(self.ext_mgr)
|
||||
self.app = self._get_fake_app()
|
||||
|
||||
def tearDown(self):
|
||||
self._delete_floating_ip()
|
||||
super(ExtendedFloatingIpTest, self).tearDown()
|
||||
super(ExtendedFloatingIpTestV21, self).tearDown()
|
||||
|
||||
def test_extended_floating_ip_associate_fixed(self):
|
||||
fixed_address = '192.168.1.101'
|
||||
@@ -799,16 +814,30 @@ class ExtendedFloatingIpTest(test.TestCase):
|
||||
req.method = "POST"
|
||||
req.body = jsonutils.dumps(body)
|
||||
req.headers["content-type"] = "application/json"
|
||||
resp = self._get_fake_response(req, 'servers')
|
||||
resp = req.get_response(self.app)
|
||||
res_dict = jsonutils.loads(resp.body)
|
||||
self.assertEqual(resp.status_int, 400)
|
||||
self.assertEqual(res_dict['badRequest']['message'],
|
||||
"Specified fixed address not assigned to instance")
|
||||
|
||||
|
||||
class FloatingIpSerializerTest(test.TestCase):
|
||||
class ExtendedFloatingIpTestV2(ExtendedFloatingIpTestV21):
|
||||
floating_ips = fips_v2
|
||||
|
||||
def _get_fake_app(self):
|
||||
return fakes.wsgi_app(init_only=('servers', 'os-floating-ips'))
|
||||
|
||||
def setUp(self):
|
||||
super(ExtendedFloatingIpTestV2, self).setUp()
|
||||
self.flags(
|
||||
osapi_compute_extension=[
|
||||
'nova.api.openstack.compute.contrib.select_extensions'],
|
||||
osapi_compute_ext_list=['Floating_ips', 'Extended_floating_ips'])
|
||||
|
||||
|
||||
class FloatingIpSerializerTestV2(test.TestCase):
|
||||
def test_default_serializer(self):
|
||||
serializer = floating_ips.FloatingIPTemplate()
|
||||
serializer = fips_v2.FloatingIPTemplate()
|
||||
text = serializer.serialize(dict(
|
||||
floating_ip=dict(
|
||||
instance_id=1,
|
||||
@@ -825,7 +854,7 @@ class FloatingIpSerializerTest(test.TestCase):
|
||||
self.assertEqual('1', tree.get('id'))
|
||||
|
||||
def test_index_serializer(self):
|
||||
serializer = floating_ips.FloatingIPsTemplate()
|
||||
serializer = fips_v2.FloatingIPsTemplate()
|
||||
text = serializer.serialize(dict(
|
||||
floating_ips=[
|
||||
dict(instance_id=1,
|
||||
|
||||
@@ -218,6 +218,7 @@ policy_data = """
|
||||
"compute_extension:floating_ip_pools": "",
|
||||
"compute_extension:v3:os-floating-ip-pools": "",
|
||||
"compute_extension:floating_ips": "",
|
||||
"compute_extension:v3:os-floating-ips": "",
|
||||
"compute_extension:floating_ips_bulk": "",
|
||||
"compute_extension:v3:os-floating-ips-bulk": "",
|
||||
"compute_extension:fping": "",
|
||||
|
||||
@@ -89,6 +89,7 @@ nova.api.v3.extensions =
|
||||
flavor_manage = nova.api.openstack.compute.plugins.v3.flavor_manage:FlavorManage
|
||||
floating_ip_dns = nova.api.openstack.compute.plugins.v3.floating_ip_dns:FloatingIpDns
|
||||
floating_ip_pools = nova.api.openstack.compute.plugins.v3.floating_ip_pools:FloatingIpPools
|
||||
floating_ips = nova.api.openstack.compute.plugins.v3.floating_ips:FloatingIps
|
||||
floating_ips_bulk = nova.api.openstack.compute.plugins.v3.floating_ips_bulk:FloatingIpsBulk
|
||||
fping = nova.api.openstack.compute.plugins.v3.fping:Fping
|
||||
hide_server_addresses = nova.api.openstack.compute.plugins.v3.hide_server_addresses:HideServerAddresses
|
||||
|
||||
Reference in New Issue
Block a user