Merge "Enhancements to Cisco v2 meta-plugin"

This commit is contained in:
Jenkins 2012-08-15 08:16:21 +00:00 committed by Gerrit Code Review
commit 8a09da6495
11 changed files with 536 additions and 41 deletions

View File

@ -7,5 +7,5 @@ ports=<put_interfaces_names_here_separated_by_commas>
nexus_ssh_port=22 nexus_ssh_port=22
[DRIVER] [DRIVER]
#name=quantum.plugins.cisco.nexus.cisco_nexus_network_driver.CiscoNEXUSDriver #name=quantum.plugins.cisco.nexus.cisco_nexus_network_driver_v2.CiscoNEXUSDriver
name=quantum.plugins.cisco.tests.unit.v2.nexus.fake_nexus_driver.CiscoNEXUSFakeDriver name=quantum.plugins.cisco.tests.unit.v2.nexus.fake_nexus_driver.CiscoNEXUSFakeDriver

View File

@ -254,6 +254,38 @@ PYTHONPATH=. python quantum/plugins/cisco/client/cli.py create_multiport <tenant
(Note that you should not be using the create port core API in the above case.) (Note that you should not be using the create port core API in the above case.)
Using an independent plugin as a device sub-plugin
-------------------------------------------------
If you would like to use an independent virtual switch plugin as one of the sub-plugins
(for eg: the OpenVSwitch plugin) with the nexus device sub-plugin perform the following steps:
(The following instructions are with respect to the OpenVSwitch plugin)
1. Update etc/quantum/plugins/cisco/l2network_plugin.ini
In the [MODEL] section of the configuration file put the following configuration
(note that this should be the only configuration in this section, all other configuration
should be either removed or commented)
model_class=quantum.plugins.cisco.models.virt_phy_sw_v2.VirtualPhysicalSwitchModelV2
2. Update etc/quantum/plugins/cisco/cisco_plugins.ini
In the [PLUGINS] section of the configuration file put the following configuration:
vswitch_plugin=quantum.plugins.openvswitch.ovs_quantum_plugin.OVSQuantumPluginV2
3. Set the DB name, the same name has to be configured in three places:
In etc/quantum/plugins/cisco/conf/db_conn.ini set the "name" value
In /etc/quantum/plugins/openvswitch/ovs_quantum_plugin.ini set the "sql_connection"
In /etc/quantum/dhcp_agent.ini set the "db_connection"
4. The range of VLAN IDs has to be set in the OpenVSwitch configuration file:
In /etc/quantum/plugins/openvswitch/ovs_quantum_plugin.ini
Set:
vlan_min = <lower_id>
vlan_max = <higher_id>
enable_tunneling = False
5. For Nexus device sub-plugin configuration refer to the above sections
How to test the installation How to test the installation
---------------------------- ----------------------------

View File

@ -117,6 +117,7 @@ UCS_PLUGIN = 'ucs_plugin'
NEXUS_PLUGIN = 'nexus_plugin' NEXUS_PLUGIN = 'nexus_plugin'
UCS_INVENTORY = 'ucs_inventory' UCS_INVENTORY = 'ucs_inventory'
NEXUS_INVENTORY = 'nexus_inventory' NEXUS_INVENTORY = 'nexus_inventory'
VSWITCH_PLUGIN = 'vswitch_plugin'
PLUGIN_OBJ_REF = 'plugin-obj-ref' PLUGIN_OBJ_REF = 'plugin-obj-ref'
PARAM_LIST = 'param-list' PARAM_LIST = 'param-list'

View File

