Merge "neutron: retrieve physical network name from a multi-provider network" into stable/ocata

This commit is contained in:
Jenkins 2017-08-13 01:56:01 +00:00 committed by Gerrit Code Review
commit ea5c69538f
4 changed files with 137 additions and 3 deletions

View File

@ -1018,6 +1018,10 @@ class API(base_api.NetworkAPI):
self._refresh_neutron_extensions_cache(context, neutron=neutron)
return constants.AUTO_ALLOCATE_TOPO_EXT in self.extensions
def _has_multi_provider_extension(self, context, neutron=None):
self._refresh_neutron_extensions_cache(context, neutron=neutron)
return constants.MULTI_NET_EXT in self.extensions
def _get_pci_device_profile(self, pci_dev):
dev_spec = self.pci_whitelist.get_devspec(pci_dev)
if dev_spec:
@ -1401,6 +1405,37 @@ class API(base_api.NetworkAPI):
raise exception.FixedIpNotFoundForSpecificInstance(
instance_uuid=instance.uuid, ip=address)
def _get_phynet_info(self, context, neutron, net_id):
phynet_name = None
if self._has_multi_provider_extension(context, neutron=neutron):
network = neutron.show_network(net_id,
fields='segments').get('network')
segments = network.get('segments', {})
for net in segments:
# NOTE(vladikr): In general, "multi-segments" network is a
# combination of L2 segments. The current implementation
# contains a vxlan and vlan(s) segments, where only a vlan
# network will have a physical_network specified, but may
# change in the future. The purpose of this method
# is to find a first segment that provides a physical network.
# TODO(vladikr): Additional work will be required to handle the
# case of multiple vlan segments associated with different
# physical networks.
phynet_name = net.get('provider:physical_network')
if phynet_name:
return phynet_name
# Raising here as at least one segment should
# have a physical network provided.
if segments:
msg = (_("None of the segments of network %s provides a "
"physical_network") % net_id)
raise exception.NovaException(message=msg)
net = neutron.show_network(net_id,
fields='provider:physical_network').get('network')
phynet_name = net.get('provider:physical_network')
return phynet_name
def _get_port_vnic_info(self, context, neutron, port_id):
"""Retrieve port vnic info
@ -1414,9 +1449,7 @@ class API(base_api.NetworkAPI):
network_model.VNIC_TYPE_NORMAL)
if vnic_type in network_model.VNIC_TYPES_SRIOV:
net_id = port['network_id']
net = neutron.show_network(net_id,
fields='provider:physical_network').get('network')
phynet_name = net.get('provider:physical_network')
phynet_name = self._get_phynet_info(context, neutron, net_id)
return vnic_type, phynet_name
def create_pci_requests_for_sriov_ports(self, context, pci_requests,

View File

@ -19,3 +19,4 @@ PORTBINDING_EXT = 'Port Binding'
VNIC_INDEX_EXT = 'VNIC Index'
DNS_INTEGRATION = 'DNS Integration'
AUTO_ALLOCATE_TOPO_EXT = 'Auto Allocated Topology Services'
MULTI_NET_EXT = 'Multi Provider Network'

View File

@ -3138,6 +3138,98 @@ class TestNeutronv2(TestNeutronv2Base):
self.assertEqual(0, len(networks))
@mock.patch.object(neutronapi, 'get_client', return_value=mock.Mock())
def test_get_port_vnic_info_multi_segment(self, mock_get_client):
api = neutronapi.API()
self.mox.ResetAll()
test_port = {
'port': {'id': 'my_port_id1',
'network_id': 'net-id',
'binding:vnic_type': model.VNIC_TYPE_DIRECT,
},
}
test_net = {'network': {'segments':
[{'provider:physical_network': 'phynet10',
'provider:segmentation_id': 1000,
'provider:network_type': 'vlan'},
{'provider:physical_network': None,
'provider:segmentation_id': 153,
'provider:network_type': 'vxlan'}]}}
test_ext_list = {'extensions':
[{'name': 'Multi Provider Network',
'alias': 'multi-segments'}]}
mock_client = mock_get_client()
mock_client.show_port.return_value = test_port
mock_client.list_extensions.return_value = test_ext_list
mock_client.show_network.return_value = test_net
vnic_type, phynet_name = api._get_port_vnic_info(
self.context, mock_client, test_port['port']['id'])
mock_client.show_network.assert_called_once_with(
test_port['port']['network_id'],
fields='segments')
self.assertEqual('phynet10', phynet_name)
@mock.patch.object(neutronapi, 'get_client', return_value=mock.Mock())
def test_get_port_vnic_info_vlan_with_multi_segment_ext(self,
mock_get_client):
api = neutronapi.API()
self.mox.ResetAll()
test_port = {
'port': {'id': 'my_port_id1',
'network_id': 'net-id',
'binding:vnic_type': model.VNIC_TYPE_DIRECT,
},
}
test_net = {'network': {'provider:physical_network': 'phynet10',
'provider:segmentation_id': 1000,
'provider:network_type': 'vlan'}}
test_ext_list = {'extensions':
[{'name': 'Multi Provider Network',
'alias': 'multi-segments'}]}
mock_client = mock_get_client()
mock_client.show_port.return_value = test_port
mock_client.list_extensions.return_value = test_ext_list
mock_client.show_network.return_value = test_net
vnic_type, phynet_name = api._get_port_vnic_info(
self.context, mock_client, test_port['port']['id'])
mock_client.show_network.assert_called_with(
test_port['port']['network_id'],
fields='provider:physical_network')
self.assertEqual('phynet10', phynet_name)
@mock.patch.object(neutronapi, 'get_client', return_value=mock.Mock())
def test_get_port_vnic_info_multi_segment_no_phynet(self, mock_get_client):
api = neutronapi.API()
self.mox.ResetAll()
test_port = {
'port': {'id': 'my_port_id1',
'network_id': 'net-id',
'binding:vnic_type': model.VNIC_TYPE_DIRECT,
},
}
test_net = {'network': {'segments':
[{'provider:physical_network': None,
'provider:segmentation_id': 1000,
'provider:network_type': 'vlan'},
{'provider:physical_network': None,
'provider:segmentation_id': 153,
'provider:network_type': 'vlan'}]}}
test_ext_list = {'extensions':
[{'name': 'Multi Provider Network',
'alias': 'multi-segments'}]}
mock_client = mock_get_client()
mock_client.show_port.return_value = test_port
mock_client.list_extensions.return_value = test_ext_list
mock_client.show_network.return_value = test_net
self.assertRaises(exception.NovaException,
api._get_port_vnic_info,
self.context, mock_client, test_port['port']['id'])
@mock.patch.object(neutronapi, 'get_client', return_value=mock.MagicMock())
def test_get_port_vnic_info_1(self, mock_get_client):
api = neutronapi.API()
self.mox.ResetAll()

View File

@ -0,0 +1,8 @@
---
fixes:
- Physical network name will be retrieved from a multi-segment network.
The current implementation will retrieve the physical network name for the
first segment that provides it. This is mostly intended to support a
combination of vxlan and vlan segments. Additional work will be required to
support a case of multiple vlan segments associated with different
physical networks.