Implement Rest API in ML2 Nexus Driver
Supercedes https://review.openstack.org/429897 This change set includes the ability to configure Nexus 9K using REST API drivers instead of ncclient ssh Drivers. By default, ssh drivers are used. To utilize REST API drivers, the user must configure 'use_restapi_driver' to True in the ml2 config file. The benefit of using REST API drivers is there are no limits on the number of session limits on the Nexus side. Also there is significant performance improvements. However, to utilize this driver, the Nexus 9K must support the ability to configure VLANS and VXLANS by way of REST. The N9K image which meets all required REST API configuration is version 7.0(3)I5(2). Removed methods 'create_vlan_svi' and 'get_version' from the file nexus_network_driver.py since it is not being called by any code. I want the capability in this driver to match the new rest api driver. There was no sense in creating unused methods in the new rest api driver. Change-Id: I841fc46af5fc7cd668935c1c734f74d7a4cd888a Closes-bug: #1655097
This commit is contained in:
parent
d88831a06e
commit
6de0f6026b
|
@ -16,6 +16,15 @@
|
|||
# Nexus switches. Defaults to False (No hostkey checks)
|
||||
# host_key_checks = False
|
||||
|
||||
# (ListOp) A choice of drivers to configure Nexus devices. The
|
||||
# default choice is 'ncclient' which was the original driver
|
||||
# until rest api driver was developed. To choose the
|
||||
# rest api driver, set nexus_driver to 'restapi' which
|
||||
# has better performance and no Nexus session limits.
|
||||
# This option should only be selected if you have a
|
||||
# Nexus 9K image version 7.0(3)I5(2) or greater.
|
||||
# nexus_driver = ncclient
|
||||
|
||||
#
|
||||
# (StrOpt) The name of the physical_network managed via the Cisco Nexus Switch.
|
||||
# This string value must be present in the ml2_conf.ini network_vlan_ranges
|
||||
|
|
|
@ -45,6 +45,11 @@ ml2_cisco_opts = [
|
|||
cfg.BoolOpt('host_key_checks', default=False,
|
||||
help=_("Enable strict host key checks when "
|
||||
"connecting to Nexus switches")),
|
||||
cfg.StrOpt('nexus_driver',
|
||||
default='ncclient',
|
||||
help=_("Choice of Nexus Config Driver to be loaded from "
|
||||
"the networking_cisco.ml2.nexus_driver namespace.")),
|
||||
|
||||
]
|
||||
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ class NexusConnectFailed(exceptions.NeutronException):
|
|||
class NexusConfigFailed(exceptions.NeutronException):
|
||||
"""Failed to configure Nexus switch."""
|
||||
message = _("Failed to configure Nexus switch: %(nexus_host)s "
|
||||
"XML: %(config)s. Reason: %(exc)s.")
|
||||
"Config: %(config)s. Reason: %(exc)s.")
|
||||
|
||||
|
||||
class NexusPortBindingNotFound(exceptions.NeutronException):
|
||||
|
|
|
@ -30,6 +30,7 @@ from oslo_utils import excutils
|
|||
|
||||
from networking_cisco import backwards_compatibility as bc
|
||||
|
||||
from neutron.common import utils as neutron_utils
|
||||
from neutron.extensions import portbindings
|
||||
from neutron.plugins.common import constants as p_const
|
||||
|
||||
|
@ -49,8 +50,6 @@ from networking_cisco.plugins.ml2.drivers.cisco.nexus import (
|
|||
exceptions as excep)
|
||||
from networking_cisco.plugins.ml2.drivers.cisco.nexus import (
|
||||
nexus_db_v2 as nxos_db)
|
||||
from networking_cisco.plugins.ml2.drivers.cisco.nexus import (
|
||||
nexus_network_driver)
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
@ -157,6 +156,16 @@ class CiscoNexusCfgMonitor(object):
|
|||
|
||||
nve_bindings = nxos_db.get_nve_switch_bindings(switch_ip)
|
||||
|
||||
# If configured to set global VXLAN values and
|
||||
# there exists VXLAN data base entries, then configure
|
||||
# the "interface nve" entry on the switch.
|
||||
if (len(nve_bindings) > 0 and
|
||||
cfg.CONF.ml2_cisco.vxlan_global_config):
|
||||
LOG.debug("Nexus: Replay NVE Interface")
|
||||
loopback = self._mdriver.get_nve_loopback(switch_ip)
|
||||
self._driver.enable_vxlan_feature(switch_ip,
|
||||
const.NVE_INT_NUM, loopback)
|
||||
|
||||
for x in nve_bindings:
|
||||
try:
|
||||
self._driver.create_nve_member(switch_ip,
|
||||
|
@ -271,6 +280,21 @@ class CiscoNexusMechanismDriver(api.MechanismDriver):
|
|||
|
||||
"""Cisco Nexus ML2 Mechanism Driver."""
|
||||
|
||||
def _load_nexus_cfg_driver(self):
|
||||
"""Load Nexus Config driver.
|
||||
:raises SystemExit of 1 if driver cannot be loaded
|
||||
"""
|
||||
|
||||
try:
|
||||
loaded_class = neutron_utils.load_class_by_alias_or_classname(
|
||||
'networking_cisco.ml2.nexus_driver',
|
||||
conf.cfg.CONF.ml2_cisco.nexus_driver)
|
||||
return loaded_class()
|
||||
except ImportError:
|
||||
LOG.error(_LE("Error loading Nexus Config driver '%s'"),
|
||||
conf.cfg.CONF.ml2_cisco.nexus_driver)
|
||||
raise SystemExit(1)
|
||||
|
||||
def initialize(self):
|
||||
# Create ML2 device dictionary from ml2_conf.ini entries.
|
||||
conf.ML2MechCiscoConfig()
|
||||
|
@ -278,10 +302,11 @@ class CiscoNexusMechanismDriver(api.MechanismDriver):
|
|||
# Extract configuration parameters from the configuration file.
|
||||
self._nexus_switches = conf.ML2MechCiscoConfig.nexus_dict
|
||||
LOG.debug("nexus_switches found = %s", self._nexus_switches)
|
||||
|
||||
# Save dynamic switch information
|
||||
self._switch_state = {}
|
||||
|
||||
self.driver = nexus_network_driver.CiscoNexusDriver()
|
||||
self.driver = self._load_nexus_cfg_driver()
|
||||
|
||||
# This method is only called once regardless of number of
|
||||
# api/rpc workers defined.
|
||||
|
@ -1059,6 +1084,10 @@ class CiscoNexusMechanismDriver(api.MechanismDriver):
|
|||
nxos_db.add_nexusnve_binding(vni, switch_ip, device_id,
|
||||
mcast_group)
|
||||
|
||||
def get_nve_loopback(self, switch_ip):
|
||||
return self._nexus_switches.get(
|
||||
(switch_ip, 'nve_src_intf'), '0')
|
||||
|
||||
def _configure_nve_member(self, vni, device_id, mcast_group, host_id):
|
||||
"""Add "member vni" configuration to the NVE interface.
|
||||
|
||||
|
@ -1075,8 +1104,7 @@ class CiscoNexusMechanismDriver(api.MechanismDriver):
|
|||
nve_bindings = nxos_db.get_nve_switch_bindings(switch_ip)
|
||||
if len(nve_bindings) == 1:
|
||||
LOG.debug("Nexus: create NVE interface")
|
||||
loopback = self._nexus_switches.get(
|
||||
(switch_ip, 'nve_src_intf'), '0')
|
||||
loopback = self.get_nve_loopback(switch_ip)
|
||||
self.driver.enable_vxlan_feature(switch_ip,
|
||||
const.NVE_INT_NUM, loopback)
|
||||
|
||||
|
@ -1177,7 +1205,7 @@ class CiscoNexusMechanismDriver(api.MechanismDriver):
|
|||
nexus_port, vni, is_native)
|
||||
elif auto_create:
|
||||
LOG.debug("Nexus: create vlan %s", vlan_name)
|
||||
self.driver.create_vlan_segment(switch_ip, vlan_id,
|
||||
self.driver.create_vlan(switch_ip, vlan_id,
|
||||
vlan_name, vni)
|
||||
elif auto_trunk:
|
||||
LOG.debug("Nexus: trunk vlan %s", vlan_name)
|
||||
|
@ -1234,11 +1262,21 @@ class CiscoNexusMechanismDriver(api.MechanismDriver):
|
|||
|
||||
def _restore_port_binding(self,
|
||||
switch_ip, pvlan_ids,
|
||||
port, is_native):
|
||||
port, native_vlan):
|
||||
"""Restores a set of vlans for a given port."""
|
||||
|
||||
intf_type, nexus_port = self.split_interface_name(port)
|
||||
|
||||
# If native_vlan is configured, this is isolated since
|
||||
# two configs (native + trunk) must be sent for this vlan only.
|
||||
if native_vlan != 0:
|
||||
self.driver.send_enable_vlan_on_trunk_int(
|
||||
switch_ip, native_vlan,
|
||||
intf_type, nexus_port, True)
|
||||
# If this is the only vlan
|
||||
if len(pvlan_ids) == 1:
|
||||
return
|
||||
|
||||
concat_vlans = ''
|
||||
compressed_vlans = self._get_compressed_vlan_list(pvlan_ids)
|
||||
for pvlan in compressed_vlans:
|
||||
|
@ -1252,14 +1290,14 @@ class CiscoNexusMechanismDriver(api.MechanismDriver):
|
|||
if len(concat_vlans) >= const.CREATE_PORT_VLAN_LENGTH:
|
||||
self.driver.send_enable_vlan_on_trunk_int(
|
||||
switch_ip, concat_vlans,
|
||||
intf_type, nexus_port, is_native)
|
||||
intf_type, nexus_port, False)
|
||||
concat_vlans = ''
|
||||
|
||||
# Send remaining vlans if any
|
||||
if len(concat_vlans):
|
||||
self.driver.send_enable_vlan_on_trunk_int(
|
||||
switch_ip, concat_vlans,
|
||||
intf_type, nexus_port, is_native)
|
||||
intf_type, nexus_port, False)
|
||||
|
||||
def _restore_vxlan_entries(self, switch_ip, vlans):
|
||||
"""Restore vxlan entries on a Nexus switch."""
|
||||
|
@ -1267,24 +1305,30 @@ class CiscoNexusMechanismDriver(api.MechanismDriver):
|
|||
count = 1
|
||||
conf_str = ''
|
||||
vnsegment_sent = 0
|
||||
path_str, conf_str = self.driver.start_create_vlan()
|
||||
# At this time, this will only configure vni information when needed
|
||||
while vnsegment_sent < const.CREATE_VLAN_BATCH and vlans:
|
||||
vlan_id, vni, vlan_name = vlans.pop(0)
|
||||
# Add it to the batch
|
||||
conf_str += self.driver.get_create_vlan(
|
||||
switch_ip, vlan_id, vni)
|
||||
conf_str = self.driver.get_create_vlan(
|
||||
switch_ip, vlan_id, vni, conf_str)
|
||||
# batch size has been met
|
||||
if (count == const.CREATE_VLAN_SEND_SIZE):
|
||||
self.driver.send_edit_string(switch_ip, conf_str)
|
||||
conf_str = self.driver.end_create_vlan(conf_str)
|
||||
self.driver.send_edit_string(switch_ip, path_str, conf_str)
|
||||
vnsegment_sent += count
|
||||
conf_str = ''
|
||||
count = 1
|
||||
else:
|
||||
count += 1
|
||||
|
||||
# batch size was not met
|
||||
if conf_str:
|
||||
vnsegment_sent += count
|
||||
self.driver.send_edit_string(switch_ip, conf_str)
|
||||
conf_str = self.driver.end_create_vlan(conf_str)
|
||||
self.driver.send_edit_string(switch_ip, path_str, conf_str)
|
||||
conf_str = ''
|
||||
|
||||
LOG.debug("Switch %s VLAN vn-segment replay summary: %d",
|
||||
switch_ip, vnsegment_sent)
|
||||
|
||||
|
@ -1391,7 +1435,7 @@ class CiscoNexusMechanismDriver(api.MechanismDriver):
|
|||
prev_vlan = -1
|
||||
prev_vni = -1
|
||||
prev_port = None
|
||||
prev_is_native = False
|
||||
prev_native_vlan = 0
|
||||
starttime = time.time()
|
||||
|
||||
port_bindings.sort(key=lambda x: (x.port_id, x.vlan_id, x.vni))
|
||||
|
@ -1422,6 +1466,8 @@ class CiscoNexusMechanismDriver(api.MechanismDriver):
|
|||
vlans.add((port.vlan_id, port.vni, vlan_name))
|
||||
if auto_trunk:
|
||||
pvlans.add(port.vlan_id)
|
||||
if port.is_native:
|
||||
prev_native_vlan = port.vlan_id
|
||||
else:
|
||||
# Different port - write out interface trunk on previous port
|
||||
if prev_port:
|
||||
|
@ -1433,22 +1479,24 @@ class CiscoNexusMechanismDriver(api.MechanismDriver):
|
|||
vlan_count = 0
|
||||
if pvlans:
|
||||
self._restore_port_binding(
|
||||
switch_ip, pvlans, prev_port, prev_is_native)
|
||||
switch_ip, pvlans, prev_port, prev_native_vlan)
|
||||
pvlans.clear()
|
||||
prev_native_vlan = 0
|
||||
# Start tracking new port
|
||||
if auto_create:
|
||||
vlans.add((port.vlan_id, port.vni, vlan_name))
|
||||
if auto_trunk:
|
||||
pvlans.add(port.vlan_id)
|
||||
prev_port = port.port_id
|
||||
prev_is_native = port.is_native
|
||||
if port.is_native:
|
||||
prev_native_vlan = port.vlan_id
|
||||
|
||||
if pvlans:
|
||||
LOG.debug("Switch %s port %s replay summary: unique vlan "
|
||||
"count %d, duplicate port entries %d",
|
||||
switch_ip, port.port_id, vlan_count, duplicate_port)
|
||||
self._restore_port_binding(
|
||||
switch_ip, pvlans, prev_port, prev_is_native)
|
||||
switch_ip, pvlans, prev_port, prev_native_vlan)
|
||||
|
||||
LOG.debug("Replayed total %d ports for Switch %s",
|
||||
interface_count + 1, switch_ip)
|
||||
|
|
|
@ -0,0 +1,184 @@
|
|||
# Copyright (c) 2013-2016 Cisco Systems, 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.
|
||||
|
||||
"""
|
||||
Base class driver for SSH and RESTAPI Client. Some APIs are
|
||||
called by upper layer code but only apply to either RESTAPIs drivers
|
||||
or SSH drivers. Having base class which simply performs 'pass'
|
||||
is necessary so these two drivers get required actions without
|
||||
breaking the other driver. Drivers defined in this base are
|
||||
mostly those called externally.
|
||||
"""
|
||||
|
||||
import os
|
||||
import threading
|
||||
import time
|
||||
|
||||
from oslo_log import log as logging
|
||||
|
||||
from networking_cisco.plugins.ml2.drivers.cisco.nexus import (
|
||||
config as conf)
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CiscoNexusBaseDriver(object):
|
||||
"""Nexus Driver Base Class."""
|
||||
def __init__(self):
|
||||
self.nexus_switches = conf.ML2MechCiscoConfig.nexus_dict
|
||||
self.time_stats = {}
|
||||
|
||||
def keep_ssh_caching(self):
|
||||
pass
|
||||
|
||||
def init_ssh_caching(self):
|
||||
pass
|
||||
|
||||
def capture_and_print_timeshot(self, start_time, which,
|
||||
other=99, switch="0.0.0.0"):
|
||||
"""Determine delta, keep track, and print results."""
|
||||
|
||||
curr_timeout = time.time() - start_time
|
||||
if which in self.time_stats:
|
||||
self.time_stats[which]["total_time"] += curr_timeout
|
||||
self.time_stats[which]["total_count"] += 1
|
||||
if (curr_timeout < self.time_stats[which]["min"]):
|
||||
self.time_stats[which]["min"] = curr_timeout
|
||||
if (curr_timeout > self.time_stats[which]["max"]):
|
||||
self.time_stats[which]["max"] = curr_timeout
|
||||
else:
|
||||
self.time_stats[which] = {
|
||||
"total_time": curr_timeout,
|
||||
"total_count": 1,
|
||||
"min": curr_timeout,
|
||||
"max": curr_timeout}
|
||||
LOG.debug("NEXUS_TIME_STATS %(switch)s, pid %(pid)d, tid %(tid)d: "
|
||||
"%(which)s_timeout %(curr)f count %(count)d "
|
||||
"average %(ave)f other %(other)d min %(min)f max %(max)f",
|
||||
{'switch': switch,
|
||||
'pid': os.getpid(),
|
||||
'tid': threading.current_thread().ident,
|
||||
'which': which,
|
||||
'curr': curr_timeout,
|
||||
'count': self.time_stats[which]["total_count"],
|
||||
'ave': (self.time_stats[which]["total_time"] /
|
||||
self.time_stats[which]["total_count"]),
|
||||
'other': other,
|
||||
'min': self.time_stats[which]["min"],
|
||||
'max': self.time_stats[which]["max"]})
|
||||
|
||||
def close_session(self, nexus_host):
|
||||
pass
|
||||
|
||||
def get_interface_switch(self, nexus_host,
|
||||
intf_type, interface):
|
||||
"""Get the interface data from host.
|
||||
|
||||
:param nexus_host: IP address of Nexus switch
|
||||
:param intf_type: String which specifies interface type.
|
||||
example: ethernet
|
||||
:param interface: String indicating which interface.
|
||||
example: 1/19
|
||||
:returns response:
|
||||
"""
|
||||
return None
|
||||
|
||||
def initialize_all_switch_interfaces(self, interfaces):
|
||||
"""Configure Nexus interface and get port channel number.
|
||||
|
||||
Receive a list of interfaces containing:
|
||||
:param nexus_host: IP address of Nexus switch
|
||||
:param intf_type: String which specifies interface type.
|
||||
example: ethernet
|
||||
:param interface: String indicating which interface.
|
||||
example: 1/19
|
||||
:returns interface: Appends port channel to each entry
|
||||
channel number is 0 if none
|
||||
"""
|
||||
pass
|
||||
|
||||
def get_nexus_type(self, nexus_host):
|
||||
"""Given the nexus host, get the type of Nexus switch.
|
||||
|
||||
:param nexus_host: IP address of Nexus switch
|
||||
:returns Nexus type
|
||||
"""
|
||||
return None
|
||||
|
||||
def set_all_vlan_states(self, nexus_host, vlanid_range):
|
||||
"""Set the VLAN states to active."""
|
||||
pass
|
||||
|
||||
def start_create_vlan(self):
|
||||
"""Returns an XML snippet for start of create VLAN."""
|
||||
return None, ''
|
||||
|
||||
def get_create_vlan(self, nexus_host, vlanid, vni, conf_str):
|
||||
"""Returns an XML snippet for create VLAN."""
|
||||
return conf_str
|
||||
|
||||
def end_create_vlan(self, conf_str):
|
||||
"""Returns an XML snippet for terminate of create VLAN."""
|
||||
return conf_str
|
||||
|
||||
def create_vlan(self, nexus_host,
|
||||
vlanid, vlanname, vni):
|
||||
"""Create a VLAN on a Nexus Switch.
|
||||
|
||||
Creates a VLAN given the VLAN ID, name and possible VxLAN ID.
|
||||
"""
|
||||
pass
|
||||
|
||||
def delete_vlan(self, nexus_host, vlanid):
|
||||
"""Delete a VLAN on Nexus Switch given the VLAN ID."""
|
||||
pass
|
||||
|
||||
def disable_vlan_on_trunk_int(self, nexus_host, vlanid, intf_type,
|
||||
interface, is_native):
|
||||
"""Disable a VLAN on a trunk interface."""
|
||||
pass
|
||||
|
||||
def send_edit_string(self, nexus_host, path, confstr,
|
||||
check_to_close_session=True):
|
||||
"""Sends any XML snippet to Nexus switch."""
|
||||
pass
|
||||
|
||||
def send_enable_vlan_on_trunk_int(self, nexus_host, vlanid, intf_type,
|
||||
interface, is_native):
|
||||
"""Gathers and sends an interface trunk XML snippet."""
|
||||
pass
|
||||
|
||||
def create_and_trunk_vlan(self, nexus_host, vlan_id,
|
||||
vlan_name, intf_type,
|
||||
nexus_port, vni,
|
||||
is_native):
|
||||
"""Create VLAN and trunk it on the specified ports."""
|
||||
pass
|
||||
|
||||
def enable_vxlan_feature(self, nexus_host, nve_int_num, src_intf):
|
||||
"""Enable VXLAN on the switch."""
|
||||
pass
|
||||
|
||||
def disable_vxlan_feature(self, nexus_host):
|
||||
"""Disable VXLAN on the switch."""
|
||||
pass
|
||||
|
||||
def create_nve_member(self, nexus_host, nve_int_num, vni, mcast_group):
|
||||
"""Add a member configuration to the NVE interface."""
|
||||
pass
|
||||
|
||||
def delete_nve_member(self, nexus_host, nve_int_num, vni):
|
||||
"""Delete a member configuration on the NVE interface."""
|
||||
pass
|
|
@ -17,10 +17,8 @@
|
|||
Implements a Nexus-OS NETCONF over SSHv2 API Client
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import six
|
||||
import threading
|
||||
import time
|
||||
|
||||
from oslo_concurrency import lockutils
|
||||
|
@ -36,20 +34,23 @@ from networking_cisco.plugins.ml2.drivers.cisco.nexus import (
|
|||
constants as const)
|
||||
from networking_cisco.plugins.ml2.drivers.cisco.nexus import (
|
||||
exceptions as cexc)
|
||||
from networking_cisco.plugins.ml2.drivers.cisco.nexus import (
|
||||
nexus_base_network_driver as basedrvr)
|
||||
from networking_cisco.plugins.ml2.drivers.cisco.nexus import (
|
||||
nexus_snippets as snipp)
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CiscoNexusDriver(object):
|
||||
class CiscoNexusSshDriver(basedrvr.CiscoNexusBaseDriver):
|
||||
"""Nexus Driver Main Class."""
|
||||
def __init__(self):
|
||||
self.ncclient = None
|
||||
self.nexus_switches = conf.ML2MechCiscoConfig.nexus_dict
|
||||
self.connections = {}
|
||||
self.time_stats = {}
|
||||
self.init_ssh_caching()
|
||||
super(CiscoNexusSshDriver, self).__init__()
|
||||
LOG.debug("ML2 Nexus SSH Drivers initialized.")
|
||||
|
||||
# Driver lock introduced to prevent replay thread and
|
||||
# transaction thread from closing each others
|
||||
|
@ -68,7 +69,7 @@ class CiscoNexusDriver(object):
|
|||
(cfg.CONF.rpc_workers + cfg.CONF.api_workers) >=
|
||||
const.MAX_NEXUS_SSH_SESSIONS) else False
|
||||
|
||||
def _import_ncclient(self):
|
||||
def _import_client(self):
|
||||
"""Import the NETCONF client (ncclient) module.
|
||||
|
||||
The ncclient module is not installed as part of the normal Neutron
|
||||
|
@ -79,39 +80,6 @@ class CiscoNexusDriver(object):
|
|||
"""
|
||||
return importutils.import_module('ncclient.manager')
|
||||
|
||||
def capture_and_print_timeshot(self, start_time, which,
|
||||
other=99, switch="0.0.0.0"):
|
||||
"""Determine delta, keep track, and print results."""
|
||||
|
||||
curr_timeout = time.time() - start_time
|
||||
if which in self.time_stats:
|
||||
self.time_stats[which]["total_time"] += curr_timeout
|
||||
self.time_stats[which]["total_count"] += 1
|
||||
if (curr_timeout < self.time_stats[which]["min"]):
|
||||
self.time_stats[which]["min"] = curr_timeout
|
||||
if (curr_timeout > self.time_stats[which]["max"]):
|
||||
self.time_stats[which]["max"] = curr_timeout
|
||||
else:
|
||||
self.time_stats[which] = {
|
||||
"total_time": curr_timeout,
|
||||
"total_count": 1,
|
||||
"min": curr_timeout,
|
||||
"max": curr_timeout}
|
||||
LOG.debug("NEXUS_TIME_STATS %(switch)s, pid %(pid)d, tid %(tid)d: "
|
||||
"%(which)s_timeout %(curr)f count %(count)d "
|
||||
"average %(ave)f other %(other)d min %(min)f max %(max)f",
|
||||
{'switch': switch,
|
||||
'pid': os.getpid(),
|
||||
'tid': threading.current_thread().ident,
|
||||
'which': which,
|
||||
'curr': curr_timeout,
|
||||
'count': self.time_stats[which]["total_count"],
|
||||
'ave': (self.time_stats[which]["total_time"] /
|
||||
self.time_stats[which]["total_count"]),
|
||||
'other': other,
|
||||
'min': self.time_stats[which]["min"],
|
||||
'max': self.time_stats[which]["max"]})
|
||||
|
||||
def _get_close_ssh_session(self):
|
||||
return self._close_ssh_session
|
||||
|
||||
|
@ -134,7 +102,7 @@ class CiscoNexusDriver(object):
|
|||
# session before complete.
|
||||
@lockutils.synchronized('cisco-nexus-drvrlock')
|
||||
def close_session(self, nexus_host):
|
||||
mgr = self.nxos_connect(nexus_host)
|
||||
mgr = self._nxos_connect(nexus_host)
|
||||
self._close_session(mgr, nexus_host)
|
||||
|
||||
# Driver lock introduced to prevent replay thread and
|
||||
|
@ -157,7 +125,7 @@ class CiscoNexusDriver(object):
|
|||
# try again
|
||||
# then quit
|
||||
for retry_count in (1, 2):
|
||||
mgr = self.nxos_connect(nexus_host)
|
||||
mgr = self._nxos_connect(nexus_host)
|
||||
starttime = time.time()
|
||||
try:
|
||||
data_xml = mgr.get(filter=('subtree', filter)).data_xml
|
||||
|
@ -224,7 +192,7 @@ class CiscoNexusDriver(object):
|
|||
# try again
|
||||
# then quit
|
||||
for retry_count in (1, 2):
|
||||
mgr = self.nxos_connect(nexus_host)
|
||||
mgr = self._nxos_connect(nexus_host)
|
||||
LOG.debug("NexusDriver edit config for host %s: %s",
|
||||
nexus_host, config)
|
||||
starttime = time.time()
|
||||
|
@ -259,7 +227,7 @@ class CiscoNexusDriver(object):
|
|||
if check_to_close_session and self._get_close_ssh_session():
|
||||
self._close_session(mgr, nexus_host)
|
||||
|
||||
def nxos_connect(self, nexus_host):
|
||||
def _nxos_connect(self, nexus_host):
|
||||
"""Make SSH connection to the Nexus Switch."""
|
||||
|
||||
starttime = time.time()
|
||||
|
@ -270,7 +238,7 @@ class CiscoNexusDriver(object):
|
|||
return self.connections[nexus_host]
|
||||
|
||||
if not self.ncclient:
|
||||
self.ncclient = self._import_ncclient()
|
||||
self.ncclient = self._import_client()
|
||||
nexus_ssh_port = int(self.nexus_switches[nexus_host, 'ssh_port'])
|
||||
nexus_user = self.nexus_switches[nexus_host, const.USERNAME]
|
||||
nexus_password = self.nexus_switches[nexus_host, const.PASSWORD]
|
||||
|
@ -374,7 +342,7 @@ class CiscoNexusDriver(object):
|
|||
"switchport trunk allowed vlan" in response):
|
||||
pass
|
||||
else:
|
||||
ifs.append(self.build_intf_confstr(
|
||||
ifs.append(self._build_intf_confstr(
|
||||
snipp.CMD_INT_VLAN_SNIPPET,
|
||||
intf_type, nexus_port, 'None'))
|
||||
if ifs:
|
||||
|
@ -385,22 +353,6 @@ class CiscoNexusDriver(object):
|
|||
starttime, "get_allif",
|
||||
switch=nexus_host)
|
||||
|
||||
def get_version(self, nexus_host):
|
||||
"""Given the nexus host, get the version data.
|
||||
|
||||
:param nexus_host: IP address of Nexus switch
|
||||
:returns version number
|
||||
"""
|
||||
|
||||
confstr = snipp.EXEC_GET_VERSION_SNIPPET
|
||||
response = self._get_config(nexus_host, confstr)
|
||||
LOG.debug("GET call returned version")
|
||||
version = None
|
||||
if response:
|
||||
version = re.findall(
|
||||
"\<sys_ver_str\>([\x20-\x7e]+)\<\/sys_ver_str\>", response)
|
||||
return version
|
||||
|
||||
def get_nexus_type(self, nexus_host):
|
||||
"""Given the nexus host, get the type of Nexus switch.
|
||||
|
||||
|
@ -443,9 +395,9 @@ class CiscoNexusDriver(object):
|
|||
self.capture_and_print_timeshot(
|
||||
starttime, "set_all_vlan_states",
|
||||
switch=nexus_host)
|
||||
self.send_edit_string(nexus_host, snippet)
|
||||
self.send_edit_string(nexus_host, None, snippet)
|
||||
|
||||
def get_create_vlan(self, nexus_host, vlanid, vni):
|
||||
def get_create_vlan(self, nexus_host, vlanid, vni, conf_str):
|
||||
"""Returns an XML snippet for create VLAN on a Nexus Switch."""
|
||||
LOG.debug("NexusDriver: ")
|
||||
|
||||
|
@ -460,7 +412,8 @@ class CiscoNexusDriver(object):
|
|||
starttime, "get_create_vlan",
|
||||
switch=nexus_host)
|
||||
|
||||
return snippet
|
||||
conf_str += snippet
|
||||
return conf_str
|
||||
|
||||
def create_vlan(self, nexus_host,
|
||||
vlanid, vlanname, vni):
|
||||
|
@ -472,9 +425,10 @@ class CiscoNexusDriver(object):
|
|||
LOG.debug("NexusDriver: ")
|
||||
|
||||
starttime = time.time()
|
||||
confstr = self.get_create_vlan(nexus_host, vlanid, vni)
|
||||
confstr = ''
|
||||
confstr = self.get_create_vlan(nexus_host, vlanid, vni, confstr)
|
||||
|
||||
self.send_edit_string(nexus_host, confstr,
|
||||
self.send_edit_string(nexus_host, None, confstr,
|
||||
check_to_close_session=False)
|
||||
|
||||
self.capture_and_print_timeshot(
|
||||
|
@ -492,12 +446,12 @@ class CiscoNexusDriver(object):
|
|||
starttime, "del_vlan",
|
||||
switch=nexus_host)
|
||||
|
||||
def build_intf_confstr(self, snippet, intf_type, interface, vlanid):
|
||||
def _build_intf_confstr(self, snippet, intf_type, interface, vlanid):
|
||||
"""Build the VLAN config string xml snippet to be used."""
|
||||
confstr = snippet % (intf_type, interface, vlanid, intf_type)
|
||||
return confstr
|
||||
|
||||
def get_enable_vlan_on_trunk_int(self, nexus_host, vlanid, intf_type,
|
||||
def _get_enable_vlan_on_trunk_int(self, nexus_host, vlanid, intf_type,
|
||||
interface, is_native, confstr=''):
|
||||
"""Prepares an XML snippet for VLAN on a trunk interface.
|
||||
|
||||
|
@ -519,7 +473,7 @@ class CiscoNexusDriver(object):
|
|||
snippets.append(snipp.CMD_INT_VLAN_ADD_SNIPPET)
|
||||
|
||||
for snip in snippets:
|
||||
confstr += self.build_intf_confstr(
|
||||
confstr += self._build_intf_confstr(
|
||||
snippet=snip,
|
||||
intf_type=intf_type,
|
||||
interface=interface,
|
||||
|
@ -551,7 +505,7 @@ class CiscoNexusDriver(object):
|
|||
starttime, "delif",
|
||||
switch=nexus_host)
|
||||
|
||||
def send_edit_string(self, nexus_host, confstr,
|
||||
def send_edit_string(self, nexus_host, path, confstr,
|
||||
check_to_close_session=True):
|
||||
"""Sends any XML snippet to Nexus switch."""
|
||||
|
||||
|
@ -571,10 +525,10 @@ class CiscoNexusDriver(object):
|
|||
def send_enable_vlan_on_trunk_int(self, nexus_host, vlanid, intf_type,
|
||||
interface, is_native):
|
||||
"""Gathers and sends an interface trunk XML snippet."""
|
||||
confstr = self.get_enable_vlan_on_trunk_int(
|
||||
confstr = self._get_enable_vlan_on_trunk_int(
|
||||
nexus_host, vlanid,
|
||||
intf_type, interface, is_native)
|
||||
self.send_edit_string(nexus_host, confstr)
|
||||
self.send_edit_string(nexus_host, None, confstr)
|
||||
|
||||
def create_and_trunk_vlan(self, nexus_host, vlan_id,
|
||||
vlan_name, intf_type,
|
||||
|
@ -593,23 +547,11 @@ class CiscoNexusDriver(object):
|
|||
starttime, "create_all",
|
||||
switch=nexus_host)
|
||||
|
||||
def create_vlan_svi(self, nexus_host, vlan_id, gateway_ip):
|
||||
"""Create VLAN vn_segment."""
|
||||
confstr = snipp.CMD_VLAN_SVI_SNIPPET % (vlan_id, gateway_ip)
|
||||
confstr = self.create_xml_snippet(confstr)
|
||||
LOG.debug("NexusDriver: ")
|
||||
self._edit_config(nexus_host, target='running', config=confstr)
|
||||
|
||||
def delete_vlan_svi(self, nexus_host, vlan_id):
|
||||
"""Delete VLAN vn_segment."""
|
||||
confstr = snipp.CMD_NO_VLAN_SVI_SNIPPET % vlan_id
|
||||
confstr = self.create_xml_snippet(confstr)
|
||||
LOG.debug("NexusDriver: ")
|
||||
self._edit_config(nexus_host, target='running', config=confstr)
|
||||
|
||||
def enable_vxlan_feature(self, nexus_host, nve_int_num, src_intf):
|
||||
"""Enable VXLAN on the switch."""
|
||||
|
||||
starttime = time.time()
|
||||
|
||||
# Configure the "feature" commands and NVE interface
|
||||
# (without "member" subcommand configuration).
|
||||
# The Nexus 9K will not allow the "interface nve" configuration
|
||||
|
@ -624,25 +566,47 @@ class CiscoNexusDriver(object):
|
|||
(nve_int_num, src_intf)))
|
||||
LOG.debug("NexusDriver: ")
|
||||
self._edit_config(nexus_host, config=confstr)
|
||||
self.capture_and_print_timeshot(
|
||||
starttime, "enable_vxlan",
|
||||
switch=nexus_host)
|
||||
|
||||
def disable_vxlan_feature(self, nexus_host):
|
||||
"""Disable VXLAN on the switch."""
|
||||
|
||||
starttime = time.time()
|
||||
|
||||
# Removing the "feature" commands also removes the NVE interface.
|
||||
confstr = self.create_xml_snippet(snipp.CMD_NO_FEATURE_VXLAN_SNIPPET)
|
||||
LOG.debug("NexusDriver: ")
|
||||
self._edit_config(nexus_host, config=confstr)
|
||||
|
||||
self.capture_and_print_timeshot(
|
||||
starttime, "disable_vxlan",
|
||||
switch=nexus_host)
|
||||
|
||||
def create_nve_member(self, nexus_host, nve_int_num, vni, mcast_group):
|
||||
"""Add a member configuration to the NVE interface."""
|
||||
|
||||
starttime = time.time()
|
||||
confstr = self.create_xml_snippet((snipp.CMD_INT_NVE_MEMBER_SNIPPET %
|
||||
(nve_int_num, vni, mcast_group)))
|
||||
LOG.debug("NexusDriver: ")
|
||||
self._edit_config(nexus_host, config=confstr)
|
||||
|
||||
self.capture_and_print_timeshot(
|
||||
starttime, "create_nve",
|
||||
switch=nexus_host)
|
||||
|
||||
def delete_nve_member(self, nexus_host, nve_int_num, vni):
|
||||
"""Delete a member configuration on the NVE interface."""
|
||||
|
||||
starttime = time.time()
|
||||
|
||||
confstr = self.create_xml_snippet((snipp.CMD_INT_NVE_NO_MEMBER_SNIPPET
|
||||
% (nve_int_num, vni)))
|
||||
LOG.debug("NexusDriver: ")
|
||||
self._edit_config(nexus_host, config=confstr)
|
||||
|
||||
self.capture_and_print_timeshot(
|
||||
starttime, "delete_nve",
|
||||
switch=nexus_host)
|
||||
|
|
|
@ -0,0 +1,178 @@
|
|||
# Copyright (c) 2017-2017 Cisco Systems, 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.
|
||||
|
||||
"""
|
||||
Implements REST API Client For Nexus
|
||||
"""
|
||||
|
||||
import netaddr
|
||||
import requests
|
||||
|
||||
from networking_cisco._i18n import _LE
|
||||
from networking_cisco.plugins.ml2.drivers.cisco.nexus import (
|
||||
exceptions as cexc)
|
||||
from oslo_log import log as logging
|
||||
from oslo_serialization import jsonutils
|
||||
|
||||
DEFAULT_HEADER = {"Content-type": "application/json", "Accept": "text/plain"}
|
||||
COOKIE_HEADER = """
|
||||
{"Cookie": %s, "Content-type": "application/json", "Accept": "text/plain"}"""
|
||||
DEFAULT_SCHEME = "http"
|
||||
ACCEPTED_CODES = [200, 201, 204]
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CiscoNexusRestapiClient(object):
|
||||
|
||||
def __init__(self, credentials,
|
||||
accepted_codes=ACCEPTED_CODES,
|
||||
scheme=DEFAULT_SCHEME,
|
||||
timeout=30,
|
||||
max_retries=2):
|
||||
"""Initialize the rest api client for Nexus."""
|
||||
self.format = 'json'
|
||||
self.accepted_codes = accepted_codes
|
||||
self.action_prefix = 'http://%s/'
|
||||
self.scheme = scheme
|
||||
self.status = requests.codes.OK
|
||||
self.time_stats = {}
|
||||
self.timeout = timeout
|
||||
self.max_retries = max_retries
|
||||
self.session = requests.Session()
|
||||
self.credentials = credentials
|
||||
|
||||
def _get_cookie(self, mgmt_ip, config):
|
||||
"""Performs authentication and retries cookie."""
|
||||
|
||||
if mgmt_ip not in self.credentials:
|
||||
return None
|
||||
|
||||
security_data = self.credentials[mgmt_ip]
|
||||
payload = {"aaaUser": {"attributes": {"name": security_data[0],
|
||||
"pwd": security_data[1]}}}
|
||||
headers = {"Content-type": "application/json", "Accept": "text/plain"}
|
||||
|
||||
url = "http://{0}/api/aaaLogin.json".format(mgmt_ip)
|
||||
|
||||
try:
|
||||
response = self.session.request('POST',
|
||||
url,
|
||||
data=jsonutils.dumps(payload),
|
||||
headers=headers,
|
||||
timeout=self.timeout * 2)
|
||||
except Exception as e:
|
||||
raise cexc.NexusConnectFailed(nexus_host=mgmt_ip,
|
||||
exc=e)
|
||||
|
||||
self.status = response.status_code
|
||||
if response.status_code == requests.codes.OK:
|
||||
return response.headers.get('Set-Cookie')
|
||||
else:
|
||||
e = "REST API connect returned Error code: "
|
||||
e += str(self.status)
|
||||
raise cexc.NexusConnectFailed(nexus_host=mgmt_ip,
|
||||
exc=e)
|
||||
|
||||
def send_request(self, method, action, body=None,
|
||||
headers=None, ipaddr=None):
|
||||
"""Perform the HTTP request.
|
||||
|
||||
The response is in either JSON format or plain text. A GET method will
|
||||
invoke a JSON response while a PUT/POST/DELETE returns message from the
|
||||
the server in plain text format.
|
||||
Exception is raised when server replies with an INTERNAL SERVER ERROR
|
||||
status code (500) i.e. an error has occurred on the server or SERVICE
|
||||
UNAVAILABLE (404) i.e. server is not reachable.
|
||||
|
||||
:param method: type of the HTTP request. POST, GET, PUT or DELETE
|
||||
:param action: path to which the client makes request
|
||||
:param body: dict of arguments which are sent as part of the request
|
||||
:param headers: header for the HTTP request
|
||||
:param server_ip: server_ip for the HTTP request.
|
||||
:returns: JSON or plain text in HTTP response
|
||||
"""
|
||||
|
||||
action = ''.join([self.scheme, '://%s/', action])
|
||||
if netaddr.valid_ipv6(ipaddr):
|
||||
# Enclose IPv6 address in [] in the URL
|
||||
action = action % ("[%s]" % ipaddr)
|
||||
else:
|
||||
# IPv4 address
|
||||
action = action % ipaddr
|
||||
|
||||
config = action + " : " + body if body else action
|
||||
|
||||
cookie = self._get_cookie(ipaddr, config)
|
||||
if not cookie or self.status != requests.codes.OK:
|
||||
return {}
|
||||
headers = {"Content-type": "application/json",
|
||||
"Accept": "text/plain", "Cookie": cookie}
|
||||
|
||||
for attempt in range(self.max_retries + 1):
|
||||
try:
|
||||
LOG.debug("[Nexus %(ipaddr)s attempt %(id)s]: Connecting.." %
|
||||
{"ipaddr": ipaddr, "id": attempt})
|
||||
response = self.session.request(
|
||||
method,
|
||||
action,
|
||||
data=body,
|
||||
headers=headers,
|
||||
timeout=self.timeout)
|
||||
except Exception as e:
|
||||
LOG.error(_LE(
|
||||
"Exception raised %(err)s for Rest API %(cfg)s"),
|
||||
{'err': str(e), 'cfg': config})
|
||||
raise cexc.NexusConfigFailed(nexus_host=ipaddr,
|
||||
config=config,
|
||||
exc=e)
|
||||
else:
|
||||
break
|
||||
|
||||
status_string = requests.status_codes._codes[response.status_code][0]
|
||||
if response.status_code in self.accepted_codes:
|
||||
LOG.debug(
|
||||
"Good status %(status)s(%(code)d) returned for %(url)s",
|
||||
{'status': status_string,
|
||||
'code': response.status_code,
|
||||
'url': action})
|
||||
if 'application/json' in response.headers['content-type']:
|
||||
try:
|
||||
return response.json()
|
||||
except ValueError:
|
||||
return {}
|
||||
else:
|
||||
LOG.error(_LE(
|
||||
"Bad status %(status)s(%(code)d) returned for %(url)s"),
|
||||
{'status': status_string,
|
||||
'code': response.status_code,
|
||||
'url': action})
|
||||
LOG.error(_LE("Response text: %(txt)s"),
|
||||
{'txt': response.text})
|
||||
raise cexc.NexusConfigFailed(nexus_host=ipaddr,
|
||||
config=action,
|
||||
exc=e)
|
||||
|
||||
def rest_delete(self, action, ipaddr=None, body=None, headers=None):
|
||||
return self.send_request("DELETE", action, body=body,
|
||||
headers=headers, ipaddr=ipaddr)
|
||||
|
||||
def rest_get(self, action, ipaddr, body=None, headers=None):
|
||||
return self.send_request("GET", action, body=body,
|
||||
headers=headers, ipaddr=ipaddr)
|
||||
|
||||
def rest_post(self, action, ipaddr=None, body=None, headers=None):
|
||||
return self.send_request("POST", action, body=body,
|
||||
headers=headers, ipaddr=ipaddr)
|
|
@ -0,0 +1,533 @@
|
|||
# Copyright (c) 2017-2017 Cisco Systems, 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.
|
||||
|
||||
"""
|
||||
Implements a Nexus-OS NETCONF over SSHv2 API Client
|
||||
"""
|
||||
|
||||
import re
|
||||
import time
|
||||
|
||||
from oslo_log import log as logging
|
||||
|
||||
from networking_cisco._i18n import _LW
|
||||
|
||||
from networking_cisco.plugins.ml2.drivers.cisco.nexus import (
|
||||
config as conf)
|
||||
from networking_cisco.plugins.ml2.drivers.cisco.nexus import (
|
||||
constants as const)
|
||||
from networking_cisco.plugins.ml2.drivers.cisco.nexus import (
|
||||
nexus_base_network_driver as basedrvr)
|
||||
from networking_cisco.plugins.ml2.drivers.cisco.nexus import (
|
||||
nexus_restapi_client as client)
|
||||
from networking_cisco.plugins.ml2.drivers.cisco.nexus import (
|
||||
nexus_restapi_snippets as snipp)
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CiscoNexusRestapiDriver(basedrvr.CiscoNexusBaseDriver):
|
||||
"""Nexus Driver Restapi Class."""
|
||||
def __init__(self):
|
||||
conf.ML2MechCiscoConfig()
|
||||
credentials = self._build_credentials(
|
||||
conf.ML2MechCiscoConfig.nexus_dict)
|
||||
self.client = self._import_client(credentials)
|
||||
super(CiscoNexusRestapiDriver, self).__init__()
|
||||
LOG.debug("ML2 Nexus RESTAPI Drivers initialized.")
|
||||
|
||||
def _import_client(self, credentials):
|
||||
"""Import the local RESTAPI client module.
|
||||
|
||||
This method was created to mirror original ssh driver so
|
||||
test code was in sync.
|
||||
|
||||
"""
|
||||
|
||||
return client.CiscoNexusRestapiClient(credentials)
|
||||
|
||||
def _build_credentials(self, nexus_switches):
|
||||
"""Build credential table for Rest API Client.
|
||||
|
||||
:param nexus_switches: switch config
|
||||
:returns credentials: switch credentials list
|
||||
"""
|
||||
|
||||
credential_attr = [const.USERNAME, const.PASSWORD]
|
||||
|
||||
credentials = {}
|
||||
for switch_ip, option in nexus_switches:
|
||||
if option in credential_attr:
|
||||
value = nexus_switches[switch_ip, option]
|
||||
if switch_ip in credentials:
|
||||
credential_tuple = credentials[switch_ip]
|
||||
else:
|
||||
credential_tuple = (None, None)
|
||||
if option == const.USERNAME:
|
||||
credential_tuple = (value,
|
||||
credential_tuple[1])
|
||||
else:
|
||||
credential_tuple = (
|
||||
credential_tuple[0],
|
||||
value)
|
||||
credentials[switch_ip] = credential_tuple
|
||||
return credentials
|
||||
|
||||
def get_interface_switch(self, nexus_host,
|
||||
intf_type, interface):
|
||||
"""Get the interface data from host.
|
||||
|
||||
:param nexus_host: IP address of Nexus switch
|
||||
:param intf_type: String which specifies interface type.
|
||||
example: ethernet
|
||||
:param interface: String indicating which interface.
|
||||
example: 1/19
|
||||
:returns response: Returns interface data
|
||||
"""
|
||||
|
||||
if intf_type == "ethernet":
|
||||
path_interface = "phys-[eth" + interface + "]"
|
||||
else:
|
||||
path_interface = "aggr-[po" + interface + "]"
|
||||
|
||||
action = snipp.PATH_IF % path_interface
|
||||
|
||||
starttime = time.time()
|
||||
response = self.client.rest_get(action, nexus_host)
|
||||
self.capture_and_print_timeshot(starttime, "getif",
|
||||
switch=nexus_host)
|
||||
LOG.debug("GET call returned interface %(if_type)s %(interface)s "
|
||||
"config", {'if_type': intf_type, 'interface': interface})
|
||||
return response
|
||||
|
||||
def _get_interface_switch_trunk_present(
|
||||
self, nexus_host, intf_type, interface):
|
||||
"""Check if 'switchport trunk allowed vlan' present.
|
||||
|
||||
:param nexus_host: IP address of Nexus switch
|
||||
:param intf_type: String which specifies interface type.
|
||||
example: ethernet
|
||||
:param interface: String indicating which interface.
|
||||
example: 1/19
|
||||
:returns found: True if config already present
|
||||
"""
|
||||
result = self.get_interface_switch(nexus_host, intf_type, interface)
|
||||
try:
|
||||
if_type = 'l1PhysIf' if intf_type == "ethernet" else 'pcAggrIf'
|
||||
vlan_list = result['imdata'][0][if_type]
|
||||
vlan_list = vlan_list['attributes']['trunkVlans']
|
||||
if vlan_list != "1-4094":
|
||||
found = True
|
||||
else:
|
||||
found = False
|
||||
except Exception:
|
||||
found = False
|
||||
|
||||
return found
|
||||
|
||||
def _get_port_channel_group(
|
||||
self, nexus_host, intf_type, interface):
|
||||
"""Look for 'channel-group x' config and return x.
|
||||
|
||||
:param nexus_host: IP address of Nexus switch
|
||||
:param intf_type: String which specifies interface type.
|
||||
example: ethernet
|
||||
:param interface: String indicating which interface.
|
||||
example: 1/19
|
||||
:returns pc_group: Returns port channel group if
|
||||
present else 0
|
||||
"""
|
||||
|
||||
ch_grp = 0
|
||||
|
||||
# channel-group only applied to ethernet,
|
||||
# otherwise, return 0
|
||||
if intf_type != 'ethernet':
|
||||
return ch_grp
|
||||
|
||||
match_key = "eth" + interface
|
||||
|
||||
action = snipp.PATH_GET_PC_MEMBERS
|
||||
|
||||
starttime = time.time()
|
||||
result = self.client.rest_get(action, nexus_host)
|
||||
self.capture_and_print_timeshot(starttime, "getpc",
|
||||
switch=nexus_host)
|
||||
try:
|
||||
for pcmbr in result['imdata']:
|
||||
mbr_data = pcmbr['pcRsMbrIfs']['attributes']
|
||||
if mbr_data['tSKey'] == match_key:
|
||||
_, nbr = mbr_data['parentSKey'].split("po")
|
||||
ch_grp = int(nbr)
|
||||
break
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
LOG.debug("GET interface %(key)s port channel is %(pc)",
|
||||
{'key': match_key, 'pc': ch_grp})
|
||||
|
||||
return ch_grp
|
||||
|
||||
def initialize_all_switch_interfaces(self, interfaces):
|
||||
"""Configure Nexus interface and get port channel number.
|
||||
|
||||
Receive a list of interfaces containing:
|
||||
:param nexus_host: IP address of Nexus switch
|
||||
:param intf_type: String which specifies interface type.
|
||||
example: ethernet
|
||||
:param interface: String indicating which interface.
|
||||
example: 1/19
|
||||
:returns interface: Appends port channel to each entry
|
||||
channel number is 0 if none
|
||||
"""
|
||||
if not interfaces:
|
||||
return
|
||||
|
||||
starttime = time.time()
|
||||
for i in range(len(interfaces)):
|
||||
nexus_host, intf_type, nexus_port, is_native = interfaces[i]
|
||||
ch_grp = self._get_port_channel_group(
|
||||
nexus_host, intf_type, nexus_port)
|
||||
if ch_grp is not 0:
|
||||
# if channel-group returned, init port-channel
|
||||
# instead of the provided ethernet interface
|
||||
intf_type = 'port-channel'
|
||||
nexus_port = str(ch_grp)
|
||||
interfaces[i] += (ch_grp,)
|
||||
present = self._get_interface_switch_trunk_present(
|
||||
nexus_host, intf_type, nexus_port)
|
||||
if not present:
|
||||
self.send_enable_vlan_on_trunk_int(
|
||||
nexus_host, "", intf_type, nexus_port, False)
|
||||
self.capture_and_print_timeshot(
|
||||
starttime, "get_allif",
|
||||
switch=nexus_host)
|
||||
|
||||
def get_nexus_type(self, nexus_host):
|
||||
"""Given the nexus host, get the type of Nexus switch.
|
||||
|
||||
:param nexus_host: IP address of Nexus switch
|
||||
:returns Nexus type
|
||||
"""
|
||||
|
||||
starttime = time.time()
|
||||
response = self.client.rest_get(
|
||||
snipp.PATH_GET_NEXUS_TYPE, nexus_host)
|
||||
self.capture_and_print_timeshot(
|
||||
starttime, "gettype",
|
||||
switch=nexus_host)
|
||||
|
||||
if response:
|
||||
try:
|
||||
result = response['imdata'][0]["eqptCh"]['attributes']['descr']
|
||||
except Exception:
|
||||
result = ''
|
||||
nexus_type = re.findall(
|
||||
"Nexus\s*(\d)\d+\s*[0-9A-Z]+\s*"
|
||||
"[cC]hassis",
|
||||
result)
|
||||
if len(nexus_type) > 0:
|
||||
LOG.debug("GET call returned Nexus type %d",
|
||||
int(nexus_type[0]))
|
||||
return int(nexus_type[0])
|
||||
|
||||
LOG.warning(_LW("GET call failed to return Nexus type"))
|
||||
return -1
|
||||
|
||||
def start_create_vlan(self):
|
||||
"""Returns REST API path and config start."""
|
||||
|
||||
return snipp.PATH_VLAN_ALL, snipp.BODY_VLAN_ALL_BEG
|
||||
|
||||
def end_create_vlan(self, conf_str):
|
||||
"""Returns current config + end of config."""
|
||||
|
||||
conf_str += snipp.BODY_VLAN_ALL_END
|
||||
return conf_str
|
||||
|
||||
def get_create_vlan(self, nexus_host, vlanid, vni, conf_str):
|
||||
"""Returns an XML snippet for create VLAN on a Nexus Switch."""
|
||||
|
||||
starttime = time.time()
|
||||
|
||||
if vni:
|
||||
body_snip = snipp.BODY_VXLAN_ALL_INCR % (vlanid, vni)
|
||||
else:
|
||||
body_snip = snipp.BODY_VLAN_ALL_INCR % vlanid
|
||||
conf_str += body_snip + snipp.BODY_VLAN_ALL_CONT
|
||||
|
||||
self.capture_and_print_timeshot(
|
||||
starttime, "get_create_vlan",
|
||||
switch=nexus_host)
|
||||
|
||||
return conf_str
|
||||
|
||||
def set_all_vlan_states(self, nexus_host, vlanid_range):
|
||||
"""Set the VLAN states to active."""
|
||||
|
||||
starttime = time.time()
|
||||
|
||||
if not vlanid_range:
|
||||
LOG.warning("Exiting set_all_vlan_states: No vlans to configure")
|
||||
return
|
||||
|
||||
# Eliminate possible whitespace and separate vlans by commas
|
||||
vlan_id_list = re.sub(r'\s', '', vlanid_range).split(',')
|
||||
if not vlan_id_list or not vlan_id_list[0]:
|
||||
LOG.warning("Exiting set_all_vlan_states: No vlans to configure")
|
||||
return
|
||||
|
||||
path_str, body_vlan_all = self.start_create_vlan()
|
||||
while vlan_id_list:
|
||||
rangev = vlan_id_list.pop(0)
|
||||
if '-' in rangev:
|
||||
fr, to = rangev.split('-')
|
||||
max = int(to) + 1
|
||||
for vlan_id in range(int(fr), max):
|
||||
body_vlan_all = self.get_create_vlan(
|
||||
nexus_host, vlan_id, 0, body_vlan_all)
|
||||
else:
|
||||
body_vlan_all = self.get_create_vlan(
|
||||
nexus_host, rangev, 0, body_vlan_all)
|
||||
|
||||
body_vlan_all = self.end_create_vlan(body_vlan_all)
|
||||
self.send_edit_string(
|
||||
nexus_host, path_str, body_vlan_all)
|
||||
|
||||
self.capture_and_print_timeshot(
|
||||
starttime, "set_all_vlan_states",
|
||||
switch=nexus_host)
|
||||
|
||||
def create_vlan(self, nexus_host,
|
||||
vlanid, vlanname, vni):
|
||||
"""Given switch, vlanid, vni, Create a VLAN on Switch."""
|
||||
|
||||
starttime = time.time()
|
||||
path_snip, body_snip = self.start_create_vlan()
|
||||
body_snip = self.get_create_vlan(nexus_host, vlanid, vni, body_snip)
|
||||
body_snip = self.end_create_vlan(body_snip)
|
||||
|
||||
self.send_edit_string(nexus_host, path_snip, body_snip)
|
||||
|
||||
self.capture_and_print_timeshot(
|
||||
starttime, "create_vlan_seg",
|
||||
switch=nexus_host)
|
||||
|
||||
def delete_vlan(self, nexus_host, vlanid):
|
||||
"""Delete a VLAN on Nexus Switch given the VLAN ID."""
|
||||
starttime = time.time()
|
||||
|
||||
path_snip = snipp.PATH_VLAN % vlanid
|
||||
self.client.rest_delete(path_snip, nexus_host)
|
||||
|
||||
self.capture_and_print_timeshot(
|
||||
starttime, "del_vlan",
|
||||
switch=nexus_host)
|
||||
|
||||
def _get_vlan_body_on_trunk_int(self, nexus_host, vlanid, intf_type,
|
||||
interface, is_native, is_delete):
|
||||
"""Prepares an XML snippet for VLAN on a trunk interface.
|
||||
|
||||
:param nexus_host: IP address of Nexus switch
|
||||
:param vlanid: Vlanid(s) to add to interface
|
||||
:param intf_type: String which specifies interface type.
|
||||
example: ethernet
|
||||
:param interface: String indicating which interface.
|
||||
example: 1/19
|
||||
:param is_native: Is native vlan config desired?
|
||||
:param is_delete: Is this a delete operation?
|
||||
:returns path_snippet, body_snippet
|
||||
"""
|
||||
|
||||
starttime = time.time()
|
||||
|
||||
LOG.debug("NexusDriver get if body config for host %s: "
|
||||
"if_type %s port %s",
|
||||
nexus_host, intf_type, interface)
|
||||
if intf_type == "ethernet":
|
||||
body_if_type = "l1PhysIf"
|
||||
path_interface = "phys-[eth" + interface + "]"
|
||||
else:
|
||||
body_if_type = "pcAggrIf"
|
||||
path_interface = "aggr-[po" + interface + "]"
|
||||
|
||||
path_snip = (snipp.PATH_IF % (path_interface))
|
||||
|
||||
if is_delete:
|
||||
increment_it = "-"
|
||||
debug_desc = "delif"
|
||||
native_vlan = ""
|
||||
else:
|
||||
native_vlan = 'vlan-' + str(vlanid)
|
||||
debug_desc = "createif"
|
||||
if vlanid is "":
|
||||
increment_it = ""
|
||||
else:
|
||||
increment_it = "+"
|
||||
|
||||
if is_native:
|
||||
body_snip = (snipp.BODY_NATIVE_TRUNKVLAN %
|
||||
(body_if_type, increment_it + str(vlanid),
|
||||
str(native_vlan)))
|
||||
else:
|
||||
body_snip = (snipp.BODY_TRUNKVLAN %
|
||||
(body_if_type, increment_it + str(vlanid)))
|
||||
|
||||
self.capture_and_print_timeshot(
|
||||
starttime, debug_desc,
|
||||
switch=nexus_host)
|
||||
|
||||
return path_snip, body_snip
|
||||
|
||||
def disable_vlan_on_trunk_int(self, nexus_host, vlanid, intf_type,
|
||||
interface, is_native):
|
||||
"""Disable a VLAN on a trunk interface."""
|
||||
|
||||
starttime = time.time()
|
||||
|
||||
path_snip, body_snip = self._get_vlan_body_on_trunk_int(
|
||||
nexus_host, vlanid, intf_type, interface,
|
||||
is_native, True)
|
||||
self.send_edit_string(nexus_host, path_snip, body_snip)
|
||||
self.capture_and_print_timeshot(
|
||||
starttime, "delif",
|
||||
switch=nexus_host)
|
||||
|
||||
def send_edit_string(self, nexus_host, path_snip, body_snip,
|
||||
check_to_close_session=True):
|
||||
"""Sends rest Post request to Nexus switch."""
|
||||
|
||||
starttime = time.time()
|
||||
LOG.debug("NexusDriver edit config for host %s: path: %s body: %s",
|
||||
nexus_host, path_snip, body_snip)
|
||||
self.client.rest_post(path_snip, nexus_host, body_snip)
|
||||
self.capture_and_print_timeshot(
|
||||
starttime, "send_edit",
|
||||
switch=nexus_host)
|
||||
|
||||
def send_enable_vlan_on_trunk_int(self, nexus_host, vlanid, intf_type,
|
||||
interface, is_native):
|
||||
"""Gathers and sends an interface trunk XML snippet."""
|
||||
|
||||
path_snip, body_snip = self._get_vlan_body_on_trunk_int(
|
||||
nexus_host, vlanid, intf_type, interface,
|
||||
is_native, False)
|
||||
self.send_edit_string(nexus_host, path_snip, body_snip)
|
||||
|
||||
def create_and_trunk_vlan(self, nexus_host, vlan_id,
|
||||
vlan_name, intf_type,
|
||||
nexus_port, vni,
|
||||
is_native):
|
||||
"""Create VLAN and trunk it on the specified ports."""
|
||||
|
||||
starttime = time.time()
|
||||
|
||||
self.create_vlan(nexus_host, vlan_id, vlan_name, vni)
|
||||
LOG.debug("NexusDriver created VLAN: %s", vlan_id)
|
||||
|
||||
if nexus_port:
|
||||
self.send_enable_vlan_on_trunk_int(
|
||||
nexus_host, vlan_id,
|
||||
intf_type, nexus_port,
|
||||
is_native)
|
||||
|
||||
self.capture_and_print_timeshot(
|
||||
starttime, "create_all",
|
||||
switch=nexus_host)
|
||||
|
||||
def enable_vxlan_feature(self, nexus_host, nve_int_num, src_intf):
|
||||
"""Enable VXLAN on the switch."""
|
||||
|
||||
# Configure the "feature" commands and NVE interface
|
||||
# (without "member" subcommand configuration).
|
||||
# The Nexus 9K will not allow the "interface nve" configuration
|
||||
# until the "feature nv overlay" command is issued and installed.
|
||||
# To get around the N9K failing on the "interface nve" command
|
||||
# send the two XML snippets down separately.
|
||||
|
||||
starttime = time.time()
|
||||
|
||||
## Do CLI 'feature nv overlay'
|
||||
self.send_edit_string(nexus_host, snipp.PATH_VXLAN_STATE,
|
||||
(snipp.BODY_VXLAN_STATE % "enabled"))
|
||||
|
||||
# Do CLI 'feature vn-segment-vlan-based'
|
||||
self.send_edit_string(nexus_host, snipp.PATH_VNSEG_STATE,
|
||||
(snipp.BODY_VNSEG_STATE % "enabled"))
|
||||
|
||||
# Do CLI 'int nve1' to Create nve1
|
||||
self.send_edit_string(
|
||||
nexus_host,
|
||||
(snipp.PATH_NVE_CREATE % nve_int_num),
|
||||
(snipp.BODY_NVE_CREATE % nve_int_num))
|
||||
|
||||
# Do CLI 'no shut
|
||||
# source-interface loopback %s'
|
||||
# beneath int nve1
|
||||
self.send_edit_string(
|
||||
nexus_host,
|
||||
(snipp.PATH_NVE_CREATE % nve_int_num),
|
||||
(snipp.BODY_NVE_ADD_LOOPBACK % ("enabled", src_intf)))
|
||||
self.capture_and_print_timeshot(
|
||||
starttime, "enable_vxlan",
|
||||
switch=nexus_host)
|
||||
|
||||
def disable_vxlan_feature(self, nexus_host):
|
||||
"""Disable VXLAN on the switch."""
|
||||
|
||||
# Removing the "feature nv overlay" configuration also
|
||||
# removes the "interface nve" configuration.
|
||||
|
||||
starttime = time.time()
|
||||
|
||||
# Do CLI 'no feature nv overlay'
|
||||
self.send_edit_string(nexus_host, snipp.PATH_VXLAN_STATE,
|
||||
(snipp.BODY_VXLAN_STATE % "disabled"))
|
||||
|
||||
# Do CLI 'no feature vn-segment-vlan-based'
|
||||
self.send_edit_string(nexus_host, snipp.PATH_VNSEG_STATE,
|
||||
(snipp.BODY_VNSEG_STATE % "disabled"))
|
||||
|
||||
self.capture_and_print_timeshot(
|
||||
starttime, "disable_vxlan",
|
||||
switch=nexus_host)
|
||||
|
||||
def create_nve_member(self, nexus_host, nve_int_num, vni, mcast_group):
|
||||
"""Add a member configuration to the NVE interface."""
|
||||
|
||||
# Do CLI [no] member vni %s mcast-group %s
|
||||
# beneath int nve1
|
||||
|
||||
starttime = time.time()
|
||||
|
||||
path = snipp.PATH_VNI_UPDATE % (nve_int_num, vni)
|
||||
body = snipp.BODY_VNI_UPDATE % (vni, vni, vni, mcast_group)
|
||||
self.send_edit_string(nexus_host, path, body)
|
||||
|
||||
self.capture_and_print_timeshot(
|
||||
starttime, "create_nve",
|
||||
switch=nexus_host)
|
||||
|
||||
def delete_nve_member(self, nexus_host, nve_int_num, vni):
|
||||
"""Delete a member configuration on the NVE interface."""
|
||||
|
||||
starttime = time.time()
|
||||
|
||||
path_snip = snipp.PATH_VNI_UPDATE % (nve_int_num, vni)
|
||||
self.client.rest_delete(path_snip, nexus_host)
|
||||
|
||||
self.capture_and_print_timeshot(
|
||||
starttime, "delete_nve",
|
||||
switch=nexus_host)
|
|
@ -0,0 +1,110 @@
|
|||
# Copyright (c) 2017-2017 Cisco Systems, 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.
|
||||
|
||||
# This section is organized by N9K CLI commands
|
||||
|
||||
# show inventory
|
||||
PATH_GET_NEXUS_TYPE = 'api/mo/sys/ch.json'
|
||||
|
||||
# conf t
|
||||
# vlan <a,n-y>
|
||||
# state active
|
||||
PATH_VLAN_ALL = 'api/mo.json'
|
||||
BODY_VLAN_ALL_BEG = '{"topSystem": { "children": [ {"bdEntity":'
|
||||
BODY_VLAN_ALL_BEG += ' { children": ['
|
||||
BODY_VLAN_ALL_INCR = ' {"l2BD": {"attributes": {"fabEncap": "vlan-%s",'
|
||||
BODY_VLAN_ALL_INCR += ' "pcTag": "1", "adminSt": "active"}}}'
|
||||
BODY_VXLAN_ALL_INCR = ' {"l2BD": {"attributes": {"fabEncap": "vlan-%s",'
|
||||
BODY_VXLAN_ALL_INCR += ' "pcTag": "1", "adminSt": "active",'
|
||||
BODY_VXLAN_ALL_INCR += ' "accEncap": "vxlan-%s"}}}'
|
||||
BODY_VLAN_ALL_CONT = ','
|
||||
BODY_VLAN_ALL_END = ' ]}}]}}'
|
||||
|
||||
# The following was added to make simple Test case results more readible.
|
||||
BODY_VLAN_ADD_START = (BODY_VLAN_ALL_BEG + BODY_VLAN_ALL_INCR +
|
||||
BODY_VLAN_ALL_CONT)
|
||||
|
||||
BODY_VLAN_ADD_NEXT = BODY_VLAN_ALL_INCR + BODY_VLAN_ALL_CONT
|
||||
|
||||
BODY_VLAN_ADD = (BODY_VLAN_ALL_BEG + BODY_VLAN_ALL_INCR +
|
||||
BODY_VLAN_ALL_CONT + BODY_VLAN_ALL_END)
|
||||
|
||||
BODY_VXLAN_ADD = (BODY_VLAN_ALL_BEG + BODY_VXLAN_ALL_INCR +
|
||||
BODY_VLAN_ALL_CONT + BODY_VLAN_ALL_END)
|
||||
|
||||
# conf t
|
||||
# vlan <n>
|
||||
# state active
|
||||
PATH_VLAN = 'api/mo/sys/bd/bd-[vlan-%s].json'
|
||||
BODY_VLAN_ACTIVE = '{"l2BD": {"attributes": {"adminSt": "active"}}}'
|
||||
|
||||
# conf t
|
||||
# vlan <n>
|
||||
# state active
|
||||
# vn-segment <vni>
|
||||
BODY_VXLAN_ACTIVE = '{"l2BD": {"attributes": {"adminSt": "active",'
|
||||
BODY_VXLAN_ACTIVE += ' "accEncap": "vxlan-%s"}}}'
|
||||
|
||||
# conf t
|
||||
# int ethernet x/x OR int port-channel n
|
||||
# where %s is "phys-[eth1/19]" OR "aggr-[po50]"
|
||||
PATH_IF = 'api/mo/sys/intf/%s.json'
|
||||
# THEN
|
||||
# switchport trunk native vlan <vlan>
|
||||
# switchport trunk allowed vlan none | add <vlan> | remove <vlan>
|
||||
# first %s is "l1PhysIf" | "pcAggrIf", 2nd trunkvlan string, 3rd one
|
||||
# native vlan
|
||||
BODY_TRUNKVLAN = '{"%s": {"attributes": {"trunkVlans": "%s"}}}'
|
||||
BODY_NATIVE_TRUNKVLAN = '{"%s": {"attributes": {"trunkVlans": "%s",'
|
||||
BODY_NATIVE_TRUNKVLAN += ' "nativeVlan": "%s"}}}'
|
||||
|
||||
# conf t
|
||||
# feature nv overlay
|
||||
PATH_VXLAN_STATE = 'api/mo/sys/fm/nvo.json'
|
||||
# where %s is "enable" | "disable"
|
||||
BODY_VXLAN_STATE = '{"fmNvo": {"attributes": {"adminSt": "%s"}}}'
|
||||
|
||||
# conf t
|
||||
# feature vn-segment-vlan-based
|
||||
PATH_VNSEG_STATE = 'api/mo/sys/fm/vnsegment.json'
|
||||
BODY_VNSEG_STATE = '{"fmVnSegment": {"attributes": {"adminSt": "%s"}}}'
|
||||
|
||||
# conf t
|
||||
# int nve%s
|
||||
# no shut
|
||||
# source-interface loopback %s
|
||||
PATH_NVE_CREATE = 'api/mo/sys/epId-%s.json'
|
||||
BODY_NVE_CREATE = '{"nvoEp": {"attributes": {"epId": "%s"}}}'
|
||||
BODY_NVE_ADD_LOOPBACK = '{"nvoEp": {"attributes": {"adminSt": "%s",'
|
||||
BODY_NVE_ADD_LOOPBACK += ' "sourceInterface": "lo%s"}}}'
|
||||
|
||||
# conf t
|
||||
# int nve%s
|
||||
# no shut
|
||||
# source-interface loopback %s
|
||||
|
||||
# conf t
|
||||
# int nve%s
|
||||
# [no] member vni %s mcast-group %s
|
||||
PATH_VNI_UPDATE = 'api/mo/sys/epId-%s/nws/vni-%s.json'
|
||||
BODY_VNI_UPDATE = '{"nvoNw": {"attributes": {"vni": "%s", "vniRangeMin": "%s",'
|
||||
BODY_VNI_UPDATE += ' "vniRangeMax": "%s", "mcastGroup": "%s", "isMcastRange":'
|
||||
BODY_VNI_UPDATE += ' "yes", "suppressARP": "no", "associateVrfFlag": "no"}}}'
|
||||
|
||||
# channel-group x mode active is not immediately available beneath the
|
||||
# ethernet interface data. Instead one needs to gather pc channel members
|
||||
# and search for ethernet interface.
|
||||
PATH_GET_PC_MEMBERS = 'api/mo/sys/intf.json?query-target=subtree&'
|
||||
PATH_GET_PC_MEMBERS += 'target-subtree-class=pcRsMbrIfs'
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright (c) 2013-2016 Cisco Systems, Inc.
|
||||
# Copyright (c) 2013-2017 Cisco Systems, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
|
@ -33,10 +33,6 @@ EXEC_GET_INTF_SNIPPET = """
|
|||
<cmd>show running-config interface %s %s</cmd>
|
||||
"""
|
||||
|
||||
EXEC_GET_VERSION_SNIPPET = """
|
||||
<cmd>show version</cmd>
|
||||
"""
|
||||
|
||||
EXEC_GET_INVENTORY_SNIPPET = """
|
||||
<cmd>show inventory</cmd>
|
||||
"""
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright (c) 2015-2016 Cisco Systems, Inc.
|
||||
# Copyright (c) 2015-2017 Cisco Systems, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
|
@ -15,13 +15,20 @@
|
|||
|
||||
"""
|
||||
Basic test Class and elements for testing Cisco Nexus platforms.
|
||||
|
||||
Most classes in this file do not contain test cases but instead
|
||||
provide common methods for other classes to utilize. This class
|
||||
provides the basic methods needed to drive a create or delete
|
||||
port request thru to the ssh or restapi driver. It verifies the
|
||||
final content of the data base and verifies what data the
|
||||
Drivers sent out. There also exists another 'base' class
|
||||
specifically for Replay testing.
|
||||
"""
|
||||
|
||||
import collections
|
||||
import mock
|
||||
import os
|
||||
from oslo_config import cfg
|
||||
from oslo_utils import importutils
|
||||
import re
|
||||
import six
|
||||
import testtools
|
||||
|
@ -31,6 +38,10 @@ from networking_cisco.plugins.ml2.drivers.cisco.nexus import (
|
|||
constants as const)
|
||||
from networking_cisco.plugins.ml2.drivers.cisco.nexus import (
|
||||
nexus_network_driver)
|
||||
from networking_cisco.plugins.ml2.drivers.cisco.nexus import (
|
||||
nexus_restapi_network_driver)
|
||||
from networking_cisco.plugins.ml2.drivers.cisco.nexus import (
|
||||
nexus_restapi_snippets as rest_snipp)
|
||||
from networking_cisco.plugins.ml2.drivers.cisco.nexus import constants
|
||||
from networking_cisco.plugins.ml2.drivers.cisco.nexus import exceptions
|
||||
from networking_cisco.plugins.ml2.drivers.cisco.nexus import mech_cisco_nexus
|
||||
|
@ -106,6 +117,55 @@ BAREMETAL_VNIC = u'baremetal'
|
|||
|
||||
CONNECT_ERROR = 'Unable to connect to Nexus'
|
||||
|
||||
GET_NEXUS_TYPE_RESPONSE = {
|
||||
"totalCount": "1",
|
||||
"imdata": [
|
||||
{
|
||||
"eqptCh": {
|
||||
"attributes": {
|
||||
"descr": "Nexus9000 C9396PX Chassis",
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
GET_INTERFACE_RESPONSE = {
|
||||
"totalCount": "1",
|
||||
"imdata": [
|
||||
{
|
||||
"l1PhysIf": {
|
||||
"attributes": {
|
||||
"trunkVlans": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
GET_INTERFACE_PCHAN_RESPONSE = {
|
||||
"totalCount": "1",
|
||||
"imdata": [
|
||||
{
|
||||
"pcAggrIf": {
|
||||
"attributes": {
|
||||
"trunkVlans": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
GET_NO_PORT_CH_RESPONSE = {
|
||||
"totalCount": "3",
|
||||
"imdata": [
|
||||
]
|
||||
}
|
||||
|
||||
POST = 0
|
||||
DELETE = 1
|
||||
|
||||
## Test snippets used to verify nexus command output
|
||||
RESULT_ADD_VLAN = """configure\>\s+\<vlan\>\s+\
|
||||
<vlan-id-create-delete\>\s+\<__XML__PARAM_value\>{0}"""
|
||||
|
@ -147,9 +207,6 @@ RESULT_DEL_NATIVE_INTERFACE = """\
|
|||
RESULT_DEL_NVE_INTERFACE = """\<interface\>\s+\
|
||||
\<nve\>nve{0}\<\/nve\>\s+[\x20-\x7e]+\s+\<member\>no member vni {1}"""
|
||||
|
||||
NEXUS_DRIVER = ('networking_cisco.plugins.ml2.drivers.cisco.nexus.'
|
||||
'nexus_network_driver.CiscoNexusDriver')
|
||||
|
||||
|
||||
class FakeNetworkContext(object):
|
||||
"""Network context for testing purposes only."""
|
||||
|
@ -291,6 +348,19 @@ class FakeUnbindPortContext(FakePortContext):
|
|||
return self._bottom_segment
|
||||
|
||||
|
||||
class TestCiscoNexusBaseResults(object):
|
||||
|
||||
"""Unit tests driver results for Cisco ML2 Nexus."""
|
||||
|
||||
test_results = {}
|
||||
|
||||
def get_test_results(self, name):
|
||||
if name in self.test_results:
|
||||
return self.test_results[name]
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
class TestCiscoNexusBase(testlib_api.SqlTestCase):
|
||||
"""Feature Base Test Class for Cisco ML2 Nexus driver."""
|
||||
|
||||
|
@ -299,19 +369,45 @@ class TestCiscoNexusBase(testlib_api.SqlTestCase):
|
|||
'nexus_ip_addr host_name nexus_port instance_id vlan_id vxlan_id '
|
||||
'mcast_group device_owner profile vnic_type')
|
||||
|
||||
def _mock_init(self):
|
||||
# this is to prevent interface initialization from occurring
|
||||
# which adds unnecessary noise to the results.
|
||||
def mock_init(self):
|
||||
|
||||
# This initializes interface responses to prevent
|
||||
# unnecessary noise to the results.
|
||||
|
||||
data_xml = {'connect.return_value.get.return_value.data_xml':
|
||||
'switchport trunk allowed vlan none'}
|
||||
self.mock_ncclient.configure_mock(**data_xml)
|
||||
|
||||
def restapi_mock_init(self):
|
||||
|
||||
# This initializes RESTAPI responses to prevent
|
||||
# unnecessary noise to the results.
|
||||
|
||||
data_json = {'rest_get.side_effect':
|
||||
self.get_side_effect}
|
||||
self.mock_ncclient.configure_mock(**data_json)
|
||||
|
||||
def get_side_effect(self, action, ipaddr=None, body=None, headers=None):
|
||||
|
||||
eth_path = 'api/mo/sys/intf/phys-'
|
||||
port_chan_path = 'api/mo/sys/intf/aggr-'
|
||||
|
||||
if action == rest_snipp.PATH_GET_NEXUS_TYPE:
|
||||
return GET_NEXUS_TYPE_RESPONSE
|
||||
elif action in rest_snipp.PATH_GET_PC_MEMBERS:
|
||||
return GET_NO_PORT_CH_RESPONSE
|
||||
elif eth_path in action:
|
||||
return GET_INTERFACE_RESPONSE
|
||||
elif port_chan_path in action:
|
||||
return GET_INTERFACE_PCHAN_RESPONSE
|
||||
|
||||
return {}
|
||||
|
||||
def _clear_port_dbs(self):
|
||||
nexus_db_v2.remove_all_nexusport_bindings()
|
||||
|
||||
def setUp(self):
|
||||
"""Sets up mock ncclient, and switch and credentials dictionaries."""
|
||||
"""Sets up mock client, switch, and credentials dictionaries."""
|
||||
|
||||
super(TestCiscoNexusBase, self).setUp()
|
||||
|
||||
|
@ -320,20 +416,32 @@ class TestCiscoNexusBase(testlib_api.SqlTestCase):
|
|||
cfg.CONF.import_opt('rpc_workers', 'neutron.service')
|
||||
cfg.CONF.set_default('rpc_workers', 0)
|
||||
|
||||
# Use a mock netconf client
|
||||
# Use a mock netconf or REST API client
|
||||
self.mock_ncclient = mock.Mock()
|
||||
mock.patch.object(nexus_network_driver.CiscoNexusDriver,
|
||||
'_import_ncclient',
|
||||
return_value=self.mock_ncclient).start()
|
||||
if cfg.CONF.ml2_cisco.nexus_driver == 'restapi':
|
||||
mock.patch.object(
|
||||
nexus_restapi_network_driver.CiscoNexusRestapiDriver,
|
||||
'_import_client',
|
||||
return_value=self.mock_ncclient).start()
|
||||
self._verify_results = self._verify_restapi_results
|
||||
else:
|
||||
mock.patch.object(
|
||||
nexus_network_driver.CiscoNexusSshDriver,
|
||||
'_import_client',
|
||||
return_value=self.mock_ncclient).start()
|
||||
self._verify_results = self._verify_ssh_results
|
||||
|
||||
self.mock_continue_binding = mock.patch.object(
|
||||
FakePortContext,
|
||||
'continue_binding').start()
|
||||
|
||||
self._mock_init()
|
||||
if cfg.CONF.ml2_cisco.nexus_driver == 'restapi':
|
||||
self.restapi_mock_init()
|
||||
else:
|
||||
self.mock_init()
|
||||
|
||||
def new_nexus_init(mech_instance):
|
||||
mech_instance.driver = importutils.import_object(NEXUS_DRIVER)
|
||||
mech_instance.driver = mech_instance._load_nexus_cfg_driver()
|
||||
mech_instance.monitor_timeout = (
|
||||
cfg.CONF.ml2_cisco.switch_heartbeat_time)
|
||||
mech_instance._ppid = os.getpid()
|
||||
|
@ -471,6 +579,57 @@ class TestCiscoNexusBase(testlib_api.SqlTestCase):
|
|||
port_config.instance_id)
|
||||
self.assertEqual(1, len(bindings))
|
||||
|
||||
def _verify_restapi_results(self, driver_result):
|
||||
"""Verifies correct entries sent to Nexus."""
|
||||
|
||||
posts = 0
|
||||
deletes = 0
|
||||
for idx in range(0, len(driver_result)):
|
||||
if driver_result[idx][3] == POST:
|
||||
posts += 1
|
||||
else:
|
||||
deletes += 1
|
||||
self.assertEqual(
|
||||
posts,
|
||||
len(self.mock_ncclient.rest_post.mock_calls),
|
||||
"Unexpected driver post calls")
|
||||
self.assertEqual(
|
||||
deletes,
|
||||
len(self.mock_ncclient.rest_delete.mock_calls),
|
||||
"Unexpected driver delete calls")
|
||||
|
||||
post_calls = self.mock_ncclient.rest_post.mock_calls
|
||||
del_calls = self.mock_ncclient.rest_delete.mock_calls
|
||||
posts = 0
|
||||
deletes = 0
|
||||
for idx in range(0, len(driver_result)):
|
||||
# assigned None to skip testing this one.
|
||||
if not driver_result[idx]:
|
||||
continue
|
||||
if driver_result[idx][3] == POST:
|
||||
test_it = post_calls[posts][1]
|
||||
else:
|
||||
test_it = del_calls[deletes][1]
|
||||
self.assertTrue(
|
||||
(driver_result[idx][0] ==
|
||||
test_it[0]),
|
||||
"Expected Rest URI does not match")
|
||||
|
||||
if driver_result[idx][1] is not None:
|
||||
self.assertTrue(
|
||||
(driver_result[idx][1] ==
|
||||
test_it[1]),
|
||||
"Expected Nexus Switch ip does not match")
|
||||
|
||||
if driver_result[idx][3] == POST:
|
||||
self.assertTrue(
|
||||
(driver_result[idx][2] ==
|
||||
test_it[2]),
|
||||
"Expected Rest Body does not match")
|
||||
posts += 1
|
||||
else:
|
||||
deletes += 1
|
||||
|
||||
def _delete_port(self, port_config):
|
||||
"""Tests deletion of a virtual port."""
|
||||
port_context = self._generate_port_context(port_config)
|
||||
|
@ -498,7 +657,7 @@ class TestCiscoNexusBase(testlib_api.SqlTestCase):
|
|||
port_config.nexus_ip_addr,
|
||||
port_config.instance_id)
|
||||
|
||||
def _verify_results(self, driver_result):
|
||||
def _verify_ssh_results(self, driver_result):
|
||||
"""Verifies correct entries sent to Nexus."""
|
||||
|
||||
self.assertEqual(
|
||||
|
|
|
@ -34,7 +34,7 @@ CONNECT_ERROR = 'Unable to connect to Nexus'
|
|||
|
||||
class TestCiscoNexusDeviceConfig(object):
|
||||
|
||||
"""Unit tests for Cisco ML2 Nexus device driver."""
|
||||
"""Unit tests Config for Cisco ML2 Nexus device driver."""
|
||||
|
||||
test_configs = {
|
||||
'test_config1':
|
||||
|
@ -185,20 +185,105 @@ class TestCiscoNexusDeviceConfig(object):
|
|||
|
||||
test_configs = collections.OrderedDict(sorted(test_configs.items()))
|
||||
|
||||
# The following contains desired Nexus output for some basic config above.
|
||||
duplicate_add_port_driver_result = (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN.format(267),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/10', 267)])
|
||||
|
||||
duplicate_delete_port_driver_result = (
|
||||
[test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/10', 267),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(267)])
|
||||
class TestCiscoNexusDeviceResults(
|
||||
test_cisco_nexus_base.TestCiscoNexusBaseResults):
|
||||
|
||||
"""Unit tests driver results for Cisco ML2 Nexus."""
|
||||
|
||||
test_results = {
|
||||
|
||||
'duplicate_add_port_driver_result': (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN.format(267),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/10', 267)]),
|
||||
|
||||
'duplicate_del_port_driver_result': (
|
||||
[test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/10', 267),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(267)]),
|
||||
|
||||
'add_port2_driver_result': (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN.format(265),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/20', 265)]),
|
||||
|
||||
'delete_port2_driver_result': (
|
||||
[test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/20', 265),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(265)]),
|
||||
|
||||
'add_port2_driver_result2': (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN.format(267),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/20', 267)]),
|
||||
|
||||
'delete_port2_driver_result2': (
|
||||
[test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/20', 267)]),
|
||||
|
||||
'add_port2_driver_result3': (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN.format(268),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('portchannel', '2', 268),
|
||||
test_cisco_nexus_base.RESULT_ADD_VLAN.format(268),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('portchannel', '2', 268)]),
|
||||
|
||||
'delete_port2_driver_result3': (
|
||||
[test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('portchannel', '2', 268),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(268),
|
||||
test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('portchannel', '2', 268),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(268)]),
|
||||
|
||||
'add_port_channel_driver_result': (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN.format(268),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('portchannel', '2', 268)]),
|
||||
|
||||
'delete_port_channel_driver_result': (
|
||||
[test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('portchannel', '2', 268),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(268)]),
|
||||
|
||||
'dual_add_port_driver_result': (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN.format(269),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/3', 269),
|
||||
test_cisco_nexus_base.RESULT_ADD_VLAN.format(269),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('portchannel', '2', 269)]),
|
||||
|
||||
'dual_delete_port_driver_result': (
|
||||
[test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/3', 269),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(269),
|
||||
test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('portchannel', '2', 269)]),
|
||||
|
||||
'migrate_add_host2_driver_result': (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN.format(267),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/20', 267)]),
|
||||
|
||||
'add_port_driver_result': (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN.format(267),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/10', 267)]),
|
||||
|
||||
'del_port_driver_result': (
|
||||
[test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/10', 267),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(267)]),
|
||||
|
||||
}
|
||||
|
||||
|
||||
class TestCiscoNexusDevice(test_cisco_nexus_base.TestCiscoNexusBase,
|
||||
TestCiscoNexusDeviceConfig):
|
||||
TestCiscoNexusDeviceConfig,
|
||||
TestCiscoNexusDeviceResults):
|
||||
|
||||
"""Unit tests for Cisco ML2 Nexus device driver."""
|
||||
|
||||
|
@ -208,13 +293,15 @@ class TestCiscoNexusDevice(test_cisco_nexus_base.TestCiscoNexusBase,
|
|||
cfg.CONF.set_override('never_cache_ssh_connection', False, 'ml2_cisco')
|
||||
super(TestCiscoNexusDevice, self).setUp()
|
||||
self.mock_ncclient.reset_mock()
|
||||
self.results = TestCiscoNexusDeviceResults()
|
||||
|
||||
def test_create_delete_duplicate_ports(self):
|
||||
"""Tests creation and deletion of two new virtual Ports."""
|
||||
|
||||
self._basic_create_verify_port_vlan(
|
||||
'test_config1',
|
||||
self.duplicate_add_port_driver_result)
|
||||
self.results.get_test_results('duplicate_add_port_driver_result')
|
||||
)
|
||||
|
||||
self._create_port(
|
||||
self.test_configs['test_config3'])
|
||||
|
@ -245,14 +332,15 @@ class TestCiscoNexusDevice(test_cisco_nexus_base.TestCiscoNexusBase,
|
|||
|
||||
self._basic_delete_verify_port_vlan(
|
||||
'test_config3',
|
||||
self.duplicate_delete_port_driver_result)
|
||||
self.results.get_test_results('duplicate_del_port_driver_result'))
|
||||
|
||||
def test_create_delete_duplicate_port_transaction(self):
|
||||
"""Tests creation and deletion same port transaction."""
|
||||
|
||||
self._basic_create_verify_port_vlan(
|
||||
'test_config1',
|
||||
self.duplicate_add_port_driver_result)
|
||||
self.results.get_test_results('duplicate_add_port_driver_result')
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
1, len(nexus_db_v2.get_nexusport_switch_bindings(
|
||||
|
@ -260,7 +348,9 @@ class TestCiscoNexusDevice(test_cisco_nexus_base.TestCiscoNexusBase,
|
|||
|
||||
self._create_port(
|
||||
self.test_configs['test_config1'])
|
||||
self._verify_results(self.duplicate_add_port_driver_result)
|
||||
self._verify_results(
|
||||
self.results.get_test_results('duplicate_add_port_driver_result')
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
1, len(nexus_db_v2.get_nexusport_switch_bindings(
|
||||
|
@ -272,32 +362,24 @@ class TestCiscoNexusDevice(test_cisco_nexus_base.TestCiscoNexusBase,
|
|||
|
||||
self._basic_delete_verify_port_vlan(
|
||||
'test_config1',
|
||||
self.duplicate_delete_port_driver_result,
|
||||
self.results.get_test_results('duplicate_del_port_driver_result'),
|
||||
nbr_of_bindings=0)
|
||||
|
||||
self._basic_delete_verify_port_vlan(
|
||||
'test_config1',
|
||||
self.duplicate_delete_port_driver_result)
|
||||
self.results.get_test_results('duplicate_del_port_driver_result'))
|
||||
|
||||
def test_create_delete_same_switch_diff_hosts_diff_vlan(self):
|
||||
"""Test create/delete two Ports, same switch/diff host & vlan."""
|
||||
|
||||
add_port2_driver_result = (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN.format(265),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/20', 265)])
|
||||
delete_port2_driver_result = (
|
||||
[test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/20', 265),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(265)])
|
||||
|
||||
self._basic_create_verify_port_vlan(
|
||||
'test_config1',
|
||||
self.duplicate_add_port_driver_result)
|
||||
self.results.get_test_results('duplicate_add_port_driver_result'))
|
||||
|
||||
self._create_port(
|
||||
self.test_configs['test_config2'])
|
||||
self._verify_results(add_port2_driver_result)
|
||||
self._verify_results(
|
||||
self.results.get_test_results('add_port2_driver_result'))
|
||||
|
||||
# Verify there are 2 port configs
|
||||
bindings = nexus_db_v2.get_nexusport_switch_bindings(
|
||||
|
@ -310,31 +392,24 @@ class TestCiscoNexusDevice(test_cisco_nexus_base.TestCiscoNexusBase,
|
|||
|
||||
self._basic_delete_verify_port_vlan(
|
||||
'test_config2',
|
||||
delete_port2_driver_result,
|
||||
self.results.get_test_results('delete_port2_driver_result'),
|
||||
nbr_of_bindings=1)
|
||||
|
||||
self._basic_delete_verify_port_vlan(
|
||||
'test_config1',
|
||||
self.duplicate_delete_port_driver_result)
|
||||
self.results.get_test_results('duplicate_del_port_driver_result'))
|
||||
|
||||
def test_create_delete_same_switch_diff_hosts_same_vlan(self):
|
||||
"""Test create/delete two Ports, same switch & vlan/diff host."""
|
||||
|
||||
add_port2_driver_result = (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN.format(267),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/20', 267)])
|
||||
delete_port2_driver_result = (
|
||||
[test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/20', 267)])
|
||||
|
||||
self._basic_create_verify_port_vlan(
|
||||
'test_config4',
|
||||
self.duplicate_add_port_driver_result)
|
||||
self.results.get_test_results('add_port_driver_result'))
|
||||
|
||||
self._create_port(
|
||||
self.test_configs['test_config5'])
|
||||
self._verify_results(add_port2_driver_result)
|
||||
self._verify_results(
|
||||
self.results.get_test_results('add_port2_driver_result2'))
|
||||
|
||||
# Verify there are 2 port configs
|
||||
bindings = nexus_db_v2.get_nexusport_switch_bindings(
|
||||
|
@ -347,34 +422,19 @@ class TestCiscoNexusDevice(test_cisco_nexus_base.TestCiscoNexusBase,
|
|||
|
||||
self._basic_delete_verify_port_vlan(
|
||||
'test_config5',
|
||||
delete_port2_driver_result,
|
||||
self.results.get_test_results('delete_port2_driver_result2'),
|
||||
nbr_of_bindings=1)
|
||||
|
||||
self._basic_delete_verify_port_vlan(
|
||||
'test_config4',
|
||||
self.duplicate_delete_port_driver_result)
|
||||
self.results.get_test_results('del_port_driver_result'))
|
||||
|
||||
def test_create_delete_diff_switch_same_host(self):
|
||||
"""Test create/delete of two Ports, diff switch/same host."""
|
||||
|
||||
add_port2_driver_result = (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN.format(268),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('portchannel', '2', 268),
|
||||
test_cisco_nexus_base.RESULT_ADD_VLAN.format(268),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('portchannel', '2', 268)])
|
||||
delete_port2_driver_result = (
|
||||
[test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('portchannel', '2', 268),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(268),
|
||||
test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('portchannel', '2', 268),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(268)])
|
||||
|
||||
self._basic_create_verify_port_vlan(
|
||||
'test_config_portchannel2',
|
||||
add_port2_driver_result)
|
||||
self.results.get_test_results('add_port2_driver_result3'))
|
||||
|
||||
# Verify there are 2 port configs. One per switch.
|
||||
bindings = nexus_db_v2.get_nexusport_switch_bindings(
|
||||
|
@ -392,60 +452,35 @@ class TestCiscoNexusDevice(test_cisco_nexus_base.TestCiscoNexusBase,
|
|||
# first port removal.
|
||||
self._basic_delete_verify_port_vlan(
|
||||
'test_config_portchannel2',
|
||||
delete_port2_driver_result)
|
||||
self.results.get_test_results('delete_port2_driver_result3'))
|
||||
|
||||
def test_create_delete_portchannel(self):
|
||||
"""Tests creation of a port over a portchannel."""
|
||||
|
||||
duplicate_add_port_driver_result = (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN.format(268),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('portchannel', '2', 268)])
|
||||
|
||||
duplicate_delete_port_driver_result = (
|
||||
[test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('portchannel', '2', 268),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(268)])
|
||||
|
||||
self._create_delete_port(
|
||||
'test_config_portchannel',
|
||||
duplicate_add_port_driver_result,
|
||||
duplicate_delete_port_driver_result)
|
||||
self.results.get_test_results('add_port_channel_driver_result'),
|
||||
self.results.get_test_results('delete_port_channel_driver_result'))
|
||||
|
||||
def test_create_delete_dual(self):
|
||||
"""Tests creation and deletion of dual ports for single server"""
|
||||
|
||||
duplicate_add_port_driver_result = (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN.format(269),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/3', 269),
|
||||
test_cisco_nexus_base.RESULT_ADD_VLAN.format(269),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('portchannel', '2', 269)])
|
||||
|
||||
duplicate_delete_port_driver_result = (
|
||||
[test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/3', 269),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(269),
|
||||
test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('portchannel', '2', 269)])
|
||||
|
||||
self._basic_create_verify_port_vlan(
|
||||
'test_config_dual',
|
||||
duplicate_add_port_driver_result,
|
||||
self.results.get_test_results('dual_add_port_driver_result'),
|
||||
nbr_of_bindings=2)
|
||||
|
||||
self._basic_delete_verify_port_vlan(
|
||||
'test_config_dual',
|
||||
duplicate_delete_port_driver_result)
|
||||
self.results.get_test_results('dual_delete_port_driver_result'))
|
||||
|
||||
def test_create_delete_dhcp(self):
|
||||
"""Tests creation and deletion of ports with device_owner of dhcp."""
|
||||
|
||||
self._create_delete_port(
|
||||
'test_config_dhcp',
|
||||
self.duplicate_add_port_driver_result,
|
||||
self.duplicate_delete_port_driver_result)
|
||||
self.results.get_test_results('duplicate_add_port_driver_result'),
|
||||
self.results.get_test_results('duplicate_del_port_driver_result'))
|
||||
|
||||
def test_create_delete_router_ha_intf(self):
|
||||
"""Tests creation and deletion of ports with device_owner
|
||||
|
@ -454,8 +489,95 @@ class TestCiscoNexusDevice(test_cisco_nexus_base.TestCiscoNexusBase,
|
|||
|
||||
self._create_delete_port(
|
||||
'test_config_router_ha_intf',
|
||||
self.duplicate_add_port_driver_result,
|
||||
self.duplicate_delete_port_driver_result)
|
||||
self.results.get_test_results('duplicate_add_port_driver_result'),
|
||||
self.results.get_test_results('duplicate_del_port_driver_result'))
|
||||
|
||||
def test_nexus_vm_migration(self):
|
||||
"""Verify VM (live) migration.
|
||||
|
||||
Simulate the following:
|
||||
Nova informs neutron of live-migration with port-update(new host).
|
||||
This should trigger two update_port_pre/postcommit() calls.
|
||||
|
||||
The first one should only change the current host_id and remove the
|
||||
binding resulting in the mechanism drivers receiving:
|
||||
PortContext.original['binding:host_id']: previous value
|
||||
PortContext.original_top_bound_segment: previous value
|
||||
PortContext.current['binding:host_id']: current (new) value
|
||||
PortContext.top_bound_segment: None
|
||||
|
||||
The second one binds the new host resulting in the mechanism
|
||||
drivers receiving:
|
||||
PortContext.original['binding:host_id']: previous value
|
||||
PortContext.original_top_bound_segment: None
|
||||
PortContext.current['binding:host_id']: previous value
|
||||
PortContext.top_bound_segment: new value
|
||||
"""
|
||||
|
||||
self._basic_create_verify_port_vlan(
|
||||
'test_config1',
|
||||
self.results.get_test_results('duplicate_add_port_driver_result'))
|
||||
binding = nexus_db_v2.get_nexusvm_bindings(
|
||||
test_cisco_nexus_base.VLAN_ID_1,
|
||||
test_cisco_nexus_base.INSTANCE_1)[0]
|
||||
self.assertEqual(
|
||||
test_cisco_nexus_base.NEXUS_PORT_1,
|
||||
binding.port_id)
|
||||
|
||||
port_context = self._generate_port_context(
|
||||
self.test_configs['test_config_migrate'],
|
||||
unbind_port=True)
|
||||
port_cfg = self.test_configs['test_config1']
|
||||
port_context.set_orig_port(
|
||||
port_cfg.instance_id,
|
||||
port_cfg.host_name,
|
||||
port_cfg.device_owner,
|
||||
port_cfg.profile,
|
||||
port_cfg.vnic_type,
|
||||
test_cisco_nexus_base.NETID)
|
||||
|
||||
self._cisco_mech_driver.create_port_postcommit(port_context)
|
||||
self._cisco_mech_driver.update_port_precommit(port_context)
|
||||
self._cisco_mech_driver.update_port_postcommit(port_context)
|
||||
|
||||
# Verify that port entry has been deleted.
|
||||
self.assertRaises(
|
||||
exceptions.NexusPortBindingNotFound,
|
||||
nexus_db_v2.get_nexusvm_bindings,
|
||||
test_cisco_nexus_base.VLAN_ID_1,
|
||||
test_cisco_nexus_base.INSTANCE_1)
|
||||
|
||||
# Clean all the ncclient mock_calls to clear exception
|
||||
# and other mock_call history.
|
||||
self.mock_ncclient.reset_mock()
|
||||
|
||||
self._basic_create_verify_port_vlan(
|
||||
'test_config_migrate',
|
||||
self.results.get_test_results('migrate_add_host2_driver_result'))
|
||||
|
||||
# Verify that port entry has been added using new host name.
|
||||
# Use port_id to verify that 2nd host name was used.
|
||||
binding = nexus_db_v2.get_nexusvm_bindings(
|
||||
test_cisco_nexus_base.VLAN_ID_1,
|
||||
test_cisco_nexus_base.INSTANCE_1)[0]
|
||||
self.assertEqual(
|
||||
test_cisco_nexus_base.NEXUS_PORT_2,
|
||||
binding.port_id)
|
||||
|
||||
|
||||
class TestCiscoNexusDeviceFailure(test_cisco_nexus_base.TestCiscoNexusBase,
|
||||
TestCiscoNexusDeviceConfig,
|
||||
TestCiscoNexusDeviceResults):
|
||||
|
||||
"""Negative Unit tests for Cisco ML2 Nexus device driver."""
|
||||
|
||||
def setUp(self):
|
||||
"""Sets up mock ncclient, and switch and credentials dictionaries."""
|
||||
|
||||
cfg.CONF.set_override('never_cache_ssh_connection', False, 'ml2_cisco')
|
||||
super(TestCiscoNexusDeviceFailure, self).setUp()
|
||||
self.mock_ncclient.reset_mock()
|
||||
self.results = TestCiscoNexusDeviceResults()
|
||||
|
||||
def test_connect_failure(self):
|
||||
"""Verifies exception handling during ncclient connect. """
|
||||
|
@ -743,7 +865,7 @@ class TestCiscoNexusDevice(test_cisco_nexus_base.TestCiscoNexusBase,
|
|||
|
||||
# Mock to keep track of number of close_session calls.
|
||||
ncclient_close = mock.patch.object(
|
||||
nexus_network_driver.CiscoNexusDriver,
|
||||
nexus_network_driver.CiscoNexusSshDriver,
|
||||
'_close_session').start()
|
||||
|
||||
# Clear out call_count changes during initialization activity
|
||||
|
@ -752,15 +874,15 @@ class TestCiscoNexusDevice(test_cisco_nexus_base.TestCiscoNexusBase,
|
|||
# Verify that ncclient is not closed by default.
|
||||
self._basic_create_verify_port_vlan(
|
||||
'test_config1',
|
||||
self.duplicate_add_port_driver_result)
|
||||
self.results.get_test_results('duplicate_add_port_driver_result'))
|
||||
assert not ncclient_close.called
|
||||
|
||||
self._basic_delete_verify_port_vlan(
|
||||
'test_config1',
|
||||
self.duplicate_delete_port_driver_result)
|
||||
self.results.get_test_results('duplicate_del_port_driver_result'))
|
||||
|
||||
# Patch to close ncclient session.
|
||||
mock.patch.object(nexus_network_driver.CiscoNexusDriver,
|
||||
mock.patch.object(nexus_network_driver.CiscoNexusSshDriver,
|
||||
'_get_close_ssh_session',
|
||||
return_value=True).start()
|
||||
|
||||
|
@ -770,7 +892,8 @@ class TestCiscoNexusDevice(test_cisco_nexus_base.TestCiscoNexusBase,
|
|||
# after trunk interface calls.
|
||||
self._basic_create_verify_port_vlan(
|
||||
'test_config1',
|
||||
self.duplicate_add_port_driver_result)
|
||||
self.results.get_test_results(
|
||||
'duplicate_add_port_driver_result'))
|
||||
self.assertEqual(2, ncclient_close.call_count)
|
||||
|
||||
def test_nexus_extended_vlan_range_failure(self):
|
||||
|
@ -801,88 +924,53 @@ class TestCiscoNexusDevice(test_cisco_nexus_base.TestCiscoNexusBase,
|
|||
# is called in _create_port_valid_exception and caching enabled
|
||||
self.assertEqual(0, self.mock_ncclient.connect.call_count)
|
||||
|
||||
def test_nexus_vm_migration(self):
|
||||
"""Verify VM (live) migration.
|
||||
|
||||
Simulate the following:
|
||||
Nova informs neutron of live-migration with port-update(new host).
|
||||
This should trigger two update_port_pre/postcommit() calls.
|
||||
class TestCiscoNexusInitResults(
|
||||
test_cisco_nexus_base.TestCiscoNexusBaseResults):
|
||||
|
||||
The first one should only change the current host_id and remove the
|
||||
binding resulting in the mechanism drivers receiving:
|
||||
PortContext.original['binding:host_id']: previous value
|
||||
PortContext.original_top_bound_segment: previous value
|
||||
PortContext.current['binding:host_id']: current (new) value
|
||||
PortContext.top_bound_segment: None
|
||||
"""Unit tests driver results for Cisco ML2 Nexus."""
|
||||
|
||||
The second one binds the new host resulting in the mechanism
|
||||
drivers receiving:
|
||||
PortContext.original['binding:host_id']: previous value
|
||||
PortContext.original_top_bound_segment: None
|
||||
PortContext.current['binding:host_id']: previous value
|
||||
PortContext.top_bound_segment: new value
|
||||
"""
|
||||
migrate_add_host2_driver_result = (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN.format(267),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/20', 267)])
|
||||
test_results = {
|
||||
# set 1 - switch 1.1.1.1 sets eth 1/10 & 1/20 to None
|
||||
# set 2 - switch 8.8.8.8 sets eth 1/10 & 1/20 to None
|
||||
# set 3 - switch 4.4.4.4 sets eth 1/3 & portchannel 2 to None
|
||||
# set 4 - switch 2.2.2.2 sets portchannel 2 to None
|
||||
# set 5 - switch 6.6.6.6 sets portchannel 2 to None
|
||||
# set 6 - switch 7.7.7.7 sets portchannel 2 to None
|
||||
'duplicate_init_port_driver_result1': (
|
||||
[test_cisco_nexus_base.RESULT_INTERFACE.
|
||||
format('ethernet', '1\/10', 'None'),
|
||||
test_cisco_nexus_base.RESULT_INTERFACE.
|
||||
format('ethernet', '1\/10', 'None'),
|
||||
test_cisco_nexus_base.RESULT_INTERFACE.
|
||||
format('ethernet', '1\/3', 'None'),
|
||||
test_cisco_nexus_base.RESULT_INTERFACE.
|
||||
format('portchannel', '2', 'None'),
|
||||
test_cisco_nexus_base.RESULT_INTERFACE.
|
||||
format('portchannel', '2', 'None'),
|
||||
test_cisco_nexus_base.RESULT_INTERFACE.
|
||||
format('portchannel', '2', 'None')]),
|
||||
|
||||
self._basic_create_verify_port_vlan(
|
||||
'test_config1',
|
||||
self.duplicate_add_port_driver_result)
|
||||
binding = nexus_db_v2.get_nexusvm_bindings(
|
||||
test_cisco_nexus_base.VLAN_ID_1,
|
||||
test_cisco_nexus_base.INSTANCE_1)[0]
|
||||
self.assertEqual(
|
||||
test_cisco_nexus_base.NEXUS_PORT_1,
|
||||
binding.port_id)
|
||||
|
||||
port_context = self._generate_port_context(
|
||||
self.test_configs['test_config_migrate'],
|
||||
unbind_port=True)
|
||||
port_cfg = self.test_configs['test_config1']
|
||||
port_context.set_orig_port(
|
||||
port_cfg.instance_id,
|
||||
port_cfg.host_name,
|
||||
port_cfg.device_owner,
|
||||
port_cfg.profile,
|
||||
port_cfg.vnic_type,
|
||||
test_cisco_nexus_base.NETID)
|
||||
|
||||
self._cisco_mech_driver.create_port_postcommit(port_context)
|
||||
self._cisco_mech_driver.update_port_precommit(port_context)
|
||||
self._cisco_mech_driver.update_port_postcommit(port_context)
|
||||
|
||||
# Verify that port entry has been deleted.
|
||||
self.assertRaises(
|
||||
exceptions.NexusPortBindingNotFound,
|
||||
nexus_db_v2.get_nexusvm_bindings,
|
||||
test_cisco_nexus_base.VLAN_ID_1,
|
||||
test_cisco_nexus_base.INSTANCE_1)
|
||||
|
||||
# Clean all the ncclient mock_calls to clear exception
|
||||
# and other mock_call history.
|
||||
self.mock_ncclient.reset_mock()
|
||||
|
||||
self._basic_create_verify_port_vlan(
|
||||
'test_config_migrate',
|
||||
migrate_add_host2_driver_result)
|
||||
|
||||
# Verify that port entry has been added using new host name.
|
||||
# Use port_id to verify that 2nd host name was used.
|
||||
binding = nexus_db_v2.get_nexusvm_bindings(
|
||||
test_cisco_nexus_base.VLAN_ID_1,
|
||||
test_cisco_nexus_base.INSTANCE_1)[0]
|
||||
self.assertEqual(
|
||||
test_cisco_nexus_base.NEXUS_PORT_2,
|
||||
binding.port_id)
|
||||
# Only one entry to match for last 3 so make None
|
||||
# so count matches in _verify_results
|
||||
'duplicate_init_port_driver_result2': (
|
||||
[test_cisco_nexus_base.RESULT_INTERFACE.
|
||||
format('ethernet', '1\/20', 'None'),
|
||||
test_cisco_nexus_base.RESULT_INTERFACE.
|
||||
format('ethernet', '1\/20', 'None'),
|
||||
test_cisco_nexus_base.RESULT_INTERFACE.
|
||||
format('portchannel', '2', 'None'),
|
||||
None,
|
||||
None,
|
||||
None])
|
||||
}
|
||||
|
||||
|
||||
class TestCiscoNexusDeviceInit(test_cisco_nexus_base.TestCiscoNexusBase,
|
||||
TestCiscoNexusDeviceConfig):
|
||||
"""Verifies interface vlan allowed none is set when missing."""
|
||||
|
||||
def _mock_init(self):
|
||||
def mock_init(self):
|
||||
# Prevent default which returns
|
||||
# 'switchport trunk allowed vlan none'
|
||||
# in get interface calls so Nexus driver
|
||||
|
@ -896,44 +984,60 @@ class TestCiscoNexusDeviceInit(test_cisco_nexus_base.TestCiscoNexusBase,
|
|||
|
||||
cfg.CONF.set_override('never_cache_ssh_connection', False, 'ml2_cisco')
|
||||
super(TestCiscoNexusDeviceInit, self).setUp()
|
||||
self.results = TestCiscoNexusInitResults()
|
||||
|
||||
def test_verify_initialization(self):
|
||||
|
||||
# set 1 - switch 1.1.1.1 sets eth 1/10 & 1/20 to None
|
||||
# set 2 - switch 8.8.8.8 sets eth 1/10 & 1/20 to None
|
||||
# set 3 - switch 4.4.4.4 sets eth 1/3 & portchannel 2 to None
|
||||
# set 4 - switch 2.2.2.2 sets portchannel 2 to None
|
||||
# set 5 - switch 6.6.6.6 sets portchannel 2 to None
|
||||
# set 6 - switch 7.7.7.7 sets portchannel 2 to None
|
||||
duplicate_init_port_driver_result1 = (
|
||||
[test_cisco_nexus_base.RESULT_INTERFACE.
|
||||
format('ethernet', '1\/10', 'None'),
|
||||
test_cisco_nexus_base.RESULT_INTERFACE.
|
||||
format('ethernet', '1\/10', 'None'),
|
||||
test_cisco_nexus_base.RESULT_INTERFACE.
|
||||
format('ethernet', '1\/3', 'None'),
|
||||
test_cisco_nexus_base.RESULT_INTERFACE.
|
||||
format('portchannel', '2', 'None'),
|
||||
test_cisco_nexus_base.RESULT_INTERFACE.
|
||||
format('portchannel', '2', 'None'),
|
||||
test_cisco_nexus_base.RESULT_INTERFACE.
|
||||
format('portchannel', '2', 'None')])
|
||||
self._verify_results(
|
||||
self.results.get_test_results(
|
||||
'duplicate_init_port_driver_result1'))
|
||||
self._verify_results(
|
||||
self.results.get_test_results(
|
||||
'duplicate_init_port_driver_result2'))
|
||||
|
||||
# Only one entry to match for last 3 so make None
|
||||
# so count matches in _verify_results
|
||||
duplicate_init_port_driver_result2 = (
|
||||
[test_cisco_nexus_base.RESULT_INTERFACE.
|
||||
format('ethernet', '1\/20', 'None'),
|
||||
test_cisco_nexus_base.RESULT_INTERFACE.
|
||||
format('ethernet', '1\/20', 'None'),
|
||||
test_cisco_nexus_base.RESULT_INTERFACE.
|
||||
format('portchannel', '2', 'None'),
|
||||
None,
|
||||
None,
|
||||
None])
|
||||
|
||||
self._verify_results(duplicate_init_port_driver_result1)
|
||||
self._verify_results(duplicate_init_port_driver_result2)
|
||||
class TestCiscoNexusBaremetalResults(
|
||||
test_cisco_nexus_base.TestCiscoNexusBaseResults):
|
||||
|
||||
"""Unit tests driver results for Cisco ML2 Nexus."""
|
||||
|
||||
test_results = {
|
||||
'add_port_ethernet_driver_result': (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN.format(267),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/10', 267)]),
|
||||
|
||||
'delete_port_ethernet_driver_result': (
|
||||
[test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/10', 267),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(267)]),
|
||||
|
||||
'add_port_channel_driver_result': (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN.format(267),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('port-channel', '469', 267)]),
|
||||
|
||||
'delete_port_channel_driver_result': (
|
||||
[test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('port-channel', '469', 267),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(267)]),
|
||||
|
||||
'add_port_ethernet_native_driver_result': (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN.format(265),
|
||||
(test_cisco_nexus_base.RESULT_ADD_NATIVE_INTERFACE.
|
||||
format('ethernet', '1\/10', 265) +
|
||||
'[\x00-\x7f]+' +
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/10', 265))]),
|
||||
|
||||
'delete_port_ethernet_native_driver_result': (
|
||||
[(test_cisco_nexus_base.RESULT_DEL_NATIVE_INTERFACE.
|
||||
format('ethernet', '1\/10') +
|
||||
'[\x00-\x7f]+' +
|
||||
test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/10', 265)),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(265)])
|
||||
}
|
||||
|
||||
|
||||
class TestCiscoNexusBaremetalDevice(test_cisco_nexus_base.TestCiscoNexusBase):
|
||||
|
@ -995,69 +1099,14 @@ class TestCiscoNexusBaremetalDevice(test_cisco_nexus_base.TestCiscoNexusBase):
|
|||
test_cisco_nexus_base.BAREMETAL_VNIC),
|
||||
}
|
||||
|
||||
simple_add_port_ethernet_driver_result = (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN.format(267),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/10', 267)])
|
||||
|
||||
simple_delete_port_ethernet_driver_result = (
|
||||
[test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/10', 267),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(267)])
|
||||
|
||||
simple_add_port_channel_driver_result = (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN.format(267),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('port-channel', '469', 267)])
|
||||
|
||||
simple_delete_port_channel_driver_result = (
|
||||
[test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('port-channel', '469', 267),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(267)])
|
||||
|
||||
simple_add_port_ethernet_native_driver_result = (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN.format(265),
|
||||
(test_cisco_nexus_base.RESULT_ADD_NATIVE_INTERFACE.
|
||||
format('ethernet', '1\/10', 265) +
|
||||
'[\x00-\x7f]+' +
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/10', 265))])
|
||||
|
||||
simple_delete_port_ethernet_native_driver_result = (
|
||||
[(test_cisco_nexus_base.RESULT_DEL_NATIVE_INTERFACE.
|
||||
format('ethernet', '1\/10') +
|
||||
'[\x00-\x7f]+' +
|
||||
test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/10', 265)),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(265)])
|
||||
|
||||
def setUp(self):
|
||||
"""Sets up mock ncclient, and switch and credentials dictionaries."""
|
||||
|
||||
cfg.CONF.set_override('never_cache_ssh_connection', False, 'ml2_cisco')
|
||||
super(TestCiscoNexusBaremetalDevice, self).setUp()
|
||||
self.results = TestCiscoNexusBaremetalResults()
|
||||
|
||||
def test_create_delete_basic_ethernet_port(self):
|
||||
"""Basic creation and deletion test of 1 ethernet port."""
|
||||
|
||||
# nbr_of_bindings includes reserved port binding
|
||||
self._basic_create_verify_port_vlan(
|
||||
'test_config1',
|
||||
self.simple_add_port_ethernet_driver_result, 2)
|
||||
|
||||
# Clean all the ncclient mock_calls so we can evaluate
|
||||
# results of delete operations.
|
||||
self.mock_ncclient.reset_mock()
|
||||
|
||||
# nbr_of_bindings includes reserved port binding
|
||||
self._basic_delete_verify_port_vlan(
|
||||
'test_config1',
|
||||
self.simple_delete_port_ethernet_driver_result,
|
||||
nbr_of_bindings=1)
|
||||
|
||||
def test_create_delete_basic_port_channel(self):
|
||||
"""Basic creation and deletion test of 1 port-channel."""
|
||||
|
||||
def _init_port_channel(self):
|
||||
# this is to prevent interface initialization from occurring
|
||||
# which adds unnecessary noise to the results.
|
||||
data_xml = {'connect.return_value.get.return_value.data_xml':
|
||||
|
@ -1065,10 +1114,15 @@ class TestCiscoNexusBaremetalDevice(test_cisco_nexus_base.TestCiscoNexusBase):
|
|||
'channel-group 469 mode active'}
|
||||
self.mock_ncclient.configure_mock(**data_xml)
|
||||
|
||||
def test_create_delete_basic_ethernet_port(self):
|
||||
"""Basic creation and deletion test of 1 ethernet port."""
|
||||
|
||||
# nbr_of_bindings includes reserved port binding
|
||||
self._basic_create_verify_port_vlan(
|
||||
'test_config1',
|
||||
self.simple_add_port_channel_driver_result, 2)
|
||||
self.results.get_test_results(
|
||||
'add_port_ethernet_driver_result'),
|
||||
2)
|
||||
|
||||
# Clean all the ncclient mock_calls so we can evaluate
|
||||
# results of delete operations.
|
||||
|
@ -1077,7 +1131,30 @@ class TestCiscoNexusBaremetalDevice(test_cisco_nexus_base.TestCiscoNexusBase):
|
|||
# nbr_of_bindings includes reserved port binding
|
||||
self._basic_delete_verify_port_vlan(
|
||||
'test_config1',
|
||||
self.simple_delete_port_channel_driver_result,
|
||||
self.results.get_test_results(
|
||||
'delete_port_ethernet_driver_result'),
|
||||
nbr_of_bindings=1)
|
||||
|
||||
def test_create_delete_basic_port_channel(self):
|
||||
"""Basic creation and deletion test of 1 port-channel."""
|
||||
|
||||
self._init_port_channel()
|
||||
# nbr_of_bindings includes reserved port binding
|
||||
self._basic_create_verify_port_vlan(
|
||||
'test_config1',
|
||||
self.results.get_test_results(
|
||||
'add_port_channel_driver_result'),
|
||||
2)
|
||||
|
||||
# Clean all the ncclient mock_calls so we can evaluate
|
||||
# results of delete operations.
|
||||
self.mock_ncclient.reset_mock()
|
||||
|
||||
# nbr_of_bindings includes reserved port binding
|
||||
self._basic_delete_verify_port_vlan(
|
||||
'test_config1',
|
||||
self.results.get_test_results(
|
||||
'delete_port_channel_driver_result'),
|
||||
nbr_of_bindings=1)
|
||||
|
||||
def test_create_delete_basic_eth_port_is_native(self):
|
||||
|
@ -1086,7 +1163,9 @@ class TestCiscoNexusBaremetalDevice(test_cisco_nexus_base.TestCiscoNexusBase):
|
|||
# nbr_of_bindings includes reserved port binding
|
||||
self._basic_create_verify_port_vlan(
|
||||
'test_config_native',
|
||||
self.simple_add_port_ethernet_native_driver_result, 2)
|
||||
self.results.get_test_results(
|
||||
'add_port_ethernet_native_driver_result'),
|
||||
2)
|
||||
|
||||
# Clean all the ncclient mock_calls so we can evaluate
|
||||
# results of delete operations.
|
||||
|
@ -1095,7 +1174,8 @@ class TestCiscoNexusBaremetalDevice(test_cisco_nexus_base.TestCiscoNexusBase):
|
|||
# nbr_of_bindings includes reserved port binding
|
||||
self._basic_delete_verify_port_vlan(
|
||||
'test_config_native',
|
||||
self.simple_delete_port_ethernet_native_driver_result,
|
||||
self.results.get_test_results(
|
||||
'delete_port_ethernet_native_driver_result'),
|
||||
nbr_of_bindings=1)
|
||||
|
||||
def test_create_delete_switch_ip_not_defined(self):
|
||||
|
@ -1140,7 +1220,8 @@ class TestCiscoNexusBaremetalDevice(test_cisco_nexus_base.TestCiscoNexusBase):
|
|||
# nbr_of_bindings includes reserved port binding
|
||||
self._basic_create_verify_port_vlan(
|
||||
'',
|
||||
self.simple_add_port_ethernet_driver_result, 2,
|
||||
self.results.get_test_results(
|
||||
'add_port_ethernet_driver_result'), 2,
|
||||
other_test=local_test_configs['test_config1'])
|
||||
|
||||
# Clean all the ncclient mock_calls so we can evaluate
|
||||
|
@ -1150,7 +1231,8 @@ class TestCiscoNexusBaremetalDevice(test_cisco_nexus_base.TestCiscoNexusBase):
|
|||
# nbr_of_bindings includes reserved port binding
|
||||
self._basic_delete_verify_port_vlan(
|
||||
'',
|
||||
self.simple_delete_port_ethernet_driver_result,
|
||||
self.results.get_test_results(
|
||||
'delete_port_ethernet_driver_result'),
|
||||
nbr_of_bindings=1,
|
||||
other_test=local_test_configs['test_config1'])
|
||||
|
||||
|
|
|
@ -115,21 +115,89 @@ class TestCiscoNexusVxlanDeviceConfig(object):
|
|||
|
||||
test_configs = collections.OrderedDict(sorted(test_configs.items()))
|
||||
|
||||
# The following contains desired Nexus output for some basic config above.
|
||||
add_port_driver_result = (
|
||||
[test_cisco_nexus_base.RESULT_ADD_NVE_INTERFACE.
|
||||
format(1, 70000, '255.1.1.1'),
|
||||
test_cisco_nexus_base.RESULT_ADD_VLAN_VNI.
|
||||
format(267, 70000),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/10', 267)])
|
||||
|
||||
delete_port_driver_result = (
|
||||
[test_cisco_nexus_base.RESULT_DEL_NVE_INTERFACE.
|
||||
format(1, 70000, 267),
|
||||
test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/10', 267),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(267)])
|
||||
class TestCiscoNexusVxlanResults(
|
||||
test_cisco_nexus_base.TestCiscoNexusBaseResults):
|
||||
|
||||
"""Unit tests driver results for Cisco ML2 Nexus."""
|
||||
|
||||
test_results = {
|
||||
|
||||
# The following contains desired Nexus output for
|
||||
# some basic config above.
|
||||
'add_port_driver_result': (
|
||||
[test_cisco_nexus_base.RESULT_ADD_NVE_INTERFACE.
|
||||
format(1, 70000, '255.1.1.1'),
|
||||
test_cisco_nexus_base.RESULT_ADD_VLAN_VNI.
|
||||
format(267, 70000),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/10', 267)]),
|
||||
|
||||
'delete_port_driver_result': (
|
||||
[test_cisco_nexus_base.RESULT_DEL_NVE_INTERFACE.
|
||||
format(1, 70000, 267),
|
||||
test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/10', 267),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(267)]),
|
||||
|
||||
'add_port2_driver_result': (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN_VNI.
|
||||
format(267, 70000),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/20', 267)]),
|
||||
|
||||
'delete_port2_driver_result': (
|
||||
[test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/20', 267)]),
|
||||
|
||||
'add_port_driver_result3': (
|
||||
[test_cisco_nexus_base.RESULT_ADD_NVE_INTERFACE.
|
||||
format(1, 70000, '255.1.1.1'),
|
||||
test_cisco_nexus_base.RESULT_ADD_NVE_INTERFACE.
|
||||
format(1, 70000, '255.1.1.1'),
|
||||
test_cisco_nexus_base.RESULT_ADD_VLAN_VNI.
|
||||
format(267, 70000),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/10', 267),
|
||||
test_cisco_nexus_base.RESULT_ADD_VLAN_VNI.
|
||||
format(267, 70000),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/2', 267),
|
||||
test_cisco_nexus_base.RESULT_ADD_VLAN_VNI.
|
||||
format(267, 70000),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/3', 267)]),
|
||||
|
||||
'delete_port_driver_result3': (
|
||||
[test_cisco_nexus_base.RESULT_DEL_NVE_INTERFACE.
|
||||
format(1, 70000, 267),
|
||||
test_cisco_nexus_base.RESULT_DEL_NVE_INTERFACE.
|
||||
format(1, 70000, 267),
|
||||
test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/10', 267),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(267),
|
||||
test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/2', 267),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(267),
|
||||
test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/3', 267)]),
|
||||
|
||||
'add_port_driver_result2': (
|
||||
[test_cisco_nexus_base.RESULT_ADD_NVE_INTERFACE.
|
||||
format(1, 70001, '255.1.1.1'),
|
||||
test_cisco_nexus_base.RESULT_ADD_VLAN_VNI.
|
||||
format(265, 70001),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/20', 265)]),
|
||||
|
||||
'delete_port_driver_result2': (
|
||||
[test_cisco_nexus_base.RESULT_DEL_NVE_INTERFACE.
|
||||
format(1, 70001, 265),
|
||||
test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/20', 265),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(265)])
|
||||
|
||||
}
|
||||
|
||||
|
||||
class TestCiscoNexusVxlanDevice(test_cisco_nexus_base.TestCiscoNexusBase,
|
||||
|
@ -144,6 +212,7 @@ class TestCiscoNexusVxlanDevice(test_cisco_nexus_base.TestCiscoNexusBase,
|
|||
super(TestCiscoNexusVxlanDevice, self).setUp()
|
||||
self.mock_ncclient.reset_mock()
|
||||
self.addCleanup(self._clear_nve_db)
|
||||
self.results = TestCiscoNexusVxlanResults()
|
||||
|
||||
def _clear_nve_db(self):
|
||||
nexus_db_v2.remove_all_nexusnve_bindings()
|
||||
|
@ -193,23 +262,16 @@ class TestCiscoNexusVxlanDevice(test_cisco_nexus_base.TestCiscoNexusBase,
|
|||
def test_nexus_vxlan_one_network_two_hosts(self):
|
||||
"""Tests creation and deletion of two new virtual Ports."""
|
||||
|
||||
add_port2_driver_result = (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN_VNI.
|
||||
format(267, 70000),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/20', 267)])
|
||||
|
||||
delete_port2_driver_result = (
|
||||
[test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/20', 267)])
|
||||
|
||||
self._basic_create_verify_port_vlan(
|
||||
'test_vxlan_config1',
|
||||
self.add_port_driver_result)
|
||||
self.results.get_test_results(
|
||||
'add_port_driver_result'))
|
||||
|
||||
self._create_port(
|
||||
self.test_configs['test_vxlan_config2'])
|
||||
self._verify_results(add_port2_driver_result)
|
||||
self._verify_results(
|
||||
self.results.get_test_results(
|
||||
'add_port2_driver_result'))
|
||||
|
||||
bindings = nexus_db_v2.get_nexusvlan_binding(
|
||||
test_cisco_nexus_base.VLAN_ID_1,
|
||||
|
@ -222,11 +284,14 @@ class TestCiscoNexusVxlanDevice(test_cisco_nexus_base.TestCiscoNexusBase,
|
|||
|
||||
self._basic_delete_verify_port_vlan(
|
||||
'test_vxlan_config2',
|
||||
delete_port2_driver_result, nbr_of_bindings=1)
|
||||
self.results.get_test_results(
|
||||
'delete_port2_driver_result'),
|
||||
nbr_of_bindings=1)
|
||||
|
||||
self._basic_delete_verify_port_vlan(
|
||||
'test_vxlan_config1',
|
||||
self.delete_port_driver_result)
|
||||
self.results.get_test_results(
|
||||
'delete_port_driver_result'))
|
||||
|
||||
def test_nexus_missing_vxlan_fields(self):
|
||||
"""Test handling of a VXLAN NexusMissingRequiredFields exception.
|
||||
|
@ -324,44 +389,13 @@ class TestCiscoNexusVxlanDevice(test_cisco_nexus_base.TestCiscoNexusBase,
|
|||
def test_nexus_vxlan_one_network(self):
|
||||
"""Test processing for creating one VXLAN segment."""
|
||||
|
||||
add_port_driver_result3 = (
|
||||
[test_cisco_nexus_base.RESULT_ADD_NVE_INTERFACE.
|
||||
format(1, 70000, '255.1.1.1'),
|
||||
test_cisco_nexus_base.RESULT_ADD_NVE_INTERFACE.
|
||||
format(1, 70000, '255.1.1.1'),
|
||||
test_cisco_nexus_base.RESULT_ADD_VLAN_VNI.
|
||||
format(267, 70000),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/10', 267),
|
||||
test_cisco_nexus_base.RESULT_ADD_VLAN_VNI.
|
||||
format(267, 70000),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/2', 267),
|
||||
test_cisco_nexus_base.RESULT_ADD_VLAN_VNI.
|
||||
format(267, 70000),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/3', 267)])
|
||||
|
||||
delete_port_driver_result3 = (
|
||||
[test_cisco_nexus_base.RESULT_DEL_NVE_INTERFACE.
|
||||
format(1, 70000, 267),
|
||||
test_cisco_nexus_base.RESULT_DEL_NVE_INTERFACE.
|
||||
format(1, 70000, 267),
|
||||
test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/10', 267),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(267),
|
||||
test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/2', 267),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(267),
|
||||
test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/3', 267)])
|
||||
|
||||
# Since test_vxlan_config3 & test_vxlan_config4 share
|
||||
# the same host name they both get processed in the
|
||||
# next call.
|
||||
self._basic_create_verify_port_vlan(
|
||||
'test_vxlan_config3',
|
||||
add_port_driver_result3)
|
||||
self.results.get_test_results(
|
||||
'add_port_driver_result3'))
|
||||
|
||||
for switch_ip, nbr_bind in [
|
||||
(test_cisco_nexus_base.NEXUS_IP_ADDRESS_1, 1),
|
||||
|
@ -378,7 +412,8 @@ class TestCiscoNexusVxlanDevice(test_cisco_nexus_base.TestCiscoNexusBase,
|
|||
# next call.
|
||||
self._basic_delete_verify_port_vlan(
|
||||
'test_vxlan_config3',
|
||||
delete_port_driver_result3)
|
||||
self.results.get_test_results(
|
||||
'delete_port_driver_result3'))
|
||||
|
||||
for switch_ip in [
|
||||
test_cisco_nexus_base.NEXUS_IP_ADDRESS_1,
|
||||
|
@ -399,29 +434,17 @@ class TestCiscoNexusVxlanDevice(test_cisco_nexus_base.TestCiscoNexusBase,
|
|||
def test_nexus_vxlan_two_network(self):
|
||||
"""Test processing for creating one VXLAN segment."""
|
||||
|
||||
add_port_driver_result2 = (
|
||||
[test_cisco_nexus_base.RESULT_ADD_NVE_INTERFACE.
|
||||
format(1, 70001, '255.1.1.1'),
|
||||
test_cisco_nexus_base.RESULT_ADD_VLAN_VNI.
|
||||
format(265, 70001),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/20', 265)])
|
||||
|
||||
delete_port_driver_result2 = (
|
||||
[test_cisco_nexus_base.RESULT_DEL_NVE_INTERFACE.
|
||||
format(1, 70001, 265),
|
||||
test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/20', 265),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(265)])
|
||||
|
||||
self._basic_create_verify_port_vlan(
|
||||
'test_vxlan_config5',
|
||||
self.add_port_driver_result)
|
||||
self.results.get_test_results(
|
||||
'add_port_driver_result'))
|
||||
|
||||
self._create_port(
|
||||
self.test_configs['test_vxlan_config6'],
|
||||
override_netid=888)
|
||||
self._verify_results(add_port_driver_result2)
|
||||
self._verify_results(
|
||||
self.results.get_test_results(
|
||||
'add_port_driver_result2'))
|
||||
|
||||
binding = nexus_db_v2.get_nve_switch_bindings(
|
||||
test_cisco_nexus_base.NEXUS_IP_ADDRESS_1)
|
||||
|
@ -433,11 +456,14 @@ class TestCiscoNexusVxlanDevice(test_cisco_nexus_base.TestCiscoNexusBase,
|
|||
|
||||
self._basic_delete_verify_port_vlan(
|
||||
'test_vxlan_config6',
|
||||
delete_port_driver_result2, nbr_of_bindings=1)
|
||||
self.results.get_test_results(
|
||||
'delete_port_driver_result2'),
|
||||
nbr_of_bindings=1)
|
||||
|
||||
self._basic_delete_verify_port_vlan(
|
||||
'test_vxlan_config5',
|
||||
self.delete_port_driver_result)
|
||||
self.results.get_test_results(
|
||||
'delete_port_driver_result'))
|
||||
|
||||
try:
|
||||
binding = nexus_db_v2.get_nve_switch_bindings(
|
||||
|
|
|
@ -31,6 +31,106 @@ RP_HOST_NAME_DUAL = 'testdualhost'
|
|||
MAX_REPLAY_COUNT = 4
|
||||
|
||||
|
||||
class TestCiscoNexusReplayResults(
|
||||
test_cisco_nexus_base.TestCiscoNexusBaseResults):
|
||||
|
||||
"""Unit tests driver results for Cisco ML2 Nexus."""
|
||||
|
||||
test_results = {
|
||||
'driver_result_unique_init': (
|
||||
[test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/10', 'None')]),
|
||||
|
||||
'driver_result_unique_add1': (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN.format(267),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/10', 267)]),
|
||||
|
||||
'driver_result_unique_add2': (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN.format(265),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/10', 265)]),
|
||||
|
||||
'driver_result_unique_del1': (
|
||||
[test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/10', 265),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(265)]),
|
||||
|
||||
'driver_result_unique_del2': (
|
||||
[test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/10', 267),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(267)]),
|
||||
|
||||
'driver_result_unique_2vlan_replay': (
|
||||
[test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/10', '265,267'),
|
||||
test_cisco_nexus_base.RESULT_ADD_VLAN.format('265,267')]),
|
||||
|
||||
'dupl_vlan_result1_add': (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN.format(267),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/10', 267),
|
||||
test_cisco_nexus_base.RESULT_ADD_VLAN.format(267),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/20', 267)]),
|
||||
|
||||
'dupl_vlan_result2_add': (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN.format(267),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/10', 267),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/20', 267)]),
|
||||
|
||||
'dupl_vlan_result2_del': (
|
||||
[test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/10', 267),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(267),
|
||||
test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/20', 267)]),
|
||||
|
||||
'dupl_vlan_result_replay': (
|
||||
[test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/10', 267),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/20', 267),
|
||||
test_cisco_nexus_base.RESULT_ADD_VLAN.format(267)]),
|
||||
|
||||
'dupl_port_result_replay': (
|
||||
[test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/10', 267),
|
||||
test_cisco_nexus_base.RESULT_ADD_VLAN.format(267)]),
|
||||
|
||||
'switch_up_result_add': (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN.format(269),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/3', 269)]),
|
||||
|
||||
'switch_up_result_del': (
|
||||
[test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/3', 269),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(269)]),
|
||||
|
||||
'switch_restore_result_add': (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN.format(269),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/3', 269)]),
|
||||
|
||||
'switch_restore_result_replay': (
|
||||
[test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/2', 269),
|
||||
test_cisco_nexus_base.RESULT_ADD_VLAN.format(269)]),
|
||||
|
||||
'switch_restore_result_del': (
|
||||
[test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/3', 269),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(269),
|
||||
test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/2', 269),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(269)]),
|
||||
|
||||
}
|
||||
|
||||
|
||||
class TestCiscoNexusReplay(test_cisco_nexus_base.TestCiscoNexusReplayBase):
|
||||
"""Unit tests for Replay of Cisco ML2 Nexus data."""
|
||||
test_configs = {
|
||||
|
@ -143,30 +243,6 @@ class TestCiscoNexusReplay(test_cisco_nexus_base.TestCiscoNexusReplayBase):
|
|||
{},
|
||||
test_cisco_nexus_base.NORMAL_VNIC),
|
||||
}
|
||||
driver_result_unique_init = (
|
||||
[test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/10', 'None')])
|
||||
|
||||
driver_result_unique_add1 = (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN.format(267),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/10', 267)])
|
||||
|
||||
driver_result_unique_add2 = (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN.format(265),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/10', 265)])
|
||||
|
||||
driver_result_unique_del1 = (
|
||||
[test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/10', 265),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(265)])
|
||||
|
||||
driver_result_unique_del2 = (
|
||||
[test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/10', 267),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(267)])
|
||||
|
||||
test_configs = collections.OrderedDict(sorted(test_configs.items()))
|
||||
|
||||
def setUp(self):
|
||||
|
@ -174,117 +250,103 @@ class TestCiscoNexusReplay(test_cisco_nexus_base.TestCiscoNexusReplayBase):
|
|||
|
||||
cfg.CONF.set_override('never_cache_ssh_connection', False, 'ml2_cisco')
|
||||
super(TestCiscoNexusReplay, self).setUp()
|
||||
self.results = TestCiscoNexusReplayResults()
|
||||
|
||||
def test_replay_unique_ports(self):
|
||||
"""Provides replay data and result data for unique ports. """
|
||||
|
||||
first_add = {'driver_results': self.
|
||||
driver_result_unique_add1,
|
||||
'nbr_db_entries': 1}
|
||||
second_add = {'driver_results': self.
|
||||
driver_result_unique_add2,
|
||||
'nbr_db_entries': 2}
|
||||
first_del = {'driver_results': self.
|
||||
driver_result_unique_del1,
|
||||
'nbr_db_entries': 1}
|
||||
second_del = {'driver_results': self.
|
||||
driver_result_unique_del2,
|
||||
'nbr_db_entries': 0}
|
||||
driver_result_unique_2vlan_replay = (
|
||||
[test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/10', '265,267'),
|
||||
test_cisco_nexus_base.RESULT_ADD_VLAN.format('265,267')])
|
||||
first_add = {
|
||||
'driver_results': self.results.get_test_results(
|
||||
'driver_result_unique_add1'),
|
||||
'nbr_db_entries': 1}
|
||||
second_add = {
|
||||
'driver_results': self.results.get_test_results(
|
||||
'driver_result_unique_add2'),
|
||||
'nbr_db_entries': 2}
|
||||
first_del = {
|
||||
'driver_results': self.results.get_test_results(
|
||||
'driver_result_unique_del1'),
|
||||
'nbr_db_entries': 1}
|
||||
second_del = {
|
||||
'driver_results': self.results.get_test_results(
|
||||
'driver_result_unique_del2'),
|
||||
'nbr_db_entries': 0}
|
||||
|
||||
self._process_replay(
|
||||
'test_replay_unique1',
|
||||
'test_replay_unique2',
|
||||
self.driver_result_unique_init,
|
||||
self.results.get_test_results(
|
||||
'driver_result_unique_init'),
|
||||
first_add,
|
||||
second_add,
|
||||
driver_result_unique_2vlan_replay,
|
||||
self.results.get_test_results(
|
||||
'driver_result_unique_2vlan_replay'),
|
||||
first_del,
|
||||
second_del)
|
||||
|
||||
def test_replay_duplicate_vlan(self):
|
||||
"""Provides replay data and result data for duplicate vlans. """
|
||||
|
||||
result1_add = (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN.format(267),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/10', 267),
|
||||
test_cisco_nexus_base.RESULT_ADD_VLAN.format(267),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/20', 267)])
|
||||
first_add = {'driver_results': result1_add,
|
||||
'nbr_db_entries': 2}
|
||||
first_add = {
|
||||
'driver_results': self.results.get_test_results(
|
||||
'dupl_vlan_result1_add'),
|
||||
'nbr_db_entries': 2}
|
||||
|
||||
result2_add = (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN.format(267),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/10', 267),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/20', 267)])
|
||||
# TODO(caboucha)
|
||||
# 'driver_result': [], until the correct fix for
|
||||
# the following issue is resolved.
|
||||
# https://review.openstack.org/#/c/241216/
|
||||
second_add = {'driver_results': result2_add,
|
||||
'nbr_db_entries': 4}
|
||||
second_add = {
|
||||
'driver_results': self.results.get_test_results(
|
||||
'dupl_vlan_result2_add'),
|
||||
'nbr_db_entries': 4}
|
||||
|
||||
first_del = {'driver_results': [],
|
||||
'nbr_db_entries': 2}
|
||||
|
||||
result2_del = (
|
||||
[test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/10', 267),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(267),
|
||||
test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/20', 267)])
|
||||
second_del = {'driver_results': result2_del,
|
||||
'nbr_db_entries': 0}
|
||||
|
||||
result_replay = (
|
||||
[test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/10', 267),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/20', 267),
|
||||
test_cisco_nexus_base.RESULT_ADD_VLAN.format(267)])
|
||||
second_del = {
|
||||
'driver_results': self.results.get_test_results(
|
||||
'dupl_vlan_result2_del'),
|
||||
'nbr_db_entries': 0}
|
||||
|
||||
self._process_replay('test_replay_duplvlan1',
|
||||
'test_replay_duplvlan2',
|
||||
[],
|
||||
first_add, second_add,
|
||||
result_replay,
|
||||
self.results.get_test_results(
|
||||
'dupl_vlan_result_replay'),
|
||||
first_del, second_del)
|
||||
|
||||
def test_replay_duplicate_ports(self):
|
||||
"""Provides replay data and result data for duplicate ports. """
|
||||
|
||||
first_add = {'driver_results': self.driver_result_unique_add1,
|
||||
'nbr_db_entries': 1}
|
||||
first_add = {
|
||||
'driver_results': self.results.get_test_results(
|
||||
'driver_result_unique_add1'),
|
||||
'nbr_db_entries': 1}
|
||||
|
||||
# TODO(caboucha)
|
||||
# 'driver_result': [], until the correct fix for
|
||||
# the following issue is resolved.
|
||||
# https://review.openstack.org/#/c/241216/
|
||||
second_add = {'driver_results': self.driver_result_unique_add1,
|
||||
'nbr_db_entries': 2}
|
||||
second_add = {
|
||||
'driver_results': self.results.get_test_results(
|
||||
'driver_result_unique_add1'),
|
||||
'nbr_db_entries': 2}
|
||||
first_del = {'driver_results': [],
|
||||
'nbr_db_entries': 1}
|
||||
|
||||
second_del = {'driver_results': self.driver_result_unique_del2,
|
||||
'nbr_db_entries': 0}
|
||||
|
||||
result_replay = (
|
||||
[test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/10', 267),
|
||||
test_cisco_nexus_base.RESULT_ADD_VLAN.format(267)])
|
||||
second_del = {
|
||||
'driver_results': self.results.get_test_results(
|
||||
'driver_result_unique_del2'),
|
||||
'nbr_db_entries': 0}
|
||||
|
||||
self._process_replay('test_replay_duplport1',
|
||||
'test_replay_duplport2',
|
||||
[],
|
||||
first_add, second_add,
|
||||
result_replay,
|
||||
self.results.get_test_results(
|
||||
'dupl_port_result_replay'),
|
||||
first_del, second_del)
|
||||
|
||||
def test_replay_enable_vxlan_feature_failure(self):
|
||||
|
@ -378,12 +440,9 @@ class TestCiscoNexusReplay(test_cisco_nexus_base.TestCiscoNexusReplayBase):
|
|||
port_cfg2.nexus_ip_addr, const.SWITCH_INACTIVE)
|
||||
|
||||
# Set-up successful creation of port vlan config
|
||||
result_add = (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN.format(269),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/3', 269)])
|
||||
self._basic_create_verify_port_vlan('test_replay_dual',
|
||||
result_add,
|
||||
self.results.get_test_results(
|
||||
'switch_up_result_add'),
|
||||
nbr_of_bindings=1)
|
||||
|
||||
# Even though 2nd entry is inactive, there should be
|
||||
|
@ -394,12 +453,9 @@ class TestCiscoNexusReplay(test_cisco_nexus_base.TestCiscoNexusReplayBase):
|
|||
port_cfg2.nexus_ip_addr)))
|
||||
|
||||
# Clean-up the port entry
|
||||
result_del = (
|
||||
[test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/3', 269),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(269)])
|
||||
self._basic_delete_verify_port_vlan('test_replay_dual',
|
||||
result_del,
|
||||
self.results.get_test_results(
|
||||
'switch_up_result_del'),
|
||||
nbr_of_bindings=0)
|
||||
|
||||
def test_replay_port_success_if_one_switch_restored(self):
|
||||
|
@ -417,12 +473,9 @@ class TestCiscoNexusReplay(test_cisco_nexus_base.TestCiscoNexusReplayBase):
|
|||
port_cfg2.nexus_ip_addr, const.SWITCH_INACTIVE)
|
||||
|
||||
# Set-up successful creation of port vlan config
|
||||
result_add = (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN.format(269),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/3', 269)])
|
||||
self._basic_create_verify_port_vlan('test_replay_dual',
|
||||
result_add,
|
||||
self.results.get_test_results(
|
||||
'switch_restore_result_add'),
|
||||
nbr_of_bindings=1)
|
||||
|
||||
# Even though 2nd entry is inactive, there should be
|
||||
|
@ -434,25 +487,17 @@ class TestCiscoNexusReplay(test_cisco_nexus_base.TestCiscoNexusReplayBase):
|
|||
|
||||
# Restore port data for that switch
|
||||
self._cfg_monitor.check_connections()
|
||||
result_replay = (
|
||||
[test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/2', 269),
|
||||
test_cisco_nexus_base.RESULT_ADD_VLAN.format(269)])
|
||||
self._verify_results(result_replay)
|
||||
self._verify_results(
|
||||
self.results.get_test_results(
|
||||
'switch_restore_result_replay'))
|
||||
|
||||
# Clear mock_call history.
|
||||
self.mock_ncclient.reset_mock()
|
||||
|
||||
# Clean-up the port entries
|
||||
result_del = (
|
||||
[test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/3', 269),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(269),
|
||||
test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/2', 269),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(269)])
|
||||
self._basic_delete_verify_port_vlan('test_replay_dual',
|
||||
result_del,
|
||||
self.results.get_test_results(
|
||||
'switch_restore_result_del'),
|
||||
nbr_of_bindings=0)
|
||||
|
||||
def test_replay_create_fails_if_single_switch_down(self):
|
||||
|
@ -495,7 +540,8 @@ class TestCiscoNexusReplay(test_cisco_nexus_base.TestCiscoNexusReplayBase):
|
|||
port_cfg.nexus_ip_addr, const.SWITCH_ACTIVE)
|
||||
|
||||
self._basic_create_verify_port_vlan('test_replay_unique1',
|
||||
self.driver_result_unique_add1)
|
||||
self.results.get_test_results(
|
||||
'driver_result_unique_add1'))
|
||||
|
||||
# Make switch inactive before delete
|
||||
self._cisco_mech_driver.set_switch_ip_and_active_state(
|
||||
|
@ -544,7 +590,8 @@ class TestCiscoNexusReplay(test_cisco_nexus_base.TestCiscoNexusReplayBase):
|
|||
|
||||
# Set-up successful creation of port vlan config
|
||||
self._basic_create_verify_port_vlan('test_replay_unique1',
|
||||
self.driver_result_unique_add1)
|
||||
self.results.get_test_results(
|
||||
'driver_result_unique_add1'))
|
||||
|
||||
# Set-up so get_nexus_type driver fails
|
||||
config = {'connect.return_value.get.side_effect':
|
||||
|
@ -581,7 +628,8 @@ class TestCiscoNexusReplay(test_cisco_nexus_base.TestCiscoNexusReplayBase):
|
|||
|
||||
# Set-up successful creation of port vlan config
|
||||
self._basic_create_verify_port_vlan('test_replay_unique1',
|
||||
self.driver_result_unique_add1)
|
||||
self.results.get_test_results(
|
||||
'driver_result_unique_add1'))
|
||||
|
||||
# Set-up exception during create_vlan
|
||||
config = {'connect.return_value.edit_config.side_effect':
|
||||
|
@ -608,6 +656,7 @@ class TestCiscoNexusReplay(test_cisco_nexus_base.TestCiscoNexusReplayBase):
|
|||
result_replay = (
|
||||
[test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/10', 267)] + driver_result1)
|
||||
|
||||
self._verify_results(result_replay)
|
||||
|
||||
# Clear the edit driver exception for next test.
|
||||
|
@ -630,7 +679,8 @@ class TestCiscoNexusReplay(test_cisco_nexus_base.TestCiscoNexusReplayBase):
|
|||
|
||||
# Clean-up the port entry
|
||||
self._basic_delete_verify_port_vlan('test_replay_unique1',
|
||||
self.driver_result_unique_del2)
|
||||
self.results.get_test_results(
|
||||
'driver_result_unique_del2'))
|
||||
|
||||
def test_replay_vlan_batch_failure_during_replay(self):
|
||||
"""Verifies handling of batch vlan during replay."""
|
||||
|
@ -737,8 +787,10 @@ class TestCiscoNexusReplay(test_cisco_nexus_base.TestCiscoNexusReplayBase):
|
|||
port_cfg.nexus_ip_addr, const.SWITCH_ACTIVE)
|
||||
|
||||
# Set-up successful creation of port vlan config
|
||||
self._basic_create_verify_port_vlan('test_replay_unique1',
|
||||
self.driver_result_unique_add1)
|
||||
self._basic_create_verify_port_vlan(
|
||||
'test_replay_unique1',
|
||||
self.results.get_test_results(
|
||||
'driver_result_unique_add1'))
|
||||
|
||||
# Test 1:
|
||||
# Set the edit create vlan driver exception
|
||||
|
@ -855,9 +907,123 @@ class TestCiscoNexusReplay(test_cisco_nexus_base.TestCiscoNexusReplayBase):
|
|||
test_cisco_nexus_base.NEXUS_IP_ADDRESS_1))
|
||||
|
||||
|
||||
class TestCiscoNexusBaremetalReplayResults(
|
||||
test_cisco_nexus_base.TestCiscoNexusBaseResults):
|
||||
"""Unit tests driver results for Cisco ML2 Nexus."""
|
||||
|
||||
test_results = {
|
||||
|
||||
'driver_result_unique_eth_init': (
|
||||
[test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/10', 'None')]),
|
||||
|
||||
'driver_result_unique_eth_add1': (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN.format(267),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/10', 267)]),
|
||||
|
||||
'driver_result_unique_eth_add2': (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN.format(265),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/10', 265)]),
|
||||
|
||||
'driver_result_unique_eth_del1': (
|
||||
[test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/10', 265),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(265)]),
|
||||
|
||||
'driver_result_unique_eth_del2': (
|
||||
[test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/10', 267),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(267)]),
|
||||
|
||||
'driver_result_unique_vPC_init': (
|
||||
[test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('port-channel', '469', 'None')]),
|
||||
|
||||
'driver_result_unique_vPC_add1': (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN.format(267),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('port-channel', '469', 267)]),
|
||||
|
||||
'driver_result_unique_vPC_add2': (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN.format(265),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('port-channel', '469', 265)]),
|
||||
|
||||
'driver_result_unique_vPC_del1': (
|
||||
[test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('port-channel', '469', 265),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(265)]),
|
||||
|
||||
'driver_result_unique_vPC_del2': (
|
||||
[test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('port-channel', '469', 267),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(267)]),
|
||||
|
||||
'driver_result_unique_native_port_ethernet_add': (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN.format(265),
|
||||
(test_cisco_nexus_base.RESULT_ADD_NATIVE_INTERFACE.
|
||||
format('ethernet', '1\/10', 265) +
|
||||
'[\x00-\x7f]+' +
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/10', 265))]),
|
||||
|
||||
'driver_result_unique_native_port_ethernet_del': (
|
||||
[(test_cisco_nexus_base.RESULT_DEL_NATIVE_INTERFACE.
|
||||
format('ethernet', '1\/10') +
|
||||
'[\x00-\x7f]+' +
|
||||
test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/10', 265)),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(265)]),
|
||||
|
||||
'driver_result_unique_2vlan_replay': (
|
||||
[test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/10', '265,267'),
|
||||
test_cisco_nexus_base.RESULT_ADD_VLAN.format('265,267')]),
|
||||
|
||||
'driver_result_unique_2vlan_vpc_replay': (
|
||||
[test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('port-channel', '469', '265,267'),
|
||||
test_cisco_nexus_base.RESULT_ADD_VLAN.format('265,267')]),
|
||||
|
||||
'driver_result_unique_vPC470_del1': (
|
||||
[test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('port-channel', '470', 265),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(265)]),
|
||||
|
||||
'driver_result_unique_vPC470_del2': (
|
||||
[test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('port-channel', '470', 267),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(267)]),
|
||||
|
||||
'driver_result_unique_vPC470_2vlan_replay': (
|
||||
[test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('port-channel', '470', '265,267'),
|
||||
test_cisco_nexus_base.RESULT_ADD_VLAN.format('265,267')]),
|
||||
|
||||
'driver_result_unique_2vlan_vpc_enchg_replay': (
|
||||
[test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/10', '265,267'),
|
||||
test_cisco_nexus_base.RESULT_ADD_VLAN.format('265,267')]),
|
||||
|
||||
'driver_result_unique_native_2vlan_replay': (
|
||||
[(test_cisco_nexus_base.RESULT_ADD_NATIVE_INTERFACE.
|
||||
format('ethernet', '1\/10', 265) +
|
||||
'[\x00-\x7f]+' +
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/10', '265')),
|
||||
(test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/10', '265,267')),
|
||||
test_cisco_nexus_base.RESULT_ADD_VLAN.format('265,267')])
|
||||
}
|
||||
|
||||
|
||||
class TestCiscoNexusBaremetalReplay(
|
||||
test_cisco_nexus_base.TestCiscoNexusReplayBase):
|
||||
|
||||
"""Unit tests for Replay of Cisco ML2 Nexus data."""
|
||||
|
||||
baremetal_profile = {
|
||||
"local_link_information": [
|
||||
{
|
||||
|
@ -921,70 +1087,6 @@ class TestCiscoNexusBaremetalReplay(
|
|||
test_cisco_nexus_base.BAREMETAL_VNIC),
|
||||
}
|
||||
|
||||
driver_result_unique_eth_init = (
|
||||
[test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/10', 'None')])
|
||||
|
||||
driver_result_unique_eth_add1 = (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN.format(267),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/10', 267)])
|
||||
|
||||
driver_result_unique_eth_add2 = (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN.format(265),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/10', 265)])
|
||||
|
||||
driver_result_unique_eth_del1 = (
|
||||
[test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/10', 265),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(265)])
|
||||
|
||||
driver_result_unique_eth_del2 = (
|
||||
[test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/10', 267),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(267)])
|
||||
|
||||
driver_result_unique_vPC_init = (
|
||||
[test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('port-channel', '469', 'None')])
|
||||
|
||||
driver_result_unique_vPC_add1 = (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN.format(267),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('port-channel', '469', 267)])
|
||||
|
||||
driver_result_unique_vPC_add2 = (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN.format(265),
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('port-channel', '469', 265)])
|
||||
|
||||
driver_result_unique_vPC_del1 = (
|
||||
[test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('port-channel', '469', 265),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(265)])
|
||||
|
||||
driver_result_unique_vPC_del2 = (
|
||||
[test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('port-channel', '469', 267),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(267)])
|
||||
|
||||
driver_result_unique_native_port_ethernet_add = (
|
||||
[test_cisco_nexus_base.RESULT_ADD_VLAN.format(265),
|
||||
(test_cisco_nexus_base.RESULT_ADD_NATIVE_INTERFACE.
|
||||
format('ethernet', '1\/10', 265) +
|
||||
'[\x00-\x7f]+' +
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/10', 265))])
|
||||
|
||||
driver_result_unique_native_port_ethernet_del = (
|
||||
[(test_cisco_nexus_base.RESULT_DEL_NATIVE_INTERFACE.
|
||||
format('ethernet', '1\/10') +
|
||||
'[\x00-\x7f]+' +
|
||||
test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('ethernet', '1\/10', 265)),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(265)])
|
||||
|
||||
test_configs = collections.OrderedDict(sorted(test_configs.items()))
|
||||
|
||||
def setUp(self):
|
||||
|
@ -992,71 +1094,81 @@ class TestCiscoNexusBaremetalReplay(
|
|||
|
||||
cfg.CONF.set_override('never_cache_ssh_connection', False, 'ml2_cisco')
|
||||
super(TestCiscoNexusBaremetalReplay, self).setUp()
|
||||
self.results = TestCiscoNexusBaremetalReplayResults()
|
||||
|
||||
def _init_port_channel(self, ch_grp):
|
||||
|
||||
# with Baremetal config when enet interface associated to port-channel,
|
||||
# the port-channel interface is configured instead. This config
|
||||
# causes this to happen.
|
||||
data_xml = {'connect.return_value.get.return_value.data_xml':
|
||||
'switchport trunk allowed vlan none\n'
|
||||
'channel-group ' + str(ch_grp) + ' mode active'}
|
||||
self.mock_ncclient.configure_mock(**data_xml)
|
||||
|
||||
def test_replay_unique_ethernet_ports(self):
|
||||
"""Provides replay data and result data for unique ports. """
|
||||
|
||||
first_add = {'driver_results': self.
|
||||
driver_result_unique_eth_add1,
|
||||
'nbr_db_entries': 2}
|
||||
second_add = {'driver_results': self.
|
||||
driver_result_unique_eth_add2,
|
||||
'nbr_db_entries': 3}
|
||||
first_del = {'driver_results': self.
|
||||
driver_result_unique_eth_del1,
|
||||
'nbr_db_entries': 2}
|
||||
second_del = {'driver_results': self.
|
||||
driver_result_unique_eth_del2,
|
||||
'nbr_db_entries': 1}
|
||||
driver_result_unique_2vlan_replay = (
|
||||
[test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/10', '265,267'),
|
||||
test_cisco_nexus_base.RESULT_ADD_VLAN.format('265,267')])
|
||||
first_add = {
|
||||
'driver_results': self.results.get_test_results(
|
||||
'driver_result_unique_eth_add1'),
|
||||
'nbr_db_entries': 2}
|
||||
second_add = {
|
||||
'driver_results': self.results.get_test_results(
|
||||
'driver_result_unique_eth_add2'),
|
||||
'nbr_db_entries': 3}
|
||||
first_del = {
|
||||
'driver_results': self.results.get_test_results(
|
||||
'driver_result_unique_eth_del1'),
|
||||
'nbr_db_entries': 2}
|
||||
second_del = {
|
||||
'driver_results': self.results.get_test_results(
|
||||
'driver_result_unique_eth_del2'),
|
||||
'nbr_db_entries': 1}
|
||||
|
||||
self._process_replay(
|
||||
'test_replay_unique1',
|
||||
'test_replay_unique2',
|
||||
self.driver_result_unique_eth_init,
|
||||
self.results.get_test_results(
|
||||
'driver_result_unique_eth_init'),
|
||||
first_add,
|
||||
second_add,
|
||||
driver_result_unique_2vlan_replay,
|
||||
self.results.get_test_results(
|
||||
'driver_result_unique_2vlan_replay'),
|
||||
first_del,
|
||||
second_del)
|
||||
|
||||
def test_replay_unique_vPC_ports(self):
|
||||
"""Provides replay data and result data for unique ports. """
|
||||
|
||||
first_add = {'driver_results': self.
|
||||
driver_result_unique_vPC_add1,
|
||||
'nbr_db_entries': 2}
|
||||
second_add = {'driver_results': self.
|
||||
driver_result_unique_vPC_add2,
|
||||
'nbr_db_entries': 3}
|
||||
first_del = {'driver_results': self.
|
||||
driver_result_unique_vPC_del1,
|
||||
'nbr_db_entries': 2}
|
||||
second_del = {'driver_results': self.
|
||||
driver_result_unique_vPC_del2,
|
||||
'nbr_db_entries': 1}
|
||||
driver_result_unique_2vlan_replay = (
|
||||
[test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('port-channel', '469', '265,267'),
|
||||
test_cisco_nexus_base.RESULT_ADD_VLAN.format('265,267')])
|
||||
first_add = {
|
||||
'driver_results': self.results.get_test_results(
|
||||
'driver_result_unique_vPC_add1'),
|
||||
'nbr_db_entries': 2}
|
||||
second_add = {
|
||||
'driver_results': self.results.get_test_results(
|
||||
'driver_result_unique_vPC_add2'),
|
||||
'nbr_db_entries': 3}
|
||||
first_del = {
|
||||
'driver_results': self.results.get_test_results(
|
||||
'driver_result_unique_vPC_del1'),
|
||||
'nbr_db_entries': 2}
|
||||
second_del = {
|
||||
'driver_results': self.results.get_test_results(
|
||||
'driver_result_unique_vPC_del2'),
|
||||
'nbr_db_entries': 1}
|
||||
|
||||
# this is to prevent interface initialization from occurring
|
||||
# which adds unnecessary noise to the results.
|
||||
data_xml = {'connect.return_value.get.return_value.data_xml':
|
||||
'switchport trunk allowed vlan none\n'
|
||||
'channel-group 469 mode active'}
|
||||
self.mock_ncclient.configure_mock(**data_xml)
|
||||
self._init_port_channel(469)
|
||||
|
||||
self._process_replay(
|
||||
'test_replay_unique1',
|
||||
'test_replay_unique2',
|
||||
self.driver_result_unique_vPC_init,
|
||||
self.results.get_test_results(
|
||||
'driver_result_unique_vPC_init'),
|
||||
first_add,
|
||||
second_add,
|
||||
driver_result_unique_2vlan_replay,
|
||||
self.results.get_test_results(
|
||||
'driver_result_unique_2vlan_vpc_replay'),
|
||||
first_del,
|
||||
second_del)
|
||||
|
||||
|
@ -1064,53 +1176,39 @@ class TestCiscoNexusBaremetalReplay(
|
|||
"""Provides replay data and result data for unique ports. """
|
||||
|
||||
def replay_init():
|
||||
# This is to cause port-channel to get configured to 470
|
||||
data_xml = {'connect.return_value.get.return_value.data_xml':
|
||||
'switchport trunk allowed vlan none\n'
|
||||
'channel-group 470 mode active'}
|
||||
self.mock_ncclient.configure_mock(**data_xml)
|
||||
# This causes port-channel 470 to get configured instead.
|
||||
self._init_port_channel(470)
|
||||
|
||||
driver_result_unique_vPC470_del1 = (
|
||||
[test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('port-channel', '470', 265),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(265)])
|
||||
|
||||
driver_result_unique_vPC470_del2 = (
|
||||
[test_cisco_nexus_base.RESULT_DEL_INTERFACE.
|
||||
format('port-channel', '470', 267),
|
||||
test_cisco_nexus_base.RESULT_DEL_VLAN.format(267)])
|
||||
|
||||
first_add = {'driver_results': self.
|
||||
driver_result_unique_vPC_add1,
|
||||
'nbr_db_entries': 2}
|
||||
second_add = {'driver_results': self.
|
||||
driver_result_unique_vPC_add2,
|
||||
'nbr_db_entries': 3}
|
||||
first_del = {'driver_results':
|
||||
driver_result_unique_vPC470_del1,
|
||||
'nbr_db_entries': 2}
|
||||
second_del = {'driver_results':
|
||||
driver_result_unique_vPC470_del2,
|
||||
'nbr_db_entries': 1}
|
||||
driver_result_unique_vPC470_2vlan_replay = (
|
||||
[test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('port-channel', '470', '265,267'),
|
||||
test_cisco_nexus_base.RESULT_ADD_VLAN.format('265,267')])
|
||||
first_add = {
|
||||
'driver_results': self.results.get_test_results(
|
||||
'driver_result_unique_vPC_add1'),
|
||||
'nbr_db_entries': 2}
|
||||
second_add = {
|
||||
'driver_results': self.results.get_test_results(
|
||||
'driver_result_unique_vPC_add2'),
|
||||
'nbr_db_entries': 3}
|
||||
first_del = {
|
||||
'driver_results': self.results.get_test_results(
|
||||
'driver_result_unique_vPC470_del1'),
|
||||
'nbr_db_entries': 2}
|
||||
second_del = {
|
||||
'driver_results': self.results.get_test_results(
|
||||
'driver_result_unique_vPC470_del2'),
|
||||
'nbr_db_entries': 1}
|
||||
|
||||
# This is to cause port-channel 469 to get configured
|
||||
data_xml = {'connect.return_value.get.return_value.data_xml':
|
||||
'switchport trunk allowed vlan none\n'
|
||||
'channel-group 469 mode active'}
|
||||
self.mock_ncclient.configure_mock(**data_xml)
|
||||
self._init_port_channel(469)
|
||||
|
||||
# Providing replay_init to change channel-group
|
||||
self._process_replay(
|
||||
'test_replay_unique1',
|
||||
'test_replay_unique2',
|
||||
self.driver_result_unique_vPC_init,
|
||||
self.results.get_test_results(
|
||||
'driver_result_unique_vPC_init'),
|
||||
first_add,
|
||||
second_add,
|
||||
driver_result_unique_vPC470_2vlan_replay,
|
||||
self.results.get_test_results(
|
||||
'driver_result_unique_vPC470_2vlan_replay'),
|
||||
first_del,
|
||||
second_del,
|
||||
replay_init)
|
||||
|
@ -1119,43 +1217,42 @@ class TestCiscoNexusBaremetalReplay(
|
|||
"""Provides replay data and result data for unique ports. """
|
||||
|
||||
def replay_init():
|
||||
# This is to cause port-channel to get replaced with enet
|
||||
data_xml = {'connect.return_value.get.return_value.data_xml':
|
||||
'switchport trunk allowed vlan none\n'}
|
||||
self.mock_ncclient.configure_mock(**data_xml)
|
||||
# This causes port-channel to get replaced with enet
|
||||
# by eliminating channel-group config from enet config.
|
||||
if cfg.CONF.ml2_cisco.nexus_driver == 'restapi':
|
||||
self.restapi_mock_init()
|
||||
else:
|
||||
self.mock_init()
|
||||
|
||||
first_add = {'driver_results': self.
|
||||
driver_result_unique_vPC_add1,
|
||||
'nbr_db_entries': 2}
|
||||
second_add = {'driver_results': self.
|
||||
driver_result_unique_vPC_add2,
|
||||
'nbr_db_entries': 3}
|
||||
first_del = {'driver_results': self.
|
||||
driver_result_unique_eth_del1,
|
||||
'nbr_db_entries': 2}
|
||||
second_del = {'driver_results': self.
|
||||
driver_result_unique_eth_del2,
|
||||
'nbr_db_entries': 1}
|
||||
driver_result_unique_2vlan_replay = (
|
||||
[test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/10', '265,267'),
|
||||
test_cisco_nexus_base.RESULT_ADD_VLAN.format('265,267')])
|
||||
first_add = {
|
||||
'driver_results': self.results.get_test_results(
|
||||
'driver_result_unique_vPC_add1'),
|
||||
'nbr_db_entries': 2}
|
||||
second_add = {
|
||||
'driver_results': self.results.get_test_results(
|
||||
'driver_result_unique_vPC_add2'),
|
||||
'nbr_db_entries': 3}
|
||||
first_del = {
|
||||
'driver_results': self.results.get_test_results(
|
||||
'driver_result_unique_eth_del1'),
|
||||
'nbr_db_entries': 2}
|
||||
second_del = {
|
||||
'driver_results': self.results.get_test_results(
|
||||
'driver_result_unique_eth_del2'),
|
||||
'nbr_db_entries': 1}
|
||||
|
||||
# this is to prevent interface initialization from occurring
|
||||
# which adds unnecessary noise to the results.
|
||||
data_xml = {'connect.return_value.get.return_value.data_xml':
|
||||
'switchport trunk allowed vlan none\n'
|
||||
'channel-group 469 mode active'}
|
||||
self.mock_ncclient.configure_mock(**data_xml)
|
||||
self._init_port_channel(469)
|
||||
|
||||
# Providing replay_init to remove port-channel
|
||||
self._process_replay(
|
||||
'test_replay_unique1',
|
||||
'test_replay_unique2',
|
||||
self.driver_result_unique_vPC_init,
|
||||
self.results.get_test_results(
|
||||
'driver_result_unique_vPC_init'),
|
||||
first_add,
|
||||
second_add,
|
||||
driver_result_unique_2vlan_replay,
|
||||
self.results.get_test_results(
|
||||
'driver_result_unique_2vlan_vpc_enchg_replay'),
|
||||
first_del,
|
||||
second_del,
|
||||
replay_init)
|
||||
|
@ -1163,33 +1260,32 @@ class TestCiscoNexusBaremetalReplay(
|
|||
def test_replay_unique_native_nonnative_ethernet_ports(self):
|
||||
"""Test replay with native and nonnative ethernet ports. """
|
||||
|
||||
first_add = {'driver_results': self.
|
||||
driver_result_unique_native_port_ethernet_add,
|
||||
'nbr_db_entries': 2}
|
||||
second_add = {'driver_results': self.
|
||||
driver_result_unique_eth_add1,
|
||||
'nbr_db_entries': 3}
|
||||
first_del = {'driver_results': self.
|
||||
driver_result_unique_eth_del2,
|
||||
'nbr_db_entries': 2}
|
||||
second_del = {'driver_results': self.
|
||||
driver_result_unique_native_port_ethernet_del,
|
||||
'nbr_db_entries': 1}
|
||||
driver_result_unique_native_2vlan_replay = (
|
||||
[(test_cisco_nexus_base.RESULT_ADD_NATIVE_INTERFACE.
|
||||
format('ethernet', '1\/10', 265) +
|
||||
'[\x00-\x7f]+' +
|
||||
test_cisco_nexus_base.RESULT_ADD_INTERFACE.
|
||||
format('ethernet', '1\/10', '265,267')),
|
||||
test_cisco_nexus_base.RESULT_ADD_VLAN.format('265,267')])
|
||||
first_add = {
|
||||
'driver_results': self.results.get_test_results(
|
||||
'driver_result_unique_native_port_ethernet_add'),
|
||||
'nbr_db_entries': 2}
|
||||
second_add = {
|
||||
'driver_results': self.results.get_test_results(
|
||||
'driver_result_unique_eth_add1'),
|
||||
'nbr_db_entries': 3}
|
||||
first_del = {
|
||||
'driver_results': self.results.get_test_results(
|
||||
'driver_result_unique_eth_del2'),
|
||||
'nbr_db_entries': 2}
|
||||
second_del = {
|
||||
'driver_results': self.results.get_test_results(
|
||||
'driver_result_unique_native_port_ethernet_del'),
|
||||
'nbr_db_entries': 1}
|
||||
|
||||
self._process_replay(
|
||||
'test_replay_unique_native1',
|
||||
'test_replay_unique1',
|
||||
self.driver_result_unique_eth_init,
|
||||
self.results.get_test_results(
|
||||
'driver_result_unique_eth_init'),
|
||||
first_add,
|
||||
second_add,
|
||||
driver_result_unique_native_2vlan_replay,
|
||||
self.results.get_test_results(
|
||||
'driver_result_unique_native_2vlan_replay'),
|
||||
first_del,
|
||||
second_del)
|
||||
|
||||
|
|
|
@ -0,0 +1,571 @@
|
|||
# Copyright (c) 2017 Cisco Systems, 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.
|
||||
|
||||
"""
|
||||
Basic Test Classes using RESTAPI Driver to test Cisco Nexus platforms.
|
||||
|
||||
These Classes are based on the original ssh event driver so same
|
||||
tests occur with same configuration. What's different between
|
||||
the tests is the resulting driver output which is what
|
||||
the tests in this class presents to its parent class.
|
||||
|
||||
You will notice in this file there are test methods which
|
||||
are skipped by using 'pass'. This is because these tests
|
||||
apply to ssh only OR because rerunning the test would be
|
||||
redundant.
|
||||
"""
|
||||
|
||||
from oslo_config import cfg
|
||||
|
||||
from networking_cisco.plugins.ml2.drivers.cisco.nexus import (
|
||||
nexus_restapi_snippets as snipp)
|
||||
from networking_cisco.tests.unit.ml2.drivers.cisco.nexus import (
|
||||
test_cisco_nexus_base as base)
|
||||
from networking_cisco.tests.unit.ml2.drivers.cisco.nexus import (
|
||||
test_cisco_nexus_events)
|
||||
|
||||
|
||||
class TestCiscoNexusRestDeviceResults(base.TestCiscoNexusBaseResults):
|
||||
|
||||
"""Unit tests driver results for Cisco ML2 Nexus."""
|
||||
|
||||
test_results = {
|
||||
'duplicate_add_port_driver_result': [
|
||||
[snipp.PATH_VLAN_ALL,
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_VLAN_ADD % 267),
|
||||
base.POST],
|
||||
[(snipp.PATH_IF % 'phys-[eth1/10]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '+267')),
|
||||
base.POST]
|
||||
],
|
||||
'duplicate_del_port_driver_result': [
|
||||
[(snipp.PATH_IF % 'phys-[eth1/10]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '-267')),
|
||||
base.POST],
|
||||
[(snipp.PATH_VLAN % '267'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
'',
|
||||
base.DELETE]
|
||||
],
|
||||
'add_port2_driver_result': [
|
||||
[snipp.PATH_VLAN_ALL,
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_VLAN_ADD % 265),
|
||||
base.POST],
|
||||
[(snipp.PATH_IF % 'phys-[eth1/20]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '+265')),
|
||||
base.POST]
|
||||
],
|
||||
'delete_port2_driver_result': [
|
||||
[(snipp.PATH_IF % 'phys-[eth1/20]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '-265')),
|
||||
base.POST],
|
||||
[(snipp.PATH_VLAN % '265'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
'',
|
||||
base.DELETE]
|
||||
],
|
||||
'add_port2_driver_result2': [
|
||||
[snipp.PATH_VLAN_ALL,
|
||||
base.NEXUS_IP_ADDRESS_8,
|
||||
(snipp.BODY_VLAN_ADD % 267),
|
||||
base.POST],
|
||||
[(snipp.PATH_IF % 'phys-[eth1/20]'),
|
||||
base.NEXUS_IP_ADDRESS_8,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '+267')),
|
||||
base.POST]
|
||||
],
|
||||
'delete_port2_driver_result2': [
|
||||
[(snipp.PATH_IF % 'phys-[eth1/20]'),
|
||||
base.NEXUS_IP_ADDRESS_8,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '-267')),
|
||||
base.POST]
|
||||
],
|
||||
'add_port2_driver_result3': [
|
||||
[snipp.PATH_VLAN_ALL,
|
||||
base.NEXUS_IP_ADDRESS_6,
|
||||
(snipp.BODY_VLAN_ADD % 268),
|
||||
base.POST],
|
||||
[(snipp.PATH_IF % 'aggr-[po2]'),
|
||||
base.NEXUS_IP_ADDRESS_6,
|
||||
(snipp.BODY_TRUNKVLAN % ('pcAggrIf', '+268')),
|
||||
base.POST],
|
||||
[snipp.PATH_VLAN_ALL,
|
||||
base.NEXUS_IP_ADDRESS_7,
|
||||
(snipp.BODY_VLAN_ADD % 268),
|
||||
base.POST],
|
||||
[(snipp.PATH_IF % 'aggr-[po2]'),
|
||||
base.NEXUS_IP_ADDRESS_7,
|
||||
(snipp.BODY_TRUNKVLAN % ('pcAggrIf', '+268')),
|
||||
base.POST]
|
||||
],
|
||||
'delete_port2_driver_result3': [
|
||||
[(snipp.PATH_IF % 'aggr-[po2]'),
|
||||
base.NEXUS_IP_ADDRESS_6,
|
||||
(snipp.BODY_TRUNKVLAN % ('pcAggrIf', '-268')),
|
||||
base.POST],
|
||||
[(snipp.PATH_VLAN % '268'),
|
||||
base.NEXUS_IP_ADDRESS_6,
|
||||
'',
|
||||
base.DELETE],
|
||||
[(snipp.PATH_IF % 'aggr-[po2]'),
|
||||
base.NEXUS_IP_ADDRESS_7,
|
||||
(snipp.BODY_TRUNKVLAN % ('pcAggrIf', '-268')),
|
||||
base.POST],
|
||||
[(snipp.PATH_VLAN % '268'),
|
||||
base.NEXUS_IP_ADDRESS_7,
|
||||
'',
|
||||
base.DELETE]
|
||||
],
|
||||
'add_port_channel_driver_result': [
|
||||
[snipp.PATH_VLAN_ALL,
|
||||
base.NEXUS_IP_ADDRESS_2,
|
||||
(snipp.BODY_VLAN_ADD % 268),
|
||||
base.POST],
|
||||
[(snipp.PATH_IF % 'aggr-[po2]'),
|
||||
base.NEXUS_IP_ADDRESS_2,
|
||||
(snipp.BODY_TRUNKVLAN % ('pcAggrIf', '+268')),
|
||||
base.POST]
|
||||
],
|
||||
'delete_port_channel_driver_result': [
|
||||
[(snipp.PATH_IF % 'aggr-[po2]'),
|
||||
base.NEXUS_IP_ADDRESS_2,
|
||||
(snipp.BODY_TRUNKVLAN % ('pcAggrIf', '-268')),
|
||||
base.POST],
|
||||
[(snipp.PATH_VLAN % '268'),
|
||||
base.NEXUS_IP_ADDRESS_2,
|
||||
'',
|
||||
base.DELETE]
|
||||
],
|
||||
'dual_add_port_driver_result': [
|
||||
[snipp.PATH_VLAN_ALL,
|
||||
base.NEXUS_IP_ADDRESS_DUAL,
|
||||
(snipp.BODY_VLAN_ADD % 269),
|
||||
base.POST],
|
||||
[(snipp.PATH_IF % 'phys-[eth1/3]'),
|
||||
base.NEXUS_IP_ADDRESS_DUAL,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '+269')),
|
||||
base.POST],
|
||||
[snipp.PATH_VLAN_ALL,
|
||||
base.NEXUS_IP_ADDRESS_DUAL,
|
||||
(snipp.BODY_VLAN_ADD % 269),
|
||||
base.POST],
|
||||
[(snipp.PATH_IF % 'aggr-[po2]'),
|
||||
base.NEXUS_IP_ADDRESS_DUAL,
|
||||
(snipp.BODY_TRUNKVLAN % ('pcAggrIf', '+269')),
|
||||
base.POST]
|
||||
],
|
||||
'dual_delete_port_driver_result': [
|
||||
[(snipp.PATH_IF % 'phys-[eth1/3]'),
|
||||
base.NEXUS_IP_ADDRESS_DUAL,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '-269')),
|
||||
base.POST],
|
||||
[(snipp.PATH_VLAN % '269'),
|
||||
base.NEXUS_IP_ADDRESS_DUAL,
|
||||
'',
|
||||
base.DELETE],
|
||||
[(snipp.PATH_IF % 'aggr-[po2]'),
|
||||
base.NEXUS_IP_ADDRESS_DUAL,
|
||||
(snipp.BODY_TRUNKVLAN % ('pcAggrIf', '-269')),
|
||||
base.POST],
|
||||
],
|
||||
'add_port_driver_result': [
|
||||
[snipp.PATH_VLAN_ALL,
|
||||
base.NEXUS_IP_ADDRESS_8,
|
||||
(snipp.BODY_VLAN_ADD % 267),
|
||||
base.POST],
|
||||
[(snipp.PATH_IF % 'phys-[eth1/10]'),
|
||||
base.NEXUS_IP_ADDRESS_8,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '+267')),
|
||||
base.POST]
|
||||
],
|
||||
'del_port_driver_result': [
|
||||
[(snipp.PATH_IF % 'phys-[eth1/10]'),
|
||||
base.NEXUS_IP_ADDRESS_8,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '-267')),
|
||||
base.POST],
|
||||
[(snipp.PATH_VLAN % '267'),
|
||||
base.NEXUS_IP_ADDRESS_8,
|
||||
'',
|
||||
base.DELETE]
|
||||
],
|
||||
'migrate_add_host2_driver_result': [
|
||||
[snipp.PATH_VLAN_ALL,
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_VLAN_ADD % 267),
|
||||
base.POST],
|
||||
[(snipp.PATH_IF % 'phys-[eth1/20]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '+267')),
|
||||
base.POST]
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
class TestCiscoNexusRestDevice(test_cisco_nexus_events.TestCiscoNexusDevice):
|
||||
|
||||
"""Unit tests for Cisco ML2 Nexus restapi device driver"""
|
||||
|
||||
def setUp(self):
|
||||
cfg.CONF.set_override('nexus_driver', 'restapi', 'ml2_cisco')
|
||||
super(TestCiscoNexusRestDevice, self).setUp()
|
||||
self.results = TestCiscoNexusRestDeviceResults()
|
||||
|
||||
def test_create_delete_duplicate_ports(self):
|
||||
(super(TestCiscoNexusRestDevice, self).
|
||||
test_create_delete_duplicate_ports())
|
||||
|
||||
def test_create_delete_duplicate_port_transaction(self):
|
||||
(super(TestCiscoNexusRestDevice, self).
|
||||
test_create_delete_duplicate_port_transaction())
|
||||
|
||||
def test_create_delete_same_switch_diff_hosts_diff_vlan(self):
|
||||
(super(TestCiscoNexusRestDevice, self).
|
||||
test_create_delete_same_switch_diff_hosts_diff_vlan())
|
||||
|
||||
def test_create_delete_same_switch_diff_hosts_same_vlan(self):
|
||||
(super(TestCiscoNexusRestDevice, self).
|
||||
test_create_delete_same_switch_diff_hosts_same_vlan())
|
||||
|
||||
def test_create_delete_diff_switch_same_host(self):
|
||||
(super(TestCiscoNexusRestDevice, self).
|
||||
test_create_delete_diff_switch_same_host())
|
||||
|
||||
def test_create_delete_portchannel(self):
|
||||
super(TestCiscoNexusRestDevice, self).test_create_delete_portchannel()
|
||||
|
||||
def test_create_delete_dual(self):
|
||||
super(TestCiscoNexusRestDevice, self).test_create_delete_dual()
|
||||
|
||||
def test_create_delete_dhcp(self):
|
||||
super(TestCiscoNexusRestDevice, self).test_create_delete_dhcp()
|
||||
|
||||
def test_create_delete_router_ha_intf(self):
|
||||
(super(TestCiscoNexusRestDevice, self).
|
||||
test_create_delete_router_ha_intf())
|
||||
|
||||
def test_nexus_vm_migration(self):
|
||||
super(TestCiscoNexusRestDevice, self).test_nexus_vm_migration()
|
||||
|
||||
|
||||
class TestCiscoNexusRestInitResults(base.TestCiscoNexusBaseResults):
|
||||
|
||||
"""Unit tests driver results for Cisco ML2 Nexus."""
|
||||
|
||||
test_results = {
|
||||
# set 1 - switch 1.1.1.1 sets eth 1/10 & 1/20 to None
|
||||
# set 2 - switch 8.8.8.8 sets eth 1/10 & 1/20 to None
|
||||
# set 3 - switch 4.4.4.4 sets eth 1/3 & portchannel 2 to None
|
||||
# set 4 - switch 2.2.2.2 sets portchannel 2 to None
|
||||
# set 5 - switch 6.6.6.6 sets portchannel 2 to None
|
||||
# set 6 - switch 7.7.7.7 sets portchannel 2 to None
|
||||
'duplicate_init_port_driver_result1': [
|
||||
[(snipp.PATH_IF % 'phys-[eth1/10]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '')),
|
||||
base.POST],
|
||||
|
||||
[(snipp.PATH_IF % 'phys-[eth1/20]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '')),
|
||||
base.POST],
|
||||
|
||||
[(snipp.PATH_IF % 'phys-[eth1/20]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '')),
|
||||
base.POST],
|
||||
|
||||
[(snipp.PATH_IF % 'phys-[eth1/10]'),
|
||||
base.NEXUS_IP_ADDRESS_8,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '')),
|
||||
base.POST],
|
||||
|
||||
[(snipp.PATH_IF % 'phys-[eth1/20]'),
|
||||
base.NEXUS_IP_ADDRESS_8,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '')),
|
||||
base.POST],
|
||||
|
||||
[(snipp.PATH_IF % 'phys-[eth1/3]'),
|
||||
base.NEXUS_IP_ADDRESS_DUAL,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '')),
|
||||
base.POST],
|
||||
|
||||
[(snipp.PATH_IF % 'aggr-[po2]'),
|
||||
base.NEXUS_IP_ADDRESS_DUAL,
|
||||
(snipp.BODY_TRUNKVLAN % ('pcAggrIf', '')),
|
||||
base.POST],
|
||||
|
||||
[(snipp.PATH_IF % 'aggr-[po2]'),
|
||||
base.NEXUS_IP_ADDRESS_2,
|
||||
(snipp.BODY_TRUNKVLAN % ('pcAggrIf', '')),
|
||||
base.POST],
|
||||
|
||||
[(snipp.PATH_IF % 'aggr-[po2]'),
|
||||
base.NEXUS_IP_ADDRESS_6,
|
||||
(snipp.BODY_TRUNKVLAN % ('pcAggrIf', '')),
|
||||
base.POST],
|
||||
|
||||
[(snipp.PATH_IF % 'aggr-[po2]'),
|
||||
base.NEXUS_IP_ADDRESS_7,
|
||||
(snipp.BODY_TRUNKVLAN % ('pcAggrIf', '')),
|
||||
base.POST],
|
||||
|
||||
],
|
||||
|
||||
}
|
||||
|
||||
GET_INTERFACE_NO_TRUNK_RESPONSE = {
|
||||
"totalCount": "1",
|
||||
"imdata": [
|
||||
{
|
||||
"l1PhysIf": {
|
||||
"attributes": {
|
||||
"trunkVlans": "1-4094"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
GET_INTERFACE_PCHAN_NO_TRUNK_RESPONSE = {
|
||||
"totalCount": "1",
|
||||
"imdata": [
|
||||
{
|
||||
"pcAggrIf": {
|
||||
"attributes": {
|
||||
"trunkVlans": "1-4094"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
# Skipped inheriting event class TestCiscoNexusDeviceFailure
|
||||
# since some tests are generic and need not be executed twice
|
||||
# and some apply only to SSH driver.
|
||||
|
||||
class TestCiscoNexusRestDeviceInit(
|
||||
test_cisco_nexus_events.TestCiscoNexusDeviceInit):
|
||||
"""Verifies interface vlan allowed none is set when missing."""
|
||||
|
||||
def get_init_side_effect(
|
||||
self, action, ipaddr=None, body=None, headers=None):
|
||||
|
||||
eth_path = 'api/mo/sys/intf/phys-'
|
||||
port_chan_path = 'api/mo/sys/intf/aggr-'
|
||||
|
||||
if action == snipp.PATH_GET_NEXUS_TYPE:
|
||||
return base.GET_NEXUS_TYPE_RESPONSE
|
||||
elif action in snipp.PATH_GET_PC_MEMBERS:
|
||||
return base.GET_NO_PORT_CH_RESPONSE
|
||||
elif eth_path in action:
|
||||
return GET_INTERFACE_NO_TRUNK_RESPONSE
|
||||
elif port_chan_path in action:
|
||||
return GET_INTERFACE_PCHAN_NO_TRUNK_RESPONSE
|
||||
|
||||
return {}
|
||||
|
||||
def restapi_mock_init(self):
|
||||
|
||||
# this is to prevent interface initialization from occurring
|
||||
# which adds unnecessary noise to the results.
|
||||
|
||||
data_json = {'rest_get.side_effect':
|
||||
self.get_init_side_effect}
|
||||
self.mock_ncclient.configure_mock(**data_json)
|
||||
|
||||
def setUp(self):
|
||||
"""Sets up mock ncclient, and switch and credentials dictionaries."""
|
||||
|
||||
cfg.CONF.set_override('nexus_driver', 'restapi', 'ml2_cisco')
|
||||
cfg.CONF.set_override('never_cache_ssh_connection', False, 'ml2_cisco')
|
||||
super(TestCiscoNexusRestDeviceInit, self).setUp()
|
||||
self.results = TestCiscoNexusRestInitResults()
|
||||
|
||||
def test_verify_initialization(self):
|
||||
self._verify_results(
|
||||
self.results.get_test_results(
|
||||
'duplicate_init_port_driver_result1'))
|
||||
|
||||
|
||||
class TestCiscoNexusRestBaremetalResults(base.TestCiscoNexusBaseResults):
|
||||
|
||||
"""Unit tests driver results for Cisco ML2 Nexus."""
|
||||
|
||||
test_results = {
|
||||
|
||||
'add_port_ethernet_driver_result': [
|
||||
[snipp.PATH_VLAN_ALL,
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_VLAN_ADD % 267),
|
||||
base.POST],
|
||||
[(snipp.PATH_IF % 'phys-[eth1/10]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '+267')),
|
||||
base.POST]
|
||||
],
|
||||
|
||||
'delete_port_ethernet_driver_result': [
|
||||
[(snipp.PATH_IF % 'phys-[eth1/10]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '-267')),
|
||||
base.POST],
|
||||
[(snipp.PATH_VLAN % '267'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
'',
|
||||
base.DELETE]
|
||||
],
|
||||
|
||||
'add_port_channel_driver_result': [
|
||||
[snipp.PATH_VLAN_ALL,
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_VLAN_ADD % 267),
|
||||
base.POST],
|
||||
[(snipp.PATH_IF % 'aggr-[po469]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_TRUNKVLAN % ('pcAggrIf', '+267')),
|
||||
base.POST]
|
||||
],
|
||||
|
||||
'delete_port_channel_driver_result': [
|
||||
[(snipp.PATH_IF % 'aggr-[po469]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_TRUNKVLAN % ('pcAggrIf', '-267')),
|
||||
base.POST],
|
||||
[(snipp.PATH_VLAN % '267'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
'',
|
||||
base.DELETE]
|
||||
],
|
||||
|
||||
'add_port_ethernet_native_driver_result': [
|
||||
[snipp.PATH_VLAN_ALL,
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_VLAN_ADD % 265),
|
||||
base.POST],
|
||||
[(snipp.PATH_IF % 'phys-[eth1/10]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_NATIVE_TRUNKVLAN % ('l1PhysIf', '+265', 'vlan-265')),
|
||||
base.POST]
|
||||
],
|
||||
|
||||
'delete_port_ethernet_native_driver_result': [
|
||||
[(snipp.PATH_IF % 'phys-[eth1/10]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_NATIVE_TRUNKVLAN % ('l1PhysIf', '-265', '')),
|
||||
base.POST],
|
||||
[(snipp.PATH_VLAN % '265'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
'',
|
||||
base.DELETE]
|
||||
],
|
||||
|
||||
}
|
||||
|
||||
GET_PORT_CH_RESPONSE = {
|
||||
"totalCount": "3",
|
||||
"imdata": [
|
||||
{
|
||||
"pcRsMbrIfs": {
|
||||
"attributes": {
|
||||
"parentSKey": "po1",
|
||||
"tSKey": "eth1/11",
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"pcRsMbrIfs": {
|
||||
"attributes": {
|
||||
"parentSKey": "po469",
|
||||
"tSKey": "eth1/10",
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"pcRsMbrIfs": {
|
||||
"attributes": {
|
||||
"parentSKey": "po2",
|
||||
"tSKey": "eth1/12",
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
class TestCiscoNexusRestBaremetalDevice(
|
||||
test_cisco_nexus_events.TestCiscoNexusBaremetalDevice):
|
||||
|
||||
"""Tests for Cisco ML2 Nexus baremetal RESTAPI device driver."""
|
||||
|
||||
def get_init_side_effect(
|
||||
self, action, ipaddr=None, body=None, headers=None):
|
||||
|
||||
eth_path = 'api/mo/sys/intf/phys-'
|
||||
port_chan_path = 'api/mo/sys/intf/aggr-'
|
||||
|
||||
if action == snipp.PATH_GET_NEXUS_TYPE:
|
||||
return base.GET_NEXUS_TYPE_RESPONSE
|
||||
elif action in snipp.PATH_GET_PC_MEMBERS:
|
||||
return GET_PORT_CH_RESPONSE
|
||||
elif eth_path in action:
|
||||
return base.GET_INTERFACE_RESPONSE
|
||||
elif port_chan_path in action:
|
||||
return base.GET_INTERFACE_PCHAN_RESPONSE
|
||||
|
||||
return {}
|
||||
|
||||
def _init_port_channel(self):
|
||||
|
||||
# this is to prevent interface initialization from occurring
|
||||
# which adds unnecessary noise to the results.
|
||||
|
||||
data_json = {'rest_get.side_effect':
|
||||
self.get_init_side_effect}
|
||||
self.mock_ncclient.configure_mock(**data_json)
|
||||
|
||||
def setUp(self):
|
||||
"""Sets up mock ncclient, and switch and credentials dictionaries."""
|
||||
|
||||
cfg.CONF.set_override('nexus_driver', 'restapi', 'ml2_cisco')
|
||||
cfg.CONF.set_override('never_cache_ssh_connection', False, 'ml2_cisco')
|
||||
super(TestCiscoNexusRestBaremetalDevice, self).setUp()
|
||||
self.results = TestCiscoNexusRestBaremetalResults()
|
||||
|
||||
def test_create_delete_basic_ethernet_port(self):
|
||||
(super(TestCiscoNexusRestBaremetalDevice, self).
|
||||
test_create_delete_basic_ethernet_port())
|
||||
|
||||
def test_create_delete_basic_port_channel(self):
|
||||
(super(TestCiscoNexusRestBaremetalDevice, self).
|
||||
test_create_delete_basic_port_channel())
|
||||
|
||||
def test_create_delete_basic_eth_port_is_native(self):
|
||||
(super(TestCiscoNexusRestBaremetalDevice, self).
|
||||
test_create_delete_basic_eth_port_is_native())
|
||||
|
||||
def test_create_delete_switch_ip_not_defined(self):
|
||||
(super(TestCiscoNexusRestBaremetalDevice, self).
|
||||
test_create_delete_switch_ip_not_defined())
|
||||
|
||||
|
||||
# Skipped inheriting event class TestCiscoNexusNonCacheSshDevice
|
||||
# since it does not apply to REST API
|
|
@ -0,0 +1,255 @@
|
|||
#Copyright (c) 2017 Cisco Systems, 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.
|
||||
|
||||
"""
|
||||
VXLAN Test Class using RESTAPI Driver to test Cisco Nexus platforms.
|
||||
|
||||
These Classes are based on the original ssh VXLAN event driver
|
||||
so same tests occur with same configuration. What's different
|
||||
between the tests is the resulting driver output which is what
|
||||
the tests in this class presents to its parent class.
|
||||
|
||||
You will notice in this file there are test methods which
|
||||
are skipped by using 'pass'. This is because these tests
|
||||
apply to ssh only OR because rerunning the test would be
|
||||
redundant.
|
||||
"""
|
||||
|
||||
from oslo_config import cfg
|
||||
|
||||
from networking_cisco.plugins.ml2.drivers.cisco.nexus import (
|
||||
nexus_restapi_snippets as snipp)
|
||||
from networking_cisco.tests.unit.ml2.drivers.cisco.nexus import (
|
||||
test_cisco_nexus_base as base)
|
||||
from networking_cisco.tests.unit.ml2.drivers.cisco.nexus import (
|
||||
test_cisco_nexus_events_vxlan)
|
||||
|
||||
|
||||
class TestCiscoNexusRestVxlanResults(base.TestCiscoNexusBaseResults):
|
||||
|
||||
"""Unit tests driver results for Cisco ML2 Nexus."""
|
||||
|
||||
test_results = {
|
||||
|
||||
# The following contains desired Nexus output for
|
||||
# some basic vxlan config.
|
||||
'add_port_driver_result': [
|
||||
[(snipp.PATH_VNI_UPDATE % ('1', '70000')),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_VNI_UPDATE % (
|
||||
'70000', '70000', '70000',
|
||||
base.MCAST_GROUP)),
|
||||
base.POST],
|
||||
[snipp.PATH_VLAN_ALL,
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_VXLAN_ADD % (267, 70000)),
|
||||
base.POST],
|
||||
[(snipp.PATH_IF % 'phys-[eth1/10]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '+267')),
|
||||
base.POST]
|
||||
],
|
||||
|
||||
'delete_port_driver_result': [
|
||||
[(snipp.PATH_VNI_UPDATE % ('1', '70000')),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
'',
|
||||
base.DELETE],
|
||||
[(snipp.PATH_IF % 'phys-[eth1/10]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '-267')),
|
||||
base.POST],
|
||||
[(snipp.PATH_VLAN % '267'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
'',
|
||||
base.DELETE]
|
||||
],
|
||||
|
||||
|
||||
'add_port2_driver_result': [
|
||||
[snipp.PATH_VLAN_ALL,
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_VXLAN_ADD % (267, 70000)),
|
||||
base.POST],
|
||||
[(snipp.PATH_IF % 'phys-[eth1/20]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '+267')),
|
||||
base.POST]
|
||||
],
|
||||
|
||||
'delete_port2_driver_result': [
|
||||
[(snipp.PATH_IF % 'phys-[eth1/20]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '-267')),
|
||||
base.POST],
|
||||
],
|
||||
|
||||
'add_port_driver_result3': [
|
||||
[(snipp.PATH_VNI_UPDATE % ('1', '70000')),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_VNI_UPDATE % (
|
||||
'70000', '70000', '70000',
|
||||
base.MCAST_GROUP)),
|
||||
base.POST],
|
||||
[(snipp.PATH_VNI_UPDATE % ('1', '70000')),
|
||||
base.NEXUS_IP_ADDRESS_2,
|
||||
(snipp.BODY_VNI_UPDATE % (
|
||||
'70000', '70000', '70000',
|
||||
base.MCAST_GROUP)),
|
||||
base.POST],
|
||||
[snipp.PATH_VLAN_ALL,
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_VXLAN_ADD % (267, 70000)),
|
||||
base.POST],
|
||||
[(snipp.PATH_IF % 'phys-[eth1/10]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '+267')),
|
||||
base.POST],
|
||||
[snipp.PATH_VLAN_ALL,
|
||||
base.NEXUS_IP_ADDRESS_2,
|
||||
(snipp.BODY_VXLAN_ADD % (267, 70000)),
|
||||
base.POST],
|
||||
[(snipp.PATH_IF % 'phys-[eth1/2]'),
|
||||
base.NEXUS_IP_ADDRESS_2,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '+267')),
|
||||
base.POST],
|
||||
[snipp.PATH_VLAN_ALL,
|
||||
base.NEXUS_IP_ADDRESS_2,
|
||||
(snipp.BODY_VXLAN_ADD % (267, 70000)),
|
||||
base.POST],
|
||||
[(snipp.PATH_IF % 'phys-[eth1/3]'),
|
||||
base.NEXUS_IP_ADDRESS_2,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '+267')),
|
||||
base.POST]
|
||||
],
|
||||
|
||||
'delete_port_driver_result3': [
|
||||
[(snipp.PATH_VNI_UPDATE % ('1', '70000')),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
'',
|
||||
base.DELETE],
|
||||
[(snipp.PATH_VNI_UPDATE % ('1', '70000')),
|
||||
base.NEXUS_IP_ADDRESS_2,
|
||||
'',
|
||||
base.DELETE],
|
||||
|
||||
[(snipp.PATH_IF % 'phys-[eth1/10]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '-267')),
|
||||
base.POST],
|
||||
[(snipp.PATH_VLAN % '267'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
'',
|
||||
base.DELETE],
|
||||
[(snipp.PATH_IF % 'phys-[eth1/2]'),
|
||||
base.NEXUS_IP_ADDRESS_2,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '-267')),
|
||||
base.POST],
|
||||
[(snipp.PATH_VLAN % '267'),
|
||||
base.NEXUS_IP_ADDRESS_2,
|
||||
'',
|
||||
base.DELETE],
|
||||
[(snipp.PATH_IF % 'phys-[eth1/3]'),
|
||||
base.NEXUS_IP_ADDRESS_2,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '-267')),
|
||||
base.POST]
|
||||
],
|
||||
|
||||
'add_port_driver_result2': [
|
||||
[(snipp.PATH_VNI_UPDATE % ('1', '70001')),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_VNI_UPDATE % (
|
||||
'70001', '70001', '70001',
|
||||
base.MCAST_GROUP)),
|
||||
base.POST],
|
||||
[snipp.PATH_VLAN_ALL,
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_VXLAN_ADD % (265, 70001)),
|
||||
base.POST],
|
||||
[(snipp.PATH_IF % 'phys-[eth1/20]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '+265')),
|
||||
base.POST]
|
||||
],
|
||||
|
||||
'delete_port_driver_result2': [
|
||||
[(snipp.PATH_VNI_UPDATE % ('1', '70001')),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
'',
|
||||
base.DELETE],
|
||||
[(snipp.PATH_IF % 'phys-[eth1/20]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '-265')),
|
||||
base.POST],
|
||||
[(snipp.PATH_VLAN % '265'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
'',
|
||||
base.DELETE]
|
||||
],
|
||||
|
||||
}
|
||||
|
||||
|
||||
class TestCiscoNexusRestVxlanDevice(
|
||||
test_cisco_nexus_events_vxlan.TestCiscoNexusVxlanDevice):
|
||||
|
||||
"""Unit tests for Cisco ML2 VXLAN Nexus device driver."""
|
||||
|
||||
def setUp(self):
|
||||
"""Sets up mock ncclient, and switch and credentials dictionaries."""
|
||||
|
||||
cfg.CONF.set_override('nexus_driver', 'restapi', 'ml2_cisco')
|
||||
cfg.CONF.set_override('never_cache_ssh_connection', False, 'ml2_cisco')
|
||||
super(TestCiscoNexusRestVxlanDevice, self).setUp()
|
||||
self.mock_ncclient.reset_mock()
|
||||
self.addCleanup(self._clear_nve_db)
|
||||
self.results = TestCiscoNexusRestVxlanResults()
|
||||
|
||||
def test_enable_vxlan_feature_failure(self):
|
||||
pass
|
||||
|
||||
def test_disable_vxlan_feature_failure(self):
|
||||
pass
|
||||
|
||||
def test_create_nve_member_failure(self):
|
||||
pass
|
||||
|
||||
def test_delete_nve_member_failure(self):
|
||||
pass
|
||||
|
||||
def test_nexus_vxlan_one_network_two_hosts(self):
|
||||
(super(TestCiscoNexusRestVxlanDevice, self).
|
||||
test_nexus_vxlan_one_network_two_hosts())
|
||||
|
||||
def test_nexus_missing_vxlan_fields(self):
|
||||
pass
|
||||
|
||||
def test_nexus_vxlan_bind_port(self):
|
||||
pass
|
||||
|
||||
def test_nexus_vxlan_bind_port_no_physnet(self):
|
||||
pass
|
||||
|
||||
def test_nexus_vxlan_bind_port_no_dynamic_segment(self):
|
||||
pass
|
||||
|
||||
def test_nexus_vxlan_one_network(self):
|
||||
(super(TestCiscoNexusRestVxlanDevice, self).
|
||||
test_nexus_vxlan_one_network())
|
||||
|
||||
def test_nexus_vxlan_two_network(self):
|
||||
(super(TestCiscoNexusRestVxlanDevice, self).
|
||||
test_nexus_vxlan_two_network())
|
|
@ -0,0 +1,644 @@
|
|||
# Copyright (c) 2017 Cisco Systems, 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.
|
||||
|
||||
"""
|
||||
Replay Test Classes using RESTAPI Driver to test Cisco Nexus platforms.
|
||||
|
||||
These Classes are based on the original ssh event driver so same
|
||||
tests occur with same configuration. What's different between
|
||||
the tests is the resulting driver output which is what
|
||||
the tests in this class presents to its parent class.
|
||||
|
||||
You will notice in this file there are test methods which
|
||||
are skipped by using 'pass'. This is because these tests
|
||||
apply to ssh only OR because rerunning the test would be
|
||||
redundant.
|
||||
"""
|
||||
|
||||
|
||||
from oslo_config import cfg
|
||||
|
||||
from networking_cisco.plugins.ml2.drivers.cisco.nexus import (
|
||||
nexus_restapi_snippets as snipp)
|
||||
from networking_cisco.tests.unit.ml2.drivers.cisco.nexus import (
|
||||
test_cisco_nexus_base as base)
|
||||
from networking_cisco.tests.unit.ml2.drivers.cisco.nexus import (
|
||||
test_cisco_nexus_replay)
|
||||
|
||||
|
||||
class TestCiscoNexusRestReplayResults(base.TestCiscoNexusBaseResults):
|
||||
|
||||
"""Unit tests driver results for Cisco ML2 Nexus."""
|
||||
|
||||
test_results = {
|
||||
|
||||
'driver_result_unique_init': [
|
||||
[(snipp.PATH_IF % 'phys-[eth1/10]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '')),
|
||||
base.POST],
|
||||
],
|
||||
|
||||
'driver_result_unique_add1': [
|
||||
[snipp.PATH_VLAN_ALL,
|
||||
None,
|
||||
(snipp.BODY_VLAN_ADD % 267),
|
||||
base.POST],
|
||||
[(snipp.PATH_IF % 'phys-[eth1/10]'),
|
||||
None,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '+267')),
|
||||
base.POST]
|
||||
],
|
||||
|
||||
'driver_result_unique_add2': [
|
||||
[snipp.PATH_VLAN_ALL,
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_VLAN_ADD % 265),
|
||||
base.POST],
|
||||
[(snipp.PATH_IF % 'phys-[eth1/10]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '+265')),
|
||||
base.POST]
|
||||
],
|
||||
|
||||
'driver_result_unique_del1': [
|
||||
[(snipp.PATH_IF % 'phys-[eth1/10]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '-265')),
|
||||
base.POST],
|
||||
[(snipp.PATH_VLAN % '265'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
'',
|
||||
base.DELETE]
|
||||
],
|
||||
|
||||
'driver_result_unique_del2': [
|
||||
[(snipp.PATH_IF % 'phys-[eth1/10]'),
|
||||
None,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '-267')),
|
||||
base.POST],
|
||||
[(snipp.PATH_VLAN % '267'),
|
||||
None,
|
||||
'',
|
||||
base.DELETE]
|
||||
],
|
||||
|
||||
'driver_result_unique_2vlan_replay': [
|
||||
[(snipp.PATH_IF % 'phys-[eth1/10]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '+265,267')),
|
||||
base.POST],
|
||||
[snipp.PATH_VLAN_ALL,
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_VLAN_ADD_START % 265) + (
|
||||
snipp.BODY_VLAN_ADD_NEXT % 267) + snipp.BODY_VLAN_ALL_END,
|
||||
base.POST]
|
||||
],
|
||||
|
||||
'dupl_vlan_result1_add': [
|
||||
[snipp.PATH_VLAN_ALL,
|
||||
base.NEXUS_IP_ADDRESS_2,
|
||||
(snipp.BODY_VLAN_ADD % 267),
|
||||
base.POST],
|
||||
[(snipp.PATH_IF % 'phys-[eth1/10]'),
|
||||
base.NEXUS_IP_ADDRESS_2,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '+267')),
|
||||
base.POST],
|
||||
[snipp.PATH_VLAN_ALL,
|
||||
base.NEXUS_IP_ADDRESS_2,
|
||||
(snipp.BODY_VLAN_ADD % 267),
|
||||
base.POST],
|
||||
[(snipp.PATH_IF % 'phys-[eth1/20]'),
|
||||
base.NEXUS_IP_ADDRESS_2,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '+267')),
|
||||
base.POST]
|
||||
],
|
||||
|
||||
'dupl_vlan_result2_add': [
|
||||
[snipp.PATH_VLAN_ALL,
|
||||
base.NEXUS_IP_ADDRESS_2,
|
||||
(snipp.BODY_VLAN_ADD % 267),
|
||||
base.POST],
|
||||
[(snipp.PATH_IF % 'phys-[eth1/10]'),
|
||||
base.NEXUS_IP_ADDRESS_2,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '+267')),
|
||||
base.POST],
|
||||
[(snipp.PATH_IF % 'phys-[eth1/20]'),
|
||||
base.NEXUS_IP_ADDRESS_2,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '+267')),
|
||||
base.POST]
|
||||
],
|
||||
|
||||
'dupl_vlan_result2_del': [
|
||||
[(snipp.PATH_IF % 'phys-[eth1/10]'),
|
||||
base.NEXUS_IP_ADDRESS_2,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '-267')),
|
||||
base.POST],
|
||||
[(snipp.PATH_VLAN % '267'),
|
||||
base.NEXUS_IP_ADDRESS_2,
|
||||
'',
|
||||
base.DELETE],
|
||||
[(snipp.PATH_IF % 'phys-[eth1/20]'),
|
||||
base.NEXUS_IP_ADDRESS_2,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '-267')),
|
||||
base.POST]
|
||||
],
|
||||
|
||||
'dupl_vlan_result_replay': [
|
||||
[(snipp.PATH_IF % 'phys-[eth1/10]'),
|
||||
base.NEXUS_IP_ADDRESS_2,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '+267')),
|
||||
base.POST],
|
||||
[(snipp.PATH_IF % 'phys-[eth1/20]'),
|
||||
base.NEXUS_IP_ADDRESS_2,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '+267')),
|
||||
base.POST],
|
||||
[snipp.PATH_VLAN_ALL,
|
||||
base.NEXUS_IP_ADDRESS_2,
|
||||
(snipp.BODY_VLAN_ADD % 267),
|
||||
base.POST],
|
||||
],
|
||||
|
||||
'dupl_port_result_replay': [
|
||||
[(snipp.PATH_IF % 'phys-[eth1/10]'),
|
||||
base.NEXUS_IP_ADDRESS_3,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '+267')),
|
||||
base.POST],
|
||||
[snipp.PATH_VLAN_ALL,
|
||||
base.NEXUS_IP_ADDRESS_3,
|
||||
(snipp.BODY_VLAN_ADD % 267),
|
||||
base.POST],
|
||||
],
|
||||
|
||||
'switch_up_result_add': [
|
||||
[snipp.PATH_VLAN_ALL,
|
||||
base.NEXUS_IP_ADDRESS_DUAL,
|
||||
(snipp.BODY_VLAN_ADD % 269),
|
||||
base.POST],
|
||||
[(snipp.PATH_IF % 'phys-[eth1/3]'),
|
||||
base.NEXUS_IP_ADDRESS_DUAL,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '+269')),
|
||||
base.POST]
|
||||
],
|
||||
|
||||
'switch_up_result_del': [
|
||||
[(snipp.PATH_IF % 'phys-[eth1/3]'),
|
||||
base.NEXUS_IP_ADDRESS_DUAL,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '-269')),
|
||||
base.POST],
|
||||
[(snipp.PATH_VLAN % '269'),
|
||||
base.NEXUS_IP_ADDRESS_DUAL,
|
||||
'',
|
||||
base.DELETE]
|
||||
],
|
||||
|
||||
'switch_restore_result_add': [
|
||||
[snipp.PATH_VLAN_ALL,
|
||||
base.NEXUS_IP_ADDRESS_DUAL,
|
||||
(snipp.BODY_VLAN_ADD % 269),
|
||||
base.POST],
|
||||
[(snipp.PATH_IF % 'phys-[eth1/3]'),
|
||||
base.NEXUS_IP_ADDRESS_DUAL,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '+269')),
|
||||
base.POST]
|
||||
],
|
||||
|
||||
'switch_restore_result_replay': [
|
||||
[(snipp.PATH_IF % 'phys-[eth1/2]'),
|
||||
base.NEXUS_IP_ADDRESS_DUAL2,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '+269')),
|
||||
base.POST],
|
||||
[snipp.PATH_VLAN_ALL,
|
||||
base.NEXUS_IP_ADDRESS_DUAL2,
|
||||
(snipp.BODY_VLAN_ADD % 269),
|
||||
base.POST]
|
||||
],
|
||||
|
||||
'switch_restore_result_del': [
|
||||
[(snipp.PATH_IF % 'phys-[eth1/3]'),
|
||||
base.NEXUS_IP_ADDRESS_DUAL,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '-269')),
|
||||
base.POST],
|
||||
[(snipp.PATH_VLAN % '269'),
|
||||
base.NEXUS_IP_ADDRESS_DUAL,
|
||||
'',
|
||||
base.DELETE],
|
||||
[(snipp.PATH_IF % 'phys-[eth1/2]'),
|
||||
base.NEXUS_IP_ADDRESS_DUAL2,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '-269')),
|
||||
base.POST],
|
||||
[(snipp.PATH_VLAN % '269'),
|
||||
base.NEXUS_IP_ADDRESS_DUAL2,
|
||||
'',
|
||||
base.DELETE]
|
||||
],
|
||||
|
||||
}
|
||||
|
||||
|
||||
class TestCiscoNexusRestReplay(test_cisco_nexus_replay.TestCiscoNexusReplay):
|
||||
"""Unit tests for Replay of Cisco ML2 Nexus data."""
|
||||
|
||||
def setUp(self):
|
||||
"""Sets up mock ncclient, and switch and credentials dictionaries."""
|
||||
|
||||
cfg.CONF.set_override('nexus_driver', 'restapi', 'ml2_cisco')
|
||||
cfg.CONF.set_override('never_cache_ssh_connection', False, 'ml2_cisco')
|
||||
super(TestCiscoNexusRestReplay, self).setUp()
|
||||
self.results = TestCiscoNexusRestReplayResults()
|
||||
|
||||
def test_replay_unique_ports(self):
|
||||
super(TestCiscoNexusRestReplay, self).test_replay_unique_ports()
|
||||
|
||||
def test_replay_duplicate_vlan(self):
|
||||
super(TestCiscoNexusRestReplay, self).test_replay_duplicate_vlan()
|
||||
|
||||
def test_replay_duplicate_ports(self):
|
||||
super(TestCiscoNexusRestReplay, self).test_replay_duplicate_ports()
|
||||
|
||||
def test_replay_enable_vxlan_feature_failure(self):
|
||||
pass
|
||||
|
||||
def test_replay_disable_vxlan_feature_failure(self):
|
||||
pass
|
||||
|
||||
def test_replay_create_nve_member_failure(self):
|
||||
pass
|
||||
|
||||
def test_replay_delete_nve_member_failure(self):
|
||||
pass
|
||||
|
||||
def test_replay_create_vlan_failure(self):
|
||||
pass
|
||||
|
||||
def test_replay_delete_vlan_failure(self):
|
||||
pass
|
||||
|
||||
def test_replay_create_trunk_failure(self):
|
||||
pass
|
||||
|
||||
def test_replay_delete_trunk_failure(self):
|
||||
pass
|
||||
|
||||
def test_replay_new_port_success_if_one_switch_up(self):
|
||||
(super(TestCiscoNexusRestReplay, self).
|
||||
test_replay_new_port_success_if_one_switch_up())
|
||||
|
||||
def test_replay_port_success_if_one_switch_restored(self):
|
||||
(super(TestCiscoNexusRestReplay, self).
|
||||
test_replay_port_success_if_one_switch_restored())
|
||||
|
||||
def test_replay_create_fails_if_single_switch_down(self):
|
||||
(super(TestCiscoNexusRestReplay, self).
|
||||
test_replay_create_fails_if_single_switch_down())
|
||||
|
||||
def test_replay_update_fails_if_single_switch_down(self):
|
||||
(super(TestCiscoNexusRestReplay, self).
|
||||
test_replay_update_fails_if_single_switch_down())
|
||||
|
||||
def test_replay_delete_success_if_switch_down(self):
|
||||
(super(TestCiscoNexusRestReplay, self).
|
||||
test_replay_delete_success_if_switch_down())
|
||||
|
||||
def test_replay_get_nexus_type_failure_two_switches(self):
|
||||
pass
|
||||
|
||||
def test_replay_get_nexus_type_failure(self):
|
||||
pass
|
||||
|
||||
def test_replay_create_vlan_failure_during_replay(self):
|
||||
pass
|
||||
|
||||
def test_replay_vlan_batch_failure_during_replay(self):
|
||||
pass
|
||||
|
||||
def test_replay_no_retry_failure_handling(self):
|
||||
pass
|
||||
|
||||
|
||||
class TestCiscoNexusRestBaremetalReplayResults(base.TestCiscoNexusBaseResults):
|
||||
|
||||
"""Unit tests driver results for Cisco ML2 Nexus."""
|
||||
|
||||
test_results = {
|
||||
|
||||
'driver_result_unique_init': [
|
||||
[(snipp.PATH_IF % 'phys-[eth1/10]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '')),
|
||||
base.POST],
|
||||
],
|
||||
|
||||
'driver_result_unique_eth_add1': [
|
||||
[snipp.PATH_VLAN_ALL,
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_VLAN_ADD % 267),
|
||||
base.POST],
|
||||
[(snipp.PATH_IF % 'phys-[eth1/10]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '+267')),
|
||||
base.POST]
|
||||
],
|
||||
|
||||
'driver_result_unique_eth_add2': [
|
||||
[snipp.PATH_VLAN_ALL,
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_VLAN_ADD % 265),
|
||||
base.POST],
|
||||
[(snipp.PATH_IF % 'phys-[eth1/10]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '+265')),
|
||||
base.POST]
|
||||
],
|
||||
|
||||
'driver_result_unique_eth_del1': [
|
||||
[(snipp.PATH_IF % 'phys-[eth1/10]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '-265')),
|
||||
base.POST],
|
||||
[(snipp.PATH_VLAN % '265'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
'',
|
||||
base.DELETE]
|
||||
],
|
||||
|
||||
'driver_result_unique_eth_del2': [
|
||||
[(snipp.PATH_IF % 'phys-[eth1/10]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '-267')),
|
||||
base.POST],
|
||||
[(snipp.PATH_VLAN % '267'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
'',
|
||||
base.DELETE]
|
||||
],
|
||||
|
||||
'driver_result_unique_vPC_init': [
|
||||
[(snipp.PATH_IF % 'aggr--[po469]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_TRUNKVLAN % ('pcAggrIf', '')),
|
||||
base.POST],
|
||||
],
|
||||
|
||||
'driver_result_unique_vPC_add1': [
|
||||
[snipp.PATH_VLAN_ALL,
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_VLAN_ADD % 267),
|
||||
base.POST],
|
||||
[(snipp.PATH_IF % 'aggr-[po469]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_TRUNKVLAN % ('pcAggrIf', '+267')),
|
||||
base.POST]
|
||||
],
|
||||
|
||||
'driver_result_unique_vPC_add2': [
|
||||
[snipp.PATH_VLAN_ALL,
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_VLAN_ADD % 265),
|
||||
base.POST],
|
||||
[(snipp.PATH_IF % 'aggr-[po469]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_TRUNKVLAN % ('pcAggrIf', '+265')),
|
||||
base.POST]
|
||||
],
|
||||
|
||||
'driver_result_unique_vPC_del1': [
|
||||
[(snipp.PATH_IF % 'aggr-[po469]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_TRUNKVLAN % ('pcAggrIf', '-265')),
|
||||
base.POST],
|
||||
[(snipp.PATH_VLAN % '265'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
'',
|
||||
base.DELETE]
|
||||
],
|
||||
|
||||
'driver_result_unique_vPC_del2': [
|
||||
[(snipp.PATH_IF % 'aggr-[po469]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_TRUNKVLAN % ('pcAggrIf', '-267')),
|
||||
base.POST],
|
||||
[(snipp.PATH_VLAN % '267'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
'',
|
||||
base.DELETE]
|
||||
],
|
||||
|
||||
'driver_result_unique_native_port_ethernet_add': [
|
||||
[snipp.PATH_VLAN_ALL,
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_VLAN_ADD % 265),
|
||||
base.POST],
|
||||
[(snipp.PATH_IF % 'phys-[eth1/10]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_NATIVE_TRUNKVLAN % ('l1PhysIf', '+265', 'vlan-265')),
|
||||
base.POST]
|
||||
],
|
||||
|
||||
'driver_result_unique_native_port_ethernet_del': [
|
||||
[(snipp.PATH_IF % 'phys-[eth1/10]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_NATIVE_TRUNKVLAN % ('l1PhysIf', '-265', '')),
|
||||
base.POST],
|
||||
[(snipp.PATH_VLAN % '265'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
'',
|
||||
base.DELETE]
|
||||
],
|
||||
|
||||
'driver_result_unique_2vlan_replay': [
|
||||
[(snipp.PATH_IF % 'phys-[eth1/10]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '+265,267')),
|
||||
base.POST],
|
||||
[snipp.PATH_VLAN_ALL,
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_VLAN_ADD_START % 265) + (
|
||||
snipp.BODY_VLAN_ADD_NEXT % 267) + snipp.BODY_VLAN_ALL_END,
|
||||
base.POST]
|
||||
],
|
||||
|
||||
'driver_result_unique_2vlan_vpc_replay': [
|
||||
[(snipp.PATH_IF % 'aggr-[po469]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_TRUNKVLAN % ('pcAggrIf', '+265,267')),
|
||||
base.POST],
|
||||
[snipp.PATH_VLAN_ALL,
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_VLAN_ADD_START % 265) + (
|
||||
snipp.BODY_VLAN_ADD_NEXT % 267) + snipp.BODY_VLAN_ALL_END,
|
||||
base.POST]
|
||||
],
|
||||
|
||||
'driver_result_unique_vPC470_del1': [
|
||||
[(snipp.PATH_IF % 'aggr-[po470]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_TRUNKVLAN % ('pcAggrIf', '-265')),
|
||||
base.POST],
|
||||
[(snipp.PATH_VLAN % '265'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
'',
|
||||
base.DELETE]
|
||||
],
|
||||
|
||||
'driver_result_unique_vPC470_del2': [
|
||||
[(snipp.PATH_IF % 'aggr-[po470]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_TRUNKVLAN % ('pcAggrIf', '-267')),
|
||||
base.POST],
|
||||
[(snipp.PATH_VLAN % '267'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
'',
|
||||
base.DELETE]
|
||||
],
|
||||
|
||||
'driver_result_unique_vPC470_2vlan_replay': [
|
||||
[(snipp.PATH_IF % 'aggr-[po470]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_TRUNKVLAN % ('pcAggrIf', '+265,267')),
|
||||
base.POST],
|
||||
[snipp.PATH_VLAN_ALL,
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_VLAN_ADD_START % 265) + (
|
||||
snipp.BODY_VLAN_ADD_NEXT % 267) + snipp.BODY_VLAN_ALL_END,
|
||||
base.POST]
|
||||
],
|
||||
|
||||
'driver_result_unique_2vlan_vpc_enchg_replay': [
|
||||
[(snipp.PATH_IF % 'phys-[eth1/10]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '+265,267')),
|
||||
base.POST],
|
||||
[snipp.PATH_VLAN_ALL,
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_VLAN_ADD_START % 265) + (
|
||||
snipp.BODY_VLAN_ADD_NEXT % 267) + snipp.BODY_VLAN_ALL_END,
|
||||
base.POST]
|
||||
],
|
||||
|
||||
'driver_result_unique_native_2vlan_replay': [
|
||||
[(snipp.PATH_IF % 'phys-[eth1/10]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_NATIVE_TRUNKVLAN % ('l1PhysIf', '+265', 'vlan-265')),
|
||||
base.POST],
|
||||
[(snipp.PATH_IF % 'phys-[eth1/10]'),
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_TRUNKVLAN % ('l1PhysIf', '+265,267')),
|
||||
base.POST],
|
||||
[snipp.PATH_VLAN_ALL,
|
||||
base.NEXUS_IP_ADDRESS_1,
|
||||
(snipp.BODY_VLAN_ADD_START % 265) + (
|
||||
snipp.BODY_VLAN_ADD_NEXT % 267) + snipp.BODY_VLAN_ALL_END,
|
||||
base.POST]
|
||||
]
|
||||
|
||||
}
|
||||
|
||||
|
||||
GET_PORT_CH_RESPONSE = {
|
||||
"totalCount": "3",
|
||||
"imdata": [
|
||||
{
|
||||
"pcRsMbrIfs": {
|
||||
"attributes": {
|
||||
"parentSKey": "po1",
|
||||
"tSKey": "eth1/11",
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"pcRsMbrIfs": {
|
||||
"attributes": {
|
||||
"parentSKey": "po469",
|
||||
"tSKey": "eth1/10",
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"pcRsMbrIfs": {
|
||||
"attributes": {
|
||||
"parentSKey": "po2",
|
||||
"tSKey": "eth1/12",
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
class TestCiscoNexusRestBaremetalReplay(
|
||||
test_cisco_nexus_replay.TestCiscoNexusBaremetalReplay):
|
||||
|
||||
def get_init_side_effect(
|
||||
self, action, ipaddr=None, body=None, headers=None):
|
||||
|
||||
eth_path = 'api/mo/sys/intf/phys-'
|
||||
port_chan_path = 'api/mo/sys/intf/aggr-'
|
||||
|
||||
if action == snipp.PATH_GET_NEXUS_TYPE:
|
||||
return base.GET_NEXUS_TYPE_RESPONSE
|
||||
elif action in snipp.PATH_GET_PC_MEMBERS:
|
||||
return GET_PORT_CH_RESPONSE
|
||||
elif eth_path in action:
|
||||
return base.GET_INTERFACE_RESPONSE
|
||||
elif port_chan_path in action:
|
||||
return base.GET_INTERFACE_PCHAN_RESPONSE
|
||||
|
||||
return {}
|
||||
|
||||
def _init_port_channel(self, ch_grp):
|
||||
|
||||
# this is to prevent interface initialization from occurring
|
||||
# which adds unnecessary noise to the results.
|
||||
|
||||
GET_PORT_CH_RESPONSE['imdata'][1]['pcRsMbrIfs'][
|
||||
'attributes']['parentSKey'] = ('po' + str(ch_grp))
|
||||
data_json = {'rest_get.side_effect':
|
||||
self.get_init_side_effect}
|
||||
self.mock_ncclient.configure_mock(**data_json)
|
||||
|
||||
def setUp(self):
|
||||
"""Sets up mock ncclient, and switch and credentials dictionaries."""
|
||||
|
||||
cfg.CONF.set_override('nexus_driver', 'restapi', 'ml2_cisco')
|
||||
cfg.CONF.set_override('never_cache_ssh_connection', False, 'ml2_cisco')
|
||||
super(TestCiscoNexusRestBaremetalReplay, self).setUp()
|
||||
self.results = TestCiscoNexusRestBaremetalReplayResults()
|
||||
|
||||
def test_replay_unique_ethernet_ports(self):
|
||||
(super(TestCiscoNexusRestBaremetalReplay, self).
|
||||
test_replay_unique_ethernet_ports())
|
||||
|
||||
def test_replay_unique_vPC_ports(self):
|
||||
(super(TestCiscoNexusRestBaremetalReplay, self).
|
||||
test_replay_unique_vPC_ports())
|
||||
|
||||
def test_replay_unique_vPC_ports_chg_vPC_nbr(self):
|
||||
(super(TestCiscoNexusRestBaremetalReplay, self).
|
||||
test_replay_unique_vPC_ports_chg_vPC_nbr())
|
||||
|
||||
def test_replay_unique_vPC_ports_chg_to_enet(self):
|
||||
(super(TestCiscoNexusRestBaremetalReplay, self).
|
||||
test_replay_unique_vPC_ports_chg_to_enet())
|
||||
|
||||
def test_replay_unique_native_nonnative_ethernet_ports(self):
|
||||
(super(TestCiscoNexusRestBaremetalReplay, self).
|
||||
test_replay_unique_native_nonnative_ethernet_ports())
|
||||
|
||||
|
||||
#The tests in class below is reproduced this is does not apply to restapis.
|
||||
#class TestCiscoNexusNonCachedSshReplay(
|
||||
# test_cisco_nexus_base.TestCiscoNexusReplayBase):
|
|
@ -101,6 +101,10 @@ neutronclient.extension =
|
|||
policy_profile = networking_cisco.neutronclient.policyprofile
|
||||
network_profile = networking_cisco.neutronclient.networkprofile
|
||||
|
||||
networking_cisco.ml2.nexus_driver =
|
||||
ncclient = networking_cisco.plugins.ml2.drivers.cisco.nexus.nexus_network_driver:CiscoNexusSshDriver
|
||||
restapi = networking_cisco.plugins.ml2.drivers.cisco.nexus.nexus_restapi_network_driver:CiscoNexusRestapiDriver
|
||||
|
||||
# Extension Firewall drivers for SAF
|
||||
services.firewall.native.drivers =
|
||||
native = networking_cisco.apps.saf.server.services.firewall.native.drivers.native:NativeFirewall
|
||||
|
|
Loading…
Reference in New Issue