@ -146,7 +146,7 @@ def get_all_vlan_bindings():
LOG.debug("get_all_vlan_bindings() called") LOG.debug("get_all_vlan_bindings() called")
session = db.get_session() session = db.get_session()
try: try:
bindings = session.query(network_models_v2.VlanBinding).all() bindings = session.query(network_models_v2.Vlan_Binding).all()
return bindings return bindings
except exc.NoResultFound: except exc.NoResultFound:
return [] return []
@ -157,7 +157,7 @@ def get_vlan_binding(netid):
LOG.debug("get_vlan_binding() called") LOG.debug("get_vlan_binding() called")
session = db.get_session() session = db.get_session()
try: try:
binding = (session.query(network_models_v2.VlanBinding). binding = (session.query(network_models_v2.Vlan_Binding).
filter_by(network_id=netid).one()) filter_by(network_id=netid).one())
return binding return binding
except exc.NoResultFound: except exc.NoResultFound:
@ -169,12 +169,12 @@ def add_vlan_binding(vlanid, vlanname, netid):
LOG.debug("add_vlan_binding() called") LOG.debug("add_vlan_binding() called")
session = db.get_session() session = db.get_session()
try: try:
binding = (session.query(network_models_v2.VlanBinding). binding = (session.query(network_models_v2.Vlan_Binding).
filter_by(vlan_id=vlanid).one()) filter_by(vlan_id=vlanid).one())
raise c_exc.NetworkVlanBindingAlreadyExists(vlan_id=vlanid, raise c_exc.NetworkVlanBindingAlreadyExists(vlan_id=vlanid,
network_id=netid) network_id=netid)
except exc.NoResultFound: except exc.NoResultFound:
binding = network_models_v2.VlanBinding(vlanid, vlanname, netid) binding = network_models_v2.Vlan_Binding(vlanid, vlanname, netid)
session.add(binding) session.add(binding)
session.flush() session.flush()
return binding return binding
@ -185,7 +185,7 @@ def remove_vlan_binding(netid):
LOG.debug("remove_vlan_binding() called") LOG.debug("remove_vlan_binding() called")
session = db.get_session() session = db.get_session()
try: try:
binding = (session.query(network_models_v2.VlanBinding). binding = (session.query(network_models_v2.Vlan_Binding).
filter_by(network_id=netid).one()) filter_by(network_id=netid).one())
session.delete(binding) session.delete(binding)
session.flush() session.flush()
@ -199,7 +199,7 @@ def update_vlan_binding(netid, newvlanid=None, newvlanname=None):
LOG.debug("update_vlan_binding() called") LOG.debug("update_vlan_binding() called")
session = db.get_session() session = db.get_session()
try: try:
binding = (session.query(network_models_v2.VlanBinding). binding = (session.query(network_models_v2.Vlan_Binding).
filter_by(network_id=netid).one()) filter_by(network_id=netid).one())
if newvlanid: if newvlanid:
binding["vlan_id"] = newvlanid binding["vlan_id"] = newvlanid

View File

@ -68,7 +68,7 @@ class L2NetworkBase(object):
class VlanID(model_base.BASEV2, L2NetworkBase): class VlanID(model_base.BASEV2, L2NetworkBase):
"""Represents a vlan_id usage""" """Represents a vlan_id usage"""
__tablename__ = 'vlan_ids' __tablename__ = 'cisco_vlan_ids'
vlan_id = Column(Integer, primary_key=True) vlan_id = Column(Integer, primary_key=True)
vlan_used = Column(Boolean) vlan_used = Column(Boolean)
@ -81,9 +81,9 @@ class VlanID(model_base.BASEV2, L2NetworkBase):
return "<VlanID(%d,%s)>" % (self.vlan_id, self.vlan_used) return "<VlanID(%d,%s)>" % (self.vlan_id, self.vlan_used)
class VlanBinding(model_base.BASEV2, L2NetworkBase): class Vlan_Binding(model_base.BASEV2, L2NetworkBase):
"""Represents a binding of vlan_id to network_id""" """Represents a binding of vlan_id to network_id"""
__tablename__ = 'vlan_bindings' __tablename__ = 'cisco_vlan_bindings'
vlan_id = Column(Integer, primary_key=True) vlan_id = Column(Integer, primary_key=True)
vlan_name = Column(String(255)) vlan_name = Column(String(255))

View File

