Merge "Add v2 API support for the Cisco plugin Blueprint cisco-plugin-v2-api-support"
This commit is contained in:
commit
8e1ebaed7c
@ -1,7 +1,8 @@
|
||||
[PLUGINS]
|
||||
#ucs_plugin=quantum.plugins.cisco.ucs.cisco_ucs_plugin.UCSVICPlugin
|
||||
#nexus_plugin=quantum.plugins.cisco.nexus.cisco_nexus_plugin.NexusPlugin
|
||||
#ucs_plugin=quantum.plugins.cisco.ucs.cisco_ucs_plugin_v2.UCSVICPlugin
|
||||
#nexus_plugin=quantum.plugins.cisco.nexus.cisco_nexus_plugin_v2.NexusPlugin
|
||||
|
||||
[INVENTORY]
|
||||
#ucs_plugin=quantum.plugins.cisco.ucs.cisco_ucs_inventory.UCSInventory
|
||||
#ucs_plugin=quantum.plugins.cisco.ucs.cisco_ucs_inventory_v2.UCSInventory
|
||||
#ucs_plugin=quantum.plugins.cisco.tests.unit.v2.ucs.cisco_ucs_inventory_fake.UCSInventory
|
||||
#nexus_plugin=quantum.plugins.cisco.nexus.cisco_nexus_inventory.NexusInventory
|
||||
|
@ -4,7 +4,7 @@ username=<put_user_name_here>
|
||||
password=<put_password_here>
|
||||
|
||||
#Provide the Nexus credentials, if you are using Nexus
|
||||
[<put_nexus_ip_address_here>]
|
||||
username=<put_user_name_here>
|
||||
password=<put_password_here>
|
||||
[1.1.1.1]
|
||||
username=abc
|
||||
password=def
|
||||
|
||||
|
@ -13,7 +13,8 @@ max_port_profiles=65568
|
||||
max_networks=65568
|
||||
|
||||
[MODEL]
|
||||
model_class=quantum.plugins.cisco.models.l2network_multi_blade.L2NetworkMultiBlade
|
||||
#model_class=quantum.plugins.cisco.models.l2network_multi_blade.L2NetworkMultiBlade
|
||||
model_class=quantum.plugins.cisco.models.network_multi_blade_v2.NetworkMultiBladeV2
|
||||
|
||||
[SEGMENTATION]
|
||||
manager_class=quantum.plugins.cisco.segmentation.l2network_vlan_mgr.L2NetworkVLANMgr
|
||||
manager_class=quantum.plugins.cisco.segmentation.l2network_vlan_mgr_v2.L2NetworkVLANMgr
|
||||
|
@ -8,4 +8,5 @@ nexus_second_port=<put_interface_name_here>
|
||||
nexus_ssh_port=22
|
||||
|
||||
[DRIVER]
|
||||
name=quantum.plugins.cisco.nexus.cisco_nexus_network_driver.CiscoNEXUSDriver
|
||||
#name=quantum.plugins.cisco.nexus.cisco_nexus_network_driver.CiscoNEXUSDriver
|
||||
name=quantum.plugins.cisco.tests.unit.v2.nexus.fake_nexus_driver.CiscoNEXUSFakeDriver
|
||||
|
@ -8,4 +8,5 @@ max_ucsm_port_profiles=1024
|
||||
profile_name_prefix=q-
|
||||
|
||||
[DRIVER]
|
||||
name=quantum.plugins.cisco.ucs.cisco_ucs_network_driver.CiscoUCSMDriver
|
||||
#name=quantum.plugins.cisco.ucs.cisco_ucs_network_driver.CiscoUCSMDriver
|
||||
name=quantum.plugins.cisco.tests.unit.v2.ucs.fake_ucs_driver.CiscoUCSMFakeDriver
|
||||
|
@ -1,5 +1,328 @@
|
||||
=========================================================================================
|
||||
README: A Quantum Plugin Framework for Supporting L2 Networks Spannning Multiple Switches
|
||||
README for Quantum v2.0:
|
||||
A Plugin Framework for Supporting Quantum Networks Spannning Multiple Switches
|
||||
=========================================================================================
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
This plugin implementation provides the following capabilities:
|
||||
|
||||
* A reference implementation for a Quantum Plugin Framework
|
||||
(For details see: http://wiki.openstack.org/quantum-multi-switch-plugin)
|
||||
* Supports multiple switches in the network
|
||||
* Supports multiple models of switches concurrently
|
||||
* Supports use of multiple L2 technologies
|
||||
* Supports the Cisco Nexus family of switches.
|
||||
* Supports Cisco UCS blade servers with M81KR Virtual Interface Cards
|
||||
(aka "Palo adapters") via 802.1Qbh.
|
||||
|
||||
Pre-requisites
|
||||
--------------
|
||||
(The following are necessary only when using the UCS and/or Nexus devices in your system.
|
||||
If you plan to just leverage the plugin framework, you do not need these.)
|
||||
|
||||
If you are using a Nexus switch in your topology, you'll need the following
|
||||
NX-OS version and packages to enable Nexus support:
|
||||
* NX-OS 5.2.1 (Delhi) Build 69 or above.
|
||||
* paramiko library - SSHv2 protocol library for python
|
||||
* ncclient v0.3.1 - Python library for NETCONF clients
|
||||
** You need a version of ncclient modifed by Cisco Systems.
|
||||
To get it, from your shell prompt do:
|
||||
|
||||
git clone git@github.com:CiscoSystems/ncclient.git
|
||||
sudo python ./setup.py install
|
||||
|
||||
** For more information of ncclient, see:
|
||||
http://schmizz.net/ncclient/
|
||||
|
||||
* One or more UCS B200 series blade servers with M81KR VIC (aka
|
||||
Palo adapters) installed.
|
||||
* UCSM 2.0 (Capitola) Build 230 or above.
|
||||
* OS supported:
|
||||
** RHEL 6.1 or above
|
||||
** Ubuntu 11.10 or above
|
||||
** Package: python-configobj-4.6.0-3.el6.noarch (or newer)
|
||||
** Package: python-routes-1.12.3-2.el6.noarch (or newer)
|
||||
** Package: pip install mysql-python
|
||||
|
||||
|
||||
Module Structure:
|
||||
-----------------
|
||||
* quantum/plugins/cisco/ - Contains the Network Plugin Framework
|
||||
/client - CLI module for core and extensions API
|
||||
/common - Modules common to the entire plugin
|
||||
/conf - All configuration files
|
||||
/db - Persistence framework
|
||||
/models - Class(es) which tie the logical abstractions
|
||||
to the physical topology
|
||||
/nova - Scheduler and VIF-driver to be used by Nova
|
||||
/nexus - Nexus-specific modules
|
||||
/segmentation - Implementation of segmentation manager,
|
||||
e.g. VLAN Manager
|
||||
/services - Set of orchestration libraries to insert
|
||||
In-path Networking Services
|
||||
/tests - Tests specific to this plugin
|
||||
/ucs - UCS-specific modules
|
||||
|
||||
|
||||
Plugin Installation Instructions
|
||||
----------------------------------
|
||||
1. Make a backup copy of quantum/etc/quantum.conf
|
||||
|
||||
2. Edit quantum/etc/quantum.conf and edit the "core_plugin" for v2 API
|
||||
|
||||
core_plugin = quantum.plugins.cisco.network_plugin.PluginV2
|
||||
|
||||
3. MySQL database setup:
|
||||
3a. Create quantum_l2network database in mysql with the following command -
|
||||
|
||||
mysql -u<mysqlusername> -p<mysqlpassword> -e "create database quantum_l2network"
|
||||
|
||||
3b. Enter the quantum_l2network database configuration info in the
|
||||
quantum/plugins/cisco/conf/db_conn.ini file.
|
||||
|
||||
4. If you want to turn on support for Cisco Nexus switches:
|
||||
4a. Uncomment the nexus_plugin property in
|
||||
etc/quantum/plugins/cisco/cisco_plugins.ini to read:
|
||||
|
||||
[PLUGINS]
|
||||
nexus_plugin=quantum.plugins.cisco.nexus.cisco_nexus_plugin_v2.NexusPlugin
|
||||
|
||||
4b. Enter the relevant configuration in the
|
||||
etc/quantum/plugins/cisco/nexus.ini file. Example:
|
||||
|
||||
[SWITCH]
|
||||
# Change the following to reflect the IP address of the Nexus switch.
|
||||
# This will be the address at which Quantum sends and receives configuration
|
||||
# information via SSHv2.
|
||||
nexus_ip_address=10.0.0.1
|
||||
# Port numbers on the Nexus switch to each one of the UCSM 6120s is connected
|
||||
# Use shortened interface syntax, e.g. "1/10" not "Ethernet1/10".
|
||||
nexus_first_port=1/10
|
||||
nexus_second_port=1/11
|
||||
#Port number where SSH will be running on the Nexus switch. Typically this is 22
|
||||
#unless you've configured your switch otherwise.
|
||||
nexus_ssh_port=22
|
||||
|
||||
[DRIVER]
|
||||
name=quantum.plugins.cisco.nexus.cisco_nexus_network_driver.CiscoNEXUSDriver
|
||||
|
||||
4c. Make sure that SSH host key of the Nexus switch is known to the
|
||||
host on which you are running the Quantum service. You can do
|
||||
this simply by logging in to your Quantum host as the user that
|
||||
Quantum runs as and SSHing to the switch at least once. If the
|
||||
host key changes (e.g. due to replacement of the supervisor or
|
||||
clearing of the SSH config on the switch), you may need to repeat
|
||||
this step and remove the old hostkey from ~/.ssh/known_hosts.
|
||||
|
||||
5. If your are using UCS blade servers with M81KR Virtual Interface Cards and
|
||||
want to leverage the VM-FEX features,
|
||||
|
||||
5a. Uncomment the ucs_plugin propertes in
|
||||
etc/quantum/plugins/cisco/cisco_plugins.ini to read:
|
||||
|
||||
[PLUGINS]
|
||||
ucs_plugin=quantum.plugins.cisco.ucs.cisco_ucs_plugin_v2.UCSVICPlugin
|
||||
[INVENTORY]
|
||||
ucs_plugin=quantum.plugins.cisco.ucs.cisco_ucs_inventory_v2.UCSInventory
|
||||
|
||||
5b. Enter the relevant configuration in the
|
||||
etc/quantum/plugins/cisco/ucs.ini file. Example:
|
||||
|
||||
[UCSM]
|
||||
#change the following to the appropriate UCSM IP address
|
||||
#if you have more than one UCSM, enter info from any one
|
||||
ip_address=<put_ucsm_ip_address_here>
|
||||
default_vlan_name=default
|
||||
default_vlan_id=1
|
||||
max_ucsm_port_profiles=1024
|
||||
profile_name_prefix=q-
|
||||
|
||||
[DRIVER]
|
||||
name=quantum.plugins.cisco.ucs.cisco_ucs_network_driver.CiscoUCSMDriver
|
||||
|
||||
5c. Configure the UCS systems' information in your deployment by editing the
|
||||
quantum/plugins/cisco/conf/ucs_inventory.ini file. You can configure multiple
|
||||
UCSMs per deployment, multiple chassis per UCSM, and multiple blades per
|
||||
chassis. Chassis ID and blade ID can be obtained from the UCSM (they will
|
||||
typically be numbers like 1, 2, 3, etc.). Also make sure that you put the exact
|
||||
hostname as nova sees it (the host column in the services table of the nova
|
||||
DB will give you that information).
|
||||
|
||||
[ucsm-1]
|
||||
ip_address = <put_ucsm_ip_address_here>
|
||||
[[chassis-1]]
|
||||
chassis_id = <put_the_chassis_id_here>
|
||||
[[[blade-1]]]
|
||||
blade_id = <put_blade_id_here>
|
||||
host_name = <put_hostname_here>
|
||||
[[[blade-2]]]
|
||||
blade_id = <put_blade_id_here>
|
||||
host_name = <put_hostname_here>
|
||||
[[[blade-3]]]
|
||||
blade_id = <put_blade_id_here>
|
||||
host_name = <put_hostname_here>
|
||||
|
||||
[ucsm-2]
|
||||
ip_address = <put_ucsm_ip_address_here>
|
||||
[[chassis-1]]
|
||||
chassis_id = <put_the_chassis_id_here>
|
||||
[[[blade-1]]]
|
||||
blade_id = <put_blade_id_here>
|
||||
host_name = <put_hostname_here>
|
||||
[[[blade-2]]]
|
||||
blade_id = <put_blade_id_here>
|
||||
host_name = <put_hostname_here>
|
||||
|
||||
5d. Configure your OpenStack installation to use the 802.1qbh VIF driver and
|
||||
Quantum-aware scheduler by editing the /etc/nova/nova.conf file with the
|
||||
following entries:
|
||||
|
||||
scheduler_driver=quantum.plugins.cisco.nova.quantum_port_aware_scheduler.QuantumPortAwareScheduler
|
||||
quantum_host=127.0.0.1
|
||||
quantum_port=9696
|
||||
libvirt_vif_driver=quantum.plugins.cisco.nova.vifdirect.Libvirt802dot1QbhDriver
|
||||
libvirt_vif_type=802.1Qbh
|
||||
|
||||
Note: To be able to bring up a VM on a UCS blade, you should first create a
|
||||
port for that VM using the Quantum create port API. VM creation will
|
||||
fail if an unused port is not available. If you have configured your
|
||||
Nova project with more than one network, Nova will attempt to instantiate
|
||||
the VM with one network interface (VIF) per configured network. To provide
|
||||
plugin points for each of these VIFs, you will need to create multiple
|
||||
Quantum ports, one for each of the networks, prior to starting the VM.
|
||||
However, in this case you will need to use the Cisco multiport extension
|
||||
API instead of the Quantum create port API. More details on using the
|
||||
multiport extension follow in the section on multi NIC support.
|
||||
|
||||
To support the above configuration, you will need some Quantum modules. It's easiest
|
||||
to copy the entire quantum directory from your quantum installation into:
|
||||
|
||||
/usr/lib/python2.7/site-packages/
|
||||
|
||||
This needs to be done on each nova compute node.
|
||||
|
||||
7. Verify that you have the correct credentials for each IP address listed
|
||||
in quantum/plugins/cisco/conf/credentials.ini. Example:
|
||||
|
||||
# Provide the UCSM credentials, create a separte entry for each UCSM used in your system
|
||||
# UCSM IP address, username and password.
|
||||
[10.0.0.2]
|
||||
username=admin
|
||||
password=mySecretPasswordForUCSM
|
||||
|
||||
# Provide the Nexus credentials, if you are using Nexus switches.
|
||||
# If not this will be ignored.
|
||||
[10.0.0.1]
|
||||
username=admin
|
||||
password=mySecretPasswordForNexus
|
||||
|
||||
In general, make sure that every UCSM and Nexus switch used in your system,
|
||||
has a credential entry in the above file. This is required for the system to
|
||||
be able to communicate with those switches.
|
||||
|
||||
|
||||
9. Start the Quantum service. If something doesn't work, verify the
|
||||
your configuration of each of the above files.
|
||||
|
||||
|
||||
Multi NIC support for VMs
|
||||
-------------------------
|
||||
As indicated earlier, if your Nova setup has a project with more than one network,
|
||||
Nova will try to create a virtual network interface (VIF) on the VM for each of those
|
||||
networks. Before each VM is instantiated, you should create Quantum ports on each of
|
||||
those networks. These ports need to be created using the following rest call:
|
||||
|
||||
POST /1.0/extensions/csco/tenants/{tenant_id}/multiport/
|
||||
|
||||
with request body:
|
||||
|
||||
{'multiport':
|
||||
{'status': 'ACTIVE',
|
||||
'net_id_list': net_id_list,
|
||||
'ports_desc': {'key': 'value'}}}
|
||||
|
||||
where,
|
||||
|
||||
net_id_list is a list of network IDs: [netid1, netid2, ...]. The "ports_desc" dictionary
|
||||
is reserved for later use. For now, the same structure in terms of the dictionary name, key
|
||||
and value should be used.
|
||||
|
||||
The corresponding CLI for this operation is as follows:
|
||||
|
||||
PYTHONPATH=. python quantum/plugins/cisco/client/cli.py create_multiport <tenant_id> <net_id1,net_id2,...>
|
||||
|
||||
(Note that you should not be using the create port core API in the above case.)
|
||||
|
||||
|
||||
How to test the installation
|
||||
----------------------------
|
||||
The unit tests are located at quantum/plugins/cisco/tests/unit/v2. They can be
|
||||
executed from the top level Quantum directory using the run_tests.sh script.
|
||||
|
||||
1. Testing the core API (without UCS/Nexus/RHEL device sub-plugins configured):
|
||||
By default all the device sub-plugins are disabled (commented out) in
|
||||
etc/quantum/plugins/cisco/cisco_plugins.ini
|
||||
|
||||
./run_tests.sh quantum.plugins.cisco.tests.unit.v2.test_api_v2
|
||||
./run_tests.sh quantum.plugins.cisco.tests.unit.v2.test_network_plugin
|
||||
|
||||
2. For testing the Nexus device sub-plugin perform the following configuration:
|
||||
|
||||
Edit etc/quantum/plugins/cisco/cisco_plugins.ini to add:
|
||||
In the [PLUGINS] section add:
|
||||
nexus_plugin=quantum.plugins.cisco.nexus.cisco_nexus_plugin_v2.NexusPlugin
|
||||
|
||||
Edit the etc/quantum/plugins/cisco/nexus.ini file.
|
||||
When not using Nexus hardware use the following dummy configuration verbatim:
|
||||
[SWITCH]
|
||||
nexus_ip_address=1.1.1.1
|
||||
nexus_first_port=1/10
|
||||
nexus_second_port=1/11
|
||||
nexus_ssh_port=22
|
||||
[DRIVER]
|
||||
name=quantum.plugins.cisco.tests.unit.v2.nexus.fake_nexus_driver.CiscoNEXUSFakeDriver
|
||||
Or when using Nexus hardware (put the values relevant to your setup):
|
||||
[SWITCH]
|
||||
nexus_ip_address=1.1.1.1
|
||||
nexus_first_port=1/10
|
||||
nexus_second_port=1/11
|
||||
nexus_ssh_port=22
|
||||
[DRIVER]
|
||||
name=quantum.plugins.cisco.nexus.cisco_nexus_network_driver.CiscoNEXUSDriver
|
||||
|
||||
(Note: Make sure that quantum/plugins/cisco/conf/credentials.ini has an entry for
|
||||
the nexus_ip_address being used in the above cases)
|
||||
|
||||
3. For testing the UCS device sub-plugin perform the following configuration:
|
||||
|
||||
Edit etc/quantum/plugins/cisco/cisco_plugins.ini to add:
|
||||
In the [PLUGINS] section add:
|
||||
ucs_plugin=quantum.plugins.cisco.ucs.cisco_ucs_plugin_v2.UCSVICPlugin
|
||||
|
||||
In the [INVENTORY] section add:
|
||||
When not using UCS hardware:
|
||||
ucs_plugin=quantum.plugins.cisco.tests.unit.v2.ucs.cisco_ucs_inventory_fake.UCSInventory
|
||||
Or when using UCS hardware:
|
||||
ucs_plugin=quantum.plugins.cisco.ucs.cisco_ucs_inventory_v2.UCSInventory
|
||||
|
||||
Edit the etc/quantum/plugins/cisco/ucs.ini file.
|
||||
When not using UCS hardware:
|
||||
[DRIVER]
|
||||
name=quantum.plugins.cisco.tests.unit.v2.ucs.fake_ucs_driver.CiscoUCSMFakeDriver
|
||||
Or when using UCS hardware:
|
||||
[DRIVER]
|
||||
name=quantum.plugins.cisco.ucs.cisco_ucs_network_driver.CiscoUCSMDriver
|
||||
|
||||
|
||||
:Web site: http://wiki.openstack.org/cisco-quantum
|
||||
:Copyright: 2012 Cisco Systems, Inc.
|
||||
:Contact: netstack@lists.launchpad.net
|
||||
|
||||
=========================================================================================
|
||||
README for Quantum v1 and v1.1:
|
||||
A Quantum Plugin Framework for Supporting L2 Networks Spannning Multiple Switches
|
||||
=========================================================================================
|
||||
|
||||
:Author: Sumit Naiksatam, Ram Durairaj, Mark Voelker, Edgar Magana, Shweta Padubidri,
|
||||
@ -83,12 +406,15 @@ Module Structure:
|
||||
|
||||
Plugin Installation Instructions
|
||||
----------------------------------
|
||||
1. Make a backup copy of quantum/etc/plugins.ini.
|
||||
1. Make a backup copy of quantum/etc/quantum.conf
|
||||
|
||||
2. Edit quantum/etc/plugins.ini and edit the "provider" entry to point
|
||||
to the L2Network-plugin:
|
||||
2. Edit quantum/etc/quantum.conf and edit the "core_plugin" for v2 API
|
||||
|
||||
provider = quantum.plugins.cisco.l2network_plugin.L2Network
|
||||
core_plugin = quantum.plugins.cisco.network_plugin.PluginV2
|
||||
|
||||
OR for v1.1 API
|
||||
|
||||
core_plugin = quantum.plugins.cisco.l2network_plugin.L2Network
|
||||
|
||||
3. Configure your OpenStack installation to use the 802.1qbh VIF driver and
|
||||
Quantum-aware scheduler by editing the /etc/nova/nova.conf file with the
|
||||
@ -374,7 +700,9 @@ result the run_tests.py script.
|
||||
Device-specific sub-plugins can be disabled by commenting out all the entries in:
|
||||
etc/quantum/plugins/cisco/cisco_plugins.ini
|
||||
|
||||
Execute the l2networkApi tests only using:
|
||||
Execute the v2 API tests only using:
|
||||
./run_tests.sh quantum.plugins.cisco.tests.unit.test_api_v2
|
||||
Execute the v1.1 API tests only using:
|
||||
./run_tests.sh quantum.plugins.cisco.tests.unit.test_l2networkApi
|
||||
|
||||
If just the ucs or both ucs and the nexus plugins are configured then all the tests could be executed by
|
||||
@ -389,13 +717,16 @@ result the run_tests.py script.
|
||||
Nexus plugins.
|
||||
Device-specific plugins can be disabled by commenting out the entries in:
|
||||
etc/quantum/plugins/cisco/cisco_plugins.ini
|
||||
Execute the test script as follows:
|
||||
|
||||
./run_tests.sh quantum.plugins.cisco.tests.unit.test_l2networkApi
|
||||
Execute the v2 API tests only using:
|
||||
./run_tests.sh quantum.plugins.cisco.tests.unit.test_api_v2
|
||||
or
|
||||
python run_tests.py quantum.plugins.cisco.tests.unit.test_api_v2
|
||||
|
||||
or
|
||||
|
||||
python run_tests.py quantum.plugins.cisco.tests.unit.test_l2networkApi
|
||||
Execute the v1.1 API tests only using:
|
||||
./run_tests.sh quantum.plugins.cisco.tests.unit.test_l2networkApi
|
||||
or
|
||||
python run_tests.py quantum.plugins.cisco.tests.unit.test_l2networkApi
|
||||
|
||||
3. Specific Plugin unit test (needs environment setup as indicated in the
|
||||
pre-requisites):
|
||||
|
@ -161,3 +161,9 @@ ASSOCIATION_STATUS = 'association_status'
|
||||
ATTACHED = 'attached'
|
||||
|
||||
DETACHED = 'detached'
|
||||
|
||||
NETWORK = 'network'
|
||||
PORT = 'port'
|
||||
BASE_PLUGIN_REF = 'base_plugin_ref'
|
||||
CONTEXT = 'context'
|
||||
SUBNET = 'subnet'
|
||||
|
82
quantum/plugins/cisco/common/cisco_credentials_v2.py
Normal file
82
quantum/plugins/cisco/common/cisco_credentials_v2.py
Normal file
@ -0,0 +1,82 @@
|
||||
# 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 as LOG
|
||||
|
||||
from quantum.common.utils import find_config_file
|
||||
from quantum.plugins.cisco.common import cisco_configparser as confp
|
||||
from quantum.plugins.cisco.common import cisco_constants as const
|
||||
from quantum.plugins.cisco.common import cisco_exceptions as cexc
|
||||
from quantum.plugins.cisco.db import network_db_v2 as cdb
|
||||
|
||||
|
||||
LOG.basicConfig(level=LOG.WARN)
|
||||
LOG.getLogger(const.LOGGER_COMPONENT_NAME)
|
||||
|
||||
CREDENTIALS_FILE = find_config_file({'plugin': 'cisco'},
|
||||
"credentials.ini")
|
||||
TENANT = const.NETWORK_ADMIN
|
||||
|
||||
cp = confp.CiscoConfigParser(CREDENTIALS_FILE)
|
||||
_creds_dictionary = cp.walk(cp.dummy)
|
||||
|
||||
|
||||
class Store(object):
|
||||
"""Credential Store"""
|
||||
|
||||
@staticmethod
|
||||
def initialize():
|
||||
for id in _creds_dictionary.keys():
|
||||
try:
|
||||
cdb.add_credential(TENANT, id,
|
||||
_creds_dictionary[id][const.USERNAME],
|
||||
_creds_dictionary[id][const.PASSWORD])
|
||||
except cexc.CredentialAlreadyExists:
|
||||
# We are quietly ignoring this, since it only happens
|
||||
# if this class module is loaded more than once, in which
|
||||
# case, the credentials are already populated
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def put_credential(cred_name, username, password):
|
||||
"""Set the username and password"""
|
||||
credential = cdb.add_credential(TENANT, cred_name, username, password)
|
||||
|
||||
@staticmethod
|
||||
def get_username(cred_name):
|
||||
"""Get the username"""
|
||||
credential = cdb.get_credential_name(TENANT, cred_name)
|
||||
return credential[const.CREDENTIAL_USERNAME]
|
||||
|
||||
@staticmethod
|
||||
def get_password(cred_name):
|
||||
"""Get the password"""
|
||||
credential = cdb.get_credential_name(TENANT, cred_name)
|
||||
return credential[const.CREDENTIAL_PASSWORD]
|
||||
|
||||
@staticmethod
|
||||
def get_credential(cred_name):
|
||||
"""Get the username and password"""
|
||||
credential = cdb.get_credential_name(TENANT, cred_name)
|
||||
return {const.USERNAME: const.CREDENTIAL_USERNAME,
|
||||
const.PASSWORD: const.CREDENTIAL_PASSWORD}
|
||||
|
||||
@staticmethod
|
||||
def delete_credential(cred_name):
|
||||
"""Delete a credential"""
|
||||
cdb.remove_credential(TENANT, cred_name)
|
527
quantum/plugins/cisco/db/network_db_v2.py
Normal file
527
quantum/plugins/cisco/db/network_db_v2.py
Normal file
@ -0,0 +1,527 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2012, Cisco Systems, Inc.
|
||||
#
|
||||
# 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: Rohit Agarwalla, Cisco Systems, Inc.
|
||||
|
||||
import logging as LOG
|
||||
from sqlalchemy.orm import exc
|
||||
|
||||
from quantum.common import exceptions as q_exc
|
||||
from quantum.db import api as db
|
||||
from quantum.db import models_v2
|
||||
from quantum.plugins.cisco.common import cisco_constants as const
|
||||
from quantum.plugins.cisco.common import cisco_exceptions as c_exc
|
||||
from quantum.plugins.cisco.db import network_models_v2
|
||||
from quantum.plugins.cisco.db import nexus_models_v2
|
||||
from quantum.plugins.cisco.db import ucs_models_v2
|
||||
from quantum.plugins.cisco import l2network_plugin_configuration as conf
|
||||
|
||||
|
||||
def initialize():
|
||||
'Establish database connection and load models'
|
||||
sql_connection = "mysql://%s:%s@%s/%s" % (conf.DB_USER, conf.DB_PASS,
|
||||
conf.DB_HOST, conf.DB_NAME)
|
||||
db.configure_db({'sql_connection': sql_connection,
|
||||
'base': network_models_v2.model_base.BASEV2})
|
||||
|
||||
|
||||
def create_vlanids():
|
||||
"""Prepopulates the vlan_bindings table"""
|
||||
LOG.debug("create_vlanids() called")
|
||||
session = db.get_session()
|
||||
try:
|
||||
vlanid = session.query(network_models_v2.VlanID).one()
|
||||
except exc.MultipleResultsFound:
|
||||
pass
|
||||
except exc.NoResultFound:
|
||||
start = int(conf.VLAN_START)
|
||||
end = int(conf.VLAN_END)
|
||||
while start <= end:
|
||||
vlanid = network_models_v2.VlanID(start)
|
||||
session.add(vlanid)
|
||||
start += 1
|
||||
session.flush()
|
||||
return
|
||||
|
||||
|
||||
def get_all_vlanids():
|
||||
"""Gets all the vlanids"""
|
||||
LOG.debug("get_all_vlanids() called")
|
||||
session = db.get_session()
|
||||
try:
|
||||
vlanids = session.query(network_models_v2.VlanID).all()
|
||||
return vlanids
|
||||
except exc.NoResultFound:
|
||||
return []
|
||||
|
||||
|
||||
def is_vlanid_used(vlan_id):
|
||||
"""Checks if a vlanid is in use"""
|
||||
LOG.debug("is_vlanid_used() called")
|
||||
session = db.get_session()
|
||||
try:
|
||||
vlanid = (session.query(network_models_v2.VlanID).
|
||||
filter_by(vlan_id=vlan_id).one())
|
||||
return vlanid["vlan_used"]
|
||||
except exc.NoResultFound:
|
||||
raise c_exc.VlanIDNotFound(vlan_id=vlan_id)
|
||||
|
||||
|
||||
def release_vlanid(vlan_id):
|
||||
"""Sets the vlanid state to be unused"""
|
||||
LOG.debug("release_vlanid() called")
|
||||
session = db.get_session()
|
||||
try:
|
||||
vlanid = (session.query(network_models_v2.VlanID).
|
||||
filter_by(vlan_id=vlan_id).one())
|
||||
vlanid["vlan_used"] = False
|
||||
session.merge(vlanid)
|
||||
session.flush()
|
||||
return vlanid["vlan_used"]
|
||||
except exc.NoResultFound:
|
||||
raise c_exc.VlanIDNotFound(vlan_id=vlan_id)
|
||||
return
|
||||
|
||||
|
||||
def delete_vlanid(vlan_id):
|
||||
"""Deletes a vlanid entry from db"""
|
||||
LOG.debug("delete_vlanid() called")
|
||||
session = db.get_session()
|
||||
try:
|
||||
vlanid = (session.query(network_models_v2.VlanID).
|
||||
filter_by(vlan_id=vlan_id).one())
|
||||
session.delete(vlanid)
|
||||
session.flush()
|
||||
return vlanid
|
||||
except exc.NoResultFound:
|
||||
pass
|
||||
|
||||
|
||||
def reserve_vlanid():
|
||||
"""Reserves the first unused vlanid"""
|
||||
LOG.debug("reserve_vlanid() called")
|
||||
session = db.get_session()
|
||||
try:
|
||||
rvlan = (session.query(network_models_v2.VlanID).
|
||||
filter_by(vlan_used=False).first())
|
||||
if not rvlan:
|
||||
raise exc.NoResultFound
|
||||
rvlanid = (session.query(network_models_v2.VlanID).
|
||||
filter_by(vlan_id=rvlan["vlan_id"]).one())
|
||||
rvlanid["vlan_used"] = True
|
||||
session.merge(rvlanid)
|
||||
session.flush()
|
||||
return rvlan["vlan_id"]
|
||||
except exc.NoResultFound:
|
||||
raise c_exc.VlanIDNotAvailable()
|
||||
|
||||
|
||||
def get_all_vlanids_used():
|
||||
"""Gets all the vlanids used"""
|
||||
LOG.debug("get_all_vlanids() called")
|
||||
session = db.get_session()
|
||||
try:
|
||||
vlanids = (session.query(network_models_v2.VlanID).
|
||||
filter_by(vlan_used=True).all())
|
||||
return vlanids
|
||||
except exc.NoResultFound:
|
||||
return []
|
||||
|
||||
|
||||
def get_all_vlan_bindings():
|
||||
"""Lists all the vlan to network associations"""
|
||||
LOG.debug("get_all_vlan_bindings() called")
|
||||
session = db.get_session()
|
||||
try:
|
||||
bindings = session.query(network_models_v2.VlanBinding).all()
|
||||
return bindings
|
||||
except exc.NoResultFound:
|
||||
return []
|
||||
|
||||
|
||||
def get_vlan_binding(netid):
|
||||
"""Lists the vlan given a network_id"""
|
||||
LOG.debug("get_vlan_binding() called")
|
||||
session = db.get_session()
|
||||
try:
|
||||
binding = (session.query(network_models_v2.VlanBinding).
|
||||
filter_by(network_id=netid).one())
|
||||
return binding
|
||||
except exc.NoResultFound:
|
||||
raise q_exc.NetworkNotFound(net_id=netid)
|
||||
|
||||
|
||||
def add_vlan_binding(vlanid, vlanname, netid):
|
||||
"""Adds a vlan to network association"""
|
||||
LOG.debug("add_vlan_binding() called")
|
||||
session = db.get_session()
|
||||
try:
|
||||
binding = (session.query(network_models_v2.VlanBinding).
|
||||
filter_by(vlan_id=vlanid).one())
|
||||
raise c_exc.NetworkVlanBindingAlreadyExists(vlan_id=vlanid,
|
||||
network_id=netid)
|
||||
except exc.NoResultFound:
|
||||
binding = network_models_v2.VlanBinding(vlanid, vlanname, netid)
|
||||
session.add(binding)
|
||||
session.flush()
|
||||
return binding
|
||||
|
||||
|
||||
def remove_vlan_binding(netid):
|
||||
"""Removes a vlan to network association"""
|
||||
LOG.debug("remove_vlan_binding() called")
|
||||
session = db.get_session()
|
||||
try:
|
||||
binding = (session.query(network_models_v2.VlanBinding).
|
||||
filter_by(network_id=netid).one())
|
||||
session.delete(binding)
|
||||
session.flush()
|
||||
return binding
|
||||
except exc.NoResultFound:
|
||||
pass
|
||||
|
||||
|
||||
def update_vlan_binding(netid, newvlanid=None, newvlanname=None):
|
||||
"""Updates a vlan to network association"""
|
||||
LOG.debug("update_vlan_binding() called")
|
||||
session = db.get_session()
|
||||
try:
|
||||
binding = (session.query(network_models_v2.VlanBinding).
|
||||
filter_by(network_id=netid).one())
|
||||
if newvlanid:
|
||||
binding["vlan_id"] = newvlanid
|
||||
if newvlanname:
|
||||
binding["vlan_name"] = newvlanname
|
||||
session.merge(binding)
|
||||
session.flush()
|
||||
return binding
|
||||
except exc.NoResultFound:
|
||||
raise q_exc.NetworkNotFound(net_id=netid)
|
||||
|
||||
|
||||
def get_all_portprofiles():
|
||||
"""Lists all the port profiles"""
|
||||
LOG.debug("get_all_portprofiles() called")
|
||||
session = db.get_session()
|
||||
try:
|
||||
pps = session.query(network_models_v2.PortProfile).all()
|
||||
return pps
|
||||
except exc.NoResultFound:
|
||||
return []
|
||||
|
||||
|
||||
def get_portprofile(tenantid, ppid):
|
||||
"""Lists a port profile"""
|
||||
LOG.debug("get_portprofile() called")
|
||||
session = db.get_session()
|
||||
try:
|
||||
pp = (session.query(network_models_v2.PortProfile).
|
||||
filter_by(uuid=ppid).one())
|
||||
return pp
|
||||
except exc.NoResultFound:
|
||||
raise c_exc.PortProfileNotFound(tenant_id=tenantid,
|
||||
portprofile_id=ppid)
|
||||
|
||||
|
||||
def add_portprofile(tenantid, ppname, vlanid, qos):
|
||||
"""Adds a port profile"""
|
||||
LOG.debug("add_portprofile() called")
|
||||
session = db.get_session()
|
||||
try:
|
||||
pp = (session.query(network_models_v2.PortProfile).
|
||||
filter_by(name=ppname).one())
|
||||
raise c_exc.PortProfileAlreadyExists(tenant_id=tenantid,
|
||||
pp_name=ppname)
|
||||
except exc.NoResultFound:
|
||||
pp = network_models_v2.PortProfile(ppname, vlanid, qos)
|
||||
session.add(pp)
|
||||
session.flush()
|
||||
return pp
|
||||
|
||||
|
||||
def remove_portprofile(tenantid, ppid):
|
||||
"""Removes a port profile"""
|
||||
LOG.debug("remove_portprofile() called")
|
||||
session = db.get_session()
|
||||
try:
|
||||
pp = (session.query(network_models_v2.PortProfile).
|
||||
filter_by(uuid=ppid).one())
|
||||
session.delete(pp)
|
||||
session.flush()
|
||||
return pp
|
||||
except exc.NoResultFound:
|
||||
pass
|
||||
|
||||
|
||||
def update_portprofile(tenantid, ppid, newppname=None, newvlanid=None,
|
||||
newqos=None):
|
||||
"""Updates port profile"""
|
||||
LOG.debug("update_portprofile() called")
|
||||
session = db.get_session()
|
||||
try:
|
||||
pp = (session.query(network_models_v2.PortProfile).
|
||||
filter_by(uuid=ppid).one())
|
||||
if newppname:
|
||||
pp["name"] = newppname
|
||||
if newvlanid:
|
||||
pp["vlan_id"] = newvlanid
|
||||
if newqos:
|
||||
pp["qos"] = newqos
|
||||
session.merge(pp)
|
||||
session.flush()
|
||||
return pp
|
||||
except exc.NoResultFound:
|
||||
raise c_exc.PortProfileNotFound(tenant_id=tenantid,
|
||||
portprofile_id=ppid)
|
||||
|
||||
|
||||
def get_all_pp_bindings():
|
||||
"""Lists all the port profiles"""
|
||||
LOG.debug("get_all_pp_bindings() called")
|
||||
session = db.get_session()
|
||||
try:
|
||||
bindings = session.query(network_models_v2.PortProfileBinding).all()
|
||||
return bindings
|
||||
except exc.NoResultFound:
|
||||
return []
|
||||
|
||||
|
||||
def get_pp_binding(tenantid, ppid):
|
||||
"""Lists a port profile binding"""
|
||||
LOG.debug("get_pp_binding() called")
|
||||
session = db.get_session()
|
||||
try:
|
||||
binding = (session.query(network_models_v2.PortProfileBinding).
|
||||
filter_by(portprofile_id=ppid).one())
|
||||
return binding
|
||||
except exc.NoResultFound:
|
||||
return []
|
||||
|
||||
|
||||
def add_pp_binding(tenantid, portid, ppid, default):
|
||||
"""Adds a port profile binding"""
|
||||
LOG.debug("add_pp_binding() called")
|
||||
session = db.get_session()
|
||||
try:
|
||||
binding = (session.query(network_models_v2.PortProfileBinding).
|
||||
filter_by(portprofile_id=ppid).one())
|
||||
raise c_exc.PortProfileBindingAlreadyExists(pp_id=ppid,
|
||||
port_id=portid)
|
||||
except exc.NoResultFound:
|
||||
binding = network_models_v2.PortProfileBinding(tenantid, portid,
|
||||
ppid, default)
|
||||
session.add(binding)
|
||||
session.flush()
|
||||
return binding
|
||||
|
||||
|
||||
def remove_pp_binding(tenantid, portid, ppid):
|
||||
"""Removes a port profile binding"""
|
||||
LOG.debug("remove_pp_binding() called")
|
||||
session = db.get_session()
|
||||
try:
|
||||
binding = (session.query(network_models_v2.PortProfileBinding).
|
||||
filter_by(portprofile_id=ppid).filter_by(port_id=portid).
|
||||
one())
|
||||
session.delete(binding)
|
||||
session.flush()
|
||||
return binding
|
||||
except exc.NoResultFound:
|
||||
pass
|
||||
|
||||
|
||||
def update_pp_binding(tenantid, ppid, newtenantid=None,
|
||||
newportid=None, newdefault=None):
|
||||
"""Updates port profile binding"""
|
||||
LOG.debug("update_pp_binding() called")
|
||||
session = db.get_session()
|
||||
try:
|
||||
binding = (session.query(network_models_v2.PortProfileBinding).
|
||||
filter_by(portprofile_id=ppid).one())
|
||||
if newtenantid:
|
||||
binding["tenant_id"] = newtenantid
|
||||
if newportid:
|
||||
binding["port_id"] = newportid
|
||||
if newdefault:
|
||||
binding["default"] = newdefault
|
||||
session.merge(binding)
|
||||
session.flush()
|
||||
return binding
|
||||
except exc.NoResultFound:
|
||||
raise c_exc.PortProfileNotFound(tenant_id=tenantid,
|
||||
portprofile_id=ppid)
|
||||
|
||||
|
||||
def get_all_qoss(tenant_id):
|
||||
"""Lists all the qos to tenant associations"""
|
||||
LOG.debug("get_all_qoss() called")
|
||||
session = db.get_session()
|
||||
try:
|
||||
qoss = (session.query(network_models_v2.QoS).
|
||||
filter_by(tenant_id=tenant_id).all())
|
||||
return qoss
|
||||
except exc.NoResultFound:
|
||||
return []
|
||||
|
||||
|
||||
def get_qos(tenant_id, qos_id):
|
||||
"""Lists the qos given a tenant_id and qos_id"""
|
||||
LOG.debug("get_qos() called")
|
||||
session = db.get_session()
|
||||
try:
|
||||
qos = (session.query(network_models_v2.QoS).
|
||||
filter_by(tenant_id=tenant_id).
|
||||
filter_by(qos_id=qos_id).one())
|
||||
return qos
|
||||
except exc.NoResultFound:
|
||||
raise c_exc.QosNotFound(qos_id=qos_id,
|
||||
tenant_id=tenant_id)
|
||||
|
||||
|
||||
def add_qos(tenant_id, qos_name, qos_desc):
|
||||
"""Adds a qos to tenant association"""
|
||||
LOG.debug("add_qos() called")
|
||||
session = db.get_session()
|
||||
try:
|
||||
qos = (session.query(network_models_v2.QoS).
|
||||
filter_by(tenant_id=tenant_id).
|
||||
filter_by(qos_name=qos_name).one())
|
||||
raise c_exc.QosNameAlreadyExists(qos_name=qos_name,
|
||||
tenant_id=tenant_id)
|
||||
except exc.NoResultFound:
|
||||
qos = network_models_v2.QoS(tenant_id, qos_name, qos_desc)
|
||||
session.add(qos)
|
||||
session.flush()
|
||||
return qos
|
||||
|
||||
|
||||
def remove_qos(tenant_id, qos_id):
|
||||
"""Removes a qos to tenant association"""
|
||||
session = db.get_session()
|
||||
try:
|
||||
qos = (session.query(network_models_v2.QoS).
|
||||
filter_by(tenant_id=tenant_id).
|
||||
filter_by(qos_id=qos_id).one())
|
||||
session.delete(qos)
|
||||
session.flush()
|
||||
return qos
|
||||
except exc.NoResultFound:
|
||||
pass
|
||||
|
||||
|
||||
def update_qos(tenant_id, qos_id, new_qos_name=None):
|
||||
"""Updates a qos to tenant association"""
|
||||
session = db.get_session()
|
||||
try:
|
||||
qos = (session.query(network_models_v2.QoS).
|
||||
filter_by(tenant_id=tenant_id).
|
||||
filter_by(qos_id=qos_id).one())
|
||||
if new_qos_name:
|
||||
qos["qos_name"] = new_qos_name
|
||||
session.merge(qos)
|
||||
session.flush()
|
||||
return qos
|
||||
except exc.NoResultFound:
|
||||
raise c_exc.QosNotFound(qos_id=qos_id,
|
||||
tenant_id=tenant_id)
|
||||
|
||||
|
||||
def get_all_credentials(tenant_id):
|
||||
"""Lists all the creds for a tenant"""
|
||||
session = db.get_session()
|
||||
try:
|
||||
creds = (session.query(network_models_v2.Credential).
|
||||
filter_by(tenant_id=tenant_id).all())
|
||||
return creds
|
||||
except exc.NoResultFound:
|
||||
return []
|
||||
|
||||
|
||||
def get_credential(tenant_id, credential_id):
|
||||
"""Lists the creds for given a cred_id and tenant_id"""
|
||||
session = db.get_session()
|
||||
try:
|
||||
cred = (session.query(network_models_v2.Credential).
|
||||
filter_by(tenant_id=tenant_id).
|
||||
filter_by(credential_id=credential_id).one())
|
||||
return cred
|
||||
except exc.NoResultFound:
|
||||
raise c_exc.CredentialNotFound(credential_id=credential_id,
|
||||
tenant_id=tenant_id)
|
||||
|
||||
|
||||
def get_credential_name(tenant_id, credential_name):
|
||||
"""Lists the creds for given a cred_name and tenant_id"""
|
||||
session = db.get_session()
|
||||
try:
|
||||
cred = (session.query(network_models_v2.Credential).
|
||||
filter_by(tenant_id=tenant_id).
|
||||
filter_by(credential_name=credential_name).one())
|
||||
return cred
|
||||
except exc.NoResultFound:
|
||||
raise c_exc.CredentialNameNotFound(credential_name=credential_name,
|
||||
tenant_id=tenant_id)
|
||||
|
||||
|
||||
def add_credential(tenant_id, credential_name, user_name, password):
|
||||
"""Adds a qos to tenant association"""
|
||||
session = db.get_session()
|
||||
try:
|
||||
cred = (session.query(network_models_v2.Credential).
|
||||
filter_by(tenant_id=tenant_id).
|
||||
filter_by(credential_name=credential_name).one())
|
||||
raise c_exc.CredentialAlreadyExists(credential_name=credential_name,
|
||||
tenant_id=tenant_id)
|
||||
except exc.NoResultFound:
|
||||
cred = network_models_v2.Credential(tenant_id, credential_name,
|
||||
user_name, password)
|
||||
session.add(cred)
|
||||
session.flush()
|
||||
return cred
|
||||
|
||||
|
||||
def remove_credential(tenant_id, credential_id):
|
||||
"""Removes a credential from a tenant"""
|
||||
session = db.get_session()
|
||||
try:
|
||||
cred = (session.query(network_models_v2.Credential).
|
||||
filter_by(tenant_id=tenant_id).
|
||||
filter_by(credential_id=credential_id).one())
|
||||
session.delete(cred)
|
||||
session.flush()
|
||||
return cred
|
||||
except exc.NoResultFound:
|
||||
pass
|
||||
|
||||
|
||||
def update_credential(tenant_id, credential_id,
|
||||
new_user_name=None, new_password=None):
|
||||
"""Updates a credential for a tenant"""
|
||||
session = db.get_session()
|
||||
try:
|
||||
cred = (session.query(network_models_v2.Credential).
|
||||
filter_by(tenant_id=tenant_id).
|
||||
filter_by(credential_id=credential_id).one())
|
||||
if new_user_name:
|
||||
cred["user_name"] = new_user_name
|
||||
if new_password:
|
||||
cred["password"] = new_password
|
||||
session.merge(cred)
|
||||
session.flush()
|
||||
return cred
|
||||
except exc.NoResultFound:
|
||||
raise c_exc.CredentialNotFound(credential_id=credential_id,
|
||||
tenant_id=tenant_id)
|
195
quantum/plugins/cisco/db/network_models_v2.py
Normal file
195
quantum/plugins/cisco/db/network_models_v2.py
Normal file
@ -0,0 +1,195 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2012, Cisco Systems, Inc.
|
||||
#
|
||||
# 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: Rohit Agarwalla, Cisco Systems, Inc.
|
||||
|
||||
import uuid
|
||||
|
||||
from sqlalchemy import Column, Integer, String, ForeignKey, Boolean
|
||||
from sqlalchemy.orm import relation, object_mapper
|
||||
|
||||
from quantum.db import model_base
|
||||
from quantum.db import models_v2 as models
|
||||
|
||||
|
||||
class L2NetworkBase(object):
|
||||
"""Base class for L2Network Models."""
|
||||
#__table_args__ = {'mysql_engine': 'InnoDB'}
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
"""Internal Dict set method"""
|
||||
setattr(self, key, value)
|
||||
|
||||
def __getitem__(self, key):
|
||||
"""Internal Dict get method"""
|
||||
return getattr(self, key)
|
||||
|
||||
def get(self, key, default=None):
|
||||
"""Dict get method"""
|
||||
return getattr(self, key, default)
|
||||
|
||||
def __iter__(self):
|
||||
"""Iterate over table columns"""
|
||||
self._i = iter(object_mapper(self).columns)
|
||||
return self
|
||||
|
||||
def next(self):
|
||||
"""Next method for the iterator"""
|
||||
n = self._i.next().name
|
||||
return n, getattr(self, n)
|
||||
|
||||
def update(self, values):
|
||||
"""Make the model object behave like a dict"""
|
||||
for k, v in values.iteritems():
|
||||
setattr(self, k, v)
|
||||
|
||||
def iteritems(self):
|
||||
"""Make the model object behave like a dict"
|
||||
Includes attributes from joins."""
|
||||
local = dict(self)
|
||||
joined = dict([(k, v) for k, v in self.__dict__.iteritems()
|
||||
if not k[0] == '_'])
|
||||
local.update(joined)
|
||||
return local.iteritems()
|
||||
|
||||
|
||||
class VlanID(model_base.BASEV2, L2NetworkBase):
|
||||
"""Represents a vlan_id usage"""
|
||||
__tablename__ = 'vlan_ids'
|
||||
|
||||
vlan_id = Column(Integer, primary_key=True)
|
||||
vlan_used = Column(Boolean)
|
||||
|
||||
def __init__(self, vlan_id):
|
||||
self.vlan_id = vlan_id
|
||||
self.vlan_used = False
|
||||
|
||||
def __repr__(self):
|
||||
return "<VlanID(%d,%s)>" % (self.vlan_id, self.vlan_used)
|
||||
|
||||
|
||||
class VlanBinding(model_base.BASEV2, L2NetworkBase):
|
||||
"""Represents a binding of vlan_id to network_id"""
|
||||
__tablename__ = 'vlan_bindings'
|
||||
|
||||
vlan_id = Column(Integer, primary_key=True)
|
||||
vlan_name = Column(String(255))
|
||||
network_id = Column(String(255),
|
||||
nullable=False)
|
||||
|
||||
def __init__(self, vlan_id, vlan_name, network_id):
|
||||
self.vlan_id = vlan_id
|
||||
self.vlan_name = vlan_name
|
||||
self.network_id = network_id
|
||||
|
||||
def __repr__(self):
|
||||
return "<VlanBinding(%d,%s,%s)>" % (self.vlan_id,
|
||||
self.vlan_name,
|
||||
self.network_id)
|
||||
|
||||
|
||||
class PortProfile(model_base.BASEV2, L2NetworkBase):
|
||||
"""Represents L2 network plugin level PortProfile for a network"""
|
||||
__tablename__ = 'portprofiles'
|
||||
|
||||
uuid = Column(String(255), primary_key=True)
|
||||
name = Column(String(255))
|
||||
vlan_id = Column(Integer)
|
||||
qos = Column(String(255))
|
||||
|
||||
def __init__(self, name, vlan_id, qos=None):
|
||||
self.uuid = uuid.uuid4()
|
||||
self.name = name
|
||||
self.vlan_id = vlan_id
|
||||
self.qos = qos
|
||||
|
||||
def __repr__(self):
|
||||
return "<PortProfile(%s,%s,%d,%s)>" % (self.uuid,
|
||||
self.name,
|
||||
self.vlan_id,
|
||||
self.qos)
|
||||
|
||||
|
||||
class PortProfileBinding(model_base.BASEV2, L2NetworkBase):
|
||||
"""Represents PortProfile binding to tenant and network"""
|
||||
__tablename__ = 'portprofile_bindings'
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
tenant_id = Column(String(255))
|
||||
|
||||
port_id = Column(String(255), ForeignKey("ports.id"), nullable=False)
|
||||
portprofile_id = Column(String(255), ForeignKey("portprofiles.uuid"),
|
||||
nullable=False)
|
||||
default = Column(Boolean)
|
||||
ports = relation(models.Port)
|
||||
portprofile = relation(PortProfile, uselist=False)
|
||||
|
||||
def __init__(self, tenant_id, port_id, portprofile_id, default):
|
||||
self.tenant_id = tenant_id
|
||||
self.port_id = port_id
|
||||
self.portprofile_id = portprofile_id
|
||||
self.default = default
|
||||
|
||||
def __repr__(self):
|
||||
return "<PortProfile Binding(%s,%s,%s,%s)>" % (self.tenant_id,
|
||||
self.port_id,
|
||||
self.portprofile_id,
|
||||
self.default)
|
||||
|
||||
|
||||
class QoS(model_base.BASEV2, L2NetworkBase):
|
||||
"""Represents QoS for a tenant"""
|
||||
__tablename__ = 'qoss'
|
||||
|
||||
qos_id = Column(String(255))
|
||||
tenant_id = Column(String(255), primary_key=True)
|
||||
qos_name = Column(String(255), primary_key=True)
|
||||
qos_desc = Column(String(255))
|
||||
|
||||
def __init__(self, tenant_id, qos_name, qos_desc):
|
||||
self.qos_id = str(uuid.uuid4())
|
||||
self.tenant_id = tenant_id
|
||||
self.qos_name = qos_name
|
||||
self.qos_desc = qos_desc
|
||||
|
||||
def __repr__(self):
|
||||
return "<QoS(%s,%s,%s,%s)>" % (self.qos_id, self.tenant_id,
|
||||
self.qos_name, self.qos_desc)
|
||||
|
||||
|
||||
class Credential(model_base.BASEV2, L2NetworkBase):
|
||||
"""Represents credentials for a tenant"""
|
||||
__tablename__ = 'credentials'
|
||||
|
||||
credential_id = Column(String(255))
|
||||
tenant_id = Column(String(255), primary_key=True)
|
||||
credential_name = Column(String(255), primary_key=True)
|
||||
user_name = Column(String(255))
|
||||
password = Column(String(255))
|
||||
|
||||
def __init__(self, tenant_id, credential_name, user_name, password):
|
||||
self.credential_id = str(uuid.uuid4())
|
||||
self.tenant_id = tenant_id
|
||||
self.credential_name = credential_name
|
||||
self.user_name = user_name
|
||||
self.password = password
|
||||
|
||||
def __repr__(self):
|
||||
return "<Credentials(%s,%s,%s,%s,%s)>" % (self.credential_id,
|
||||
self.tenant_id,
|
||||
self.credential_name,
|
||||
self.user_name,
|
||||
self.password)
|
89
quantum/plugins/cisco/db/nexus_db_v2.py
Normal file
89
quantum/plugins/cisco/db/nexus_db_v2.py
Normal file
@ -0,0 +1,89 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2012, Cisco Systems, Inc.
|
||||
#
|
||||
# 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: Rohit Agarwalla, Cisco Systems, Inc.
|
||||
|
||||
import logging as LOG
|
||||
|
||||
from sqlalchemy.orm import exc
|
||||
|
||||
import quantum.db.api as db
|
||||
|
||||
from quantum.plugins.cisco.common import cisco_exceptions as c_exc
|
||||
from quantum.plugins.cisco.db import nexus_models_v2
|
||||
|
||||
|
||||
def get_all_nexusport_bindings():
|
||||
"""Lists all the nexusport bindings"""
|
||||
LOG.debug("get_all_nexusport_bindings() called")
|
||||
session = db.get_session()
|
||||
try:
|
||||
bindings = session.query(nexus_models_v2.NexusPortBinding).all()
|
||||
return bindings
|
||||
except exc.NoResultFound:
|
||||
return []
|
||||
|
||||
|
||||
def get_nexusport_binding(vlan_id):
|
||||
"""Lists a nexusport binding"""
|
||||
LOG.debug("get_nexusport_binding() called")
|
||||
session = db.get_session()
|
||||
try:
|
||||
binding = (session.query(nexus_models_v2.NexusPortBinding).
|
||||
filter_by(vlan_id=vlan_id).all())
|
||||
return binding
|
||||
except exc.NoResultFound:
|
||||
raise c_exc.NexusPortBindingNotFound(vlan_id=vlan_id)
|
||||
|
||||
|
||||
def add_nexusport_binding(port_id, vlan_id):
|
||||
"""Adds a nexusport binding"""
|
||||
LOG.debug("add_nexusport_binding() called")
|
||||
session = db.get_session()
|
||||
binding = nexus_models_v2.NexusPortBinding(port_id, vlan_id)
|
||||
session.add(binding)
|
||||
session.flush()
|
||||
return binding
|
||||
|
||||
|
||||
def remove_nexusport_binding(vlan_id):
|
||||
"""Removes a nexusport binding"""
|
||||
LOG.debug("remove_nexusport_binding() called")
|
||||
session = db.get_session()
|
||||
try:
|
||||
binding = (session.query(nexus_models_v2.NexusPortBinding).
|
||||
filter_by(vlan_id=vlan_id).all())
|
||||
for bind in binding:
|
||||
session.delete(bind)
|
||||
session.flush()
|
||||
return binding
|
||||
except exc.NoResultFound:
|
||||
pass
|
||||
|
||||
|
||||
def update_nexusport_binding(port_id, new_vlan_id):
|
||||
"""Updates nexusport binding"""
|
||||
LOG.debug("update_nexusport_binding called")
|
||||
session = db.get_session()
|
||||
try:
|
||||
binding = (session.query(nexus_models_v2.NexusPortBinding).
|
||||
filter_by(port_id=port_id).one())
|
||||
if new_vlan_id:
|
||||
binding["vlan_id"] = new_vlan_id
|
||||
session.merge(binding)
|
||||
session.flush()
|
||||
return binding
|
||||
except exc.NoResultFound:
|
||||
raise c_exc.NexusPortBindingNotFound()
|
37
quantum/plugins/cisco/db/nexus_models_v2.py
Normal file
37
quantum/plugins/cisco/db/nexus_models_v2.py
Normal file
@ -0,0 +1,37 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2012, Cisco Systems, Inc.
|
||||
#
|
||||
# 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: Rohit Agarwalla, Cisco Systems, Inc.
|
||||
|
||||
from sqlalchemy import Column, Integer, String
|
||||
|
||||
from quantum.db import model_base
|
||||
from quantum.plugins.cisco.db.l2network_models import L2NetworkBase
|
||||
|
||||
|
||||
class NexusPortBinding(model_base.BASEV2, L2NetworkBase):
|
||||
"""Represents a binding of nexus port to vlan_id"""
|
||||
__tablename__ = 'nexusport_bindings'
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
port_id = Column(String(255))
|
||||
vlan_id = Column(Integer, nullable=False)
|
||||
|
||||
def __init__(self, port_id, vlan_id):
|
||||
self.port_id = port_id
|
||||
self.vlan_id = vlan_id
|
||||
|
||||
def __repr__(self):
|
||||
return "<NexusPortBinding (%s,%d)>" % (self.port_id, self.vlan_id)
|
155
quantum/plugins/cisco/db/ucs_db_v2.py
Normal file
155
quantum/plugins/cisco/db/ucs_db_v2.py
Normal file
@ -0,0 +1,155 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2012, Cisco Systems, Inc.
|
||||
#
|
||||
# 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: Rohit Agarwalla, Cisco Systems, Inc.
|
||||
|
||||
import logging as LOG
|
||||
|
||||
from sqlalchemy.orm import exc
|
||||
|
||||
from quantum.db import api as db
|
||||
|
||||
from quantum.plugins.cisco.common import cisco_exceptions as c_exc
|
||||
from quantum.plugins.cisco.db import ucs_models_v2 as ucs_models
|
||||
|
||||
|
||||
def get_all_portbindings():
|
||||
"""Lists all the port bindings"""
|
||||
LOG.debug("db get_all_portbindings() called")
|
||||
session = db.get_session()
|
||||
try:
|
||||
port_bindings = session.query(ucs_models.PortBinding).all()
|
||||
return port_bindings
|
||||
except exc.NoResultFound:
|
||||
return []
|
||||
|
||||
|
||||
def get_portbinding(port_id):
|
||||
"""Lists a port binding"""
|
||||
LOG.debug("get_portbinding() called")
|
||||
session = db.get_session()
|
||||
try:
|
||||
port_binding = (session.query(ucs_models.PortBinding).
|
||||
filter_by(port_id=port_id).one())
|
||||
return port_binding
|
||||
except exc.NoResultFound:
|
||||
raise c_exc.PortVnicNotFound(port_id=port_id)
|
||||
|
||||
|
||||
def add_portbinding(port_id, blade_intf_dn, portprofile_name,
|
||||
vlan_name, vlan_id, qos):
|
||||
"""Adds a port binding"""
|
||||
LOG.debug("add_portbinding() called")
|
||||
session = db.get_session()
|
||||
try:
|
||||
port_binding = (session.query(ucs_models.PortBinding).
|
||||
filter_by(port_id=port_id).one())
|
||||
raise c_exc.PortVnicBindingAlreadyExists(port_id=port_id)
|
||||
except exc.NoResultFound:
|
||||
port_binding = ucs_models.PortBinding(port_id, blade_intf_dn,
|
||||
portprofile_name, vlan_name,
|
||||
vlan_id, qos)
|
||||
session.add(port_binding)
|
||||
session.flush()
|
||||
return port_binding
|
||||
|
||||
|
||||
def remove_portbinding(port_id):
|
||||
"""Removes a port binding"""
|
||||
LOG.debug("db remove_portbinding() called")
|
||||
session = db.get_session()
|
||||
try:
|
||||
port_binding = (session.query(ucs_models.PortBinding).
|
||||
filter_by(port_id=port_id).one())
|
||||
session.delete(port_binding)
|
||||
session.flush()
|
||||
return port_binding
|
||||
except exc.NoResultFound:
|
||||
pass
|
||||
|
||||
|
||||
def update_portbinding(port_id, blade_intf_dn=None, portprofile_name=None,
|
||||
vlan_name=None, vlan_id=None, qos=None,
|
||||
tenant_id=None, instance_id=None,
|
||||
vif_id=None):
|
||||
"""Updates port binding"""
|
||||
LOG.debug("db update_portbinding() called")
|
||||
session = db.get_session()
|
||||
try:
|
||||
port_binding = (session.query(ucs_models.PortBinding).
|
||||
filter_by(port_id=port_id).one())
|
||||
if blade_intf_dn:
|
||||
port_binding.blade_intf_dn = blade_intf_dn
|
||||
if portprofile_name:
|
||||
port_binding.portprofile_name = portprofile_name
|
||||
if vlan_name:
|
||||
port_binding.vlan_name = vlan_name
|
||||
if vlan_name:
|
||||
port_binding.vlan_id = vlan_id
|
||||
if qos:
|
||||
port_binding.qos = qos
|
||||
if tenant_id:
|
||||
port_binding.tenant_id = tenant_id
|
||||
if instance_id:
|
||||
port_binding.instance_id = instance_id
|
||||
if vif_id:
|
||||
port_binding.vif_id = vif_id
|
||||
session.merge(port_binding)
|
||||
session.flush()
|
||||
return port_binding
|
||||
except exc.NoResultFound:
|
||||
raise c_exc.PortVnicNotFound(port_id=port_id)
|
||||
|
||||
|
||||
def update_portbinding_instance_id(port_id, instance_id):
|
||||
"""Updates port binding for the instance ID"""
|
||||
LOG.debug("db update_portbinding_instance_id() called")
|
||||
session = db.get_session()
|
||||
try:
|
||||
port_binding = (session.query(ucs_models.PortBinding).
|
||||
filter_by(port_id=port_id).one())
|
||||
port_binding.instance_id = instance_id
|
||||
session.merge(port_binding)
|
||||
session.flush()
|
||||
return port_binding
|
||||
except exc.NoResultFound:
|
||||
raise c_exc.PortVnicNotFound(port_id=port_id)
|
||||
|
||||
|
||||
def update_portbinding_vif_id(port_id, vif_id):
|
||||
"""Updates port binding for the VIF ID"""
|
||||
LOG.debug("db update_portbinding_vif_id() called")
|
||||
session = db.get_session()
|
||||
try:
|
||||
port_binding = (session.query(ucs_models.PortBinding).
|
||||
filter_by(port_id=port_id).one())
|
||||
port_binding.vif_id = vif_id
|
||||
session.merge(port_binding)
|
||||
session.flush()
|
||||
return port_binding
|
||||
except exc.NoResultFound:
|
||||
raise c_exc.PortVnicNotFound(port_id=port_id)
|
||||
|
||||
|
||||
def get_portbinding_dn(blade_intf_dn):
|
||||
"""Lists a port binding"""
|
||||
LOG.debug("get_portbinding_dn() called")
|
||||
session = db.get_session()
|
||||
try:
|
||||
port_binding = (session.query(ucs_models.PortBinding).
|
||||
filter_by(blade_intf_dn=blade_intf_dn).one())
|
||||
return port_binding
|
||||
except exc.NoResultFound:
|
||||
return []
|
53
quantum/plugins/cisco/db/ucs_models_v2.py
Normal file
53
quantum/plugins/cisco/db/ucs_models_v2.py
Normal file
@ -0,0 +1,53 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2012, Cisco Systems, Inc.
|
||||
#
|
||||
# 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: Rohit Agarwalla, Cisco Systems, Inc.
|
||||
|
||||
from sqlalchemy import Column, Integer, String
|
||||
from sqlalchemy.orm import relation
|
||||
|
||||
from quantum.db.model_base import BASEV2 as BASE
|
||||
from quantum.db import models_v2 as models
|
||||
from quantum.plugins.cisco.db.network_models_v2 import L2NetworkBase
|
||||
|
||||
|
||||
class PortBinding(BASE, L2NetworkBase):
|
||||
"""Represents Port binding to device interface"""
|
||||
__tablename__ = 'port_bindings'
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
port_id = Column(String(255), nullable=False)
|
||||
blade_intf_dn = Column(String(255), nullable=False)
|
||||
portprofile_name = Column(String(255))
|
||||
vlan_name = Column(String(255))
|
||||
vlan_id = Column(Integer)
|
||||
qos = Column(String(255))
|
||||
tenant_id = Column(String(255))
|
||||
instance_id = Column(String(255))
|
||||
vif_id = Column(String(255))
|
||||
|
||||
def __init__(self, port_id, blade_intf_dn, portprofile_name,
|
||||
vlan_name, vlan_id, qos):
|
||||
self.port_id = port_id
|
||||
self.blade_intf_dn = blade_intf_dn
|
||||
self.portprofile_name = portprofile_name
|
||||
self.vlan_name = vlan_name
|
||||
self.vlan_id = vlan_id
|
||||
self.qos = qos
|
||||
|
||||
def __repr__(self):
|
||||
return "<PortProfile Binding(%s,%s,%s,%s,%s,%s)>" % (
|
||||
self.port_id, self.blade_intf_dn, self.portprofile_name,
|
||||
self.vlan_name, self.vlan_id, self.qos)
|
@ -1,6 +1,6 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2011 Cisco Systems, Inc. All rights reserved.
|
||||
# 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
|
||||
@ -128,6 +128,42 @@ class L2DevicePluginBase(object):
|
||||
"""
|
||||
pass
|
||||
|
||||
def create_subnet(self, tenant_id, net_id, ip_version,
|
||||
subnet_cidr, **kwargs):
|
||||
"""
|
||||
:returns:
|
||||
:raises:
|
||||
"""
|
||||
pass
|
||||
|
||||
def get_subnets(self, tenant_id, net_id, **kwargs):
|
||||
"""
|
||||
:returns:
|
||||
:raises:
|
||||
"""
|
||||
pass
|
||||
|
||||
def get_subnet(self, tenant_id, net_id, subnet_id, **kwargs):
|
||||
"""
|
||||
:returns:
|
||||
:raises:
|
||||
"""
|
||||
pass
|
||||
|
||||
def update_subnet(self, tenant_id, net_id, subnet_id, **kwargs):
|
||||
"""
|
||||
:returns:
|
||||
:raises:
|
||||
"""
|
||||
pass
|
||||
|
||||
def delete_subnet(self, tenant_id, net_id, subnet_id, **kwargs):
|
||||
"""
|
||||
:returns:
|
||||
:raises:
|
||||
"""
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def __subclasshook__(cls, klass):
|
||||
"""
|
||||
|
296
quantum/plugins/cisco/models/network_multi_blade_v2.py
Normal file
296
quantum/plugins/cisco/models/network_multi_blade_v2.py
Normal file
@ -0,0 +1,296 @@
|
||||
# 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.
|
||||
|
||||
from copy import deepcopy
|
||||
import inspect
|
||||
import logging
|
||||
|
||||
from quantum.openstack.common import importutils
|
||||
from quantum.plugins.cisco.common import cisco_constants as const
|
||||
from quantum.plugins.cisco.db import network_db_v2 as cdb
|
||||
from quantum.plugins.cisco import l2network_plugin_configuration as conf
|
||||
from quantum import quantum_plugin_base_v2
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NetworkMultiBladeV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
|
||||
"""
|
||||
This implementation works with UCS and Nexus plugin for the
|
||||
following topology:
|
||||
One or more UCSM (each with one or more chasses connected),
|
||||
All FICs connected to a single Nexus Switch.
|
||||
"""
|
||||
_plugins = {}
|
||||
_inventory = {}
|
||||
|
||||
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
|
||||
"""
|
||||
self._vlan_mgr = importutils.import_object(conf.MANAGER_CLASS)
|
||||
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 _func_name(self, offset=0):
|
||||
"""Get the name of the calling function"""
|
||||
return inspect.stack()[1 + offset][3]
|
||||
|
||||
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
|
||||
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:
|
||||
return func(*args, **kwargs)
|
||||
|
||||
def create_network(self, context, network):
|
||||
"""
|
||||
Perform this operation in the context of the configured device
|
||||
plugins.
|
||||
"""
|
||||
n = network
|
||||
try:
|
||||
vlan_id = self._vlan_mgr.reserve_segmentation_id(n['tenant_id'],
|
||||
n['name'])
|
||||
vlan_name = self._vlan_mgr.get_vlan_name(n['id'], str(vlan_id))
|
||||
args = [n['tenant_id'], n['name'], n['id'], vlan_name, vlan_id]
|
||||
output = []
|
||||
ucs_output = self._invoke_plugin_per_device(const.UCS_PLUGIN,
|
||||
self._func_name(),
|
||||
args)
|
||||
nexus_output = self._invoke_plugin_per_device(const.NEXUS_PLUGIN,
|
||||
self._func_name(),
|
||||
args)
|
||||
output.extend(ucs_output or [])
|
||||
output.extend(nexus_output or [])
|
||||
cdb.add_vlan_binding(vlan_id, vlan_name, n['id'])
|
||||
return output
|
||||
except:
|
||||
# TODO (Sumit): Check if we need to perform any rollback here
|
||||
raise
|
||||
|
||||
def get_network(self, context, id, fields=None, verbose=None):
|
||||
"""Currently there is no processing required for the device plugins"""
|
||||
pass
|
||||
|
||||
def get_networks(self, context, filters=None, fields=None, verbose=None):
|
||||
"""Currently there is no processing required for the device plugins"""
|
||||
pass
|
||||
|
||||
def update_network(self, context, id, network):
|
||||
"""Currently there is no processing required for the device plugins"""
|
||||
pass
|
||||
|
||||
def delete_network(self, context, id, kwargs):
|
||||
"""
|
||||
Perform this operation in the context of the configured device
|
||||
plugins.
|
||||
"""
|
||||
try:
|
||||
base_plugin_ref = kwargs[const.BASE_PLUGIN_REF]
|
||||
n = kwargs[const.NETWORK]
|
||||
tenant_id = n['tenant_id']
|
||||
args = [tenant_id, id, {const.CONTEXT:context},
|
||||
{const.BASE_PLUGIN_REF:base_plugin_ref}]
|
||||
# TODO (Sumit): Might first need to check here if there are active
|
||||
# ports
|
||||
output = []
|
||||
ucs_output = self._invoke_plugin_per_device(const.UCS_PLUGIN,
|
||||
self._func_name(),
|
||||
args)
|
||||
nexus_output = self._invoke_plugin_per_device(const.NEXUS_PLUGIN,
|
||||
self._func_name(),
|
||||
args)
|
||||
output.extend(ucs_output or [])
|
||||
output.extend(nexus_output or [])
|
||||
self._vlan_mgr.release_segmentation_id(tenant_id, id)
|
||||
cdb.remove_vlan_binding(id)
|
||||
return output
|
||||
except:
|
||||
# TODO (Sumit): Check if we need to perform any rollback here
|
||||
raise
|
||||
|
||||
def create_port(self, context, port):
|
||||
"""
|
||||
Perform this operation in the context of the configured device
|
||||
plugins.
|
||||
"""
|
||||
try:
|
||||
tenant_id = port['tenant_id']
|
||||
net_id = port['network_id']
|
||||
port_state = port['admin_state_up']
|
||||
port_id_string = port['id']
|
||||
args = [tenant_id, net_id, port_state, port_id_string]
|
||||
ret_val = self._invoke_plugin_per_device(const.UCS_PLUGIN,
|
||||
self._func_name(), args)
|
||||
new_args = [tenant_id, net_id, port['id'], port['id']]
|
||||
self._invoke_plugin_per_device(const.UCS_PLUGIN,
|
||||
"plug_interface", new_args)
|
||||
return ret_val
|
||||
except:
|
||||
# TODO (Sumit): Check if we need to perform any rollback here
|
||||
raise
|
||||
|
||||
def get_port(self, context, id, fields=None, verbose=None):
|
||||
"""Currently there is no processing required for the device plugins"""
|
||||
pass
|
||||
|
||||
def get_ports(self, context, filters=None, fields=None, verbose=None):
|
||||
"""Currently there is no processing required for the device plugins"""
|
||||
pass
|
||||
|
||||
def update_port(self, context, id, port):
|
||||
"""Currently there is no processing required for the device plugins"""
|
||||
pass
|
||||
|
||||
def delete_port(self, context, id, kwargs):
|
||||
"""
|
||||
Perform this operation in the context of the configured device
|
||||
plugins.
|
||||
"""
|
||||
try:
|
||||
p = kwargs['port']
|
||||
args = [p['tenant_id'], p['network_id'], p['id']]
|
||||
return self._invoke_plugin_per_device(const.UCS_PLUGIN,
|
||||
self._func_name(), args)
|
||||
except:
|
||||
# TODO (Sumit): Check if we need to perform any rollback here
|
||||
raise
|
||||
|
||||
def create_subnet(self, context, subnet):
|
||||
"""Currently there is no processing required for the device plugins"""
|
||||
pass
|
||||
|
||||
def update_subnet(self, context, id, subnet):
|
||||
"""Currently there is no processing required for the device plugins"""
|
||||
pass
|
||||
|
||||
def get_subnet(self, context, id, fields=None, verbose=None):
|
||||
"""Currently there is no processing required for the device plugins"""
|
||||
pass
|
||||
|
||||
def delete_subnet(self, context, id, kwargs):
|
||||
"""Currently there is no processing required for the device plugins"""
|
||||
pass
|
||||
|
||||
def get_subnets(self, context, filters=None, fields=None, verbose=None):
|
||||
"""Currently there is no processing required for the device plugins"""
|
||||
pass
|
||||
|
||||
"""
|
||||
Extensions' implementation in device plugins
|
||||
"""
|
||||
def schedule_host(self, args):
|
||||
"""Provides the hostname on which a dynamic vnic is reserved"""
|
||||
try:
|
||||
return self._invoke_inventory(const.UCS_PLUGIN, self._func_name(),
|
||||
args)
|
||||
except:
|
||||
# TODO (Sumit): Check if we need to perform any rollback here
|
||||
raise
|
||||
|
||||
def associate_port(self, args):
|
||||
"""Get the portprofile name and the device name for the dynamic vnic"""
|
||||
try:
|
||||
return self._invoke_inventory(const.UCS_PLUGIN, self._func_name(),
|
||||
args)
|
||||
except:
|
||||
# TODO (Sumit): Check if we need to perform any rollback here
|
||||
raise
|
||||
|
||||
def detach_port(self, args):
|
||||
"""Remove the association of the VIF with the dynamic vnic """
|
||||
try:
|
||||
return self._invoke_plugin_per_device(const.UCS_PLUGIN,
|
||||
self._func_name(), args)
|
||||
except:
|
||||
# TODO (Sumit): Check if we need to perform any rollback here
|
||||
raise
|
||||
|
||||
def create_multiport(self, args):
|
||||
"""
|
||||
Makes a call to the UCS device plugin to create ports on the same
|
||||
host.
|
||||
"""
|
||||
try:
|
||||
self._invoke_plugin_per_device(const.UCS_PLUGIN, self._func_name(),
|
||||
args)
|
||||
except:
|
||||
# TODO (Sumit): Check if we need to perform any rollback here
|
||||
raise
|
455
quantum/plugins/cisco/network_plugin.py
Normal file
455
quantum/plugins/cisco/network_plugin.py
Normal file
@ -0,0 +1,455 @@
|
||||
# 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 inspect
|
||||
import logging
|
||||
|
||||
from quantum.common import exceptions as exc
|
||||
from quantum.db import db_base_plugin_v2
|
||||
from quantum.db import models_v2
|
||||
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.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 import l2network_plugin_configuration as conf
|
||||
from quantum.quantum_plugin_base import QuantumPluginBase
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PluginV2(db_base_plugin_v2.QuantumDbPluginV2):
|
||||
"""
|
||||
Plugin with v2 API support for multiple sub-plugins
|
||||
"""
|
||||
supported_extension_aliases = ["Cisco Credential", "Cisco Port Profile",
|
||||
"Cisco qos", "Cisco Nova Tenant",
|
||||
"Cisco Multiport"]
|
||||
|
||||
"""
|
||||
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):
|
||||
"""
|
||||
Creates a new Virtual Network, and assigns it
|
||||
a symbolic name.
|
||||
"""
|
||||
LOG.debug("create_network() called\n")
|
||||
new_network = super(PluginV2, self).create_network(context, network)
|
||||
try:
|
||||
self._invoke_device_plugins(self._func_name(), [context,
|
||||
new_network])
|
||||
return new_network
|
||||
except:
|
||||
super(PluginV2, self).delete_network(context, new_network['id'])
|
||||
raise
|
||||
|
||||
def update_network(self, context, id, network):
|
||||
"""
|
||||
Updates the symbolic name belonging to a particular
|
||||
Virtual Network.
|
||||
"""
|
||||
LOG.debug("update_network() called\n")
|
||||
try:
|
||||
self._invoke_device_plugins(self._func_name(), [context, id,
|
||||
network])
|
||||
return super(PluginV2, self).update_network(context, id, network)
|
||||
except:
|
||||
raise
|
||||
|
||||
def delete_network(self, context, id):
|
||||
"""
|
||||
Deletes the network with the specified network identifier
|
||||
belonging to the specified tenant.
|
||||
"""
|
||||
LOG.debug("delete_network() called\n")
|
||||
#We first need to check if there are any ports on this network
|
||||
with context.session.begin():
|
||||
network = self._get_network(context, id)
|
||||
|
||||
filter = {'network_id': [id]}
|
||||
ports = self.get_ports(context, filters=filter)
|
||||
if ports:
|
||||
raise exc.NetworkInUse(net_id=id)
|
||||
context.session.close()
|
||||
#Network does not have any ports, we can proceed to delete
|
||||
try:
|
||||
network = self._get_network(context, id)
|
||||
kwargs = {const.NETWORK: network,
|
||||
const.BASE_PLUGIN_REF: self}
|
||||
self._invoke_device_plugins(self._func_name(), [context, id,
|
||||
kwargs])
|
||||
return super(PluginV2, self).delete_network(context, id)
|
||||
except:
|
||||
raise
|
||||
|
||||
def create_port(self, context, port):
|
||||
"""
|
||||
Creates a port on the specified Virtual Network.
|
||||
"""
|
||||
LOG.debug("create_port() called\n")
|
||||
new_port = super(PluginV2, self).create_port(context, port)
|
||||
try:
|
||||
self._invoke_device_plugins(self._func_name(), [context, new_port])
|
||||
return new_port
|
||||
except:
|
||||
super(PluginV2, self).delete_port(context, new_port['id'])
|
||||
raise
|
||||
|
||||
def delete_port(self, context, id):
|
||||
"""
|
||||
Deletes a port
|
||||
"""
|
||||
LOG.debug("delete_port() called\n")
|
||||
port = self._get_port(context, id)
|
||||
"""
|
||||
TODO (Sumit): Disabling this check for now, check later
|
||||
#Allow deleting a port only if the administrative state is down,
|
||||
#and its operation status is also down
|
||||
if port['admin_state_up'] or port['status'] == 'ACTIVE':
|
||||
raise exc.PortInUse(port_id=id, net_id=port['network_id'],
|
||||
att_id=port['device_id'])
|
||||
"""
|
||||
try:
|
||||
kwargs = {const.PORT: port}
|
||||
# TODO (Sumit): Might first need to check here if port is active
|
||||
self._invoke_device_plugins(self._func_name(), [context, id,
|
||||
kwargs])
|
||||
return super(PluginV2, self).delete_port(context, id)
|
||||
except:
|
||||
raise
|
||||
|
||||
def update_port(self, context, id, port):
|
||||
"""
|
||||
Updates the state of a port and returns the updated port
|
||||
"""
|
||||
LOG.debug("update_port() called\n")
|
||||
try:
|
||||
self._invoke_device_plugins(self._func_name(), [context, id,
|
||||
port])
|
||||
return super(PluginV2, self).update_port(context, id, port)
|
||||
except:
|
||||
raise
|
||||
|
||||
def create_subnet(self, context, subnet):
|
||||
"""
|
||||
Create a subnet, which represents a range of IP addresses
|
||||
that can be allocated to devices.
|
||||
"""
|
||||
LOG.debug("create_subnet() called\n")
|
||||
new_subnet = super(PluginV2, self).create_subnet(context, subnet)
|
||||
try:
|
||||
self._invoke_device_plugins(self._func_name(), [context,
|
||||
new_subnet])
|
||||
return new_subnet
|
||||
except:
|
||||
super(PluginV2, self).delete_subnet(context, new_subnet['id'])
|
||||
raise
|
||||
|
||||
def update_subnet(self, context, id, subnet):
|
||||
"""
|
||||
Updates the state of a subnet and returns the updated subnet
|
||||
"""
|
||||
LOG.debug("update_subnet() called\n")
|
||||
try:
|
||||
self._invoke_device_plugins(self._func_name(), [context, id,
|
||||
subnet])
|
||||
return super(PluginV2, self).update_subnet(context, id, subnet)
|
||||
except:
|
||||
raise
|
||||
|
||||
def delete_subnet(self, context, id):
|
||||
"""
|
||||
Deletes a subnet
|
||||
"""
|
||||
LOG.debug("delete_subnet() called\n")
|
||||
with context.session.begin():
|
||||
subnet = self._get_subnet(context, id)
|
||||
# Check if ports are using this subnet
|
||||
allocated_qry = context.session.query(models_v2.IPAllocation)
|
||||
allocated = allocated_qry.filter_by(subnet_id=id).all()
|
||||
if allocated:
|
||||
raise exc.SubnetInUse(subnet_id=id)
|
||||
context.session.close()
|
||||
try:
|
||||
kwargs = {const.SUBNET: subnet}
|
||||
self._invoke_device_plugins(self._func_name(), [context, id,
|
||||
kwargs])
|
||||
return super(PluginV2, self).delete_subnet(context, id)
|
||||
except:
|
||||
raise
|
||||
|
||||
"""
|
||||
Extension API implementation
|
||||
"""
|
||||
def get_all_portprofiles(self, tenant_id):
|
||||
"""Get all port profiles"""
|
||||
LOG.debug("get_all_portprofiles() called\n")
|
||||
pplist = cdb.get_all_portprofiles()
|
||||
new_pplist = []
|
||||
for portprofile in pplist:
|
||||
new_pp = cutil.make_portprofile_dict(tenant_id,
|
||||
portprofile[const.UUID],
|
||||
portprofile[const.PPNAME],
|
||||
portprofile[const.PPQOS])
|
||||
new_pplist.append(new_pp)
|
||||
|
||||
return new_pplist
|
||||
|
||||
def get_portprofile_details(self, tenant_id, profile_id):
|
||||
"""Get port profile details"""
|
||||
LOG.debug("get_portprofile_details() called\n")
|
||||
try:
|
||||
portprofile = cdb.get_portprofile(tenant_id, profile_id)
|
||||
except Exception:
|
||||
raise cexc.PortProfileNotFound(tenant_id=tenant_id,
|
||||
portprofile_id=profile_id)
|
||||
|
||||
new_pp = cutil.make_portprofile_dict(tenant_id,
|
||||
portprofile[const.UUID],
|
||||
portprofile[const.PPNAME],
|
||||
portprofile[const.PPQOS])
|
||||
return new_pp
|
||||
|
||||
def create_portprofile(self, tenant_id, profile_name, qos):
|
||||
"""Create port profile"""
|
||||
LOG.debug("create_portprofile() called\n")
|
||||
portprofile = cdb.add_portprofile(tenant_id, profile_name,
|
||||
const.NO_VLAN_ID, qos)
|
||||
new_pp = cutil.make_portprofile_dict(tenant_id,
|
||||
portprofile[const.UUID],
|
||||
portprofile[const.PPNAME],
|
||||
portprofile[const.PPQOS])
|
||||
return new_pp
|
||||
|
||||
def delete_portprofile(self, tenant_id, profile_id):
|
||||
"""Delete portprofile"""
|
||||
LOG.debug("delete_portprofile() called\n")
|
||||
try:
|
||||
portprofile = cdb.get_portprofile(tenant_id, profile_id)
|
||||
except Exception:
|
||||
raise cexc.PortProfileNotFound(tenant_id=tenant_id,
|
||||
portprofile_id=profile_id)
|
||||
|
||||
plist = cdb.get_pp_binding(tenant_id, profile_id)
|
||||
if plist:
|
||||
raise cexc.PortProfileInvalidDelete(tenant_id=tenant_id,
|
||||
profile_id=profile_id)
|
||||
else:
|
||||
cdb.remove_portprofile(tenant_id, profile_id)
|
||||
|
||||
def rename_portprofile(self, tenant_id, profile_id, new_name):
|
||||
"""Rename port profile"""
|
||||
LOG.debug("rename_portprofile() called\n")
|
||||
try:
|
||||
portprofile = cdb.get_portprofile(tenant_id, profile_id)
|
||||
except Exception:
|
||||
raise cexc.PortProfileNotFound(tenant_id=tenant_id,
|
||||
portprofile_id=profile_id)
|
||||
portprofile = cdb.update_portprofile(tenant_id, profile_id, new_name)
|
||||
new_pp = cutil.make_portprofile_dict(tenant_id,
|
||||
portprofile[const.UUID],
|
||||
portprofile[const.PPNAME],
|
||||
portprofile[const.PPQOS])
|
||||
return new_pp
|
||||
|
||||
def associate_portprofile(self, tenant_id, net_id,
|
||||
port_id, portprofile_id):
|
||||
"""Associate port profile"""
|
||||
LOG.debug("associate_portprofile() called\n")
|
||||
try:
|
||||
portprofile = cdb.get_portprofile(tenant_id, portprofile_id)
|
||||
except Exception:
|
||||
raise cexc.PortProfileNotFound(tenant_id=tenant_id,
|
||||
portprofile_id=portprofile_id)
|
||||
|
||||
cdb.add_pp_binding(tenant_id, port_id, portprofile_id, False)
|
||||
|
||||
def disassociate_portprofile(self, tenant_id, net_id,
|
||||
port_id, portprofile_id):
|
||||
"""Disassociate port profile"""
|
||||
LOG.debug("disassociate_portprofile() called\n")
|
||||
try:
|
||||
portprofile = cdb.get_portprofile(tenant_id, portprofile_id)
|
||||
except Exception:
|
||||
raise cexc.PortProfileNotFound(tenant_id=tenant_id,
|
||||
portprofile_id=portprofile_id)
|
||||
|
||||
cdb.remove_pp_binding(tenant_id, port_id, portprofile_id)
|
||||
|
||||
def get_all_qoss(self, tenant_id):
|
||||
"""Get all QoS levels"""
|
||||
LOG.debug("get_all_qoss() called\n")
|
||||
qoslist = cdb.get_all_qoss(tenant_id)
|
||||
return qoslist
|
||||
|
||||
def get_qos_details(self, tenant_id, qos_id):
|
||||
"""Get QoS Details"""
|
||||
LOG.debug("get_qos_details() called\n")
|
||||
try:
|
||||
qos_level = cdb.get_qos(tenant_id, qos_id)
|
||||
except Exception:
|
||||
raise cexc.QosNotFound(tenant_id=tenant_id,
|
||||
qos_id=qos_id)
|
||||
return qos_level
|
||||
|
||||
def create_qos(self, tenant_id, qos_name, qos_desc):
|
||||
"""Create a QoS level"""
|
||||
LOG.debug("create_qos() called\n")
|
||||
qos = cdb.add_qos(tenant_id, qos_name, str(qos_desc))
|
||||
return qos
|
||||
|
||||
def delete_qos(self, tenant_id, qos_id):
|
||||
"""Delete a QoS level"""
|
||||
LOG.debug("delete_qos() called\n")
|
||||
try:
|
||||
qos_level = cdb.get_qos(tenant_id, qos_id)
|
||||
except Exception:
|
||||
raise cexc.QosNotFound(tenant_id=tenant_id,
|
||||
qos_id=qos_id)
|
||||
return cdb.remove_qos(tenant_id, qos_id)
|
||||
|
||||
def rename_qos(self, tenant_id, qos_id, new_name):
|
||||
"""Rename QoS level"""
|
||||
LOG.debug("rename_qos() called\n")
|
||||
try:
|
||||
qos_level = cdb.get_qos(tenant_id, qos_id)
|
||||
except Exception:
|
||||
raise cexc.QosNotFound(tenant_id=tenant_id,
|
||||
qos_id=qos_id)
|
||||
qos = cdb.update_qos(tenant_id, qos_id, new_name)
|
||||
return qos
|
||||
|
||||
def get_all_credentials(self, tenant_id):
|
||||
"""Get all credentials"""
|
||||
LOG.debug("get_all_credentials() called\n")
|
||||
credential_list = cdb.get_all_credentials(tenant_id)
|
||||
return credential_list
|
||||
|
||||
def get_credential_details(self, tenant_id, credential_id):
|
||||
"""Get a particular credential"""
|
||||
LOG.debug("get_credential_details() called\n")
|
||||
try:
|
||||
credential = cdb.get_credential(tenant_id, credential_id)
|
||||
except Exception:
|
||||
raise cexc.CredentialNotFound(tenant_id=tenant_id,
|
||||
credential_id=credential_id)
|
||||
return credential
|
||||
|
||||
def create_credential(self, tenant_id, credential_name, user_name,
|
||||
password):
|
||||
"""Create a new credential"""
|
||||
LOG.debug("create_credential() called\n")
|
||||
credential = cdb.add_credential(tenant_id, credential_name,
|
||||
user_name, password)
|
||||
return credential
|
||||
|
||||
def delete_credential(self, tenant_id, credential_id):
|
||||
"""Delete a credential"""
|
||||
LOG.debug("delete_credential() called\n")
|
||||
try:
|
||||
credential = cdb.get_credential(tenant_id, credential_id)
|
||||
except Exception:
|
||||
raise cexc.CredentialNotFound(tenant_id=tenant_id,
|
||||
credential_id=credential_id)
|
||||
credential = cdb.remove_credential(tenant_id, credential_id)
|
||||
return credential
|
||||
|
||||
def rename_credential(self, tenant_id, credential_id, new_name):
|
||||
"""Rename the particular credential resource"""
|
||||
LOG.debug("rename_credential() called\n")
|
||||
try:
|
||||
credential = cdb.get_credential(tenant_id, credential_id)
|
||||
except Exception:
|
||||
raise cexc.CredentialNotFound(tenant_id=tenant_id,
|
||||
credential_id=credential_id)
|
||||
credential = cdb.update_credential(tenant_id, credential_id, new_name)
|
||||
return credential
|
||||
|
||||
def schedule_host(self, tenant_id, instance_id, instance_desc):
|
||||
"""Provides the hostname on which a dynamic vnic is reserved"""
|
||||
LOG.debug("schedule_host() called\n")
|
||||
host_list = self._invoke_device_plugins(self._func_name(),
|
||||
[tenant_id,
|
||||
instance_id,
|
||||
instance_desc])
|
||||
return host_list
|
||||
|
||||
def associate_port(self, tenant_id, instance_id, instance_desc):
|
||||
"""
|
||||
Get the portprofile name and the device name for the dynamic vnic
|
||||
"""
|
||||
LOG.debug("associate_port() called\n")
|
||||
return self._invoke_device_plugins(self._func_name(), [tenant_id,
|
||||
instance_id,
|
||||
instance_desc])
|
||||
|
||||
def detach_port(self, tenant_id, instance_id, instance_desc):
|
||||
"""
|
||||
Remove the association of the VIF with the dynamic vnic
|
||||
"""
|
||||
LOG.debug("detach_port() called\n")
|
||||
return self._invoke_device_plugins(self._func_name(), [tenant_id,
|
||||
instance_id,
|
||||
instance_desc])
|
||||
|
||||
def create_multiport(self, tenant_id, net_id_list, port_state, ports_desc):
|
||||
"""
|
||||
Creates multiple ports on the specified Virtual Network.
|
||||
"""
|
||||
LOG.debug("create_ports() called\n")
|
||||
ports_num = len(net_id_list)
|
||||
ports_id_list = []
|
||||
ports_dict_list = []
|
||||
|
||||
for net_id in net_id_list:
|
||||
db.validate_network_ownership(tenant_id, net_id)
|
||||
port = db.port_create(net_id, port_state)
|
||||
ports_id_list.append(port[const.UUID])
|
||||
port_dict = {const.PORT_ID: port[const.UUID]}
|
||||
ports_dict_list.append(port_dict)
|
||||
|
||||
self._invoke_device_plugins(self._func_name(), [tenant_id,
|
||||
net_id_list,
|
||||
ports_num,
|
||||
ports_id_list])
|
||||
return ports_dict_list
|
||||
|
||||
"""
|
||||
Private functions
|
||||
"""
|
||||
def _invoke_device_plugins(self, function_name, args):
|
||||
"""
|
||||
All device-specific calls are delegated to the model
|
||||
"""
|
||||
return getattr(self._model, function_name)(*args)
|
||||
|
||||
def _func_name(self, offset=0):
|
||||
"""Getting the name of the calling funciton"""
|
||||
return inspect.stack()[1 + offset][3]
|
203
quantum/plugins/cisco/nexus/cisco_nexus_plugin_v2.py
Normal file
203
quantum/plugins/cisco/nexus/cisco_nexus_plugin_v2.py
Normal file
@ -0,0 +1,203 @@
|
||||
# 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: Edgar Magana, Cisco Systems, Inc.
|
||||
#
|
||||
"""
|
||||
PlugIn for Nexus OS driver
|
||||
"""
|
||||
import logging
|
||||
|
||||
from quantum.common import exceptions as exc
|
||||
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.db import network_db_v2 as cdb
|
||||
from quantum.plugins.cisco.db import nexus_db_v2 as nxos_db
|
||||
from quantum.plugins.cisco.l2device_plugin_base import L2DevicePluginBase
|
||||
from quantum.plugins.cisco.nexus import cisco_nexus_configuration as conf
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NexusPlugin(L2DevicePluginBase):
|
||||
"""
|
||||
Nexus PLugIn Main Class
|
||||
"""
|
||||
_networks = {}
|
||||
|
||||
def __init__(self):
|
||||
"""
|
||||
Extracts the configuration parameters from the configuration file
|
||||
"""
|
||||
self._client = importutils.import_object(conf.NEXUS_DRIVER)
|
||||
LOG.debug("Loaded driver %s\n" % conf.NEXUS_DRIVER)
|
||||
self._nexus_ip = conf.NEXUS_IP_ADDRESS
|
||||
self._nexus_username = cred.Store.get_username(conf.NEXUS_IP_ADDRESS)
|
||||
self._nexus_password = cred.Store.get_password(conf.NEXUS_IP_ADDRESS)
|
||||
self._nexus_first_port = conf.NEXUS_FIRST_PORT
|
||||
self._nexus_second_port = conf.NEXUS_SECOND_PORT
|
||||
self._nexus_ssh_port = conf.NEXUS_SSH_PORT
|
||||
|
||||
def get_all_networks(self, tenant_id):
|
||||
"""
|
||||
Returns a dictionary containing all
|
||||
<network_uuid, network_name> for
|
||||
the specified tenant.
|
||||
"""
|
||||
LOG.debug("NexusPlugin:get_all_networks() called\n")
|
||||
return self._networks.values()
|
||||
|
||||
def create_network(self, tenant_id, net_name, net_id, vlan_name, vlan_id,
|
||||
**kwargs):
|
||||
"""
|
||||
Create a VLAN in the switch, and configure the appropriate interfaces
|
||||
for this VLAN
|
||||
"""
|
||||
LOG.debug("NexusPlugin:create_network() called\n")
|
||||
self._client.create_vlan(
|
||||
vlan_name, str(vlan_id), self._nexus_ip,
|
||||
self._nexus_username, self._nexus_password,
|
||||
self._nexus_first_port, self._nexus_second_port,
|
||||
self._nexus_ssh_port)
|
||||
nxos_db.add_nexusport_binding(self._nexus_first_port, str(vlan_id))
|
||||
nxos_db.add_nexusport_binding(self._nexus_second_port, str(vlan_id))
|
||||
|
||||
new_net_dict = {const.NET_ID: net_id,
|
||||
const.NET_NAME: net_name,
|
||||
const.NET_PORTS: {},
|
||||
const.NET_VLAN_NAME: vlan_name,
|
||||
const.NET_VLAN_ID: vlan_id}
|
||||
self._networks[net_id] = new_net_dict
|
||||
return new_net_dict
|
||||
|
||||
def delete_network(self, tenant_id, net_id, **kwargs):
|
||||
"""
|
||||
Deletes a VLAN in the switch, and removes the VLAN configuration
|
||||
from the relevant interfaces
|
||||
"""
|
||||
LOG.debug("NexusPlugin:delete_network() called\n")
|
||||
context = kwargs[const.CONTEXT]
|
||||
base_plugin_ref = kwargs[const.BASE_PLUGIN_REF]
|
||||
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)
|
||||
LOG.debug("NexusPlugin: Interfaces to be disassociated: %s" % ports_id)
|
||||
nxos_db.remove_nexusport_binding(vlan_id)
|
||||
net = self._get_network(tenant_id, net_id, context, base_plugin_ref)
|
||||
if net:
|
||||
self._client.delete_vlan(
|
||||
str(vlan_id), self._nexus_ip,
|
||||
self._nexus_username, self._nexus_password,
|
||||
self._nexus_first_port, self._nexus_second_port,
|
||||
self._nexus_ssh_port)
|
||||
return net
|
||||
# Network not found
|
||||
raise exc.NetworkNotFound(net_id=net_id)
|
||||
|
||||
def get_network_details(self, tenant_id, net_id, **kwargs):
|
||||
"""
|
||||
Returns the details of a particular network
|
||||
"""
|
||||
LOG.debug("NexusPlugin:get_network_details() called\n")
|
||||
network = self._get_network(tenant_id, net_id)
|
||||
return network
|
||||
|
||||
def update_network(self, tenant_id, net_id, **kwargs):
|
||||
"""
|
||||
Updates the properties of a particular
|
||||
Virtual Network.
|
||||
"""
|
||||
LOG.debug("NexusPlugin:update_network() called\n")
|
||||
network = self._get_network(tenant_id, net_id)
|
||||
network[const.NET_NAME] = kwargs["name"]
|
||||
return network
|
||||
|
||||
def get_all_ports(self, tenant_id, net_id, **kwargs):
|
||||
"""
|
||||
This is probably not applicable to the Nexus plugin.
|
||||
Delete if not required.
|
||||
"""
|
||||
LOG.debug("NexusPlugin:get_all_ports() called\n")
|
||||
|
||||
def create_port(self, tenant_id, net_id, port_state, port_id, **kwargs):
|
||||
"""
|
||||
This is probably not applicable to the Nexus plugin.
|
||||
Delete if not required.
|
||||
"""
|
||||
LOG.debug("NexusPlugin:create_port() called\n")
|
||||
|
||||
def delete_port(self, tenant_id, net_id, port_id, **kwargs):
|
||||
"""
|
||||
This is probably not applicable to the Nexus plugin.
|
||||
Delete if not required.
|
||||
"""
|
||||
LOG.debug("NexusPlugin:delete_port() called\n")
|
||||
|
||||
def update_port(self, tenant_id, net_id, port_id, port_state, **kwargs):
|
||||
"""
|
||||
This is probably not applicable to the Nexus plugin.
|
||||
Delete if not required.
|
||||
"""
|
||||
LOG.debug("NexusPlugin:update_port() called\n")
|
||||
|
||||
def get_port_details(self, tenant_id, net_id, port_id, **kwargs):
|
||||
"""
|
||||
This is probably not applicable to the Nexus plugin.
|
||||
Delete if not required.
|
||||
"""
|
||||
LOG.debug("NexusPlugin:get_port_details() called\n")
|
||||
|
||||
def plug_interface(self, tenant_id, net_id, port_id, remote_interface_id,
|
||||
**kwargs):
|
||||
"""
|
||||
This is probably not applicable to the Nexus plugin.
|
||||
Delete if not required.
|
||||
"""
|
||||
LOG.debug("NexusPlugin:plug_interface() called\n")
|
||||
|
||||
def unplug_interface(self, tenant_id, net_id, port_id, **kwargs):
|
||||
"""
|
||||
This is probably not applicable to the Nexus plugin.
|
||||
Delete if not required.
|
||||
"""
|
||||
LOG.debug("NexusPlugin:unplug_interface() called\n")
|
||||
|
||||
def _get_vlan_id_for_network(self, tenant_id, network_id, context,
|
||||
base_plugin_ref):
|
||||
"""
|
||||
Obtain the VLAN ID given the Network ID
|
||||
"""
|
||||
net = self._get_network(tenant_id, network_id, context,
|
||||
base_plugin_ref)
|
||||
vlan_id = net[const.NET_VLAN_ID]
|
||||
return vlan_id
|
||||
|
||||
def _get_network(self, tenant_id, network_id, context, base_plugin_ref):
|
||||
"""
|
||||
Gets the NETWORK ID
|
||||
"""
|
||||
network = base_plugin_ref._get_network(context, network_id)
|
||||
if not network:
|
||||
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,
|
||||
const.NET_PORTS: network.ports,
|
||||
const.NET_VLAN_NAME: vlan.vlan_name,
|
||||
const.NET_VLAN_ID: vlan.vlan_id}
|
52
quantum/plugins/cisco/segmentation/l2network_vlan_mgr_v2.py
Normal file
52
quantum/plugins/cisco/segmentation/l2network_vlan_mgr_v2.py
Normal file
@ -0,0 +1,52 @@
|
||||
# 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.plugins.cisco.common import cisco_constants as const
|
||||
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.l2network_segmentation_base import (
|
||||
L2NetworkSegmentationMgrBase,
|
||||
)
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class L2NetworkVLANMgr(L2NetworkSegmentationMgrBase):
|
||||
"""
|
||||
VLAN Manager which gets VLAN ID from DB
|
||||
"""
|
||||
def __init__(self):
|
||||
cdb.create_vlanids()
|
||||
|
||||
def reserve_segmentation_id(self, tenant_id, net_name, **kwargs):
|
||||
"""Get an available VLAN ID"""
|
||||
return cdb.reserve_vlanid()
|
||||
|
||||
def release_segmentation_id(self, tenant_id, net_id, **kwargs):
|
||||
"""Release the ID"""
|
||||
vlan_binding = cdb.get_vlan_binding(net_id)
|
||||
return cdb.release_vlanid(vlan_binding[const.VLANID])
|
||||
|
||||
def get_vlan_name(self, net_id, vlan):
|
||||
"""Getting the vlan name from the tenant and vlan"""
|
||||
vlan_name = conf.VLAN_NAME_PREFIX + vlan
|
||||
return vlan_name
|
32
quantum/plugins/cisco/tests/unit/v2/__init__.py
Normal file
32
quantum/plugins/cisco/tests/unit/v2/__init__.py
Normal file
@ -0,0 +1,32 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2012 OpenStack LLC.
|
||||
# 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 __builtin__
|
||||
import unittest
|
||||
|
||||
|
||||
setattr(__builtin__, '_', lambda x: x)
|
||||
|
||||
|
||||
class BaseTest(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
pass
|
||||
|
||||
|
||||
def setUp():
|
||||
pass
|
32
quantum/plugins/cisco/tests/unit/v2/nexus/__init__.py
Normal file
32
quantum/plugins/cisco/tests/unit/v2/nexus/__init__.py
Normal file
@ -0,0 +1,32 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2012 OpenStack LLC.
|
||||
# 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 __builtin__
|
||||
import unittest
|
||||
|
||||
|
||||
setattr(__builtin__, '_', lambda x: x)
|
||||
|
||||
|
||||
class BaseTest(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
pass
|
||||
|
||||
|
||||
def setUp():
|
||||
pass
|
101
quantum/plugins/cisco/tests/unit/v2/nexus/fake_nexus_driver.py
Normal file
101
quantum/plugins/cisco/tests/unit/v2/nexus/fake_nexus_driver.py
Normal file
@ -0,0 +1,101 @@
|
||||
# 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.
|
||||
|
||||
|
||||
class CiscoNEXUSFakeDriver():
|
||||
"""
|
||||
Nexus Driver Fake Class
|
||||
"""
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def nxos_connect(self, nexus_host, nexus_ssh_port, nexus_user,
|
||||
nexus_password):
|
||||
"""
|
||||
Makes the fake connection to the Nexus Switch
|
||||
"""
|
||||
pass
|
||||
|
||||
def create_xml_snippet(self, cutomized_config):
|
||||
"""
|
||||
Creates the Proper XML structure for the Nexus Switch Configuration
|
||||
"""
|
||||
pass
|
||||
|
||||
def enable_vlan(self, mgr, vlanid, vlanname):
|
||||
"""
|
||||
Creates a VLAN on Nexus Switch given the VLAN ID and Name
|
||||
"""
|
||||
pass
|
||||
|
||||
def disable_vlan(self, mgr, vlanid):
|
||||
"""
|
||||
Delete a VLAN on Nexus Switch given the VLAN ID
|
||||
"""
|
||||
pass
|
||||
|
||||
def enable_port_trunk(self, mgr, interface):
|
||||
"""
|
||||
Enables trunk mode an interface on Nexus Switch
|
||||
"""
|
||||
pass
|
||||
|
||||
def disable_switch_port(self, mgr, interface):
|
||||
"""
|
||||
Disables trunk mode an interface on Nexus Switch
|
||||
"""
|
||||
pass
|
||||
|
||||
def enable_vlan_on_trunk_int(self, mgr, interface, vlanid):
|
||||
"""
|
||||
Enables trunk mode vlan access an interface on Nexus Switch given
|
||||
VLANID
|
||||
"""
|
||||
pass
|
||||
|
||||
def disable_vlan_on_trunk_int(self, mgr, interface, vlanid):
|
||||
"""
|
||||
Enables trunk mode vlan access an interface on Nexus Switch given
|
||||
VLANID
|
||||
"""
|
||||
pass
|
||||
|
||||
def create_vlan(self, vlan_name, vlan_id, nexus_host, nexus_user,
|
||||
nexus_password, nexus_first_interface,
|
||||
nexus_second_interface, nexus_ssh_port):
|
||||
"""
|
||||
Creates a VLAN and Enable on trunk mode an interface on Nexus Switch
|
||||
given the VLAN ID and Name and Interface Number
|
||||
"""
|
||||
pass
|
||||
|
||||
def delete_vlan(self, vlan_id, nexus_host, nexus_user, nexus_password,
|
||||
nexus_first_interface, nexus_second_interface,
|
||||
nexus_ssh_port):
|
||||
"""
|
||||
Delete a VLAN and Disables trunk mode an interface on Nexus Switch
|
||||
given the VLAN ID and Interface Number
|
||||
"""
|
||||
pass
|
||||
|
||||
def build_vlans_cmd(self):
|
||||
"""
|
||||
Builds a string with all the VLANs on the same Switch
|
||||
"""
|
||||
pass
|
@ -0,0 +1,20 @@
|
||||
[DEFAULT]
|
||||
# Show more verbose log output (sets INFO log level output)
|
||||
verbose = True
|
||||
|
||||
# Show debugging output in logs (sets DEBUG log level output)
|
||||
debug = False
|
||||
|
||||
# Address to bind the API server
|
||||
bind_host = 0.0.0.0
|
||||
|
||||
# Port the bind the API server to
|
||||
bind_port = 9696
|
||||
|
||||
# Path to the extensions
|
||||
api_extensions_path = ../../../../extensions
|
||||
|
||||
# Paste configuration file
|
||||
api_paste_config = api-paste.ini.cisco.test
|
||||
|
||||
core_plugin = quantum.plugins.cisco.network_plugin.PluginV2
|
55
quantum/plugins/cisco/tests/unit/v2/test_api_v2.py
Normal file
55
quantum/plugins/cisco/tests/unit/v2/test_api_v2.py
Normal file
@ -0,0 +1,55 @@
|
||||
# Copyright 2012 OpenStack LLC.
|
||||
# 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 spec
|
||||
|
||||
import inspect
|
||||
import logging
|
||||
import mock
|
||||
import os
|
||||
import webtest
|
||||
|
||||
from quantum.api.v2 import router
|
||||
from quantum.common import config
|
||||
from quantum.openstack.common import cfg
|
||||
from quantum.tests.unit import test_api_v2
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def curdir(*p):
|
||||
return os.path.join(os.path.dirname(__file__), *p)
|
||||
|
||||
|
||||
class APIv2TestCase(test_api_v2.APIv2TestCase):
|
||||
|
||||
def setUp(self):
|
||||
plugin = 'quantum.plugins.cisco.network_plugin.PluginV2'
|
||||
# Create the default configurations
|
||||
args = ['--config-file', curdir('quantumv2.conf.cisco.test')]
|
||||
config.parse(args=args)
|
||||
# Update the plugin
|
||||
cfg.CONF.set_override('core_plugin', plugin)
|
||||
|
||||
self._plugin_patcher = mock.patch(plugin, autospec=True)
|
||||
self.plugin = self._plugin_patcher.start()
|
||||
|
||||
api = router.APIRouter()
|
||||
self.api = webtest.TestApp(api)
|
||||
LOG.debug("%s.%s.%s done" % (__name__, self.__class__.__name__,
|
||||
inspect.stack()[0][3]))
|
||||
|
||||
|
||||
class JSONV2TestCase(APIv2TestCase, test_api_v2.JSONV2TestCase):
|
||||
|
||||
pass
|
86
quantum/plugins/cisco/tests/unit/v2/test_network_plugin.py
Normal file
86
quantum/plugins/cisco/tests/unit/v2/test_network_plugin.py
Normal file
@ -0,0 +1,86 @@
|
||||
# Copyright (c) 2012 OpenStack, LLC.
|
||||
#
|
||||
# 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 inspect
|
||||
import logging
|
||||
import mock
|
||||
import os
|
||||
|
||||
from quantum.api.v2.router import APIRouter
|
||||
from quantum.common import config
|
||||
from quantum.db import api as db
|
||||
from quantum.plugins.cisco.db import network_models_v2
|
||||
from quantum.openstack.common import cfg
|
||||
from quantum.tests.unit import test_db_plugin
|
||||
from quantum.wsgi import JSONDeserializer
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def curdir(*p):
|
||||
return os.path.join(os.path.dirname(__file__), *p)
|
||||
|
||||
|
||||
class NetworkPluginV2TestCase(test_db_plugin.QuantumDbPluginV2TestCase):
|
||||
|
||||
def setUp(self):
|
||||
db._ENGINE = None
|
||||
db._MAKER = None
|
||||
|
||||
self._tenant_id = 'test-tenant'
|
||||
|
||||
json_deserializer = JSONDeserializer()
|
||||
self._deserializers = {
|
||||
'application/json': json_deserializer,
|
||||
}
|
||||
|
||||
plugin = 'quantum.plugins.cisco.network_plugin.PluginV2'
|
||||
# Create the default configurations
|
||||
args = ['--config-file', curdir('quantumv2.conf.cisco.test')]
|
||||
config.parse(args=args)
|
||||
# Update the plugin
|
||||
cfg.CONF.set_override('core_plugin', plugin)
|
||||
cfg.CONF.set_override('base_mac', "12:34:56:78:90:ab")
|
||||
self.api = APIRouter()
|
||||
LOG.debug("%s.%s.%s done" % (__name__, self.__class__.__name__,
|
||||
inspect.stack()[0][3]))
|
||||
|
||||
def tearDown(self):
|
||||
db.clear_db(network_models_v2.model_base.BASEV2)
|
||||
db._ENGINE = None
|
||||
db._MAKER = None
|
||||
|
||||
cfg.CONF.reset()
|
||||
|
||||
|
||||
class TestV2HTTPResponse(NetworkPluginV2TestCase,
|
||||
test_db_plugin.TestV2HTTPResponse):
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class TestPortsV2(NetworkPluginV2TestCase, test_db_plugin.TestPortsV2):
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class TestNetworksV2(NetworkPluginV2TestCase, test_db_plugin.TestNetworksV2):
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class TestSubnetsV2(NetworkPluginV2TestCase, test_db_plugin.TestSubnetsV2):
|
||||
|
||||
pass
|
32
quantum/plugins/cisco/tests/unit/v2/ucs/__init__.py
Normal file
32
quantum/plugins/cisco/tests/unit/v2/ucs/__init__.py
Normal file
@ -0,0 +1,32 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2012 OpenStack LLC.
|
||||
# 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 __builtin__
|
||||
import unittest
|
||||
|
||||
|
||||
setattr(__builtin__, '_', lambda x: x)
|
||||
|
||||
|
||||
class BaseTest(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
pass
|
||||
|
||||
|
||||
def setUp():
|
||||
pass
|
@ -0,0 +1,59 @@
|
||||
# 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
|
||||
import os
|
||||
|
||||
from quantum.common.utils import find_config_file
|
||||
from quantum.openstack.common import importutils
|
||||
from quantum.plugins.cisco.common import cisco_configparser as confp
|
||||
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.ucs import (
|
||||
cisco_ucs_inventory_configuration as conf,
|
||||
)
|
||||
from quantum.plugins.cisco.ucs import cisco_ucs_inventory_v2
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def curdir(*p):
|
||||
return os.path.join(os.path.dirname(__file__), *p)
|
||||
|
||||
|
||||
class UCSInventory(cisco_ucs_inventory_v2.UCSInventory):
|
||||
"""
|
||||
Inventory implementation for testing
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
fake_ucs_driver = "quantum.plugins.cisco.tests.unit.v2.ucs." + \
|
||||
"fake_ucs_driver.CiscoUCSMFakeDriver"
|
||||
self._client = importutils.import_object(fake_ucs_driver)
|
||||
conf_parser = confp.CiscoConfigParser(curdir("fake_ucs_inventory.ini"))
|
||||
|
||||
conf.INVENTORY = conf_parser.walk(conf_parser.dummy)
|
||||
for ucsm in conf.INVENTORY.keys():
|
||||
ucsm_ip = conf.INVENTORY[ucsm][const.IP_ADDRESS]
|
||||
try:
|
||||
cred.Store.put_credential(ucsm_ip, "username", "password")
|
||||
except:
|
||||
pass
|
||||
self._load_inventory()
|
96
quantum/plugins/cisco/tests/unit/v2/ucs/fake_ucs_driver.py
Normal file
96
quantum/plugins/cisco/tests/unit/v2/ucs/fake_ucs_driver.py
Normal file
@ -0,0 +1,96 @@
|
||||
# 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 quantum.plugins.cisco.common import cisco_constants as const
|
||||
|
||||
|
||||
class CiscoUCSMFakeDriver():
|
||||
"""UCSM Fake Driver"""
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def _get_blade_interfaces(self, chassis_number, blade_number, ucsm_ip,
|
||||
ucsm_username, ucsm_password):
|
||||
blade_interfaces = {}
|
||||
for element in range(20):
|
||||
dist_name = "dn" + str(element)
|
||||
if dist_name:
|
||||
order = str(element)
|
||||
rhel_name = "eth" + str(element)
|
||||
blade_interface = {
|
||||
const.BLADE_INTF_DN: dist_name,
|
||||
const.BLADE_INTF_ORDER: order,
|
||||
const.BLADE_INTF_LINK_STATE: None,
|
||||
const.BLADE_INTF_OPER_STATE: None,
|
||||
const.BLADE_INTF_INST_TYPE: const.BLADE_INTF_DYNAMIC,
|
||||
const.BLADE_INTF_RHEL_DEVICE_NAME: rhel_name,
|
||||
}
|
||||
blade_interfaces[dist_name] = blade_interface
|
||||
|
||||
return blade_interfaces
|
||||
|
||||
def _get_blade_interface_state(self, blade_intf, ucsm_ip,
|
||||
ucsm_username, ucsm_password):
|
||||
blade_intf[const.BLADE_INTF_LINK_STATE] = \
|
||||
const.BLADE_INTF_STATE_UNKNOWN
|
||||
blade_intf[const.BLADE_INTF_OPER_STATE] = \
|
||||
const.BLADE_INTF_STATE_UNKNOWN
|
||||
blade_intf[const.BLADE_INTF_INST_TYPE] = \
|
||||
const.BLADE_INTF_DYNAMIC
|
||||
|
||||
def create_vlan(self, vlan_name, vlan_id, ucsm_ip, ucsm_username,
|
||||
ucsm_password):
|
||||
pass
|
||||
|
||||
def create_profile(self, profile_name, vlan_name, ucsm_ip, ucsm_username,
|
||||
ucsm_password):
|
||||
pass
|
||||
|
||||
def change_vlan_in_profile(self, profile_name, old_vlan_name,
|
||||
new_vlan_name, ucsm_ip, ucsm_username,
|
||||
ucsm_password):
|
||||
pass
|
||||
|
||||
def get_blade_data(self, chassis_number, blade_number, ucsm_ip,
|
||||
ucsm_username, ucsm_password):
|
||||
"""
|
||||
Returns only the dynamic interfaces on the blade
|
||||
"""
|
||||
blade_interfaces = self._get_blade_interfaces(chassis_number,
|
||||
blade_number,
|
||||
ucsm_ip,
|
||||
ucsm_username,
|
||||
ucsm_password)
|
||||
for blade_intf in blade_interfaces.keys():
|
||||
self._get_blade_interface_state(blade_interfaces[blade_intf],
|
||||
ucsm_ip, ucsm_username,
|
||||
ucsm_password)
|
||||
if ((blade_interfaces[blade_intf][const.BLADE_INTF_INST_TYPE] !=
|
||||
const.BLADE_INTF_DYNAMIC)):
|
||||
blade_interfaces.pop(blade_intf)
|
||||
|
||||
return blade_interfaces
|
||||
|
||||
def delete_vlan(self, vlan_name, ucsm_ip, ucsm_username, ucsm_password):
|
||||
pass
|
||||
|
||||
def delete_profile(self, profile_name, ucsm_ip, ucsm_username,
|
||||
ucsm_password):
|
||||
pass
|
@ -0,0 +1,7 @@
|
||||
[ucsm-1]
|
||||
ip_address = 192.168.100.2
|
||||
[[chassis-1]]
|
||||
chassis_id = 1
|
||||
[[[blade-1]]]
|
||||
blade_id = 1
|
||||
host_name = blade1
|
127
quantum/plugins/cisco/tests/unit/v2/ucs/test_ucs_inventory_v2.py
Normal file
127
quantum/plugins/cisco/tests/unit/v2/ucs/test_ucs_inventory_v2.py
Normal file
@ -0,0 +1,127 @@
|
||||
# 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: Shubhangi Satras, Cisco Systems, Inc.
|
||||
# @author: Tyler Smith, Cisco Systems, Inc.
|
||||
|
||||
import logging
|
||||
import unittest
|
||||
import uuid
|
||||
|
||||
from quantum.common import exceptions as exc
|
||||
from quantum.plugins.cisco.common import cisco_constants as const
|
||||
from quantum.plugins.cisco.common import cisco_credentials_v2 as creds
|
||||
from quantum.plugins.cisco.db import network_db_v2 as cdb
|
||||
from quantum.plugins.cisco.tests.unit.v2.ucs.cisco_ucs_inventory_fake import (
|
||||
UCSInventory,
|
||||
)
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
# Set some data to use in tests
|
||||
tenant = 'shubh'
|
||||
net_name = 'TestNetwork1'
|
||||
port_state = const.PORT_UP
|
||||
interface_id = 'vif-01'
|
||||
|
||||
|
||||
class TestUCSInventory(unittest.TestCase):
|
||||
"""
|
||||
Tests for the UCS Inventory. Each high-level operation should return
|
||||
some information about which devices to perform the action on.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
"""Setup our tests"""
|
||||
cdb.initialize()
|
||||
creds.Store.initialize()
|
||||
|
||||
# Create the ucs inventory object
|
||||
self._ucs_inventory = UCSInventory()
|
||||
self.inventory = self._ucs_inventory._inventory
|
||||
|
||||
def assertValidUCM(self, ip_address):
|
||||
"""Asserts that the given ip is in the UCS inventory"""
|
||||
if ip_address in self.inventory.keys():
|
||||
assert(1)
|
||||
return
|
||||
assert(0)
|
||||
|
||||
def _test_get_all_ucms(self, cmd):
|
||||
"""Runs tests for commands that expect a list of all UCMS"""
|
||||
LOG.debug("test_%s - START", cmd)
|
||||
results = getattr(self._ucs_inventory, cmd)([])
|
||||
self.assertEqual(results[const.DEVICE_IP], self.inventory.keys())
|
||||
LOG.debug("test_%s - END", cmd)
|
||||
|
||||
def _test_with_port_creation(self, cmd, params=None):
|
||||
"""Tests commands that requires a port to exist"""
|
||||
LOG.debug("test_%s - START", cmd)
|
||||
net_uuid = str(uuid.uuid4())
|
||||
device_params = self._ucs_inventory.create_port(tenant, net_uuid,
|
||||
port_state,
|
||||
state=port_state)
|
||||
|
||||
args = [tenant, net_uuid, port[const.PORT_ID]]
|
||||
if params is not None:
|
||||
args.extend(params)
|
||||
|
||||
ip_address = getattr(self._ucs_inventory, cmd)(args)
|
||||
ip_address = ip_address[const.DEVICE_IP][0]
|
||||
self.assertValidUCM(ip_address)
|
||||
cdb.clear_db()
|
||||
|
||||
LOG.debug("test_%s - END", cmd)
|
||||
|
||||
def test_create_port(self):
|
||||
"""Test that the UCS Inventory returns the correct devices to use"""
|
||||
LOG.debug("test_create_port - START")
|
||||
results = self._ucs_inventory.create_port([])
|
||||
results = results[const.LEAST_RSVD_BLADE_DICT]
|
||||
|
||||
ip_address = results[const.LEAST_RSVD_BLADE_UCSM]
|
||||
chassis = results[const.LEAST_RSVD_BLADE_CHASSIS]
|
||||
blade = results[const.LEAST_RSVD_BLADE_ID]
|
||||
|
||||
if blade not in self.inventory[ip_address][chassis]:
|
||||
self.assertEqual(0, 1)
|
||||
self.assertEqual(1, 1)
|
||||
LOG.debug("test_create_port - END")
|
||||
|
||||
def test_get_all_networks(self):
|
||||
"""Test that the UCS Inventory returns the correct devices to use"""
|
||||
self._test_get_all_ucms('get_all_networks')
|
||||
|
||||
def test_create_network(self):
|
||||
"""Test that the UCS Inventory returns the correct devices to use"""
|
||||
self._test_get_all_ucms('create_network')
|
||||
|
||||
def test_delete_network(self):
|
||||
"""Test that the UCS Inventory returns the correct devices to use"""
|
||||
self._test_get_all_ucms('delete_network')
|
||||
|
||||
def test_get_network_details(self):
|
||||
"""Test that the UCS Inventory returns the correct devices to use"""
|
||||
self._test_get_all_ucms('get_network_details')
|
||||
|
||||
def test_update_network(self):
|
||||
"""Test that the UCS Inventory returns the correct devices to use"""
|
||||
self._test_get_all_ucms('update_network')
|
||||
|
||||
def test_get_all_ports(self):
|
||||
"""Test that the UCS Inventory returns the correct devices to use"""
|
||||
self._test_get_all_ucms('get_all_ports')
|
709
quantum/plugins/cisco/ucs/cisco_ucs_inventory_v2.py
Normal file
709
quantum/plugins/cisco/ucs/cisco_ucs_inventory_v2.py
Normal file
@ -0,0 +1,709 @@
|
||||
# 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.
|
||||
|
||||
"""
|
||||
The _inventory data strcuture contains a nested disctioary:
|
||||
{"UCSM_IP: {"Chassis-ID": [Balde-ID, Blade-ID],
|
||||
"Chassis-ID": [Blade-ID, Blade-ID, Blade-ID]]},
|
||||
"UCSM_IP: {"Chassis-ID": [Balde-ID]}
|
||||
}
|
||||
"""
|
||||
"""
|
||||
_inventory_state data structure is organized as below:
|
||||
{ucsm_ip:
|
||||
{chassis_id:
|
||||
{blade_id:
|
||||
{'blade-data':
|
||||
{blade-dn-1: {blade-intf-data},
|
||||
blade-dn-2: {blade-intf-data}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'blade-data': Blade Data dictionary has the following keys:
|
||||
===========================================================
|
||||
const.BLADE_INTF_DATA: This is a dictionary, with the key as the
|
||||
dn of the interface, and the value as the
|
||||
Blade Interface Dictionary described next
|
||||
const.BLADE_UNRESERVED_INTF_COUNT: Number of unreserved interfaces
|
||||
on this blade
|
||||
|
||||
'blade-intf-data': Blade Interface dictionary has the following keys:
|
||||
=====================================================================
|
||||
const.BLADE_INTF_DN
|
||||
const.BLADE_INTF_ORDER
|
||||
const.BLADE_INTF_LINK_STATE
|
||||
const.BLADE_INTF_OPER_STATE
|
||||
const.BLADE_INTF_INST_TYPE
|
||||
const.BLADE_INTF_RHEL_DEVICE_NAME
|
||||
const.BLADE_INTF_RESERVATION
|
||||
const.TENANTID
|
||||
const.PORTID
|
||||
const.PROFILE_ID
|
||||
const.INSTANCE_ID
|
||||
const.VIF_ID
|
||||
"""
|
||||
|
||||
from copy import deepcopy
|
||||
import logging
|
||||
|
||||
from quantum.common import exceptions as exc
|
||||
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.common import cisco_exceptions as cexc
|
||||
from quantum.plugins.cisco.db import ucs_db_v2 as udb
|
||||
from quantum.plugins.cisco.l2device_inventory_base import (
|
||||
L2NetworkDeviceInventoryBase,
|
||||
)
|
||||
from quantum.plugins.cisco.ucs import (
|
||||
cisco_ucs_inventory_configuration as conf,
|
||||
)
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class UCSInventory(L2NetworkDeviceInventoryBase):
|
||||
"""
|
||||
Manages the state of all the UCS chasses, and blades in
|
||||
the system
|
||||
"""
|
||||
|
||||
_inventory = {}
|
||||
_host_names = {}
|
||||
_inventory_state = {}
|
||||
|
||||
def __init__(self):
|
||||
self._client = importutils.import_object(conf.UCSM_DRIVER)
|
||||
self._load_inventory()
|
||||
|
||||
def _load_inventory(self):
|
||||
"""Load the inventory from a config file"""
|
||||
inventory = deepcopy(conf.INVENTORY)
|
||||
LOG.info("Loaded UCS inventory: %s\n" % inventory)
|
||||
LOG.info("Building UCS inventory state (this may take a while)...")
|
||||
|
||||
for ucsm in inventory.keys():
|
||||
ucsm_ip = inventory[ucsm][const.IP_ADDRESS]
|
||||
inventory[ucsm].pop(const.IP_ADDRESS)
|
||||
chassis_dict = {}
|
||||
for chassis in inventory[ucsm].keys():
|
||||
chassis_id = inventory[ucsm][chassis][const.CHASSIS_ID]
|
||||
inventory[ucsm][chassis].pop(const.CHASSIS_ID)
|
||||
blade_list = []
|
||||
for blade in inventory[ucsm][chassis].keys():
|
||||
blade_id = (
|
||||
inventory[ucsm][chassis][blade][const.BLADE_ID])
|
||||
host_name = (
|
||||
inventory[ucsm][chassis][blade][const.HOST_NAME])
|
||||
host_key = ucsm_ip + "-" + chassis_id + "-" + blade_id
|
||||
self._host_names[host_key] = host_name
|
||||
blade_list.append(blade_id)
|
||||
chassis_dict[chassis_id] = blade_list
|
||||
self._inventory[ucsm_ip] = chassis_dict
|
||||
|
||||
self._build_inventory_state()
|
||||
|
||||
def _build_inventory_state(self):
|
||||
"""Populate the state of all the blades"""
|
||||
for ucsm_ip in self._inventory.keys():
|
||||
self._inventory_state[ucsm_ip] = {ucsm_ip: {}}
|
||||
ucsm_username = cred.Store.get_username(ucsm_ip)
|
||||
ucsm_password = cred.Store.get_password(ucsm_ip)
|
||||
chasses_state = {}
|
||||
self._inventory_state[ucsm_ip] = chasses_state
|
||||
ucsm = self._inventory[ucsm_ip]
|
||||
for chassis_id in ucsm.keys():
|
||||
blades_dict = {}
|
||||
chasses_state[chassis_id] = blades_dict
|
||||
for blade_id in ucsm[chassis_id]:
|
||||
blade_data = self._get_initial_blade_state(chassis_id,
|
||||
blade_id,
|
||||
ucsm_ip,
|
||||
ucsm_username,
|
||||
ucsm_password)
|
||||
blades_dict[blade_id] = blade_data
|
||||
|
||||
LOG.debug("UCS Inventory state is: %s\n" % self._inventory_state)
|
||||
return True
|
||||
|
||||
def _get_host_name(self, ucsm_ip, chassis_id, blade_id):
|
||||
"""Get the hostname based on the blade info"""
|
||||
host_key = ucsm_ip + "-" + chassis_id + "-" + blade_id
|
||||
return self._host_names[host_key]
|
||||
|
||||
def _get_initial_blade_state(self, chassis_id, blade_id, ucsm_ip,
|
||||
ucsm_username, ucsm_password):
|
||||
"""Get the initial blade state"""
|
||||
blade_intf_data = self._client.get_blade_data(chassis_id, blade_id,
|
||||
ucsm_ip, ucsm_username,
|
||||
ucsm_password)
|
||||
|
||||
unreserved_counter = 0
|
||||
|
||||
for blade_intf in blade_intf_data.keys():
|
||||
dist_name = blade_intf_data[blade_intf][const.BLADE_INTF_DN]
|
||||
# We first make a pass through the state in UCSM
|
||||
# If a particular interface is showing as being allocated in
|
||||
# UCSM then it is definitely being used and so should be
|
||||
# marked as reserved, else we temporarily mark it as unreserved
|
||||
# based on the UCSM state, but may later change it if a port
|
||||
# association is found in the DB
|
||||
if not const.TENANTID in blade_intf_data[blade_intf].keys():
|
||||
blade_intf_data[blade_intf][const.TENANTID] = None
|
||||
if not const.PORTID in blade_intf_data[blade_intf].keys():
|
||||
blade_intf_data[blade_intf][const.PORTID] = None
|
||||
if not const.PROFILE_ID in blade_intf_data[blade_intf].keys():
|
||||
blade_intf_data[blade_intf][const.PROFILE_ID] = None
|
||||
if not const.INSTANCE_ID in blade_intf_data[blade_intf].keys():
|
||||
blade_intf_data[blade_intf][const.INSTANCE_ID] = None
|
||||
if not const.VIF_ID in blade_intf_data[blade_intf].keys():
|
||||
blade_intf_data[blade_intf][const.VIF_ID] = None
|
||||
|
||||
if (blade_intf_data[blade_intf][const.BLADE_INTF_LINK_STATE] ==
|
||||
const.BLADE_INTF_STATE_UNALLOCATED or
|
||||
blade_intf_data[blade_intf][const.BLADE_INTF_LINK_STATE] ==
|
||||
const.BLADE_INTF_STATE_UNKNOWN) and (
|
||||
blade_intf_data[blade_intf][const.BLADE_INTF_OPER_STATE] ==
|
||||
const.BLADE_INTF_STATE_UNKNOWN):
|
||||
blade_intf_data[blade_intf][const.BLADE_INTF_RESERVATION] = (
|
||||
const.BLADE_INTF_UNRESERVED)
|
||||
unreserved_counter += 1
|
||||
else:
|
||||
blade_intf_data[blade_intf][const.BLADE_INTF_RESERVATION] = (
|
||||
const.BLADE_INTF_RESERVED)
|
||||
|
||||
port_binding = udb.get_portbinding_dn(dist_name)
|
||||
if port_binding:
|
||||
# We have found a port binding for this interface in the DB,
|
||||
# so we have earlier marked this interface as unreserved, we
|
||||
# need to change it, and also load the state from the DB for
|
||||
# other associations
|
||||
intf_data = blade_intf_data[blade_intf]
|
||||
if ((intf_data[const.BLADE_INTF_RESERVATION] == const.
|
||||
BLADE_INTF_UNRESERVED)):
|
||||
unreserved_counter -= 1
|
||||
intf_data[const.BLADE_INTF_RESERVATION] = (
|
||||
const.BLADE_INTF_RESERVED)
|
||||
intf_data[const.TENANTID] = port_binding[const.TENANTID]
|
||||
intf_data[const.PORTID] = port_binding[const.PORTID]
|
||||
intf_data[const.PROFILE_ID] = (
|
||||
port_binding[const.PORTPROFILENAME])
|
||||
intf_data[const.INSTANCE_ID] = port_binding[const.INSTANCE_ID]
|
||||
intf_data[const.VIF_ID] = port_binding[const.VIF_ID]
|
||||
host_name = self._get_host_name(ucsm_ip, chassis_id, blade_id)
|
||||
blade_data = {const.BLADE_INTF_DATA: blade_intf_data,
|
||||
const.BLADE_UNRESERVED_INTF_COUNT: unreserved_counter,
|
||||
const.HOST_NAME: host_name}
|
||||
return blade_data
|
||||
|
||||
def _get_blade_state(self, chassis_id, blade_id, ucsm_ip,
|
||||
ucsm_username, ucsm_password):
|
||||
"""Get the blade state"""
|
||||
blade_intf_data = self._client.get_blade_data(chassis_id, blade_id,
|
||||
ucsm_ip, ucsm_username,
|
||||
ucsm_password)
|
||||
unreserved_counter = 0
|
||||
|
||||
for blade_intf in blade_intf_data.keys():
|
||||
if (blade_intf_data[blade_intf][const.BLADE_INTF_LINK_STATE] ==
|
||||
const.BLADE_INTF_STATE_UNALLOCATED or
|
||||
blade_intf_data[blade_intf][const.BLADE_INTF_LINK_STATE] ==
|
||||
const.BLADE_INTF_STATE_UNKNOWN) and (
|
||||
blade_intf_data[blade_intf][const.BLADE_INTF_OPER_STATE] ==
|
||||
const.BLADE_INTF_STATE_UNKNOWN):
|
||||
blade_intf_data[blade_intf][const.BLADE_INTF_RESERVATION] = (
|
||||
const.BLADE_INTF_UNRESERVED)
|
||||
unreserved_counter += 1
|
||||
else:
|
||||
blade_intf_data[blade_intf][const.BLADE_INTF_RESERVATION] = (
|
||||
const.BLADE_INTF_RESERVED)
|
||||
|
||||
blade_data = {const.BLADE_INTF_DATA: blade_intf_data,
|
||||
const.BLADE_UNRESERVED_INTF_COUNT: unreserved_counter}
|
||||
return blade_data
|
||||
|
||||
def _get_all_ucsms(self):
|
||||
"""Return a list of the IPs of all the UCSMs in the system"""
|
||||
return {const.DEVICE_IP: self._inventory.keys()}
|
||||
|
||||
def _get_blade_for_port(self, args):
|
||||
"""
|
||||
Return the a dict with IP address of the blade
|
||||
on which a dynamic vnic was reserved for this port
|
||||
"""
|
||||
tenant_id = args[0]
|
||||
net_id = args[1]
|
||||
port_id = args[2]
|
||||
rsvd_info = self._get_rsvd_blade_intf_by_port(tenant_id, port_id)
|
||||
if not rsvd_info:
|
||||
raise exc.PortNotFound(net_id=net_id, port_id=port_id)
|
||||
device_params = {const.DEVICE_IP: [rsvd_info[const.UCSM_IP]]}
|
||||
return device_params
|
||||
|
||||
def _get_host_name_for_rsvd_intf(self, tenant_id, instance_id):
|
||||
"""
|
||||
Return the hostname of the blade with a reserved instance
|
||||
for this tenant
|
||||
"""
|
||||
for ucsm_ip in self._inventory_state.keys():
|
||||
ucsm = self._inventory_state[ucsm_ip]
|
||||
for chassis_id in ucsm.keys():
|
||||
for blade_id in ucsm[chassis_id]:
|
||||
blade_data = ucsm[chassis_id][blade_id]
|
||||
blade_intf_data = blade_data[const.BLADE_INTF_DATA]
|
||||
for blade_intf in blade_intf_data.keys():
|
||||
tmp = deepcopy(blade_intf_data[blade_intf])
|
||||
intf_data = blade_intf_data[blade_intf]
|
||||
if (intf_data[const.BLADE_INTF_RESERVATION] ==
|
||||
const.BLADE_INTF_RESERVED and
|
||||
intf_data[const.TENANTID] == tenant_id and
|
||||
intf_data[const.INSTANCE_ID] is None):
|
||||
intf_data[const.INSTANCE_ID] = instance_id
|
||||
host_name = self._get_host_name(ucsm_ip,
|
||||
chassis_id,
|
||||
blade_id)
|
||||
port_binding = udb.get_portbinding_dn(blade_intf)
|
||||
port_id = port_binding[const.PORTID]
|
||||
udb.update_portbinding(port_id,
|
||||
instance_id=instance_id)
|
||||
return host_name
|
||||
LOG.warn("Could not find a reserved dynamic nic for tenant: %s" %
|
||||
tenant_id)
|
||||
return None
|
||||
|
||||
def _get_instance_port(self, tenant_id, instance_id, vif_id):
|
||||
"""
|
||||
Return the device name for a reserved interface
|
||||
"""
|
||||
found_blade_intf_data = None
|
||||
for ucsm_ip in self._inventory_state.keys():
|
||||
ucsm = self._inventory_state[ucsm_ip]
|
||||
for chassis_id in ucsm.keys():
|
||||
for blade_id in ucsm[chassis_id]:
|
||||
blade_data = ucsm[chassis_id][blade_id]
|
||||
blade_intf_data = blade_data[const.BLADE_INTF_DATA]
|
||||
for blade_intf in blade_intf_data.keys():
|
||||
intf_data = blade_intf_data[blade_intf]
|
||||
if (intf_data[const.BLADE_INTF_RESERVATION] ==
|
||||
const.BLADE_INTF_RESERVED and
|
||||
intf_data[const.TENANTID] == tenant_id and
|
||||
intf_data[const.INSTANCE_ID] == instance_id):
|
||||
found_blade_intf_data = blade_intf_data
|
||||
LOG.debug(("Found blade %s associated with this"
|
||||
" instance: %s") % (blade_id,
|
||||
instance_id))
|
||||
break
|
||||
|
||||
if found_blade_intf_data:
|
||||
blade_intf_data = found_blade_intf_data
|
||||
for blade_intf in blade_intf_data.keys():
|
||||
intf_data = blade_intf_data[blade_intf]
|
||||
if (intf_data[const.BLADE_INTF_RESERVATION] ==
|
||||
const.BLADE_INTF_RESERVED and
|
||||
intf_data[const.TENANTID] == tenant_id and
|
||||
(not intf_data[const.VIF_ID])):
|
||||
intf_data[const.VIF_ID] = vif_id
|
||||
intf_data[const.INSTANCE_ID] = instance_id
|
||||
port_binding = udb.get_portbinding_dn(blade_intf)
|
||||
port_id = port_binding[const.PORTID]
|
||||
udb.update_portbinding(port_id, instance_id=instance_id,
|
||||
vif_id=vif_id)
|
||||
device_name = intf_data[const.BLADE_INTF_RHEL_DEVICE_NAME]
|
||||
profile_name = port_binding[const.PORTPROFILENAME]
|
||||
dynamicnic_details = {
|
||||
const.DEVICENAME: device_name,
|
||||
const.UCSPROFILE: profile_name,
|
||||
}
|
||||
LOG.debug(("Found reserved dynamic nic: %s"
|
||||
"associated with port %s") %
|
||||
(intf_data, port_id))
|
||||
LOG.debug("Returning dynamic nic details: %s" %
|
||||
dynamicnic_details)
|
||||
return dynamicnic_details
|
||||
|
||||
LOG.warn("Could not find a reserved dynamic nic for tenant: %s" %
|
||||
tenant_id)
|
||||
return None
|
||||
|
||||
def _disassociate_vifid_from_port(self, tenant_id, instance_id, vif_id):
|
||||
"""
|
||||
Disassociate a VIF-ID from a port, this happens when a
|
||||
VM is destroyed
|
||||
"""
|
||||
for ucsm_ip in self._inventory_state.keys():
|
||||
ucsm = self._inventory_state[ucsm_ip]
|
||||
for chassis_id in ucsm.keys():
|
||||
for blade_id in ucsm[chassis_id]:
|
||||
blade_data = ucsm[chassis_id][blade_id]
|
||||
blade_intf_data = blade_data[const.BLADE_INTF_DATA]
|
||||
for blade_intf in blade_intf_data.keys():
|
||||
intf_data = blade_intf_data[blade_intf]
|
||||
if (intf_data[const.BLADE_INTF_RESERVATION] ==
|
||||
const.BLADE_INTF_RESERVED and
|
||||
intf_data[const.TENANTID] == tenant_id and
|
||||
blade_intf_data[blade_intf][const.INSTANCE_ID]
|
||||
== instance_id and
|
||||
intf_data[const.VIF_ID][:const.UUID_LENGTH] ==
|
||||
vif_id):
|
||||
intf_data[const.VIF_ID] = None
|
||||
intf_data[const.INSTANCE_ID] = None
|
||||
port_binding = udb.get_portbinding_dn(blade_intf)
|
||||
port_id = port_binding[const.PORTID]
|
||||
udb.update_portbinding(port_id, instance_id=None,
|
||||
vif_id=None)
|
||||
LOG.debug(
|
||||
("Disassociated VIF-ID: %s "
|
||||
"from port: %s"
|
||||
"in UCS inventory state for blade: %s") %
|
||||
(vif_id, port_id, intf_data))
|
||||
device_params = {const.DEVICE_IP: [ucsm_ip],
|
||||
const.PORTID: port_id}
|
||||
return device_params
|
||||
LOG.warn(("Disassociating VIF-ID in UCS inventory failed. "
|
||||
"Could not find a reserved dynamic nic for tenant: %s") %
|
||||
tenant_id)
|
||||
return None
|
||||
|
||||
def _get_rsvd_blade_intf_by_port(self, tenant_id, port_id):
|
||||
"""
|
||||
Lookup a reserved blade interface based on tenant_id and port_id
|
||||
and return the blade interface info
|
||||
"""
|
||||
for ucsm_ip in self._inventory_state.keys():
|
||||
ucsm = self._inventory_state[ucsm_ip]
|
||||
for chassis_id in ucsm.keys():
|
||||
for blade_id in ucsm[chassis_id]:
|
||||
blade_data = ucsm[chassis_id][blade_id]
|
||||
blade_intf_data = blade_data[const.BLADE_INTF_DATA]
|
||||
for blade_intf in blade_intf_data.keys():
|
||||
if ((not blade_intf_data[blade_intf][const.PORTID] or
|
||||
not blade_intf_data[blade_intf][const.TENANTID])):
|
||||
continue
|
||||
intf_data = blade_intf_data[blade_intf]
|
||||
if (intf_data[const.BLADE_INTF_RESERVATION] ==
|
||||
const.BLADE_INTF_RESERVED and
|
||||
intf_data[const.TENANTID] == tenant_id and
|
||||
intf_data[const.PORTID] == port_id):
|
||||
interface_dn = intf_data[const.BLADE_INTF_DN]
|
||||
blade_intf_info = {const.UCSM_IP: ucsm_ip,
|
||||
const.CHASSIS_ID: chassis_id,
|
||||
const.BLADE_ID: blade_id,
|
||||
const.BLADE_INTF_DN:
|
||||
interface_dn}
|
||||
return blade_intf_info
|
||||
LOG.warn("Could not find a reserved nic for tenant: %s port: %s" %
|
||||
(tenant_id, port_id))
|
||||
return None
|
||||
|
||||
def _get_least_reserved_blade(self, intf_count=1):
|
||||
"""Return the blade with least number of dynamic nics reserved"""
|
||||
unreserved_interface_count = 0
|
||||
least_reserved_blade_ucsm = None
|
||||
least_reserved_blade_chassis = None
|
||||
least_reserved_blade_id = None
|
||||
least_reserved_blade_data = None
|
||||
|
||||
for ucsm_ip in self._inventory_state.keys():
|
||||
ucsm = self._inventory_state[ucsm_ip]
|
||||
for chassis_id in ucsm.keys():
|
||||
for blade_id in ucsm[chassis_id]:
|
||||
blade_data = ucsm[chassis_id][blade_id]
|
||||
if ((blade_data[const.BLADE_UNRESERVED_INTF_COUNT] >
|
||||
unreserved_interface_count)):
|
||||
unreserved_interface_count = (
|
||||
blade_data[const.BLADE_UNRESERVED_INTF_COUNT])
|
||||
least_reserved_blade_ucsm = ucsm_ip
|
||||
least_reserved_blade_chassis = chassis_id
|
||||
least_reserved_blade_id = blade_id
|
||||
least_reserved_blade_data = blade_data
|
||||
|
||||
if unreserved_interface_count < intf_count:
|
||||
LOG.warn(("Not enough dynamic nics available on a single host."
|
||||
" Requested: %s, Maximum available: %s") %
|
||||
(intf_count, unreserved_interface_count))
|
||||
return False
|
||||
|
||||
least_reserved_blade_dict = {
|
||||
const.LEAST_RSVD_BLADE_UCSM: least_reserved_blade_ucsm,
|
||||
const.LEAST_RSVD_BLADE_CHASSIS: least_reserved_blade_chassis,
|
||||
const.LEAST_RSVD_BLADE_ID: least_reserved_blade_id,
|
||||
const.LEAST_RSVD_BLADE_DATA: least_reserved_blade_data,
|
||||
}
|
||||
LOG.debug("Found dynamic nic %s available for reservation",
|
||||
least_reserved_blade_dict)
|
||||
return least_reserved_blade_dict
|
||||
|
||||
def reload_inventory(self):
|
||||
"""Reload the inventory from a conf file"""
|
||||
self._load_inventory()
|
||||
|
||||
def reserve_blade_interface(self, ucsm_ip, chassis_id, blade_id,
|
||||
blade_data_dict, tenant_id, port_id,
|
||||
portprofile_name):
|
||||
"""Reserve an interface on a blade"""
|
||||
ucsm_username = cred.Store.get_username(ucsm_ip)
|
||||
ucsm_password = cred.Store.get_password(ucsm_ip)
|
||||
"""
|
||||
We are first getting the updated UCSM-specific blade
|
||||
interface state
|
||||
"""
|
||||
blade_data = self._get_blade_state(chassis_id, blade_id, ucsm_ip,
|
||||
ucsm_username, ucsm_password)
|
||||
blade_intf_data = blade_data[const.BLADE_INTF_DATA]
|
||||
chassis_data = self._inventory_state[ucsm_ip][chassis_id]
|
||||
old_blade_intf_data = chassis_data[blade_id][const.BLADE_INTF_DATA]
|
||||
|
||||
"""
|
||||
We will now copy the older non-UCSM-specific blade
|
||||
interface state
|
||||
"""
|
||||
for blade_intf in blade_intf_data.keys():
|
||||
old_intf_data = old_blade_intf_data[blade_intf]
|
||||
blade_intf_data[blade_intf][const.BLADE_INTF_RESERVATION] = (
|
||||
old_intf_data[const.BLADE_INTF_RESERVATION])
|
||||
blade_intf_data[blade_intf][const.TENANTID] = (
|
||||
old_intf_data[const.TENANTID])
|
||||
blade_intf_data[blade_intf][const.PORTID] = (
|
||||
old_intf_data[const.PORTID])
|
||||
blade_intf_data[blade_intf][const.PROFILE_ID] = (
|
||||
old_intf_data[const.PROFILE_ID])
|
||||
blade_intf_data[blade_intf][const.INSTANCE_ID] = (
|
||||
old_intf_data[const.INSTANCE_ID])
|
||||
blade_intf_data[blade_intf][const.VIF_ID] = (
|
||||
old_intf_data[const.VIF_ID])
|
||||
|
||||
blade_data[const.BLADE_UNRESERVED_INTF_COUNT] = (
|
||||
chassis_data[blade_id][const.BLADE_UNRESERVED_INTF_COUNT])
|
||||
"""
|
||||
Now we will reserve an interface if its available
|
||||
"""
|
||||
for blade_intf in blade_intf_data.keys():
|
||||
intf_data = blade_intf_data[blade_intf]
|
||||
if (intf_data[const.BLADE_INTF_RESERVATION] ==
|
||||
const.BLADE_INTF_UNRESERVED):
|
||||
intf_data[const.BLADE_INTF_RESERVATION] = (
|
||||
const.BLADE_INTF_RESERVED)
|
||||
intf_data[const.TENANTID] = tenant_id
|
||||
intf_data[const.PORTID] = port_id
|
||||
intf_data[const.INSTANCE_ID] = None
|
||||
dev_eth_name = intf_data[const.BLADE_INTF_RHEL_DEVICE_NAME]
|
||||
"""
|
||||
We are replacing the older blade interface state with new
|
||||
"""
|
||||
chassis_data[blade_id][const.BLADE_INTF_DATA] = blade_intf_data
|
||||
chassis_data[blade_id][const.BLADE_UNRESERVED_INTF_COUNT] -= 1
|
||||
host_name = self._get_host_name(ucsm_ip, chassis_id, blade_id)
|
||||
reserved_nic_dict = {
|
||||
const.RESERVED_NIC_HOSTNAME: host_name,
|
||||
const.RESERVED_NIC_NAME: dev_eth_name,
|
||||
const.BLADE_INTF_DN: blade_intf,
|
||||
}
|
||||
port_binding = udb.add_portbinding(port_id, blade_intf, None,
|
||||
None, None, None)
|
||||
udb.update_portbinding(port_id,
|
||||
tenant_id=intf_data[const.TENANTID])
|
||||
LOG.debug("Reserved blade interface: %s\n" % reserved_nic_dict)
|
||||
return reserved_nic_dict
|
||||
|
||||
LOG.warn("Dynamic nic %s could not be reserved for port-id: %s" %
|
||||
(blade_data, port_id))
|
||||
return False
|
||||
|
||||
def unreserve_blade_interface(self, ucsm_ip, chassis_id, blade_id,
|
||||
interface_dn):
|
||||
"""Unreserve a previously reserved interface on a blade"""
|
||||
ucsm_username = cred.Store.get_username(ucsm_ip)
|
||||
ucsm_password = cred.Store.get_password(ucsm_ip)
|
||||
blade_data = self._inventory_state[ucsm_ip][chassis_id][blade_id]
|
||||
|
||||
blade_data[const.BLADE_UNRESERVED_INTF_COUNT] += 1
|
||||
blade_intf = blade_data[const.BLADE_INTF_DATA][interface_dn]
|
||||
blade_intf[const.BLADE_INTF_RESERVATION] = const.BLADE_INTF_UNRESERVED
|
||||
blade_intf[const.TENANTID] = None
|
||||
blade_intf[const.PORTID] = None
|
||||
blade_intf[const.PROFILE_ID] = None
|
||||
blade_intf[const.INSTANCE_ID] = None
|
||||
blade_intf[const.VIF_ID] = None
|
||||
LOG.debug("Unreserved blade interface %s\n" % interface_dn)
|
||||
|
||||
def add_blade(self, ucsm_ip, chassis_id, blade_id):
|
||||
"""Add a blade to the inventory"""
|
||||
# TODO (Sumit)
|
||||
pass
|
||||
|
||||
def get_all_networks(self, args):
|
||||
"""Return all UCSM IPs"""
|
||||
LOG.debug("get_all_networks() called\n")
|
||||
return self._get_all_ucsms()
|
||||
|
||||
def create_network(self, args):
|
||||
"""Return all UCSM IPs"""
|
||||
LOG.debug("create_network() called\n")
|
||||
return self._get_all_ucsms()
|
||||
|
||||
def delete_network(self, args):
|
||||
"""Return all UCSM IPs"""
|
||||
LOG.debug("delete_network() called\n")
|
||||
return self._get_all_ucsms()
|
||||
|
||||
def get_network_details(self, args):
|
||||
"""Return all UCSM IPs"""
|
||||
LOG.debug("get_network_details() called\n")
|
||||
return self._get_all_ucsms()
|
||||
|
||||
def update_network(self, args):
|
||||
"""Return all UCSM IPs"""
|
||||
LOG.debug("update_network() called\n")
|
||||
return self._get_all_ucsms()
|
||||
|
||||
def get_all_ports(self, args):
|
||||
"""Return all UCSM IPs"""
|
||||
LOG.debug("get_all_ports() called\n")
|
||||
return self._get_all_ucsms()
|
||||
|
||||
def create_port(self, args):
|
||||
"""
|
||||
Return the a dict with information of the blade
|
||||
on which a dynamic vnic is available
|
||||
"""
|
||||
LOG.debug("create_port() called\n")
|
||||
least_reserved_blade_dict = self._get_least_reserved_blade()
|
||||
if not least_reserved_blade_dict:
|
||||
raise cexc.NoMoreNics()
|
||||
ucsm_ip = least_reserved_blade_dict[const.LEAST_RSVD_BLADE_UCSM]
|
||||
device_params = {
|
||||
const.DEVICE_IP: [ucsm_ip],
|
||||
const.UCS_INVENTORY: self,
|
||||
const.LEAST_RSVD_BLADE_DICT: least_reserved_blade_dict,
|
||||
}
|
||||
return device_params
|
||||
|
||||
def delete_port(self, args):
|
||||
"""
|
||||
Return the a dict with information of the blade
|
||||
on which a dynamic vnic was reserved for this port
|
||||
"""
|
||||
LOG.debug("delete_port() called\n")
|
||||
tenant_id = args[0]
|
||||
net_id = args[1]
|
||||
port_id = args[2]
|
||||
rsvd_info = self._get_rsvd_blade_intf_by_port(tenant_id, port_id)
|
||||
if not rsvd_info:
|
||||
LOG.warn("UCSInventory: Port not found: net_id: %s, port_id: %s" %
|
||||
(net_id, port_id))
|
||||
return {const.DEVICE_IP: []}
|
||||
device_params = {
|
||||
const.DEVICE_IP: [rsvd_info[const.UCSM_IP]],
|
||||
const.UCS_INVENTORY: self,
|
||||
const.CHASSIS_ID: rsvd_info[const.CHASSIS_ID],
|
||||
const.BLADE_ID: rsvd_info[const.BLADE_ID],
|
||||
const.BLADE_INTF_DN: rsvd_info[const.BLADE_INTF_DN],
|
||||
}
|
||||
return device_params
|
||||
|
||||
def update_port(self, args):
|
||||
"""
|
||||
Return the a dict with IP address of the blade
|
||||
on which a dynamic vnic was reserved for this port
|
||||
"""
|
||||
LOG.debug("update_port() called\n")
|
||||
return self._get_blade_for_port(args)
|
||||
|
||||
def get_port_details(self, args):
|
||||
"""
|
||||
Return the a dict with IP address of the blade
|
||||
on which a dynamic vnic was reserved for this port
|
||||
"""
|
||||
LOG.debug("get_port_details() called\n")
|
||||
return self._get_blade_for_port(args)
|
||||
|
||||
def plug_interface(self, args):
|
||||
"""
|
||||
Return the a dict with IP address of the blade
|
||||
on which a dynamic vnic was reserved for this port
|
||||
"""
|
||||
LOG.debug("plug_interface() called\n")
|
||||
return self._get_blade_for_port(args)
|
||||
|
||||
def unplug_interface(self, args):
|
||||
"""
|
||||
Return the a dict with IP address of the blade
|
||||
on which a dynamic vnic was reserved for this port
|
||||
"""
|
||||
LOG.debug("unplug_interface() called\n")
|
||||
return self._get_blade_for_port(args)
|
||||
|
||||
def schedule_host(self, args):
|
||||
"""Provides the hostname on which a dynamic vnic is reserved"""
|
||||
LOG.debug("schedule_host() called\n")
|
||||
instance_id = args[1]
|
||||
tenant_id = args[2][const.PROJECT_ID]
|
||||
host_name = self._get_host_name_for_rsvd_intf(tenant_id, instance_id)
|
||||
host_list = {const.HOST_LIST: {const.HOST_1: host_name}}
|
||||
LOG.debug("host_list is: %s" % host_list)
|
||||
return host_list
|
||||
|
||||
def associate_port(self, args):
|
||||
"""
|
||||
Get the portprofile name and the device name for the dynamic vnic
|
||||
"""
|
||||
LOG.debug("associate_port() called\n")
|
||||
instance_id = args[1]
|
||||
tenant_id = args[2][const.PROJECT_ID]
|
||||
vif_id = args[2][const.VIF_ID]
|
||||
vif_info = self._get_instance_port(tenant_id, instance_id, vif_id)
|
||||
vif_desc = {const.VIF_DESC: vif_info}
|
||||
|
||||
LOG.debug("vif_desc is: %s" % vif_desc)
|
||||
return vif_desc
|
||||
|
||||
def detach_port(self, args):
|
||||
"""
|
||||
Remove the VIF-ID and instance name association
|
||||
with the port
|
||||
"""
|
||||
LOG.debug("detach_port() called\n")
|
||||
instance_id = args[1]
|
||||
tenant_id = args[2][const.PROJECT_ID]
|
||||
vif_id = args[2][const.VIF_ID]
|
||||
device_params = self._disassociate_vifid_from_port(tenant_id,
|
||||
instance_id,
|
||||
vif_id)
|
||||
return device_params
|
||||
|
||||
def create_multiport(self, args):
|
||||
"""
|
||||
Create multiple ports for a VM
|
||||
"""
|
||||
LOG.debug("create_ports() called\n")
|
||||
tenant_id = args[0]
|
||||
ports_num = args[2]
|
||||
least_reserved_blade_dict = self._get_least_reserved_blade(ports_num)
|
||||
if not least_reserved_blade_dict:
|
||||
raise cexc.NoMoreNics()
|
||||
ucsm_ip = least_reserved_blade_dict[const.LEAST_RSVD_BLADE_UCSM]
|
||||
device_params = {
|
||||
const.DEVICE_IP: [ucsm_ip],
|
||||
const.UCS_INVENTORY: self,
|
||||
const.LEAST_RSVD_BLADE_DICT:
|
||||
least_reserved_blade_dict,
|
||||
}
|
||||
return device_params
|
337
quantum/plugins/cisco/ucs/cisco_ucs_plugin_v2.py
Normal file
337
quantum/plugins/cisco/ucs/cisco_ucs_plugin_v2.py
Normal file
@ -0,0 +1,337 @@
|
||||
# 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)
|
Loading…
Reference in New Issue
Block a user