Add port_details to Floating IP

If the floating IP is associated with a port, this attribute
will contain detailed information of the associated port. This allows
users to retrieve the floating IPs with information of its associated
port (if any) in one API call.

Other related patches:
* neutron-lib: https://review.openstack.org/#/c/534882/
* osc: https://review.openstack.org/#/c/533809/
* sdk: https://review.openstack.org/#/c/533811/
* tempest-plugin: https://review.openstack.org/#/c/561710/

APIImpact the API reference needs to be updated

Change-Id: I31e940d2986278d2fbee6fdfea4ff15f7c07ebaa
Partial-Bug: #1723026
This commit is contained in:
Hongbin Lu 2018-01-12 23:52:26 +00:00 committed by Hongbin Lu
parent f2dced777a
commit c760d4f26f
8 changed files with 257 additions and 2 deletions

View File

@ -0,0 +1,42 @@
#
# 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 l3 as l3_apidef
from neutron.db import _resource_extend as resource_extend
def _make_port_details_dict(port):
return {'name': port['name'],
'network_id': port['network_id'],
'mac_address': port['mac_address'],
'admin_state_up': port['admin_state_up'],
'status': port['status'],
'device_id': port['device_id'],
'device_owner': port['device_owner']}
@resource_extend.has_resource_extenders
class Fip_port_details_db_mixin(object):
"""Mixin class to enable floating IP's port_details attributes."""
@staticmethod
@resource_extend.extends([l3_apidef.FLOATINGIPS])
def _extend_fip_dict_device_id(fip_res, fip_db):
if fip_db.fixed_port:
fip_res['port_details'] = _make_port_details_dict(
fip_db.fixed_port)
else:
fip_res['port_details'] = None
return fip_res

View File

@ -90,6 +90,9 @@ class FloatingIP(standard_attr.HasStandardAttributes, model_base.BASEV2,
cascade='all,delete-orphan'),
foreign_keys='FloatingIP.floating_port_id')
fixed_port_id = sa.Column(sa.String(36), sa.ForeignKey('ports.id'))
fixed_port = orm.relationship(models_v2.Port,
foreign_keys='FloatingIP.fixed_port_id',
lazy='joined')
fixed_ip_address = sa.Column(sa.String(64))
router_id = sa.Column(sa.String(36), sa.ForeignKey('routers.id'))
# Additional attribute for keeping track of the router where the floating

View File

@ -0,0 +1,43 @@
# 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.
"""
TODO(hongbin): This module should be deleted once neutron-lib containing
https://review.openstack.org/#/c/534882/ change is released.
"""
from neutron_lib.api.definitions import l3
from neutron_lib import constants
PORT_DETAILS = 'port_details'
ALIAS = 'fip-port-details'
IS_SHIM_EXTENSION = False
IS_STANDARD_ATTR_EXTENSION = False
NAME = 'Floating IP Port Details Extension'
DESCRIPTION = 'Add port_details attribute to Floating IP resource'
UPDATED_TIMESTAMP = '2018-04-09T10:00:00-00:00'
RESOURCE_ATTRIBUTE_MAP = {
l3.FLOATINGIPS: {
PORT_DETAILS: {
'allow_post': False, 'allow_put': False,
'default': constants.ATTR_NOT_SPECIFIED,
'is_visible': True
}
}
}
SUB_RESOURCE_ATTRIBUTE_MAP = {}
ACTION_MAP = {}
REQUIRED_EXTENSIONS = [l3.ALIAS]
OPTIONAL_EXTENSIONS = []
ACTION_STATUS = {}

View File