@ -0,0 +1,251 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Copyright 2012 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.
#
# @author: Sumit Naiksatam, Cisco Systems, Inc.
# @author: Rohit Agarwalla, Cisco Systems, Inc.
from copy import deepcopy
import inspect
import logging
from quantum.manager import QuantumManager
from quantum.openstack.common import importutils
from quantum.plugins.cisco.common import cisco_constants as const
from quantum.plugins.cisco.common import cisco_credentials_v2 as cred
from quantum.plugins.cisco.db import network_db_v2 as cdb
from quantum.plugins.cisco import l2network_plugin_configuration as conf
from quantum.plugins.openvswitch import ovs_db_v2 as odb
from quantum import quantum_plugin_base_v2
LOG = logging.getLogger(__name__)
class VirtualPhysicalSwitchModelV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
"""
This implementation works with OVS and Nexus plugin for the
following topology:
One or more servers to a nexus switch.
"""
MANAGE_STATE = True
supported_extension_aliases = []
_plugins = {}
_inventory = {}
_methods_to_delegate = ['update_network', 'get_network', 'get_networks',
'create_port', 'delete_port', 'update_port',
'get_port', 'get_ports',
'create_subnet', 'delete_subnet', 'update_subnet',
'get_subnet', 'get_subnets']
def __init__(self):
"""
Initialize the segmentation manager, check which device plugins are
configured, and load the inventories those device plugins for which the
inventory is configured
"""
cdb.initialize()
cred.Store.initialize()
for key in conf.PLUGINS[const.PLUGINS].keys():
plugin_obj = conf.PLUGINS[const.PLUGINS][key]
self._plugins[key] = importutils.import_object(plugin_obj)
LOG.debug("Loaded device plugin %s\n" %
conf.PLUGINS[const.PLUGINS][key])
if key in conf.PLUGINS[const.INVENTORY].keys():
inventory_obj = conf.PLUGINS[const.INVENTORY][key]
self._inventory[key] = importutils.import_object(inventory_obj)
LOG.debug("Loaded device inventory %s\n" %
conf.PLUGINS[const.INVENTORY][key])
LOG.debug("%s.%s init done" % (__name__, self.__class__.__name__))
def __getattribute__(self, name):
methods = object.__getattribute__(self, "_methods_to_delegate")
if name in methods:
return getattr(object.__getattribute__(self, "_plugins")
[const.VSWITCH_PLUGIN], name)
else:
return object.__getattribute__(self, name)
def _func_name(self, offset=0):
"""Get the name of the calling function"""
frame_record = inspect.stack()[1 + offset]
func_name = frame_record[3]
return func_name
def _invoke_plugin_per_device(self, plugin_key, function_name, args):
"""
Invokes a device plugin's relevant functions (on the it's
inventory and plugin implementation) for completing this operation.
"""
if not plugin_key in self._plugins.keys():
LOG.info("No %s Plugin loaded" % plugin_key)
LOG.info("%s: %s with args %s ignored" %
(plugin_key, function_name, args))
return
device_params = self._invoke_inventory(plugin_key, function_name,
args)
device_ips = device_params[const.DEVICE_IP]
if not device_ips:
return [self._invoke_plugin(plugin_key, function_name, args,
device_params)]
else:
output = []
for device_ip in device_ips:
new_device_params = deepcopy(device_params)
new_device_params[const.DEVICE_IP] = device_ip
output.append(self._invoke_plugin(plugin_key, function_name,
args, new_device_params))
return output
def _invoke_inventory(self, plugin_key, function_name, args):
"""
Invokes the relevant function on a device plugin's
inventory for completing this operation.
"""
if not plugin_key in self._inventory.keys():
LOG.info("No %s inventory loaded" % plugin_key)
LOG.info("%s: %s with args %s ignored" %
(plugin_key, function_name, args))
return {const.DEVICE_IP: []}
else:
return getattr(self._inventory[plugin_key], function_name)(args)
def _invoke_plugin(self, plugin_key, function_name, args, kwargs):
"""
Invokes the relevant function on a device plugin's
implementation for completing this operation.
"""
func = getattr(self._plugins[plugin_key], function_name)
func_args_len = int(inspect.getargspec(func).args.__len__()) - 1
fargs, varargs, varkw, defaults = inspect.getargspec(func)
if args.__len__() > func_args_len:
func_args = args[:func_args_len]
extra_args = args[func_args_len:]
for dict_arg in extra_args:
for k, v in dict_arg.iteritems():
kwargs[k] = v
return func(*func_args, **kwargs)
else:
if (varkw == 'kwargs'):
return func(*args, **kwargs)
else:
return func(*args)
def create_network(self, context, network):
"""
Perform this operation in the context of the configured device
plugins.
"""
LOG.debug("create_network() called\n")
try:
args = [context, network]
ovs_output = self._invoke_plugin_per_device(const.VSWITCH_PLUGIN,
self._func_name(),
args)
vlan_id = odb.get_vlan(ovs_output[0]['id'])
vlan_name = conf.VLAN_NAME_PREFIX + str(vlan_id)
vlan_ids = odb.get_vlans()
vlanids = ''
for v_id in vlan_ids:
vlanids = str(v_id[0]) + ',' + vlanids
vlanids = vlanids.strip(',')
args = [ovs_output[0]['tenant_id'], ovs_output[0]['name'],
ovs_output[0]['id'], vlan_name, vlan_id,
{'vlan_ids':vlanids}]
nexus_output = self._invoke_plugin_per_device(const.NEXUS_PLUGIN,
self._func_name(),
args)
return ovs_output[0]
except:
# TODO (Sumit): Check if we need to perform any rollback here
raise
def update_network(self, context, id, network):
"""For this model this method will be delegated to vswitch plugin"""
pass
def delete_network(self, context, id):
"""
Perform this operation in the context of the configured device
plugins.
"""
try:
base_plugin_ref = QuantumManager.get_plugin()
n = base_plugin_ref.get_network(context, id)
tenant_id = n['tenant_id']
vlan_id = odb.get_vlan(id)
output = []
args = [tenant_id, id, {const.VLANID:vlan_id},
{const.CONTEXT:context},
{const.BASE_PLUGIN_REF:base_plugin_ref}]
nexus_output = self._invoke_plugin_per_device(const.NEXUS_PLUGIN,
self._func_name(),
args)
args = [context, id]
ovs_output = self._invoke_plugin_per_device(const.VSWITCH_PLUGIN,
self._func_name(),
args)
return ovs_output[0]
except:
raise
def get_network(self, context, id, fields=None, verbose=None):
"""For this model this method will be delegated to vswitch plugin"""
pass
def get_networks(self, context, filters=None, fields=None, verbose=None):
"""For this model this method will be delegated to vswitch plugin"""
pass
def create_port(self, context, port):
"""For this model this method will be delegated to vswitch plugin"""
pass
def get_port(self, context, id, fields=None, verbose=None):
"""For this model this method will be delegated to vswitch plugin"""
pass
def get_ports(self, context, filters=None, fields=None, verbose=None):
"""For this model this method will be delegated to vswitch plugin"""
pass
def update_port(self, context, id, port):
"""For this model this method will be delegated to vswitch plugin"""
pass
def delete_port(self, context, id, kwargs):
"""For this model this method will be delegated to vswitch plugin"""
pass
def create_subnet(self, context, subnet):
"""For this model this method will be delegated to vswitch plugin"""
pass
def update_subnet(self, context, id, subnet):
"""For this model this method will be delegated to vswitch plugin"""
pass
def get_subnet(self, context, id, fields=None, verbose=None):
"""For this model this method will be delegated to vswitch plugin"""
pass
def delete_subnet(self, context, id, kwargs):
"""For this model this method will be delegated to vswitch plugin"""
pass
def get_subnets(self, context, filters=None, fields=None, verbose=None):
"""For this model this method will be delegated to vswitch plugin"""
pass

