]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Arista L3 Service Plugin decomposition
authorSukhdev <sukhdev@aristanetworks.com>
Fri, 6 Mar 2015 01:28:25 +0000 (17:28 -0800)
committerSukhdev <sukhdev@aristanetworks.com>
Thu, 12 Mar 2015 00:06:44 +0000 (17:06 -0700)
Moving back-end drivers of Arista L3
Service Plugin from neutron tree to
stackforge networking-arista.

Change-Id: I0b10ce12bc10fb74c905ec11e64be8da12f341f4
Closes-bug: 1428909
Related-blueprint: core-vendor-decomposition

doc/source/devref/contribute.rst
neutron/plugins/ml2/drivers/arista/README
neutron/plugins/ml2/drivers/arista/arista_l3_driver.py [deleted file]
neutron/plugins/ml2/drivers/arista/requirements.txt
neutron/services/l3_router/l3_arista.py
neutron/tests/unit/ml2/drivers/arista/test_arista_l3_driver.py [deleted file]

index ed18bb2979fb2d18454959e303de27744e7fbaa0..5b705185f335bd69bc680abebd04376c40a62eb4 100644 (file)
@@ -398,7 +398,7 @@ The following chart captures the following aspects:
 +===============================+=======================+===========+==================+=========+==============+
 | freescale-nscs_               |         ml2,fw        |    no     |       no         |   [D]   |              |
 +-------------------------------+-----------------------+-----------+------------------+---------+--------------+
-| networking-arista_            |          ml2          |    no     |       yes        |   [B]   |              |
+| networking-arista_            |       ml2,l3          |    yes    |       yes        |   [C]   |     Kilo     |
 +-------------------------------+-----------------------+-----------+------------------+---------+--------------+
 | networking-brocade_           |                       |           |                  |         |              |
 +-------------------------------+-----------------------+-----------+------------------+---------+--------------+
@@ -437,7 +437,8 @@ Arista
 ------
 
 * Git: https://github.com/stackforge/networking-arista
-* PyPI: https://pypi.python.org/pypi/networking-arista
+* Launchpad: https://launchpad.net/networking-arista
+* Pypi: https://pypi.python.org/pypi/networking-arista
 
 .. _networking-brocade:
 
index 6e30bf9e553fae716d204bc863e0e8c09152ce90..080e581f754538ae9a19c1c0d1eda1a8e3f77414 100644 (file)
@@ -7,3 +7,6 @@ Note: Initial version of this driver support VLANs only.
 
 For more details on use please refer to:
 https://wiki.openstack.org/wiki/Arista-neutron-ml2-driver
