Browse Source

Add support for specifying switch shortnames in physnets for HPB

Change-Id: I9a9d57ecfadc194024d3619928f3a816d12cba75
(cherry picked from commit 155f93d1e5)
changes/23/794823/1 2021.1.0
Mitchell Jameson 5 months ago
parent
commit
eb2d44f1ba
  1. 4
      devstack/plugin.sh
  2. 5
      etc/ml2_conf_arista.ini
  3. 6
      networking_arista/common/config.py
  4. 5
      networking_arista/common/utils.py
  5. 5
      networking_arista/ml2/rpc/arista_eapi.py
  6. 119
      networking_arista/tests/unit/ml2/rpc/test_arista_eapi_rpc_wrapper.py

4
devstack/plugin.sh

@ -24,6 +24,10 @@ function configure_arista() {
iniset $ARISTA_ML2_CONF_FILE ml2_arista use_fqdn $ARISTA_USE_FQDN
fi
if [ -n "${ARISTA_USE_FQDN_PHYSNET+x}" ]; then
iniset $ARISTA_ML2_CONF_FILE ml2_arista use_fqdn_physnet $ARISTA_USE_FQDN_PHYSNET
fi
if [ -n "${ARISTA_ML2_SYNC_INTERVAL+x}" ]; then
iniset $ARISTA_ML2_CONF_FILE ml2_arista sync_interval $ARISTA_ML2_SYNC_INTERVAL
fi

5
etc/ml2_conf_arista.ini

@ -105,6 +105,11 @@
# If not set, a value of "True" is assumed. (boolean value)
#use_fqdn = true
# In HPB deployments, this should be set to False if short switch hostnames
# are used for physnets in network_vlan_ranges and bridge_mappings. If
# FQDNs are used in physnets, this should be set to True. (boolean value)
#use_fqdn_physnet = true
# Sync interval in seconds between Neutron plugin and EOS. This
# interval defines how often the synchronization is performed. This is
# an optional field. If not set, a value of 30 seconds is assumed.

6
networking_arista/common/config.py

@ -53,6 +53,12 @@ ARISTA_DRIVER_OPTS = [
'("node1.domain.com") or as short names ("node1"). '
'This is optional. If not set, a value of "True" '
'is assumed.')),
cfg.BoolOpt('use_fqdn_physnet',
default=True,
help=_('In HPB deployments, this should be set to False if '
'short switch hostnames are used for physnets in '
'network_vlan_ranges and bridge_mappings. If FQDNs '
'are used in physnets, this should be set to True.')),
cfg.IntOpt('sync_interval',
default=30,
help=_('Sync interval in seconds between Neutron plugin and '

5
networking_arista/common/utils.py

@ -67,3 +67,8 @@ def supported_device_owner(device_owner):
def hostname(hostname, extra=None):
fqdns_used = cfg.CONF.ml2_arista['use_fqdn']
return hostname if fqdns_used else hostname.split('.')[0]
def physnet(hostname):
fqdns_used = cfg.CONF.ml2_arista['use_fqdn_physnet']
return hostname if fqdns_used else hostname.split('.')[0]

5
networking_arista/ml2/rpc/arista_eapi.py

@ -299,7 +299,7 @@ class AristaRPCWrapperEapi(AristaRPCWrapperBase):
switch_id = link.get('switch_id')
for host in response[0]['hosts'].values():
if switch_id == host['name']:
physnet = host['hostname']
physnet = utils.physnet(host['hostname'])
LOG.debug("get_physical_network: Physical Network for "
"%(host)s is %(physnet)s",
{'host': host_id, 'physnet': physnet})
@ -325,7 +325,8 @@ class AristaRPCWrapperEapi(AristaRPCWrapperBase):
neighbors = response[0]['neighbors']
for neighbor in neighbors:
if host_id in neighbor:
physnet = neighbors[neighbor]['toPort'][0]['hostname']
physnet = utils.physnet(
neighbors[neighbor]['toPort'][0]['hostname'])
LOG.debug("get_physical_network: Physical Network for "
"%(host)s is %(physnet)s", {'host': host_id,
'physnet': physnet})

119
networking_arista/tests/unit/ml2/rpc/test_arista_eapi_rpc_wrapper.py

@ -18,6 +18,7 @@ from oslo_config import cfg
from neutron.tests import base
from neutron.tests.unit import testlib_api
from neutron_lib.api.definitions import portbindings
from networking_arista.common import exceptions as arista_exc
from networking_arista.ml2.rpc import arista_eapi
@ -60,3 +61,121 @@ class NegativeRPCWrapperTestCase(testlib_api.SqlTestCase):
self.assertRaises(arista_exc.AristaRpcError,
drv._run_openstack_cmds, [])
log_err.assert_called_once_with(mock.ANY)
class GetPhysnetTestCase(base.BaseTestCase):
"""Test cases to validate parsing of topology output to find physnets"""
def setUp(self):
super(GetPhysnetTestCase, self).setUp()
setup_valid_config()
def _test_get_host_physnet(self, nova_fqdn, topo_host_fqdn,
topo_switch_fqdn, bridge_map_fqdn, use_fqdn,
use_fqdn_physnet):
cfg.CONF.set_override('use_fqdn', use_fqdn, "ml2_arista")
cfg.CONF.set_override('use_fqdn_physnet', use_fqdn_physnet,
"ml2_arista")
context = mock.MagicMock()
nova_host1 = 'host1.full.name' if nova_fqdn else 'host1'
nova_host2 = 'host2.full.name' if nova_fqdn else 'host2'
topo_host1 = 'host1.full.name' if topo_host_fqdn else 'host1'
topo_host2 = 'host2.full.name' if topo_host_fqdn else 'host2'
topo_switch1 = 'switch1.full.name' if topo_switch_fqdn else 'switch1'
topo_switch2 = 'switch2.full.name' if topo_switch_fqdn else 'switch2'
bridge_map_switch1 = ('switch1.full.name' if bridge_map_fqdn
else 'switch1')
bridge_map_switch2 = ('switch2.full.name' if bridge_map_fqdn
else 'switch2')
context.host = nova_host1
topology = [{'neighbors':
{'%s-et1' % topo_host1:
{'fromPort':
{'name': 'et1',
'hostname': topo_host1,
'hostid': '00:00:00:00:00:00'},
'toPort': [
{'name': 'Ethernet1',
'hostname': topo_switch1,
'hostid': '00:00:00:00:00:01'}]},
'%s-et1' % topo_host2:
{'fromPort':
{'name': 'et1',
'hostname': topo_host2,
'hostid': '00:00:00:00:00:02'},
'toPort': [
{'name': 'Ethernet1',
'hostname': topo_switch2,
'hostid': '00:00:00:00:00:03'}]}}}]
drv = arista_eapi.AristaRPCWrapperEapi()
drv._run_eos_cmds = mock.MagicMock()
drv._run_eos_cmds.return_value = topology
self.assertEqual(drv.get_host_physnet(context), bridge_map_switch1)
context.host = nova_host2
self.assertEqual(drv.get_host_physnet(context), bridge_map_switch2)
def _test_get_baremetal_physnet(self, topo_switch_fqdn, bridge_map_fqdn,
use_fqdn_physnet):
cfg.CONF.set_override('use_fqdn_physnet', use_fqdn_physnet,
"ml2_arista")
context = mock.MagicMock()
topo_switch1 = 'switch1.full.name' if topo_switch_fqdn else 'switch1'
topo_switch2 = 'switch2.full.name' if topo_switch_fqdn else 'switch2'
bridge_map_switch1 = ('switch1.full.name' if bridge_map_fqdn
else 'switch1')
bridge_map_switch2 = ('switch2.full.name' if bridge_map_fqdn
else 'switch2')
context.host = 'host1'
context.current = {portbindings.PROFILE: {
'local_link_information': [{'switch_id': '00:00:00:00:00:00'}]}}
topology = [{'hosts':
{'00:00:00:00:00:00': {'name': '00:00:00:00:00:00',
'hostname': topo_switch1},
'00:00:00:00:00:01': {'name': '00:00:00:00:00:01',
'hostname': topo_switch2}}}]
drv = arista_eapi.AristaRPCWrapperEapi()
drv._run_eos_cmds = mock.MagicMock()
drv._run_eos_cmds.return_value = topology
self.assertEqual(drv.get_baremetal_physnet(context),
bridge_map_switch1)
context.host = 'host2'
context.current = {portbindings.PROFILE: {
'local_link_information': [{'switch_id': '00:00:00:00:00:01'}]}}
self.assertEqual(drv.get_baremetal_physnet(context),
bridge_map_switch2)
def test_get_host_physnet(self):
for nova_fqdn in (True, False):
for topo_host_fqdn in (True, False):
for topo_switch_fqdn in (True, False):
for bridge_map_fqdn in (True, False):
if bridge_map_fqdn and not topo_switch_fqdn:
# Topology has less info than bridge map.
# This isn't supported
continue
use_fqdn = True
if nova_fqdn and not topo_host_fqdn:
use_fqdn = False
use_fqdn_physnet = True
if topo_switch_fqdn and not bridge_map_fqdn:
use_fqdn_physnet = False
self._test_get_host_physnet(nova_fqdn,
topo_host_fqdn,
topo_switch_fqdn,
bridge_map_fqdn,
use_fqdn,
use_fqdn_physnet)
def test_get_baremetal_physnet(self):
for topo_switch_fqdn in (True, False):
for bridge_map_fqdn in (True, False):
if bridge_map_fqdn and not topo_switch_fqdn:
# Topology has less info than bridge map.
# This isn't supported.
continue
use_fqdn_physnet = True
if topo_switch_fqdn and not bridge_map_fqdn:
use_fqdn_physnet = False
self._test_get_baremetal_physnet(topo_switch_fqdn,
bridge_map_fqdn,
use_fqdn_physnet)

Loading…
Cancel
Save