Merge "Introduce floating IP pool resource"
This commit is contained in:
commit
eb8759aa98
@ -150,6 +150,7 @@
|
||||
"create_floatingip": "rule:regular_user",
|
||||
"create_floatingip:floating_ip_address": "rule:admin_only",
|
||||
"get_floatingip": "rule:admin_or_owner",
|
||||
"get_floatingip_pool": "rule:regular_user",
|
||||
"update_floatingip": "rule:admin_or_owner",
|
||||
"delete_floatingip": "rule:admin_or_owner",
|
||||
|
||||
|
77
neutron/db/l3_fip_pools_db.py
Normal file
77
neutron/db/l3_fip_pools_db.py
Normal file
@ -0,0 +1,77 @@
|
||||
# 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.
|
||||
|
||||
from neutron_lib.api.definitions import fip64
|
||||
from neutron_lib.api import extensions
|
||||
from neutron_lib import constants as lib_const
|
||||
from neutron_lib.db import utils as lib_db_utils
|
||||
from neutron_lib.plugins import directory
|
||||
|
||||
from neutron.extensions import floatingip_pools as fip_pools_ext
|
||||
from neutron.objects import base as base_obj
|
||||
from neutron.objects import network as net_obj
|
||||
from neutron.objects import subnet as subnet_obj
|
||||
|
||||
|
||||
class FloatingIPPoolsDbMixin(object):
|
||||
"""Class to support floating IP pool."""
|
||||
|
||||
_is_v6_supported = None
|
||||
|
||||
@staticmethod
|
||||
def _make_floatingip_pool_dict(context, subnet, fields=None):
|
||||
res = {'subnet_id': subnet.id,
|
||||
'subnet_name': subnet.name,
|
||||
'tenant_id': context.tenant_id,
|
||||
'network_id': subnet.network_id,
|
||||
'cidr': str(subnet.cidr)}
|
||||
|
||||
return lib_db_utils.resource_fields(res, fields)
|
||||
|
||||
def get_floatingip_pools(self, context, filters=None, fields=None,
|
||||
sorts=None, limit=None, marker=None,
|
||||
page_reverse=False):
|
||||
"""Return information for available floating IP pools"""
|
||||
pager = base_obj.Pager(sorts, limit, page_reverse, marker)
|
||||
net_ids = [n.network_id
|
||||
for n in net_obj.ExternalNetwork.get_objects(context)]
|
||||
# NOTE(hongbin): Use elevated context to make sure we have enough
|
||||
# permission to retrieve subnets that are not in current tenant
|
||||
# but belongs to external networks shared with current tenant.
|
||||
admin_context = context.elevated()
|
||||
subnet_objs = subnet_obj.Subnet.get_objects(admin_context,
|
||||
_pager=pager,
|
||||
network_id=net_ids)
|
||||
return [self._make_floatingip_pool_dict(context, obj, fields)
|
||||
for obj in subnet_objs
|
||||
if (obj.ip_version == lib_const.IP_VERSION_4 or
|
||||
self.is_v6_supported)]
|
||||
|
||||
@property
|
||||
def is_v6_supported(self):
|
||||
supported = self._is_v6_supported
|
||||
if supported is None:
|
||||
supported = False
|
||||
for plugin in directory.get_plugins().values():
|
||||
if extensions.is_extension_supported(plugin, fip64.ALIAS):
|
||||
supported = True
|
||||
break
|
||||
self._is_v6_supported = supported
|
||||
|
||||
return supported
|
||||
|
||||
|
||||
class FloatingIPPoolsMixin(FloatingIPPoolsDbMixin,
|
||||
fip_pools_ext.FloatingIPPoolPluginBase):
|
||||
pass
|
53
neutron/extensions/floatingip_pools.py
Normal file
53
neutron/extensions/floatingip_pools.py
Normal file
@ -0,0 +1,53 @@
|
||||
# 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 abc
|
||||
import itertools
|
||||
|
||||
from neutron_lib.api.definitions import floatingip_pools as apidef
|
||||
from neutron_lib.api import extensions as api_extensions
|
||||
from neutron_lib.plugins import constants
|
||||
import six
|
||||
|
||||
from neutron.api.v2 import resource_helper
|
||||
|
||||
|
||||
class Floatingip_pools(api_extensions.APIExtensionDescriptor):
|
||||
"""Neutron floating IP pool api extension."""
|
||||
|
||||
api_definition = apidef
|
||||
|
||||
@classmethod
|
||||
def get_resources(cls):
|
||||
"""Returns Ext Resources."""
|
||||
plural_mappings = resource_helper.build_plural_mappings(
|
||||
{}, itertools.chain(apidef.RESOURCE_ATTRIBUTE_MAP))
|
||||
|
||||
resources = resource_helper.build_resource_info(
|
||||
plural_mappings,
|
||||
apidef.RESOURCE_ATTRIBUTE_MAP,
|
||||
constants.L3,
|
||||
translate_name=True,
|
||||
allow_bulk=True)
|
||||
|
||||
return resources
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class FloatingIPPoolPluginBase(object):
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_floatingip_pools(self, context, filters=None, fields=None,
|
||||
sorts=None, limit=None, marker=None,
|
||||
page_reverse=False):
|
||||
"""List all floating ip pools."""
|
||||
pass
|
@ -32,6 +32,7 @@ from neutron.db import dns_db
|
||||
from neutron.db import extraroute_db
|
||||
from neutron.db import l3_dvr_ha_scheduler_db
|
||||
from neutron.db import l3_dvrscheduler_db
|
||||
from neutron.db import l3_fip_pools_db
|
||||
from neutron.db import l3_fip_port_details
|
||||
from neutron.db import l3_fip_qos
|
||||
from neutron.db import l3_gwmode_db
|
||||
@ -69,7 +70,8 @@ class L3RouterPlugin(service_base.ServicePluginBase,
|
||||
l3_dvr_ha_scheduler_db.L3_DVR_HA_scheduler_db_mixin,
|
||||
dns_db.DNSDbMixin,
|
||||
l3_fip_qos.FloatingQoSDbMixin,
|
||||
l3_fip_port_details.Fip_port_details_db_mixin):
|
||||
l3_fip_port_details.Fip_port_details_db_mixin,
|
||||
l3_fip_pools_db.FloatingIPPoolsMixin):
|
||||
|
||||
"""Implementation of the Neutron L3 Router Service Plugin.
|
||||
|
||||
@ -84,7 +86,7 @@ class L3RouterPlugin(service_base.ServicePluginBase,
|
||||
"extraroute", "l3_agent_scheduler",
|
||||
"l3-ha", "router_availability_zone",
|
||||
"l3-flavors", "qos-fip",
|
||||
"fip-port-details"]
|
||||
"fip-port-details", "floatingip-pools"]
|
||||
|
||||
__native_pagination_support = True
|
||||
__native_sorting_support = True
|
||||
|
@ -20,6 +20,7 @@ NETWORK_API_EXTENSIONS+=",extraroute"
|
||||
NETWORK_API_EXTENSIONS+=",filter-validation"
|
||||
NETWORK_API_EXTENSIONS+=",fip-port-details"
|
||||
NETWORK_API_EXTENSIONS+=",flavors"
|
||||
NETWORK_API_EXTENSIONS+=",floatingip-pools"
|
||||
NETWORK_API_EXTENSIONS+=",ip-substring-filtering"
|
||||
NETWORK_API_EXTENSIONS+=",l3-flavors"
|
||||
NETWORK_API_EXTENSIONS+=",l3-ha"
|
||||
|
@ -150,6 +150,7 @@
|
||||
"create_floatingip": "rule:regular_user",
|
||||
"create_floatingip:floating_ip_address": "rule:admin_only",
|
||||
"get_floatingip": "rule:admin_or_owner",
|
||||
"get_floatingip_pool": "rule:regular_user",
|
||||
"update_floatingip": "rule:admin_or_owner",
|
||||
"delete_floatingip": "rule:admin_or_owner",
|
||||
|
||||
|
155
neutron/tests/unit/extensions/test_floatingip_pools.py
Normal file
155
neutron/tests/unit/extensions/test_floatingip_pools.py
Normal file
@ -0,0 +1,155 @@
|
||||
#
|
||||
# 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 ddt
|
||||
import mock
|
||||
|
||||
from neutron_lib.api.definitions import floatingip_pools as apidef
|
||||
from neutron_lib import constants as lib_const
|
||||
from neutron_lib import context
|
||||
from neutron_lib.plugins import constants as plugin_constants
|
||||
from neutron_lib.plugins import directory
|
||||
from oslo_config import cfg
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
from neutron.db import l3_fip_pools_db
|
||||
from neutron.extensions import l3
|
||||
from neutron.objects import network as net_obj
|
||||
from neutron.objects import subnet as subnet_obj
|
||||
from neutron.tests.unit.extensions import test_l3
|
||||
|
||||
|
||||
class FloatingIPPoolsTestExtensionManager(object):
|
||||
|
||||
def get_resources(self):
|
||||
return l3.L3.get_resources()
|
||||
|
||||
def get_actions(self):
|
||||
return []
|
||||
|
||||
def get_request_extensions(self):
|
||||
return []
|
||||
|
||||
|
||||
class TestFloatingIPPoolsIntPlugin(
|
||||
test_l3.TestL3NatIntPlugin,
|
||||
l3_fip_pools_db.FloatingIPPoolsDbMixin):
|
||||
supported_extension_aliases = ["external-net", "router",
|
||||
apidef.ALIAS]
|
||||
|
||||
|
||||
class TestFloatingIPPoolsL3NatServicePlugin(
|
||||
test_l3.TestL3NatServicePlugin,
|
||||
l3_fip_pools_db.FloatingIPPoolsDbMixin):
|
||||
supported_extension_aliases = ["router", apidef.ALIAS]
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class FloatingIPPoolsDBTestCaseBase(test_l3.L3NatTestCaseMixin):
|
||||
|
||||
def test_get_floatingip_pools_ipv4(self):
|
||||
self._test_get_floatingip_pools(lib_const.IP_VERSION_4, False)
|
||||
|
||||
@ddt.data(True, False)
|
||||
def test_get_floatingip_pools_ipv6(self, fake_is_v6_supported):
|
||||
self._test_get_floatingip_pools(lib_const.IP_VERSION_6,
|
||||
fake_is_v6_supported)
|
||||
|
||||
def _test_get_floatingip_pools(self, ip_version, is_v6_supported):
|
||||
fake_network_id = uuidutils.generate_uuid()
|
||||
fake_subnet_id = uuidutils.generate_uuid()
|
||||
fake_ext_network = mock.Mock(network_id=fake_network_id)
|
||||
if ip_version == lib_const.IP_VERSION_4:
|
||||
fake_cidr = '10.0.0.0/24'
|
||||
else:
|
||||
fake_cidr = 'fe80:cafe::/64'
|
||||
fake_subnet = mock.Mock(id=fake_subnet_id,
|
||||
network_id=fake_network_id,
|
||||
cidr=fake_cidr,
|
||||
ip_version=ip_version,
|
||||
tenant_id='fake_tenant',
|
||||
project_id='fake_tenant')
|
||||
fake_subnet.name = 'fake_subnet'
|
||||
self.plugin._is_v6_supported = is_v6_supported
|
||||
with mock.patch.object(
|
||||
subnet_obj.Subnet, 'get_objects',
|
||||
return_value=[fake_subnet]
|
||||
) as mock_subnet_get_objects, mock.patch.object(
|
||||
net_obj.ExternalNetwork, 'get_objects',
|
||||
return_value=[fake_ext_network]
|
||||
) as mock_extnet_get_objects, mock.patch.object(
|
||||
self.ctxt, 'elevated',
|
||||
return_value=self.admin_ctxt
|
||||
) as mock_context_elevated:
|
||||
fip_pools = self.plugin.get_floatingip_pools(self.ctxt)
|
||||
|
||||
expected_fip_pools = []
|
||||
if ip_version == lib_const.IP_VERSION_4 or is_v6_supported:
|
||||
expected_fip_pools = [{'cidr': fake_cidr,
|
||||
'subnet_id': fake_subnet_id,
|
||||
'subnet_name': 'fake_subnet',
|
||||
'network_id': fake_network_id,
|
||||
'project_id': 'fake_tenant',
|
||||
'tenant_id': 'fake_tenant'}]
|
||||
self.assertEqual(expected_fip_pools, fip_pools)
|
||||
mock_subnet_get_objects.assert_called_once_with(
|
||||
self.admin_ctxt, _pager=mock.ANY, network_id=[fake_network_id])
|
||||
mock_extnet_get_objects.assert_called_once_with(self.ctxt)
|
||||
mock_context_elevated.assert_called_once_with()
|
||||
|
||||
|
||||
class FloatingIPPoolsDBIntTestCase(test_l3.L3BaseForIntTests,
|
||||
FloatingIPPoolsDBTestCaseBase):
|
||||
|
||||
def setUp(self, plugin=None):
|
||||
if not plugin:
|
||||
plugin = ('neutron.tests.unit.extensions.test_floatingip_pools.'
|
||||
'TestFloatingIPPoolsIntPlugin')
|
||||
# for these tests we need to enable overlapping ips
|
||||
cfg.CONF.set_default('allow_overlapping_ips', True)
|
||||
cfg.CONF.set_default('max_routes', 3)
|
||||
ext_mgr = FloatingIPPoolsTestExtensionManager()
|
||||
super(test_l3.L3BaseForIntTests, self).setUp(
|
||||
plugin=plugin,
|
||||
ext_mgr=ext_mgr)
|
||||
|
||||
self.setup_notification_driver()
|
||||
self.ctxt = context.Context('fake_user', 'fake_tenant')
|
||||
self.admin_ctxt = self.ctxt.elevated()
|
||||
|
||||
|
||||
class FloatingIPPoolsDBSepTestCase(test_l3.L3BaseForSepTests,
|
||||
FloatingIPPoolsDBTestCaseBase):
|
||||
|
||||
def setUp(self):
|
||||
# the plugin without L3 support
|
||||
plugin = 'neutron.tests.unit.extensions.test_l3.TestNoL3NatPlugin'
|
||||
# the L3 service plugin
|
||||
l3_plugin = ('neutron.tests.unit.extensions.test_floatingip_pools.'
|
||||
'TestFloatingIPPoolsL3NatServicePlugin')
|
||||
service_plugins = {'l3_plugin_name': l3_plugin}
|
||||
|
||||
# for these tests we need to enable overlapping ips
|
||||
cfg.CONF.set_default('allow_overlapping_ips', True)
|
||||
cfg.CONF.set_default('max_routes', 3)
|
||||
ext_mgr = FloatingIPPoolsTestExtensionManager()
|
||||
super(test_l3.L3BaseForSepTests, self).setUp(
|
||||
plugin=plugin,
|
||||
ext_mgr=ext_mgr,
|
||||
service_plugins=service_plugins)
|
||||
|
||||
self.setup_notification_driver()
|
||||
self.plugin = directory.get_plugin(plugin_constants.L3)
|
||||
self.ctxt = context.Context('fake_user', 'fake_tenant')
|
||||
self.admin_ctxt = self.ctxt.elevated()
|
@ -0,0 +1,8 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Add support for listing floating ip pools (subnets) in L3 plugin.
|
||||
A new API resource ``floatingip-pools`` is introduced.
|
||||
This API endpoint can return a list of floating ip pools which are
|
||||
essentially mappings between network UUIDs and subnet CIDRs.
|
||||
Users can use this API to find out the pool to create the floating IPs.
|
Loading…
Reference in New Issue
Block a user