Merge "Add support for the multiprovider API to ML2"
This commit is contained in:
commit
38f76fc672
@ -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)
|
||||||
|
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user