View File

@ -29,45 +29,83 @@ from quantum.plugins.cisco.common import cisco_exceptions as cexc
from quantum.plugins.cisco.common import cisco_utils as cutil from quantum.plugins.cisco.common import cisco_utils as cutil
from quantum.plugins.cisco.db import network_db_v2 as cdb from quantum.plugins.cisco.db import network_db_v2 as cdb
from quantum.plugins.cisco import l2network_plugin_configuration as conf from quantum.plugins.cisco import l2network_plugin_configuration as conf
from quantum.quantum_plugin_base_v2 import QuantumPluginBaseV2
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
class PluginV2(db_base_plugin_v2.QuantumDbPluginV2): class PluginV2(db_base_plugin_v2.QuantumDbPluginV2):
""" """
Plugin with v2 API support for multiple sub-plugins Meta-Plugin with v2 API support for multiple sub-plugins.
""" """
supported_extension_aliases = ["Cisco Credential", "Cisco Port Profile", supported_extension_aliases = ["Cisco Credential", "Cisco Port Profile",
"Cisco qos", "Cisco Nova Tenant", "Cisco qos", "Cisco Nova Tenant",
"Cisco Multiport"] "Cisco Multiport"]
_methods_to_delegate = ['create_network', 'delete_network',
'update_network', 'get_network', 'get_networks',
'create_port', 'delete_port', 'update_port',
'get_port', 'get_ports',
'create_subnet', 'delete_subnet', 'update_subnet',
'get_subnet', 'get_subnets']
_master = True
def __init__(self):
"""
Loads the model class, initializes the DB, and credential store.
"""
self._model = importutils.import_object(conf.MODEL_CLASS)
if hasattr(self._model, "MANAGE_STATE") and self._model.MANAGE_STATE:
self._master = False
LOG.debug("Model %s manages state" % conf.MODEL_CLASS)
else:
cdb.initialize()
cred.Store.initialize()
if hasattr(self._model, "supported_extension_aliases"):
self.supported_extension_aliases.extend(
self._model.supported_extension_aliases)
super(PluginV2, self).__init__()
LOG.debug("Plugin initialization complete")
def __getattribute__(self, name):
"""
When the configured model class offers to manage the state of the
logical resources, we delegate the core API calls directly to it.
"""
master = object.__getattribute__(self, "_master")
methods = object.__getattribute__(self, "_methods_to_delegate")
if not master and name in methods:
return getattr(object.__getattribute__(self, "_model"),
name)
else:
return object.__getattribute__(self, name)
def __getattr__(self, name):
"""
This delegates the calls to the extensions explicitly implemented by
the model.
"""
if hasattr(self._model, name):
return getattr(self._model, name)
""" """
Core API implementation Core API implementation
""" """
def __init__(self):
"""
Initializes the DB, and credential store.
"""
cdb.initialize()
cred.Store.initialize()
self._model = importutils.import_object(conf.MODEL_CLASS)
super(PluginV2, self).__init__()
LOG.debug("Plugin initialization complete")
def create_network(self, context, network): def create_network(self, context, network):
""" """
Creates a new Virtual Network, and assigns it Creates a new Virtual Network, and assigns it
a symbolic name. a symbolic name.
""" """
LOG.debug("create_network() called\n") LOG.debug("create_network() called\n")
new_network = super(PluginV2, self).create_network(context, network) new_network = super(PluginV2, self).create_network(context,
network)
try: try:
self._invoke_device_plugins(self._func_name(), [context, self._invoke_device_plugins(self._func_name(), [context,
new_network]) new_network])
return new_network return new_network
except: except:
super(PluginV2, self).delete_network(context, new_network['id']) super(PluginV2, self).delete_network(context,
new_network['id'])
raise raise
def update_network(self, context, id, network): def update_network(self, context, id, network):
@ -79,7 +117,8 @@ class PluginV2(db_base_plugin_v2.QuantumDbPluginV2):
try: try:
self._invoke_device_plugins(self._func_name(), [context, id, self._invoke_device_plugins(self._func_name(), [context, id,
network]) network])
return super(PluginV2, self).update_network(context, id, network) return super(PluginV2, self).update_network(context, id,
network)
except: except:
raise raise
@ -92,7 +131,6 @@ class PluginV2(db_base_plugin_v2.QuantumDbPluginV2):
#We first need to check if there are any ports on this network #We first need to check if there are any ports on this network
with context.session.begin(): with context.session.begin():
network = self._get_network(context, id) network = self._get_network(context, id)
filter = {'network_id': [id]} filter = {'network_id': [id]}
ports = self.get_ports(context, filters=filter) ports = self.get_ports(context, filters=filter)
if ports: if ports:
@ -109,6 +147,22 @@ class PluginV2(db_base_plugin_v2.QuantumDbPluginV2):
except: except:
raise raise
def get_network(self, context, id, fields=None, verbose=None):
"""
Gets a particular network
"""
LOG.debug("get_network() called\n")
return super(PluginV2, self).get_network(context, id,
fields, verbose)
def get_networks(self, context, filters=None, fields=None, verbose=None):
"""
Gets all networks
"""
LOG.debug("get_networks() called\n")
return super(PluginV2, self).get_networks(context, filters,
fields, verbose)
def create_port(self, context, port): def create_port(self, context, port):
""" """
Creates a port on the specified Virtual Network. Creates a port on the specified Virtual Network.
@ -446,9 +500,11 @@ class PluginV2(db_base_plugin_v2.QuantumDbPluginV2):
""" """
def _invoke_device_plugins(self, function_name, args): def _invoke_device_plugins(self, function_name, args):
""" """
All device-specific calls are delegated to the model Device-specific calls including core API and extensions are
delegated to the model.
""" """
return getattr(self._model, function_name)(*args) if hasattr(self._model, function_name):
return getattr(self._model, function_name)(*args)
def _func_name(self, offset=0): def _func_name(self, offset=0):
"""Getting the name of the calling funciton""" """Getting the name of the calling funciton"""

