
Blueprint cisco-plugin-v2-api-support New meta-plugin which makes use of the Quantum db_plugin and supports the new v2 API Changes to the Cisco DB model, now reusing quantum DB for core attributes Changes to the device sub plugins to access the quantum DB for core resources' state versus Cisco DB Addition of fake/dummy drivers to support testing of the device sub plugins even without actual hardware New v2 unit tests which exercise the meta-plugin and the device sub -plugins as well In general creating new v2 modules such that v1.x code can be deprecated easily by deleting the older modules. The following files are v2 versions of older modules, only the imports have changed, most of the other code is the same as from the older modules (already reviewed): quantum/plugins/cisco/common/cisco_credentials_v2.py quantum/plugins/cisco/db/network_db_v2.py quantum/plugins/cisco/db/network_models_v2.py quantum/plugins/cisco/db/nexus_db_v2.py quantum/plugins/cisco/db/nexus_models_v2.py quantum/plugins/cisco/db/ucs_db_v2.py quantum/plugins/cisco/db/ucs_models_v2.py quantum/plugins/cisco/nexus/cisco_nexus_plugin_v2.py quantum/plugins/cisco/ucs/cisco_ucs_inventory_v2.py quantum/plugins/cisco/ucs/cisco_ucs_plugin_v2.py quantum/plugins/cisco/segmentation/l2network_vlan_mgr_v2.py All changes are contained with the Cisco plugin. (Sumit & Rohit) Change-Id: Ib82a9f843548c286c84ba63caf5406a773ac85b1
338 lines
15 KiB
Python
338 lines
15 KiB
Python
# 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.
|
|
#
|
|
|
|
import logging
|
|
|
|
from quantum.db import api as db
|
|
|
|
from quantum.openstack.common import importutils
|
|
from quantum.plugins.cisco.common import cisco_constants as const
|
|
from quantum.plugins.cisco.common import cisco_credentials as cred
|
|
from quantum.plugins.cisco.common import cisco_exceptions as cexc
|
|
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 ucs_db_v2 as udb
|
|
from quantum.plugins.cisco.l2device_plugin_base import L2DevicePluginBase
|
|
from quantum.plugins.cisco.ucs import cisco_ucs_configuration as conf
|
|
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
class UCSVICPlugin(L2DevicePluginBase):
|
|
"""UCS Device Plugin"""
|
|
|
|
def __init__(self):
|
|
self._driver = importutils.import_object(conf.UCSM_DRIVER)
|
|
LOG.debug("Loaded driver %s\n" % conf.UCSM_DRIVER)
|
|
# TODO (Sumit) Make the counter per UCSM
|
|
self._port_profile_counter = 0
|
|
|
|
def get_all_networks(self, tenant_id, **kwargs):
|
|
"""
|
|
Returns a dictionary containing all
|
|
<network_uuid, network_name> for
|
|
the specified tenant.
|
|
"""
|
|
LOG.debug("UCSVICPlugin:get_all_networks() called\n")
|
|
self._set_ucsm(kwargs[const.DEVICE_IP])
|
|
networks_list = db.network_list(tenant_id)
|
|
new_networks_list = []
|
|
for network in networks_list:
|
|
new_network_dict = cutil.make_net_dict(network[const.UUID],
|
|
network[const.NETWORKNAME],
|
|
[])
|
|
new_networks_list.append(new_network_dict)
|
|
|
|
return new_networks_list
|
|
|
|
def create_network(self, tenant_id, net_name, net_id, vlan_name, vlan_id,
|
|
**kwargs):
|
|
"""
|
|
Creates a new Virtual Network, and assigns it
|
|
a symbolic name.
|
|
"""
|
|
LOG.debug("UCSVICPlugin:create_network() called\n")
|
|
self._set_ucsm(kwargs[const.DEVICE_IP])
|
|
self._driver.create_vlan(vlan_name, str(vlan_id), self._ucsm_ip,
|
|
self._ucsm_username, self._ucsm_password)
|
|
ports_on_net = []
|
|
new_network_dict = cutil.make_net_dict(net_id,
|
|
net_name,
|
|
ports_on_net)
|
|
return new_network_dict
|
|
|
|
def delete_network(self, tenant_id, net_id, **kwargs):
|
|
"""
|
|
Deletes the network with the specified network identifier
|
|
belonging to the specified tenant.
|
|
"""
|
|
LOG.debug("UCSVICPlugin:delete_network() called\n")
|
|
self._set_ucsm(kwargs[const.DEVICE_IP])
|
|
vlan_binding = cdb.get_vlan_binding(net_id)
|
|
vlan_name = vlan_binding[const.VLANNAME]
|
|
self._driver.delete_vlan(vlan_name, self._ucsm_ip,
|
|
self._ucsm_username, self._ucsm_password)
|
|
#Rohit:passing empty network name, might not need fixing
|
|
net_dict = cutil.make_net_dict(net_id,
|
|
"",
|
|
[])
|
|
return net_dict
|
|
|
|
def get_network_details(self, tenant_id, net_id, **kwargs):
|
|
"""
|
|
Deletes the Virtual Network belonging to a the
|
|
spec
|
|
"""
|
|
LOG.debug("UCSVICPlugin:get_network_details() called\n")
|
|
self._set_ucsm(kwargs[const.DEVICE_IP])
|
|
network = db.network_get(net_id)
|
|
ports_list = network[const.NETWORKPORTS]
|
|
ports_on_net = []
|
|
for port in ports_list:
|
|
new_port = cutil.make_port_dict(port[const.UUID],
|
|
port[const.PORTSTATE],
|
|
port[const.NETWORKID],
|
|
port[const.INTERFACEID])
|
|
ports_on_net.append(new_port)
|
|
|
|
new_network = cutil.make_net_dict(network[const.UUID],
|
|
network[const.NETWORKNAME],
|
|
ports_on_net)
|
|
|
|
return new_network
|
|
|
|
def update_network(self, tenant_id, net_id, **kwargs):
|
|
"""
|
|
Updates the symbolic name belonging to a particular
|
|
Virtual Network.
|
|
"""
|
|
LOG.debug("UCSVICPlugin:update_network() called\n")
|
|
self._set_ucsm(kwargs[const.DEVICE_IP])
|
|
network = db.network_get(net_id)
|
|
net_dict = cutil.make_net_dict(network[const.UUID],
|
|
network[const.NETWORKNAME],
|
|
[])
|
|
return net_dict
|
|
|
|
def get_all_ports(self, tenant_id, net_id, **kwargs):
|
|
"""
|
|
Retrieves all port identifiers belonging to the
|
|
specified Virtual Network.
|
|
"""
|
|
LOG.debug("UCSVICPlugin:get_all_ports() called\n")
|
|
self._set_ucsm(kwargs[const.DEVICE_IP])
|
|
network = db.network_get(net_id)
|
|
ports_list = network[const.NETWORKPORTS]
|
|
ports_on_net = []
|
|
for port in ports_list:
|
|
port_binding = udb.get_portbinding(port[const.UUID])
|
|
ports_on_net.append(port_binding)
|
|
|
|
return ports_on_net
|
|
|
|
def create_port(self, tenant_id, net_id, port_state, port_id, **kwargs):
|
|
"""
|
|
Creates a port on the specified Virtual Network.
|
|
"""
|
|
LOG.debug("UCSVICPlugin:create_port() called\n")
|
|
self._set_ucsm(kwargs[const.DEVICE_IP])
|
|
qos = None
|
|
ucs_inventory = kwargs[const.UCS_INVENTORY]
|
|
least_rsvd_blade_dict = kwargs[const.LEAST_RSVD_BLADE_DICT]
|
|
chassis_id = least_rsvd_blade_dict[const.LEAST_RSVD_BLADE_CHASSIS]
|
|
blade_id = least_rsvd_blade_dict[const.LEAST_RSVD_BLADE_ID]
|
|
blade_data_dict = least_rsvd_blade_dict[const.LEAST_RSVD_BLADE_DATA]
|
|
new_port_profile = self._create_port_profile(tenant_id, net_id,
|
|
port_id,
|
|
conf.DEFAULT_VLAN_NAME,
|
|
conf.DEFAULT_VLAN_ID)
|
|
profile_name = new_port_profile[const.PROFILE_NAME]
|
|
rsvd_nic_dict = ucs_inventory.reserve_blade_interface(
|
|
self._ucsm_ip, chassis_id,
|
|
blade_id, blade_data_dict,
|
|
tenant_id, port_id,
|
|
profile_name)
|
|
port_binding = udb.update_portbinding(port_id,
|
|
portprofile_name=profile_name,
|
|
vlan_name=conf.DEFAULT_VLAN_NAME,
|
|
vlan_id=conf.DEFAULT_VLAN_ID,
|
|
qos=qos)
|
|
return port_binding
|
|
|
|
def delete_port(self, tenant_id, net_id, port_id, **kwargs):
|
|
"""
|
|
Deletes a port on a specified Virtual Network,
|
|
if the port contains a remote interface attachment,
|
|
the remote interface should first be un-plugged and
|
|
then the port can be deleted.
|
|
"""
|
|
LOG.debug("UCSVICPlugin:delete_port() called\n")
|
|
self._set_ucsm(kwargs[const.DEVICE_IP])
|
|
ucs_inventory = kwargs[const.UCS_INVENTORY]
|
|
chassis_id = kwargs[const.CHASSIS_ID]
|
|
blade_id = kwargs[const.BLADE_ID]
|
|
interface_dn = kwargs[const.BLADE_INTF_DN]
|
|
port_binding = udb.get_portbinding(port_id)
|
|
profile_name = port_binding[const.PORTPROFILENAME]
|
|
self._delete_port_profile(port_id, profile_name)
|
|
ucs_inventory.unreserve_blade_interface(self._ucsm_ip, chassis_id,
|
|
blade_id, interface_dn)
|
|
return udb.remove_portbinding(port_id)
|
|
|
|
def update_port(self, tenant_id, net_id, port_id, **kwargs):
|
|
"""
|
|
Updates the state of a port on the specified Virtual Network.
|
|
"""
|
|
LOG.debug("UCSVICPlugin:update_port() called\n")
|
|
self._set_ucsm(kwargs[const.DEVICE_IP])
|
|
pass
|
|
|
|
def get_port_details(self, tenant_id, net_id, port_id, **kwargs):
|
|
"""
|
|
This method allows the user to retrieve a remote interface
|
|
that is attached to this particular port.
|
|
"""
|
|
LOG.debug("UCSVICPlugin:get_port_details() called\n")
|
|
self._set_ucsm(kwargs[const.DEVICE_IP])
|
|
port_binding = udb.get_portbinding(port_id)
|
|
return port_binding
|
|
|
|
def plug_interface(self, tenant_id, net_id, port_id, remote_interface_id,
|
|
**kwargs):
|
|
"""
|
|
Attaches a remote interface to the specified port on the
|
|
specified Virtual Network.
|
|
"""
|
|
LOG.debug("UCSVICPlugin:plug_interface() called\n")
|
|
self._set_ucsm(kwargs[const.DEVICE_IP])
|
|
port_binding = udb.get_portbinding(port_id)
|
|
profile_name = port_binding[const.PORTPROFILENAME]
|
|
old_vlan_name = port_binding[const.VLANNAME]
|
|
new_vlan_name = self._get_vlan_name_for_network(tenant_id, net_id)
|
|
new_vlan_id = self._get_vlan_id_for_network(tenant_id, net_id)
|
|
self._driver.change_vlan_in_profile(profile_name, old_vlan_name,
|
|
new_vlan_name, self._ucsm_ip,
|
|
self._ucsm_username,
|
|
self._ucsm_password)
|
|
return udb.update_portbinding(port_id, vlan_name=new_vlan_name,
|
|
vlan_id=new_vlan_id)
|
|
|
|
def unplug_interface(self, tenant_id, net_id, port_id, **kwargs):
|
|
"""
|
|
Detaches a remote interface from the specified port on the
|
|
specified Virtual Network.
|
|
"""
|
|
LOG.debug("UCSVICPlugin:unplug_interface() called\n")
|
|
self._set_ucsm(kwargs[const.DEVICE_IP])
|
|
port_binding = udb.get_portbinding(port_id)
|
|
profile_name = port_binding[const.PORTPROFILENAME]
|
|
old_vlan_name = port_binding[const.VLANNAME]
|
|
new_vlan_name = conf.DEFAULT_VLAN_NAME
|
|
self._driver.change_vlan_in_profile(profile_name, old_vlan_name,
|
|
new_vlan_name, self._ucsm_ip,
|
|
self._ucsm_username,
|
|
self._ucsm_password)
|
|
return udb.update_portbinding(port_id, vlan_name=new_vlan_name,
|
|
vlan_id=conf.DEFAULT_VLAN_ID)
|
|
|
|
def create_multiport(self, tenant_id, net_id_list, ports_num,
|
|
port_id_list, **kwargs):
|
|
"""
|
|
Creates a port on the specified Virtual Network.
|
|
"""
|
|
LOG.debug("UCSVICPlugin:create_multiport() called\n")
|
|
self._set_ucsm(kwargs[const.DEVICE_IP])
|
|
qos = None
|
|
ucs_inventory = kwargs[const.UCS_INVENTORY]
|
|
least_rsvd_blade_dict = kwargs[const.LEAST_RSVD_BLADE_DICT]
|
|
chassis_id = least_rsvd_blade_dict[const.LEAST_RSVD_BLADE_CHASSIS]
|
|
blade_id = least_rsvd_blade_dict[const.LEAST_RSVD_BLADE_ID]
|
|
blade_data_dict = least_rsvd_blade_dict[const.LEAST_RSVD_BLADE_DATA]
|
|
port_binding_list = []
|
|
for port_id, net_id in zip(port_id_list, net_id_list):
|
|
new_port_profile = self._create_port_profile(
|
|
tenant_id, net_id, port_id,
|
|
conf.DEFAULT_VLAN_NAME,
|
|
conf.DEFAULT_VLAN_ID)
|
|
profile_name = new_port_profile[const.PROFILE_NAME]
|
|
rsvd_nic_dict = ucs_inventory.reserve_blade_interface(
|
|
self._ucsm_ip, chassis_id,
|
|
blade_id, blade_data_dict,
|
|
tenant_id, port_id,
|
|
profile_name)
|
|
port_binding = udb.update_portbinding(
|
|
port_id,
|
|
portprofile_name=profile_name,
|
|
vlan_name=conf.DEFAULT_VLAN_NAME,
|
|
vlan_id=conf.DEFAULT_VLAN_ID,
|
|
qos=qos)
|
|
port_binding_list.append(port_binding)
|
|
return port_binding_list
|
|
|
|
def detach_port(self, tenant_id, instance_id, instance_desc, **kwargs):
|
|
"""
|
|
Remove the association of the VIF with the dynamic vnic
|
|
"""
|
|
LOG.debug("detach_port() called\n")
|
|
port_id = kwargs[const.PORTID]
|
|
kwargs.pop(const.PORTID)
|
|
return self.unplug_interface(tenant_id, None, port_id, **kwargs)
|
|
|
|
def _get_profile_name(self, port_id):
|
|
"""Returns the port profile name based on the port UUID"""
|
|
profile_name = conf.PROFILE_NAME_PREFIX + cutil.get16ByteUUID(port_id)
|
|
return profile_name
|
|
|
|
def _get_vlan_name_for_network(self, tenant_id, network_id):
|
|
"""Return the VLAN name as set by the L2 network plugin"""
|
|
vlan_binding = cdb.get_vlan_binding(network_id)
|
|
return vlan_binding[const.VLANNAME]
|
|
|
|
def _get_vlan_id_for_network(self, tenant_id, network_id):
|
|
"""Return the VLAN id as set by the L2 network plugin"""
|
|
vlan_binding = cdb.get_vlan_binding(network_id)
|
|
return vlan_binding[const.VLANID]
|
|
|
|
def _create_port_profile(self, tenant_id, net_id, port_id, vlan_name,
|
|
vlan_id):
|
|
"""Create port profile in UCSM"""
|
|
if self._port_profile_counter >= int(conf.MAX_UCSM_PORT_PROFILES):
|
|
raise cexc.UCSMPortProfileLimit(net_id=net_id, port_id=port_id)
|
|
profile_name = self._get_profile_name(port_id)
|
|
self._driver.create_profile(profile_name, vlan_name, self._ucsm_ip,
|
|
self._ucsm_username, self._ucsm_password)
|
|
self._port_profile_counter += 1
|
|
new_port_profile = {const.PROFILE_NAME: profile_name,
|
|
const.PROFILE_VLAN_NAME: vlan_name,
|
|
const.PROFILE_VLAN_ID: vlan_id}
|
|
return new_port_profile
|
|
|
|
def _delete_port_profile(self, port_id, profile_name):
|
|
"""Delete port profile in UCSM"""
|
|
self._driver.delete_profile(profile_name, self._ucsm_ip,
|
|
self._ucsm_username, self._ucsm_password)
|
|
self._port_profile_counter -= 1
|
|
|
|
def _set_ucsm(self, ucsm_ip):
|
|
"""Set the UCSM IP, username, and password"""
|
|
self._ucsm_ip = ucsm_ip
|
|
self._ucsm_username = cred.Store.get_username(conf.UCSM_IP_ADDRESS)
|
|
self._ucsm_password = cred.Store.get_password(conf.UCSM_IP_ADDRESS)
|