Arista L3 Ops is success if it is successful on one peer

This fix checks to see if Arista HW is
configured in MLAG (redundant) mode. If yes,
as long as operation is successful on one of the
paired switches, consider it successful.

Closes-bug: 1373652

Change-Id: If929d3fcc109b81f4cf071380a1645d403feb363
(cherry picked from commit 5fd628f123)
(cherry picked from commit 2fb5c43950)
This commit is contained in:
Sukhdev 2014-09-24 15:57:15 -07:00
parent 704c47c132
commit 57bbce13fd
2 changed files with 120 additions and 10 deletions

View File

@ -21,6 +21,7 @@ from oslo.config import cfg
from neutron import context as nctx
from neutron.db import db_base_plugin_v2
from neutron.openstack.common.gettextutils import _LE
from neutron.openstack.common import log as logging
from neutron.plugins.ml2.drivers.arista import exceptions as arista_exc
@ -247,16 +248,38 @@ class AristaL3Driver(object):
rdm = str(int(hashlib.sha256(router_name).hexdigest(),
16) % 6553)
mlag_peer_failed = False
for s in self._servers:
self.create_router_on_eos(router_name, rdm, s)
try:
self.create_router_on_eos(router_name, rdm, s)
mlag_peer_failed = False
except Exception:
if self.mlag_configured and not mlag_peer_failed:
mlag_peer_failed = True
else:
msg = (_('Failed to create router %s on EOS') %
router_name)
LOG.exception(msg)
raise arista_exc.AristaServicePluginRpcError(msg=msg)
def delete_router(self, context, tenant_id, router_id, router):
"""Deletes a router from Arista Switch."""
if router:
router_name = self._arista_router_name(tenant_id, router['name'])
mlag_peer_failed = False
for s in self._servers:
self.delete_router_from_eos(self._arista_router_name(
tenant_id, router['name']), s)
try:
self.delete_router_from_eos(router_name, s)
mlag_peer_failed = False
except Exception:
if self.mlag_configured and not mlag_peer_failed:
mlag_peer_failed = True
else:
msg = (_LE('Failed to delete router %s from EOS') %
router_name)
LOG.exception(msg)
raise arista_exc.AristaServicePluginRpcError(msg=msg)
def update_router(self, context, router_id, original_router, new_router):
"""Updates a router which is already created on Arista Switch.
@ -279,15 +302,27 @@ class AristaL3Driver(object):
if self.mlag_configured:
# For MLAG, we send a specific IP address as opposed to cidr
# For now, we are using x.x.x.253 and x.x.x.254 as virtual IP
mlag_peer_failed = False
for i, server in enumerate(self._servers):
#get appropriate virtual IP address for this router
router_ip = self._get_router_ip(cidr, i,
router_info['ip_version'])
self.add_interface_to_router(router_info['seg_id'],
router_name,
router_info['gip'],
router_ip, subnet_mask,
server)
try:
self.add_interface_to_router(router_info['seg_id'],
router_name,
router_info['gip'],
router_ip, subnet_mask,
server)
mlag_peer_failed = False
except Exception:
if not mlag_peer_failed:
mlag_peer_failed = True
else:
msg = (_('Failed to add interface to router '
'%s on EOS') % router_name)
LOG.exception(msg)
raise arista_exc.AristaServicePluginRpcError(
msg=msg)
else:
for s in self._servers:
@ -304,9 +339,21 @@ class AristaL3Driver(object):
if router_info:
router_name = self._arista_router_name(router_info['tenant_id'],
router_info['name'])
mlag_peer_failed = False
for s in self._servers:
self.delete_interface_from_router(router_info['seg_id'],
router_name, s)
try:
self.delete_interface_from_router(router_info['seg_id'],
router_name, s)
if self.mlag_configured:
mlag_peer_failed = False
except Exception:
if self.mlag_configured and not mlag_peer_failed:
mlag_peer_failed = True
else:
msg = (_LE('Failed to remove interface from router '
'%s on EOS') % router_name)
LOG.exception(msg)
raise arista_exc.AristaServicePluginRpcError(msg=msg)
def _run_openstack_l3_cmds(self, commands, server):
"""Execute/sends a CAPI (Command API) command to EOS.

View File

@ -391,3 +391,66 @@ class AristaL3DriverTestCases_MLAG_v6(base.BaseTestCase):
'ip_version': 6}
self.assertFalse(self.drv.remove_router_interface(None, router))
class AristaL3DriverTestCasesMlag_one_switch_failed(base.BaseTestCase):
"""Test cases to test with non redundant hardare in redundancy mode.
In the following test cases, the driver is configured in MLAG (redundancy
mode) but, one of the switches is mocked to throw exceptoin to mimic
failure of the switch. Ensure that the the operation does not fail when
one of the switches fails.
"""
def setUp(self):
super(AristaL3DriverTestCasesMlag_one_switch_failed, self).setUp()
setup_arista_config('value', mlag=True)
self.drv = arista.AristaL3Driver()
self.drv._servers = []
self.drv._servers.append(mock.MagicMock())
self.drv._servers.append(mock.MagicMock())
def test_create_router_when_one_switch_fails(self):
router = {}
router['name'] = 'test-router-1'
tenant = '123'
# Make one of the switches throw an exception - i.e. fail
self.drv._servers[0].runCmds = mock.Mock(side_effect = Exception())
self.drv.create_router(None, tenant, router)
def test_delete_router_when_one_switch_fails(self):
router = {}
router['name'] = 'test-router-1'
tenant = '123'
router_id = '345'
# Make one of the switches throw an exception - i.e. fail
self.drv._servers[1].runCmds = mock.Mock(side_effect = Exception())
self.drv.delete_router(None, tenant, router_id, router)
def test_add_router_interface_when_one_switch_fails(self):
router = {}
router['name'] = 'test-router-1'
router['tenant_id'] = 'ten-1'
router['seg_id'] = '100'
router['ip_version'] = 4
router['cidr'] = '10.10.10.0/24'
router['gip'] = '10.10.10.1'
# Make one of the switches throw an exception - i.e. fail
self.drv._servers[1].runCmds = mock.Mock(side_effect = Exception())
self.drv.add_router_interface(None, router)
def test_remove_router_interface_when_one_switch_fails(self):
router = {}
router['name'] = 'test-router-1'
router['tenant_id'] = 'ten-1'
router['seg_id'] = '100'
router['ip_version'] = 4
router['cidr'] = '10.10.10.0/24'
router['gip'] = '10.10.10.1'
# Make one of the switches throw an exception - i.e. fail
self.drv._servers[0].runCmds = mock.Mock(side_effect = Exception())
self.drv.remove_router_interface(None, router)