From 3f570567ad3e00ab0682d9abb54e51a8425837c8 Mon Sep 17 00:00:00 2001 From: Ryan Tidwell Date: Tue, 28 Jun 2016 16:10:32 -0700 Subject: [PATCH] Fill in trunk_details on port resource This patch fills in the trunk_details field with trunk_id and sub_ports, exposing trunk-related information on the ports resource to consumers of the Neutron API. Change-Id: I1678301734e7f945e6f0400e62970b908da77a71 Partially-implements: blueprint vlan-aware-vms --- neutron/services/trunk/models.py | 2 + neutron/services/trunk/plugin.py | 18 ++++++ .../tests/tempest/api/test_trunk_details.py | 57 +++++++++++++++++++ 3 files changed, 77 insertions(+) create mode 100644 neutron/tests/tempest/api/test_trunk_details.py diff --git a/neutron/services/trunk/models.py b/neutron/services/trunk/models.py index c6eacbc1dc8..69933b66b54 100644 --- a/neutron/services/trunk/models.py +++ b/neutron/services/trunk/models.py @@ -32,6 +32,8 @@ class Trunk(model_base.HasStandardAttributes, model_base.BASEV2, backref=sa.orm.backref('trunk_port', lazy='joined', uselist=False, cascade='delete')) + sub_ports = sa.orm.relationship('SubPort', lazy='joined', uselist=True) + class SubPort(model_base.BASEV2): diff --git a/neutron/services/trunk/plugin.py b/neutron/services/trunk/plugin.py index a80678137ae..2d9ca450001 100644 --- a/neutron/services/trunk/plugin.py +++ b/neutron/services/trunk/plugin.py @@ -15,11 +15,13 @@ from oslo_log import log as logging from oslo_utils import uuidutils +from neutron.api.v2 import attributes from neutron.callbacks import events from neutron.callbacks import registry from neutron.db import api as db_api from neutron.db import common_db_mixin from neutron.db import db_base_plugin_common +from neutron.db import db_base_plugin_v2 from neutron.objects import base as objects_base from neutron.objects import trunk as trunk_objects from neutron.services import service_base @@ -30,12 +32,28 @@ from neutron.services.trunk import rules LOG = logging.getLogger(__name__) +def _extend_port_trunk_details(core_plugin, port_res, port_db): + """Add trunk details to a port.""" + if port_db.trunk_port: + subports = [{'segmentation_id': x.segmentation_id, + 'segmentation_type': x.segmentation_type, + 'port_id': x.port_id} + for x in port_db.trunk_port.sub_ports] + trunk_details = {'trunk_id': port_db.trunk_port.id, + 'sub_ports': subports} + port_res['trunk_details'] = trunk_details + + return port_res + + class TrunkPlugin(service_base.ServicePluginBase, common_db_mixin.CommonDbMixin): supported_extension_aliases = ["trunk", "trunk-details"] def __init__(self): + db_base_plugin_v2.NeutronDbPluginV2.register_dict_extend_funcs( + attributes.PORTS, [_extend_port_trunk_details]) self._segmentation_types = {} registry.notify(constants.TRUNK_PLUGIN, events.AFTER_INIT, self) LOG.debug('Trunk plugin loaded') diff --git a/neutron/tests/tempest/api/test_trunk_details.py b/neutron/tests/tempest/api/test_trunk_details.py new file mode 100644 index 00000000000..4b7ec289bc4 --- /dev/null +++ b/neutron/tests/tempest/api/test_trunk_details.py @@ -0,0 +1,57 @@ +# Copyright 2016 Hewlett Packard Enterprise Development Company LP +# +# 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 tempest import test + +from neutron.tests.tempest.api import test_trunk + + +class TestTrunkDetailsJSON(test_trunk.TrunkTestJSONBase): + + extension = 'trunk-details' + + @test.idempotent_id('f0bed24f-d36a-498b-b4e7-0d66e3fb7308') + def test_port_resource_trunk_details_no_subports(self): + trunk = self._create_trunk_with_network_and_parent([]) + port = self.client.show_port(trunk['trunk']['port_id']) + expected_trunk_details = {'sub_ports': [], + 'trunk_id': trunk['trunk']['id']} + observed_trunk_details = port['port'].get('trunk_details') + self.assertIsNotNone(observed_trunk_details) + self.assertEqual(expected_trunk_details, + observed_trunk_details) + + @test.idempotent_id('544bcaf2-86fb-4930-93ab-ece1c3cc33df') + def test_port_resource_trunk_details_with_subport(self): + subport_network = self.create_network() + parent_port = self.create_port(subport_network) + subport_data = {'port_id': parent_port['id'], + 'segmentation_type': 'vlan', + 'segmentation_id': 2} + trunk = self._create_trunk_with_network_and_parent([subport_data]) + port = self.client.show_port(trunk['trunk']['port_id']) + expected_trunk_details = {'sub_ports': [subport_data], + 'trunk_id': trunk['trunk']['id']} + observed_trunk_details = port['port'].get('trunk_details') + self.assertIsNotNone(observed_trunk_details) + self.assertEqual(expected_trunk_details, + observed_trunk_details) + + @test.idempotent_id('fe6d865f-1d5c-432e-b65d-904157172f24') + def test_port_resource_empty_trunk_details(self): + network = self.create_network() + port = self.create_port(network) + port = self.client.show_port(port['id']) + observed_trunk_details = port['port'].get('trunk_details') + self.assertIsNone(observed_trunk_details)