@ -0,0 +1,21 @@
# 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 import extensions
from neutron.extensions import _fip_port_details_lib as apidef
class Fip_port_details(extensions.APIExtensionDescriptor):
"""Extension class adding port_details to Floating IP."""
api_definition = apidef

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_port_details
from neutron.db import l3_fip_qos
from neutron.db import l3_gwmode_db
from neutron.db import l3_hamode_db
@ -67,7 +68,8 @@ class L3RouterPlugin(service_base.ServicePluginBase,
l3_gwmode_db.L3_NAT_db_mixin,
l3_dvr_ha_scheduler_db.L3_DVR_HA_scheduler_db_mixin,
dns_db.DNSDbMixin,
l3_fip_qos.FloatingQoSDbMixin):
l3_fip_qos.FloatingQoSDbMixin,
l3_fip_port_details.Fip_port_details_db_mixin):
"""Implementation of the Neutron L3 Router Service Plugin.
@ -81,7 +83,8 @@ class L3RouterPlugin(service_base.ServicePluginBase,
_supported_extension_aliases = ["dvr", "router", "ext-gw-mode",
"extraroute", "l3_agent_scheduler",
"l3-ha", "router_availability_zone",
"l3-flavors", "qos-fip"]
"l3-flavors", "qos-fip",
"fip-port-details"]
__native_pagination_support = True
__native_sorting_support = True

View File

@ -14,6 +14,7 @@ NETWORK_API_EXTENSIONS+=",ext-gw-mode"
NETWORK_API_EXTENSIONS+=",external-net"
NETWORK_API_EXTENSIONS+=",extra_dhcp_opt"
NETWORK_API_EXTENSIONS+=",extraroute"
NETWORK_API_EXTENSIONS+=",fip-port-details"
NETWORK_API_EXTENSIONS+=",flavors"
NETWORK_API_EXTENSIONS+=",ip-substring-filtering"
NETWORK_API_EXTENSIONS+=",l3-flavors"

View File

@ -0,0 +1,136 @@
#
# 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 neutron.db import l3_fip_port_details
from neutron.extensions import _fip_port_details_lib as apiref
from neutron.extensions import l3
from neutron.tests.unit.extensions import test_l3
class FloatingIPPortDetailsTestExtensionManager(object):
def get_resources(self):
return l3.L3.get_resources()
def get_actions(self):
return []
def get_request_extensions(self):
return []
class TestFloatingIPPortDetailsIntPlugin(
test_l3.TestL3NatIntPlugin,
l3_fip_port_details.Fip_port_details_db_mixin):
supported_extension_aliases = ["external-net", "router",
apiref.ALIAS]
class TestFloatingIPPortDetailsL3NatServicePlugin(
test_l3.TestL3NatServicePlugin,
l3_fip_port_details.Fip_port_details_db_mixin):
supported_extension_aliases = ["router", apiref.ALIAS]
class FloatingIPPortDetailsDBTestCaseBase(test_l3.L3NatTestCaseMixin):
def _assert_port_details(self, port, port_details):
port['name'] = port_details['name']
port['network_id'] = port_details['network_id']
port['mac_address'] = port_details['mac_address']
port['admin_state_up'] = port_details['admin_state_up']
port['status'] = port_details['status']
port['device_id'] = port_details['device_id']
port['device_owner'] = port_details['device_owner']
def test_floatingip_create_with_port_details(self):
with self.port() as p:
with self.floatingip_with_assoc(port_id=p['port']['id']) as fip:
body = self._show('floatingips', fip['floatingip']['id'])
self.assertEqual(body['floatingip']['id'],
fip['floatingip']['id'])
self.assertEqual(body['floatingip']['port_id'],
fip['floatingip']['port_id'])
self._assert_port_details(
p['port'], body['floatingip']['port_details'])
def test_floatingip_update_with_port_details(self):
with self.port() as p:
private_sub = {'subnet': {'id':
p['port']['fixed_ips'][0]['subnet_id']}}
with self.floatingip_no_assoc(private_sub) as fip:
body = self._show('floatingips', fip['floatingip']['id'])
self.assertIsNone(body['floatingip']['port_id'])
self.assertIsNone(body['floatingip']['port_details'])
port_id = p['port']['id']
body = self._update('floatingips', fip['floatingip']['id'],
{'floatingip': {'port_id': port_id}})
self.assertEqual(port_id, body['floatingip']['port_id'])
self._assert_port_details(
p['port'], body['floatingip']['port_details'])
def test_floatingip_list_with_port_details(self):
with self.port() as p:
with self.floatingip_with_assoc(port_id=p['port']['id']) as fip:
body = self._list('floatingips')
self.assertEqual(body['floatingips'][0]['id'],
fip['floatingip']['id'])
self.assertEqual(body['floatingips'][0]['port_id'],
fip['floatingip']['port_id'])
self._assert_port_details(
p['port'], body['floatingips'][0]['port_details'])
class FloatingIPPortDetailsDBIntTestCase(test_l3.L3BaseForIntTests,
FloatingIPPortDetailsDBTestCaseBase):
def setUp(self, plugin=None):
if not plugin:
plugin = ('neutron.tests.unit.extensions.test_fip_port_details.'
'TestFloatingIPPortDetailsIntPlugin')
# 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 = FloatingIPPortDetailsTestExtensionManager()
super(test_l3.L3BaseForIntTests, self).setUp(
plugin=plugin,
ext_mgr=ext_mgr)
self.setup_notification_driver()
class FloatingIPPortDetailsDBSepTestCase(test_l3.L3BaseForSepTests,
FloatingIPPortDetailsDBTestCaseBase):
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_fip_port_details.'
'TestFloatingIPPortDetailsL3NatServicePlugin')
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 = FloatingIPPortDetailsTestExtensionManager()
super(test_l3.L3BaseForSepTests, self).setUp(
plugin=plugin,
ext_mgr=ext_mgr,
service_plugins=service_plugins)
self.setup_notification_driver()

View File

@ -0,0 +1,6 @@
---
features:
- |
Add attribute ``port_details`` to floating IP. The value of this attribute
contains information of the associated port.