From 43aed62f267fb02b38019038f5df95e062ea913b Mon Sep 17 00:00:00 2001 From: Arvind Somya Date: Fri, 15 Aug 2014 14:22:05 -0700 Subject: [PATCH] ML2 Type driver refactor part 1 This commit moves segment management from the ML2 plugin to the type manager in preparation for dynamic segment support. Partially implements: Blueprint ml2-type-driver-refactor Change-Id: I068b82369250d115ef91680f19e733ed9aa4659b --- neutron/plugins/ml2/managers.py | 89 ++++++++++++++++++++- neutron/plugins/ml2/plugin.py | 95 ++--------------------- neutron/tests/unit/ml2/test_ml2_plugin.py | 5 +- 3 files changed, 99 insertions(+), 90 deletions(-) diff --git a/neutron/plugins/ml2/managers.py b/neutron/plugins/ml2/managers.py index 33293823c7..d679e7dd5b 100644 --- a/neutron/plugins/ml2/managers.py +++ b/neutron/plugins/ml2/managers.py @@ -16,13 +16,16 @@ from oslo.config import cfg import stevedore +from neutron.api.v2 import attributes from neutron.common import exceptions as exc +from neutron.extensions import multiprovidernet as mpnet from neutron.extensions import portbindings +from neutron.extensions import providernet as provider from neutron.openstack.common import log from neutron.plugins.ml2.common import exceptions as ml2_exc +from neutron.plugins.ml2 import db from neutron.plugins.ml2 import driver_api as api - LOG = log.getLogger(__name__) @@ -68,11 +71,95 @@ class TypeManager(stevedore.named.NamedExtensionManager): raise SystemExit(1) LOG.info(_("Tenant network_types: %s"), self.tenant_network_types) + def _process_provider_segment(self, segment): + network_type = self._get_attribute(segment, provider.NETWORK_TYPE) + physical_network = self._get_attribute(segment, + provider.PHYSICAL_NETWORK) + segmentation_id = self._get_attribute(segment, + provider.SEGMENTATION_ID) + + if attributes.is_attr_set(network_type): + segment = {api.NETWORK_TYPE: network_type, + api.PHYSICAL_NETWORK: physical_network, + api.SEGMENTATION_ID: segmentation_id} + self.validate_provider_segment(segment) + return segment + + msg = _("network_type required") + raise exc.InvalidInput(error_message=msg) + + def _process_provider_create(self, network): + if any(attributes.is_attr_set(network.get(f)) + for f in (provider.NETWORK_TYPE, provider.PHYSICAL_NETWORK, + provider.SEGMENTATION_ID)): + # Verify that multiprovider and provider attributes are not set + # at the same time. + if attributes.is_attr_set(network.get(mpnet.SEGMENTS)): + raise mpnet.SegmentsSetInConjunctionWithProviders() + + network_type = self._get_attribute(network, provider.NETWORK_TYPE) + physical_network = self._get_attribute(network, + provider.PHYSICAL_NETWORK) + segmentation_id = self._get_attribute(network, + provider.SEGMENTATION_ID) + segments = [{provider.NETWORK_TYPE: network_type, + provider.PHYSICAL_NETWORK: physical_network, + provider.SEGMENTATION_ID: segmentation_id}] + return [self._process_provider_segment(s) for s in segments] + elif attributes.is_attr_set(network.get(mpnet.SEGMENTS)): + segments = [self._process_provider_segment(s) + for s in network[mpnet.SEGMENTS]] + mpnet.check_duplicate_segments( + segments, + self.is_partial_segment) + return segments + + def _get_attribute(self, attrs, key): + value = attrs.get(key) + if value is attributes.ATTR_NOT_SPECIFIED: + value = None + return value + + def _extend_network_dict_provider(self, context, network): + id = network['id'] + segments = db.get_network_segments(context.session, id) + if not segments: + LOG.error(_("Network %s has no segments"), id) + network[provider.NETWORK_TYPE] = None + network[provider.PHYSICAL_NETWORK] = None + network[provider.SEGMENTATION_ID] = None + elif len(segments) > 1: + network[mpnet.SEGMENTS] = [ + {provider.NETWORK_TYPE: segment[api.NETWORK_TYPE], + provider.PHYSICAL_NETWORK: segment[api.PHYSICAL_NETWORK], + provider.SEGMENTATION_ID: segment[api.SEGMENTATION_ID]} + for segment in segments] + else: + segment = segments[0] + network[provider.NETWORK_TYPE] = segment[api.NETWORK_TYPE] + network[provider.PHYSICAL_NETWORK] = segment[api.PHYSICAL_NETWORK] + network[provider.SEGMENTATION_ID] = segment[api.SEGMENTATION_ID] + def initialize(self): for network_type, driver in self.drivers.iteritems(): LOG.info(_("Initializing driver for type '%s'"), network_type) driver.obj.initialize() + def create_network_segments(self, context, network, tenant_id): + """Call type drivers to create network segments.""" + segments = self._process_provider_create(network) + session = context.session + with session.begin(subtransactions=True): + network_id = network['id'] + if segments: + for segment in segments: + segment = self.reserve_provider_segment( + session, segment) + db.add_network_segment(session, network_id, segment) + else: + segment = self.allocate_tenant_segment(session) + db.add_network_segment(session, network_id, segment) + def is_partial_segment(self, segment): network_type = segment[api.NETWORK_TYPE] driver = self.drivers.get(network_type) diff --git a/neutron/plugins/ml2/plugin.py b/neutron/plugins/ml2/plugin.py index c29122eaf1..dae053c927 100644 --- a/neutron/plugins/ml2/plugin.py +++ b/neutron/plugins/ml2/plugin.py @@ -41,7 +41,6 @@ from neutron.db import quota_db # noqa from neutron.db import securitygroups_rpc_base as sg_db_rpc from neutron.extensions import allowedaddresspairs as addr_pair from neutron.extensions import extra_dhcp_opt as edo_ext -from neutron.extensions import multiprovidernet as mpnet from neutron.extensions import portbindings from neutron.extensions import providernet as provider from neutron import manager @@ -142,75 +141,6 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, fanout=False) return self.conn.consume_in_threads() - def _process_provider_segment(self, segment): - network_type = self._get_attribute(segment, provider.NETWORK_TYPE) - physical_network = self._get_attribute(segment, - provider.PHYSICAL_NETWORK) - segmentation_id = self._get_attribute(segment, - provider.SEGMENTATION_ID) - - if attributes.is_attr_set(network_type): - segment = {api.NETWORK_TYPE: network_type, - api.PHYSICAL_NETWORK: physical_network, - api.SEGMENTATION_ID: segmentation_id} - self.type_manager.validate_provider_segment(segment) - return segment - - msg = _("network_type required") - raise exc.InvalidInput(error_message=msg) - - def _process_provider_create(self, network): - if any(attributes.is_attr_set(network.get(f)) - for f in (provider.NETWORK_TYPE, provider.PHYSICAL_NETWORK, - provider.SEGMENTATION_ID)): - # Verify that multiprovider and provider attributes are not set - # at the same time. - if attributes.is_attr_set(network.get(mpnet.SEGMENTS)): - raise mpnet.SegmentsSetInConjunctionWithProviders() - - network_type = self._get_attribute(network, provider.NETWORK_TYPE) - physical_network = self._get_attribute(network, - provider.PHYSICAL_NETWORK) - segmentation_id = self._get_attribute(network, - provider.SEGMENTATION_ID) - segments = [{provider.NETWORK_TYPE: network_type, - provider.PHYSICAL_NETWORK: physical_network, - provider.SEGMENTATION_ID: segmentation_id}] - return [self._process_provider_segment(s) for s in segments] - elif attributes.is_attr_set(network.get(mpnet.SEGMENTS)): - segments = [self._process_provider_segment(s) - for s in network[mpnet.SEGMENTS]] - mpnet.check_duplicate_segments( - segments, - self.type_manager.is_partial_segment) - return segments - - def _get_attribute(self, attrs, key): - value = attrs.get(key) - if value is attributes.ATTR_NOT_SPECIFIED: - value = None - return value - - def _extend_network_dict_provider(self, context, network): - id = network['id'] - segments = db.get_network_segments(context.session, id) - if not segments: - LOG.error(_("Network %s has no segments"), id) - network[provider.NETWORK_TYPE] = None - network[provider.PHYSICAL_NETWORK] = None - network[provider.SEGMENTATION_ID] = None - elif len(segments) > 1: - network[mpnet.SEGMENTS] = [ - {provider.NETWORK_TYPE: segment[api.NETWORK_TYPE], - provider.PHYSICAL_NETWORK: segment[api.PHYSICAL_NETWORK], - provider.SEGMENTATION_ID: segment[api.SEGMENTATION_ID]} - for segment in segments] - else: - segment = segments[0] - network[provider.NETWORK_TYPE] = segment[api.NETWORK_TYPE] - network[provider.PHYSICAL_NETWORK] = segment[api.PHYSICAL_NETWORK] - network[provider.SEGMENTATION_ID] = segment[api.SEGMENTATION_ID] - def _filter_nets_provider(self, context, nets, filters): # TODO(rkukura): Implement filtering. return nets @@ -512,26 +442,16 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, def create_network(self, context, network): net_data = network['network'] - segments = self._process_provider_create(net_data) tenant_id = self._get_tenant_id_for_create(context, net_data) - session = context.session with session.begin(subtransactions=True): self._ensure_default_security_group(context, tenant_id) result = super(Ml2Plugin, self).create_network(context, network) - network_id = result['id'] self._process_l3_create(context, result, net_data) - # REVISIT(rkukura): Consider moving all segment management - # to TypeManager. - if segments: - for segment in segments: - segment = self.type_manager.reserve_provider_segment( - session, segment) - db.add_network_segment(session, network_id, segment) - else: - segment = self.type_manager.allocate_tenant_segment(session) - db.add_network_segment(session, network_id, segment) - self._extend_network_dict_provider(context, result) + net_data['id'] = result['id'] + self.type_manager.create_network_segments(context, net_data, + tenant_id) + self.type_manager._extend_network_dict_provider(context, result) mech_context = driver_context.NetworkContext(self, context, result) self.mechanism_manager.create_network_precommit(mech_context) @@ -556,7 +476,8 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, network) self._process_l3_update(context, updated_network, network['network']) - self._extend_network_dict_provider(context, updated_network) + self.type_manager._extend_network_dict_provider(context, + updated_network) mech_context = driver_context.NetworkContext( self, context, updated_network, original_network=original_network) @@ -573,7 +494,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, session = context.session with session.begin(subtransactions=True): result = super(Ml2Plugin, self).get_network(context, id, None) - self._extend_network_dict_provider(context, result) + self.type_manager._extend_network_dict_provider(context, result) return self._fields(result, fields) @@ -585,7 +506,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, self).get_networks(context, filters, None, sorts, limit, marker, page_reverse) for net in nets: - self._extend_network_dict_provider(context, net) + self.type_manager._extend_network_dict_provider(context, net) nets = self._filter_nets_provider(context, nets, filters) nets = self._filter_nets_l3(context, nets, filters) diff --git a/neutron/tests/unit/ml2/test_ml2_plugin.py b/neutron/tests/unit/ml2/test_ml2_plugin.py index 6cbc858013..5e2d261ae4 100644 --- a/neutron/tests/unit/ml2/test_ml2_plugin.py +++ b/neutron/tests/unit/ml2/test_ml2_plugin.py @@ -477,7 +477,7 @@ class TestMultiSegmentNetworks(Ml2PluginV2TestCase): pnet.PHYSICAL_NETWORK: 'phys_net', pnet.SEGMENTATION_ID: None} with testtools.ExpectedException(exc.InvalidInput): - self.driver._process_provider_create(segment) + self.driver.type_manager._process_provider_create(segment) def test_create_network_plugin(self): data = {'network': {'name': 'net1', @@ -499,7 +499,8 @@ class TestMultiSegmentNetworks(Ml2PluginV2TestCase): def test_extend_dictionary_no_segments(self): network = dict(name='net_no_segment', id='5', tenant_id='tenant_one') - self.driver._extend_network_dict_provider(self.context, network) + self.driver.type_manager._extend_network_dict_provider(self.context, + network) self.assertIsNone(network[pnet.NETWORK_TYPE]) self.assertIsNone(network[pnet.PHYSICAL_NETWORK]) self.assertIsNone(network[pnet.SEGMENTATION_ID])