View File

@ -0,0 +1,150 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Copyright 2011 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.
#
# @author: Debojyoti Dutta, Cisco Systems, Inc.
# @author: Edgar Magana, Cisco Systems Inc.
#
"""
Implements a Nexus-OS NETCONF over SSHv2 API Client
"""
import logging
from ncclient import manager
from quantum.plugins.cisco.db import network_db_v2 as cdb
from quantum.plugins.cisco.nexus import cisco_nexus_snippets as snipp
LOG = logging.getLogger(__name__)
class CiscoNEXUSDriver():
"""
Nexus Driver Main Class
"""
def __init__(self):
pass
def nxos_connect(self, nexus_host, nexus_ssh_port, nexus_user,
nexus_password):
"""
Makes the SSH connection to the Nexus Switch
"""
man = manager.connect(host=nexus_host, port=nexus_ssh_port,
username=nexus_user, password=nexus_password)
return man
def create_xml_snippet(self, cutomized_config):
"""
Creates the Proper XML structure for the Nexus Switch Configuration
"""
conf_xml_snippet = snipp.EXEC_CONF_SNIPPET % (cutomized_config)
return conf_xml_snippet
def enable_vlan(self, mgr, vlanid, vlanname):
"""
Creates a VLAN on Nexus Switch given the VLAN ID and Name
"""
confstr = snipp.CMD_VLAN_CONF_SNIPPET % (vlanid, vlanname)
confstr = self.create_xml_snippet(confstr)
mgr.edit_config(target='running', config=confstr)
def disable_vlan(self, mgr, vlanid):
"""
Delete a VLAN on Nexus Switch given the VLAN ID
"""
confstr = snipp.CMD_NO_VLAN_CONF_SNIPPET % vlanid
confstr = self.create_xml_snippet(confstr)
mgr.edit_config(target='running', config=confstr)
def enable_port_trunk(self, mgr, interface):
"""
Enables trunk mode an interface on Nexus Switch
"""
confstr = snipp.CMD_PORT_TRUNK % (interface)
confstr = self.create_xml_snippet(confstr)
LOG.debug("NexusDriver: %s" % confstr)
mgr.edit_config(target='running', config=confstr)
def disable_switch_port(self, mgr, interface):
"""
Disables trunk mode an interface on Nexus Switch
"""
confstr = snipp.CMD_NO_SWITCHPORT % (interface)
confstr = self.create_xml_snippet(confstr)
LOG.debug("NexusDriver: %s" % confstr)
mgr.edit_config(target='running', config=confstr)
def enable_vlan_on_trunk_int(self, mgr, interface, vlanid):
"""
Enables trunk mode vlan access an interface on Nexus Switch given
VLANID
"""
confstr = snipp.CMD_VLAN_INT_SNIPPET % (interface, vlanid)
confstr = self.create_xml_snippet(confstr)
LOG.debug("NexusDriver: %s" % confstr)
mgr.edit_config(target='running', config=confstr)
def disable_vlan_on_trunk_int(self, mgr, interface, vlanid):
"""
Enables trunk mode vlan access an interface on Nexus Switch given
VLANID
"""
confstr = snipp.CMD_NO_VLAN_INT_SNIPPET % (interface, vlanid)
confstr = self.create_xml_snippet(confstr)
LOG.debug("NexusDriver: %s" % confstr)
mgr.edit_config(target='running', config=confstr)
def create_vlan(self, vlan_name, vlan_id, nexus_host, nexus_user,
nexus_password, nexus_ports,
nexus_ssh_port, vlan_ids=None):
"""
Creates a VLAN and Enable on trunk mode an interface on Nexus Switch
given the VLAN ID and Name and Interface Number
"""
with self.nxos_connect(nexus_host, int(nexus_ssh_port), nexus_user,
nexus_password) as man:
self.enable_vlan(man, vlan_id, vlan_name)
if vlan_ids is '':
vlan_ids = self.build_vlans_cmd()
LOG.debug("NexusDriver VLAN IDs: %s" % vlan_ids)
for ports in nexus_ports:
self.enable_vlan_on_trunk_int(man, ports, vlan_ids)
def delete_vlan(self, vlan_id, nexus_host, nexus_user, nexus_password,
nexus_ports, nexus_ssh_port):
"""
Delete a VLAN and Disables trunk mode an interface on Nexus Switch
given the VLAN ID and Interface Number
"""
with self.nxos_connect(nexus_host, int(nexus_ssh_port), nexus_user,
nexus_password) as man:
self.disable_vlan(man, vlan_id)
for ports in nexus_ports:
self.disable_vlan_on_trunk_int(man, ports, vlan_id)
def build_vlans_cmd(self):
"""
Builds a string with all the VLANs on the same Switch
"""
assigned_vlan = cdb.get_all_vlanids_used()
vlans = ''
for vlanid in assigned_vlan:
vlans = str(vlanid["vlan_id"]) + ',' + vlans
if vlans == '':
vlans = 'none'
return vlans.strip(',')

