Merge "neutron: retrieve physical network name from a multi-provider network"
This commit is contained in:
commit
d219a3dcdc
@ -1019,6 +1019,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:
|
||||
@ -1402,6 +1406,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
|
||||
|
||||
@ -1415,9 +1450,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,
|
||||
|
@ -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'
|
||||
|
@ -3139,6 +3139,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()
|
||||
|
@ -0,0 +1,8 @@
|
||||
---
|
||||
fixes:
|
||||
- Physical network name will be retrieved from a multi-segement network.
|
||||
The current implementation will retrieve the physical network name for the
|
||||
first segment that provides it. This is mostly intended to support a
|
||||
combinatin of vxlan and vlan segments. Additional work will be required to
|
||||
support a case of multiple vlan segments associated with different
|
||||
physical networks.
|
Loading…
Reference in New Issue
Block a user