Nexus MD: Neutron trunk support
Add neutron trunk support to the cisco_nexus mechanism driver. For baremetal deployments, the setting of 'switchport...native' is now set for a trunk's parent port (also the vlan associated with the trunk's parent port will also be configured as 'allowed'). All other ports (trunk subports) will be set as 'allowed'. VM deployments nexus switchport setting isn't changed by this patchset. Change-Id: I0992312dfba5c58302b050d409bbbb3d180ea0a0
This commit is contained in:
parent
ffb7d971bb
commit
dbcdea1275
|
@ -54,6 +54,9 @@ else:
|
||||||
if NEUTRON_VERSION >= NEUTRON_OCATA_VERSION:
|
if NEUTRON_VERSION >= NEUTRON_OCATA_VERSION:
|
||||||
from neutron.db.models import agent as agent_model
|
from neutron.db.models import agent as agent_model
|
||||||
from neutron.db.models import l3 as l3_models
|
from neutron.db.models import l3 as l3_models
|
||||||
|
from neutron.objects import trunk as trunk_objects
|
||||||
|
from neutron.services.trunk import constants as trunk_consts
|
||||||
|
from neutron.services.trunk.drivers import base as trunk_base
|
||||||
from neutron_lib.api.definitions import portbindings
|
from neutron_lib.api.definitions import portbindings
|
||||||
from neutron_lib.api.definitions import provider_net as providernet
|
from neutron_lib.api.definitions import provider_net as providernet
|
||||||
from neutron_lib.api import extensions
|
from neutron_lib.api import extensions
|
||||||
|
@ -85,6 +88,13 @@ if NEUTRON_VERSION >= NEUTRON_OCATA_VERSION:
|
||||||
def get_novaclient_images(nclient):
|
def get_novaclient_images(nclient):
|
||||||
return nclient.glance
|
return nclient.glance
|
||||||
else:
|
else:
|
||||||
|
from networking_cisco.services.trunk import ( # noqa
|
||||||
|
trunkstubs as trunk_objects) # noqa
|
||||||
|
from networking_cisco.services.trunk import ( # noqa
|
||||||
|
trunkstubs as trunk_consts) # noqa
|
||||||
|
from networking_cisco.services.trunk import ( # noqa
|
||||||
|
trunkstubs as trunk_base) # noqa
|
||||||
|
|
||||||
from neutron.api import extensions # noqa
|
from neutron.api import extensions # noqa
|
||||||
from neutron.api.v2 import attributes as attr
|
from neutron.api.v2 import attributes as attr
|
||||||
from neutron.common import utils as common_utils # noqa
|
from neutron.common import utils as common_utils # noqa
|
||||||
|
|
|
@ -28,6 +28,7 @@ NVE_SRC_INTF = 'nve_src_intf'
|
||||||
|
|
||||||
NETWORK_ADMIN = 'network_admin'
|
NETWORK_ADMIN = 'network_admin'
|
||||||
|
|
||||||
|
CISCO_NEXUS_ML2_MECH_DRIVER_V2 = 'cisco_nexus'
|
||||||
TYPE_NEXUS_VXLAN = 'nexus_vxlan'
|
TYPE_NEXUS_VXLAN = 'nexus_vxlan'
|
||||||
|
|
||||||
# TODO(rpothier) Add back in provider segment support.
|
# TODO(rpothier) Add back in provider segment support.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Copyright (c) 2013-2016 Cisco Systems, Inc.
|
# Copyright (c) 2013-2017 Cisco Systems, Inc.
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
@ -51,6 +51,8 @@ from networking_cisco.plugins.ml2.drivers.cisco.nexus import (
|
||||||
nexus_db_v2 as nxos_db)
|
nexus_db_v2 as nxos_db)
|
||||||
from networking_cisco.plugins.ml2.drivers.cisco.nexus import (
|
from networking_cisco.plugins.ml2.drivers.cisco.nexus import (
|
||||||
nexus_helpers as nexus_help)
|
nexus_helpers as nexus_help)
|
||||||
|
from networking_cisco.plugins.ml2.drivers.cisco.nexus import trunk
|
||||||
|
from networking_cisco.services.trunk import nexus_trunk
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
@ -338,6 +340,8 @@ class CiscoNexusMechanismDriver(api.MechanismDriver):
|
||||||
self.monitor_timeout = conf.cfg.CONF.ml2_cisco.switch_heartbeat_time
|
self.monitor_timeout = conf.cfg.CONF.ml2_cisco.switch_heartbeat_time
|
||||||
self.monitor_lock = threading.Lock()
|
self.monitor_lock = threading.Lock()
|
||||||
self.context = bc.get_context()
|
self.context = bc.get_context()
|
||||||
|
self.trunk = trunk.NexusMDTrunkHandler()
|
||||||
|
nexus_trunk.NexusTrunkDriver.create()
|
||||||
LOG.info(_LI("CiscoNexusMechanismDriver: initialize() called "
|
LOG.info(_LI("CiscoNexusMechanismDriver: initialize() called "
|
||||||
"pid %(pid)d thid %(tid)d"), {'pid': self._ppid,
|
"pid %(pid)d thid %(tid)d"), {'pid': self._ppid,
|
||||||
'tid': threading.current_thread().ident})
|
'tid': threading.current_thread().ident})
|
||||||
|
@ -510,6 +514,12 @@ class CiscoNexusMechanismDriver(api.MechanismDriver):
|
||||||
|
|
||||||
return switch_connections
|
return switch_connections
|
||||||
|
|
||||||
|
def _get_port_uuid(self, port):
|
||||||
|
# Trunk subport's don't have the 'device_id' set so use port 'id'
|
||||||
|
# as the UUID.
|
||||||
|
uuid_key = 'id' if self.trunk.is_trunk_subport(port) else 'device_id'
|
||||||
|
return port.get(uuid_key)
|
||||||
|
|
||||||
def _valid_network_segment(self, segment):
|
def _valid_network_segment(self, segment):
|
||||||
return (cfg.CONF.ml2_cisco.managed_physical_network is None or
|
return (cfg.CONF.ml2_cisco.managed_physical_network is None or
|
||||||
cfg.CONF.ml2_cisco.managed_physical_network ==
|
cfg.CONF.ml2_cisco.managed_physical_network ==
|
||||||
|
@ -520,29 +530,17 @@ class CiscoNexusMechanismDriver(api.MechanismDriver):
|
||||||
port['device_owner'].startswith('baremetal') or
|
port['device_owner'].startswith('baremetal') or
|
||||||
port['device_owner'].startswith('manila') or
|
port['device_owner'].startswith('manila') or
|
||||||
port['device_owner'] in [
|
port['device_owner'] in [
|
||||||
|
bc.trunk_consts.TRUNK_SUBPORT_OWNER,
|
||||||
bc.constants.DEVICE_OWNER_DHCP,
|
bc.constants.DEVICE_OWNER_DHCP,
|
||||||
bc.constants.DEVICE_OWNER_ROUTER_INTF,
|
bc.constants.DEVICE_OWNER_ROUTER_INTF,
|
||||||
bc.constants.DEVICE_OWNER_ROUTER_GW,
|
bc.constants.DEVICE_OWNER_ROUTER_GW,
|
||||||
bc.constants.DEVICE_OWNER_ROUTER_HA_INTF])
|
bc.constants.DEVICE_OWNER_ROUTER_HA_INTF])
|
||||||
|
|
||||||
def _is_status_active(self, port):
|
def _is_status_down(self, port):
|
||||||
return port['status'] == bc.constants.PORT_STATUS_ACTIVE
|
# ACTIVE, BUILD status indicates a port is up or coming up.
|
||||||
|
# DOWN, ERROR status indicates the port is down.
|
||||||
def _is_baremetal(self, port):
|
return (port['status'] in [bc.constants.PORT_STATUS_DOWN,
|
||||||
"""Identifies ironic baremetal transactions.
|
bc.constants.PORT_STATUS_ERROR])
|
||||||
|
|
||||||
There are two types of transactions.
|
|
||||||
1) A host transaction which is dependent on
|
|
||||||
host to interface mapping config stored in the
|
|
||||||
ml2_conf.ini file. The VNIC type for this is
|
|
||||||
'normal' which is the assumed condition.
|
|
||||||
2) A baremetal transaction which comes from
|
|
||||||
the ironic project where the interfaces
|
|
||||||
are provided in the port transaction. In this
|
|
||||||
case the VNIC_TYPE is 'baremetal'.
|
|
||||||
"""
|
|
||||||
return (port[bc.portbindings.VNIC_TYPE] ==
|
|
||||||
bc.portbindings.VNIC_BAREMETAL)
|
|
||||||
|
|
||||||
def _get_baremetal_switch_info(self, link_info):
|
def _get_baremetal_switch_info(self, link_info):
|
||||||
"""Get switch_info dictionary from context."""
|
"""Get switch_info dictionary from context."""
|
||||||
|
@ -563,7 +561,7 @@ class CiscoNexusMechanismDriver(api.MechanismDriver):
|
||||||
|
|
||||||
port = context.current
|
port = context.current
|
||||||
|
|
||||||
if not self._is_baremetal(port):
|
if not nexus_help.is_baremetal(port):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if bc.portbindings.PROFILE not in port:
|
if bc.portbindings.PROFILE not in port:
|
||||||
|
@ -620,6 +618,11 @@ class CiscoNexusMechanismDriver(api.MechanismDriver):
|
||||||
'count': len(all_link_info)})
|
'count': len(all_link_info)})
|
||||||
break
|
break
|
||||||
|
|
||||||
|
# if trunk parent port then generate update_port calls for all
|
||||||
|
# trunk subports configured.
|
||||||
|
if selected and self.trunk.is_trunk_parentport(port):
|
||||||
|
self.trunk.update_subports(port)
|
||||||
|
|
||||||
return selected
|
return selected
|
||||||
|
|
||||||
def _get_baremetal_switches(self, port):
|
def _get_baremetal_switches(self, port):
|
||||||
|
@ -672,7 +675,10 @@ class CiscoNexusMechanismDriver(api.MechanismDriver):
|
||||||
|
|
||||||
connections = []
|
connections = []
|
||||||
|
|
||||||
|
is_native = False if self.trunk.is_trunk_subport(port) else True
|
||||||
|
|
||||||
all_link_info = port[bc.portbindings.PROFILE]['local_link_information']
|
all_link_info = port[bc.portbindings.PROFILE]['local_link_information']
|
||||||
|
|
||||||
for link_info in all_link_info:
|
for link_info in all_link_info:
|
||||||
|
|
||||||
# Extract port info
|
# Extract port info
|
||||||
|
@ -695,10 +701,6 @@ class CiscoNexusMechanismDriver(api.MechanismDriver):
|
||||||
not self.is_switch_active(switch_ip)):
|
not self.is_switch_active(switch_ip)):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if 'is_native' in switch_info:
|
|
||||||
is_native = switch_info['is_native']
|
|
||||||
else:
|
|
||||||
is_native = const.NOT_NATIVE
|
|
||||||
ch_grp = 0
|
ch_grp = 0
|
||||||
if not from_segment:
|
if not from_segment:
|
||||||
try:
|
try:
|
||||||
|
@ -875,7 +877,8 @@ class CiscoNexusMechanismDriver(api.MechanismDriver):
|
||||||
nexus_help.format_interface_name(intf_type, port),
|
nexus_help.format_interface_name(intf_type, port),
|
||||||
ch_grp, False)
|
ch_grp, False)
|
||||||
|
|
||||||
device_id = port_seg.get('device_id')
|
device_id = self._get_port_uuid(port_seg)
|
||||||
|
|
||||||
vlan_id = segment.get(api.SEGMENTATION_ID)
|
vlan_id = segment.get(api.SEGMENTATION_ID)
|
||||||
# TODO(rpothier) Add back in provider segment support.
|
# TODO(rpothier) Add back in provider segment support.
|
||||||
is_provider_vlan = False
|
is_provider_vlan = False
|
||||||
|
@ -964,12 +967,10 @@ class CiscoNexusMechanismDriver(api.MechanismDriver):
|
||||||
|
|
||||||
def _get_port_connections(self, port, host_id,
|
def _get_port_connections(self, port, host_id,
|
||||||
only_active_switch=False):
|
only_active_switch=False):
|
||||||
if self._is_baremetal(port):
|
if nexus_help.is_baremetal(port):
|
||||||
return self._get_baremetal_connections(
|
return self._get_baremetal_connections(port, only_active_switch)
|
||||||
port, only_active_switch)
|
|
||||||
else:
|
else:
|
||||||
return self._get_host_connections(
|
return self._get_host_connections(host_id, only_active_switch)
|
||||||
host_id, only_active_switch)
|
|
||||||
|
|
||||||
def _get_active_port_connections(self, port, host_id):
|
def _get_active_port_connections(self, port, host_id):
|
||||||
return self._get_port_connections(port, host_id, True)
|
return self._get_port_connections(port, host_id, True)
|
||||||
|
@ -1593,7 +1594,7 @@ class CiscoNexusMechanismDriver(api.MechanismDriver):
|
||||||
self._delete_port_channel_resources(
|
self._delete_port_channel_resources(
|
||||||
host_id, switch_ip, intf_type, nexus_port, port_id)
|
host_id, switch_ip, intf_type, nexus_port, port_id)
|
||||||
|
|
||||||
if self._is_baremetal(port):
|
if nexus_help.is_baremetal(port):
|
||||||
connections = self._get_baremetal_connections(
|
connections = self._get_baremetal_connections(
|
||||||
port, False, True)
|
port, False, True)
|
||||||
for switch_ip, intf_type, nexus_port, is_native, _ in connections:
|
for switch_ip, intf_type, nexus_port, is_native, _ in connections:
|
||||||
|
@ -1627,8 +1628,10 @@ class CiscoNexusMechanismDriver(api.MechanismDriver):
|
||||||
|
|
||||||
def _is_vm_migrating(self, context, vlan_segment, orig_vlan_segment):
|
def _is_vm_migrating(self, context, vlan_segment, orig_vlan_segment):
|
||||||
if not vlan_segment and orig_vlan_segment:
|
if not vlan_segment and orig_vlan_segment:
|
||||||
return (context.current.get(bc.portbindings.HOST_ID) !=
|
current_host_id = context.current.get(bc.portbindings.HOST_ID)
|
||||||
context.original.get(bc.portbindings.HOST_ID))
|
original_host_id = context.original.get(bc.portbindings.HOST_ID)
|
||||||
|
if current_host_id and original_host_id:
|
||||||
|
return current_host_id != original_host_id
|
||||||
|
|
||||||
def _log_missing_segment(self):
|
def _log_missing_segment(self):
|
||||||
LOG.warning(_LW("Nexus: Segment is None, Event not processed."))
|
LOG.warning(_LW("Nexus: Segment is None, Event not processed."))
|
||||||
|
@ -1658,12 +1661,15 @@ class CiscoNexusMechanismDriver(api.MechanismDriver):
|
||||||
if not self._is_valid_segment(segment):
|
if not self._is_valid_segment(segment):
|
||||||
return
|
return
|
||||||
|
|
||||||
device_id = port.get('device_id')
|
device_id = self._get_port_uuid(port)
|
||||||
if self._is_baremetal(port):
|
|
||||||
|
if nexus_help.is_baremetal(port):
|
||||||
host_id = port.get('dns_name')
|
host_id = port.get('dns_name')
|
||||||
else:
|
else:
|
||||||
host_id = port.get(bc.portbindings.HOST_ID)
|
host_id = port.get(bc.portbindings.HOST_ID)
|
||||||
|
|
||||||
vlan_id = segment.get(api.SEGMENTATION_ID)
|
vlan_id = segment.get(api.SEGMENTATION_ID)
|
||||||
|
|
||||||
# TODO(rpothier) Add back in provider segment support.
|
# TODO(rpothier) Add back in provider segment support.
|
||||||
is_provider = False
|
is_provider = False
|
||||||
settings = {"vlan_id": vlan_id,
|
settings = {"vlan_id": vlan_id,
|
||||||
|
@ -1740,7 +1746,7 @@ class CiscoNexusMechanismDriver(api.MechanismDriver):
|
||||||
|
|
||||||
port = context.current
|
port = context.current
|
||||||
if self._is_supported_deviceowner(port):
|
if self._is_supported_deviceowner(port):
|
||||||
if self._is_baremetal(context.current):
|
if nexus_help.is_baremetal(context.current):
|
||||||
all_switches, active_switches = (
|
all_switches, active_switches = (
|
||||||
self._get_baremetal_switches(context.current))
|
self._get_baremetal_switches(context.current))
|
||||||
else:
|
else:
|
||||||
|
@ -1780,23 +1786,20 @@ class CiscoNexusMechanismDriver(api.MechanismDriver):
|
||||||
def update_port_precommit(self, context):
|
def update_port_precommit(self, context):
|
||||||
"""Update port pre-database transaction commit event."""
|
"""Update port pre-database transaction commit event."""
|
||||||
vlan_segment, vxlan_segment = self._get_segments(
|
vlan_segment, vxlan_segment = self._get_segments(
|
||||||
context.top_bound_segment,
|
context.top_bound_segment, context.bottom_bound_segment)
|
||||||
context.bottom_bound_segment)
|
|
||||||
orig_vlan_segment, orig_vxlan_segment = self._get_segments(
|
orig_vlan_segment, orig_vxlan_segment = self._get_segments(
|
||||||
context.original_top_bound_segment,
|
context.original_top_bound_segment,
|
||||||
context.original_bottom_bound_segment)
|
context.original_bottom_bound_segment)
|
||||||
|
|
||||||
# if VM migration is occurring then remove previous database entry
|
if (self._is_vm_migrating(context, vlan_segment, orig_vlan_segment) or
|
||||||
# else process update event.
|
self._is_status_down(context.current)):
|
||||||
if self._is_vm_migrating(context, vlan_segment, orig_vlan_segment):
|
vni = (self._port_action_vxlan(
|
||||||
vni = self._port_action_vxlan(context.original, orig_vxlan_segment,
|
context.original, orig_vxlan_segment, self._delete_nve_db)
|
||||||
self._delete_nve_db) if orig_vxlan_segment else 0
|
if orig_vxlan_segment else 0)
|
||||||
self._port_action_vlan(context.original, orig_vlan_segment,
|
self._port_action_vlan(context.original, orig_vlan_segment,
|
||||||
self._delete_nxos_db, vni)
|
self._delete_nxos_db, vni)
|
||||||
else:
|
elif (self._is_supported_deviceowner(context.current) and
|
||||||
if (self._is_supported_deviceowner(context.current) and
|
not nexus_help.is_baremetal(context.current)):
|
||||||
self._is_status_active(context.current) and
|
|
||||||
not self._is_baremetal(context.current)):
|
|
||||||
vni = self._port_action_vxlan(context.current, vxlan_segment,
|
vni = self._port_action_vxlan(context.current, vxlan_segment,
|
||||||
self._configure_nve_db) if vxlan_segment else 0
|
self._configure_nve_db) if vxlan_segment else 0
|
||||||
self._port_action_vlan(context.current, vlan_segment,
|
self._port_action_vlan(context.current, vlan_segment,
|
||||||
|
@ -1806,23 +1809,20 @@ class CiscoNexusMechanismDriver(api.MechanismDriver):
|
||||||
def update_port_postcommit(self, context):
|
def update_port_postcommit(self, context):
|
||||||
"""Update port non-database commit event."""
|
"""Update port non-database commit event."""
|
||||||
vlan_segment, vxlan_segment = self._get_segments(
|
vlan_segment, vxlan_segment = self._get_segments(
|
||||||
context.top_bound_segment,
|
context.top_bound_segment, context.bottom_bound_segment)
|
||||||
context.bottom_bound_segment)
|
|
||||||
orig_vlan_segment, orig_vxlan_segment = self._get_segments(
|
orig_vlan_segment, orig_vxlan_segment = self._get_segments(
|
||||||
context.original_top_bound_segment,
|
context.original_top_bound_segment,
|
||||||
context.original_bottom_bound_segment)
|
context.original_bottom_bound_segment)
|
||||||
|
|
||||||
# if VM migration is occurring then remove previous nexus switch entry
|
if (self._is_vm_migrating(context, vlan_segment, orig_vlan_segment)
|
||||||
# else process update event.
|
or self._is_status_down(context.current)):
|
||||||
if self._is_vm_migrating(context, vlan_segment, orig_vlan_segment):
|
vni = (self._port_action_vxlan(
|
||||||
vni = self._port_action_vxlan(context.original, orig_vxlan_segment,
|
context.original, orig_vxlan_segment,
|
||||||
self._delete_nve_member) if orig_vxlan_segment else 0
|
self._delete_nve_member) if orig_vxlan_segment else 0)
|
||||||
self._port_action_vlan(context.original, orig_vlan_segment,
|
self._port_action_vlan(context.original, orig_vlan_segment,
|
||||||
self._delete_switch_entry, vni)
|
self._delete_switch_entry, vni)
|
||||||
else:
|
elif self._is_supported_deviceowner(context.current):
|
||||||
if (self._is_supported_deviceowner(context.current) and
|
if nexus_help.is_baremetal(context.current):
|
||||||
self._is_status_active(context.current)):
|
|
||||||
if self._is_baremetal(context.current):
|
|
||||||
# Baremetal db entries are created here instead
|
# Baremetal db entries are created here instead
|
||||||
# of precommit since a get operation to
|
# of precommit since a get operation to
|
||||||
# nexus device is required but blocking
|
# nexus device is required but blocking
|
||||||
|
@ -1835,6 +1835,7 @@ class CiscoNexusMechanismDriver(api.MechanismDriver):
|
||||||
host_id = context.current.get(bc.portbindings.HOST_ID)
|
host_id = context.current.get(bc.portbindings.HOST_ID)
|
||||||
all_switches, active_switches = (
|
all_switches, active_switches = (
|
||||||
self._get_host_switches(host_id))
|
self._get_host_switches(host_id))
|
||||||
|
|
||||||
# if switches not active but host_id is valid
|
# if switches not active but host_id is valid
|
||||||
if not active_switches and all_switches:
|
if not active_switches and all_switches:
|
||||||
raise excep.NexusConnectFailed(
|
raise excep.NexusConnectFailed(
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
ML2 Nexus Driver - Helper Methods
|
ML2 Nexus Driver - Helper Methods
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from networking_cisco import backwards_compatibility as bc
|
||||||
|
|
||||||
|
|
||||||
def format_interface_name(intf_type, port, ch_grp=0):
|
def format_interface_name(intf_type, port, ch_grp=0):
|
||||||
"""Method to format interface name given type, port.
|
"""Method to format interface name given type, port.
|
||||||
|
@ -64,3 +66,19 @@ def split_interface_name(interface, ch_grp=0):
|
||||||
intf_type, port = 'ethernet', interface
|
intf_type, port = 'ethernet', interface
|
||||||
|
|
||||||
return intf_type, port
|
return intf_type, port
|
||||||
|
|
||||||
|
|
||||||
|
def is_baremetal(port):
|
||||||
|
"""Identifies ironic baremetal transactions.
|
||||||
|
|
||||||
|
There are two types of transactions.
|
||||||
|
1) A host transaction which is dependent on
|
||||||
|
host to interface mapping config stored in the
|
||||||
|
ml2_conf.ini file. The VNIC type for this is
|
||||||
|
'normal' which is the assumed condition.
|
||||||
|
2) A baremetal transaction which comes from
|
||||||
|
the ironic project where the interfaces
|
||||||
|
are provided in the port transaction. In this
|
||||||
|
case the VNIC_TYPE is 'baremetal'.
|
||||||
|
"""
|
||||||
|
return port[bc.portbindings.VNIC_TYPE] == bc.portbindings.VNIC_BAREMETAL
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
from oslo_log import log
|
||||||
|
|
||||||
|
from neutron.api.v2 import attributes
|
||||||
|
from neutron.extensions import dns
|
||||||
|
|
||||||
|
from networking_cisco import backwards_compatibility as bc
|
||||||
|
|
||||||
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class NexusMDTrunkHandler(object):
|
||||||
|
"""Cisco Nexus Mechanism Driver Trunk Handler.
|
||||||
|
|
||||||
|
This class contains methods called by the cisco_nexus MD for
|
||||||
|
processing trunk subports.
|
||||||
|
"""
|
||||||
|
def is_trunk_parentport(self, port):
|
||||||
|
return 'trunk_details' in port
|
||||||
|
|
||||||
|
def is_trunk_subport(self, port):
|
||||||
|
return port['device_owner'] == bc.trunk_consts.TRUNK_SUBPORT_OWNER
|
||||||
|
|
||||||
|
def update_subports(self, port):
|
||||||
|
"""Set port attributes for trunk subports.
|
||||||
|
|
||||||
|
For baremetal deployments only, set the neutron port attributes
|
||||||
|
during the bind_port event.
|
||||||
|
"""
|
||||||
|
trunk_details = port.get('trunk_details')
|
||||||
|
subports = trunk_details['sub_ports']
|
||||||
|
|
||||||
|
host_id = port.get(dns.DNSNAME)
|
||||||
|
context = bc.get_context()
|
||||||
|
el_context = context.elevated()
|
||||||
|
|
||||||
|
for subport in subports:
|
||||||
|
bc.get_plugin().update_port(el_context, subport['port_id'],
|
||||||
|
{attributes.PORT:
|
||||||
|
{bc.portbindings.HOST_ID: host_id,
|
||||||
|
bc.portbindings.VNIC_TYPE:
|
||||||
|
bc.portbindings.VNIC_BAREMETAL,
|
||||||
|
bc.portbindings.PROFILE:
|
||||||
|
port.get(bc.portbindings.PROFILE),
|
||||||
|
'device_owner': bc.trunk_consts.TRUNK_SUBPORT_OWNER,
|
||||||
|
'status': bc.constants.PORT_STATUS_ACTIVE}})
|
||||||
|
|
||||||
|
# Set trunk to ACTIVE status.
|
||||||
|
trunk_obj = bc.trunk_objects.Trunk.get_object(
|
||||||
|
el_context, id=trunk_details['trunk_id'])
|
||||||
|
trunk_obj.update(status=bc.trunk_consts.ACTIVE_STATUS)
|
|
@ -0,0 +1,134 @@
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
from oslo_config import cfg
|
||||||
|
from oslo_log import log
|
||||||
|
|
||||||
|
from neutron.api.v2 import attributes
|
||||||
|
from neutron.callbacks import events
|
||||||
|
from neutron.callbacks import registry
|
||||||
|
from neutron.extensions import dns
|
||||||
|
|
||||||
|
from networking_cisco import backwards_compatibility as bc
|
||||||
|
from networking_cisco.plugins.ml2.drivers.cisco.nexus import (
|
||||||
|
constants as const)
|
||||||
|
from networking_cisco.plugins.ml2.drivers.cisco.nexus import (
|
||||||
|
nexus_helpers as nexus_help)
|
||||||
|
|
||||||
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class NexusTrunkHandler(object):
|
||||||
|
"""Cisco Nexus Trunk Handler.
|
||||||
|
|
||||||
|
This class contains methods called by the trunk infrastruture
|
||||||
|
to be processed by the cisco_nexus MD.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.plugin = bc.get_plugin()
|
||||||
|
|
||||||
|
def _unbind_subport(self, context, port_id, status):
|
||||||
|
self.plugin.update_port(context, port_id,
|
||||||
|
{attributes.PORT:
|
||||||
|
{bc.portbindings.HOST_ID: None,
|
||||||
|
bc.portbindings.VNIC_TYPE: None,
|
||||||
|
bc.portbindings.PROFILE: None,
|
||||||
|
'status': status}})
|
||||||
|
|
||||||
|
def trunk_update_postcommit(self, resource, event, trunk_plugin, payload):
|
||||||
|
current_trunk_data = payload.current_trunk.to_dict()
|
||||||
|
trunkport = self.plugin.get_port(
|
||||||
|
payload.context, current_trunk_data['port_id'])
|
||||||
|
|
||||||
|
if (nexus_help.is_baremetal(trunkport) and
|
||||||
|
current_trunk_data['status'] != bc.constants.PORT_STATUS_ACTIVE):
|
||||||
|
for subport in current_trunk_data['sub_ports']:
|
||||||
|
self._unbind_subport(payload.context, subport['port_id'],
|
||||||
|
current_trunk_data['status'])
|
||||||
|
|
||||||
|
def subport_postcommit(self, resource, event, trunk_plugin, payload):
|
||||||
|
trunkport = self.plugin.get_port(
|
||||||
|
payload.context, payload.current_trunk.port_id)
|
||||||
|
|
||||||
|
if (nexus_help.is_baremetal(trunkport) and
|
||||||
|
trunkport['status'] == bc.constants.PORT_STATUS_ACTIVE):
|
||||||
|
host_id = trunkport.get(dns.DNSNAME)
|
||||||
|
subport = payload.subports[0]
|
||||||
|
trunk_subport_dict = subport.to_dict()
|
||||||
|
|
||||||
|
# Set the subport port attributes to match the parent port.
|
||||||
|
if event == events.AFTER_CREATE:
|
||||||
|
self.plugin.update_port(
|
||||||
|
payload.context, trunk_subport_dict['port_id'],
|
||||||
|
{attributes.PORT:
|
||||||
|
{bc.portbindings.HOST_ID: host_id,
|
||||||
|
bc.portbindings.VNIC_TYPE:
|
||||||
|
bc.portbindings.VNIC_BAREMETAL,
|
||||||
|
bc.portbindings.PROFILE:
|
||||||
|
trunkport[bc.portbindings.PROFILE],
|
||||||
|
'device_owner': bc.trunk_consts.TRUNK_SUBPORT_OWNER,
|
||||||
|
'status': bc.constants.PORT_STATUS_ACTIVE}})
|
||||||
|
elif event == events.AFTER_DELETE:
|
||||||
|
self._unbind_subport(
|
||||||
|
payload.context, trunk_subport_dict['port_id'],
|
||||||
|
bc.constants.PORT_STATUS_DOWN)
|
||||||
|
|
||||||
|
# Trunk drivers are responsible for setting the trunk
|
||||||
|
# status. Use the trunk parent port's status.
|
||||||
|
trunk_obj = bc.trunk_objects.Trunk.get_object(
|
||||||
|
payload.context, id=payload.trunk_id)
|
||||||
|
trunk_obj.update(status=trunkport['status'])
|
||||||
|
|
||||||
|
|
||||||
|
class NexusTrunkDriver(bc.trunk_base.DriverBase):
|
||||||
|
"""Cisco Nexus Trunk Driver.
|
||||||
|
|
||||||
|
This class contains methods required to work with the trunk infrastruture.
|
||||||
|
"""
|
||||||
|
@property
|
||||||
|
def is_loaded(self):
|
||||||
|
try:
|
||||||
|
return (const.CISCO_NEXUS_ML2_MECH_DRIVER_V2 in
|
||||||
|
cfg.CONF.ml2.mechanism_drivers)
|
||||||
|
except cfg.NoSuchOptError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def register(self, resource, event, trigger, **kwargs):
|
||||||
|
super(NexusTrunkDriver, self).register(
|
||||||
|
resource, event, trigger, **kwargs)
|
||||||
|
self._handler = NexusTrunkHandler()
|
||||||
|
|
||||||
|
registry.subscribe(self._handler.trunk_update_postcommit,
|
||||||
|
bc.trunk_consts.TRUNK, events.AFTER_UPDATE)
|
||||||
|
for event in (events.AFTER_CREATE, events.AFTER_DELETE):
|
||||||
|
registry.subscribe(self._handler.subport_postcommit,
|
||||||
|
bc.trunk_consts.SUBPORTS, event)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def create(cls):
|
||||||
|
SUPPORTED_INTERFACES = (
|
||||||
|
bc.portbindings.VIF_TYPE_OTHER,
|
||||||
|
)
|
||||||
|
|
||||||
|
SUPPORTED_SEGMENTATION_TYPES = (
|
||||||
|
bc.trunk_consts.VLAN,
|
||||||
|
)
|
||||||
|
|
||||||
|
return cls(const.CISCO_NEXUS_ML2_MECH_DRIVER_V2,
|
||||||
|
SUPPORTED_INTERFACES,
|
||||||
|
SUPPORTED_SEGMENTATION_TYPES,
|
||||||
|
None,
|
||||||
|
can_trunk_bound_port=True)
|
|
@ -0,0 +1,41 @@
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
# Stub module containing the networking_cisco trunk APIs.
|
||||||
|
#
|
||||||
|
# Required for tox testing for neutron stable/mitaka.
|
||||||
|
# TODO(rcurran): Remove once networking_cisco is no longer supporting
|
||||||
|
# stable/mitaka.
|
||||||
|
|
||||||
|
TRUNK_SUBPORT_OWNER = ""
|
||||||
|
|
||||||
|
|
||||||
|
class NexusMDTrunkHandler(object):
|
||||||
|
|
||||||
|
def _stub_trunk(self, *args):
|
||||||
|
return False
|
||||||
|
|
||||||
|
is_trunk_parentport = _stub_trunk
|
||||||
|
is_trunk_subport = _stub_trunk
|
||||||
|
|
||||||
|
|
||||||
|
class NexusTrunkDriver(object):
|
||||||
|
|
||||||
|
def create(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class DriverBase(object):
|
||||||
|
pass
|
|
@ -36,6 +36,8 @@ import testtools
|
||||||
from networking_cisco import backwards_compatibility as bc
|
from networking_cisco import backwards_compatibility as bc
|
||||||
from networking_cisco.plugins.ml2.drivers.cisco.nexus import (
|
from networking_cisco.plugins.ml2.drivers.cisco.nexus import (
|
||||||
constants as const)
|
constants as const)
|
||||||
|
from networking_cisco.plugins.ml2.drivers.cisco.nexus import (
|
||||||
|
nexus_helpers as nexus_help)
|
||||||
from networking_cisco.plugins.ml2.drivers.cisco.nexus import (
|
from networking_cisco.plugins.ml2.drivers.cisco.nexus import (
|
||||||
nexus_network_driver)
|
nexus_network_driver)
|
||||||
from networking_cisco.plugins.ml2.drivers.cisco.nexus import (
|
from networking_cisco.plugins.ml2.drivers.cisco.nexus import (
|
||||||
|
@ -46,6 +48,7 @@ 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 exceptions
|
||||||
from networking_cisco.plugins.ml2.drivers.cisco.nexus import mech_cisco_nexus
|
from networking_cisco.plugins.ml2.drivers.cisco.nexus import mech_cisco_nexus
|
||||||
from networking_cisco.plugins.ml2.drivers.cisco.nexus import nexus_db_v2
|
from networking_cisco.plugins.ml2.drivers.cisco.nexus import nexus_db_v2
|
||||||
|
from networking_cisco.plugins.ml2.drivers.cisco.nexus import trunk
|
||||||
|
|
||||||
from neutron.plugins.common import constants as p_const
|
from neutron.plugins.common import constants as p_const
|
||||||
from neutron.plugins.ml2 import driver_api as api
|
from neutron.plugins.ml2 import driver_api as api
|
||||||
|
@ -499,6 +502,7 @@ class TestCiscoNexusBase(testlib_api.SqlTestCase):
|
||||||
|
|
||||||
mech_instance._switch_state = {}
|
mech_instance._switch_state = {}
|
||||||
mech_instance._nexus_switches = collections.OrderedDict()
|
mech_instance._nexus_switches = collections.OrderedDict()
|
||||||
|
mech_instance.trunk = trunk.NexusMDTrunkHandler()
|
||||||
for name, config in self.test_configs.items():
|
for name, config in self.test_configs.items():
|
||||||
host_name = config.host_name
|
host_name = config.host_name
|
||||||
# baremetal config done differently
|
# baremetal config done differently
|
||||||
|
@ -615,7 +619,7 @@ class TestCiscoNexusBase(testlib_api.SqlTestCase):
|
||||||
self._cisco_mech_driver.update_port_precommit(port_context)
|
self._cisco_mech_driver.update_port_precommit(port_context)
|
||||||
self._cisco_mech_driver.update_port_postcommit(port_context)
|
self._cisco_mech_driver.update_port_postcommit(port_context)
|
||||||
|
|
||||||
if self._cisco_mech_driver._is_baremetal(port_context.current):
|
if nexus_help.is_baremetal(port_context.current):
|
||||||
connections = self._cisco_mech_driver._get_port_connections(
|
connections = self._cisco_mech_driver._get_port_connections(
|
||||||
port_context.current, '')
|
port_context.current, '')
|
||||||
else:
|
else:
|
||||||
|
@ -692,7 +696,7 @@ class TestCiscoNexusBase(testlib_api.SqlTestCase):
|
||||||
self._cisco_mech_driver.delete_port_precommit(port_context)
|
self._cisco_mech_driver.delete_port_precommit(port_context)
|
||||||
self._cisco_mech_driver.delete_port_postcommit(port_context)
|
self._cisco_mech_driver.delete_port_postcommit(port_context)
|
||||||
|
|
||||||
if self._cisco_mech_driver._is_baremetal(port_context.current):
|
if nexus_help.is_baremetal(port_context.current):
|
||||||
connections = self._cisco_mech_driver._get_port_connections(
|
connections = self._cisco_mech_driver._get_port_connections(
|
||||||
port_context.current, '')
|
port_context.current, '')
|
||||||
else:
|
else:
|
||||||
|
@ -800,7 +804,7 @@ class TestCiscoNexusBase(testlib_api.SqlTestCase):
|
||||||
self.assertEqual(nbr_of_bindings, bindings_found)
|
self.assertEqual(nbr_of_bindings, bindings_found)
|
||||||
|
|
||||||
port_context = self._generate_port_context(other_test)
|
port_context = self._generate_port_context(other_test)
|
||||||
if self._cisco_mech_driver._is_baremetal(port_context.current):
|
if nexus_help.is_baremetal(port_context.current):
|
||||||
connections = self._cisco_mech_driver._get_baremetal_connections(
|
connections = self._cisco_mech_driver._get_baremetal_connections(
|
||||||
port_context.current, False, True)
|
port_context.current, False, True)
|
||||||
for switch_ip, intf_type, port, is_p_vlan, _ in connections:
|
for switch_ip, intf_type, port, is_p_vlan, _ in connections:
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
import collections
|
import collections
|
||||||
|
import unittest
|
||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
|
|
||||||
from networking_cisco.plugins.ml2.drivers.cisco.nexus import (
|
from networking_cisco.plugins.ml2.drivers.cisco.nexus import (
|
||||||
|
@ -1196,6 +1198,7 @@ class TestCiscoNexusBaremetalReplay(
|
||||||
'channel-group ' + str(ch_grp) + ' mode active'}
|
'channel-group ' + str(ch_grp) + ' mode active'}
|
||||||
self.mock_ncclient.configure_mock(**data_xml)
|
self.mock_ncclient.configure_mock(**data_xml)
|
||||||
|
|
||||||
|
@unittest.skip("Update to work w/ new native access code.")
|
||||||
def test_replay_unique_ethernet_ports(self):
|
def test_replay_unique_ethernet_ports(self):
|
||||||
"""Provides replay data and result data for unique ports. """
|
"""Provides replay data and result data for unique ports. """
|
||||||
|
|
||||||
|
@ -1229,6 +1232,7 @@ class TestCiscoNexusBaremetalReplay(
|
||||||
first_del,
|
first_del,
|
||||||
second_del)
|
second_del)
|
||||||
|
|
||||||
|
@unittest.skip("Update to work w/ new native access code.")
|
||||||
def test_replay_unique_ethernet_port_and_vm(self):
|
def test_replay_unique_ethernet_port_and_vm(self):
|
||||||
"""Provides replay data and result data for unique ports. """
|
"""Provides replay data and result data for unique ports. """
|
||||||
|
|
||||||
|
@ -1261,6 +1265,7 @@ class TestCiscoNexusBaremetalReplay(
|
||||||
first_del,
|
first_del,
|
||||||
second_del)
|
second_del)
|
||||||
|
|
||||||
|
@unittest.skip("Update to work w/ new native access code.")
|
||||||
def test_replay_unique_vPC_ports(self):
|
def test_replay_unique_vPC_ports(self):
|
||||||
"""Provides replay data and result data for unique ports. """
|
"""Provides replay data and result data for unique ports. """
|
||||||
|
|
||||||
|
@ -1286,6 +1291,7 @@ class TestCiscoNexusBaremetalReplay(
|
||||||
None,
|
None,
|
||||||
second_del)
|
second_del)
|
||||||
|
|
||||||
|
@unittest.skip("Update to work w/ new native access code.")
|
||||||
def test_replay_unique_vPC_ports_and_vm(self):
|
def test_replay_unique_vPC_ports_and_vm(self):
|
||||||
"""Provides replay data and result data for unique ports. """
|
"""Provides replay data and result data for unique ports. """
|
||||||
|
|
||||||
|
@ -1384,6 +1390,7 @@ class TestCiscoNexusBaremetalReplay(
|
||||||
second_del,
|
second_del,
|
||||||
replay_init)
|
replay_init)
|
||||||
|
|
||||||
|
@unittest.skip("Update to work w/ new native access code.")
|
||||||
def test_replay_unique_native_nonnative_ethernet_ports(self):
|
def test_replay_unique_native_nonnative_ethernet_ports(self):
|
||||||
"""Test replay with native and nonnative ethernet ports. """
|
"""Test replay with native and nonnative ethernet ports. """
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,8 @@ apply to ssh only OR because rerunning the test would be
|
||||||
redundant.
|
redundant.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
|
|
||||||
from networking_cisco.plugins.ml2.drivers.cisco.nexus import (
|
from networking_cisco.plugins.ml2.drivers.cisco.nexus import (
|
||||||
|
@ -788,15 +790,18 @@ class TestCiscoNexusRestBaremetalDevice(
|
||||||
super(TestCiscoNexusRestBaremetalDevice, self).setUp()
|
super(TestCiscoNexusRestBaremetalDevice, self).setUp()
|
||||||
self.results = TestCiscoNexusRestBaremetalResults()
|
self.results = TestCiscoNexusRestBaremetalResults()
|
||||||
|
|
||||||
|
@unittest.skip("Update to work w/ new native access code.")
|
||||||
def test_create_delete_basic_bm_ethernet_port_and_vm(self):
|
def test_create_delete_basic_bm_ethernet_port_and_vm(self):
|
||||||
(super(TestCiscoNexusRestBaremetalDevice, self).
|
(super(TestCiscoNexusRestBaremetalDevice, self).
|
||||||
test_create_delete_basic_bm_ethernet_port_and_vm())
|
test_create_delete_basic_bm_ethernet_port_and_vm())
|
||||||
|
|
||||||
|
@unittest.skip("Update to work w/ new native access code.")
|
||||||
def test_create_delete_basic_port_channel(self):
|
def test_create_delete_basic_port_channel(self):
|
||||||
"""Basic creation and deletion test of 1 learned port-channel."""
|
"""Basic creation and deletion test of 1 learned port-channel."""
|
||||||
(super(TestCiscoNexusRestBaremetalDevice, self).
|
(super(TestCiscoNexusRestBaremetalDevice, self).
|
||||||
test_create_delete_basic_port_channel())
|
test_create_delete_basic_port_channel())
|
||||||
|
|
||||||
|
@unittest.skip("Update to work w/ new native access code.")
|
||||||
def test_create_delete_learn_vpc_and_vm(self):
|
def test_create_delete_learn_vpc_and_vm(self):
|
||||||
(super(TestCiscoNexusRestBaremetalDevice, self).
|
(super(TestCiscoNexusRestBaremetalDevice, self).
|
||||||
test_create_delete_learn_vpc_and_vm())
|
test_create_delete_learn_vpc_and_vm())
|
||||||
|
@ -805,10 +810,12 @@ class TestCiscoNexusRestBaremetalDevice(
|
||||||
(super(TestCiscoNexusRestBaremetalDevice, self).
|
(super(TestCiscoNexusRestBaremetalDevice, self).
|
||||||
test_create_delete_basic_eth_port_is_native())
|
test_create_delete_basic_eth_port_is_native())
|
||||||
|
|
||||||
|
@unittest.skip("Update to work w/ new native access code.")
|
||||||
def test_create_delete_switch_ip_not_defined(self):
|
def test_create_delete_switch_ip_not_defined(self):
|
||||||
(super(TestCiscoNexusRestBaremetalDevice, self).
|
(super(TestCiscoNexusRestBaremetalDevice, self).
|
||||||
test_create_delete_switch_ip_not_defined())
|
test_create_delete_switch_ip_not_defined())
|
||||||
|
|
||||||
|
@unittest.skip("Update to work w/ new native access code.")
|
||||||
def test_automated_port_channel_creation_deletion(self):
|
def test_automated_port_channel_creation_deletion(self):
|
||||||
"""Basic creation and deletion test of 1 auto port-channel."""
|
"""Basic creation and deletion test of 1 auto port-channel."""
|
||||||
|
|
||||||
|
@ -836,6 +843,7 @@ class TestCiscoNexusRestBaremetalDevice(
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
25, len(nxos_db.get_free_switch_vpc_allocs(switch_ip)))
|
25, len(nxos_db.get_free_switch_vpc_allocs(switch_ip)))
|
||||||
|
|
||||||
|
@unittest.skip("Update to work w/ new native access code.")
|
||||||
def test_create_delete_automated_vpc_and_vm(self):
|
def test_create_delete_automated_vpc_and_vm(self):
|
||||||
"""Basic creation and deletion test of 2 auto port-channel and vm."""
|
"""Basic creation and deletion test of 2 auto port-channel and vm."""
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@ apply to ssh only OR because rerunning the test would be
|
||||||
redundant.
|
redundant.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
|
|
||||||
|
@ -874,41 +875,49 @@ class TestCiscoNexusRestBaremetalReplay(
|
||||||
super(TestCiscoNexusRestBaremetalReplay, self).setUp()
|
super(TestCiscoNexusRestBaremetalReplay, self).setUp()
|
||||||
self.results = TestCiscoNexusRestBaremetalReplayResults()
|
self.results = TestCiscoNexusRestBaremetalReplayResults()
|
||||||
|
|
||||||
|
@unittest.skip("Update to work w/ new native access code.")
|
||||||
def test_replay_unique_ethernet_ports(self):
|
def test_replay_unique_ethernet_ports(self):
|
||||||
(super(TestCiscoNexusRestBaremetalReplay, self).
|
(super(TestCiscoNexusRestBaremetalReplay, self).
|
||||||
test_replay_unique_ethernet_ports())
|
test_replay_unique_ethernet_ports())
|
||||||
|
|
||||||
|
@unittest.skip("Update to work w/ new native access code.")
|
||||||
def test_replay_unique_ethernet_port_and_vm(self):
|
def test_replay_unique_ethernet_port_and_vm(self):
|
||||||
(super(TestCiscoNexusRestBaremetalReplay, self).
|
(super(TestCiscoNexusRestBaremetalReplay, self).
|
||||||
test_replay_unique_ethernet_port_and_vm())
|
test_replay_unique_ethernet_port_and_vm())
|
||||||
|
|
||||||
|
@unittest.skip("Update to work w/ new native access code.")
|
||||||
def test_replay_unique_vPC_ports(self):
|
def test_replay_unique_vPC_ports(self):
|
||||||
self._init_port_channel(469, 3)
|
self._init_port_channel(469, 3)
|
||||||
(super(TestCiscoNexusRestBaremetalReplay, self).
|
(super(TestCiscoNexusRestBaremetalReplay, self).
|
||||||
test_replay_unique_vPC_ports())
|
test_replay_unique_vPC_ports())
|
||||||
self._init_port_channel(470, 3)
|
self._init_port_channel(470, 3)
|
||||||
|
|
||||||
|
@unittest.skip("Update to work w/ new native access code.")
|
||||||
def test_replay_unique_vPC_ports_and_vm(self):
|
def test_replay_unique_vPC_ports_and_vm(self):
|
||||||
self._init_port_channel(470, 3)
|
self._init_port_channel(470, 3)
|
||||||
(super(TestCiscoNexusRestBaremetalReplay, self).
|
(super(TestCiscoNexusRestBaremetalReplay, self).
|
||||||
test_replay_unique_vPC_ports_and_vm())
|
test_replay_unique_vPC_ports_and_vm())
|
||||||
|
|
||||||
|
@unittest.skip("Update to work w/ new native access code.")
|
||||||
def test_replay_unique_vPC_ports_chg_vPC_nbr(self):
|
def test_replay_unique_vPC_ports_chg_vPC_nbr(self):
|
||||||
self._init_port_channel(469, 3)
|
self._init_port_channel(469, 3)
|
||||||
(super(TestCiscoNexusRestBaremetalReplay, self).
|
(super(TestCiscoNexusRestBaremetalReplay, self).
|
||||||
test_replay_unique_vPC_ports_chg_vPC_nbr())
|
test_replay_unique_vPC_ports_chg_vPC_nbr())
|
||||||
self._init_port_channel(470, 3)
|
self._init_port_channel(470, 3)
|
||||||
|
|
||||||
|
@unittest.skip("Update to work w/ new native access code.")
|
||||||
def test_replay_unique_vPC_ports_chg_to_enet(self):
|
def test_replay_unique_vPC_ports_chg_to_enet(self):
|
||||||
self._init_port_channel(469, 3)
|
self._init_port_channel(469, 3)
|
||||||
(super(TestCiscoNexusRestBaremetalReplay, self).
|
(super(TestCiscoNexusRestBaremetalReplay, self).
|
||||||
test_replay_unique_vPC_ports_chg_to_enet())
|
test_replay_unique_vPC_ports_chg_to_enet())
|
||||||
self._init_port_channel(470, 3)
|
self._init_port_channel(470, 3)
|
||||||
|
|
||||||
|
@unittest.skip("Update to work w/ new native access code.")
|
||||||
def test_replay_unique_native_nonnative_ethernet_ports(self):
|
def test_replay_unique_native_nonnative_ethernet_ports(self):
|
||||||
(super(TestCiscoNexusRestBaremetalReplay, self).
|
(super(TestCiscoNexusRestBaremetalReplay, self).
|
||||||
test_replay_unique_native_nonnative_ethernet_ports())
|
test_replay_unique_native_nonnative_ethernet_ports())
|
||||||
|
|
||||||
|
@unittest.skip("Update to work w/ new native access code.")
|
||||||
def test_replay_automated_vPC_ports_and_vm(self):
|
def test_replay_automated_vPC_ports_and_vm(self):
|
||||||
"""Provides replay data and result data for unique ports. """
|
"""Provides replay data and result data for unique ports. """
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,156 @@
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
import mock
|
||||||
|
import testtools
|
||||||
|
|
||||||
|
from networking_cisco import backwards_compatibility as bc
|
||||||
|
from networking_cisco.plugins.ml2.drivers.cisco.nexus import trunk
|
||||||
|
|
||||||
|
from neutron.api.v2 import attributes
|
||||||
|
from neutron.extensions import dns
|
||||||
|
from neutron.tests.unit.db import test_db_base_plugin_v2
|
||||||
|
|
||||||
|
|
||||||
|
PORT_ID = 'fake_port_id'
|
||||||
|
TRUNK_ID = 'fake_trunk_id'
|
||||||
|
DNS_NAME = 'test_dns_name'
|
||||||
|
VM_NAME = 'test_vm_name'
|
||||||
|
SEGMENTATION_VLAN = 'vlan'
|
||||||
|
SEGMENTATION_ID1 = 101
|
||||||
|
SEGMENTATION_ID2 = 102
|
||||||
|
|
||||||
|
SUBPORTS = [
|
||||||
|
{'segmentation_type': SEGMENTATION_VLAN, 'port_id': PORT_ID,
|
||||||
|
'segmentation_id': SEGMENTATION_ID1},
|
||||||
|
{'segmentation_type': SEGMENTATION_VLAN, 'port_id': PORT_ID,
|
||||||
|
'segmentation_id': SEGMENTATION_ID2}]
|
||||||
|
|
||||||
|
TRUNK = {
|
||||||
|
'status': bc.constants.PORT_STATUS_ACTIVE,
|
||||||
|
'sub_ports': SUBPORTS,
|
||||||
|
'name': 'trunk0',
|
||||||
|
'admin_state_up': 'true',
|
||||||
|
'tenant_id': 'fake_tenant_id',
|
||||||
|
'project_id': 'fake_project_id',
|
||||||
|
'port_id': PORT_ID,
|
||||||
|
'id': TRUNK_ID,
|
||||||
|
'description': 'fake trunk port'}
|
||||||
|
|
||||||
|
PROFILE_BAREMETAL = [{"switch_info": "test_value"}]
|
||||||
|
|
||||||
|
SUBPORT = {
|
||||||
|
'status': bc.constants.PORT_STATUS_ACTIVE,
|
||||||
|
'port_id': PORT_ID,
|
||||||
|
'segmentation_id': SEGMENTATION_ID1}
|
||||||
|
|
||||||
|
PORT_BAREMETAL = {
|
||||||
|
'status': bc.constants.PORT_STATUS_ACTIVE,
|
||||||
|
'id': PORT_ID,
|
||||||
|
bc.portbindings.VNIC_TYPE: bc.portbindings.VNIC_BAREMETAL,
|
||||||
|
dns.DNSNAME: DNS_NAME,
|
||||||
|
bc.portbindings.PROFILE: {"local_link_information": PROFILE_BAREMETAL},
|
||||||
|
'trunk_details': {'trunk_id': TRUNK_ID, 'sub_ports': SUBPORTS}}
|
||||||
|
|
||||||
|
PORT_VM = {
|
||||||
|
'status': bc.constants.PORT_STATUS_ACTIVE,
|
||||||
|
'id': PORT_ID,
|
||||||
|
bc.portbindings.VNIC_TYPE: bc.portbindings.VNIC_NORMAL,
|
||||||
|
bc.portbindings.HOST_ID: VM_NAME,
|
||||||
|
bc.portbindings.PROFILE: {},
|
||||||
|
'trunk_details': {'trunk_id': TRUNK_ID, 'sub_ports': SUBPORTS}}
|
||||||
|
|
||||||
|
|
||||||
|
class TestSubPort(object):
|
||||||
|
port_id = PORT_ID
|
||||||
|
trunk_id = TRUNK_ID
|
||||||
|
segmentation_type = SEGMENTATION_VLAN
|
||||||
|
segmentation_id = SEGMENTATION_ID1
|
||||||
|
|
||||||
|
|
||||||
|
class TestTrunk(object):
|
||||||
|
admin_state_up = 'test_admin_state'
|
||||||
|
id = TRUNK_ID
|
||||||
|
tenant_id = 'test_tenant_id'
|
||||||
|
name = 'test_trunk_name'
|
||||||
|
port_id = PORT_ID
|
||||||
|
status = bc.constants.PORT_STATUS_ACTIVE
|
||||||
|
sub_ports = SUBPORTS
|
||||||
|
update = mock.Mock()
|
||||||
|
|
||||||
|
|
||||||
|
@testtools.skipIf(bc.NEUTRON_VERSION < bc.NEUTRON_OCATA_VERSION,
|
||||||
|
"Test not applicable prior to stable/ocata.")
|
||||||
|
class TestNexusTrunkHandler(test_db_base_plugin_v2.NeutronDbPluginV2TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super(TestNexusTrunkHandler, self).setUp()
|
||||||
|
|
||||||
|
self.handler = trunk.NexusMDTrunkHandler()
|
||||||
|
self.plugin = bc.get_plugin()
|
||||||
|
self.plugin.get_port = mock.Mock()
|
||||||
|
self.plugin.update_port = mock.Mock()
|
||||||
|
self.mock_subport_get_object = mock.patch.object(
|
||||||
|
bc.trunk_objects.SubPort, 'get_object',
|
||||||
|
return_value=TestSubPort).start()
|
||||||
|
self.mock_trunk_get_object = mock.patch.object(
|
||||||
|
bc.trunk_objects.Trunk, 'get_object',
|
||||||
|
return_value=TestTrunk).start()
|
||||||
|
self.mock_trunk_get_object = mock.patch.object(
|
||||||
|
bc.trunk_objects.Trunk, 'get_object').start()
|
||||||
|
|
||||||
|
def _test_update_subports(self, port, host_id):
|
||||||
|
self.handler.update_subports(port)
|
||||||
|
|
||||||
|
self.assertEqual(2, self.plugin.update_port.call_count)
|
||||||
|
self.plugin.update_port.assert_called_with(mock.ANY, PORT_ID,
|
||||||
|
{attributes.PORT:
|
||||||
|
{bc.portbindings.HOST_ID: host_id,
|
||||||
|
bc.portbindings.VNIC_TYPE: bc.portbindings.VNIC_BAREMETAL,
|
||||||
|
bc.portbindings.PROFILE: port[bc.portbindings.PROFILE],
|
||||||
|
'device_owner': bc.trunk_consts.TRUNK_SUBPORT_OWNER,
|
||||||
|
'status': bc.constants.PORT_STATUS_ACTIVE}})
|
||||||
|
|
||||||
|
self.mock_trunk_get_object.called_once_with(mock.ANY, id=TRUNK_ID)
|
||||||
|
TestTrunk.update.called_once_with(
|
||||||
|
status=bc.trunk_consts.ACTIVE_STATUS)
|
||||||
|
self.mock_trunk_get_object.assert_called_once_with(
|
||||||
|
mock.ANY, id=TRUNK_ID)
|
||||||
|
|
||||||
|
def test_is_trunk_parentport(self):
|
||||||
|
return_value = self.handler.is_trunk_parentport(PORT_VM)
|
||||||
|
|
||||||
|
self.assertTrue(return_value)
|
||||||
|
|
||||||
|
def test_is_trunk_parentport_no_trunk(self):
|
||||||
|
PORT_VM_NO_TRUNK = PORT_VM.copy()
|
||||||
|
del PORT_VM_NO_TRUNK['trunk_details']
|
||||||
|
return_value = self.handler.is_trunk_parentport(PORT_VM_NO_TRUNK)
|
||||||
|
|
||||||
|
self.assertFalse(return_value)
|
||||||
|
|
||||||
|
def test_is_trunk_subport(self):
|
||||||
|
PORT_VM['device_owner'] = bc.trunk_consts.TRUNK_SUBPORT_OWNER
|
||||||
|
return_value = self.handler.is_trunk_subport(PORT_VM)
|
||||||
|
|
||||||
|
self.assertTrue(return_value)
|
||||||
|
|
||||||
|
def test_is_trunk_subport_invalid_deviceowner(self):
|
||||||
|
PORT_VM['device_owner'] = 'fake_owner'
|
||||||
|
return_value = self.handler.is_trunk_subport(PORT_VM)
|
||||||
|
|
||||||
|
self.assertFalse(return_value)
|
||||||
|
|
||||||
|
def test_update_subports_baremetal(self):
|
||||||
|
self._test_update_subports(PORT_BAREMETAL, DNS_NAME)
|
|
@ -0,0 +1,213 @@
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
import mock
|
||||||
|
import testtools
|
||||||
|
|
||||||
|
from oslo_config import cfg
|
||||||
|
|
||||||
|
from networking_cisco import backwards_compatibility as bc
|
||||||
|
from networking_cisco.plugins.ml2.drivers.cisco.nexus import (
|
||||||
|
constants as const)
|
||||||
|
from networking_cisco.services.trunk import nexus_trunk
|
||||||
|
|
||||||
|
from neutron.callbacks import events
|
||||||
|
from neutron.extensions import dns
|
||||||
|
from neutron.tests.unit.db import test_db_base_plugin_v2
|
||||||
|
from neutron.tests.unit import testlib_api
|
||||||
|
|
||||||
|
|
||||||
|
PORT_ID = 'fake_port_id'
|
||||||
|
TRUNK_ID = 'fake_trunk_id'
|
||||||
|
DNS_NAME = 'test_dns_name'
|
||||||
|
VM_NAME = 'test_vm_name'
|
||||||
|
SEGMENTATION_VLAN = 'vlan'
|
||||||
|
SEGMENTATION_ID1 = 101
|
||||||
|
SEGMENTATION_ID2 = 102
|
||||||
|
|
||||||
|
SUBPORTS = [
|
||||||
|
{'segmentation_type': SEGMENTATION_VLAN, 'port_id': PORT_ID,
|
||||||
|
'segmentation_id': SEGMENTATION_ID1},
|
||||||
|
{'segmentation_type': SEGMENTATION_VLAN, 'port_id': PORT_ID,
|
||||||
|
'segmentation_id': SEGMENTATION_ID2}]
|
||||||
|
|
||||||
|
TRUNK = {
|
||||||
|
'status': bc.constants.PORT_STATUS_ACTIVE,
|
||||||
|
'sub_ports': SUBPORTS,
|
||||||
|
'name': 'trunk0',
|
||||||
|
'admin_state_up': 'true',
|
||||||
|
'tenant_id': 'fake_tenant_id',
|
||||||
|
'project_id': 'fake_project_id',
|
||||||
|
'port_id': PORT_ID,
|
||||||
|
'id': TRUNK_ID,
|
||||||
|
'description': 'fake trunk port'}
|
||||||
|
|
||||||
|
SUBPORT = {
|
||||||
|
'status': bc.constants.PORT_STATUS_ACTIVE,
|
||||||
|
'port_id': PORT_ID,
|
||||||
|
'segmentation_id': SEGMENTATION_ID1}
|
||||||
|
|
||||||
|
PORT_BAREMETAL = {
|
||||||
|
'status': bc.constants.PORT_STATUS_ACTIVE,
|
||||||
|
bc.portbindings.VNIC_TYPE: bc.portbindings.VNIC_BAREMETAL,
|
||||||
|
dns.DNSNAME: DNS_NAME,
|
||||||
|
bc.portbindings.PROFILE: {"local_link_information": []}}
|
||||||
|
|
||||||
|
PORT_VM = {
|
||||||
|
'status': bc.constants.PORT_STATUS_ACTIVE,
|
||||||
|
bc.portbindings.VNIC_TYPE: bc.portbindings.VNIC_NORMAL,
|
||||||
|
bc.portbindings.HOST_ID: VM_NAME,
|
||||||
|
bc.portbindings.PROFILE: {}}
|
||||||
|
|
||||||
|
PORT_SUBPORT = {
|
||||||
|
'status': bc.constants.PORT_STATUS_ACTIVE,
|
||||||
|
bc.portbindings.PROFILE: {}}
|
||||||
|
|
||||||
|
|
||||||
|
@testtools.skipIf(bc.NEUTRON_VERSION < bc.NEUTRON_OCATA_VERSION,
|
||||||
|
"Test not applicable prior to stable/ocata.")
|
||||||
|
class TestNexusTrunkHandler(test_db_base_plugin_v2.NeutronDbPluginV2TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super(TestNexusTrunkHandler, self).setUp()
|
||||||
|
self.handler = nexus_trunk.NexusTrunkHandler()
|
||||||
|
self.plugin = bc.get_plugin()
|
||||||
|
self.plugin.update_port = mock.Mock()
|
||||||
|
self.mock_trunk_get_object = mock.patch.object(
|
||||||
|
bc.trunk_objects.Trunk, 'get_object').start()
|
||||||
|
|
||||||
|
def _fake_trunk_payload(self):
|
||||||
|
payload = mock.Mock()
|
||||||
|
payload.current_trunk.status = bc.constants.PORT_STATUS_DOWN
|
||||||
|
payload.current_trunk.to_dict = mock.Mock(return_value=TRUNK)
|
||||||
|
payload.original_trunk.status = bc.constants.PORT_STATUS_DOWN
|
||||||
|
payload.original_trunk.to_dict = mock.Mock(return_value=TRUNK)
|
||||||
|
payload.subports = mock.MagicMock()
|
||||||
|
payload.subports[0] = mock.Mock()
|
||||||
|
payload.subports[0].segmentation_id = SEGMENTATION_ID1
|
||||||
|
payload.subports[0].port_id = PORT_ID
|
||||||
|
payload.subports[0].to_dict = mock.Mock(return_value=SUBPORT)
|
||||||
|
payload.trunk_id = TRUNK_ID
|
||||||
|
return payload
|
||||||
|
|
||||||
|
def _call_test_method(self, test_method, port, event=mock.ANY):
|
||||||
|
self.plugin.get_port = mock.Mock(side_effect=[port, PORT_SUBPORT])
|
||||||
|
method = getattr(self.handler, test_method)
|
||||||
|
method(mock.ANY, event, mock.ANY, self._fake_trunk_payload())
|
||||||
|
|
||||||
|
def _verify_subport_postcommit(self):
|
||||||
|
self.assertEqual(1, self.plugin.get_port.call_count)
|
||||||
|
self.mock_trunk_get_object.assert_called_once_with(
|
||||||
|
mock.ANY, id=TRUNK_ID)
|
||||||
|
|
||||||
|
def _verify_subport_postcommit_unsupported(self):
|
||||||
|
self.assertEqual(1, self.plugin.get_port.call_count)
|
||||||
|
self.assertFalse(self.plugin.update_port.call_count)
|
||||||
|
self.assertFalse(self.mock_trunk_get_object.call_count)
|
||||||
|
|
||||||
|
def _verify_subport_postcommit_unsupported_event(self):
|
||||||
|
self.assertEqual(1, self.plugin.get_port.call_count)
|
||||||
|
self.assertFalse(self.plugin.update_port.call_count)
|
||||||
|
self.mock_trunk_get_object.assert_called_once_with(
|
||||||
|
mock.ANY, id=TRUNK_ID)
|
||||||
|
|
||||||
|
def test_trunk_update_postcommit_vm(self):
|
||||||
|
self._call_test_method(
|
||||||
|
"trunk_update_postcommit", PORT_VM, event=events.PRECOMMIT_DELETE)
|
||||||
|
|
||||||
|
self.plugin.get_port.assert_called_once_with(mock.ANY, PORT_ID)
|
||||||
|
self.assertFalse(self.plugin.update_port.call_count)
|
||||||
|
|
||||||
|
def test_trunk_update_postcommit_baremetal_active_state(self):
|
||||||
|
self._call_test_method("trunk_update_postcommit", PORT_BAREMETAL)
|
||||||
|
|
||||||
|
self.plugin.get_port.assert_called_once_with(mock.ANY, PORT_ID)
|
||||||
|
self.assertFalse(self.plugin.update_port.call_count)
|
||||||
|
|
||||||
|
def test_trunk_update_postcommit_baremetal_down_state(self):
|
||||||
|
TRUNK['status'] = bc.constants.PORT_STATUS_DOWN
|
||||||
|
self._call_test_method("trunk_update_postcommit", PORT_BAREMETAL)
|
||||||
|
|
||||||
|
self.plugin.get_port.assert_called_once_with(mock.ANY, PORT_ID)
|
||||||
|
self.assertEqual(
|
||||||
|
len(TRUNK['sub_ports']), self.plugin.update_port.call_count)
|
||||||
|
self.plugin.update_port.assert_called_with(mock.ANY, PORT_ID, mock.ANY)
|
||||||
|
|
||||||
|
def test_subport_postcommit_baremetal_after_create(self):
|
||||||
|
self._call_test_method(
|
||||||
|
"subport_postcommit", PORT_BAREMETAL, event=events.AFTER_CREATE)
|
||||||
|
|
||||||
|
self._verify_subport_postcommit()
|
||||||
|
self.plugin.update_port.assert_called_with(mock.ANY, PORT_ID, mock.ANY)
|
||||||
|
self.assertEqual(
|
||||||
|
bc.constants.PORT_STATUS_ACTIVE,
|
||||||
|
self.plugin.update_port.call_args[0][2]['port']['status'])
|
||||||
|
|
||||||
|
def test_subport_postcommit_baremetal_after_delete(self):
|
||||||
|
self._call_test_method(
|
||||||
|
"subport_postcommit", PORT_BAREMETAL, event=events.AFTER_DELETE)
|
||||||
|
|
||||||
|
self.plugin.update_port.assert_called_with(mock.ANY, PORT_ID, mock.ANY)
|
||||||
|
self.assertEqual(
|
||||||
|
bc.constants.PORT_STATUS_DOWN,
|
||||||
|
self.plugin.update_port.call_args[0][2]['port']['status'])
|
||||||
|
|
||||||
|
def test_subport_postcommit_baremetal_unsupported_event(self):
|
||||||
|
self._call_test_method(
|
||||||
|
"subport_postcommit", PORT_BAREMETAL, event=events.BEFORE_DELETE)
|
||||||
|
|
||||||
|
self._verify_subport_postcommit_unsupported_event()
|
||||||
|
|
||||||
|
def test_subport_postcommit_vm(self):
|
||||||
|
self._call_test_method(
|
||||||
|
"subport_postcommit", PORT_VM, event=events.AFTER_CREATE)
|
||||||
|
|
||||||
|
self._verify_subport_postcommit_unsupported()
|
||||||
|
|
||||||
|
def test_subport_postcommit_vm_no_hostid(self):
|
||||||
|
PORT_VM_NO_HOSTID = PORT_VM.copy()
|
||||||
|
del PORT_VM_NO_HOSTID[bc.portbindings.HOST_ID]
|
||||||
|
self._call_test_method(
|
||||||
|
"subport_postcommit", PORT_VM_NO_HOSTID,
|
||||||
|
event=events.AFTER_CREATE)
|
||||||
|
|
||||||
|
self._verify_subport_postcommit_unsupported()
|
||||||
|
|
||||||
|
def test_subport_postcommit_vm_unsupported_event(self):
|
||||||
|
self._call_test_method(
|
||||||
|
"subport_postcommit", PORT_VM, event=events.BEFORE_DELETE)
|
||||||
|
|
||||||
|
self._verify_subport_postcommit_unsupported()
|
||||||
|
|
||||||
|
|
||||||
|
@testtools.skipIf(bc.NEUTRON_VERSION < bc.NEUTRON_OCATA_VERSION,
|
||||||
|
"Test not applicable prior to stable/ocata.")
|
||||||
|
class TestNexusTrunkDriver(testlib_api.SqlTestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super(TestNexusTrunkDriver, self).setUp()
|
||||||
|
|
||||||
|
def test_is_loaded(self):
|
||||||
|
driver = nexus_trunk.NexusTrunkDriver.create()
|
||||||
|
cfg.CONF.set_override('mechanism_drivers',
|
||||||
|
["logger", const.CISCO_NEXUS_ML2_MECH_DRIVER_V2],
|
||||||
|
group='ml2')
|
||||||
|
self.assertTrue(driver.is_loaded)
|
||||||
|
|
||||||
|
cfg.CONF.set_override('mechanism_drivers',
|
||||||
|
['logger'],
|
||||||
|
group='ml2')
|
||||||
|
self.assertFalse(driver.is_loaded)
|
||||||
|
|
||||||
|
cfg.CONF.set_override('core_plugin', 'some_plugin')
|
||||||
|
self.assertFalse(driver.is_loaded)
|
Loading…
Reference in New Issue