View File

@ -71,10 +71,14 @@ class NexusPlugin(L2DevicePluginBase):
for this VLAN for this VLAN
""" """
LOG.debug("NexusPlugin:create_network() called\n") LOG.debug("NexusPlugin:create_network() called\n")
vlan_ids = ''
for key in kwargs:
if key == 'vlan_ids':
vlan_ids = kwargs['vlan_ids']
self._client.create_vlan( self._client.create_vlan(
vlan_name, str(vlan_id), self._nexus_ip, vlan_name, str(vlan_id), self._nexus_ip,
self._nexus_username, self._nexus_password, self._nexus_username, self._nexus_password,
self._nexus_ports, self._nexus_ssh_port) self._nexus_ports, self._nexus_ssh_port, vlan_ids)
for ports in self._nexus_ports: for ports in self._nexus_ports:
try: try:
nxos_db.add_nexusport_binding(ports, str(vlan_id)) nxos_db.add_nexusport_binding(ports, str(vlan_id))
@ -95,10 +99,15 @@ class NexusPlugin(L2DevicePluginBase):
from the relevant interfaces from the relevant interfaces
""" """
LOG.debug("NexusPlugin:delete_network() called\n") LOG.debug("NexusPlugin:delete_network() called\n")
vlan_id = None
context = kwargs[const.CONTEXT] context = kwargs[const.CONTEXT]
base_plugin_ref = kwargs[const.BASE_PLUGIN_REF] base_plugin_ref = kwargs[const.BASE_PLUGIN_REF]
vlan_id = self._get_vlan_id_for_network(tenant_id, net_id, for key in kwargs:
context, base_plugin_ref) if key == 'vlan_id':
vlan_id = kwargs['vlan_id']
if vlan_id is None:
vlan_id = self._get_vlan_id_for_network(tenant_id, net_id,
context, base_plugin_ref)
ports_id = nxos_db.get_nexusport_binding(vlan_id) ports_id = nxos_db.get_nexusport_binding(vlan_id)
LOG.debug("NexusPlugin: Interfaces to be disassociated: %s" % ports_id) LOG.debug("NexusPlugin: Interfaces to be disassociated: %s" % ports_id)
nxos_db.remove_nexusport_binding(vlan_id) nxos_db.remove_nexusport_binding(vlan_id)
@ -185,10 +194,8 @@ class NexusPlugin(L2DevicePluginBase):
""" """
Obtain the VLAN ID given the Network ID Obtain the VLAN ID given the Network ID
""" """
net = self._get_network(tenant_id, network_id, context, vlan = cdb.get_vlan_binding(network_id)
base_plugin_ref) return vlan.vlan_id
vlan_id = net[const.NET_VLAN_ID]
return vlan_id
def _get_network(self, tenant_id, network_id, context, base_plugin_ref): def _get_network(self, tenant_id, network_id, context, base_plugin_ref):
""" """
@ -197,8 +204,5 @@ class NexusPlugin(L2DevicePluginBase):
network = base_plugin_ref._get_network(context, network_id) network = base_plugin_ref._get_network(context, network_id)
if not network: if not network:
raise exc.NetworkNotFound(net_id=network_id) raise exc.NetworkNotFound(net_id=network_id)
vlan = cdb.get_vlan_binding(network_id)
return {const.NET_ID: network_id, const.NET_NAME: network.name, return {const.NET_ID: network_id, const.NET_NAME: network.name,
const.NET_PORTS: network.ports, const.NET_PORTS: network.ports}
const.NET_VLAN_NAME: vlan.vlan_name,
const.NET_VLAN_ID: vlan.vlan_id}

