Merge "Introduce floating IP pool resource"

This commit is contained in:
Zuul 2018-10-30 06:54:59 +00:00 committed by Gerrit Code Review
commit eb8759aa98
8 changed files with 300 additions and 2 deletions

View File

@ -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",

View 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

View 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

View File

@ -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

View File

@ -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"

View File

@ -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",

View 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()

View File

@ -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.