+
+The back-end of the driver is now moved to:
+https://github.com/stackforge/networking-arista
diff --git a/neutron/plugins/ml2/drivers/arista/arista_l3_driver.py b/neutron/plugins/ml2/drivers/arista/arista_l3_driver.py
deleted file mode 100644 (file)
index a9cda5a..0000000
+++ /dev/null
@@ -1,498 +0,0 @@
-# Copyright 2014 Arista Networks, Inc.  All rights reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-import hashlib
-import socket
-import struct
-
-import jsonrpclib
-from oslo_config import cfg
-
-from neutron import context as nctx
-from neutron.db import db_base_plugin_v2
-from neutron.i18n import _LE, _LI
-from neutron.openstack.common import log as logging
-from neutron.plugins.ml2.drivers.arista import exceptions as arista_exc
-
-LOG = logging.getLogger(__name__)
-
-EOS_UNREACHABLE_MSG = _('Unable to reach EOS')
-DEFAULT_VLAN = 1
-MLAG_SWITCHES = 2
-VIRTUAL_ROUTER_MAC = '00:11:22:33:44:55'
-IPV4_BITS = 32
-IPV6_BITS = 128
-
-# This string-format-at-a-distance confuses pylint :(
-# pylint: disable=too-many-format-args
-router_in_vrf = {
-    'router': {'create': ['vrf definition {0}',
-                          'rd {1}',
-                          'exit'],
-               'delete': ['no vrf definition {0}']},
-
-    'interface': {'add': ['ip routing vrf {1}',
-                          'vlan {0}',
-                          'exit',
-                          'interface vlan {0}',
-                          'vrf forwarding {1}',
-                          'ip address {2}'],
-                  'remove': ['no interface vlan {0}']}}
-
-router_in_default_vrf = {
-    'router': {'create': [],   # Place holder for now.
-               'delete': []},  # Place holder for now.
-
-    'interface': {'add': ['ip routing',
-                          'vlan {0}',
-                          'exit',
-                          'interface vlan {0}',
-                          'ip address {2}'],
-                  'remove': ['no interface vlan {0}']}}
-
-router_in_default_vrf_v6 = {
-    'router': {'create': [],
-               'delete': []},
-
-    'interface': {'add': ['ipv6 unicast-routing',
-                          'vlan {0}',
-                          'exit',
-                          'interface vlan {0}',
-                          'ipv6 enable',
-                          'ipv6 address {2}'],
-                  'remove': ['no interface vlan {0}']}}
-
-additional_cmds_for_mlag = {
-    'router': {'create': ['ip virtual-router mac-address {0}'],
-               'delete': ['no ip virtual-router mac-address']},
-
-    'interface': {'add': ['ip virtual-router address {0}'],
-                  'remove': []}}
-
-additional_cmds_for_mlag_v6 = {
-    'router': {'create': [],
-               'delete': []},
-
-    'interface': {'add': ['ipv6 virtual-router address {0}'],
-                  'remove': []}}
-
-
-class AristaL3Driver(object):
-    """Wraps Arista JSON RPC.
-
-    All communications between Neutron and EOS are over JSON RPC.
-    EOS - operating system used on Arista hardware
-    Command API - JSON RPC API provided by Arista EOS
-    """
-    def __init__(self):
-        self._servers = []
-        self._hosts = []
-        self.interfaceDict = None
-        self._validate_config()
-        host = cfg.CONF.l3_arista.primary_l3_host
-        self._hosts.append(host)
-        self._servers.append(jsonrpclib.Server(self._eapi_host_url(host)))
-        self.mlag_configured = cfg.CONF.l3_arista.mlag_config
-        self.use_vrf = cfg.CONF.l3_arista.use_vrf
-        if self.mlag_configured:
-            host = cfg.CONF.l3_arista.secondary_l3_host
-            self._hosts.append(host)
-            self._servers.append(jsonrpclib.Server(self._eapi_host_url(host)))
-            self._additionalRouterCmdsDict = additional_cmds_for_mlag['router']
-            self._additionalInterfaceCmdsDict = (
-                additional_cmds_for_mlag['interface'])
-        if self.use_vrf:
-            self.routerDict = router_in_vrf['router']
-            self.interfaceDict = router_in_vrf['interface']
-        else:
-            self.routerDict = router_in_default_vrf['router']
-            self.interfaceDict = router_in_default_vrf['interface']
-
-    def _eapi_host_url(self, host):
-        user = cfg.CONF.l3_arista.primary_l3_host_username
-        pwd = cfg.CONF.l3_arista.primary_l3_host_password
-
-        eapi_server_url = ('https://%s:%s@%s/command-api' %
-                           (user, pwd, host))
-        return eapi_server_url
-
-    def _validate_config(self):
-        if cfg.CONF.l3_arista.get('primary_l3_host') == '':
-            msg = _('Required option primary_l3_host is not set')
-            LOG.error(msg)
-            raise arista_exc.AristaServicePluginConfigError(msg=msg)
-        if cfg.CONF.l3_arista.get('mlag_config'):
-            if cfg.CONF.l3_arista.get('secondary_l3_host') == '':
-                msg = _('Required option secondary_l3_host is not set')
-                LOG.error(msg)
-                raise arista_exc.AristaServicePluginConfigError(msg=msg)
-        if cfg.CONF.l3_arista.get('primary_l3_host_username') == '':
-            msg = _('Required option primary_l3_host_username is not set')
-            LOG.error(msg)
-            raise arista_exc.AristaServicePluginConfigError(msg=msg)
-
-    def create_router_on_eos(self, router_name, rdm, server):
-        """Creates a router on Arista HW Device.
-
-        :param router_name: globally unique identifier for router/VRF
-        :param rdm: A value generated by hashing router name
-        :param server: Server endpoint on the Arista switch to be configured
-        """
-        cmds = []
-        rd = "%s:%s" % (rdm, rdm)
-
-        for c in self.routerDict['create']:
-            cmds.append(c.format(router_name, rd))
-
-        if self.mlag_configured:
-            mac = VIRTUAL_ROUTER_MAC
-            for c in self._additionalRouterCmdsDict['create']:
-                cmds.append(c.format(mac))
-
-        self._run_openstack_l3_cmds(cmds, server)
-
-    def delete_router_from_eos(self, router_name, server):
-        """Deletes a router from Arista HW Device.
-
-        :param router_name: globally unique identifier for router/VRF
-        :param server: Server endpoint on the Arista switch to be configured
-        """
-        cmds = []
-        for c in self.routerDict['delete']:
-            cmds.append(c.format(router_name))
-        if self.mlag_configured:
-            for c in self._additionalRouterCmdsDict['delete']:
-                cmds.append(c)
-
-        self._run_openstack_l3_cmds(cmds, server)
-
-    def _select_dicts(self, ipv):
-        if self.use_vrf:
-            self.interfaceDict = router_in_vrf['interface']
-        else:
-            if ipv == 6:
-                #for IPv6 use IPv6 commmands
-                self.interfaceDict = router_in_default_vrf_v6['interface']
-                self._additionalInterfaceCmdsDict = (
-                    additional_cmds_for_mlag_v6['interface'])
-            else:
-                self.interfaceDict = router_in_default_vrf['interface']
-                self._additionalInterfaceCmdsDict = (
-                    additional_cmds_for_mlag['interface'])
-
-    def add_interface_to_router(self, segment_id,
-                                router_name, gip, router_ip, mask, server):
-        """Adds an interface to existing HW router on Arista HW device.
-
-        :param segment_id: VLAN Id associated with interface that is added
-        :param router_name: globally unique identifier for router/VRF
-        :param gip: Gateway IP associated with the subnet
-        :param router_ip: IP address of the router
-        :param mask: subnet mask to be used
-        :param server: Server endpoint on the Arista switch to be configured
-        """
-
-        if not segment_id:
-            segment_id = DEFAULT_VLAN
-        cmds = []
-        for c in self.interfaceDict['add']:
-            if self.mlag_configured:
-                ip = router_ip
-            else:
-                ip = gip + '/' + mask
-            cmds.append(c.format(segment_id, router_name, ip))
-        if self.mlag_configured:
-            for c in self._additionalInterfaceCmdsDict['add']:
-                cmds.append(c.format(gip))
-
-        self._run_openstack_l3_cmds(cmds, server)
-
-    def delete_interface_from_router(self, segment_id, router_name, server):
-        """Deletes an interface from existing HW router on Arista HW device.
-
-        :param segment_id: VLAN Id associated with interface that is added
-        :param router_name: globally unique identifier for router/VRF
-        :param server: Server endpoint on the Arista switch to be configured
-        """
-
-        if not segment_id:
-            segment_id = DEFAULT_VLAN
-        cmds = []
-        for c in self.interfaceDict['remove']:
-            cmds.append(c.format(segment_id))
-
-        self._run_openstack_l3_cmds(cmds, server)
-
-    def create_router(self, context, tenant_id, router):
-        """Creates a router on Arista Switch.
-
-        Deals with multiple configurations - such as Router per VRF,
-        a router in default VRF, Virtual Router in MLAG configurations
-        """
-        if router:
-            router_name = self._arista_router_name(tenant_id, router['name'])
-
-            rdm = str(int(hashlib.sha256(router_name).hexdigest(),
-                    16) % 6553)
-            mlag_peer_failed = False
-            for s in self._servers:
-                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:
-                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.
-
-        TODO: (Sukhdev) - to be implemented in next release.
-        """
-        pass
-
-    def add_router_interface(self, context, router_info):
-        """Adds an interface to a router created on Arista HW router.
-
-        This deals with both IPv6 and IPv4 configurations.
-        """
-        if router_info:
-            self._select_dicts(router_info['ip_version'])
-            cidr = router_info['cidr']
-            subnet_mask = cidr.split('/')[1]
-            router_name = self._arista_router_name(router_info['tenant_id'],
-                                                   router_info['name'])
-            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'])
-                    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:
-                    self.add_interface_to_router(router_info['seg_id'],
-                                                 router_name,
-                                                 router_info['gip'],
-                                                 None, subnet_mask, s)
-
-    def remove_router_interface(self, context, router_info):
-        """Removes previously configured interface from router on Arista HW.
-
-        This deals with both IPv6 and IPv4 configurations.
-        """
-        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:
-                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.
-
-        In this method, list of commands is appended with prefix and
-        postfix commands - to make is understandble by EOS.
-
-        :param commands : List of command to be executed on EOS.
-        :param server: Server endpoint on the Arista switch to be configured
-        """
-        command_start = ['enable', 'configure']
-        command_end = ['exit']
-        full_command = command_start + commands + command_end
-
-        LOG.info(_LI('Executing command on Arista EOS: %s'), full_command)
-
-        try:
-            # this returns array of return values for every command in
-            # full_command list
-            ret = server.runCmds(version=1, cmds=full_command)
-            LOG.info(_LI('Results of execution on Arista EOS: %s'), ret)
-
-        except Exception:
-            msg = (_LE("Error occurred while trying to execute "
-                     "commands %(cmd)s on EOS %(host)s"),
-                   {'cmd': full_command, 'host': server})
-            LOG.exception(msg)
-            raise arista_exc.AristaServicePluginRpcError(msg=msg)
-
-    def _arista_router_name(self, tenant_id, name):
-        # Use a unique name so that OpenStack created routers/SVIs
-        # can be distinguishged from the user created routers/SVIs
-        # on Arista HW.
-        return 'OS' + '-' + tenant_id + '-' + name
-
-    def _get_binary_from_ipv4(self, ip_addr):
-        return struct.unpack("!L", socket.inet_pton(socket.AF_INET,
-                                                    ip_addr))[0]
-
-    def _get_binary_from_ipv6(self, ip_addr):
-        hi, lo = struct.unpack("!QQ", socket.inet_pton(socket.AF_INET6,
-                                                       ip_addr))
-        return (hi << 64) | lo
-
-    def _get_ipv4_from_binary(self, bin_addr):
-        return socket.inet_ntop(socket.AF_INET, struct.pack("!L", bin_addr))
-
-    def _get_ipv6_from_binary(self, bin_addr):
-        hi = bin_addr >> 64
-        lo = bin_addr & 0xFFFFFFFF
-        return socket.inet_ntop(socket.AF_INET6, struct.pack("!QQ", hi, lo))
-
-    def _get_router_ip(self, cidr, ip_count, ip_ver):
-        """For a given IP subnet and IP version type, generate IP for router.
-
-        This method takes the network address (cidr) and selects an
-        IP address that should be assigned to virtual router running
-        on multiple switches. It uses upper addresses in a subnet address
-        as IP for the router. Each instace of the router, on each switch,
-        requires uniqe IP address. For example in IPv4 case, on a 255
-        subnet, it will pick X.X.X.254 as first addess, X.X.X.253 for next,
-        and so on.
-        """
-        start_ip = MLAG_SWITCHES + ip_count
-        network_addr, prefix = cidr.split('/')
-        if ip_ver == 4:
-            bits = IPV4_BITS
-            ip = self._get_binary_from_ipv4(network_addr)
-        elif ip_ver == 6:
-            bits = IPV6_BITS
-            ip = self._get_binary_from_ipv6(network_addr)
-
-        mask = (pow(2, bits) - 1) << (bits - int(prefix))
-
-        network_addr = ip & mask
-
-        router_ip = pow(2, bits - int(prefix)) - start_ip
-
-        router_ip = network_addr | router_ip
-        if ip_ver == 4:
-            return self._get_ipv4_from_binary(router_ip) + '/' + prefix
-        else:
-            return self._get_ipv6_from_binary(router_ip) + '/' + prefix
-
-
-class NeutronNets(db_base_plugin_v2.NeutronDbPluginV2):
-    """Access to Neutron DB.
-
-    Provides access to the Neutron Data bases for all provisioned
-    networks as well ports. This data is used during the synchronization
-    of DB between ML2 Mechanism Driver and Arista EOS
-    Names of the networks and ports are not stored in Arista repository
-    They are pulled from Neutron DB.
-    """
-
-    def __init__(self):
-        self.admin_ctx = nctx.get_admin_context()
-
-    def get_all_networks_for_tenant(self, tenant_id):
-        filters = {'tenant_id': [tenant_id]}
-        return super(NeutronNets,
-                     self).get_networks(self.admin_ctx, filters=filters) or []
-
-    def get_all_ports_for_tenant(self, tenant_id):
-        filters = {'tenant_id': [tenant_id]}
-        return super(NeutronNets,
-                     self).get_ports(self.admin_ctx, filters=filters) or []
-
-    def _get_network(self, tenant_id, network_id):
-        filters = {'tenant_id': [tenant_id],
-                   'id': [network_id]}
-        return super(NeutronNets,
-                     self).get_networks(self.admin_ctx, filters=filters) or []
-
-    def get_subnet_info(self, subnet_id):
-        subnet = self.get_subnet(subnet_id)
-        return subnet
-
-    def get_subnet_ip_version(self, subnet_id):
-        subnet = self.get_subnet(subnet_id)
-        return subnet['ip_version']
-
-    def get_subnet_gateway_ip(self, subnet_id):
-        subnet = self.get_subnet(subnet_id)
-        return subnet['gateway_ip']
-
-    def get_subnet_cidr(self, subnet_id):
-        subnet = self.get_subnet(subnet_id)
-        return subnet['cidr']
-
-    def get_network_id(self, subnet_id):
-        subnet = self.get_subnet(subnet_id)
-        return subnet['network_id']
-
-    def get_network_id_from_port_id(self, port_id):
-        port = self.get_port(port_id)
-        return port['network_id']
-
-    def get_subnet(self, subnet_id):
-        return super(NeutronNets,
-                     self).get_subnet(self.admin_ctx, subnet_id) or []
-
-    def get_port(self, port_id):
-        return super(NeutronNets,
-                     self).get_port(self.admin_ctx, port_id) or []
index 48fa2c744acdeb68f28068f9cc9e44d8d54c67d0..a46afe38c92869b4d7c5d7688e1b4a4c77ce888d 100644 (file)
@@ -1 +1 @@
-networking_arista
+networking_arista>=2015.1.1,<2015.2.1
index 3b5b6a42874ce255baa4b060e3a68775a936dff6..3465eee3fad443c00175e131ff176df6d0b9b84f 100644 (file)
@@ -15,6 +15,8 @@
 import copy
 import threading
 