View File

@ -29,7 +29,7 @@ LOG = logging.getLogger(__name__)
# The following are standard strings, messages used to communicate with Nexus, # The following are standard strings, messages used to communicate with Nexus,
EXEC_CONF_SNIPPET = """ EXEC_CONF_SNIPPET = """
<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0"> <config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
<configure xmlns="http://www.cisco.com/nxos:1.0:vlan_mgr_cli"> <configure>
<__XML__MODE__exec_configure>%s <__XML__MODE__exec_configure>%s
</__XML__MODE__exec_configure> </__XML__MODE__exec_configure>
</configure> </configure>

View File

@ -21,6 +21,7 @@ import os
from quantum.api.v2.router import APIRouter from quantum.api.v2.router import APIRouter
from quantum.common import config from quantum.common import config
from quantum.db import api as db from quantum.db import api as db
from quantum.manager import QuantumManager
from quantum.plugins.cisco.db import network_models_v2 from quantum.plugins.cisco.db import network_models_v2
from quantum.openstack.common import cfg from quantum.openstack.common import cfg
from quantum.tests.unit import test_db_plugin from quantum.tests.unit import test_db_plugin
@ -38,7 +39,7 @@ class NetworkPluginV2TestCase(test_db_plugin.QuantumDbPluginV2TestCase):
def setUp(self): def setUp(self):
db._ENGINE = None db._ENGINE = None
db._MAKER = None db._MAKER = None
QuantumManager._instance = None
self._tenant_id = 'test-tenant' self._tenant_id = 'test-tenant'
json_deserializer = JSONDeserializer() json_deserializer = JSONDeserializer()