Merge "Add support for the multiprovider API to ML2"

This commit is contained in:
Jenkins 2013-09-05 06:01:30 +00:00 committed by Gerrit Code Review
commit 38f76fc672
2 changed files with 162 additions and 26 deletions

View File

@ -29,6 +29,7 @@ from neutron.db import l3_gwmode_db
from neutron.db import models_v2 from neutron.db import models_v2
from neutron.db import quota_db # noqa 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 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.openstack.common import excutils from neutron.openstack.common import excutils
@ -77,7 +78,8 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
_supported_extension_aliases = ["provider", "router", "extraroute", _supported_extension_aliases = ["provider", "router", "extraroute",
"binding", "quotas", "security-group", "binding", "quotas", "security-group",
"agent", "l3_agent_scheduler", "agent", "l3_agent_scheduler",
"dhcp_agent_scheduler", "ext-gw-mode"] "dhcp_agent_scheduler", "ext-gw-mode",
"multi-provider"]
@property @property
def supported_extension_aliases(self): def supported_extension_aliases(self):
@ -123,26 +125,49 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
fanout=False) fanout=False)
self.conn.consume_in_thread() self.conn.consume_in_thread()
def _process_provider_create(self, context, attrs): def _process_provider_segment(self, segment):
network_type = self._get_attribute(attrs, provider.NETWORK_TYPE) network_type = self._get_attribute(segment, provider.NETWORK_TYPE)
physical_network = self._get_attribute(attrs, physical_network = self._get_attribute(segment,
provider.PHYSICAL_NETWORK) provider.PHYSICAL_NETWORK)
segmentation_id = self._get_attribute(attrs, provider.SEGMENTATION_ID) segmentation_id = self._get_attribute(segment,
provider.SEGMENTATION_ID)
if attributes.is_attr_set(network_type): if attributes.is_attr_set(network_type):
segment = {api.NETWORK_TYPE: network_type, segment = {api.NETWORK_TYPE: network_type,
api.PHYSICAL_NETWORK: physical_network, api.PHYSICAL_NETWORK: physical_network,
api.SEGMENTATION_ID: segmentation_id} api.SEGMENTATION_ID: segmentation_id}
self.type_manager.validate_provider_segment(segment) self.type_manager.validate_provider_segment(segment)
return segment return segment
if (attributes.is_attr_set(attrs.get(provider.PHYSICAL_NETWORK)) or msg = _("network_type required")
attributes.is_attr_set(attrs.get(provider.SEGMENTATION_ID))):
msg = _("network_type required if other provider attributes "
"specified")
raise exc.InvalidInput(error_message=msg) raise exc.InvalidInput(error_message=msg)
def _process_provider_create(self, network):
segments = []
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}]
elif attributes.is_attr_set(network.get(mpnet.SEGMENTS)):
segments = network[mpnet.SEGMENTS]
else:
return
return [self._process_provider_segment(s) for s in segments]
def _get_attribute(self, attrs, key): def _get_attribute(self, attrs, key):
value = attrs.get(key) value = attrs.get(key)
if value is attributes.ATTR_NOT_SPECIFIED: if value is attributes.ATTR_NOT_SPECIFIED:
@ -158,9 +183,11 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
network[provider.PHYSICAL_NETWORK] = None network[provider.PHYSICAL_NETWORK] = None
network[provider.SEGMENTATION_ID] = None network[provider.SEGMENTATION_ID] = None
elif len(segments) > 1: elif len(segments) > 1:
network[provider.NETWORK_TYPE] = TYPE_MULTI_SEGMENT network[mpnet.SEGMENTS] = [
network[provider.PHYSICAL_NETWORK] = None {provider.NETWORK_TYPE: segment[api.NETWORK_TYPE],
network[provider.SEGMENTATION_ID] = None provider.PHYSICAL_NETWORK: segment[api.PHYSICAL_NETWORK],
provider.SEGMENTATION_ID: segment[api.SEGMENTATION_ID]}
for segment in segments]
else: else:
segment = segments[0] segment = segments[0]
network[provider.NETWORK_TYPE] = segment[api.NETWORK_TYPE] network[provider.NETWORK_TYPE] = segment[api.NETWORK_TYPE]
@ -260,23 +287,26 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
# TODO(apech): Need to override bulk operations # TODO(apech): Need to override bulk operations
def create_network(self, context, network): def create_network(self, context, network):
attrs = network['network'] net_data = network['network']
segment = self._process_provider_create(context, attrs) segments = self._process_provider_create(net_data)
tenant_id = self._get_tenant_id_for_create(context, attrs) 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)
if segment:
self.type_manager.reserve_provider_segment(session, segment)
else:
segment = self.type_manager.allocate_tenant_segment(session)
result = super(Ml2Plugin, self).create_network(context, network) result = super(Ml2Plugin, self).create_network(context, network)
id = result['id'] network_id = result['id']
self._process_l3_create(context, result, attrs) self._process_l3_create(context, result, net_data)
# REVISIT(rkukura): Consider moving all segment management # REVISIT(rkukura): Consider moving all segment management
# to TypeManager. # to TypeManager.
db.add_network_segment(session, id, segment) if segments:
for segment in segments:
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) self._extend_network_dict_provider(context, result)
mech_context = driver_context.NetworkContext(self, context, mech_context = driver_context.NetworkContext(self, context,
result) result)

