Merge "ML2 Type driver refactor part 1"
This commit is contained in:
commit
f718df7ec3
@ -16,13 +16,16 @@
|
|||||||
from oslo.config import cfg
|
from oslo.config import cfg
|
||||||
import stevedore
|
import stevedore
|
||||||
|
|
||||||
|
from neutron.api.v2 import attributes
|
||||||
from neutron.common import exceptions as exc
|
from neutron.common import exceptions as exc
|
||||||
|
from neutron.extensions import multiprovidernet as mpnet
|
||||||
from neutron.extensions import portbindings
|
from neutron.extensions import portbindings
|
||||||
|
from neutron.extensions import providernet as provider
|
||||||
from neutron.openstack.common import log
|
from neutron.openstack.common import log
|
||||||
from neutron.plugins.ml2.common import exceptions as ml2_exc
|
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
|
from neutron.plugins.ml2 import driver_api as api
|
||||||
|
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@ -68,11 +71,95 @@ class TypeManager(stevedore.named.NamedExtensionManager):
|
|||||||
raise SystemExit(1)
|
raise SystemExit(1)
|
||||||
LOG.info(_("Tenant network_types: %s"), self.tenant_network_types)
|
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):
|
def initialize(self):
|
||||||
for network_type, driver in self.drivers.iteritems():
|
for network_type, driver in self.drivers.iteritems():
|
||||||
LOG.info(_("Initializing driver for type '%s'"), network_type)
|
LOG.info(_("Initializing driver for type '%s'"), network_type)
|
||||||
driver.obj.initialize()
|
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):
|
def is_partial_segment(self, segment):
|
||||||
network_type = segment[api.NETWORK_TYPE]
|
network_type = segment[api.NETWORK_TYPE]
|
||||||
driver = self.drivers.get(network_type)
|
driver = self.drivers.get(network_type)
|
||||||
|
@ -41,7 +41,6 @@ from neutron.db import quota_db # noqa
|
|||||||
from neutron.db import securitygroups_rpc_base as sg_db_rpc
|
from neutron.db import securitygroups_rpc_base as sg_db_rpc
|
||||||
from neutron.extensions import allowedaddresspairs as addr_pair
|
from neutron.extensions import allowedaddresspairs as addr_pair
|
||||||
from neutron.extensions import extra_dhcp_opt as edo_ext
|
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 portbindings
|
||||||
from neutron.extensions import providernet as provider
|
from neutron.extensions import providernet as provider
|
||||||
from neutron import manager
|
from neutron import manager
|
||||||
@ -142,75 +141,6 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
fanout=False)
|
fanout=False)
|
||||||
return self.conn.consume_in_threads()
|
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):
|
def _filter_nets_provider(self, context, nets, filters):
|
||||||
# TODO(rkukura): Implement filtering.
|
# TODO(rkukura): Implement filtering.
|
||||||
return nets
|
return nets
|
||||||
@ -512,26 +442,16 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
|
|
||||||
def create_network(self, context, network):
|
def create_network(self, context, network):
|
||||||
net_data = network['network']
|
net_data = network['network']
|
||||||
segments = self._process_provider_create(net_data)
|
|
||||||
tenant_id = self._get_tenant_id_for_create(context, net_data)
|
tenant_id = self._get_tenant_id_for_create(context, net_data)
|
||||||
|
|
||||||
session = context.session
|
session = context.session
|
||||||
with session.begin(subtransactions=True):
|
with session.begin(subtransactions=True):
|
||||||
self._ensure_default_security_group(context, tenant_id)
|
self._ensure_default_security_group(context, tenant_id)
|
||||||
result = super(Ml2Plugin, self).create_network(context, network)
|
result = super(Ml2Plugin, self).create_network(context, network)
|
||||||
network_id = result['id']
|
|
||||||
self._process_l3_create(context, result, net_data)
|
self._process_l3_create(context, result, net_data)
|
||||||
# REVISIT(rkukura): Consider moving all segment management
|
net_data['id'] = result['id']
|
||||||
# to TypeManager.
|
self.type_manager.create_network_segments(context, net_data,
|
||||||
if segments:
|
tenant_id)
|
||||||
for segment in segments:
|
self.type_manager._extend_network_dict_provider(context, result)
|
||||||
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)
|
|
||||||
mech_context = driver_context.NetworkContext(self, context,
|
mech_context = driver_context.NetworkContext(self, context,
|
||||||
result)
|
result)
|
||||||
self.mechanism_manager.create_network_precommit(mech_context)
|
self.mechanism_manager.create_network_precommit(mech_context)
|
||||||
@ -556,7 +476,8 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
network)
|
network)
|
||||||
self._process_l3_update(context, updated_network,
|
self._process_l3_update(context, updated_network,
|
||||||
network['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(
|
mech_context = driver_context.NetworkContext(
|
||||||
self, context, updated_network,
|
self, context, updated_network,
|
||||||
original_network=original_network)
|
original_network=original_network)
|
||||||
@ -573,7 +494,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
session = context.session
|
session = context.session
|
||||||
with session.begin(subtransactions=True):
|
with session.begin(subtransactions=True):
|
||||||
result = super(Ml2Plugin, self).get_network(context, id, None)
|
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)
|
return self._fields(result, fields)
|
||||||
|
|
||||||
@ -585,7 +506,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
self).get_networks(context, filters, None, sorts,
|
self).get_networks(context, filters, None, sorts,
|
||||||
limit, marker, page_reverse)
|
limit, marker, page_reverse)
|
||||||
for net in nets:
|
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_provider(context, nets, filters)
|
||||||
nets = self._filter_nets_l3(context, nets, filters)
|
nets = self._filter_nets_l3(context, nets, filters)
|
||||||
|
@ -477,7 +477,7 @@ class TestMultiSegmentNetworks(Ml2PluginV2TestCase):
|
|||||||
pnet.PHYSICAL_NETWORK: 'phys_net',
|
pnet.PHYSICAL_NETWORK: 'phys_net',
|
||||||
pnet.SEGMENTATION_ID: None}
|
pnet.SEGMENTATION_ID: None}
|
||||||
with testtools.ExpectedException(exc.InvalidInput):
|
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):
|
def test_create_network_plugin(self):
|
||||||
data = {'network': {'name': 'net1',
|
data = {'network': {'name': 'net1',
|
||||||
@ -499,7 +499,8 @@ class TestMultiSegmentNetworks(Ml2PluginV2TestCase):
|
|||||||
|
|
||||||
def test_extend_dictionary_no_segments(self):
|
def test_extend_dictionary_no_segments(self):
|
||||||
network = dict(name='net_no_segment', id='5', tenant_id='tenant_one')
|
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.NETWORK_TYPE])
|
||||||
self.assertIsNone(network[pnet.PHYSICAL_NETWORK])
|
self.assertIsNone(network[pnet.PHYSICAL_NETWORK])
|
||||||
self.assertIsNone(network[pnet.SEGMENTATION_ID])
|
self.assertIsNone(network[pnet.SEGMENTATION_ID])
|
||||||
|
Loading…
Reference in New Issue
Block a user