+from networking_arista.common import db_lib
+from networking_arista.l3Plugin import arista_l3_driver
 from oslo_config import cfg
 from oslo_utils import excutils
 
@@ -33,7 +35,6 @@ from neutron.i18n import _LE, _LI
 from neutron.openstack.common import log as logging
 from neutron.plugins.common import constants
 from neutron.plugins.ml2.driver_context import NetworkContext  # noqa
-from neutron.plugins.ml2.drivers.arista import arista_l3_driver
 
 LOG = logging.getLogger(__name__)
 
@@ -55,7 +56,7 @@ class AristaL3ServicePlugin(db_base_plugin_v2.NeutronDbPluginV2,
     def __init__(self, driver=None):
 
         self.driver = driver or arista_l3_driver.AristaL3Driver()
-        self.ndb = arista_l3_driver.NeutronNets()
+        self.ndb = db_lib.NeutronNets()
         self.setup_rpc()
         self.sync_timeout = cfg.CONF.l3_arista.l3_sync_interval
         self.sync_lock = threading.Lock()
diff --git a/neutron/tests/unit/ml2/drivers/arista/test_arista_l3_driver.py b/neutron/tests/unit/ml2/drivers/arista/test_arista_l3_driver.py
deleted file mode 100644 (file)
index d2467ec..0000000
+++ /dev/null
@@ -1,456 +0,0 @@
-# Copyright (c) 2013 OpenStack Foundation
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-# implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-
-import mock
-from oslo_config import cfg
-
-from neutron.plugins.ml2.drivers.arista import arista_l3_driver as arista
-from neutron.tests import base
-
-
-def setup_arista_config(value='', vrf=False, mlag=False):
-    cfg.CONF.set_override('primary_l3_host', value, "l3_arista")
-    cfg.CONF.set_override('primary_l3_host_username', value, "l3_arista")
-    if vrf:
-        cfg.CONF.set_override('use_vrf', value, "l3_arista")
-    if mlag:
-        cfg.CONF.set_override('secondary_l3_host', value, "l3_arista")
-        cfg.CONF.set_override('mlag_config', value, "l3_arista")
-
-
-class AristaL3DriverTestCasesDefaultVrf(base.BaseTestCase):
-    """Test cases to test the RPC between Arista Driver and EOS.
-
-    Tests all methods used to send commands between Arista L3 Driver and EOS
-    to program routing functions in Default VRF.
-    """
-
-    def setUp(self):
-        super(AristaL3DriverTestCasesDefaultVrf, self).setUp()
-        setup_arista_config('value')
-        self.drv = arista.AristaL3Driver()
-        self.drv._servers = []
-        self.drv._servers.append(mock.MagicMock())
-
-    def test_no_exception_on_correct_configuration(self):
-        self.assertIsNotNone(self.drv)
-
-    def test_create_router_on_eos(self):
-        router_name = 'test-router-1'
-        route_domain = '123:123'
-
-        self.drv.create_router_on_eos(router_name, route_domain,
-                                      self.drv._servers[0])
-        cmds = ['enable', 'configure', 'exit']
-
-        self.drv._servers[0].runCmds.assert_called_once_with(version=1,
-                                                             cmds=cmds)
-
-    def test_delete_router_from_eos(self):
-        router_name = 'test-router-1'
-
-        self.drv.delete_router_from_eos(router_name, self.drv._servers[0])
-        cmds = ['enable', 'configure', 'exit']
-
-        self.drv._servers[0].runCmds.assert_called_once_with(version=1,
-                                                             cmds=cmds)
-
-    def test_add_interface_to_router_on_eos(self):
-        router_name = 'test-router-1'
-        segment_id = '123'
-        router_ip = '10.10.10.10'
-        gw_ip = '10.10.10.1'
-        mask = '255.255.255.0'
-
-        self.drv.add_interface_to_router(segment_id, router_name, gw_ip,
-                                         router_ip, mask, self.drv._servers[0])
-        cmds = ['enable', 'configure', 'ip routing',
-                'vlan %s' % segment_id, 'exit',
-                'interface vlan %s' % segment_id,
-                'ip address %s/%s' % (gw_ip, mask), 'exit']
-
-        self.drv._servers[0].runCmds.assert_called_once_with(version=1,
-                                                             cmds=cmds)
-
-    def test_delete_interface_from_router_on_eos(self):
-        router_name = 'test-router-1'
-        segment_id = '123'
-
-        self.drv.delete_interface_from_router(segment_id, router_name,
-                                              self.drv._servers[0])
-        cmds = ['enable', 'configure', 'no interface vlan %s' % segment_id,
-                'exit']
-
-        self.drv._servers[0].runCmds.assert_called_once_with(version=1,
-                                                             cmds=cmds)
-
-
-class AristaL3DriverTestCasesUsingVRFs(base.BaseTestCase):
-    """Test cases to test the RPC between Arista Driver and EOS.
-
-    Tests all methods used to send commands between Arista L3 Driver and EOS
-    to program routing functions using multiple VRFs.
-    Note that the configuration commands are different when VRFs are used.
-    """
-
-    def setUp(self):
-        super(AristaL3DriverTestCasesUsingVRFs, self).setUp()
-        setup_arista_config('value', vrf=True)
-        self.drv = arista.AristaL3Driver()
-        self.drv._servers = []
-        self.drv._servers.append(mock.MagicMock())
-
-    def test_no_exception_on_correct_configuration(self):
-        self.assertIsNotNone(self.drv)
-
-    def test_create_router_on_eos(self):
-        max_vrfs = 5
-        routers = ['testRouter-%s' % n for n in range(max_vrfs)]
-        domains = ['10%s' % n for n in range(max_vrfs)]
-
-        for (r, d) in zip(routers, domains):
-            self.drv.create_router_on_eos(r, d, self.drv._servers[0])
-
-            cmds = ['enable', 'configure',
-                    'vrf definition %s' % r,
-                    'rd %(rd)s:%(rd)s' % {'rd': d}, 'exit', 'exit']
-
-            self.drv._servers[0].runCmds.assert_called_with(version=1,
-                                                            cmds=cmds)
-
-    def test_delete_router_from_eos(self):
-        max_vrfs = 5
-        routers = ['testRouter-%s' % n for n in range(max_vrfs)]
-
-        for r in routers:
-            self.drv.delete_router_from_eos(r, self.drv._servers[0])
-            cmds = ['enable', 'configure', 'no vrf definition %s' % r,
-                    'exit']
-
-            self.drv._servers[0].runCmds.assert_called_with(version=1,
-                                                            cmds=cmds)
-
-    def test_add_interface_to_router_on_eos(self):
-        router_name = 'test-router-1'
-        segment_id = '123'
-        router_ip = '10.10.10.10'
-        gw_ip = '10.10.10.1'
-        mask = '255.255.255.0'
-
-        self.drv.add_interface_to_router(segment_id, router_name, gw_ip,
-                                         router_ip, mask, self.drv._servers[0])
-        cmds = ['enable', 'configure',
-                'ip routing vrf %s' % router_name,
-                'vlan %s' % segment_id, 'exit',
-                'interface vlan %s' % segment_id,
-                'vrf forwarding %s' % router_name,
-                'ip address %s/%s' % (gw_ip, mask), 'exit']
-
-        self.drv._servers[0].runCmds.assert_called_once_with(version=1,
-                                                             cmds=cmds)
-
-    def test_delete_interface_from_router_on_eos(self):
-        router_name = 'test-router-1'
-        segment_id = '123'
-
-        self.drv.delete_interface_from_router(segment_id, router_name,
-                                              self.drv._servers[0])
-        cmds = ['enable', 'configure', 'no interface vlan %s' % segment_id,
-                'exit']
-
-        self.drv._servers[0].runCmds.assert_called_once_with(version=1,
-                                                             cmds=cmds)
-
-
-class AristaL3DriverTestCasesMlagConfig(base.BaseTestCase):
-    """Test cases to test the RPC between Arista Driver and EOS.
-
-    Tests all methods used to send commands between Arista L3 Driver and EOS
-    to program routing functions in Default VRF using MLAG configuration.
-    MLAG configuration means that the commands will be sent to both
-    primary and secondary Arista Switches.
-    """
-
-    def setUp(self):
-        super(AristaL3DriverTestCasesMlagConfig, 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_no_exception_on_correct_configuration(self):
-        self.assertIsNotNone(self.drv)
-
-    def test_create_router_on_eos(self):
-        router_name = 'test-router-1'
-        route_domain = '123:123'
-        router_mac = '00:11:22:33:44:55'
-
-        for s in self.drv._servers:
-            self.drv.create_router_on_eos(router_name, route_domain, s)
-            cmds = ['enable', 'configure',
-                    'ip virtual-router mac-address %s' % router_mac, 'exit']
-
-            s.runCmds.assert_called_with(version=1, cmds=cmds)
-
-    def test_delete_router_from_eos(self):
-        router_name = 'test-router-1'
-
-        for s in self.drv._servers:
-            self.drv.delete_router_from_eos(router_name, s)
-            cmds = ['enable', 'configure',
-                    'no ip virtual-router mac-address', 'exit']
-
-            s.runCmds.assert_called_once_with(version=1, cmds=cmds)
-
-    def test_add_interface_to_router_on_eos(self):
-        router_name = 'test-router-1'
-        segment_id = '123'
-        router_ip = '10.10.10.10'
-        gw_ip = '10.10.10.1'
-        mask = '255.255.255.0'
-
-        for s in self.drv._servers:
-            self.drv.add_interface_to_router(segment_id, router_name, gw_ip,
-                                             router_ip, mask, s)
-            cmds = ['enable', 'configure', 'ip routing',
-                    'vlan %s' % segment_id, 'exit',
-                    'interface vlan %s' % segment_id,
-                    'ip address %s' % router_ip,
-                    'ip virtual-router address %s' % gw_ip, 'exit']
-
-            s.runCmds.assert_called_once_with(version=1, cmds=cmds)
-
-    def test_delete_interface_from_router_on_eos(self):
-        router_name = 'test-router-1'
-        segment_id = '123'
-
-        for s in self.drv._servers:
-            self.drv.delete_interface_from_router(segment_id, router_name, s)
-
-            cmds = ['enable', 'configure', 'no interface vlan %s' % segment_id,
-                    'exit']
-
-            s.runCmds.assert_called_once_with(version=1, cmds=cmds)
-
-
-class AristaL3DriverTestCases_v4(base.BaseTestCase):
-    """Test cases to test the RPC between Arista Driver and EOS.
-
-    Tests all methods used to send commands between Arista L3 Driver and EOS
-    to program routing functions in Default VRF using IPv4.
-    """
-
-    def setUp(self):
-        super(AristaL3DriverTestCases_v4, self).setUp()
-        setup_arista_config('value')
-        self.drv = arista.AristaL3Driver()
-        self.drv._servers = []
-        self.drv._servers.append(mock.MagicMock())
-
-    def test_no_exception_on_correct_configuration(self):
-        self.assertIsNotNone(self.drv)
-
-    def test_add_v4_interface_to_router(self):
-        gateway_ip = '10.10.10.1'
-        cidrs = ['10.10.10.0/24', '10.11.11.0/24']
-
-        # Add couple of IPv4 subnets to router
-        for cidr in cidrs:
-            router = {'name': 'test-router-1',
-                      'tenant_id': 'ten-a',
-                      'seg_id': '123',
-                      'cidr': "%s" % cidr,
-                      'gip': "%s" % gateway_ip,
-                      'ip_version': 4}
-
-            self.assertFalse(self.drv.add_router_interface(None, router))
-
-    def test_delete_v4_interface_from_router(self):
-        gateway_ip = '10.10.10.1'
-        cidrs = ['10.10.10.0/24', '10.11.11.0/24']
-
-        # remove couple of IPv4 subnets from router
-        for cidr in cidrs:
-            router = {'name': 'test-router-1',
-                      'tenant_id': 'ten-a',
-                      'seg_id': '123',
-                      'cidr': "%s" % cidr,
-                      'gip': "%s" % gateway_ip,
-                      'ip_version': 4}
-
-            self.assertFalse(self.drv.remove_router_interface(None, router))
-
-
-class AristaL3DriverTestCases_v6(base.BaseTestCase):
-    """Test cases to test the RPC between Arista Driver and EOS.
-
-    Tests all methods used to send commands between Arista L3 Driver and EOS
-    to program routing functions in Default VRF using IPv6.
-    """
-
-    def setUp(self):
-        super(AristaL3DriverTestCases_v6, self).setUp()
-        setup_arista_config('value')
-        self.drv = arista.AristaL3Driver()
-        self.drv._servers = []
-        self.drv._servers.append(mock.MagicMock())
-
-    def test_no_exception_on_correct_configuration(self):
-        self.assertIsNotNone(self.drv)
-
-    def test_add_v6_interface_to_router(self):
-        gateway_ip = '3FFE::1'
-        cidrs = ['3FFE::/16', '2001::/16']
-
-        # Add couple of IPv6 subnets to router
-        for cidr in cidrs:
-            router = {'name': 'test-router-1',
-                      'tenant_id': 'ten-a',
-                      'seg_id': '123',
-                      'cidr': "%s" % cidr,
-                      'gip': "%s" % gateway_ip,
-                      'ip_version': 6}
-
-            self.assertFalse(self.drv.add_router_interface(None, router))
-
-    def test_delete_v6_interface_from_router(self):
-        gateway_ip = '3FFE::1'
-        cidrs = ['3FFE::/16', '2001::/16']
-
-        # remove couple of IPv6 subnets from router
-        for cidr in cidrs:
-            router = {'name': 'test-router-1',
-                      'tenant_id': 'ten-a',
-                      'seg_id': '123',
-                      'cidr': "%s" % cidr,
-                      'gip': "%s" % gateway_ip,
-                      'ip_version': 6}
-
-            self.assertFalse(self.drv.remove_router_interface(None, router))
-
-
-class AristaL3DriverTestCases_MLAG_v6(base.BaseTestCase):
-    """Test cases to test the RPC between Arista Driver and EOS.
-
-    Tests all methods used to send commands between Arista L3 Driver and EOS
-    to program routing functions in Default VRF on MLAG'ed switches using IPv6.
-    """
-
-    def setUp(self):
-        super(AristaL3DriverTestCases_MLAG_v6, 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_no_exception_on_correct_configuration(self):
-        self.assertIsNotNone(self.drv)
-
-    def test_add_v6_interface_to_router(self):
-        gateway_ip = '3FFE::1'
-        cidrs = ['3FFE::/16', '2001::/16']
-
-        # Add couple of IPv6 subnets to router
-        for cidr in cidrs:
-            router = {'name': 'test-router-1',
-                      'tenant_id': 'ten-a',
-                      'seg_id': '123',
-                      'cidr': "%s" % cidr,
-                      'gip': "%s" % gateway_ip,
-                      'ip_version': 6}
-
-            self.assertFalse(self.drv.add_router_interface(None, router))
-
-    def test_delete_v6_interface_from_router(self):
-        gateway_ip = '3FFE::1'
-        cidrs = ['3FFE::/16', '2001::/16']
-
-        # remove couple of IPv6 subnets from router
-        for cidr in cidrs:
-            router = {'name': 'test-router-1',
-                      'tenant_id': 'ten-a',
-                      'seg_id': '123',
-                      'cidr': "%s" % cidr,
-                      'gip': "%s" % gateway_ip,
-                      '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)