View File

@ -13,8 +13,10 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from neutron.extensions import multiprovidernet as mpnet
from neutron.extensions import portbindings from neutron.extensions import portbindings
from neutron.plugins.ml2 import config as config from neutron.extensions import providernet as pnet
from neutron.plugins.ml2 import config
from neutron.tests.unit import _test_extension_portbindings as test_bindings from neutron.tests.unit import _test_extension_portbindings as test_bindings
from neutron.tests.unit import test_db_plugin as test_plugin from neutron.tests.unit import test_db_plugin as test_plugin
from neutron.tests.unit import test_extension_ext_gw_mode from neutron.tests.unit import test_extension_ext_gw_mode
@ -34,7 +36,12 @@ class Ml2PluginV2TestCase(test_plugin.NeutronDbPluginV2TestCase):
# driver apis. # driver apis.
config.cfg.CONF.set_override('mechanism_drivers', config.cfg.CONF.set_override('mechanism_drivers',
['logger', 'test'], ['logger', 'test'],
'ml2') group='ml2')
self.physnet = 'physnet1'
self.vlan_range = '1:100'
self.phys_vrange = ':'.join([self.physnet, self.vlan_range])
config.cfg.CONF.set_override('network_vlan_ranges', [self.phys_vrange],
group='ml2_type_vlan')
self.addCleanup(config.cfg.CONF.reset) self.addCleanup(config.cfg.CONF.reset)
super(Ml2PluginV2TestCase, self).setUp(PLUGIN_NAME) super(Ml2PluginV2TestCase, self).setUp(PLUGIN_NAME)
self.port_create_status = 'DOWN' self.port_create_status = 'DOWN'
@ -89,3 +96,102 @@ class TestMl2PortBindingHost(Ml2PluginV2TestCase,
class TestMl2ExtGwModeSupport(Ml2PluginV2TestCase, class TestMl2ExtGwModeSupport(Ml2PluginV2TestCase,
test_extension_ext_gw_mode.ExtGwModeTestCase): test_extension_ext_gw_mode.ExtGwModeTestCase):
pass pass
class TestMultiSegmentNetworks(Ml2PluginV2TestCase):
def setUp(self, plugin=None):
super(TestMultiSegmentNetworks, self).setUp()
def test_create_network_provider(self):
data = {'network': {'name': 'net1',
pnet.NETWORK_TYPE: 'vlan',
pnet.PHYSICAL_NETWORK: 'physnet1',
pnet.SEGMENTATION_ID: 1,
'tenant_id': 'tenant_one'}}
network_req = self.new_create_request('networks', data)
network = self.deserialize(self.fmt,
network_req.get_response(self.api))
self.assertEqual(network['network'][pnet.NETWORK_TYPE], 'vlan')
self.assertEqual(network['network'][pnet.PHYSICAL_NETWORK], 'physnet1')
self.assertEqual(network['network'][pnet.SEGMENTATION_ID], 1)
self.assertNotIn(mpnet.SEGMENTS, network['network'])
def test_create_network_single_multiprovider(self):
data = {'network': {'name': 'net1',
mpnet.SEGMENTS:
[{pnet.NETWORK_TYPE: 'vlan',
pnet.PHYSICAL_NETWORK: 'physnet1',
pnet.SEGMENTATION_ID: 1}],
'tenant_id': 'tenant_one'}}
net_req = self.new_create_request('networks', data)
network = self.deserialize(self.fmt, net_req.get_response(self.api))
self.assertEqual(network['network'][pnet.NETWORK_TYPE], 'vlan')
self.assertEqual(network['network'][pnet.PHYSICAL_NETWORK], 'physnet1')
self.assertEqual(network['network'][pnet.SEGMENTATION_ID], 1)
self.assertNotIn(mpnet.SEGMENTS, network['network'])
# Tests get_network()
net_req = self.new_show_request('networks', network['network']['id'])
network = self.deserialize(self.fmt, net_req.get_response(self.api))
self.assertEqual(network['network'][pnet.NETWORK_TYPE], 'vlan')
self.assertEqual(network['network'][pnet.PHYSICAL_NETWORK], 'physnet1')
self.assertEqual(network['network'][pnet.SEGMENTATION_ID], 1)
self.assertNotIn(mpnet.SEGMENTS, network['network'])
def test_create_network_multiprovider(self):
data = {'network': {'name': 'net1',
mpnet.SEGMENTS:
[{pnet.NETWORK_TYPE: 'vlan',
pnet.PHYSICAL_NETWORK: 'physnet1',
pnet.SEGMENTATION_ID: 1},
{pnet.NETWORK_TYPE: 'vlan',
pnet.PHYSICAL_NETWORK: 'physnet1',
pnet.SEGMENTATION_ID: 2}],
'tenant_id': 'tenant_one'}}
network_req = self.new_create_request('networks', data)
network = self.deserialize(self.fmt,
network_req.get_response(self.api))
tz = network['network'][mpnet.SEGMENTS]
for tz in data['network'][mpnet.SEGMENTS]:
for field in [pnet.NETWORK_TYPE, pnet.PHYSICAL_NETWORK,
pnet.SEGMENTATION_ID]:
self.assertEqual(tz.get(field), tz.get(field))
# Tests get_network()
net_req = self.new_show_request('networks', network['network']['id'])
network = self.deserialize(self.fmt, net_req.get_response(self.api))
tz = network['network'][mpnet.SEGMENTS]
for tz in data['network'][mpnet.SEGMENTS]:
for field in [pnet.NETWORK_TYPE, pnet.PHYSICAL_NETWORK,
pnet.SEGMENTATION_ID]:
self.assertEqual(tz.get(field), tz.get(field))
def test_create_network_with_provider_and_multiprovider_fail(self):
data = {'network': {'name': 'net1',
mpnet.SEGMENTS:
[{pnet.NETWORK_TYPE: 'vlan',
pnet.PHYSICAL_NETWORK: 'physnet1',
pnet.SEGMENTATION_ID: 1}],
pnet.NETWORK_TYPE: 'vlan',
pnet.PHYSICAL_NETWORK: 'physnet1',
pnet.SEGMENTATION_ID: 1,
'tenant_id': 'tenant_one'}}
network_req = self.new_create_request('networks', data)
res = network_req.get_response(self.api)
self.assertEqual(res.status_int, 400)
def test_create_network_duplicate_segments(self):
data = {'network': {'name': 'net1',
mpnet.SEGMENTS:
[{pnet.NETWORK_TYPE: 'vlan',
pnet.PHYSICAL_NETWORK: 'physnet1',
pnet.SEGMENTATION_ID: 1},
{pnet.NETWORK_TYPE: 'vlan',
pnet.PHYSICAL_NETWORK: 'physnet1',
pnet.SEGMENTATION_ID: 1}],
'tenant_id': 'tenant_one'}}
network_req = self.new_create_request('networks', data)
res = network_req.get_response(self.api)
self.assertEqual(res.status_int, 400)