Merge "Implement Rest API in ML2 Nexus Driver"
This commit is contained in:
commit
eb95a7d2de
|
@ -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