+++ /dev/null
-# Defines configuration options specific for Arista ML2 Mechanism driver
-
-[ml2_arista]
-# (StrOpt) EOS IP address. This is required field. If not set, all
-# communications to Arista EOS will fail
-#
-# eapi_host =
-# Example: eapi_host = 192.168.0.1
-#
-# (StrOpt) EOS command API username. This is required field.
-# if not set, all communications to Arista EOS will fail.
-#
-# eapi_username =
-# Example: arista_eapi_username = admin
-#
-# (StrOpt) EOS command API password. This is required field.
-# if not set, all communications to Arista EOS will fail.
-#
-# eapi_password =
-# Example: eapi_password = my_password
-#
-# (StrOpt) Defines if hostnames are sent to Arista EOS as FQDNs
-# ("node1.domain.com") or as short names ("node1"). This is
-# optional. If not set, a value of "True" is assumed.
-#
-# use_fqdn =
-# Example: use_fqdn = True
-#
-# (IntOpt) Sync interval in seconds between Neutron plugin and EOS.
-# This field defines how often the synchronization is performed.
-# This is an optional field. If not set, a value of 180 seconds
-# is assumed.
-#
-# sync_interval =
-# Example: sync_interval = 60
-#
-# (StrOpt) Defines Region Name that is assigned to this OpenStack Controller.
-# This is useful when multiple OpenStack/Neutron controllers are
-# managing the same Arista HW clusters. Note that this name must
-# match with the region name registered (or known) to keystone
-# service. Authentication with Keysotne is performed by EOS.
-# This is optional. If not set, a value of "RegionOne" is assumed.
-#
-# region_name =
-# Example: region_name = RegionOne
-
-
-[l3_arista]
-
-# (StrOpt) primary host IP address. This is required field. If not set, all
-# communications to Arista EOS will fail. This is the host where
-# primary router is created.
-#
-# primary_l3_host =
-# Example: primary_l3_host = 192.168.10.10
-#
-# (StrOpt) Primary host username. This is required field.
-# if not set, all communications to Arista EOS will fail.
-#
-# primary_l3_host_username =
-# Example: arista_primary_l3_username = admin
-#
-# (StrOpt) Primary host password. This is required field.
-# if not set, all communications to Arista EOS will fail.
-#
-# primary_l3_host_password =
-# Example: primary_l3_password = my_password
-#
-# (StrOpt) IP address of the second Arista switch paired as
-# MLAG (Multi-chassis Link Aggregation) with the first.
-# This is optional field, however, if mlag_config flag is set,
-# then this is a required field. If not set, all
-# communications to Arista EOS will fail. If mlag_config is set
-# to False, then this field is ignored
-#
-# seconadary_l3_host =
-# Example: seconadary_l3_host = 192.168.10.20
-#
-# (BoolOpt) Defines if Arista switches are configured in MLAG mode
-# If yes, all L3 configuration is pushed to both switches
-# automatically. If this flag is set, ensure that secondary_l3_host
-# is set to the second switch's IP.
-# This flag is Optional. If not set, a value of "False" is assumed.
-#
-# mlag_config =
-# Example: mlag_config = True
-#
-# (BoolOpt) Defines if the router is created in default VRF or a
-# a specific VRF. This is optional.
-# If not set, a value of "False" is assumed.
-#
-# Example: use_vrf = True
-#
-# (IntOpt) Sync interval in seconds between Neutron plugin and EOS.
-# This field defines how often the synchronization is performed.
-# This is an optional field. If not set, a value of 180 seconds
-# is assumed.
-#
-# l3_sync_interval =
-# Example: l3_sync_interval = 60
FWAAS_TABLES = ['firewall_rules', 'firewalls', 'firewall_policies']
DRIVER_TABLES = [
+ # Arista ML2 driver Models moved to openstack/networking-arista
+ 'arista_provisioned_nets',
+ 'arista_provisioned_vms',
+ 'arista_provisioned_tenants',
# Models moved to openstack/networking-cisco
'cisco_ml2_apic_contracts',
'cisco_ml2_apic_names',
from neutron.plugins.cisco.db.l3 import l3_models # noqa
from neutron.plugins.cisco.db import n1kv_models_v2 # noqa
from neutron.plugins.cisco.db import network_models_v2 # noqa
-from neutron.plugins.ml2.drivers.arista import db # noqa
from neutron.plugins.ml2.drivers.brocade.db import ( # noqa
models as ml2_brocade_models)
from neutron.plugins.ml2.drivers.cisco.n1kv import n1kv_models # noqa
+++ /dev/null
-
-Arista Neutron ML2 Mechanism Driver
-
-This mechanism driver implements ML2 Driver API and is used to manage the virtual and physical networks using Arista Hardware.
-
-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
+++ /dev/null
-# 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.
-
-
-from oslo_config import cfg
-
-
-# Arista ML2 Mechanism driver specific configuration knobs.
-#
-# Following are user configurable options for Arista ML2 Mechanism
-# driver. The eapi_username, eapi_password, and eapi_host are
-# required options. Region Name must be the same that is used by
-# Keystone service. This option is available to support multiple
-# OpenStack/Neutron controllers.
-
-ARISTA_DRIVER_OPTS = [
- cfg.StrOpt('eapi_username',
- default='',
- help=_('Username for Arista EOS. This is required field. '
- 'If not set, all communications to Arista EOS '
- 'will fail.')),
- cfg.StrOpt('eapi_password',
- default='',
- secret=True, # do not expose value in the logs
- help=_('Password for Arista EOS. This is required field. '
- 'If not set, all communications to Arista EOS '
- 'will fail.')),
- cfg.StrOpt('eapi_host',
- default='',
- help=_('Arista EOS IP address. This is required field. '
- 'If not set, all communications to Arista EOS '
- 'will fail.')),
- cfg.BoolOpt('use_fqdn',
- default=True,
- help=_('Defines if hostnames are sent to Arista EOS as FQDNs '
- '("node1.domain.com") or as short names ("node1"). '
- 'This is optional. If not set, a value of "True" '
- 'is assumed.')),
- cfg.IntOpt('sync_interval',
- default=180,
- help=_('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 180 seconds is '
- 'assumed.')),
- cfg.StrOpt('region_name',
- default='RegionOne',
- help=_('Defines Region Name that is assigned to this OpenStack '
- 'Controller. This is useful when multiple '
- 'OpenStack/Neutron controllers are managing the same '
- 'Arista HW clusters. Note that this name must match '
- 'with the region name registered (or known) to keystone '
- 'service. Authentication with Keysotne is performed by '
- 'EOS. This is optional. If not set, a value of '
- '"RegionOne" is assumed.'))
-]
-
-
-""" Arista L3 Service Plugin specific configuration knobs.
-
-Following are user configurable options for Arista L3 plugin
-driver. The eapi_username, eapi_password, and eapi_host are
-required options.
-"""
-
-ARISTA_L3_PLUGIN = [
- cfg.StrOpt('primary_l3_host_username',
- default='',
- help=_('Username for Arista EOS. This is required field. '
- 'If not set, all communications to Arista EOS '
- 'will fail')),
- cfg.StrOpt('primary_l3_host_password',
- default='',
- secret=True, # do not expose value in the logs
- help=_('Password for Arista EOS. This is required field. '
- 'If not set, all communications to Arista EOS '
- 'will fail')),
- cfg.StrOpt('primary_l3_host',
- default='',
- help=_('Arista EOS IP address. This is required field. '
- 'If not set, all communications to Arista EOS '
- 'will fail')),
- cfg.StrOpt('secondary_l3_host',
- default='',
- help=_('Arista EOS IP address for second Switch MLAGed with '
- 'the first one. This an optional field, however, if '
- 'mlag_config flag is set, then this is required. '
- 'If not set, all communications to Arista EOS '
- 'will fail')),
- cfg.BoolOpt('mlag_config',
- default=False,
- help=_('This flag is used indicate if Arista Switches are '
- 'configured in MLAG mode. If yes, all L3 config '
- 'is pushed to both the switches automatically. '
- 'If this flag is set to True, ensure to specify IP '
- 'addresses of both switches. '
- 'This is optional. If not set, a value of "False" '
- 'is assumed.')),
- cfg.BoolOpt('use_vrf',
- default=False,
- help=_('A "True" value for this flag indicates to create a '
- 'router in VRF. If not set, all routers are created '
- 'in default VRF. '
- 'This is optional. If not set, a value of "False" '
- 'is assumed.')),
- cfg.IntOpt('l3_sync_interval',
- default=180,
- help=_('Sync interval in seconds between L3 Service plugin '
- 'and EOS. This interval defines how often the '
- 'synchronization is performed. This is an optional '
- 'field. If not set, a value of 180 seconds is assumed'))
-]
-
-cfg.CONF.register_opts(ARISTA_L3_PLUGIN, "l3_arista")
-
-cfg.CONF.register_opts(ARISTA_DRIVER_OPTS, "ml2_arista")
+++ /dev/null
-# 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 sqlalchemy as sa
-
-from neutron.db import model_base
-from neutron.db import models_v2
-
-UUID_LEN = 36
-STR_LEN = 255
-
-
-class AristaProvisionedNets(model_base.BASEV2, models_v2.HasId,
- models_v2.HasTenant):
- """Stores networks provisioned on Arista EOS.
-
- Saves the segmentation ID for each network that is provisioned
- on EOS. This information is used during synchronization between
- Neutron and EOS.
- """
- __tablename__ = 'arista_provisioned_nets'
-
- network_id = sa.Column(sa.String(UUID_LEN))
- segmentation_id = sa.Column(sa.Integer)
-
- def eos_network_representation(self, segmentation_type):
- return {u'networkId': self.network_id,
- u'segmentationTypeId': self.segmentation_id,
- u'segmentationType': segmentation_type}
-
-
-class AristaProvisionedVms(model_base.BASEV2, models_v2.HasId,
- models_v2.HasTenant):
- """Stores VMs provisioned on Arista EOS.
-
- All VMs launched on physical hosts connected to Arista
- Switches are remembered
- """
- __tablename__ = 'arista_provisioned_vms'
-
- vm_id = sa.Column(sa.String(STR_LEN))
- host_id = sa.Column(sa.String(STR_LEN))
- port_id = sa.Column(sa.String(UUID_LEN))
- network_id = sa.Column(sa.String(UUID_LEN))
-
- def eos_vm_representation(self):
- return {u'vmId': self.vm_id,
- u'host': self.host_id,
- u'ports': {self.port_id: [{u'portId': self.port_id,
- u'networkId': self.network_id}]}}
-
- def eos_port_representation(self):
- return {u'vmId': self.vm_id,
- u'host': self.host_id,
- u'portId': self.port_id,
- u'networkId': self.network_id}
-
-
-class AristaProvisionedTenants(model_base.BASEV2, models_v2.HasId,
- models_v2.HasTenant):
- """Stores Tenants provisioned on Arista EOS.
-
- Tenants list is maintained for sync between Neutron and EOS.
- """
- __tablename__ = 'arista_provisioned_tenants'
-
- def eos_tenant_representation(self):
- return {u'tenantId': self.tenant_id}
+++ /dev/null
-# 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.
-
-
-"""Exceptions used by Arista ML2 Mechanism Driver."""
-
-from neutron.common import exceptions
-
-
-class AristaRpcError(exceptions.NeutronException):
- message = _('%(msg)s')
-
-
-class AristaConfigError(exceptions.NeutronException):
- message = _('%(msg)s')
-
-
-class AristaServicePluginRpcError(exceptions.NeutronException):
- message = _('%(msg)s')
-
-
-class AristaServicePluginConfigError(exceptions.NeutronException):
- message = _('%(msg)s')
+++ /dev/null
-# 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 threading
-
-from networking_arista.common import db_lib
-from networking_arista.ml2 import arista_ml2
-from oslo_config import cfg
-from oslo_log import log as logging
-
-from neutron.common import constants as n_const
-from neutron.i18n import _LI
-from neutron.plugins.common import constants as p_const
-from neutron.plugins.ml2.common import exceptions as ml2_exc
-from neutron.plugins.ml2 import driver_api
-from neutron.plugins.ml2.drivers.arista import config # noqa
-from neutron.plugins.ml2.drivers.arista import db
-from neutron.plugins.ml2.drivers.arista import exceptions as arista_exc
-
-LOG = logging.getLogger(__name__)
-
-EOS_UNREACHABLE_MSG = _('Unable to reach EOS')
-
-
-class AristaDriver(driver_api.MechanismDriver):
- """Ml2 Mechanism driver for Arista networking hardware.
-
- Remembers all networks and VMs that are provisioned on Arista Hardware.
- Does not send network provisioning request if the network has already been
- provisioned before for the given port.
- """
- def __init__(self, rpc=None):
-
- self.rpc = rpc or arista_ml2.AristaRPCWrapper()
- self.db_nets = db.AristaProvisionedNets()
- self.db_vms = db.AristaProvisionedVms()
- self.db_tenants = db.AristaProvisionedTenants()
- self.ndb = db_lib.NeutronNets()
-
- confg = cfg.CONF.ml2_arista
- self.segmentation_type = db_lib.VLAN_SEGMENTATION
- self.timer = None
- self.eos = arista_ml2.SyncService(self.rpc, self.ndb)
- self.sync_timeout = confg['sync_interval']
- self.eos_sync_lock = threading.Lock()
-
- def initialize(self):
- self.rpc.register_with_eos()
- self._cleanup_db()
- self.rpc.check_cli_commands()
- # Registering with EOS updates self.rpc.region_updated_time. Clear it
- # to force an initial sync
- self.rpc.clear_region_updated_time()
- self._synchronization_thread()
-
- def create_network_precommit(self, context):
- """Remember the tenant, and network information."""
-
- network = context.current
- segments = context.network_segments
- if segments[0][driver_api.NETWORK_TYPE] != p_const.TYPE_VLAN:
- # If network type is not VLAN, do nothing
- return
- network_id = network['id']
- tenant_id = network['tenant_id']
- if not tenant_id:
- tenant_id = context._plugin_context.tenant_id
- segmentation_id = segments[0]['segmentation_id']
- with self.eos_sync_lock:
- db_lib.remember_tenant(tenant_id)
- db_lib.remember_network(tenant_id,
- network_id,
- segmentation_id)
-
- def create_network_postcommit(self, context):
- """Provision the network on the Arista Hardware."""
-
- network = context.current
- network_id = network['id']
- network_name = network['name']
- tenant_id = network['tenant_id']
- if not tenant_id:
- tenant_id = context._plugin_context.tenant_id
- segments = context.network_segments
- vlan_id = segments[0]['segmentation_id']
- shared_net = network['shared']
- with self.eos_sync_lock:
- if db_lib.is_network_provisioned(tenant_id, network_id):
- try:
- network_dict = {
- 'network_id': network_id,
- 'segmentation_id': vlan_id,
- 'network_name': network_name,
- 'shared': shared_net}
- self.rpc.create_network(tenant_id, network_dict)
- except arista_exc.AristaRpcError:
- LOG.info(EOS_UNREACHABLE_MSG)
- raise ml2_exc.MechanismDriverError()
- else:
- LOG.info(_LI('Network %s is not created as it is not found in '
- 'Arista DB'), network_id)
-
- def update_network_precommit(self, context):
- """At the moment we only support network name change
-
- Any other change in network is not supported at this time.
- We do not store the network names, therefore, no DB store
- action is performed here.
- """
- new_network = context.current
- orig_network = context.original
- if new_network['name'] != orig_network['name']:
- LOG.info(_LI('Network name changed to %s'), new_network['name'])
-
- def update_network_postcommit(self, context):
- """At the moment we only support network name change
-
- If network name is changed, a new network create request is
- sent to the Arista Hardware.
- """
- new_network = context.current
- orig_network = context.original
- if ((new_network['name'] != orig_network['name']) or
- (new_network['shared'] != orig_network['shared'])):
- network_id = new_network['id']
- network_name = new_network['name']
- tenant_id = new_network['tenant_id']
- if not tenant_id:
- tenant_id = context._plugin_context.tenant_id
- vlan_id = new_network['provider:segmentation_id']
- shared_net = new_network['shared']
- with self.eos_sync_lock:
- if db_lib.is_network_provisioned(tenant_id, network_id):
- try:
- network_dict = {
- 'network_id': network_id,
- 'segmentation_id': vlan_id,
- 'network_name': network_name,
- 'shared': shared_net}
- self.rpc.create_network(tenant_id, network_dict)
- except arista_exc.AristaRpcError:
- LOG.info(EOS_UNREACHABLE_MSG)
- raise ml2_exc.MechanismDriverError()
- else:
- LOG.info(_LI('Network %s is not updated as it is not found'
- ' in Arista DB'), network_id)
-
- def delete_network_precommit(self, context):
- """Delete the network infromation from the DB."""
- network = context.current
- network_id = network['id']
- tenant_id = network['tenant_id']
- with self.eos_sync_lock:
- if db_lib.is_network_provisioned(tenant_id, network_id):
- db_lib.forget_network(tenant_id, network_id)
-
- def delete_network_postcommit(self, context):
- """Send network delete request to Arista HW."""
- network = context.current
- segments = context.network_segments
- if segments[0][driver_api.NETWORK_TYPE] != p_const.TYPE_VLAN:
- # If networtk type is not VLAN, do nothing
- return
- network_id = network['id']
- tenant_id = network['tenant_id']
- if not tenant_id:
- tenant_id = context._plugin_context.tenant_id
- with self.eos_sync_lock:
-
- # Succeed deleting network in case EOS is not accessible.
- # EOS state will be updated by sync thread once EOS gets
- # alive.
- try:
- self.rpc.delete_network(tenant_id, network_id)
- # if necessary, delete tenant as well.
- self.delete_tenant(tenant_id)
- except arista_exc.AristaRpcError:
- LOG.info(EOS_UNREACHABLE_MSG)
- raise ml2_exc.MechanismDriverError()
-
- def create_port_precommit(self, context):
- """Remember the infromation about a VM and its ports
-
- A VM information, along with the physical host information
- is saved.
- """
- port = context.current
- device_id = port['device_id']
- device_owner = port['device_owner']
- host = context.host
-
- # device_id and device_owner are set on VM boot
- is_vm_boot = device_id and device_owner
- if host and is_vm_boot:
- port_id = port['id']
- network_id = port['network_id']
- tenant_id = port['tenant_id']
- if not tenant_id:
- tenant_id = context._plugin_context.tenant_id
- with self.eos_sync_lock:
- if not db_lib.is_network_provisioned(tenant_id, network_id):
- # Ignore this request if network is not provisioned
- return
- db_lib.remember_tenant(tenant_id)
- db_lib.remember_vm(device_id, host, port_id,
- network_id, tenant_id)
-
- def create_port_postcommit(self, context):
- """Plug a physical host into a network.
-
- Send provisioning request to Arista Hardware to plug a host
- into appropriate network.
- """
- port = context.current
- device_id = port['device_id']
- device_owner = port['device_owner']
- host = context.host
-
- # device_id and device_owner are set on VM boot
- is_vm_boot = device_id and device_owner
- if host and is_vm_boot:
- port_id = port['id']
- port_name = port['name']
- network_id = port['network_id']
- tenant_id = port['tenant_id']
- if not tenant_id:
- tenant_id = context._plugin_context.tenant_id
- with self.eos_sync_lock:
- hostname = self._host_name(host)
- vm_provisioned = db_lib.is_vm_provisioned(device_id,
- host,
- port_id,
- network_id,
- tenant_id)
- # If network does not exist under this tenant,
- # it may be a shared network. Get shared network owner Id
- net_provisioned = (
- db_lib.is_network_provisioned(tenant_id, network_id) or
- self.ndb.get_shared_network_owner_id(network_id)
- )
- if vm_provisioned and net_provisioned:
- try:
- self.rpc.plug_port_into_network(device_id,
- hostname,
- port_id,
- network_id,
- tenant_id,
- port_name,
- device_owner)
- except arista_exc.AristaRpcError:
- LOG.info(EOS_UNREACHABLE_MSG)
- raise ml2_exc.MechanismDriverError()
- else:
- LOG.info(_LI('VM %s is not created as it is not found in '
- 'Arista DB'), device_id)
-
- def update_port_precommit(self, context):
- """Update the name of a given port.
-
- At the moment we only support port name change.
- Any other change to port is not supported at this time.
- We do not store the port names, therefore, no DB store
- action is performed here.
- """
- new_port = context.current
- orig_port = context.original
- if new_port['name'] != orig_port['name']:
- LOG.info(_LI('Port name changed to %s'), new_port['name'])
- new_port = context.current
- device_id = new_port['device_id']
- device_owner = new_port['device_owner']
- host = context.host
-
- # device_id and device_owner are set on VM boot
- is_vm_boot = device_id and device_owner
- if host and host != orig_port['binding:host_id'] and is_vm_boot:
- port_id = new_port['id']
- network_id = new_port['network_id']
- tenant_id = new_port['tenant_id']
- if not tenant_id:
- tenant_id = context._plugin_context.tenant_id
- with self.eos_sync_lock:
- db_lib.update_vm_host(device_id, host, port_id,
- network_id, tenant_id)
-
- def update_port_postcommit(self, context):
- """Update the name of a given port in EOS.
-
- At the moment we only support port name change
- Any other change to port is not supported at this time.
- """
- port = context.current
- orig_port = context.original
-
- device_id = port['device_id']
- device_owner = port['device_owner']
- host = context.host
- is_vm_boot = device_id and device_owner
-
- if host and is_vm_boot:
- port_id = port['id']
- port_name = port['name']
- network_id = port['network_id']
- tenant_id = port['tenant_id']
- if not tenant_id:
- tenant_id = context._plugin_context.tenant_id
- with self.eos_sync_lock:
- hostname = self._host_name(host)
- segmentation_id = db_lib.get_segmentation_id(tenant_id,
- network_id)
- vm_provisioned = db_lib.is_vm_provisioned(device_id,
- host,
- port_id,
- network_id,
- tenant_id)
- # If network does not exist under this tenant,
- # it may be a shared network. Get shared network owner Id
- net_provisioned = (
- db_lib.is_network_provisioned(tenant_id, network_id,
- segmentation_id) or
- self.ndb.get_shared_network_owner_id(network_id)
- )
- if vm_provisioned and net_provisioned:
- try:
- orig_host = orig_port['binding:host_id']
- if host != orig_host:
- # The port moved to a different host. So delete the
- # old port on the old host before creating a new
- # port on the new host.
- self._delete_port(port, orig_host, tenant_id)
- self.rpc.plug_port_into_network(device_id,
- hostname,
- port_id,
- network_id,
- tenant_id,
- port_name,
- device_owner)
- except arista_exc.AristaRpcError:
- LOG.info(EOS_UNREACHABLE_MSG)
- raise ml2_exc.MechanismDriverError()
- else:
- LOG.info(_LI('VM %s is not updated as it is not found in '
- 'Arista DB'), device_id)
-
- def delete_port_precommit(self, context):
- """Delete information about a VM and host from the DB."""
- port = context.current
-
- host_id = context.host
- device_id = port['device_id']
- tenant_id = port['tenant_id']
- if not tenant_id:
- tenant_id = context._plugin_context.tenant_id
- network_id = port['network_id']
- port_id = port['id']
- with self.eos_sync_lock:
- if db_lib.is_vm_provisioned(device_id, host_id, port_id,
- network_id, tenant_id):
- db_lib.forget_vm(device_id, host_id, port_id,
- network_id, tenant_id)
-
- def delete_port_postcommit(self, context):
- """unPlug a physical host from a network.
-
- Send provisioning request to Arista Hardware to unplug a host
- from appropriate network.
- """
- port = context.current
- host = context.host
- tenant_id = port['tenant_id']
- if not tenant_id:
- tenant_id = context._plugin_context.tenant_id
-
- with self.eos_sync_lock:
- self._delete_port(port, host, tenant_id)
-
- def _delete_port(self, port, host, tenant_id):
- """Deletes the port from EOS.
-
- param port: Port which is to be deleted
- param host: The host on which the port existed
- param tenant_id: The tenant to which the port belongs to. Some times
- the tenant id in the port dict is not present (as in
- the case of HA router).
- """
- device_id = port['device_id']
- port_id = port['id']
- network_id = port['network_id']
- device_owner = port['device_owner']
-
- try:
- if not db_lib.is_network_provisioned(tenant_id, network_id):
- # If we do not have network associated with this, ignore it
- return
- hostname = self._host_name(host)
- if device_owner == n_const.DEVICE_OWNER_DHCP:
- self.rpc.unplug_dhcp_port_from_network(device_id,
- hostname,
- port_id,
- network_id,
- tenant_id)
- else:
- self.rpc.unplug_host_from_network(device_id,
- hostname,
- port_id,
- network_id,
- tenant_id)
- # if necessary, delete tenant as well.
- self.delete_tenant(tenant_id)
- except arista_exc.AristaRpcError:
- LOG.info(EOS_UNREACHABLE_MSG)
- raise ml2_exc.MechanismDriverError()
-
- def delete_tenant(self, tenant_id):
- """delete a tenant from DB.
-
- A tenant is deleted only if there is no network or VM configured
- configured for this tenant.
- """
- objects_for_tenant = (db_lib.num_nets_provisioned(tenant_id) +
- db_lib.num_vms_provisioned(tenant_id))
- if not objects_for_tenant:
- db_lib.forget_tenant(tenant_id)
- try:
- self.rpc.delete_tenant(tenant_id)
- except arista_exc.AristaRpcError:
- LOG.info(EOS_UNREACHABLE_MSG)
- raise ml2_exc.MechanismDriverError()
-
- def _host_name(self, hostname):
- fqdns_used = cfg.CONF.ml2_arista['use_fqdn']
- return hostname if fqdns_used else hostname.split('.')[0]
-
- def _synchronization_thread(self):
- with self.eos_sync_lock:
- self.eos.do_synchronize()
-
- self.timer = threading.Timer(self.sync_timeout,
- self._synchronization_thread)
- self.timer.start()
-
- def stop_synchronization_thread(self):
- if self.timer:
- self.timer.cancel()
- self.timer = None
-
- def _cleanup_db(self):
- """Clean up any uncessary entries in our DB."""
- db_tenants = db_lib.get_tenants()
- for tenant in db_tenants:
- neutron_nets = self.ndb.get_all_networks_for_tenant(tenant)
- neutron_nets_id = []
- for net in neutron_nets:
- neutron_nets_id.append(net['id'])
- db_nets = db_lib.get_networks(tenant)
- for net_id in db_nets.keys():
- if net_id not in neutron_nets_id:
- db_lib.forget_network(tenant, net_id)
+++ /dev/null
-# 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 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_log import helpers as log_helpers
-from oslo_log import log as logging
-from oslo_utils import excutils
-
-from neutron.api.rpc.agentnotifiers import l3_rpc_agent_api
-from neutron.api.rpc.handlers import l3_rpc
-from neutron.common import constants as n_const
-from neutron.common import rpc as n_rpc
-from neutron.common import topics
-from neutron import context as nctx
-from neutron.db import db_base_plugin_v2
-from neutron.db import extraroute_db
-from neutron.db import l3_agentschedulers_db
-from neutron.db import l3_gwmode_db
-from neutron.i18n import _LE, _LI
-from neutron.plugins.common import constants
-from neutron.plugins.ml2.driver_context import NetworkContext # noqa
-
-LOG = logging.getLogger(__name__)
-
-
-class AristaL3ServicePlugin(db_base_plugin_v2.NeutronDbPluginV2,
- extraroute_db.ExtraRoute_db_mixin,
- l3_gwmode_db.L3_NAT_db_mixin,
- l3_agentschedulers_db.L3AgentSchedulerDbMixin):
-
- """Implements L3 Router service plugin for Arista hardware.
-
- Creates routers in Arista hardware, manages them, adds/deletes interfaces
- to the routes.
- """
-
- supported_extension_aliases = ["router", "ext-gw-mode",
- "extraroute"]
-
- def __init__(self, driver=None):
-
- self.driver = driver or arista_l3_driver.AristaL3Driver()
- self.ndb = db_lib.NeutronNets()
- self.setup_rpc()
- self.sync_timeout = cfg.CONF.l3_arista.l3_sync_interval
- self.sync_lock = threading.Lock()
- self._synchronization_thread()
-
- def setup_rpc(self):
- # RPC support
- self.topic = topics.L3PLUGIN
- self.conn = n_rpc.create_connection(new=True)
- self.agent_notifiers.update(
- {n_const.AGENT_TYPE_L3: l3_rpc_agent_api.L3AgentNotifyAPI()})
- self.endpoints = [l3_rpc.L3RpcCallback()]
- self.conn.create_consumer(self.topic, self.endpoints,
- fanout=False)
- self.conn.consume_in_threads()
-
- def get_plugin_type(self):
- return constants.L3_ROUTER_NAT
-
- def get_plugin_description(self):
- """Returns string description of the plugin."""
- return ("Arista L3 Router Service Plugin for Arista Hardware "
- "based routing")
-
- def _synchronization_thread(self):
- with self.sync_lock:
- self.synchronize()
-
- self.timer = threading.Timer(self.sync_timeout,
- self._synchronization_thread)
- self.timer.start()
-
- def stop_synchronization_thread(self):
- if self.timer:
- self.timer.cancel()
- self.timer = None
-
- @log_helpers.log_method_call
- def create_router(self, context, router):
- """Create a new router entry in DB, and create it Arista HW."""
-
- tenant_id = self._get_tenant_id_for_create(context, router['router'])
-
- # Add router to the DB
- with context.session.begin(subtransactions=True):
- new_router = super(AristaL3ServicePlugin, self).create_router(
- context,
- router)
- # create router on the Arista Hw
- try:
- self.driver.create_router(context, tenant_id, new_router)
- return new_router
- except Exception:
- with excutils.save_and_reraise_exception():
- LOG.error(_LE("Error creating router on Arista HW router=%s "),
- new_router)
- super(AristaL3ServicePlugin, self).delete_router(context,
- new_router['id'])
-
- @log_helpers.log_method_call
- def update_router(self, context, router_id, router):
- """Update an existing router in DB, and update it in Arista HW."""
-
- with context.session.begin(subtransactions=True):
- # Read existing router record from DB
- original_router = super(AristaL3ServicePlugin, self).get_router(
- context, router_id)
- # Update router DB
- new_router = super(AristaL3ServicePlugin, self).update_router(
- context, router_id, router)
-
- # Modify router on the Arista Hw
- try:
- self.driver.update_router(context, router_id,
- original_router, new_router)
- return new_router
- except Exception:
- LOG.error(_LE("Error updating router on Arista HW router=%s "),
- new_router)
-
- @log_helpers.log_method_call
- def delete_router(self, context, router_id):
- """Delete an existing router from Arista HW as well as from the DB."""
-
- router = super(AristaL3ServicePlugin, self).get_router(context,
- router_id)
- tenant_id = router['tenant_id']
-
- # Delete router on the Arista Hw
- try:
- self.driver.delete_router(context, tenant_id, router_id, router)
- except Exception as e:
- LOG.error(_LE("Error deleting router on Arista HW "
- "router %(r)s exception=%(e)s"),
- {'r': router, 'e': e})
-
- with context.session.begin(subtransactions=True):
- super(AristaL3ServicePlugin, self).delete_router(context,
- router_id)
-
- @log_helpers.log_method_call
- def add_router_interface(self, context, router_id, interface_info):
- """Add a subnet of a network to an existing router."""
-
- new_router = super(AristaL3ServicePlugin, self).add_router_interface(
- context, router_id, interface_info)
-
- # Get network info for the subnet that is being added to the router.
- # Check if the interface information is by port-id or subnet-id
- add_by_port, add_by_sub = self._validate_interface_info(interface_info)
- if add_by_sub:
- subnet = self.get_subnet(context, interface_info['subnet_id'])
- elif add_by_port:
- port = self.get_port(context, interface_info['port_id'])
- subnet_id = port['fixed_ips'][0]['subnet_id']
- subnet = self.get_subnet(context, subnet_id)
- network_id = subnet['network_id']
-
- # To create SVI's in Arista HW, the segmentation Id is required
- # for this network.
- ml2_db = NetworkContext(self, context, {'id': network_id})
- seg_id = ml2_db.network_segments[0]['segmentation_id']
-
- # Package all the info needed for Hw programming
- router = super(AristaL3ServicePlugin, self).get_router(context,
- router_id)
- router_info = copy.deepcopy(new_router)
- router_info['seg_id'] = seg_id
- router_info['name'] = router['name']
- router_info['cidr'] = subnet['cidr']
- router_info['gip'] = subnet['gateway_ip']
- router_info['ip_version'] = subnet['ip_version']
-
- try:
- self.driver.add_router_interface(context, router_info)
- return new_router
- except Exception:
- with excutils.save_and_reraise_exception():
- LOG.error(_LE("Error Adding subnet %(subnet)s to "
- "router %(router_id)s on Arista HW"),
- {'subnet': subnet, 'router_id': router_id})
- super(AristaL3ServicePlugin, self).remove_router_interface(
- context,
- router_id,
- interface_info)
-
- @log_helpers.log_method_call
- def remove_router_interface(self, context, router_id, interface_info):
- """Remove a subnet of a network from an existing router."""
-
- new_router = (
- super(AristaL3ServicePlugin, self).remove_router_interface(
- context, router_id, interface_info))
-
- # Get network information of the subnet that is being removed
- subnet = self.get_subnet(context, new_router['subnet_id'])
- network_id = subnet['network_id']
-
- # For SVI removal from Arista HW, segmentation ID is needed
- ml2_db = NetworkContext(self, context, {'id': network_id})
- seg_id = ml2_db.network_segments[0]['segmentation_id']
-
- router = super(AristaL3ServicePlugin, self).get_router(context,
- router_id)
- router_info = copy.deepcopy(new_router)
- router_info['seg_id'] = seg_id
- router_info['name'] = router['name']
-
- try:
- self.driver.remove_router_interface(context, router_info)
- return new_router
- except Exception as exc:
- LOG.error(_LE("Error removing interface %(interface)s from "
- "router %(router_id)s on Arista HW"
- "Exception =(exc)s"),
- {'interface': interface_info, 'router_id': router_id,
- 'exc': exc})
-
- def synchronize(self):
- """Synchronizes Router DB from Neturon DB with EOS.
-
- Walks through the Neturon Db and ensures that all the routers
- created in Netuton DB match with EOS. After creating appropriate
- routers, it ensures to add interfaces as well.
- Uses idempotent properties of EOS configuration, which means
- same commands can be repeated.
- """
- LOG.info(_LI('Syncing Neutron Router DB <-> EOS'))
- ctx = nctx.get_admin_context()
-
- routers = super(AristaL3ServicePlugin, self).get_routers(ctx)
- for r in routers:
- tenant_id = r['tenant_id']
- ports = self.ndb.get_all_ports_for_tenant(tenant_id)
-
- try:
- self.driver.create_router(self, tenant_id, r)
-
- except Exception:
- continue
-
- # Figure out which interfaces are added to this router
- for p in ports:
- if p['device_id'] == r['id']:
- net_id = p['network_id']
- subnet_id = p['fixed_ips'][0]['subnet_id']
- subnet = self.ndb.get_subnet_info(subnet_id)
- ml2_db = NetworkContext(self, ctx, {'id': net_id})
- seg_id = ml2_db.network_segments[0]['segmentation_id']
-
- r['seg_id'] = seg_id
- r['cidr'] = subnet['cidr']
- r['gip'] = subnet['gateway_ip']
- r['ip_version'] = subnet['ip_version']
-
- try:
- self.driver.add_router_interface(self, r)
- except Exception:
- LOG.error(_LE("Error Adding interface %(subnet_id)s "
- "to router %(router_id)s on Arista HW"),
- {'subnet_id': subnet_id, 'router_id': r})
+++ /dev/null
-# 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 sys
-
-import mock
-
-from neutron.extensions import portbindings
-from neutron.tests.unit import testlib_api
-
-with mock.patch.dict(sys.modules,
- {'networking_arista': mock.Mock(),
- 'networking_arista.ml2': mock.Mock(),
- 'networking_arista.common': mock.Mock()}):
- from neutron.plugins.ml2.drivers.arista import mechanism_arista
-
-
-class AristaDriverTestCase(testlib_api.SqlTestCase):
- """Main test cases for Arista Mechanism driver.
-
- Tests all mechanism driver APIs supported by Arista Driver. It invokes
- all the APIs as they would be invoked in real world scenarios and
- verifies the functionality.
- """
- def setUp(self):
- super(AristaDriverTestCase, self).setUp()
- self.fake_rpc = mock.MagicMock()
- mechanism_arista.db_lib = self.fake_rpc
- self.drv = mechanism_arista.AristaDriver(self.fake_rpc)
-
- def tearDown(self):
- super(AristaDriverTestCase, self).tearDown()
- self.drv.stop_synchronization_thread()
-
- def test_create_network_precommit(self):
- tenant_id = 'ten-1'
- network_id = 'net1-id'
- segmentation_id = 1001
-
- network_context = self._get_network_context(tenant_id,
- network_id,
- segmentation_id,
- False)
- self.drv.create_network_precommit(network_context)
-
- expected_calls = [
- mock.call.remember_tenant(tenant_id),
- mock.call.remember_network(tenant_id,
- network_id,
- segmentation_id)
- ]
-
- mechanism_arista.db_lib.assert_has_calls(expected_calls)
-
- def test_create_network_postcommit(self):
- tenant_id = 'ten-1'
- network_id = 'net1-id'
- segmentation_id = 1001
-
- network_context = self._get_network_context(tenant_id,
- network_id,
- segmentation_id,
- False)
- mechanism_arista.db_lib.is_network_provisioned.return_value = True
- network = network_context.current
- segments = network_context.network_segments
- net_dict = {
- 'network_id': network['id'],
- 'segmentation_id': segments[0]['segmentation_id'],
- 'network_name': network['name'],
- 'shared': network['shared']}
-
- self.drv.create_network_postcommit(network_context)
-
- expected_calls = [
- mock.call.is_network_provisioned(tenant_id, network_id),
- mock.call.create_network(tenant_id, net_dict),
- ]
-
- mechanism_arista.db_lib.assert_has_calls(expected_calls)
-
- def test_delete_network_precommit(self):
- tenant_id = 'ten-1'
- network_id = 'net1-id'
- segmentation_id = 1001
-
- network_context = self._get_network_context(tenant_id,
- network_id,
- segmentation_id,
- False)
- mechanism_arista.db_lib.is_network_provisioned.return_value = True
- mechanism_arista.db_lib.num_nets_provisioned.return_value = 0
- mechanism_arista.db_lib.num_vms_provisioned.return_value = 0
- self.drv.delete_network_precommit(network_context)
-
- expected_calls = [
- mock.call.is_network_provisioned(tenant_id, network_id),
- mock.call.forget_network(tenant_id, network_id),
- ]
-
- mechanism_arista.db_lib.assert_has_calls(expected_calls)
-
- def test_delete_network_postcommit(self):
- tenant_id = 'ten-1'
- network_id = 'net1-id'
- segmentation_id = 1001
-
- network_context = self._get_network_context(tenant_id,
- network_id,
- segmentation_id,
- False)
-
- self.drv.delete_network_postcommit(network_context)
- expected_calls = [
- mock.call.delete_network(tenant_id, network_id),
- ]
-
- mechanism_arista.db_lib.assert_has_calls(expected_calls)
-
- def test_create_port_precommit(self):
- tenant_id = 'ten-1'
- network_id = 'net1-id'
- segmentation_id = 1001
- vm_id = 'vm1'
-
- network_context = self._get_network_context(tenant_id,
- network_id,
- segmentation_id,
- False)
-
- port_context = self._get_port_context(tenant_id,
- network_id,
- vm_id,
- network_context)
- host_id = port_context.current['binding:host_id']
- port_id = port_context.current['id']
- self.drv.create_port_precommit(port_context)
-
- expected_calls = [
- mock.call.remember_tenant(tenant_id),
- mock.call.remember_vm(vm_id, host_id, port_id,
- network_id, tenant_id)
- ]
-
- mechanism_arista.db_lib.assert_has_calls(expected_calls)
-
- def test_create_port_postcommit(self):
- tenant_id = 'ten-1'
- network_id = 'net1-id'
- segmentation_id = 1001
- vm_id = 'vm1'
-
- network_context = self._get_network_context(tenant_id,
- network_id,
- segmentation_id,
- False)
- port_context = self._get_port_context(tenant_id,
- network_id,
- vm_id,
- network_context)
- mechanism_arista.db_lib.is_vm_provisioned.return_value = True
- mechanism_arista.db_lib.is_network_provisioned.return_value = True
- mechanism_arista.db_lib.get_shared_network_owner_id.return_value = 1
-
- port = port_context.current
- device_id = port['device_id']
- device_owner = port['device_owner']
- host_id = port['binding:host_id']
- port_id = port['id']
- port_name = port['name']
-
- self.drv.create_port_postcommit(port_context)
-
- expected_calls = [
- mock.call.is_vm_provisioned(device_id, host_id, port_id,
- network_id, tenant_id),
- mock.call.is_network_provisioned(tenant_id, network_id),
- mock.call.plug_port_into_network(device_id, host_id, port_id,
- network_id, tenant_id,
- port_name, device_owner)
- ]
-
- mechanism_arista.db_lib.assert_has_calls(expected_calls)
-
- # Now test the delete ports
- def test_delete_port_precommit(self):
- tenant_id = 'ten-1'
- network_id = 'net1-id'
- segmentation_id = 1001
- vm_id = 'vm1'
-
- network_context = self._get_network_context(tenant_id,
- network_id,
- segmentation_id,
- False)
-
- port_context = self._get_port_context(tenant_id,
- network_id,
- vm_id,
- network_context)
- mechanism_arista.db_lib.is_vm_provisioned.return_value = True
- mechanism_arista.db_lib.num_nets_provisioned.return_value = 0
- mechanism_arista.db_lib.num_vms_provisioned.return_value = 0
- self.drv.delete_port_precommit(port_context)
-
- host_id = port_context.current['binding:host_id']
- port_id = port_context.current['id']
- expected_calls = [
- mock.call.is_vm_provisioned(vm_id, host_id, port_id,
- network_id, tenant_id),
- mock.call.forget_vm(vm_id, host_id, port_id,
- network_id, tenant_id),
- ]
-
- mechanism_arista.db_lib.assert_has_calls(expected_calls)
-
- def test_delete_port_postcommit(self):
- tenant_id = 'ten-1'
- network_id = 'net1-id'
- segmentation_id = 1001
- vm_id = 'vm1'
-
- network_context = self._get_network_context(tenant_id,
- network_id,
- segmentation_id,
- False)
- port_context = self._get_port_context(tenant_id,
- network_id,
- vm_id,
- network_context)
- port = port_context.current
- device_id = port['device_id']
- host_id = port['binding:host_id']
- port_id = port['id']
-
- self.drv.delete_port_postcommit(port_context)
-
- expected_calls = [
- mock.call.unplug_host_from_network(device_id, host_id, port_id,
- network_id, tenant_id)
- ]
-
- mechanism_arista.db_lib.assert_has_calls(expected_calls)
-
- def test_update_port_precommit(self):
- tenant_id = 'ten-1'
- network_id = 'net1-id'
- segmentation_id = 1001
- vm_id = 'vm1'
-
- network_context = self._get_network_context(tenant_id,
- network_id,
- segmentation_id,
- False)
-
- port_context = self._get_port_context(tenant_id,
- network_id,
- vm_id,
- network_context)
- host_id = port_context.current['binding:host_id']
- port_context.original['binding:host_id'] = 'ubuntu0'
- port_id = port_context.current['id']
- self.drv.update_port_precommit(port_context)
-
- expected_calls = [
- mock.call.update_vm_host(vm_id, host_id, port_id,
- network_id, tenant_id)
- ]
-
- mechanism_arista.db_lib.assert_has_calls(expected_calls)
-
- def test_update_port_postcommit(self):
- tenant_id = 'ten-1'
- network_id = 'net1-id'
- segmentation_id = 1001
- vm_id = 'vm1'
-
- network_context = self._get_network_context(tenant_id,
- network_id,
- segmentation_id,
- False)
- port_context = self._get_port_context(tenant_id,
- network_id,
- vm_id,
- network_context)
-
- mechanism_arista.db_lib.is_vm_provisioned.return_value = True
- mechanism_arista.db_lib.is_network_provisioned.return_value = True
- mechanism_arista.db_lib.get_shared_network_owner_id.return_value = 1
- mechanism_arista.db_lib.get_segmentation_id.return_value = 1001
- mechanism_arista.db_lib.num_nets_provisioned.return_value = 1
- mechanism_arista.db_lib.num_vms_provisioned.return_value = 1
-
- port = port_context.current
- device_id = port['device_id']
- device_owner = port['device_owner']
- host_id = port['binding:host_id']
- orig_host_id = 'ubuntu0'
- port_context.original['binding:host_id'] = orig_host_id
- port_id = port['id']
- port_name = port['name']
-
- self.drv.update_port_postcommit(port_context)
-
- expected_calls = [
- mock.call.NeutronNets(),
- mock.call.get_segmentation_id(tenant_id, network_id),
- mock.call.is_vm_provisioned(device_id, host_id, port_id,
- network_id, tenant_id),
- mock.call.is_network_provisioned(tenant_id, network_id,
- segmentation_id),
- mock.call.is_network_provisioned(tenant_id, network_id),
- mock.call.unplug_host_from_network(device_id, orig_host_id,
- port_id, network_id, tenant_id),
- mock.call.num_nets_provisioned(tenant_id),
- mock.call.num_vms_provisioned(tenant_id),
- mock.call.plug_port_into_network(device_id, host_id, port_id,
- network_id, tenant_id,
- port_name, device_owner)
- ]
-
- mechanism_arista.db_lib.assert_has_calls(expected_calls)
-
- def _get_network_context(self, tenant_id, net_id, seg_id, shared):
- network = {'id': net_id,
- 'tenant_id': tenant_id,
- 'name': 'test-net',
- 'shared': shared}
- network_segments = [{'segmentation_id': seg_id,
- 'network_type': 'vlan'}]
- return FakeNetworkContext(network, network_segments, network)
-
- def _get_port_context(self, tenant_id, net_id, vm_id, network):
- port = {'device_id': vm_id,
- 'device_owner': 'compute',
- 'binding:host_id': 'ubuntu1',
- 'name': 'test-port',
- 'tenant_id': tenant_id,
- 'id': 101,
- 'network_id': net_id
- }
- return FakePortContext(port, dict(port), network)
-
-
-class fake_keystone_info_class(object):
- """To generate fake Keystone Authentification token information
-
- Arista Driver expects Keystone auth info. This fake information
- is for testing only
- """
- auth_uri = 'abc://host:35357/v2.0/'
- identity_uri = 'abc://host:5000'
- admin_user = 'neutron'
- admin_password = 'fun'
- admin_tenant_name = 'tenant_name'
-
-
-class FakeNetworkContext(object):
- """To generate network context for testing purposes only."""
-
- def __init__(self, network, segments=None, original_network=None):
- self._network = network
- self._original_network = original_network
- self._segments = segments
-
- @property
- def current(self):
- return self._network
-
- @property
- def original(self):
- return self._original_network
-
- @property
- def network_segments(self):
- return self._segments
-
-
-class FakePortContext(object):
- """To generate port context for testing purposes only."""
-
- def __init__(self, port, original_port, network):
- self._port = port
- self._original_port = original_port
- self._network_context = network
-
- @property
- def current(self):
- return self._port
-
- @property
- def original(self):
- return self._original_port
-
- @property
- def network(self):
- return self._network_context
-
- @property
- def host(self):
- return self._port.get(portbindings.HOST_ID)
-
- @property
- def original_host(self):
- return self._original_port.get(portbindings.HOST_ID)
etc/neutron/plugins/bigswitch/restproxy.ini
etc/neutron/plugins/ml2/linuxbridge_agent.ini
etc/neutron/plugins/ml2/ml2_conf.ini
- etc/neutron/plugins/ml2/ml2_conf_arista.ini
etc/neutron/plugins/ml2/ml2_conf_brocade.ini
etc/neutron/plugins/ml2/ml2_conf_brocade_fi_ni.ini
etc/neutron/plugins/ml2/ml2_conf_cisco.ini
linuxbridge = neutron.plugins.ml2.drivers.linuxbridge.mech_driver.mech_linuxbridge:LinuxbridgeMechanismDriver
openvswitch = neutron.plugins.ml2.drivers.openvswitch.mech_driver.mech_openvswitch:OpenvswitchMechanismDriver
hyperv = neutron.plugins.ml2.drivers.hyperv.mech_hyperv:HypervMechanismDriver
- arista = neutron.plugins.ml2.drivers.arista.mechanism_arista:AristaDriver
# Note: ncs and cisco_ncs point to the same driver entrypoint
# TODO: The old name (ncs) can be dropped when it is no longer used
ncs = neutron.plugins.ml2.drivers.cisco.ncs.driver:NCSMechanismDriver
neutron.tests.unit.plugins.ml2.drivers.test_type_vxlan \
neutron.tests.unit.plugins.ml2.drivers.test_type_gre \
neutron.tests.unit.plugins.ml2.drivers.test_helpers \
- neutron.tests.unit.plugins.ml2.drivers.arista.test_mechanism_arista \
neutron.tests.unit.plugins.ml2.drivers.test_type_local \
neutron.tests.unit.plugins.ml2.drivers.mechanism_logger \
neutron.tests.unit.plugins.ml2.drivers.test_type_flat \