Merge trunk
This commit is contained in:
commit
c67ae6e12f
|
@ -30,8 +30,7 @@ EXCEPTIONS = {
|
|||
430: exceptions.PortNotFound,
|
||||
431: exceptions.StateInvalid,
|
||||
432: exceptions.PortInUse,
|
||||
440: exceptions.AlreadyAttached
|
||||
}
|
||||
440: exceptions.AlreadyAttached}
|
||||
|
||||
|
||||
class ApiCall(object):
|
||||
|
@ -61,8 +60,6 @@ class Client(object):
|
|||
|
||||
"""A base client class - derived from Glance.BaseClient"""
|
||||
|
||||
action_prefix = '/v0.1/tenants/{tenant_id}'
|
||||
|
||||
# Action query strings
|
||||
networks_path = "/networks"
|
||||
network_path = "/networks/%s"
|
||||
|
@ -72,7 +69,7 @@ class Client(object):
|
|||
|
||||
def __init__(self, host="127.0.0.1", port=9696, use_ssl=False, tenant=None,
|
||||
format="xml", testingStub=None, key_file=None, cert_file=None,
|
||||
logger=None):
|
||||
logger=None, action_prefix="/v1.0/tenants/{tenant_id}"):
|
||||
"""
|
||||
Creates a new client to some service.
|
||||
|
||||
|
@ -95,6 +92,7 @@ class Client(object):
|
|||
self.key_file = key_file
|
||||
self.cert_file = cert_file
|
||||
self.logger = logger
|
||||
self.action_prefix = action_prefix
|
||||
|
||||
def get_connection_type(self):
|
||||
"""
|
||||
|
@ -128,7 +126,7 @@ class Client(object):
|
|||
|
||||
# Add format and tenant_id
|
||||
action += ".%s" % self.format
|
||||
action = Client.action_prefix + action
|
||||
action = self.action_prefix + action
|
||||
action = action.replace('{tenant_id}', self.tenant)
|
||||
|
||||
if type(params) is dict:
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
=====================================================================
|
||||
README: A Framework for a Quantum Plugin Supporting Multiple Switches
|
||||
=====================================================================
|
||||
=========================================================================================
|
||||
README: A Quantum Plugin Framework for Supporting L2 Networks Spannning Multiple Switches
|
||||
=========================================================================================
|
||||
|
||||
:Author: Sumit Naiksatam, Ram Durairaj, Mark Voelker, Edgar Magana, Shweta Padubidri, Rohit Agarwalla, Ying Liu
|
||||
:Author: Sumit Naiksatam, Ram Durairaj, Mark Voelker, Edgar Magana, Shweta Padubidri, Rohit Agarwalla, Ying Liu, Debo Dutta
|
||||
:Contact: netstack@lists.launchpad.net
|
||||
:Web site: https://launchpad.net/~cisco-openstack
|
||||
:Copyright: 2011 Cisco Systems, Inc.
|
||||
|
@ -15,9 +15,11 @@ Introduction
|
|||
This plugin implementation provides the following capabilities
|
||||
to help you take your Layer 2 network for a Quantum leap:
|
||||
|
||||
* A reference implementation a framework for a Quantum Plugin
|
||||
to use multiple devices/switches in a L2 network
|
||||
* 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 Cisco UCS blade servers with M81KR Virtual Interface Cards
|
||||
(aka "Palo adapters") via 802.1Qbh.
|
||||
* Supports the Cisco Nexus family of switches.
|
||||
|
@ -119,6 +121,8 @@ nexus_ip_address=10.0.0.1
|
|||
# Port number on the Nexus switch to which the UCSM 6120 is connected
|
||||
# Use shortened interface syntax, e.g. "3/23" not "Ethernet3/23".
|
||||
nexus_port=3/23
|
||||
#Port number where the SSH will be running at Nexus Switch, e.g.: 22 (Default)
|
||||
nexus_ssh_port=22
|
||||
|
||||
[DRIVER]
|
||||
name=quantum.plugins.cisco.nexus.cisco_nexus_network_driver.CiscoNEXUSDriver
|
||||
|
@ -130,8 +134,23 @@ name=quantum.plugins.cisco.nexus.cisco_nexus_network_driver.CiscoNEXUSDriver
|
|||
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. Plugin Persistence framework setup:
|
||||
5a. Create quantum_l2network database in mysql with the following command -
|
||||
|
||||
mysql -u<mysqlusername> -p<mysqlpassword> -e "create database quantum_l2network"
|
||||
|
||||
5. Verify that you have the correct credentials for each IP address listed
|
||||
5b. Enter the quantum_l2network database configuration info in the
|
||||
quantum/plugins/cisco/conf/db_conn.ini file.
|
||||
|
||||
5c. If there is a change in the plugin configuration, service would need
|
||||
to be restarted after dropping and re-creating the database using
|
||||
the following commands -
|
||||
|
||||
mysql -u<mysqlusername> -p<mysqlpassword> -e "drop database quantum_l2network"
|
||||
mysql -u<mysqlusername> -p<mysqlpassword> -e "create database quantum_l2network"
|
||||
|
||||
6. Verify that you have the correct credentials for each IP address listed
|
||||
in quantum/plugins/cisco/conf/credentials.ini. Example:
|
||||
|
||||
# Provide the UCSM credentials
|
||||
|
@ -152,7 +171,7 @@ password=mySecretPasswordForNova
|
|||
username=admin
|
||||
password=mySecretPasswordForNexus
|
||||
|
||||
6. Start the Quantum service. If something doesn't work, verify that
|
||||
7. Start the Quantum service. If something doesn't work, verify that
|
||||
your configuration of each of the above files hasn't gone a little kaka.
|
||||
Once you've put right what once went wrong, leap on.
|
||||
|
||||
|
@ -160,7 +179,8 @@ password=mySecretPasswordForNexus
|
|||
How to test the installation
|
||||
----------------------------
|
||||
The unit tests are located at quantum/plugins/cisco/tests/unit. They can be
|
||||
executed from quantum/plugins/cisco/ using the run_tests.py script.
|
||||
executed from the main folder using the run_tests.sh or to get a more detailed
|
||||
result the quantum/plugins/cisco/run_tests.py script.
|
||||
|
||||
1. Testing the core API (without UCS/Nexus/RHEL hardware, and can be run on
|
||||
Ubuntu):
|
||||
|
@ -168,18 +188,41 @@ executed from quantum/plugins/cisco/ using the run_tests.py script.
|
|||
quantum/plugins/cisco/conf/plugins.ini
|
||||
Then run the test script:
|
||||
|
||||
python run_tests.py unit.test_l2networkApi
|
||||
Set the environment variable PLUGIN_DIR to the location of the plugin
|
||||
directory. This is manadatory if the run_tests.sh script is used.
|
||||
|
||||
export PLUGIN_DIR=quantum/plugins/cisco
|
||||
./run_tests.sh quantum.plugins.cisco.tests.unit.test_l2networkApi
|
||||
|
||||
or
|
||||
|
||||
python quantum/plugins/cisco/run_tests.py
|
||||
quantum.plugins.cisco.tests.unit.test_l2networkApi
|
||||
|
||||
2. Specific Plugin unit test (needs environment setup as indicated in the
|
||||
pre-requisites):
|
||||
python run_tests.py unit.<name_of_the file>
|
||||
|
||||
export PLUGIN_DIR=quantum/plugins/cisco
|
||||
./run_tests.sh quantum.plugins.cisco.tests.unit.<name_of_the file>
|
||||
|
||||
or
|
||||
|
||||
python <path to the plugin directory>/run_tests.py
|
||||
quantum.plugins.cisco.tests.unit.<name_of_the file>
|
||||
E.g.:
|
||||
|
||||
python run_tests.py unit.test_ucs_plugin.py
|
||||
python quantum/plugins/cisco/run_tests.py
|
||||
quantum.plugins.cisco.tests.unit.test_ucs_plugin.py
|
||||
|
||||
3. All unit tests (needs environment setup as indicated in the pre-requisites):
|
||||
|
||||
python run_tests.py unit
|
||||
export PLUGIN_DIR=quantum/plugins/cisco
|
||||
./run_tests.sh quantum.plugins.cisco.tests.unit
|
||||
|
||||
or
|
||||
|
||||
python quantum/plugins/cisco/run_tests.py quantum.plugins.cisco.tests.unit
|
||||
|
||||
|
||||
|
||||
Additional installation required on Nova Compute
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
"""
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2011 Cisco Systems, Inc. All rights reserved.
|
||||
|
@ -16,3 +17,4 @@
|
|||
#
|
||||
# @author: Sumit Naiksatam, Cisco Systems, Inc.
|
||||
#
|
||||
"""
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
"""
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2011 Cisco Systems, Inc. All rights reserved.
|
||||
|
@ -16,3 +17,4 @@
|
|||
#
|
||||
# @author: Sumit Naiksatam, Cisco Systems, Inc.
|
||||
#
|
||||
"""
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
"""
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2011 Cisco Systems, Inc. All rights reserved.
|
||||
|
@ -16,25 +17,23 @@
|
|||
#
|
||||
# @author: Sumit Naiksatam, Cisco Systems, Inc.
|
||||
#
|
||||
"""
|
||||
|
||||
import logging as LOG
|
||||
import os
|
||||
|
||||
from configobj import ConfigObj
|
||||
from validate import Validator
|
||||
|
||||
from quantum.plugins.cisco.common import cisco_constants as const
|
||||
from quantum.plugins.cisco.common import cisco_exceptions as cexc
|
||||
|
||||
LOG.basicConfig(level=LOG.WARN)
|
||||
LOG.getLogger(const.LOGGER_COMPONENT_NAME)
|
||||
|
||||
|
||||
class CiscoConfigParser(ConfigObj):
|
||||
"""Config Parser based on the ConfigObj module"""
|
||||
|
||||
def __init__(self, filename):
|
||||
super(CiscoConfigParser, self).__init__(filename, raise_errors=True,
|
||||
file_error=True)
|
||||
|
||||
def dummy(self, section, key):
|
||||
"""Dummy function to return the same key, used in walk"""
|
||||
return section[key]
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
"""
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2011 Cisco Systems, Inc. All rights reserved.
|
||||
|
@ -16,13 +17,29 @@
|
|||
#
|
||||
# @author: Sumit Naiksatam, Cisco Systems, Inc.
|
||||
#
|
||||
"""
|
||||
|
||||
PLUGINS = 'PLUGINS'
|
||||
|
||||
PORT_STATE = 'port-state'
|
||||
PORT_UP = "UP"
|
||||
PORT_UP = "ACTIVE"
|
||||
PORT_DOWN = "DOWN"
|
||||
|
||||
UUID = 'uuid'
|
||||
TENANTID = 'tenant_id'
|
||||
NETWORKID = 'network_id'
|
||||
NETWORKNAME = 'name'
|
||||
NETWORKPORTS = 'ports'
|
||||
INTERFACEID = 'interface_id'
|
||||
PORTSTATE = 'state'
|
||||
PORTID = 'port_id'
|
||||
PPNAME = 'name'
|
||||
PPVLANID = 'vlan_id'
|
||||
PPQOS = 'qos'
|
||||
PPID = 'portprofile_id'
|
||||
PPDEFAULT = 'default'
|
||||
VLANID = 'vlan_id'
|
||||
|
||||
ATTACHMENT = 'attachment'
|
||||
PORT_ID = 'port-id'
|
||||
|
||||
|
@ -101,3 +118,5 @@ PLUGIN_OBJ_REF = 'plugin-obj-ref'
|
|||
PARAM_LIST = 'param-list'
|
||||
|
||||
DEVICE_IP = 'device-ip'
|
||||
|
||||
NO_VLAN_ID = 0
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
"""
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2011 Cisco Systems, Inc. All rights reserved.
|
||||
|
@ -16,6 +17,7 @@
|
|||
#
|
||||
# @author: Sumit Naiksatam, Cisco Systems, Inc.
|
||||
#
|
||||
"""
|
||||
|
||||
import logging as LOG
|
||||
import os
|
||||
|
@ -34,27 +36,35 @@ _creds_dictionary = cp.walk(cp.dummy)
|
|||
|
||||
|
||||
class Store(object):
|
||||
"""Credential Store"""
|
||||
|
||||
@staticmethod
|
||||
def putCredential(id, username, password):
|
||||
"""Set the username and password"""
|
||||
_creds_dictionary[id] = {const.USERNAME: username,
|
||||
const.PASSWORD: password}
|
||||
const.PASSWORD: password}
|
||||
|
||||
@staticmethod
|
||||
def getUsername(id):
|
||||
"""Get the username"""
|
||||
return _creds_dictionary[id][const.USERNAME]
|
||||
|
||||
@staticmethod
|
||||
def getPassword(id):
|
||||
"""Get the password"""
|
||||
return _creds_dictionary[id][const.PASSWORD]
|
||||
|
||||
@staticmethod
|
||||
def getCredential(id):
|
||||
"""Get the username and password"""
|
||||
return _creds_dictionary[id]
|
||||
|
||||
@staticmethod
|
||||
def getCredentials():
|
||||
"""Get all usernames and passwords"""
|
||||
return _creds_dictionary
|
||||
|
||||
@staticmethod
|
||||
def deleteCredential(id):
|
||||
"""Delete a credential"""
|
||||
return _creds_dictionary.pop(id)
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
"""
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2011 Cisco Systems, Inc. All rights reserved.
|
||||
|
@ -15,43 +16,89 @@
|
|||
# under the License.
|
||||
#
|
||||
# @author: Sumit Naiksatam, Cisco Systems, Inc.
|
||||
#
|
||||
|
||||
# @author: Rohit Agarwalla, Cisco Systems, Inc.
|
||||
"""
|
||||
"""
|
||||
Exceptions used by the Cisco plugin
|
||||
"""
|
||||
|
||||
from quantum.common import exceptions
|
||||
|
||||
|
||||
class NoMoreNics(exceptions.QuantumException):
|
||||
message = _("Unable to complete operation on port %(port_id)s " \
|
||||
"for network %(net_id)s. No more dynamic nics are available" \
|
||||
"in the system.")
|
||||
"""No more dynamic nics are available in the system"""
|
||||
message = _("Unable to complete operation. No more dynamic nics are " \
|
||||
"available in the system.")
|
||||
|
||||
|
||||
class PortProfileLimit(exceptions.QuantumException):
|
||||
"""Port profile limit has been hit"""
|
||||
message = _("Unable to complete operation on port %(port_id)s " \
|
||||
"for network %(net_id)s. The system has reached the maximum" \
|
||||
"limit of allowed port profiles.")
|
||||
|
||||
|
||||
class UCSMPortProfileLimit(exceptions.QuantumException):
|
||||
"""UCSM Port profile limit has been hit"""
|
||||
message = _("Unable to complete operation on port %(port_id)s " \
|
||||
"for network %(net_id)s. The system has reached the maximum" \
|
||||
"limit of allowed UCSM port profiles.")
|
||||
|
||||
|
||||
class NetworksLimit(exceptions.QuantumException):
|
||||
"""Total number of network objects limit has been hit"""
|
||||
message = _("Unable to create new network. Number of networks" \
|
||||
"for the system has exceeded the limit")
|
||||
|
||||
|
||||
class PortProfileNotFound(exceptions.QuantumException):
|
||||
"""Port profile cannot be found"""
|
||||
message = _("Port profile %(portprofile_id)s could not be found " \
|
||||
"for tenant %(tenant_id)s")
|
||||
|
||||
|
||||
class PortProfileInvalidDelete(exceptions.QuantumException):
|
||||
"""Port profile cannot be deleted since its being used"""
|
||||
message = _("Port profile %(profile_id)s could not be deleted " \
|
||||
"for tenant %(tenant_id)s since port associations exist")
|
||||
|
||||
|
||||
class NetworkVlanBindingAlreadyExists(exceptions.QuantumException):
|
||||
"""Binding cannot be created, since it already exists"""
|
||||
message = _("NetworkVlanBinding for %(vlan_id)s and network " \
|
||||
"%(network_id)s already exists")
|
||||
|
||||
|
||||
class PortProfileAlreadyExists(exceptions.QuantumException):
|
||||
"""Port profile cannot be created since it already exisits"""
|
||||
message = _("PortProfile %(pp_name) for %(tenant_id)s " \
|
||||
"already exists")
|
||||
|
||||
|
||||
class PortProfileBindingAlreadyExists(exceptions.QuantumException):
|
||||
"""Binding cannot be created, since it already exists"""
|
||||
message = _("PortProfileBinding for port profile %(pp_id)s to " \
|
||||
"port %(port_id) already exists")
|
||||
|
||||
|
||||
class VlanIDNotFound(exceptions.QuantumException):
|
||||
"""VLAN ID cannot be found"""
|
||||
message = _("Vlan ID %(vlan_id)s not found")
|
||||
|
||||
|
||||
class VlanIDNotAvailable(exceptions.QuantumException):
|
||||
"""VLAN ID is reserved"""
|
||||
message = _("No available Vlan ID found")
|
||||
|
||||
try:
|
||||
_("test")
|
||||
except NameError:
|
||||
|
||||
def _(a_string):
|
||||
"""
|
||||
Default implementation of the gettext string
|
||||
translation function: no translation
|
||||
"""
|
||||
return a_string
|
||||
except TypeError:
|
||||
# during doctesting, _ might mean something else
|
||||
pass
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
"""
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2011 Cisco Systems, Inc. All rights reserved.
|
||||
|
@ -16,6 +17,7 @@
|
|||
#
|
||||
# @author: Sumit Naiksatam, Cisco Systems, Inc.
|
||||
#
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
|
@ -23,13 +25,13 @@ from quantum.plugins.cisco.common import cisco_configparser as confp
|
|||
|
||||
CONF_FILE = "../conf/nova.ini"
|
||||
|
||||
cp = confp.CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) \
|
||||
CP = confp.CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) \
|
||||
+ "/" + CONF_FILE)
|
||||
|
||||
section = cp['NOVA']
|
||||
DB_SERVER_IP = section['db_server_ip']
|
||||
DB_NAME = section['db_name']
|
||||
DB_USERNAME = section['db_username']
|
||||
DB_PASSWORD = section['db_password']
|
||||
NOVA_HOST_NAME = section['nova_host_name']
|
||||
NOVA_PROJ_NAME = section['nova_proj_name']
|
||||
SECTION = CP['NOVA']
|
||||
DB_SERVER_IP = SECTION['db_server_ip']
|
||||
DB_NAME = SECTION['db_name']
|
||||
DB_USERNAME = SECTION['db_username']
|
||||
DB_PASSWORD = SECTION['db_password']
|
||||
NOVA_HOST_NAME = SECTION['nova_host_name']
|
||||
NOVA_PROJ_NAME = SECTION['nova_proj_name']
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
"""
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2011 Cisco Systems, Inc. All rights reserved.
|
||||
|
@ -16,27 +17,36 @@
|
|||
#
|
||||
# @author: Sumit Naiksatam, Cisco Systems, Inc.
|
||||
#
|
||||
"""
|
||||
|
||||
import MySQLdb
|
||||
import hashlib
|
||||
import logging as LOG
|
||||
import sys
|
||||
import MySQLdb
|
||||
import traceback
|
||||
|
||||
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 as cred
|
||||
from quantum.plugins.cisco.common import cisco_nova_configuration as conf
|
||||
|
||||
LOG.basicConfig(level=LOG.WARN)
|
||||
LOG.getLogger(const.LOGGER_COMPONENT_NAME)
|
||||
|
||||
|
||||
def get16ByteUUID(uuid):
|
||||
"""
|
||||
Return a 16 byte has of the UUID, used when smaller unique
|
||||
ID is required.
|
||||
"""
|
||||
return hashlib.md5(uuid).hexdigest()[:16]
|
||||
|
||||
|
||||
class DBUtils(object):
|
||||
"""Utilities to use connect to MySQL DB and execute queries"""
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def _get_db_connection(self):
|
||||
"""Get a connection to the DB"""
|
||||
db_ip = conf.DB_SERVER_IP
|
||||
db_username = conf.DB_USERNAME
|
||||
db_password = conf.DB_PASSWORD
|
||||
|
@ -45,6 +55,7 @@ class DBUtils(object):
|
|||
return self.db
|
||||
|
||||
def execute_db_query(self, sql_query):
|
||||
"""Execute a DB query"""
|
||||
db = self._get_db_connection()
|
||||
cursor = db.cursor()
|
||||
try:
|
||||
|
@ -52,6 +63,7 @@ class DBUtils(object):
|
|||
results = cursor.fetchall()
|
||||
db.commit()
|
||||
LOG.debug("DB query execution succeeded: %s" % sql_query)
|
||||
db.close()
|
||||
except:
|
||||
db.rollback()
|
||||
LOG.debug("DB query execution failed: %s" % sql_query)
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
[DATABASE]
|
||||
name = quantum_l2network
|
||||
user = <put_db_user_name_here>
|
||||
pass = <put_db_password_here>
|
||||
host = <put_quantum_mysql_host_here>
|
|
@ -3,6 +3,8 @@
|
|||
nexus_ip_address=<put_nexus_switch_ip_address_here>
|
||||
#Port number of the Interface connected from the Nexus 7K Switch to UCSM 6120, e.g.: 3/23
|
||||
nexus_port=<put_interface_name_here>
|
||||
#Port number where the SSH will be running at the Nexus Switch, e.g.: 22 (Default)
|
||||
nexus_ssh_port=22
|
||||
|
||||
[DRIVER]
|
||||
name=quantum.plugins.cisco.nexus.cisco_nexus_network_driver.CiscoNEXUSDriver
|
||||
|
|
|
@ -0,0 +1,254 @@
|
|||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
# Copyright 2011 Nicira Networks, 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: Somik Behera, Nicira Networks, Inc.
|
||||
# @author: Brad Hall, Nicira Networks, Inc.
|
||||
# @author: Dan Wendlandt, Nicira Networks, Inc.
|
||||
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import sessionmaker, exc, joinedload
|
||||
|
||||
from quantum.common import exceptions as q_exc
|
||||
from quantum.plugins.cisco.db import models
|
||||
|
||||
_ENGINE = None
|
||||
_MAKER = None
|
||||
BASE = models.BASE
|
||||
|
||||
|
||||
def configure_db(options):
|
||||
"""
|
||||
Establish the database, create an engine if needed, and
|
||||
register the models.
|
||||
|
||||
:param options: Mapping of configuration options
|
||||
"""
|
||||
global _ENGINE
|
||||
if not _ENGINE:
|
||||
_ENGINE = create_engine(options['sql_connection'],
|
||||
echo=False,
|
||||
echo_pool=True,
|
||||
pool_recycle=3600)
|
||||
register_models()
|
||||
|
||||
|
||||
def clear_db():
|
||||
global _ENGINE
|
||||
assert _ENGINE
|
||||
for table in reversed(BASE.metadata.sorted_tables):
|
||||
_ENGINE.execute(table.delete())
|
||||
|
||||
|
||||
def get_session(autocommit=True, expire_on_commit=False):
|
||||
"""Helper method to grab session"""
|
||||
global _MAKER, _ENGINE
|
||||
if not _MAKER:
|
||||
assert _ENGINE
|
||||
_MAKER = sessionmaker(bind=_ENGINE,
|
||||
autocommit=autocommit,
|
||||
expire_on_commit=expire_on_commit)
|
||||
return _MAKER()
|
||||
|
||||
|
||||
def register_models():
|
||||
"""Register Models and create properties"""
|
||||
global _ENGINE
|
||||
assert _ENGINE
|
||||
BASE.metadata.create_all(_ENGINE)
|
||||
|
||||
|
||||
def unregister_models():
|
||||
"""Unregister Models, useful clearing out data before testing"""
|
||||
global _ENGINE
|
||||
assert _ENGINE
|
||||
BASE.metadata.drop_all(_ENGINE)
|
||||
|
||||
|
||||
def _check_duplicate_net_name(tenant_id, net_name):
|
||||
session = get_session()
|
||||
try:
|
||||
net = session.query(models.Network).\
|
||||
filter_by(tenant_id=tenant_id, name=net_name).\
|
||||
one()
|
||||
raise q_exc.NetworkNameExists(tenant_id=tenant_id,
|
||||
net_name=net_name, net_id=net.uuid)
|
||||
except exc.NoResultFound:
|
||||
# this is the "normal" path, as API spec specifies
|
||||
# that net-names are unique within a tenant
|
||||
pass
|
||||
|
||||
|
||||
def network_create(tenant_id, name):
|
||||
session = get_session()
|
||||
|
||||
_check_duplicate_net_name(tenant_id, name)
|
||||
with session.begin():
|
||||
net = models.Network(tenant_id, name)
|
||||
session.add(net)
|
||||
session.flush()
|
||||
return net
|
||||
|
||||
|
||||
def network_list(tenant_id):
|
||||
session = get_session()
|
||||
return session.query(models.Network).\
|
||||
options(joinedload(models.Network.ports)). \
|
||||
filter_by(tenant_id=tenant_id).\
|
||||
all()
|
||||
|
||||
|
||||
def network_get(net_id):
|
||||
session = get_session()
|
||||
try:
|
||||
return session.query(models.Network).\
|
||||
options(joinedload(models.Network.ports)). \
|
||||
filter_by(uuid=net_id).\
|
||||
one()
|
||||
except exc.NoResultFound, e:
|
||||
raise q_exc.NetworkNotFound(net_id=net_id)
|
||||
|
||||
|
||||
def network_rename(tenant_id, net_id, new_name):
|
||||
session = get_session()
|
||||
net = network_get(net_id)
|
||||
_check_duplicate_net_name(tenant_id, new_name)
|
||||
net.name = new_name
|
||||
session.merge(net)
|
||||
session.flush()
|
||||
return net
|
||||
|
||||
|
||||
def network_destroy(net_id):
|
||||
session = get_session()
|
||||
try:
|
||||
net = session.query(models.Network).\
|
||||
filter_by(uuid=net_id).\
|
||||
one()
|
||||
session.delete(net)
|
||||
session.flush()
|
||||
return net
|
||||
except exc.NoResultFound:
|
||||
raise q_exc.NetworkNotFound(net_id=net_id)
|
||||
|
||||
|
||||
def port_create(net_id, state=None):
|
||||
# confirm network exists
|
||||
network_get(net_id)
|
||||
|
||||
session = get_session()
|
||||
with session.begin():
|
||||
port = models.Port(net_id)
|
||||
port['state'] = state or 'DOWN'
|
||||
session.add(port)
|
||||
session.flush()
|
||||
return port
|
||||
|
||||
|
||||
def port_list(net_id):
|
||||
session = get_session()
|
||||
return session.query(models.Port).\
|
||||
options(joinedload(models.Port.network)). \
|
||||
filter_by(network_id=net_id).\
|
||||
all()
|
||||
|
||||
|
||||
def port_get(net_id, port_id):
|
||||
# confirm network exists
|
||||
network_get(net_id)
|
||||
session = get_session()
|
||||
try:
|
||||
return session.query(models.Port).\
|
||||
filter_by(uuid=port_id).\
|
||||
filter_by(network_id=net_id).\
|
||||
one()
|
||||
except exc.NoResultFound:
|
||||
raise q_exc.PortNotFound(net_id=net_id, port_id=port_id)
|
||||
|
||||
|
||||
def port_set_state(net_id, port_id, new_state):
|
||||
if new_state not in ('ACTIVE', 'DOWN'):
|
||||
raise q_exc.StateInvalid(port_state=new_state)
|
||||
|
||||
# confirm network exists
|
||||
network_get(net_id)
|
||||
|
||||
port = port_get(net_id, port_id)
|
||||
session = get_session()
|
||||
port.state = new_state
|
||||
session.merge(port)
|
||||
session.flush()
|
||||
return port
|
||||
|
||||
|
||||
def port_set_attachment(net_id, port_id, new_interface_id):
|
||||
# confirm network exists
|
||||
network_get(net_id)
|
||||
|
||||
session = get_session()
|
||||
port = port_get(net_id, port_id)
|
||||
|
||||
if new_interface_id != "":
|
||||
# We are setting, not clearing, the attachment-id
|
||||
if port['interface_id']:
|
||||
raise q_exc.PortInUse(net_id=net_id, port_id=port_id,
|
||||
att_id=port['interface_id'])
|
||||
|
||||
try:
|
||||
port = session.query(models.Port).\
|
||||
filter_by(interface_id=new_interface_id).\
|
||||
one()
|
||||
raise q_exc.AlreadyAttached(net_id=net_id,
|
||||
port_id=port_id,
|
||||
att_id=new_interface_id,
|
||||
att_port_id=port['uuid'])
|
||||
except exc.NoResultFound:
|
||||
# this is what should happen
|
||||
pass
|
||||
port.interface_id = new_interface_id
|
||||
session.merge(port)
|
||||
session.flush()
|
||||
return port
|
||||
|
||||
|
||||
def port_unset_attachment(net_id, port_id):
|
||||
# confirm network exists
|
||||
network_get(net_id)
|
||||
|
||||
session = get_session()
|
||||
port = port_get(net_id, port_id)
|
||||
port.interface_id = None
|
||||
session.merge(port)
|
||||
session.flush()
|
||||
return port
|
||||
|
||||
|
||||
def port_destroy(net_id, port_id):
|
||||
# confirm network exists
|
||||
network_get(net_id)
|
||||
|
||||
session = get_session()
|
||||
try:
|
||||
port = session.query(models.Port).\
|
||||
filter_by(uuid=port_id).\
|
||||
filter_by(network_id=net_id).\
|
||||
one()
|
||||
if port['interface_id']:
|
||||
raise q_exc.PortInUse(net_id=net_id, port_id=port_id,
|
||||
att_id=port['interface_id'])
|
||||
session.delete(port)
|
||||
session.flush()
|
||||
return port
|
||||
except exc.NoResultFound:
|
||||
raise q_exc.PortNotFound(port_id=port_id)
|
|
@ -0,0 +1,346 @@
|
|||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2011, 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.orm import exc
|
||||
|
||||
from quantum.common import exceptions as q_exc
|
||||
from quantum.plugins.cisco import l2network_plugin_configuration as conf
|
||||
from quantum.plugins.cisco.common import cisco_exceptions as c_exc
|
||||
from quantum.plugins.cisco.db import l2network_models
|
||||
|
||||
import quantum.plugins.cisco.db.api as db
|
||||
|
||||
|
||||
def initialize():
|
||||
'Establish database connection and load models'
|
||||
options = {"sql_connection": "mysql://%s:%s@%s/%s" % (conf.DB_USER,
|
||||
conf.DB_PASS, conf.DB_HOST, conf.DB_NAME)}
|
||||
db.configure_db(options)
|
||||
|
||||
|
||||
def create_vlanids():
|
||||
"""Prepopulates the vlan_bindings table"""
|
||||
session = db.get_session()
|
||||
try:
|
||||
vlanid = session.query(l2network_models.VlanID).\
|
||||
one()
|
||||
except exc.MultipleResultsFound:
|
||||
pass
|
||||
except exc.NoResultFound:
|
||||
start = int(conf.VLAN_START)
|
||||
end = int(conf.VLAN_END)
|
||||
while start <= end:
|
||||
vlanid = l2network_models.VlanID(start)
|
||||
session.add(vlanid)
|
||||
start += 1
|
||||
session.flush()
|
||||
return
|
||||
|
||||
|
||||
def get_all_vlanids():
|
||||
"""Gets all the vlanids"""
|
||||
session = db.get_session()
|
||||
try:
|
||||
vlanids = session.query(l2network_models.VlanID).\
|
||||
all()
|
||||
return vlanids
|
||||
except exc.NoResultFound:
|
||||
return []
|
||||
|
||||
|
||||
def is_vlanid_used(vlan_id):
|
||||
"""Checks if a vlanid is in use"""
|
||||
session = db.get_session()
|
||||
try:
|
||||
vlanid = session.query(l2network_models.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"""
|
||||
session = db.get_session()
|
||||
try:
|
||||
vlanid = session.query(l2network_models.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"""
|
||||
session = db.get_session()
|
||||
try:
|
||||
vlanid = session.query(l2network_models.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"""
|
||||
session = db.get_session()
|
||||
try:
|
||||
rvlan = session.query(l2network_models.VlanID).\
|
||||
filter_by(vlan_used=False).\
|
||||
first()
|
||||
rvlanid = session.query(l2network_models.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_vlan_bindings():
|
||||
"""Lists all the vlan to network associations"""
|
||||
session = db.get_session()
|
||||
try:
|
||||
bindings = session.query(l2network_models.VlanBinding).\
|
||||
all()
|
||||
return bindings
|
||||
except exc.NoResultFound:
|
||||
return []
|
||||
|
||||
|
||||
def get_vlan_binding(netid):
|
||||
"""Lists the vlan given a network_id"""
|
||||
session = db.get_session()
|
||||
try:
|
||||
binding = session.query(l2network_models.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"""
|
||||
session = db.get_session()
|
||||
try:
|
||||
binding = session.query(l2network_models.VlanBinding).\
|
||||
filter_by(vlan_id=vlanid).\
|
||||
one()
|
||||
raise c_exc.NetworkVlanBindingAlreadyExists(vlan_id=vlanid,
|
||||
network_id=netid)
|
||||
except exc.NoResultFound:
|
||||
binding = l2network_models.VlanBinding(vlanid, vlanname, netid)
|
||||
session.add(binding)
|
||||
session.flush()
|
||||
return binding
|
||||
|
||||
|
||||
def remove_vlan_binding(netid):
|
||||
"""Removes a vlan to network association"""
|
||||
session = db.get_session()
|
||||
try:
|
||||
binding = session.query(l2network_models.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"""
|
||||
session = db.get_session()
|
||||
try:
|
||||
binding = session.query(l2network_models.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"""
|
||||
session = db.get_session()
|
||||
try:
|
||||
pps = session.query(l2network_models.PortProfile).\
|
||||
all()
|
||||
return pps
|
||||
except exc.NoResultFound:
|
||||
return []
|
||||
|
||||
|
||||
def get_portprofile(tenantid, ppid):
|
||||
"""Lists a port profile"""
|
||||
session = db.get_session()
|
||||
try:
|
||||
pp = session.query(l2network_models.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"""
|
||||
session = db.get_session()
|
||||
try:
|
||||
pp = session.query(l2network_models.PortProfile).\
|
||||
filter_by(name=ppname).\
|
||||
one()
|
||||
raise c_exc.PortProfileAlreadyExists(tenant_id=tenantid,
|
||||
pp_name=ppname)
|
||||
except exc.NoResultFound:
|
||||
pp = l2network_models.PortProfile(ppname, vlanid, qos)
|
||||
session.add(pp)
|
||||
session.flush()
|
||||
return pp
|
||||
|
||||
|
||||
def remove_portprofile(tenantid, ppid):
|
||||
"""Removes a port profile"""
|
||||
session = db.get_session()
|
||||
try:
|
||||
pp = session.query(l2network_models.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"""
|
||||
session = db.get_session()
|
||||
try:
|
||||
pp = session.query(l2network_models.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"""
|
||||
session = db.get_session()
|
||||
try:
|
||||
bindings = session.query(l2network_models.PortProfileBinding).\
|
||||
all()
|
||||
return bindings
|
||||
except exc.NoResultFound:
|
||||
return []
|
||||
|
||||
|
||||
def get_pp_binding(tenantid, ppid):
|
||||
"""Lists a port profile binding"""
|
||||
session = db.get_session()
|
||||
try:
|
||||
binding = session.query(l2network_models.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"""
|
||||
session = db.get_session()
|
||||
try:
|
||||
binding = session.query(l2network_models.PortProfileBinding).\
|
||||
filter_by(portprofile_id=ppid).\
|
||||
one()
|
||||
raise c_exc.PortProfileBindingAlreadyExists(pp_id=ppid,
|
||||
port_id=portid)
|
||||
except exc.NoResultFound:
|
||||
binding = l2network_models.PortProfileBinding(tenantid, portid, \
|
||||
ppid, default)
|
||||
session.add(binding)
|
||||
session.flush()
|
||||
return binding
|
||||
|
||||
|
||||
def remove_pp_binding(tenantid, portid, ppid):
|
||||
"""Removes a port profile binding"""
|
||||
session = db.get_session()
|
||||
try:
|
||||
binding = session.query(l2network_models.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"""
|
||||
session = db.get_session()
|
||||
try:
|
||||
binding = session.query(l2network_models.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)
|
|
@ -0,0 +1,147 @@
|
|||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2011, 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.plugins.cisco.db.models import BASE
|
||||
from quantum.plugins.cisco.db import 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(BASE, 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 "<VlanBinding(%d,%s)>" % \
|
||||
(self.vlan_id, self.vlan_used)
|
||||
|
||||
|
||||
class VlanBinding(BASE, 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), ForeignKey("networks.uuid"), \
|
||||
nullable=False)
|
||||
network = relation(models.Network, uselist=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(BASE, 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(BASE, 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.uuid"), \
|
||||
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)
|
|
@ -0,0 +1,102 @@
|
|||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
# Copyright 2011 Nicira Networks, 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: Somik Behera, Nicira Networks, Inc.
|
||||
# @author: Brad Hall, Nicira Networks, Inc.
|
||||
# @author: Dan Wendlandt, Nicira Networks, Inc.
|
||||
|
||||
import uuid
|
||||
|
||||
from sqlalchemy import Column, String, ForeignKey
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.orm import relation, object_mapper
|
||||
|
||||
BASE = declarative_base()
|
||||
|
||||
|
||||
class QuantumBase(object):
|
||||
"""Base class for Quantum Models."""
|
||||
__table_args__ = {'mysql_engine': 'InnoDB'}
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
setattr(self, key, value)
|
||||
|
||||
def __getitem__(self, key):
|
||||
return getattr(self, key)
|
||||
|
||||
def get(self, key, default=None):
|
||||
return getattr(self, key, default)
|
||||
|
||||
def __iter__(self):
|
||||
self._i = iter(object_mapper(self).columns)
|
||||
return self
|
||||
|
||||
def next(self):
|
||||
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 Port(BASE, QuantumBase):
|
||||
"""Represents a port on a quantum network"""
|
||||
__tablename__ = 'ports'
|
||||
|
||||
uuid = Column(String(255), primary_key=True)
|
||||
network_id = Column(String(255), ForeignKey("networks.uuid"),
|
||||
nullable=False)
|
||||
interface_id = Column(String(255))
|
||||
# Port state - Hardcoding string value at the moment
|
||||
state = Column(String(8))
|
||||
|
||||
def __init__(self, network_id):
|
||||
self.uuid = str(uuid.uuid4())
|
||||
self.network_id = network_id
|
||||
self.state = "DOWN"
|
||||
|
||||
def __repr__(self):
|
||||
return "<Port(%s,%s,%s,%s)>" % (self.uuid, self.network_id,
|
||||
self.state, self.interface_id)
|
||||
|
||||
|
||||
class Network(BASE, QuantumBase):
|
||||
"""Represents a quantum network"""
|
||||
__tablename__ = 'networks'
|
||||
|
||||
uuid = Column(String(255), primary_key=True)
|
||||
tenant_id = Column(String(255), nullable=False)
|
||||
name = Column(String(255))
|
||||
ports = relation(Port, order_by=Port.uuid, backref="network")
|
||||
|
||||
def __init__(self, tenant_id, name):
|
||||
self.uuid = str(uuid.uuid4())
|
||||
self.tenant_id = tenant_id
|
||||
self.name = name
|
||||
|
||||
def __repr__(self):
|
||||
return "<Network(%s,%s,%s)>" % \
|
||||
(self.uuid, self.name, self.tenant_id)
|
|
@ -1,3 +1,4 @@
|
|||
"""
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2011 Cisco Systems, Inc. All rights reserved.
|
||||
|
@ -16,12 +17,19 @@
|
|||
#
|
||||
# @author: Sumit Naiksatam, Cisco Systems, Inc.
|
||||
#
|
||||
"""
|
||||
|
||||
import inspect
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
||||
|
||||
class L2DevicePluginBase(object):
|
||||
"""
|
||||
Base class for a device-specific plugin.
|
||||
An example of a device-specific plugin is a Nexus switch plugin.
|
||||
The network model relies on device-category-specific plugins to perform
|
||||
the configuration on each device.
|
||||
"""
|
||||
|
||||
__metaclass__ = ABCMeta
|
||||
|
||||
|
@ -133,7 +141,7 @@ class L2DevicePluginBase(object):
|
|||
marked with the abstractmethod decorator is
|
||||
provided by the plugin class.
|
||||
"""
|
||||
if cls is QuantumPluginBase:
|
||||
if cls is L2DevicePluginBase:
|
||||
for method in cls.__abstractmethods__:
|
||||
method_ok = False
|
||||
for base in klass.__mro__:
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
"""
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2011 Cisco Systems, Inc. All rights reserved.
|
||||
|
@ -16,6 +17,7 @@
|
|||
#
|
||||
# @author: Sumit Naiksatam, Cisco Systems, Inc.
|
||||
#
|
||||
"""
|
||||
|
||||
import inspect
|
||||
import logging as LOG
|
||||
|
@ -30,71 +32,92 @@ LOG.getLogger(const.LOGGER_COMPONENT_NAME)
|
|||
|
||||
|
||||
class L2NetworkModel(L2NetworkModelBase):
|
||||
"""
|
||||
Implements the L2NetworkModelBase
|
||||
This implementation works with UCS and Nexus plugin,
|
||||
with one UCS blade, and one Nexus switch.
|
||||
"""
|
||||
_plugins = {}
|
||||
|
||||
def __init__(self):
|
||||
for key in conf.plugins[const.PLUGINS].keys():
|
||||
for key in conf.PLUGINS[const.PLUGINS].keys():
|
||||
self._plugins[key] = utils.import_object(
|
||||
conf.plugins[const.PLUGINS][key])
|
||||
LOG.debug("Loaded device plugin %s\n" % \
|
||||
conf.plugins[const.PLUGINS][key])
|
||||
conf.PLUGINS[const.PLUGINS][key])
|
||||
LOG.debug("Loaded device plugin %s" % \
|
||||
conf.PLUGINS[const.PLUGINS][key])
|
||||
|
||||
def _funcName(self, offset=0):
|
||||
def _func_name(self, offset=0):
|
||||
"""Get the name of the calling function"""
|
||||
return inspect.stack()[1 + offset][3]
|
||||
|
||||
def _invokeAllDevicePlugins(self, function_name, args, kwargs):
|
||||
for pluginObjRef in self._plugins.values():
|
||||
getattr(pluginObjRef, function_name)(*args, **kwargs)
|
||||
def _invoke_all_device_plugins(self, function_name, args, kwargs):
|
||||
"""Invoke all device plugins for this model implementation"""
|
||||
for plugin_obj_ref in self._plugins.values():
|
||||
getattr(plugin_obj_ref, function_name)(*args, **kwargs)
|
||||
|
||||
def _invokeUCSPlugin(self, function_name, args, kwargs):
|
||||
def _invoke_ucs_plugin(self, function_name, args, kwargs):
|
||||
"""Invoke only the UCS plugin"""
|
||||
if const.UCS_PLUGIN in self._plugins.keys():
|
||||
getattr(self._plugins[const.UCS_PLUGIN],
|
||||
function_name)(*args, **kwargs)
|
||||
|
||||
def _invokeNexusPlugin(self, function_name, args, kwargs):
|
||||
def _invoke_nexus_plugin(self, function_name, args, kwargs):
|
||||
"""Invoke only the Nexus plugin"""
|
||||
if const.NEXUS_PLUGIN in self._plugins.keys():
|
||||
getattr(self._plugins[const.NEXUS_PLUGIN],
|
||||
function_name)(*args, **kwargs)
|
||||
|
||||
def get_all_networks(self, args):
|
||||
"""Not implemented for this model"""
|
||||
pass
|
||||
|
||||
def create_network(self, args):
|
||||
deviceParams = {const.DEVICE_IP: ""}
|
||||
self._invokeAllDevicePlugins(self._funcName(), args, deviceParams)
|
||||
"""Support for the Quantum core API call"""
|
||||
device_params = {const.DEVICE_IP: ""}
|
||||
self._invoke_all_device_plugins(self._func_name(), args, device_params)
|
||||
|
||||
def delete_network(self, args):
|
||||
deviceParams = {const.DEVICE_IP: ""}
|
||||
self._invokeAllDevicePlugins(self._funcName(), args, deviceParams)
|
||||
"""Support for the Quantum core API call"""
|
||||
device_params = {const.DEVICE_IP: ""}
|
||||
self._invoke_all_device_plugins(self._func_name(), args, device_params)
|
||||
|
||||
def get_network_details(self, args):
|
||||
"""Not implemented for this model"""
|
||||
pass
|
||||
|
||||
def rename_network(self, args):
|
||||
deviceParams = {const.DEVICE_IP: ""}
|
||||
self._invokeAllDevicePlugins(self._funcName(), args, deviceParams)
|
||||
"""Support for the Quantum core API call"""
|
||||
device_params = {const.DEVICE_IP: ""}
|
||||
self._invoke_all_device_plugins(self._func_name(), args, device_params)
|
||||
|
||||
def get_all_ports(self, args):
|
||||
"""Not implemented for this model"""
|
||||
pass
|
||||
|
||||
def create_port(self, args):
|
||||
deviceParams = {const.DEVICE_IP: ""}
|
||||
self._invokeUCSPlugin(self._funcName(), args, deviceParams)
|
||||
"""Support for the Quantum core API call"""
|
||||
device_params = {const.DEVICE_IP: ""}
|
||||
self._invoke_ucs_plugin(self._func_name(), args, device_params)
|
||||
|
||||
def delete_port(self, args):
|
||||
deviceParams = {const.DEVICE_IP: ""}
|
||||
self._invokeUCSPlugin(self._funcName(), args, deviceParams)
|
||||
"""Support for the Quantum core API call"""
|
||||
device_params = {const.DEVICE_IP: ""}
|
||||
self._invoke_ucs_plugin(self._func_name(), args, device_params)
|
||||
|
||||
def update_port(self, args):
|
||||
"""Not implemented for this model"""
|
||||
pass
|
||||
|
||||
def get_port_details(self, args):
|
||||
"""Not implemented for this model"""
|
||||
pass
|
||||
|
||||
def plug_interface(self, args):
|
||||
deviceParams = {const.DEVICE_IP: ""}
|
||||
self._invokeUCSPlugin(self._funcName(), args, deviceParams)
|
||||
"""Support for the Quantum core API call"""
|
||||
device_params = {const.DEVICE_IP: ""}
|
||||
self._invoke_ucs_plugin(self._func_name(), args, device_params)
|
||||
|
||||
def unplug_interface(self, args):
|
||||
deviceParams = {const.DEVICE_IP: ""}
|
||||
self._invokeUCSPlugin(self._funcName(), args, deviceParams)
|
||||
"""Support for the Quantum core API call"""
|
||||
device_params = {const.DEVICE_IP: ""}
|
||||
self._invoke_ucs_plugin(self._func_name(), args, device_params)
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
"""
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2011 Cisco Systems, Inc. All rights reserved.
|
||||
|
@ -16,12 +17,20 @@
|
|||
#
|
||||
# @author: Sumit Naiksatam, Cisco Systems, Inc.
|
||||
#
|
||||
"""
|
||||
|
||||
import inspect
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
||||
|
||||
class L2NetworkModelBase(object):
|
||||
"""
|
||||
Base class for L2 Network Model
|
||||
It relies on a pluggable network configuration module to gather
|
||||
knowledge of the system, but knows which device-specific plugins
|
||||
to invoke for a corresponding core API call, and what parameters to pass
|
||||
to that plugin.
|
||||
"""
|
||||
|
||||
__metaclass__ = ABCMeta
|
||||
|
||||
|
@ -131,7 +140,7 @@ class L2NetworkModelBase(object):
|
|||
marked with the abstractmethod decorator is
|
||||
provided by the plugin class.
|
||||
"""
|
||||
if cls is QuantumPluginBase:
|
||||
if cls is L2NetworkModelBase:
|
||||
for method in cls.__abstractmethods__:
|
||||
method_ok = False
|
||||
for base in klass.__mro__:
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
"""
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2011 Cisco Systems, Inc. All rights reserved.
|
||||
|
@ -16,6 +17,7 @@
|
|||
#
|
||||
# @author: Sumit Naiksatam, Cisco Systems, Inc.
|
||||
#
|
||||
"""
|
||||
|
||||
import inspect
|
||||
import logging as LOG
|
||||
|
@ -26,22 +28,22 @@ from quantum.quantum_plugin_base import QuantumPluginBase
|
|||
from quantum.plugins.cisco import l2network_plugin_configuration as conf
|
||||
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 api as db
|
||||
from quantum.plugins.cisco.db import l2network_db as cdb
|
||||
|
||||
LOG.basicConfig(level=LOG.WARN)
|
||||
LOG.getLogger(const.LOGGER_COMPONENT_NAME)
|
||||
|
||||
|
||||
class L2Network(QuantumPluginBase):
|
||||
_networks = {}
|
||||
_tenants = {}
|
||||
_portprofiles = {}
|
||||
""" L2 Network Framework Plugin """
|
||||
|
||||
def __init__(self):
|
||||
self._net_counter = 0
|
||||
self._portprofile_counter = 0
|
||||
self._port_counter = 0
|
||||
self._vlan_counter = int(conf.VLAN_START) - 1
|
||||
self._model = utils.import_object(conf.MODEL_CLASS)
|
||||
cdb.initialize()
|
||||
# TODO (Sumit): The following should move to the segmentation module
|
||||
cdb.create_vlanids()
|
||||
|
||||
"""
|
||||
Core API implementation
|
||||
|
@ -53,8 +55,16 @@ class L2Network(QuantumPluginBase):
|
|||
the specified tenant.
|
||||
"""
|
||||
LOG.debug("get_all_networks() called\n")
|
||||
self._invokeDevicePlugins(self._funcName(), [tenant_id])
|
||||
return self._networks.values()
|
||||
self._invoke_device_plugins(self._func_name(), [tenant_id])
|
||||
networks_list = db.network_list(tenant_id)
|
||||
new_networks_list = []
|
||||
for network in networks_list:
|
||||
new_network_dict = self._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):
|
||||
"""
|
||||
|
@ -62,22 +72,17 @@ class L2Network(QuantumPluginBase):
|
|||
a symbolic name.
|
||||
"""
|
||||
LOG.debug("create_network() called\n")
|
||||
new_net_id = self._get_unique_net_id(tenant_id)
|
||||
new_network = db.network_create(tenant_id, net_name)
|
||||
new_net_id = new_network[const.UUID]
|
||||
vlan_id = self._get_vlan_for_tenant(tenant_id, net_name)
|
||||
vlan_name = self._get_vlan_name(new_net_id, str(vlan_id))
|
||||
self._invokeDevicePlugins(self._funcName(), [tenant_id, net_name,
|
||||
self._invoke_device_plugins(self._func_name(), [tenant_id, net_name,
|
||||
new_net_id, vlan_name,
|
||||
vlan_id])
|
||||
cdb.add_vlan_binding(vlan_id, vlan_name, new_net_id)
|
||||
new_net_dict = {const.NET_ID: new_net_id,
|
||||
const.NET_NAME: net_name,
|
||||
const.NET_PORTS: {},
|
||||
const.NET_VLAN_NAME: vlan_name,
|
||||
const.NET_VLAN_ID: vlan_id,
|
||||
const.NET_TENANTS: [tenant_id]}
|
||||
self._networks[new_net_id] = new_net_dict
|
||||
tenant = self._get_tenant(tenant_id)
|
||||
tenant_networks = tenant[const.TENANT_NETWORKS]
|
||||
tenant_networks[new_net_id] = new_net_dict
|
||||
const.NET_PORTS: []}
|
||||
return new_net_dict
|
||||
|
||||
def delete_network(self, tenant_id, net_id):
|
||||
|
@ -86,22 +91,24 @@ class L2Network(QuantumPluginBase):
|
|||
belonging to the specified tenant.
|
||||
"""
|
||||
LOG.debug("delete_network() called\n")
|
||||
net = self._networks.get(net_id)
|
||||
net = db.network_get(net_id)
|
||||
if net:
|
||||
if len(net[const.NET_PORTS].values()) > 0:
|
||||
ports_on_net = net[const.NET_PORTS].values()
|
||||
if len(net[const.NETWORKPORTS]) > 0:
|
||||
ports_on_net = db.port_list(net_id)
|
||||
for port in ports_on_net:
|
||||
if port[const.ATTACHMENT]:
|
||||
if port[const.INTERFACEID]:
|
||||
raise exc.NetworkInUse(net_id=net_id)
|
||||
for port in ports_on_net:
|
||||
self.delete_port(tenant_id, net_id, port[const.PORT_ID])
|
||||
self.delete_port(tenant_id, net_id, port[const.PORTID])
|
||||
|
||||
self._invokeDevicePlugins(self._funcName(), [tenant_id, net_id])
|
||||
self._networks.pop(net_id)
|
||||
tenant = self._get_tenant(tenant_id)
|
||||
tenant_networks = tenant[const.TENANT_NETWORKS]
|
||||
tenant_networks.pop(net_id)
|
||||
return net
|
||||
self._invoke_device_plugins(self._func_name(), [tenant_id, net_id])
|
||||
net_dict = self._make_net_dict(net[const.UUID],
|
||||
net[const.NETWORKNAME],
|
||||
[])
|
||||
self._release_vlan_for_tenant(tenant_id, net_id)
|
||||
cdb.remove_vlan_binding(net_id)
|
||||
db.network_destroy(net_id)
|
||||
return net_dict
|
||||
# Network not found
|
||||
raise exc.NetworkNotFound(net_id=net_id)
|
||||
|
||||
|
@ -110,12 +117,22 @@ class L2Network(QuantumPluginBase):
|
|||
Gets the details of a particular network
|
||||
"""
|
||||
LOG.debug("get_network_details() called\n")
|
||||
self._invokeDevicePlugins(self._funcName(), [tenant_id, net_id])
|
||||
network = self._get_network(tenant_id, net_id)
|
||||
ports_on_net = network[const.NET_PORTS].values()
|
||||
return {const.NET_ID: network[const.NET_ID],
|
||||
const.NET_NAME: network[const.NET_NAME],
|
||||
const.NET_PORTS: ports_on_net}
|
||||
self._invoke_device_plugins(self._func_name(), [tenant_id, net_id])
|
||||
network = db.network_get(net_id)
|
||||
ports_list = network[const.NETWORKPORTS]
|
||||
ports_on_net = []
|
||||
for port in ports_list:
|
||||
new_port = self._make_port_dict(port[const.UUID],
|
||||
port[const.PORTSTATE],
|
||||
port[const.NETWORKID],
|
||||
port[const.INTERFACEID])
|
||||
ports_on_net.append(new_port)
|
||||
|
||||
new_network = self._make_net_dict(network[const.UUID],
|
||||
network[const.NETWORKNAME],
|
||||
ports_on_net)
|
||||
|
||||
return new_network
|
||||
|
||||
def rename_network(self, tenant_id, net_id, new_name):
|
||||
"""
|
||||
|
@ -123,11 +140,13 @@ class L2Network(QuantumPluginBase):
|
|||
Virtual Network.
|
||||
"""
|
||||
LOG.debug("rename_network() called\n")
|
||||
self._invokeDevicePlugins(self._funcName(), [tenant_id, net_id,
|
||||
self._invoke_device_plugins(self._func_name(), [tenant_id, net_id,
|
||||
new_name])
|
||||
network = self._get_network(tenant_id, net_id)
|
||||
network[const.NET_NAME] = new_name
|
||||
return network
|
||||
network = db.network_rename(tenant_id, net_id, new_name)
|
||||
net_dict = self._make_net_dict(network[const.UUID],
|
||||
network[const.NETWORKNAME],
|
||||
[])
|
||||
return net_dict
|
||||
|
||||
def get_all_ports(self, tenant_id, net_id):
|
||||
"""
|
||||
|
@ -135,9 +154,17 @@ class L2Network(QuantumPluginBase):
|
|||
specified Virtual Network.
|
||||
"""
|
||||
LOG.debug("get_all_ports() called\n")
|
||||
self._invokeDevicePlugins(self._funcName(), [tenant_id, net_id])
|
||||
network = self._get_network(tenant_id, net_id)
|
||||
ports_on_net = network[const.NET_PORTS].values()
|
||||
self._invoke_device_plugins(self._func_name(), [tenant_id, net_id])
|
||||
network = db.network_get(net_id)
|
||||
ports_list = network[const.NETWORKPORTS]
|
||||
ports_on_net = []
|
||||
for port in ports_list:
|
||||
new_port = self._make_port_dict(port[const.UUID],
|
||||
port[const.PORTSTATE],
|
||||
port[const.NETWORKID],
|
||||
port[const.INTERFACEID])
|
||||
ports_on_net.append(new_port)
|
||||
|
||||
return ports_on_net
|
||||
|
||||
def create_port(self, tenant_id, net_id, port_state=None):
|
||||
|
@ -145,16 +172,15 @@ class L2Network(QuantumPluginBase):
|
|||
Creates a port on the specified Virtual Network.
|
||||
"""
|
||||
LOG.debug("create_port() called\n")
|
||||
net = self._get_network(tenant_id, net_id)
|
||||
ports = net[const.NET_PORTS]
|
||||
unique_port_id_string = self._get_unique_port_id(tenant_id, net_id)
|
||||
self._invokeDevicePlugins(self._funcName(), [tenant_id, net_id,
|
||||
port = db.port_create(net_id, port_state)
|
||||
unique_port_id_string = port[const.UUID]
|
||||
self._invoke_device_plugins(self._func_name(), [tenant_id, net_id,
|
||||
port_state,
|
||||
unique_port_id_string])
|
||||
new_port_dict = {const.PORT_ID: unique_port_id_string,
|
||||
const.PORT_STATE: const.PORT_UP,
|
||||
const.ATTACHMENT: None}
|
||||
ports[unique_port_id_string] = new_port_dict
|
||||
new_port_dict = self._make_port_dict(port[const.UUID],
|
||||
port[const.PORTSTATE],
|
||||
port[const.NETWORKID],
|
||||
port[const.INTERFACEID])
|
||||
return new_port_dict
|
||||
|
||||
def delete_port(self, tenant_id, net_id, port_id):
|
||||
|
@ -165,31 +191,24 @@ class L2Network(QuantumPluginBase):
|
|||
then the port can be deleted.
|
||||
"""
|
||||
LOG.debug("delete_port() called\n")
|
||||
port = self._get_port(tenant_id, net_id, port_id)
|
||||
if port[const.ATTACHMENT]:
|
||||
raise exc.PortInUse(net_id=net_id, port_id=port_id,
|
||||
att_id=port[const.ATTACHMENT])
|
||||
try:
|
||||
#TODO (Sumit): Before deleting port profile make sure that there
|
||||
# is no VM using this port profile
|
||||
self._invokeDevicePlugins(self._funcName(), [tenant_id, net_id,
|
||||
port_id])
|
||||
net = self._get_network(tenant_id, net_id)
|
||||
net[const.NET_PORTS].pop(port_id)
|
||||
except KeyError:
|
||||
raise exc.PortNotFound(net_id=net_id, port_id=port_id)
|
||||
self._invoke_device_plugins(self._func_name(), [tenant_id, net_id,
|
||||
port_id])
|
||||
db.port_destroy(net_id, port_id)
|
||||
new_port_dict = self._make_port_dict(port_id, None, None, None)
|
||||
return new_port_dict
|
||||
|
||||
def update_port(self, tenant_id, net_id, port_id, port_state):
|
||||
"""
|
||||
Updates the state of a port on the specified Virtual Network.
|
||||
"""
|
||||
LOG.debug("update_port() called\n")
|
||||
self._invokeDevicePlugins(self._funcName(), [tenant_id, net_id,
|
||||
self._invoke_device_plugins(self._func_name(), [tenant_id, net_id,
|
||||
port_id, port_state])
|
||||
port = self._get_port(tenant_id, net_id, port_id)
|
||||
self._validate_port_state(port_state)
|
||||
port[const.PORT_STATE] = port_state
|
||||
return port
|
||||
db.port_set_state(net_id, port_id, port_state)
|
||||
new_port_dict = self._make_port_dict(port_id, port_state, net_id,
|
||||
None)
|
||||
return new_port_dict
|
||||
|
||||
def get_port_details(self, tenant_id, net_id, port_id):
|
||||
"""
|
||||
|
@ -197,9 +216,14 @@ class L2Network(QuantumPluginBase):
|
|||
that is attached to this particular port.
|
||||
"""
|
||||
LOG.debug("get_port_details() called\n")
|
||||
self._invokeDevicePlugins(self._funcName(), [tenant_id, net_id,
|
||||
self._invoke_device_plugins(self._func_name(), [tenant_id, net_id,
|
||||
port_id])
|
||||
return self._get_port(tenant_id, net_id, port_id)
|
||||
port = db.port_get(net_id, port_id)
|
||||
new_port_dict = self._make_port_dict(port[const.UUID],
|
||||
port[const.PORTSTATE],
|
||||
port[const.NETWORKID],
|
||||
port[const.INTERFACEID])
|
||||
return new_port_dict
|
||||
|
||||
def plug_interface(self, tenant_id, net_id, port_id,
|
||||
remote_interface_id):
|
||||
|
@ -208,16 +232,10 @@ class L2Network(QuantumPluginBase):
|
|||
specified Virtual Network.
|
||||
"""
|
||||
LOG.debug("plug_interface() called\n")
|
||||
self._validate_attachment(tenant_id, net_id, port_id,
|
||||
remote_interface_id)
|
||||
port = self._get_port(tenant_id, net_id, port_id)
|
||||
if port[const.ATTACHMENT]:
|
||||
raise exc.PortInUse(net_id=net_id, port_id=port_id,
|
||||
att_id=port[const.ATTACHMENT])
|
||||
self._invokeDevicePlugins(self._funcName(), [tenant_id, net_id,
|
||||
self._invoke_device_plugins(self._func_name(), [tenant_id, net_id,
|
||||
port_id,
|
||||
remote_interface_id])
|
||||
port[const.ATTACHMENT] = remote_interface_id
|
||||
db.port_set_attachment(net_id, port_id, remote_interface_id)
|
||||
|
||||
def unplug_interface(self, tenant_id, net_id, port_id):
|
||||
"""
|
||||
|
@ -225,170 +243,165 @@ class L2Network(QuantumPluginBase):
|
|||
specified Virtual Network.
|
||||
"""
|
||||
LOG.debug("unplug_interface() called\n")
|
||||
port = self._get_port(tenant_id, net_id, port_id)
|
||||
self._invokeDevicePlugins(self._funcName(), [tenant_id, net_id,
|
||||
self._invoke_device_plugins(self._func_name(), [tenant_id, net_id,
|
||||
port_id])
|
||||
port[const.ATTACHMENT] = None
|
||||
db.port_unset_attachment(net_id, port_id)
|
||||
|
||||
"""
|
||||
Extension API implementation
|
||||
"""
|
||||
def get_all_portprofiles(self, tenant_id):
|
||||
return self._portprofiles.values()
|
||||
"""Get all port profiles"""
|
||||
pplist = cdb.get_all_portprofiles()
|
||||
new_pplist = []
|
||||
for portprofile in pplist:
|
||||
new_pp = self._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):
|
||||
return self._get_portprofile(tenant_id, profile_id)
|
||||
"""Get port profile details"""
|
||||
portprofile = cdb.get_portprofile(tenant_id, profile_id)
|
||||
new_pp = self._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, vlan_id):
|
||||
profile_id = self._get_unique_profile_id(tenant_id)
|
||||
new_port_profile_dict = {const.PROFILE_ID: profile_id,
|
||||
const.PROFILE_NAME: profile_name,
|
||||
const.PROFILE_ASSOCIATIONS: [],
|
||||
const.PROFILE_VLAN_ID: vlan_id,
|
||||
const.PROFILE_QOS: None}
|
||||
self._portprofiles[profile_id] = new_port_profile_dict
|
||||
tenant = self._get_tenant(tenant_id)
|
||||
portprofiles = tenant[const.TENANT_PORTPROFILES]
|
||||
portprofiles[profile_id] = new_port_profile_dict
|
||||
return new_port_profile_dict
|
||||
def create_portprofile(self, tenant_id, profile_name, qos):
|
||||
"""Create port profile"""
|
||||
portprofile = cdb.add_portprofile(tenant_id, profile_name,
|
||||
const.NO_VLAN_ID, qos)
|
||||
new_pp = self._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):
|
||||
portprofile = self._get_portprofile(tenant_id, profile_id)
|
||||
associations = portprofile[const.PROFILE_ASSOCIATIONS]
|
||||
if len(associations) > 0:
|
||||
"""Delete portprofile"""
|
||||
try:
|
||||
portprofile = cdb.get_portprofile(tenant_id, profile_id)
|
||||
except Exception, exc:
|
||||
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)
|
||||
profile_id=profile_id)
|
||||
else:
|
||||
self._portprofiles.pop(profile_id)
|
||||
tenant = self._get_tenant(tenant_id)
|
||||
tenant[const.TENANT_PORTPROFILES].pop(profile_id)
|
||||
cdb.remove_portprofile(tenant_id, profile_id)
|
||||
|
||||
def rename_portprofile(self, tenant_id, profile_id, new_name):
|
||||
portprofile = self._get_portprofile(tenant_id, profile_id)
|
||||
portprofile[const.PROFILE_NAME] = new_name
|
||||
return portprofile
|
||||
"""Rename port profile"""
|
||||
try:
|
||||
portprofile = cdb.get_portprofile(tenant_id, profile_id)
|
||||
except Exception, exc:
|
||||
raise cexc.PortProfileNotFound(tenant_id=tenant_id,
|
||||
portprofile_id=profile_id)
|
||||
portprofile = cdb.update_portprofile(tenant_id, profile_id, new_name)
|
||||
new_pp = self._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):
|
||||
portprofile = self._get_portprofile(tenant_id, portprofile_id)
|
||||
associations = portprofile[const.PROFILE_ASSOCIATIONS]
|
||||
associations.append(port_id)
|
||||
"""Associate port profile"""
|
||||
try:
|
||||
portprofile = cdb.get_portprofile(tenant_id, portprofile_id)
|
||||
except Exception, exc:
|
||||
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):
|
||||
portprofile = self._get_portprofile(tenant_id, portprofile_id)
|
||||
associations = portprofile[const.PROFILE_ASSOCIATIONS]
|
||||
associations.remove(port_id)
|
||||
"""Disassociate port profile"""
|
||||
try:
|
||||
portprofile = cdb.get_portprofile(tenant_id, portprofile_id)
|
||||
except Exception, exc:
|
||||
raise cexc.PortProfileNotFound(tenant_id=tenant_id,
|
||||
portprofile_id=portprofile_id)
|
||||
|
||||
def create_defaultPProfile(self, tenant_id, network_id, profile_name,
|
||||
vlan_id):
|
||||
pass
|
||||
cdb.remove_pp_binding(tenant_id, port_id, portprofile_id)
|
||||
|
||||
"""
|
||||
Private functions
|
||||
"""
|
||||
def _invokeDevicePlugins(self, function_name, args):
|
||||
def _invoke_device_plugins(self, function_name, args):
|
||||
"""
|
||||
All device-specific calls are delegate to the model
|
||||
"""
|
||||
getattr(self._model, function_name)(args)
|
||||
|
||||
def _get_vlan_for_tenant(self, tenant_id, net_name):
|
||||
"""Get vlan ID"""
|
||||
# TODO (Sumit):
|
||||
# The VLAN ID for a tenant might need to be obtained from
|
||||
# somewhere (from Donabe/Melange?)
|
||||
# Also need to make sure that the VLAN ID is not being used already
|
||||
# Currently, just a wrap-around counter ranging from VLAN_START to
|
||||
# VLAN_END
|
||||
self._vlan_counter += 1
|
||||
self._vlan_counter %= int(conf.VLAN_END)
|
||||
if self._vlan_counter < int(conf.VLAN_START):
|
||||
self._vlan_counter = int(conf.VLAN_START)
|
||||
return self._vlan_counter
|
||||
return cdb.reserve_vlanid()
|
||||
|
||||
def _release_vlan_for_tenant(self, tenant_id, net_id):
|
||||
"""Relase VLAN"""
|
||||
vlan_binding = cdb.get_vlan_binding(net_id)
|
||||
return cdb.release_vlanid(vlan_binding[const.VLANID])
|
||||
|
||||
def _get_vlan_name(self, net_id, vlan):
|
||||
vlan_name = conf.VLAN_NAME_PREFIX + net_id + "-" + vlan
|
||||
"""Getting the vlan name from the tenant and vlan"""
|
||||
vlan_name = conf.VLAN_NAME_PREFIX + vlan
|
||||
return vlan_name
|
||||
|
||||
def _validate_port_state(self, port_state):
|
||||
"""Checking the port state"""
|
||||
if port_state.upper() not in (const.PORT_UP, const.PORT_DOWN):
|
||||
raise exc.StateInvalid(port_state=port_state)
|
||||
return True
|
||||
|
||||
def _validate_attachment(self, tenant_id, network_id, port_id,
|
||||
remote_interface_id):
|
||||
network = self._get_network(tenant_id, network_id)
|
||||
for port in network[const.NET_PORTS].values():
|
||||
if port[const.ATTACHMENT] == remote_interface_id:
|
||||
raise exc.AlreadyAttached(net_id=network_id,
|
||||
port_id=port_id,
|
||||
att_id=port[const.ATTACHMENT],
|
||||
att_port_id=port[const.PORT_ID])
|
||||
|
||||
def _get_network(self, tenant_id, network_id):
|
||||
network = self._networks.get(network_id)
|
||||
if not network:
|
||||
raise exc.NetworkNotFound(net_id=network_id)
|
||||
return network
|
||||
|
||||
def _get_tenant(self, tenant_id):
|
||||
tenant = self._tenants.get(tenant_id)
|
||||
if not tenant:
|
||||
LOG.debug("Creating new tenant record with tenant id %s\n" %
|
||||
tenant_id)
|
||||
tenant = {const.TENANT_ID: tenant_id,
|
||||
const.TENANT_NAME: tenant_id,
|
||||
const.TENANT_NETWORKS: {},
|
||||
const.TENANT_PORTPROFILES: {}}
|
||||
self._tenants[tenant_id] = tenant
|
||||
return tenant
|
||||
|
||||
def _get_port(self, tenant_id, network_id, port_id):
|
||||
net = self._get_network(tenant_id, network_id)
|
||||
port = net[const.NET_PORTS].get(port_id)
|
||||
if not port:
|
||||
raise exc.PortNotFound(net_id=network_id, port_id=port_id)
|
||||
return port
|
||||
|
||||
def _get_portprofile(self, tenant_id, portprofile_id):
|
||||
portprofile = self._portprofiles.get(portprofile_id)
|
||||
if not portprofile:
|
||||
raise cexc.PortProfileNotFound(tenant_id=tenant_id,
|
||||
portprofile_id=portprofile_id)
|
||||
return portprofile
|
||||
|
||||
def _get_unique_net_id(self, tenant_id):
|
||||
self._net_counter += 1
|
||||
self._net_counter %= int(conf.MAX_NETWORKS)
|
||||
id = tenant_id[:3] + \
|
||||
"-n-" + ("0" * (6 - len(str(self._net_counter)))) + \
|
||||
str(self._net_counter)
|
||||
# TODO (Sumit): Need to check if the ID has already been allocated
|
||||
# ID will be generated by DB
|
||||
return id
|
||||
|
||||
def _get_unique_port_id(self, tenant_id, net_id):
|
||||
self._port_counter += 1
|
||||
self._port_counter %= int(conf.MAX_PORTS)
|
||||
id = net_id + "-p-" + str(self._port_counter)
|
||||
# TODO (Sumit): Need to check if the ID has already been allocated
|
||||
# ID will be generated by DB
|
||||
return id
|
||||
|
||||
def _get_unique_profile_id(self, tenant_id):
|
||||
self._portprofile_counter += 1
|
||||
self._portprofile_counter %= int(conf.MAX_PORT_PROFILES)
|
||||
id = tenant_id[:3] + "-pp-" + \
|
||||
("0" * (6 - len(str(self._net_counter)))) \
|
||||
+ str(self._portprofile_counter)
|
||||
# TODO (Sumit): Need to check if the ID has already been allocated
|
||||
# ID will be generated by DB
|
||||
return id
|
||||
|
||||
def _funcName(self, offset=0):
|
||||
def _func_name(self, offset=0):
|
||||
"""Getting the name of the calling funciton"""
|
||||
return inspect.stack()[1 + offset][3]
|
||||
|
||||
"""
|
||||
TODO (Sumit):
|
||||
(1) Persistent storage
|
||||
"""
|
||||
def _make_net_dict(self, net_id, net_name, ports):
|
||||
"""Helper funciton"""
|
||||
res = {const.NET_ID: net_id, const.NET_NAME: net_name}
|
||||
res[const.NET_PORTS] = ports
|
||||
return res
|
||||
|
||||
def _make_port_dict(self, port_id, port_state, net_id, attachment):
|
||||
"""Helper funciton"""
|
||||
res = {const.PORT_ID: port_id, const.PORT_STATE: port_state}
|
||||
res[const.NET_ID] = net_id
|
||||
res[const.ATTACHMENT] = attachment
|
||||
return res
|
||||
|
||||
def _make_portprofile_dict(self, tenant_id, profile_id, profile_name,
|
||||
qos):
|
||||
"""Helper funciton"""
|
||||
profile_associations = self._make_portprofile_assc_list(tenant_id,
|
||||
profile_id)
|
||||
res = {const.PROFILE_ID: str(profile_id),
|
||||
const.PROFILE_NAME: profile_name,
|
||||
const.PROFILE_ASSOCIATIONS: profile_associations,
|
||||
const.PROFILE_VLAN_ID: None,
|
||||
const.PROFILE_QOS: qos}
|
||||
return res
|
||||
|
||||
def _make_portprofile_assc_list(self, tenant_id, profile_id):
|
||||
"""Helper function to create port profile association list"""
|
||||
plist = cdb.get_pp_binding(tenant_id, profile_id)
|
||||
assc_list = []
|
||||
for port in plist:
|
||||
assc_list.append(port[const.PORTID])
|
||||
|
||||
return assc_list
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
"""
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2011 Cisco Systems, Inc. All rights reserved.
|
||||
|
@ -15,7 +16,8 @@
|
|||
# under the License.
|
||||
#
|
||||
# @author: Sumit Naiksatam, Cisco Systems, Inc.
|
||||
#
|
||||
# @author: Rohit Agarwalla, Cisco Systems, Inc.
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
|
@ -23,28 +25,43 @@ from quantum.plugins.cisco.common import cisco_configparser as confp
|
|||
|
||||
CONF_FILE = "conf/l2network_plugin.ini"
|
||||
|
||||
cp = confp.CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) \
|
||||
+ "/" + CONF_FILE)
|
||||
CONF_PARSER_OBJ = confp.\
|
||||
CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) + \
|
||||
"/" + CONF_FILE)
|
||||
|
||||
section = cp['VLANS']
|
||||
VLAN_NAME_PREFIX = section['vlan_name_prefix']
|
||||
VLAN_START = section['vlan_start']
|
||||
VLAN_END = section['vlan_end']
|
||||
SECTION_CONF = CONF_PARSER_OBJ['VLANS']
|
||||
VLAN_NAME_PREFIX = SECTION_CONF['vlan_name_prefix']
|
||||
VLAN_START = SECTION_CONF['vlan_start']
|
||||
VLAN_END = SECTION_CONF['vlan_end']
|
||||
|
||||
section = cp['PORTS']
|
||||
MAX_PORTS = section['max_ports']
|
||||
SECTION_CONF = CONF_PARSER_OBJ['PORTS']
|
||||
MAX_PORTS = SECTION_CONF['max_ports']
|
||||
|
||||
section = cp['PORTPROFILES']
|
||||
MAX_PORT_PROFILES = section['max_port_profiles']
|
||||
SECTION_CONF = CONF_PARSER_OBJ['PORTPROFILES']
|
||||
MAX_PORT_PROFILES = SECTION_CONF['max_port_profiles']
|
||||
|
||||
section = cp['NETWORKS']
|
||||
MAX_NETWORKS = section['max_networks']
|
||||
SECTION_CONF = CONF_PARSER_OBJ['NETWORKS']
|
||||
MAX_NETWORKS = SECTION_CONF['max_networks']
|
||||
|
||||
section = cp['MODEL']
|
||||
MODEL_CLASS = section['model_class']
|
||||
SECTION_CONF = CONF_PARSER_OBJ['MODEL']
|
||||
MODEL_CLASS = SECTION_CONF['model_class']
|
||||
|
||||
CONF_FILE = "conf/plugins.ini"
|
||||
|
||||
cp = confp.CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) \
|
||||
+ "/" + CONF_FILE)
|
||||
plugins = cp.walk(cp.dummy)
|
||||
CONF_PARSER_OBJ = confp.\
|
||||
CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) + \
|
||||
"/" + CONF_FILE)
|
||||
|
||||
PLUGINS = CONF_PARSER_OBJ.walk(CONF_PARSER_OBJ.dummy)
|
||||
|
||||
CONF_FILE = "conf/db_conn.ini"
|
||||
|
||||
CONF_PARSER_OBJ = confp.\
|
||||
CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) + \
|
||||
"/" + CONF_FILE)
|
||||
|
||||
SECTION_CONF = CONF_PARSER_OBJ['DATABASE']
|
||||
DB_NAME = SECTION_CONF['name']
|
||||
DB_USER = SECTION_CONF['user']
|
||||
DB_PASS = SECTION_CONF['pass']
|
||||
DB_HOST = SECTION_CONF['host']
|
||||
|
|
|
@ -15,4 +15,7 @@
|
|||
# under the License.
|
||||
#
|
||||
# @author: Sumit Naiksatam, Cisco Systems, Inc.
|
||||
#
|
||||
# @author: Edgar Magana, Cisco Systems, Inc.
|
||||
"""
|
||||
Init module for Nexus Driver
|
||||
"""
|
||||
|
|
|
@ -17,19 +17,24 @@
|
|||
# @author: Sumit Naiksatam, Cisco Systems, Inc.
|
||||
# @author: Edgar Magana, Cisco Systems, Inc.
|
||||
#
|
||||
|
||||
"""
|
||||
Configuration consolidation for the Nexus Driver
|
||||
This module will export the configuration parameters
|
||||
from the nexus.ini file
|
||||
"""
|
||||
import os
|
||||
|
||||
from quantum.plugins.cisco.common import cisco_configparser as confp
|
||||
|
||||
CONF_FILE = "../conf/nexus.ini"
|
||||
|
||||
cp = confp.CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) \
|
||||
CP = confp.CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) \
|
||||
+ "/" + CONF_FILE)
|
||||
|
||||
section = cp['SWITCH']
|
||||
NEXUS_IP_ADDRESS = section['nexus_ip_address']
|
||||
NEXUS_PORT = section['nexus_port']
|
||||
SECTION = CP['SWITCH']
|
||||
NEXUS_IP_ADDRESS = SECTION['nexus_ip_address']
|
||||
NEXUS_PORT = SECTION['nexus_port']
|
||||
NEXUS_SSH_PORT = SECTION['nexus_ssh_port']
|
||||
|
||||
section = cp['DRIVER']
|
||||
NEXUS_DRIVER = section['name']
|
||||
SECTION = CP['DRIVER']
|
||||
NEXUS_DRIVER = SECTION['name']
|
||||
|
|
|
@ -22,11 +22,9 @@ Implements a Nexus-OS NETCONF over SSHv2 API Client
|
|||
"""
|
||||
|
||||
import logging as LOG
|
||||
import string
|
||||
import subprocess
|
||||
|
||||
from quantum.plugins.cisco.common import cisco_constants as const
|
||||
from quantum.plugins.cisco.common import cisco_exceptions as cexc
|
||||
from quantum.plugins.cisco.nexus import cisco_nexus_snippets as snipp
|
||||
|
||||
from ncclient import manager
|
||||
|
||||
|
@ -34,193 +32,101 @@ LOG.basicConfig(level=LOG.WARN)
|
|||
LOG.getLogger(const.LOGGER_COMPONENT_NAME)
|
||||
|
||||
|
||||
# The following are standard strings, messages used to communicate with Nexus,
|
||||
#only place holder values change for each message
|
||||
exec_conf_prefix = """
|
||||
<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
|
||||
<configure xmlns="http://www.cisco.com/nxos:1.0:vlan_mgr_cli">
|
||||
<__XML__MODE__exec_configure>
|
||||
"""
|
||||
|
||||
|
||||
exec_conf_postfix = """
|
||||
</__XML__MODE__exec_configure>
|
||||
</configure>
|
||||
</config>
|
||||
"""
|
||||
|
||||
|
||||
cmd_vlan_conf_snippet = """
|
||||
<vlan>
|
||||
<vlan-id-create-delete>
|
||||
<__XML__PARAM_value>%s</__XML__PARAM_value>
|
||||
<__XML__MODE_vlan>
|
||||
<name>
|
||||
<vlan-name>%s</vlan-name>
|
||||
</name>
|
||||
<state>
|
||||
<vstate>active</vstate>
|
||||
</state>
|
||||
<no>
|
||||
<shutdown/>
|
||||
</no>
|
||||
</__XML__MODE_vlan>
|
||||
</vlan-id-create-delete>
|
||||
</vlan>
|
||||
"""
|
||||
|
||||
cmd_no_vlan_conf_snippet = """
|
||||
<no>
|
||||
<vlan>
|
||||
<vlan-id-create-delete>
|
||||
<__XML__PARAM_value>%s</__XML__PARAM_value>
|
||||
</vlan-id-create-delete>
|
||||
</vlan>
|
||||
</no>
|
||||
"""
|
||||
|
||||
cmd_vlan_int_snippet = """
|
||||
<interface>
|
||||
<ethernet>
|
||||
<interface>%s</interface>
|
||||
<__XML__MODE_if-ethernet-switch>
|
||||
<switchport></switchport>
|
||||
<switchport>
|
||||
<trunk>
|
||||
<allowed>
|
||||
<vlan>
|
||||
<__XML__BLK_Cmd_switchport_trunk_allowed_allow-vlans>
|
||||
<allow-vlans>%s</allow-vlans>
|
||||
</__XML__BLK_Cmd_switchport_trunk_allowed_allow-vlans>
|
||||
</vlan>
|
||||
</allowed>
|
||||
</trunk>
|
||||
</switchport>
|
||||
</__XML__MODE_if-ethernet-switch>
|
||||
</ethernet>
|
||||
</interface>
|
||||
"""
|
||||
|
||||
cmd_port_trunk = """
|
||||
<interface>
|
||||
<ethernet>
|
||||
<interface>%s</interface>
|
||||
<__XML__MODE_if-ethernet-switch>
|
||||
<switchport></switchport>
|
||||
<switchport>
|
||||
<mode>
|
||||
<trunk>
|
||||
</trunk>
|
||||
</mode>
|
||||
</switchport>
|
||||
</__XML__MODE_if-ethernet-switch>
|
||||
</ethernet>
|
||||
</interface>
|
||||
"""
|
||||
|
||||
cmd_no_switchport = """
|
||||
<interface>
|
||||
<ethernet>
|
||||
<interface>%s</interface>
|
||||
<__XML__MODE_if-ethernet-switch>
|
||||
<no>
|
||||
<switchport>
|
||||
</switchport>
|
||||
</no>
|
||||
</__XML__MODE_if-ethernet-switch>
|
||||
</ethernet>
|
||||
</interface>
|
||||
"""
|
||||
|
||||
|
||||
cmd_no_vlan_int_snippet = """
|
||||
<interface>
|
||||
<ethernet>
|
||||
<interface>%s</interface>
|
||||
<__XML__MODE_if-ethernet-switch>
|
||||
<switchport></switchport>
|
||||
<no>
|
||||
<switchport>
|
||||
<trunk>
|
||||
<allowed>
|
||||
<vlan>
|
||||
<__XML__BLK_Cmd_switchport_trunk_allowed_allow-vlans>
|
||||
<allow-vlans>%s</allow-vlans>
|
||||
</__XML__BLK_Cmd_switchport_trunk_allowed_allow-vlans>
|
||||
</vlan>
|
||||
</allowed>
|
||||
</trunk>
|
||||
</switchport>
|
||||
</no>
|
||||
</__XML__MODE_if-ethernet-switch>
|
||||
</ethernet>
|
||||
</interface>
|
||||
"""
|
||||
|
||||
|
||||
filter_show_vlan_brief_snippet = """
|
||||
<show xmlns="http://www.cisco.com/nxos:1.0:vlan_mgr_cli">
|
||||
<vlan>
|
||||
<brief/>
|
||||
</vlan>
|
||||
</show> """
|
||||
|
||||
|
||||
class CiscoNEXUSDriver():
|
||||
|
||||
"""
|
||||
Nexus Driver Main Class
|
||||
"""
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def nxos_connect(self, nexus_host, port, nexus_user, nexus_password):
|
||||
m = manager.connect(host=nexus_host, port=22, username=nexus_user,
|
||||
password=nexus_password)
|
||||
return m
|
||||
def nxos_connect(self, nexus_host, nexus_ssh_port, nexus_user,
|
||||
nexus_password):
|
||||
"""
|
||||
Makes the SSH connection to the Nexus Switch
|
||||
"""
|
||||
man = manager.connect(host=nexus_host, port=nexus_ssh_port,
|
||||
username=nexus_user, password=nexus_password)
|
||||
return man
|
||||
|
||||
def create_xml_snippet(self, cutomized_config):
|
||||
"""
|
||||
Creates the Proper XML structure for the Nexus Switch Configuration
|
||||
"""
|
||||
conf_xml_snippet = snipp.EXEC_CONF_SNIPPET % (cutomized_config)
|
||||
return conf_xml_snippet
|
||||
|
||||
def enable_vlan(self, mgr, vlanid, vlanname):
|
||||
confstr = cmd_vlan_conf_snippet % (vlanid, vlanname)
|
||||
confstr = exec_conf_prefix + confstr + exec_conf_postfix
|
||||
"""
|
||||
Creates a VLAN on Nexus Switch given the VLAN ID and Name
|
||||
"""
|
||||
confstr = snipp.CMD_VLAN_CONF_SNIPPET % (vlanid, vlanname)
|
||||
confstr = self.create_xml_snippet(confstr)
|
||||
mgr.edit_config(target='running', config=confstr)
|
||||
|
||||
def disable_vlan(self, mgr, vlanid):
|
||||
confstr = cmd_no_vlan_conf_snippet % vlanid
|
||||
confstr = exec_conf_prefix + confstr + exec_conf_postfix
|
||||
"""
|
||||
Delete a VLAN on Nexus Switch given the VLAN ID
|
||||
"""
|
||||
confstr = snipp.CMD_NO_VLAN_CONF_SNIPPET % vlanid
|
||||
confstr = self.create_xml_snippet(confstr)
|
||||
mgr.edit_config(target='running', config=confstr)
|
||||
|
||||
def enable_port_trunk(self, mgr, interface):
|
||||
confstr = cmd_port_trunk % (interface)
|
||||
confstr = exec_conf_prefix + confstr + exec_conf_postfix
|
||||
print confstr
|
||||
"""
|
||||
Enables trunk mode an interface on Nexus Switch
|
||||
"""
|
||||
confstr = snipp.CMD_PORT_TRUNK % (interface)
|
||||
confstr = self.create_xml_snippet(confstr)
|
||||
LOG.debug("NexusDriver: %s" % confstr)
|
||||
mgr.edit_config(target='running', config=confstr)
|
||||
|
||||
def disable_switch_port(self, mgr, interface):
|
||||
confstr = cmd_no_switchport % (interface)
|
||||
confstr = exec_conf_prefix + confstr + exec_conf_postfix
|
||||
print confstr
|
||||
"""
|
||||
Disables trunk mode an interface on Nexus Switch
|
||||
"""
|
||||
confstr = snipp.CMD_NO_SWITCHPORT % (interface)
|
||||
confstr = self.create_xml_snippet(confstr)
|
||||
LOG.debug("NexusDriver: %s" % confstr)
|
||||
mgr.edit_config(target='running', config=confstr)
|
||||
|
||||
def enable_vlan_on_trunk_int(self, mgr, interface, vlanid):
|
||||
confstr = cmd_vlan_int_snippet % (interface, vlanid)
|
||||
confstr = exec_conf_prefix + confstr + exec_conf_postfix
|
||||
print confstr
|
||||
"""
|
||||
Enables trunk mode vlan access an interface on Nexus Switch given
|
||||
VLANID
|
||||
"""
|
||||
confstr = snipp.CMD_VLAN_INT_SNIPPET % (interface, vlanid)
|
||||
confstr = self.create_xml_snippet(confstr)
|
||||
LOG.debug("NexusDriver: %s" % confstr)
|
||||
mgr.edit_config(target='running', config=confstr)
|
||||
|
||||
def disable_vlan_on_trunk_int(self, mgr, interface, vlanid):
|
||||
confstr = cmd_no_vlan_int_snippet % (interface, vlanid)
|
||||
confstr = exec_conf_prefix + confstr + exec_conf_postfix
|
||||
print confstr
|
||||
"""
|
||||
Enables trunk mode vlan access an interface on Nexus Switch given
|
||||
VLANID
|
||||
"""
|
||||
confstr = snipp.CMD_NO_VLAN_INT_SNIPPET % (interface, vlanid)
|
||||
confstr = self.create_xml_snippet(confstr)
|
||||
LOG.debug("NexusDriver: %s" % confstr)
|
||||
mgr.edit_config(target='running', config=confstr)
|
||||
|
||||
def create_vlan(self, vlan_name, vlan_id, nexus_host, nexus_user,
|
||||
nexus_password, nexus_interface):
|
||||
#TODO (Edgar) Move the SSH port to the configuration file
|
||||
with self.nxos_connect(nexus_host, 22, nexus_user,
|
||||
nexus_password) as m:
|
||||
self.enable_vlan(m, vlan_id, vlan_name)
|
||||
self.enable_vlan_on_trunk_int(m, nexus_interface, vlan_id)
|
||||
nexus_password, nexus_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
|
||||
"""
|
||||
with self.nxos_connect(nexus_host, int(nexus_ssh_port), nexus_user,
|
||||
nexus_password) as man:
|
||||
self.enable_vlan(man, vlan_id, vlan_name)
|
||||
self.enable_vlan_on_trunk_int(man, nexus_interface, vlan_id)
|
||||
|
||||
def delete_vlan(self, vlan_id, nexus_host, nexus_user,
|
||||
nexus_password, nexus_interface):
|
||||
with self.nxos_connect(nexus_host, 22, nexus_user,
|
||||
nexus_password) as m:
|
||||
self.disable_vlan(m, vlan_id)
|
||||
self.disable_switch_port(m, nexus_interface)
|
||||
nexus_password, nexus_interface, nexus_ssh_port):
|
||||
"""
|
||||
Delete a VLAN and Disables trunk mode an interface on Nexus Switch
|
||||
given the VLAN ID and Interface Number
|
||||
"""
|
||||
with self.nxos_connect(nexus_host, int(nexus_ssh_port), nexus_user,
|
||||
nexus_password) as man:
|
||||
self.disable_vlan(man, vlan_id)
|
||||
self.disable_switch_port(man, nexus_interface)
|
||||
|
|
|
@ -17,14 +17,15 @@
|
|||
# @author: Sumit Naiksatam, Cisco Systems, Inc.
|
||||
# @author: Edgar Magana, Cisco Systems, Inc.
|
||||
#
|
||||
"""
|
||||
PlugIn for Nexus OS driver
|
||||
"""
|
||||
import logging as LOG
|
||||
|
||||
from quantum.common import exceptions as exc
|
||||
from quantum.common import utils
|
||||
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.l2device_plugin_base import L2DevicePluginBase
|
||||
from quantum.plugins.cisco.nexus import cisco_nexus_configuration as conf
|
||||
|
||||
|
@ -33,16 +34,22 @@ LOG.getLogger(const.LOGGER_COMPONENT_NAME)
|
|||
|
||||
|
||||
class NexusPlugin(L2DevicePluginBase):
|
||||
"""
|
||||
Nexus PLugIn Main Class
|
||||
"""
|
||||
_networks = {}
|
||||
|
||||
def __init__(self):
|
||||
"""
|
||||
Extracts the configuration parameters from the configuration file
|
||||
"""
|
||||
self._client = utils.import_object(conf.NEXUS_DRIVER)
|
||||
LOG.debug("Loaded driver %s\n" % conf.NEXUS_DRIVER)
|
||||
#TODO (Edgar) Using just one Nexus 7K Switch and Port
|
||||
self._nexus_ip = conf.NEXUS_IP_ADDRESS
|
||||
self._nexus_username = cred.Store.getUsername(conf.NEXUS_IP_ADDRESS)
|
||||
self._nexus_password = cred.Store.getPassword(conf.NEXUS_IP_ADDRESS)
|
||||
self._nexus_port = conf.NEXUS_PORT
|
||||
self._nexus_ssh_port = conf.NEXUS_SSH_PORT
|
||||
|
||||
def get_all_networks(self, tenant_id):
|
||||
"""
|
||||
|
@ -61,7 +68,8 @@ class NexusPlugin(L2DevicePluginBase):
|
|||
"""
|
||||
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_port)
|
||||
self._nexus_username, self._nexus_password, self._nexus_port,
|
||||
self._nexus_ssh_port)
|
||||
|
||||
new_net_dict = {const.NET_ID: net_id,
|
||||
const.NET_NAME: net_name,
|
||||
|
@ -81,7 +89,8 @@ class NexusPlugin(L2DevicePluginBase):
|
|||
vlan_id = self._get_vlan_id_for_network(tenant_id, net_id)
|
||||
if net:
|
||||
self._client.delete_vlan(str(vlan_id), self._nexus_ip,
|
||||
self._nexus_username, self._nexus_password, self._nexus_port)
|
||||
self._nexus_username, self._nexus_password, self._nexus_port,
|
||||
self._nexus_ssh_port)
|
||||
self._networks.pop(net_id)
|
||||
return net
|
||||
# Network not found
|
||||
|
@ -100,7 +109,6 @@ class NexusPlugin(L2DevicePluginBase):
|
|||
Updates the symbolic name belonging to a particular
|
||||
Virtual Network.
|
||||
"""
|
||||
#TODO (Edgar) We need to add an update method in the Nexus Driver
|
||||
LOG.debug("NexusPlugin:rename_network() called\n")
|
||||
network = self._get_network(tenant_id, net_id)
|
||||
network[const.NET_NAME] = new_name
|
||||
|
@ -157,11 +165,17 @@ class NexusPlugin(L2DevicePluginBase):
|
|||
LOG.debug("NexusPlugin:unplug_interface() called\n")
|
||||
|
||||
def _get_vlan_id_for_network(self, tenant_id, network_id):
|
||||
"""
|
||||
Obtain the VLAN ID given the Network ID
|
||||
"""
|
||||
net = self._get_network(tenant_id, network_id)
|
||||
vlan_id = net[const.NET_VLAN_ID]
|
||||
return vlan_id
|
||||
|
||||
def _get_network(self, tenant_id, network_id):
|
||||
"""
|
||||
Gets the NETWORK ID
|
||||
"""
|
||||
network = self._networks.get(network_id)
|
||||
if not network:
|
||||
raise exc.NetworkNotFound(net_id=network_id)
|
||||
|
|
|
@ -0,0 +1,156 @@
|
|||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2011 Cisco Systems, Inc. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
# @author: Edgar Magana, Cisco Systems, Inc.
|
||||
|
||||
"""
|
||||
Nexus-OS XML-based configuration snippets
|
||||
"""
|
||||
|
||||
import logging as LOG
|
||||
|
||||
from quantum.plugins.cisco.common import cisco_constants as const
|
||||
|
||||
LOG.basicConfig(level=LOG.WARN)
|
||||
LOG.getLogger(const.LOGGER_COMPONENT_NAME)
|
||||
|
||||
|
||||
# The following are standard strings, messages used to communicate with Nexus,
|
||||
EXEC_CONF_SNIPPET = """
|
||||
<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
|
||||
<configure xmlns="http://www.cisco.com/nxos:1.0:vlan_mgr_cli">
|
||||
<__XML__MODE__exec_configure>%s
|
||||
</__XML__MODE__exec_configure>
|
||||
</configure>
|
||||
</config>
|
||||
"""
|
||||
|
||||
|
||||
CMD_VLAN_CONF_SNIPPET = """
|
||||
<vlan>
|
||||
<vlan-id-create-delete>
|
||||
<__XML__PARAM_value>%s</__XML__PARAM_value>
|
||||
<__XML__MODE_vlan>
|
||||
<name>
|
||||
<vlan-name>%s</vlan-name>
|
||||
</name>
|
||||
<state>
|
||||
<vstate>active</vstate>
|
||||
</state>
|
||||
<no>
|
||||
<shutdown/>
|
||||
</no>
|
||||
</__XML__MODE_vlan>
|
||||
</vlan-id-create-delete>
|
||||
</vlan>
|
||||
"""
|
||||
|
||||
CMD_NO_VLAN_CONF_SNIPPET = """
|
||||
<no>
|
||||
<vlan>
|
||||
<vlan-id-create-delete>
|
||||
<__XML__PARAM_value>%s</__XML__PARAM_value>
|
||||
</vlan-id-create-delete>
|
||||
</vlan>
|
||||
</no>
|
||||
"""
|
||||
|
||||
CMD_VLAN_INT_SNIPPET = """
|
||||
<interface>
|
||||
<ethernet>
|
||||
<interface>%s</interface>
|
||||
<__XML__MODE_if-ethernet-switch>
|
||||
<switchport></switchport>import logging as LOG
|
||||
<switchport>
|
||||
<trunk>
|
||||
<allowed>
|
||||
<vlan>
|
||||
<__XML__BLK_Cmd_switchport_trunk_allowed_allow-vlans>
|
||||
<allow-vlans>%s</allow-vlans>
|
||||
</__XML__BLK_Cmd_switchport_trunk_allowed_allow-vlans>
|
||||
</vlan>
|
||||
</allowed>
|
||||
</trunk>
|
||||
</switchport>
|
||||
</__XML__MODE_if-ethernet-switch>
|
||||
</ethernet>
|
||||
</interface>
|
||||
"""
|
||||
|
||||
CMD_PORT_TRUNK = """
|
||||
<interface>
|
||||
<ethernet>
|
||||
<interface>%s</interface>
|
||||
<__XML__MODE_if-ethernet-switch>
|
||||
<switchport></switchport>
|
||||
<switchport>
|
||||
<mode>
|
||||
<trunk>
|
||||
</trunk>
|
||||
</mode>
|
||||
</switchport>
|
||||
</__XML__MODE_if-ethernet-switch>C: 1: Missing docstring
|
||||
</ethernet>
|
||||
</interface>
|
||||
"""
|
||||
|
||||
CMD_NO_SWITCHPORT = """
|
||||
<interface>
|
||||
<ethernet>
|
||||
<interface>%s</interface>
|
||||
<__XML__MODE_if-ethernet-switch>
|
||||
<no>
|
||||
<switchport>
|
||||
</switchport>
|
||||
</no>
|
||||
</__XML__MODE_if-ethernet-switch>
|
||||
</ethernet>
|
||||
</interface>
|
||||
"""
|
||||
|
||||
|
||||
CMD_NO_VLAN_INT_SNIPPET = """
|
||||
<interface>
|
||||
<ethernet>C: 1: Missing docstring
|
||||
<interface>%s</interface>
|
||||
<__XML__MODE_if-ethernet-switch>
|
||||
<switchport></switchport>
|
||||
<no>
|
||||
<switchport>
|
||||
<trunk>
|
||||
<allowed>
|
||||
<vlan>
|
||||
<__XML__BLK_Cmd_switchport_trunk_allowed_allow-vlans>
|
||||
<allow-vlans>%s</allow-vlans>
|
||||
</__XML__BLK_Cmd_switchport_trunk_allowed_allow-vlans>
|
||||
</vlan>
|
||||
</allowed>
|
||||
</trunk>
|
||||
</switchport>
|
||||
</no>
|
||||
</__XML__MODE_if-ethernet-switch>
|
||||
</ethernet>
|
||||
</interface>
|
||||
"""
|
||||
|
||||
|
||||
FILTER_SHOW_VLAN_BRIEF_SNIPPET = """
|
||||
<show xmlns="http://www.cisco.com/nxos:1.0:vlan_mgr_cli">
|
||||
<vlan>
|
||||
<brief/>
|
||||
</vlan>
|
||||
</show>
|
||||
"""
|
|
@ -0,0 +1,96 @@
|
|||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2011 Cisco Systems, Inc. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
# @author: Sumit Naiksatam, Cisco Systems, Inc.
|
||||
#
|
||||
|
||||
from nova import exception as excp
|
||||
from nova import flags
|
||||
from nova import log as logging
|
||||
from nova.scheduler import driver
|
||||
from quantum.client import Client
|
||||
from quantum.common.wsgi import Serializer
|
||||
|
||||
LOG = logging.getLogger('quantum.plugins.cisco.nova.quantum_aware_scheduler')
|
||||
|
||||
FLAGS = flags.FLAGS
|
||||
flags.DEFINE_string('quantum_host', "127.0.0.1",
|
||||
'IP address of the quantum network service.')
|
||||
flags.DEFINE_integer('quantum_port', 9696,
|
||||
'Listening port for Quantum network service')
|
||||
|
||||
HOST = FLAGS.quantum_host
|
||||
PORT = FLAGS.quantum_port
|
||||
USE_SSL = False
|
||||
ACTION_PREFIX_EXT = '/v0.1'
|
||||
ACTION_PREFIX_CSCO = ACTION_PREFIX_EXT + \
|
||||
'/extensions/csco/tenants/{tenant_id}'
|
||||
TENANT_ID = 'nova'
|
||||
CSCO_EXT_NAME = 'Cisco Nova Tenant'
|
||||
|
||||
|
||||
class QuantumScheduler(driver.Scheduler):
|
||||
"""
|
||||
Quantum network service dependent scheduler
|
||||
Obtains the hostname from Quantum using an extension API
|
||||
"""
|
||||
def __init__(self):
|
||||
# We have to send a dummy tenant name here since the client
|
||||
# needs some tenant name, but the tenant name will not be used
|
||||
# since the extensions URL does not require it
|
||||
client = Client(HOST, PORT, USE_SSL, format='json',
|
||||
action_prefix=ACTION_PREFIX_EXT, tenant="dummy")
|
||||
request_url = "/extensions"
|
||||
data = client.do_request('GET', request_url)
|
||||
LOG.debug("Obtained supported extensions from Quantum: %s" % data)
|
||||
for ext in data['extensions']:
|
||||
name = ext['name']
|
||||
if name == CSCO_EXT_NAME:
|
||||
LOG.debug("Quantum plugin supports required \"%s\" extension"
|
||||
"for the scheduler." % name)
|
||||
return
|
||||
LOG.error("Quantum plugin does not support required \"%s\" extension"
|
||||
" for the scheduler. Scheduler will quit." % CSCO_EXT_NAME)
|
||||
raise excp.ServiceUnavailable()
|
||||
|
||||
def schedule(self, context, topic, *args, **kwargs):
|
||||
"""Gets the host name from the Quantum service"""
|
||||
instance_id = kwargs['instance_id']
|
||||
user_id = \
|
||||
kwargs['request_spec']['instance_properties']['user_id']
|
||||
project_id = \
|
||||
kwargs['request_spec']['instance_properties']['project_id']
|
||||
|
||||
instance_data_dict = \
|
||||
{'novatenant': \
|
||||
{'instance_id': instance_id,
|
||||
'instance_desc': \
|
||||
{'user_id': user_id,
|
||||
'project_id': project_id}}}
|
||||
|
||||
client = Client(HOST, PORT, USE_SSL, format='json', tenant=TENANT_ID,
|
||||
action_prefix=ACTION_PREFIX_CSCO)
|
||||
request_url = "/novatenants/" + project_id + "/get_host"
|
||||
data = client.do_request('PUT', request_url, body=instance_data_dict)
|
||||
|
||||
hostname = data["host_list"]["host_1"]
|
||||
if not hostname:
|
||||
raise driver.NoValidHost(_("Scheduler was unable to locate a host"
|
||||
" for this request. Is the appropriate"
|
||||
" service running?"))
|
||||
|
||||
LOG.debug(_("Quantum service returned host: %s") % hostname)
|
||||
return hostname
|
|
@ -0,0 +1,112 @@
|
|||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
# Copyright 2011 Cisco Systems, Inc. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
# @author: Sumit Naiksatam, Cisco Systems, Inc.
|
||||
#
|
||||
|
||||
"""VIF drivers for interface type direct."""
|
||||
|
||||
from nova import exception as excp
|
||||
from nova import flags
|
||||
from nova import log as logging
|
||||
from nova.network import linux_net
|
||||
from nova.virt.libvirt import netutils
|
||||
from nova import utils
|
||||
from nova.virt.vif import VIFDriver
|
||||
from quantum.client import Client
|
||||
from quantum.common.wsgi import Serializer
|
||||
|
||||
LOG = logging.getLogger('quantum.plugins.cisco.nova.vifdirect')
|
||||
|
||||
FLAGS = flags.FLAGS
|
||||
flags.DEFINE_string('quantum_host', "127.0.0.1",
|
||||
'IP address of the quantum network service.')
|
||||
flags.DEFINE_integer('quantum_port', 9696,
|
||||
'Listening port for Quantum network service')
|
||||
|
||||
HOST = FLAGS.quantum_host
|
||||
PORT = FLAGS.quantum_port
|
||||
USE_SSL = False
|
||||
TENANT_ID = 'nova'
|
||||
ACTION_PREFIX_EXT = '/v0.1'
|
||||
ACTION_PREFIX_CSCO = ACTION_PREFIX_EXT + \
|
||||
'/extensions/csco/tenants/{tenant_id}'
|
||||
TENANT_ID = 'nova'
|
||||
CSCO_EXT_NAME = 'Cisco Nova Tenant'
|
||||
|
||||
|
||||
class Libvirt802dot1QbhDriver(VIFDriver):
|
||||
"""VIF driver for Linux bridge."""
|
||||
def __init__(self):
|
||||
# We have to send a dummy tenant name here since the client
|
||||
# needs some tenant name, but the tenant name will not be used
|
||||
# since the extensions URL does not require it
|
||||
client = Client(HOST, PORT, USE_SSL, format='json',
|
||||
action_prefix=ACTION_PREFIX_EXT, tenant="dummy")
|
||||
request_url = "/extensions"
|
||||
data = client.do_request('GET', request_url)
|
||||
LOG.debug("Obtained supported extensions from Quantum: %s" % data)
|
||||
for ext in data['extensions']:
|
||||
name = ext['name']
|
||||
if name == CSCO_EXT_NAME:
|
||||
LOG.debug("Quantum plugin supports required \"%s\" extension"
|
||||
"for the VIF driver." % name)
|
||||
return
|
||||
LOG.error("Quantum plugin does not support required \"%s\" extension"
|
||||
" for the VIF driver. nova-compute will quit." \
|
||||
% CSCO_EXT_NAME)
|
||||
raise excp.ServiceUnavailable()
|
||||
|
||||
def _get_configurations(self, instance, network, mapping):
|
||||
"""Gets the device name and the profile name from Quantum"""
|
||||
|
||||
instance_id = instance['id']
|
||||
user_id = instance['user_id']
|
||||
project_id = instance['project_id']
|
||||
vif_id = mapping['vif_uuid']
|
||||
|
||||
instance_data_dict = \
|
||||
{'novatenant': \
|
||||
{'instance_id': instance_id,
|
||||
'instance_desc': \
|
||||
{'user_id': user_id,
|
||||
'project_id': project_id,
|
||||
'vif_id': vif_id}}}
|
||||
|
||||
client = Client(HOST, PORT, USE_SSL, format='json', tenant=TENANT_ID,
|
||||
action_prefix=ACTION_PREFIX_CSCO)
|
||||
request_url = "/novatenants/" + project_id + "/get_instance_port"
|
||||
data = client.do_request('PUT', request_url, body=instance_data_dict)
|
||||
|
||||
device = data['vif_desc']['device']
|
||||
portprofile = data['vif_desc']['portprofile']
|
||||
LOG.debug(_("Quantum provided the device: %s") % device)
|
||||
LOG.debug(_("Quantum provided the portprofile: %s") % portprofile)
|
||||
mac_id = mapping['mac'].replace(':', '')
|
||||
|
||||
result = {
|
||||
'id': mac_id,
|
||||
'mac_address': mapping['mac'],
|
||||
'device_name': device,
|
||||
'profile_name': portprofile,
|
||||
}
|
||||
|
||||
return result
|
||||
|
||||
def plug(self, instance, network, mapping):
|
||||
return self._get_configurations(instance, network, mapping)
|
||||
|
||||
def unplug(self, instance, network, mapping):
|
||||
pass
|
|
@ -16,50 +16,34 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# Colorizer Code is borrowed from Twisted:
|
||||
# Copyright (c) 2001-2010 Twisted Matrix Laboratories.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be
|
||||
# included in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
"""Unittest runner for quantum
|
||||
"""Unittest runner for quantum Cisco plugin
|
||||
|
||||
This file should be run from the top dir in the quantum directory
|
||||
|
||||
To run all test::
|
||||
python run_tests.py
|
||||
python quantum/plugins/cisco/run_tests.py
|
||||
|
||||
To run all unit tests::
|
||||
python run_tests.py unit
|
||||
python quantum/plugins/cisco/run_tests.py quantum.plugins.cisco.tests.unit
|
||||
|
||||
To run all functional tests::
|
||||
python run_tests.py functional
|
||||
python quantum/plugins/cisco/run_tests.py functional
|
||||
|
||||
To run a single unit test::
|
||||
python run_tests.py unit.test_stores:TestSwiftBackend.test_get
|
||||
python quantum/plugins/cisco/run_tests.py \
|
||||
quantum.plugins.cisco.tests.unit.test_stores:TestSwiftBackend.test_get
|
||||
|
||||
To run a single functional test::
|
||||
python run_tests.py functional.test_service:TestController.test_create
|
||||
python quantum/plugins/cisco/run_tests.py \
|
||||
quantum.plugins.cisco.tests.functional.test_service \
|
||||
:TestController.test_create
|
||||
|
||||
To run a single unit test module::
|
||||
python run_tests.py unit.test_stores
|
||||
python quantum/plugins/cisco/run_tests.py unit.test_stores
|
||||
|
||||
To run a single functional test module::
|
||||
python run_tests.py functional.test_stores
|
||||
python quantum/plugins/cisco/run_tests.py functional.test_stores
|
||||
"""
|
||||
|
||||
import gettext
|
||||
|
@ -69,233 +53,37 @@ import unittest
|
|||
import sys
|
||||
|
||||
from nose import config
|
||||
from nose import result
|
||||
from nose import core
|
||||
|
||||
sys.path.append(os.getcwd())
|
||||
|
||||
class _AnsiColorizer(object):
|
||||
"""
|
||||
A colorizer is an object that loosely wraps around a stream, allowing
|
||||
callers to write text to the stream in a particular color.
|
||||
|
||||
Colorizer classes must implement C{supported()} and C{write(text, color)}.
|
||||
"""
|
||||
_colors = dict(black=30, red=31, green=32, yellow=33,
|
||||
blue=34, magenta=35, cyan=36, white=37)
|
||||
|
||||
def __init__(self, stream):
|
||||
self.stream = stream
|
||||
|
||||
def supported(cls, stream=sys.stdout):
|
||||
"""
|
||||
A class method that returns True if the current platform supports
|
||||
coloring terminal output using this method. Returns False otherwise.
|
||||
"""
|
||||
if not stream.isatty():
|
||||
return False # auto color only on TTYs
|
||||
try:
|
||||
import curses
|
||||
except ImportError:
|
||||
return False
|
||||
else:
|
||||
try:
|
||||
try:
|
||||
return curses.tigetnum("colors") > 2
|
||||
except curses.error:
|
||||
curses.setupterm()
|
||||
return curses.tigetnum("colors") > 2
|
||||
except:
|
||||
raise
|
||||
# guess false in case of error
|
||||
return False
|
||||
supported = classmethod(supported)
|
||||
|
||||
def write(self, text, color):
|
||||
"""
|
||||
Write the given text to the stream in the given color.
|
||||
|
||||
@param text: Text to be written to the stream.
|
||||
|
||||
@param color: A string label for a color. e.g. 'red', 'white'.
|
||||
"""
|
||||
color = self._colors[color]
|
||||
self.stream.write('\x1b[%s;1m%s\x1b[0m' % (color, text))
|
||||
|
||||
|
||||
class _Win32Colorizer(object):
|
||||
"""
|
||||
See _AnsiColorizer docstring.
|
||||
"""
|
||||
def __init__(self, stream):
|
||||
from win32console import GetStdHandle, STD_OUT_HANDLE, \
|
||||
FOREGROUND_RED, FOREGROUND_BLUE, FOREGROUND_GREEN, \
|
||||
FOREGROUND_INTENSITY
|
||||
red, green, blue, bold = (FOREGROUND_RED, FOREGROUND_GREEN,
|
||||
FOREGROUND_BLUE, FOREGROUND_INTENSITY)
|
||||
self.stream = stream
|
||||
self.screenBuffer = GetStdHandle(STD_OUT_HANDLE)
|
||||
self._colors = {
|
||||
'normal': red | green | blue,
|
||||
'red': red | bold,
|
||||
'green': green | bold,
|
||||
'blue': blue | bold,
|
||||
'yellow': red | green | bold,
|
||||
'magenta': red | blue | bold,
|
||||
'cyan': green | blue | bold,
|
||||
'white': red | green | blue | bold}
|
||||
|
||||
def supported(cls, stream=sys.stdout):
|
||||
try:
|
||||
import win32console
|
||||
screenBuffer = win32console.GetStdHandle(
|
||||
win32console.STD_OUT_HANDLE)
|
||||
except ImportError:
|
||||
return False
|
||||
import pywintypes
|
||||
try:
|
||||
screenBuffer.SetConsoleTextAttribute(
|
||||
win32console.FOREGROUND_RED |
|
||||
win32console.FOREGROUND_GREEN |
|
||||
win32console.FOREGROUND_BLUE)
|
||||
except pywintypes.error:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
supported = classmethod(supported)
|
||||
|
||||
def write(self, text, color):
|
||||
color = self._colors[color]
|
||||
self.screenBuffer.SetConsoleTextAttribute(color)
|
||||
self.stream.write(text)
|
||||
self.screenBuffer.SetConsoleTextAttribute(self._colors['normal'])
|
||||
|
||||
|
||||
class _NullColorizer(object):
|
||||
"""
|
||||
See _AnsiColorizer docstring.
|
||||
"""
|
||||
def __init__(self, stream):
|
||||
self.stream = stream
|
||||
|
||||
def supported(cls, stream=sys.stdout):
|
||||
return True
|
||||
supported = classmethod(supported)
|
||||
|
||||
def write(self, text, color):
|
||||
self.stream.write(text)
|
||||
|
||||
|
||||
class QuantumTestResult(result.TextTestResult):
|
||||
def __init__(self, *args, **kw):
|
||||
result.TextTestResult.__init__(self, *args, **kw)
|
||||
self._last_case = None
|
||||
self.colorizer = None
|
||||
# NOTE(vish, tfukushima): reset stdout for the terminal check
|
||||
stdout = sys.__stdout__
|
||||
for colorizer in [_Win32Colorizer, _AnsiColorizer, _NullColorizer]:
|
||||
if colorizer.supported():
|
||||
self.colorizer = colorizer(self.stream)
|
||||
break
|
||||
sys.stdout = stdout
|
||||
|
||||
def getDescription(self, test):
|
||||
return str(test)
|
||||
|
||||
# NOTE(vish, tfukushima): copied from unittest with edit to add color
|
||||
def addSuccess(self, test):
|
||||
unittest.TestResult.addSuccess(self, test)
|
||||
if self.showAll:
|
||||
self.colorizer.write("OK", 'green')
|
||||
self.stream.writeln()
|
||||
elif self.dots:
|
||||
self.stream.write('.')
|
||||
self.stream.flush()
|
||||
|
||||
# NOTE(vish, tfukushima): copied from unittest with edit to add color
|
||||
def addFailure(self, test, err):
|
||||
unittest.TestResult.addFailure(self, test, err)
|
||||
if self.showAll:
|
||||
self.colorizer.write("FAIL", 'red')
|
||||
self.stream.writeln()
|
||||
elif self.dots:
|
||||
self.stream.write('F')
|
||||
self.stream.flush()
|
||||
|
||||
# NOTE(vish, tfukushima): copied from unittest with edit to add color
|
||||
def addError(self, test, err):
|
||||
"""Overrides normal addError to add support for errorClasses.
|
||||
If the exception is a registered class, the error will be added
|
||||
to the list for that class, not errors.
|
||||
"""
|
||||
stream = getattr(self, 'stream', None)
|
||||
ec, ev, tb = err
|
||||
try:
|
||||
exc_info = self._exc_info_to_string(err, test)
|
||||
except TypeError:
|
||||
# This is for compatibility with Python 2.3.
|
||||
exc_info = self._exc_info_to_string(err)
|
||||
for cls, (storage, label, isfail) in self.errorClasses.items():
|
||||
if result.isclass(ec) and issubclass(ec, cls):
|
||||
if isfail:
|
||||
test.passwd = False
|
||||
storage.append((test, exc_info))
|
||||
# Might get patched into a streamless result
|
||||
if stream is not None:
|
||||
if self.showAll:
|
||||
message = [label]
|
||||
detail = result._exception_details(err[1])
|
||||
if detail:
|
||||
message.append(detail)
|
||||
stream.writeln(": ".join(message))
|
||||
elif self.dots:
|
||||
stream.write(label[:1])
|
||||
return
|
||||
self.errors.append((test, exc_info))
|
||||
test.passed = False
|
||||
if stream is not None:
|
||||
if self.showAll:
|
||||
self.colorizer.write("ERROR", 'red')
|
||||
self.stream.writeln()
|
||||
elif self.dots:
|
||||
stream.write('E')
|
||||
|
||||
def startTest(self, test):
|
||||
unittest.TestResult.startTest(self, test)
|
||||
current_case = test.test.__class__.__name__
|
||||
|
||||
if self.showAll:
|
||||
if current_case != self._last_case:
|
||||
self.stream.writeln(current_case)
|
||||
self._last_case = current_case
|
||||
|
||||
self.stream.write(
|
||||
' %s' % str(test.test._testMethodName).ljust(60))
|
||||
self.stream.flush()
|
||||
|
||||
|
||||
class QuantumTestRunner(core.TextTestRunner):
|
||||
def _makeResult(self):
|
||||
return QuantumTestResult(self.stream,
|
||||
self.descriptions,
|
||||
self.verbosity,
|
||||
self.config)
|
||||
|
||||
from quantum.common.test_lib import run_tests, test_config
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Set up test logger.
|
||||
logger = logging.getLogger()
|
||||
hdlr = logging.StreamHandler()
|
||||
formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
|
||||
hdlr.setFormatter(formatter)
|
||||
logger.addHandler(hdlr)
|
||||
logger.setLevel(logging.DEBUG)
|
||||
exit_status = False
|
||||
|
||||
# if a single test case was specified,
|
||||
# we should only invoked the tests once
|
||||
invoke_once = len(sys.argv) > 1
|
||||
|
||||
cwd = os.getcwd()
|
||||
|
||||
working_dir = os.path.abspath("tests")
|
||||
c = config.Config(stream=sys.stdout,
|
||||
env=os.environ,
|
||||
verbosity=3,
|
||||
workingDir=working_dir)
|
||||
runner = QuantumTestRunner(stream=c.stream,
|
||||
verbosity=c.verbosity,
|
||||
config=c)
|
||||
sys.exit(not core.run(config=c, testRunner=runner))
|
||||
exit_status = run_tests(c)
|
||||
|
||||
if invoke_once:
|
||||
sys.exit(0)
|
||||
|
||||
os.chdir(cwd)
|
||||
|
||||
working_dir = os.path.abspath("quantum/plugins/cisco/tests")
|
||||
c = config.Config(stream=sys.stdout,
|
||||
env=os.environ,
|
||||
verbosity=3,
|
||||
workingDir=working_dir)
|
||||
exit_status = exit_status or run_tests(c)
|
||||
|
||||
sys.exit(exit_status)
|
||||
|
|
|
@ -0,0 +1,840 @@
|
|||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2011, 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.
|
||||
|
||||
"""
|
||||
test_database.py is an independent test suite
|
||||
that tests the database api method calls
|
||||
"""
|
||||
import logging as LOG
|
||||
import unittest
|
||||
|
||||
from quantum.plugins.cisco.common import cisco_constants as const
|
||||
|
||||
import quantum.plugins.cisco.db.api as db
|
||||
import quantum.plugins.cisco.db.l2network_db as l2network_db
|
||||
|
||||
|
||||
LOG.getLogger(const.LOGGER_COMPONENT_NAME)
|
||||
|
||||
|
||||
class L2networkDB(object):
|
||||
"""Class conisting of methods to call L2network db methods"""
|
||||
def get_all_vlan_bindings(self):
|
||||
"""Get all vlan binding into a list of dict"""
|
||||
vlans = []
|
||||
try:
|
||||
for vlan_bind in l2network_db.get_all_vlan_bindings():
|
||||
LOG.debug("Getting vlan bindings for vlan: %s" % \
|
||||
vlan_bind.vlan_id)
|
||||
vlan_dict = {}
|
||||
vlan_dict["vlan-id"] = str(vlan_bind.vlan_id)
|
||||
vlan_dict["vlan-name"] = vlan_bind.vlan_name
|
||||
vlan_dict["net-id"] = str(vlan_bind.network_id)
|
||||
vlans.append(vlan_dict)
|
||||
except Exception, exc:
|
||||
LOG.error("Failed to get all vlan bindings: %s" % str(exc))
|
||||
return vlans
|
||||
|
||||
def get_vlan_binding(self, network_id):
|
||||
"""Get a vlan binding"""
|
||||
vlan = []
|
||||
try:
|
||||
for vlan_bind in l2network_db.get_vlan_binding(network_id):
|
||||
LOG.debug("Getting vlan binding for vlan: %s" \
|
||||
% vlan_bind.vlan_id)
|
||||
vlan_dict = {}
|
||||
vlan_dict["vlan-id"] = str(vlan_bind.vlan_id)
|
||||
vlan_dict["vlan-name"] = vlan_bind.vlan_name
|
||||
vlan_dict["net-id"] = str(vlan_bind.network_id)
|
||||
vlan.append(vlan_dict)
|
||||
except Exception, exc:
|
||||
LOG.error("Failed to get vlan binding: %s" % str(exc))
|
||||
return vlan
|
||||
|
||||
def create_vlan_binding(self, vlan_id, vlan_name, network_id):
|
||||
"""Create a vlan binding"""
|
||||
vlan_dict = {}
|
||||
try:
|
||||
res = l2network_db.add_vlan_binding(vlan_id, vlan_name, network_id)
|
||||
LOG.debug("Created vlan binding for vlan: %s" % res.vlan_id)
|
||||
vlan_dict["vlan-id"] = str(res.vlan_id)
|
||||
vlan_dict["vlan-name"] = res.vlan_name
|
||||
vlan_dict["net-id"] = str(res.network_id)
|
||||
return vlan_dict
|
||||
except Exception, exc:
|
||||
LOG.error("Failed to create vlan binding: %s" % str(exc))
|
||||
|
||||
def delete_vlan_binding(self, network_id):
|
||||
"""Delete a vlan binding"""
|
||||
try:
|
||||
res = l2network_db.remove_vlan_binding(network_id)
|
||||
LOG.debug("Deleted vlan binding for vlan: %s" % res.vlan_id)
|
||||
vlan_dict = {}
|
||||
vlan_dict["vlan-id"] = str(res.vlan_id)
|
||||
return vlan_dict
|
||||
except Exception, exc:
|
||||
raise Exception("Failed to delete vlan binding: %s" % str(exc))
|
||||
|
||||
def update_vlan_binding(self, network_id, vlan_id, vlan_name):
|
||||
"""Update a vlan binding"""
|
||||
try:
|
||||
res = l2network_db.update_vlan_binding(network_id, vlan_id, \
|
||||
vlan_name)
|
||||
LOG.debug("Updating vlan binding for vlan: %s" % res.vlan_id)
|
||||
vlan_dict = {}
|
||||
vlan_dict["vlan-id"] = str(res.vlan_id)
|
||||
vlan_dict["vlan-name"] = res.vlan_name
|
||||
vlan_dict["net-id"] = str(res.network_id)
|
||||
return vlan_dict
|
||||
except Exception, exc:
|
||||
raise Exception("Failed to update vlan binding: %s" % str(exc))
|
||||
|
||||
def get_all_portprofiles(self):
|
||||
"""Get all portprofiles"""
|
||||
pps = []
|
||||
try:
|
||||
for portprof in l2network_db.get_all_portprofiles():
|
||||
LOG.debug("Getting port profile : %s" % portprof.uuid)
|
||||
pp_dict = {}
|
||||
pp_dict["portprofile-id"] = str(portprof.uuid)
|
||||
pp_dict["portprofile-name"] = portprof.name
|
||||
pp_dict["vlan-id"] = str(portprof.vlan_id)
|
||||
pp_dict["qos"] = portprof.qos
|
||||
pps.append(pp_dict)
|
||||
except Exception, exc:
|
||||
LOG.error("Failed to get all port profiles: %s" % str(exc))
|
||||
return pps
|
||||
|
||||
def get_portprofile(self, tenant_id, pp_id):
|
||||
"""Get a portprofile"""
|
||||
pp_list = []
|
||||
try:
|
||||
for portprof in l2network_db.get_portprofile(tenant_id, pp_id):
|
||||
LOG.debug("Getting port profile : %s" % portprof.uuid)
|
||||
pp_dict = {}
|
||||
pp_dict["portprofile-id"] = str(portprof.uuid)
|
||||
pp_dict["portprofile-name"] = portprof.name
|
||||
pp_dict["vlan-id"] = str(portprof.vlan_id)
|
||||
pp_dict["qos"] = portprof.qos
|
||||
pp_list.append(pp_dict)
|
||||
except Exception, exc:
|
||||
LOG.error("Failed to get port profile: %s" % str(exc))
|
||||
return pp
|
||||
|
||||
def create_portprofile(self, tenant_id, name, vlan_id, qos):
|
||||
"""Create a portprofile"""
|
||||
pp_dict = {}
|
||||
try:
|
||||
res = l2network_db.add_portprofile(tenant_id, name, vlan_id, qos)
|
||||
LOG.debug("Created port profile: %s" % res.uuid)
|
||||
pp_dict["portprofile-id"] = str(res.uuid)
|
||||
pp_dict["portprofile-name"] = res.name
|
||||
pp_dict["vlan-id"] = str(res.vlan_id)
|
||||
pp_dict["qos"] = res.qos
|
||||
return pp_dict
|
||||
except Exception, exc:
|
||||
LOG.error("Failed to create port profile: %s" % str(exc))
|
||||
|
||||
def delete_portprofile(self, tenant_id, pp_id):
|
||||
"""Delete a portprofile"""
|
||||
try:
|
||||
res = l2network_db.remove_portprofile(tenant_id, pp_id)
|
||||
LOG.debug("Deleted port profile : %s" % res.uuid)
|
||||
pp_dict = {}
|
||||
pp_dict["pp-id"] = str(res.uuid)
|
||||
return pp_dict
|
||||
except Exception, exc:
|
||||
raise Exception("Failed to delete port profile: %s" % str(exc))
|
||||
|
||||
def update_portprofile(self, tenant_id, pp_id, name, vlan_id, qos):
|
||||
"""Update a portprofile"""
|
||||
try:
|
||||
res = l2network_db.update_portprofile(tenant_id, pp_id, name,
|
||||
vlan_id, qos)
|
||||
LOG.debug("Updating port profile : %s" % res.uuid)
|
||||
pp_dict = {}
|
||||
pp_dict["portprofile-id"] = str(res.uuid)
|
||||
pp_dict["portprofile-name"] = res.name
|
||||
pp_dict["vlan-id"] = str(res.vlan_id)
|
||||
pp_dict["qos"] = res.qos
|
||||
return pp_dict
|
||||
except Exception, exc:
|
||||
raise Exception("Failed to update port profile: %s" % str(exc))
|
||||
|
||||
def get_all_pp_bindings(self):
|
||||
"""Get all portprofile bindings"""
|
||||
pp_bindings = []
|
||||
try:
|
||||
for pp_bind in l2network_db.get_all_pp_bindings():
|
||||
LOG.debug("Getting port profile binding: %s" % \
|
||||
pp_bind.portprofile_id)
|
||||
ppbinding_dict = {}
|
||||
ppbinding_dict["portprofile-id"] = str(pp_bind.portprofile_id)
|
||||
ppbinding_dict["port-id"] = str(pp_bind.port_id)
|
||||
ppbinding_dict["tenant-id"] = pp_bind.tenant_id
|
||||
ppbinding_dict["default"] = pp_bind.default
|
||||
pp_bindings.append(ppbinding_dict)
|
||||
except Exception, exc:
|
||||
LOG.error("Failed to get all port profiles: %s" % str(exc))
|
||||
return pp_bindings
|
||||
|
||||
def get_pp_binding(self, tenant_id, pp_id):
|
||||
"""Get a portprofile binding"""
|
||||
pp_binding = []
|
||||
try:
|
||||
for pp_bind in l2network_db.get_pp_binding(tenant_id, pp_id):
|
||||
LOG.debug("Getting port profile binding: %s" % \
|
||||
pp_bind.portprofile_id)
|
||||
ppbinding_dict = {}
|
||||
ppbinding_dict["portprofile-id"] = str(pp_bind.portprofile_id)
|
||||
ppbinding_dict["port-id"] = str(pp_bind.port_id)
|
||||
ppbinding_dict["tenant-id"] = pp_bind.tenant_id
|
||||
ppbinding_dict["default"] = pp_bind.default
|
||||
pp_binding.append(ppbinding_dict)
|
||||
except Exception, exc:
|
||||
LOG.error("Failed to get port profile binding: %s" % str(exc))
|
||||
return pp_binding
|
||||
|
||||
def create_pp_binding(self, tenant_id, port_id, pp_id, default):
|
||||
"""Add a portprofile binding"""
|
||||
ppbinding_dict = {}
|
||||
try:
|
||||
res = l2network_db.add_pp_binding(tenant_id, port_id, pp_id, \
|
||||
default)
|
||||
LOG.debug("Created port profile binding: %s" % res.portprofile_id)
|
||||
ppbinding_dict["portprofile-id"] = str(res.portprofile_id)
|
||||
ppbinding_dict["port-id"] = str(res.port_id)
|
||||
ppbinding_dict["tenant-id"] = res.tenant_id
|
||||
ppbinding_dict["default"] = res.default
|
||||
return ppbinding_dict
|
||||
except Exception, exc:
|
||||
LOG.error("Failed to create port profile binding: %s" % str(exc))
|
||||
|
||||
def delete_pp_binding(self, tenant_id, port_id, pp_id):
|
||||
"""Delete a portprofile binding"""
|
||||
try:
|
||||
res = l2network_db.remove_pp_binding(tenant_id, port_id, pp_id)
|
||||
LOG.debug("Deleted port profile binding : %s" % res.portprofile_id)
|
||||
ppbinding_dict = {}
|
||||
ppbinding_dict["portprofile-id"] = str(res.portprofile_id)
|
||||
return ppbinding_dict
|
||||
except Exception, exc:
|
||||
raise Exception("Failed to delete port profile: %s" % str(exc))
|
||||
|
||||
def update_pp_binding(self, tenant_id, pp_id, newtenant_id, \
|
||||
port_id, default):
|
||||
"""Update portprofile binding"""
|
||||
try:
|
||||
res = l2network_db.update_pp_binding(tenant_id, pp_id,
|
||||
newtenant_id, port_id, default)
|
||||
LOG.debug("Updating port profile binding: %s" % res.portprofile_id)
|
||||
ppbinding_dict = {}
|
||||
ppbinding_dict["portprofile-id"] = str(res.portprofile_id)
|
||||
ppbinding_dict["port-id"] = str(res.port_id)
|
||||
ppbinding_dict["tenant-id"] = res.tenant_id
|
||||
ppbinding_dict["default"] = res.default
|
||||
return ppbinding_dict
|
||||
except Exception, exc:
|
||||
raise Exception("Failed to update portprofile binding:%s" \
|
||||
% str(exc))
|
||||
|
||||
|
||||
class QuantumDB(object):
|
||||
"""Class conisting of methods to call Quantum db methods"""
|
||||
def get_all_networks(self, tenant_id):
|
||||
"""Get all networks"""
|
||||
nets = []
|
||||
try:
|
||||
for net in db.network_list(tenant_id):
|
||||
LOG.debug("Getting network: %s" % net.uuid)
|
||||
net_dict = {}
|
||||
net_dict["tenant-id"] = net.tenant_id
|
||||
net_dict["net-id"] = str(net.uuid)
|
||||
net_dict["net-name"] = net.name
|
||||
nets.append(net_dict)
|
||||
except Exception, exc:
|
||||
LOG.error("Failed to get all networks: %s" % str(exc))
|
||||
return nets
|
||||
|
||||
def get_network(self, network_id):
|
||||
"""Get a network"""
|
||||
net = []
|
||||
try:
|
||||
for net in db.network_get(network_id):
|
||||
LOG.debug("Getting network: %s" % net.uuid)
|
||||
net_dict = {}
|
||||
net_dict["tenant-id"] = net.tenant_id
|
||||
net_dict["net-id"] = str(net.uuid)
|
||||
net_dict["net-name"] = net.name
|
||||
net.append(net_dict)
|
||||
except Exception, exc:
|
||||
LOG.error("Failed to get network: %s" % str(exc))
|
||||
return net
|
||||
|
||||
def create_network(self, tenant_id, net_name):
|
||||
"""Create a network"""
|
||||
net_dict = {}
|
||||
try:
|
||||
res = db.network_create(tenant_id, net_name)
|
||||
LOG.debug("Created network: %s" % res.uuid)
|
||||
net_dict["tenant-id"] = res.tenant_id
|
||||
net_dict["net-id"] = str(res.uuid)
|
||||
net_dict["net-name"] = res.name
|
||||
return net_dict
|
||||
except Exception, exc:
|
||||
LOG.error("Failed to create network: %s" % str(exc))
|
||||
|
||||
def delete_network(self, net_id):
|
||||
"""Delete a network"""
|
||||
try:
|
||||
net = db.network_destroy(net_id)
|
||||
LOG.debug("Deleted network: %s" % net.uuid)
|
||||
net_dict = {}
|
||||
net_dict["net-id"] = str(net.uuid)
|
||||
return net_dict
|
||||
except Exception, exc:
|
||||
raise Exception("Failed to delete port: %s" % str(exc))
|
||||
|
||||
def rename_network(self, tenant_id, net_id, new_name):
|
||||
"""Rename a network"""
|
||||
try:
|
||||
net = db.network_rename(tenant_id, net_id, new_name)
|
||||
LOG.debug("Renamed network: %s" % net.uuid)
|
||||
net_dict = {}
|
||||
net_dict["net-id"] = str(net.uuid)
|
||||
net_dict["net-name"] = net.name
|
||||
return net_dict
|
||||
except Exception, exc:
|
||||
raise Exception("Failed to rename network: %s" % str(exc))
|
||||
|
||||
def get_all_ports(self, net_id):
|
||||
"""Get all ports"""
|
||||
ports = []
|
||||
try:
|
||||
for port in db.port_list(net_id):
|
||||
LOG.debug("Getting port: %s" % port.uuid)
|
||||
port_dict = {}
|
||||
port_dict["port-id"] = str(port.uuid)
|
||||
port_dict["net-id"] = str(port.network_id)
|
||||
port_dict["int-id"] = port.interface_id
|
||||
port_dict["state"] = port.state
|
||||
port_dict["net"] = port.network
|
||||
ports.append(port_dict)
|
||||
return ports
|
||||
except Exception, exc:
|
||||
LOG.error("Failed to get all ports: %s" % str(exc))
|
||||
|
||||
def get_port(self, net_id, port_id):
|
||||
"""Get a port"""
|
||||
port_list = []
|
||||
port = db.port_get(net_id, port_id)
|
||||
try:
|
||||
LOG.debug("Getting port: %s" % port.uuid)
|
||||
port_dict = {}
|
||||
port_dict["port-id"] = str(port.uuid)
|
||||
port_dict["net-id"] = str(port.network_id)
|
||||
port_dict["int-id"] = port.interface_id
|
||||
port_dict["state"] = port.state
|
||||
port_list.append(port_dict)
|
||||
return port_list
|
||||
except Exception, exc:
|
||||
LOG.error("Failed to get port: %s" % str(exc))
|
||||
|
||||
def create_port(self, net_id):
|
||||
"""Add a port"""
|
||||
port_dict = {}
|
||||
try:
|
||||
port = db.port_create(net_id)
|
||||
LOG.debug("Creating port %s" % port.uuid)
|
||||
port_dict["port-id"] = str(port.uuid)
|
||||
port_dict["net-id"] = str(port.network_id)
|
||||
port_dict["int-id"] = port.interface_id
|
||||
port_dict["state"] = port.state
|
||||
return port_dict
|
||||
except Exception, exc:
|
||||
LOG.error("Failed to create port: %s" % str(exc))
|
||||
|
||||
def delete_port(self, net_id, port_id):
|
||||
"""Delete a port"""
|
||||
try:
|
||||
port = db.port_destroy(net_id, port_id)
|
||||
LOG.debug("Deleted port %s" % port.uuid)
|
||||
port_dict = {}
|
||||
port_dict["port-id"] = str(port.uuid)
|
||||
return port_dict
|
||||
except Exception, exc:
|
||||
raise Exception("Failed to delete port: %s" % str(exc))
|
||||
|
||||
def update_port(self, net_id, port_id, port_state):
|
||||
"""Update a port"""
|
||||
try:
|
||||
port = db.port_set_state(net_id, port_id, port_state)
|
||||
LOG.debug("Updated port %s" % port.uuid)
|
||||
port_dict = {}
|
||||
port_dict["port-id"] = str(port.uuid)
|
||||
port_dict["net-id"] = str(port.network_id)
|
||||
port_dict["int-id"] = port.interface_id
|
||||
port_dict["state"] = port.state
|
||||
return port_dict
|
||||
except Exception, exc:
|
||||
raise Exception("Failed to update port state: %s" % str(exc))
|
||||
|
||||
def plug_interface(self, net_id, port_id, int_id):
|
||||
"""Plug interface to a port"""
|
||||
try:
|
||||
port = db.port_set_attachment(net_id, port_id, int_id)
|
||||
LOG.debug("Attached interface to port %s" % port.uuid)
|
||||
port_dict = {}
|
||||
port_dict["port-id"] = str(port.uuid)
|
||||
port_dict["net-id"] = str(port.network_id)
|
||||
port_dict["int-id"] = port.interface_id
|
||||
port_dict["state"] = port.state
|
||||
return port_dict
|
||||
except Exception, exc:
|
||||
raise Exception("Failed to plug interface: %s" % str(exc))
|
||||
|
||||
def unplug_interface(self, net_id, port_id):
|
||||
"""Unplug interface to a port"""
|
||||
try:
|
||||
port = db.port_unset_attachment(net_id, port_id)
|
||||
LOG.debug("Detached interface from port %s" % port.uuid)
|
||||
port_dict = {}
|
||||
port_dict["port-id"] = str(port.uuid)
|
||||
port_dict["net-id"] = str(port.network_id)
|
||||
port_dict["int-id"] = port.interface_id
|
||||
port_dict["state"] = port.state
|
||||
return port_dict
|
||||
except Exception, exc:
|
||||
raise Exception("Failed to unplug interface: %s" % str(exc))
|
||||
|
||||
|
||||
class L2networkDBTest(unittest.TestCase):
|
||||
"""Class conisting of L2network DB unit tests"""
|
||||
def setUp(self):
|
||||
"""Setup for tests"""
|
||||
l2network_db.initialize()
|
||||
self.dbtest = L2networkDB()
|
||||
self.quantum = QuantumDB()
|
||||
LOG.debug("Setup")
|
||||
|
||||
def tearDown(self):
|
||||
"""Tear Down"""
|
||||
db.clear_db()
|
||||
|
||||
def testa_create_vlanbinding(self):
|
||||
"""test add vlan binding"""
|
||||
net1 = self.quantum.create_network("t1", "netid1")
|
||||
vlan1 = self.dbtest.create_vlan_binding(10, "vlan1", net1["net-id"])
|
||||
self.assertTrue(vlan1["vlan-id"] == "10")
|
||||
self.teardown_vlanbinding()
|
||||
self.teardown_network()
|
||||
|
||||
def testb_getall_vlanbindings(self):
|
||||
"""test get all vlan binding"""
|
||||
net1 = self.quantum.create_network("t1", "netid1")
|
||||
net2 = self.quantum.create_network("t1", "netid2")
|
||||
vlan1 = self.dbtest.create_vlan_binding(10, "vlan1", net1["net-id"])
|
||||
self.assertTrue(vlan1["vlan-id"] == "10")
|
||||
vlan2 = self.dbtest.create_vlan_binding(20, "vlan2", net2["net-id"])
|
||||
self.assertTrue(vlan2["vlan-id"] == "20")
|
||||
vlans = self.dbtest.get_all_vlan_bindings()
|
||||
count = 0
|
||||
for vlan in vlans:
|
||||
if "vlan" in vlan["vlan-name"]:
|
||||
count += 1
|
||||
self.assertTrue(count == 2)
|
||||
self.teardown_vlanbinding()
|
||||
self.teardown_network()
|
||||
|
||||
def testc_delete_vlanbinding(self):
|
||||
"""test delete vlan binding"""
|
||||
net1 = self.quantum.create_network("t1", "netid1")
|
||||
vlan1 = self.dbtest.create_vlan_binding(10, "vlan1", net1["net-id"])
|
||||
self.assertTrue(vlan1["vlan-id"] == "10")
|
||||
self.dbtest.delete_vlan_binding(net1["net-id"])
|
||||
vlans = self.dbtest.get_all_vlan_bindings()
|
||||
count = 0
|
||||
for vlan in vlans:
|
||||
if "vlan " in vlan["vlan-name"]:
|
||||
count += 1
|
||||
self.assertTrue(count == 0)
|
||||
self.teardown_vlanbinding()
|
||||
self.teardown_network()
|
||||
|
||||
def testd_update_vlanbinding(self):
|
||||
"""test update vlan binding"""
|
||||
net1 = self.quantum.create_network("t1", "netid1")
|
||||
vlan1 = self.dbtest.create_vlan_binding(10, "vlan1", net1["net-id"])
|
||||
self.assertTrue(vlan1["vlan-id"] == "10")
|
||||
vlan1 = self.dbtest.update_vlan_binding(net1["net-id"], 11, "newvlan1")
|
||||
vlans = self.dbtest.get_all_vlan_bindings()
|
||||
count = 0
|
||||
for vlan in vlans:
|
||||
if "new" in vlan["vlan-name"]:
|
||||
count += 1
|
||||
self.assertTrue(count == 1)
|
||||
self.teardown_vlanbinding()
|
||||
self.teardown_network()
|
||||
|
||||
def teste_create_portprofile(self):
|
||||
"""test add port profile"""
|
||||
pp1 = self.dbtest.create_portprofile("t1", "portprofile1", 10, "qos1")
|
||||
self.assertTrue(pp1["portprofile-name"] == "portprofile1")
|
||||
self.teardown_portprofile()
|
||||
self.teardown_network()
|
||||
|
||||
def testf_getall_portprofile(self):
|
||||
"""test get all portprofiles"""
|
||||
pp1 = self.dbtest.create_portprofile("t1", "portprofile1", 10, "qos1")
|
||||
self.assertTrue(pp1["portprofile-name"] == "portprofile1")
|
||||
pp2 = self.dbtest.create_portprofile("t1", "portprofile2", 20, "qos2")
|
||||
self.assertTrue(pp2["portprofile-name"] == "portprofile2")
|
||||
pps = self.dbtest.get_all_portprofiles()
|
||||
count = 0
|
||||
for pprofile in pps:
|
||||
if "portprofile" in pprofile["portprofile-name"]:
|
||||
count += 1
|
||||
self.assertTrue(count == 2)
|
||||
self.teardown_portprofile()
|
||||
|
||||
def testg_delete_portprofile(self):
|
||||
"""test delete portprofile"""
|
||||
pp1 = self.dbtest.create_portprofile("t1", "portprofile1", 10, "qos1")
|
||||
self.assertTrue(pp1["portprofile-name"] == "portprofile1")
|
||||
self.dbtest.delete_portprofile("t1", pp1["portprofile-id"])
|
||||
pps = self.dbtest.get_all_portprofiles()
|
||||
count = 0
|
||||
for pprofile in pps:
|
||||
if "portprofile " in pprofile["portprofile-name"]:
|
||||
count += 1
|
||||
self.assertTrue(count == 0)
|
||||
self.teardown_portprofile()
|
||||
|
||||
def testh_update_portprofile(self):
|
||||
"""test update portprofile"""
|
||||
pp1 = self.dbtest.create_portprofile("t1", "portprofile1", 10, "qos1")
|
||||
self.assertTrue(pp1["portprofile-name"] == "portprofile1")
|
||||
pp1 = self.dbtest.update_portprofile("t1", pp1["portprofile-id"], \
|
||||
"newportprofile1", 20, "qos2")
|
||||
pps = self.dbtest.get_all_portprofiles()
|
||||
count = 0
|
||||
for pprofile in pps:
|
||||
if "new" in pprofile["portprofile-name"]:
|
||||
count += 1
|
||||
self.assertTrue(count == 1)
|
||||
self.teardown_portprofile()
|
||||
|
||||
def testi_create_portprofilebinding(self):
|
||||
"""test create portprofile binding"""
|
||||
net1 = self.quantum.create_network("t1", "netid1")
|
||||
port1 = self.quantum.create_port(net1["net-id"])
|
||||
pp1 = self.dbtest.create_portprofile("t1", "portprofile1", 10, "qos1")
|
||||
pp_binding1 = self.dbtest.create_pp_binding("t1", port1["port-id"], \
|
||||
pp1["portprofile-id"], "0")
|
||||
self.assertTrue(pp_binding1["tenant-id"] == "t1")
|
||||
self.teardown_portprofilebinding()
|
||||
self.teardown_port()
|
||||
self.teardown_network()
|
||||
self.teardown_portprofile()
|
||||
|
||||
def testj_getall_portprofilebinding(self):
|
||||
"""test get all portprofile binding"""
|
||||
net1 = self.quantum.create_network("t1", "netid1")
|
||||
port1 = self.quantum.create_port(net1["net-id"])
|
||||
port2 = self.quantum.create_port(net1["net-id"])
|
||||
pp1 = self.dbtest.create_portprofile("t1", "portprofile1", 10, "qos1")
|
||||
pp2 = self.dbtest.create_portprofile("t1", "portprofile2", 20, "qos2")
|
||||
pp_binding1 = self.dbtest.create_pp_binding("t1", port1["port-id"], \
|
||||
pp1["portprofile-id"], "0")
|
||||
self.assertTrue(pp_binding1["tenant-id"] == "t1")
|
||||
pp_binding2 = self.dbtest.create_pp_binding("t1", port2["port-id"], \
|
||||
pp2["portprofile-id"], "0")
|
||||
self.assertTrue(pp_binding2["tenant-id"] == "t1")
|
||||
pp_bindings = self.dbtest.get_all_pp_bindings()
|
||||
count = 0
|
||||
for pp_bind in pp_bindings:
|
||||
if "t1" in pp_bind["tenant-id"]:
|
||||
count += 1
|
||||
self.assertTrue(count == 2)
|
||||
self.teardown_portprofilebinding()
|
||||
self.teardown_port()
|
||||
self.teardown_network()
|
||||
self.teardown_portprofile()
|
||||
|
||||
def testk_delete_portprofilebinding(self):
|
||||
"""test delete portprofile binding"""
|
||||
net1 = self.quantum.create_network("t1", "netid1")
|
||||
port1 = self.quantum.create_port(net1["net-id"])
|
||||
pp1 = self.dbtest.create_portprofile("t1", "portprofile1", 10, "qos1")
|
||||
pp_binding1 = self.dbtest.create_pp_binding("t1", port1["port-id"], \
|
||||
pp1["portprofile-id"], "0")
|
||||
self.assertTrue(pp_binding1["tenant-id"] == "t1")
|
||||
self.dbtest.delete_pp_binding("t1", port1["port-id"], \
|
||||
pp_binding1["portprofile-id"])
|
||||
pp_bindings = self.dbtest.get_all_pp_bindings()
|
||||
count = 0
|
||||
for pp_bind in pp_bindings:
|
||||
if "t1 " in pp_bind["tenant-id"]:
|
||||
count += 1
|
||||
self.assertTrue(count == 0)
|
||||
self.teardown_portprofilebinding()
|
||||
self.teardown_port()
|
||||
self.teardown_network()
|
||||
self.teardown_portprofile()
|
||||
|
||||
def testl_update_portprofilebinding(self):
|
||||
"""test update portprofile binding"""
|
||||
net1 = self.quantum.create_network("t1", "netid1")
|
||||
port1 = self.quantum.create_port(net1["net-id"])
|
||||
pp1 = self.dbtest.create_portprofile("t1", "portprofile1", 10, "qos1")
|
||||
pp_binding1 = self.dbtest.create_pp_binding("t1", port1["port-id"], \
|
||||
pp1["portprofile-id"], "0")
|
||||
self.assertTrue(pp_binding1["tenant-id"] == "t1")
|
||||
pp_binding1 = self.dbtest.update_pp_binding("t1", \
|
||||
pp1["portprofile-id"], "newt1", port1["port-id"], "1")
|
||||
pp_bindings = self.dbtest.get_all_pp_bindings()
|
||||
count = 0
|
||||
for pp_bind in pp_bindings:
|
||||
if "new" in pp_bind["tenant-id"]:
|
||||
count += 1
|
||||
self.assertTrue(count == 1)
|
||||
self.teardown_portprofilebinding()
|
||||
self.teardown_port()
|
||||
self.teardown_network()
|
||||
self.teardown_portprofile()
|
||||
|
||||
def testm_test_vlanids(self):
|
||||
"""test vlanid methods"""
|
||||
l2network_db.create_vlanids()
|
||||
vlanids = l2network_db.get_all_vlanids()
|
||||
self.assertTrue(len(vlanids) > 0)
|
||||
vlanid = l2network_db.reserve_vlanid()
|
||||
used = l2network_db.is_vlanid_used(vlanid)
|
||||
self.assertTrue(used == True)
|
||||
used = l2network_db.release_vlanid(vlanid)
|
||||
self.assertTrue(used == False)
|
||||
self.teardown_vlanid()
|
||||
|
||||
def teardown_network(self):
|
||||
"""tearDown Network table"""
|
||||
LOG.debug("Tearing Down Network")
|
||||
nets = self.quantum.get_all_networks("t1")
|
||||
for net in nets:
|
||||
netid = net["net-id"]
|
||||
self.quantum.delete_network(netid)
|
||||
|
||||
def teardown_port(self):
|
||||
"""tearDown Port table"""
|
||||
LOG.debug("Tearing Down Port")
|
||||
nets = self.quantum.get_all_networks("t1")
|
||||
for net in nets:
|
||||
netid = net["net-id"]
|
||||
ports = self.quantum.get_all_ports(netid)
|
||||
for port in ports:
|
||||
portid = port["port-id"]
|
||||
self.quantum.delete_port(netid, portid)
|
||||
|
||||
def teardown_vlanbinding(self):
|
||||
"""tearDown VlanBinding table"""
|
||||
LOG.debug("Tearing Down Vlan Binding")
|
||||
vlans = self.dbtest.get_all_vlan_bindings()
|
||||
for vlan in vlans:
|
||||
netid = vlan["net-id"]
|
||||
self.dbtest.delete_vlan_binding(netid)
|
||||
|
||||
def teardown_portprofile(self):
|
||||
"""tearDown PortProfile table"""
|
||||
LOG.debug("Tearing Down Port Profile")
|
||||
pps = self.dbtest.get_all_portprofiles()
|
||||
for pprofile in pps:
|
||||
ppid = pprofile["portprofile-id"]
|
||||
self.dbtest.delete_portprofile("t1", ppid)
|
||||
|
||||
def teardown_portprofilebinding(self):
|
||||
"""tearDown PortProfileBinding table"""
|
||||
LOG.debug("Tearing Down Port Profile Binding")
|
||||
pp_bindings = self.dbtest.get_all_pp_bindings()
|
||||
for pp_binding in pp_bindings:
|
||||
ppid = pp_binding["portprofile-id"]
|
||||
portid = pp_binding["port-id"]
|
||||
self.dbtest.delete_pp_binding("t1", portid, ppid)
|
||||
|
||||
def teardown_vlanid(self):
|
||||
"""tearDown VlanID table"""
|
||||
LOG.debug("Tearing Down Vlan IDs")
|
||||
vlanids = l2network_db.get_all_vlanids()
|
||||
for vlanid in vlanids:
|
||||
vlan_id = vlanid["vlan_id"]
|
||||
l2network_db.delete_vlanid(vlan_id)
|
||||
|
||||
|
||||
class QuantumDBTest(unittest.TestCase):
|
||||
"""Class conisting of Quantum DB unit tests"""
|
||||
def setUp(self):
|
||||
"""Setup for tests"""
|
||||
l2network_db.initialize()
|
||||
self.dbtest = QuantumDB()
|
||||
self.tenant_id = "t1"
|
||||
LOG.debug("Setup")
|
||||
|
||||
def tearDown(self):
|
||||
"""Tear Down"""
|
||||
db.clear_db()
|
||||
|
||||
def testa_create_network(self):
|
||||
"""test to create network"""
|
||||
net1 = self.dbtest.create_network(self.tenant_id, "plugin_test1")
|
||||
self.assertTrue(net1["net-name"] == "plugin_test1")
|
||||
self.teardown_network_port()
|
||||
|
||||
def testb_get_networks(self):
|
||||
"""test to get all networks"""
|
||||
net1 = self.dbtest.create_network(self.tenant_id, "plugin_test1")
|
||||
self.assertTrue(net1["net-name"] == "plugin_test1")
|
||||
net2 = self.dbtest.create_network(self.tenant_id, "plugin_test2")
|
||||
self.assertTrue(net2["net-name"] == "plugin_test2")
|
||||
nets = self.dbtest.get_all_networks(self.tenant_id)
|
||||
count = 0
|
||||
for net in nets:
|
||||
if "plugin_test" in net["net-name"]:
|
||||
count += 1
|
||||
self.assertTrue(count == 2)
|
||||
self.teardown_network_port()
|
||||
|
||||
def testc_delete_network(self):
|
||||
"""test to delete network"""
|
||||
net1 = self.dbtest.create_network(self.tenant_id, "plugin_test1")
|
||||
self.assertTrue(net1["net-name"] == "plugin_test1")
|
||||
self.dbtest.delete_network(net1["net-id"])
|
||||
nets = self.dbtest.get_all_networks(self.tenant_id)
|
||||
count = 0
|
||||
for net in nets:
|
||||
if "plugin_test1" in net["net-name"]:
|
||||
count += 1
|
||||
self.assertTrue(count == 0)
|
||||
self.teardown_network_port()
|
||||
|
||||
def testd_rename_network(self):
|
||||
"""test to rename network"""
|
||||
net1 = self.dbtest.create_network(self.tenant_id, "plugin_test1")
|
||||
self.assertTrue(net1["net-name"] == "plugin_test1")
|
||||
net = self.dbtest.rename_network(self.tenant_id, net1["net-id"],
|
||||
"plugin_test1_renamed")
|
||||
self.assertTrue(net["net-name"] == "plugin_test1_renamed")
|
||||
self.teardown_network_port()
|
||||
|
||||
def teste_create_port(self):
|
||||
"""test to create port"""
|
||||
net1 = self.dbtest.create_network(self.tenant_id, "plugin_test1")
|
||||
port = self.dbtest.create_port(net1["net-id"])
|
||||
self.assertTrue(port["net-id"] == net1["net-id"])
|
||||
ports = self.dbtest.get_all_ports(net1["net-id"])
|
||||
count = 0
|
||||
for por in ports:
|
||||
count += 1
|
||||
self.assertTrue(count == 1)
|
||||
self.teardown_network_port()
|
||||
|
||||
def testf_delete_port(self):
|
||||
"""test to delete port"""
|
||||
net1 = self.dbtest.create_network(self.tenant_id, "plugin_test1")
|
||||
port = self.dbtest.create_port(net1["net-id"])
|
||||
self.assertTrue(port["net-id"] == net1["net-id"])
|
||||
ports = self.dbtest.get_all_ports(net1["net-id"])
|
||||
count = 0
|
||||
for por in ports:
|
||||
count += 1
|
||||
self.assertTrue(count == 1)
|
||||
for por in ports:
|
||||
self.dbtest.delete_port(net1["net-id"], por["port-id"])
|
||||
ports = self.dbtest.get_all_ports(net1["net-id"])
|
||||
count = 0
|
||||
for por in ports:
|
||||
count += 1
|
||||
self.assertTrue(count == 0)
|
||||
self.teardown_network_port()
|
||||
|
||||
def testg_plug_unplug_interface(self):
|
||||
"""test to plug/unplug interface"""
|
||||
net1 = self.dbtest.create_network(self.tenant_id, "plugin_test1")
|
||||
port1 = self.dbtest.create_port(net1["net-id"])
|
||||
self.dbtest.plug_interface(net1["net-id"], port1["port-id"], "vif1.1")
|
||||
port = self.dbtest.get_port(net1["net-id"], port1["port-id"])
|
||||
self.assertTrue(port[0]["int-id"] == "vif1.1")
|
||||
self.dbtest.unplug_interface(net1["net-id"], port1["port-id"])
|
||||
port = self.dbtest.get_port(net1["net-id"], port1["port-id"])
|
||||
self.assertTrue(port[0]["int-id"] == None)
|
||||
self.teardown_network_port()
|
||||
|
||||
def testh_joined_test(self):
|
||||
"""test to get network and port"""
|
||||
net1 = self.dbtest.create_network("t1", "net1")
|
||||
port1 = self.dbtest.create_port(net1["net-id"])
|
||||
self.assertTrue(port1["net-id"] == net1["net-id"])
|
||||
port2 = self.dbtest.create_port(net1["net-id"])
|
||||
self.assertTrue(port2["net-id"] == net1["net-id"])
|
||||
ports = self.dbtest.get_all_ports(net1["net-id"])
|
||||
for port in ports:
|
||||
net = port["net"]
|
||||
LOG.debug("Port id %s Net id %s" % (port["port-id"], net.uuid))
|
||||
self.teardown_joined_test()
|
||||
|
||||
def teardown_network_port(self):
|
||||
"""tearDown for Network and Port table"""
|
||||
networks = self.dbtest.get_all_networks(self.tenant_id)
|
||||
for net in networks:
|
||||
netid = net["net-id"]
|
||||
name = net["net-name"]
|
||||
if "plugin_test" in name:
|
||||
ports = self.dbtest.get_all_ports(netid)
|
||||
for por in ports:
|
||||
self.dbtest.delete_port(netid, por["port-id"])
|
||||
self.dbtest.delete_network(netid)
|
||||
|
||||
def teardown_joined_test(self):
|
||||
"""tearDown for joined Network and Port test"""
|
||||
LOG.debug("Tearing Down Network and Ports")
|
||||
nets = self.dbtest.get_all_networks("t1")
|
||||
for net in nets:
|
||||
netid = net["net-id"]
|
||||
ports = self.dbtest.get_all_ports(netid)
|
||||
for port in ports:
|
||||
self.dbtest.delete_port(port["net-id"], port["port-id"])
|
||||
self.dbtest.delete_network(netid)
|
||||
|
||||
"""
|
||||
if __name__ == "__main__":
|
||||
usagestr = "Usage: %prog [OPTIONS] <command> [args]"
|
||||
parser = OptionParser(usage=usagestr)
|
||||
parser.add_option("-v", "--verbose", dest="verbose",
|
||||
action="store_true", default=False, help="turn on verbose logging")
|
||||
|
||||
options, args = parser.parse_args()
|
||||
|
||||
if options.verbose:
|
||||
LOG.basicConfig(level=LOG.DEBUG)
|
||||
else:
|
||||
LOG.basicConfig(level=LOG.WARN)
|
||||
|
||||
l2network_db.initialize()
|
||||
|
||||
# Run the tests
|
||||
suite = unittest.TestLoader().loadTestsFromTestCase(QuantumDBTest)
|
||||
unittest.TextTestRunner(verbosity=2).run(suite)
|
||||
suite = unittest.TestLoader().loadTestsFromTestCase(L2networkDBTest)
|
||||
unittest.TextTestRunner(verbosity=2).run(suite)
|
||||
"""
|
|
@ -24,6 +24,8 @@ from quantum.plugins.cisco.common import cisco_constants as const
|
|||
from quantum.plugins.cisco.common import cisco_exceptions as cexc
|
||||
from quantum.plugins.cisco import l2network_plugin
|
||||
from quantum.plugins.cisco import l2network_plugin_configuration as conf
|
||||
from quantum.plugins.cisco.db import api as db
|
||||
from quantum.plugins.cisco.db import l2network_db as cdb
|
||||
|
||||
LOG = logging.getLogger('quantum.tests.test_core_api_func')
|
||||
|
||||
|
@ -47,6 +49,8 @@ class CoreAPITestFunc(unittest.TestCase):
|
|||
network_name = self.network_name
|
||||
new_net_dict = self._l2network_plugin.create_network(
|
||||
tenant_id, network_name)
|
||||
net = db.network_get(new_net_dict[const.NET_ID])
|
||||
self.assertEqual(net[const.NETWORKNAME], network_name)
|
||||
self.assertEqual(new_net_dict[const.NET_NAME], network_name)
|
||||
self.tearDownNetwork(tenant_id, new_net_dict[const.NET_ID])
|
||||
LOG.debug("test_create_network - END")
|
||||
|
@ -64,6 +68,8 @@ class CoreAPITestFunc(unittest.TestCase):
|
|||
tenant_id, self.network_name)
|
||||
delete_net_dict = self._l2network_plugin.delete_network(
|
||||
tenant_id, new_net_dict[const.NET_ID])
|
||||
self.assertRaises(exc.NetworkNotFound, db.network_get,
|
||||
new_net_dict[const.NET_ID])
|
||||
self.assertEqual(
|
||||
new_net_dict[const.NET_ID], delete_net_dict[const.NET_ID])
|
||||
LOG.debug("test_delete_network - END")
|
||||
|
@ -117,6 +123,8 @@ class CoreAPITestFunc(unittest.TestCase):
|
|||
tenant_id, self.network_name)
|
||||
result_net_dict = self._l2network_plugin.get_network_details(
|
||||
tenant_id, new_net_dict[const.NET_ID])
|
||||
net = db.network_get(new_net_dict[const.NET_ID])
|
||||
self.assertEqual(net[const.UUID], new_net_dict[const.NET_ID])
|
||||
self.assertEqual(
|
||||
new_net_dict[const.NET_ID], result_net_dict[const.NET_ID])
|
||||
self.tearDownNetwork(tenant_id, new_net_dict[const.NET_ID])
|
||||
|
@ -152,6 +160,8 @@ class CoreAPITestFunc(unittest.TestCase):
|
|||
tenant_id, self.network_name)
|
||||
rename_net_dict = self._l2network_plugin.rename_network(
|
||||
tenant_id, new_net_dict[const.NET_ID], new_name)
|
||||
net = db.network_get(new_net_dict[const.NET_ID])
|
||||
self.assertEqual(net[const.NETWORKNAME], new_name)
|
||||
self.assertEqual(new_name, rename_net_dict[const.NET_NAME])
|
||||
self.tearDownNetwork(tenant_id, new_net_dict[const.NET_ID])
|
||||
LOG.debug("test_rename_network - END")
|
||||
|
@ -184,9 +194,18 @@ class CoreAPITestFunc(unittest.TestCase):
|
|||
tenant_id, 'test_net2')
|
||||
net_list = self._l2network_plugin.get_all_networks(tenant_id)
|
||||
net_temp_list = [new_net_dict, new_net_dict2]
|
||||
networks_list = db.network_list(tenant_id)
|
||||
new_networks_list = []
|
||||
for network in networks_list:
|
||||
new_network_dict = self._make_net_dict(network[const.UUID],
|
||||
network[const.NETWORKNAME],
|
||||
[])
|
||||
new_networks_list.append(new_network_dict)
|
||||
self.assertEqual(len(net_list), 2)
|
||||
self.assertTrue(net_list[0] in net_temp_list)
|
||||
self.assertTrue(net_list[1] in net_temp_list)
|
||||
self.assertTrue(new_networks_list[0] in net_temp_list)
|
||||
self.assertTrue(new_networks_list[1] in net_temp_list)
|
||||
self.tearDownNetwork(tenant_id, new_net_dict[const.NET_ID])
|
||||
self.tearDownNetwork(tenant_id, new_net_dict2[const.NET_ID])
|
||||
LOG.debug("test_list_networks - END")
|
||||
|
@ -206,9 +225,20 @@ class CoreAPITestFunc(unittest.TestCase):
|
|||
port_list = self._l2network_plugin.get_all_ports(
|
||||
tenant_id, new_net_dict[const.NET_ID])
|
||||
port_temp_list = [port_dict, port_dict2]
|
||||
network = db.network_get(new_net_dict[const.NET_ID])
|
||||
ports_list = network[const.NETWORKPORTS]
|
||||
ports_on_net = []
|
||||
for port in ports_list:
|
||||
new_port = self._make_port_dict(port[const.UUID],
|
||||
port[const.PORTSTATE],
|
||||
port[const.NETWORKID],
|
||||
port[const.INTERFACEID])
|
||||
ports_on_net.append(new_port)
|
||||
self.assertEqual(len(port_list), 2)
|
||||
self.assertTrue(port_list[0] in port_temp_list)
|
||||
self.assertTrue(port_list[1] in port_temp_list)
|
||||
self.assertTrue(ports_on_net[0] in port_temp_list)
|
||||
self.assertTrue(ports_on_net[1] in port_temp_list)
|
||||
|
||||
self.tearDownPortOnly(tenant_id, new_net_dict[const.NET_ID],
|
||||
port_dict[const.PORT_ID])
|
||||
|
@ -227,7 +257,12 @@ class CoreAPITestFunc(unittest.TestCase):
|
|||
tenant_id, self.network_name)
|
||||
port_dict = self._l2network_plugin.create_port(
|
||||
tenant_id, new_net_dict[const.NET_ID], port_state)
|
||||
port = db.port_get(new_net_dict[const.NET_ID],
|
||||
port_dict[const.PORT_ID])
|
||||
self.assertEqual(port_dict[const.PORT_STATE], port_state)
|
||||
self.assertEqual(port_dict[const.NET_ID], new_net_dict[const.NET_ID])
|
||||
self.assertEqual(port[const.PORTSTATE], port_state)
|
||||
self.assertEqual(port[const.NETWORKID], new_net_dict[const.NET_ID])
|
||||
self.tearDownNetworkPort(tenant_id, new_net_dict[const.NET_ID],
|
||||
port_dict[const.PORT_ID])
|
||||
LOG.debug("test_create_port - END")
|
||||
|
@ -263,8 +298,11 @@ class CoreAPITestFunc(unittest.TestCase):
|
|||
delete_port_dict = self._l2network_plugin.delete_port(
|
||||
tenant_id, new_net_dict[const.NET_ID],
|
||||
port_dict[const.PORT_ID])
|
||||
self.assertRaises(exc.PortNotFound, db.port_get,
|
||||
new_net_dict[const.NET_ID], port_dict[const.PORT_ID])
|
||||
self.tearDownNetwork(tenant_id, new_net_dict[const.NET_ID])
|
||||
self.assertEqual(delete_port_dict, None)
|
||||
self.assertEqual(delete_port_dict[const.PORT_ID],
|
||||
port_dict[const.PORT_ID])
|
||||
LOG.debug("test_delete_port - END")
|
||||
|
||||
def test_delete_port_networkDNE(self, tenant_id='test_tenant',
|
||||
|
@ -327,6 +365,9 @@ class CoreAPITestFunc(unittest.TestCase):
|
|||
update_port_dict = self._l2network_plugin.update_port(
|
||||
tenant_id, new_net_dict[const.NET_ID],
|
||||
port_dict[const.PORT_ID], port_state)
|
||||
new_port = db.port_get(new_net_dict[const.NET_ID],
|
||||
port_dict[const.PORT_ID])
|
||||
self.assertEqual(new_port[const.PORTSTATE], port_state)
|
||||
self.assertEqual(update_port_dict[const.PORT_STATE], port_state)
|
||||
self.tearDownNetworkPort(tenant_id, new_net_dict[const.NET_ID],
|
||||
port_dict[const.PORT_ID])
|
||||
|
@ -341,7 +382,7 @@ class CoreAPITestFunc(unittest.TestCase):
|
|||
LOG.debug("test_update_port_networkDNE - START")
|
||||
self.assertRaises(exc.NetworkNotFound,
|
||||
self._l2network_plugin.update_port, tenant_id,
|
||||
net_id, port_id, self.port_state)
|
||||
net_id, port_id, const.PORT_UP)
|
||||
LOG.debug("test_update_port_networkDNE - END")
|
||||
|
||||
def test_update_portDNE(self, tenant_id='test_tenant', port_id='p0005'):
|
||||
|
@ -354,7 +395,7 @@ class CoreAPITestFunc(unittest.TestCase):
|
|||
tenant_id, self.network_name)
|
||||
self.assertRaises(
|
||||
exc.PortNotFound, self._l2network_plugin.update_port, tenant_id,
|
||||
new_net_dict[const.NET_ID], port_id, self.port_state)
|
||||
new_net_dict[const.NET_ID], port_id, const.PORT_UP)
|
||||
self.tearDownNetwork(tenant_id, new_net_dict[const.NET_ID])
|
||||
LOG.debug("test_update_portDNE - END")
|
||||
|
||||
|
@ -371,6 +412,9 @@ class CoreAPITestFunc(unittest.TestCase):
|
|||
get_port_dict = self._l2network_plugin.get_port_details(
|
||||
tenant_id, new_net_dict[const.NET_ID],
|
||||
port_dict[const.PORT_ID])
|
||||
port = db.port_get(new_net_dict[const.NET_ID],
|
||||
port_dict[const.PORT_ID])
|
||||
self.assertEqual(port[const.PORTSTATE], self.port_state)
|
||||
self.assertEqual(get_port_dict[const.PORT_STATE], self.port_state)
|
||||
self.tearDownNetworkPort(tenant_id, new_net_dict[const.NET_ID],
|
||||
port_dict[const.PORT_ID])
|
||||
|
@ -416,10 +460,9 @@ class CoreAPITestFunc(unittest.TestCase):
|
|||
self._l2network_plugin.plug_interface(
|
||||
tenant_id, new_net_dict[const.NET_ID],
|
||||
port_dict[const.PORT_ID], remote_interface)
|
||||
self.assertEqual(
|
||||
self._l2network_plugin._networks[new_net_dict[const.NET_ID]]
|
||||
[const.NET_PORTS][port_dict[const.PORT_ID]]
|
||||
[const.ATTACHMENT], remote_interface)
|
||||
port = db.port_get(new_net_dict[const.NET_ID],
|
||||
port_dict[const.PORT_ID])
|
||||
self.assertEqual(port[const.INTERFACEID], remote_interface)
|
||||
self.tearDownNetworkPortInterface(
|
||||
tenant_id, new_net_dict[const.NET_ID],
|
||||
port_dict[const.PORT_ID])
|
||||
|
@ -470,7 +513,7 @@ class CoreAPITestFunc(unittest.TestCase):
|
|||
self._l2network_plugin.plug_interface(
|
||||
tenant_id, new_net_dict[const.NET_ID],
|
||||
port_dict[const.PORT_ID], remote_interface)
|
||||
self.assertRaises(exc.AlreadyAttached,
|
||||
self.assertRaises(exc.PortInUse,
|
||||
self._l2network_plugin.plug_interface, tenant_id,
|
||||
new_net_dict[const.NET_ID],
|
||||
port_dict[const.PORT_ID], remote_interface)
|
||||
|
@ -496,9 +539,9 @@ class CoreAPITestFunc(unittest.TestCase):
|
|||
self._l2network_plugin.unplug_interface(
|
||||
tenant_id, new_net_dict[const.NET_ID],
|
||||
port_dict[const.PORT_ID])
|
||||
self.assertEqual(self._l2network_plugin._networks
|
||||
[new_net_dict[const.NET_ID]][const.NET_PORTS]
|
||||
[port_dict[const.PORT_ID]][const.ATTACHMENT], None)
|
||||
port = db.port_get(new_net_dict[const.NET_ID],
|
||||
port_dict[const.PORT_ID])
|
||||
self.assertEqual(port[const.INTERFACEID], None)
|
||||
self.tearDownNetworkPort(tenant_id, new_net_dict[const.NET_ID],
|
||||
port_dict[const.PORT_ID])
|
||||
LOG.debug("test_unplug_interface - END")
|
||||
|
@ -533,7 +576,7 @@ class CoreAPITestFunc(unittest.TestCase):
|
|||
LOG.debug("test_unplug_interface_portDNE - END")
|
||||
|
||||
def test_create_portprofile(self, net_tenant_id=None,
|
||||
net_profile_name=None, net_vlan_id=None):
|
||||
net_profile_name=None, net_qos=None):
|
||||
"""
|
||||
Tests creation of a port-profile
|
||||
"""
|
||||
|
@ -548,19 +591,16 @@ class CoreAPITestFunc(unittest.TestCase):
|
|||
profile_name = net_profile_name
|
||||
else:
|
||||
profile_name = self.profile_name
|
||||
if net_vlan_id:
|
||||
vlan_id = net_vlan_id
|
||||
if net_qos:
|
||||
qos = net_qos
|
||||
else:
|
||||
vlan_id = self.vlan_id
|
||||
qos = self.qos
|
||||
port_profile_dict = self._l2network_plugin.create_portprofile(
|
||||
tenant_id, profile_name, vlan_id)
|
||||
tenant_id, profile_name, qos)
|
||||
port_profile_id = port_profile_dict['profile-id']
|
||||
self.assertEqual(
|
||||
self._l2network_plugin._portprofiles[port_profile_id]['vlan-id'],
|
||||
vlan_id)
|
||||
self.assertEqual(
|
||||
self._l2network_plugin._portprofiles[port_profile_id]
|
||||
['profile-name'], profile_name)
|
||||
port_profile = cdb.get_portprofile(tenant_id, port_profile_id)
|
||||
self.assertEqual(port_profile[const.PPNAME], profile_name)
|
||||
self.assertEqual(port_profile[const.PPQOS], qos)
|
||||
self.tearDownPortProfile(tenant_id, port_profile_id)
|
||||
LOG.debug("test_create_portprofile - tenant id: %s - END",
|
||||
net_tenant_id)
|
||||
|
@ -577,10 +617,10 @@ class CoreAPITestFunc(unittest.TestCase):
|
|||
else:
|
||||
tenant_id = self.tenant_id
|
||||
port_profile_dict = self._l2network_plugin.create_portprofile(
|
||||
tenant_id, self.profile_name, self.vlan_id)
|
||||
tenant_id, self.profile_name, self.qos)
|
||||
port_profile_id = port_profile_dict['profile-id']
|
||||
self._l2network_plugin.delete_portprofile(tenant_id, port_profile_id)
|
||||
self.assertEqual(self._l2network_plugin._portprofiles, {})
|
||||
self.assertRaises(Exception, cdb.get_portprofile, port_profile_id)
|
||||
LOG.debug("test_delete_portprofile - tenant id: %s - END",
|
||||
net_tenant_id)
|
||||
|
||||
|
@ -604,15 +644,23 @@ class CoreAPITestFunc(unittest.TestCase):
|
|||
|
||||
LOG.debug("test_delete_portprofileAssociated - START")
|
||||
port_profile_dict = self._l2network_plugin.create_portprofile(
|
||||
tenant_id, self.profile_name, self.vlan_id)
|
||||
tenant_id, self.profile_name, self.qos)
|
||||
port_profile_id = port_profile_dict['profile-id']
|
||||
new_net_dict = self._l2network_plugin.create_network(
|
||||
tenant_id, 'test_network')
|
||||
port_dict = self._l2network_plugin.create_port(
|
||||
tenant_id, new_net_dict[const.NET_ID], 'const.PORT_UP')
|
||||
self._l2network_plugin.associate_portprofile(
|
||||
tenant_id, self.net_id, self.port_id, port_profile_id)
|
||||
tenant_id, new_net_dict[const.NET_ID],
|
||||
port_dict[const.PORT_ID], port_profile_id)
|
||||
self.assertRaises(cexc.PortProfileInvalidDelete,
|
||||
self._l2network_plugin.delete_portprofile,
|
||||
tenant_id, port_profile_id)
|
||||
self.tearDownAssociatePortProfile(tenant_id, self.net_id,
|
||||
self.port_id, port_profile_id)
|
||||
self.tearDownAssociatePortProfile(
|
||||
tenant_id, new_net_dict[const.NET_ID],
|
||||
port_dict[const.PORT_ID], port_profile_id)
|
||||
self.tearDownNetworkPort(tenant_id, new_net_dict[const.NET_ID],
|
||||
port_dict[const.PORT_ID])
|
||||
LOG.debug("test_delete_portprofileAssociated - END")
|
||||
|
||||
def test_list_portprofile(self, tenant_id='test_tenant'):
|
||||
|
@ -622,24 +670,30 @@ class CoreAPITestFunc(unittest.TestCase):
|
|||
|
||||
LOG.debug("test_list_portprofile - tenant id: %s - START", tenant_id)
|
||||
profile_name2 = tenant_id + '_port_profile2'
|
||||
vlan_id2 = tenant_id + '201'
|
||||
qos2 = tenant_id + 'qos2'
|
||||
port_profile_dict1 = self._l2network_plugin.create_portprofile(
|
||||
tenant_id, self.profile_name, self.vlan_id)
|
||||
tenant_id, self.profile_name, self.qos)
|
||||
port_profile_dict2 = self._l2network_plugin.create_portprofile(
|
||||
tenant_id, profile_name2, vlan_id2)
|
||||
tenant_id, profile_name2, qos2)
|
||||
port_profile_id1 = port_profile_dict1['profile-id']
|
||||
port_profile_id2 = port_profile_dict2['profile-id']
|
||||
list_all_portprofiles = self._l2network_plugin.get_all_portprofiles(
|
||||
tenant_id)
|
||||
self.assertEqual(self._l2network_plugin._portprofiles
|
||||
[port_profile_id1]['vlan-id'], self.vlan_id)
|
||||
self.assertEqual(self._l2network_plugin._portprofiles
|
||||
[port_profile_id1]['profile-name'], self.profile_name)
|
||||
self.assertEqual(self._l2network_plugin._portprofiles
|
||||
[port_profile_id2]['vlan-id'], vlan_id2)
|
||||
self.assertEqual(self._l2network_plugin._portprofiles
|
||||
[port_profile_id2]['profile-name'], profile_name2)
|
||||
LOG.debug("test_create_portprofile - tenant id: %s - END", tenant_id)
|
||||
port_profile_list = [port_profile_dict1, port_profile_dict2]
|
||||
pplist = cdb.get_all_portprofiles()
|
||||
new_pplist = []
|
||||
for pp in pplist:
|
||||
new_pp = self._make_portprofile_dict(tenant_id,
|
||||
pp[const.UUID],
|
||||
pp[const.PPNAME],
|
||||
pp[const.PPQOS])
|
||||
new_pplist.append(new_pp)
|
||||
self.assertTrue(new_pplist[0] in port_profile_list)
|
||||
self.assertTrue(new_pplist[1] in port_profile_list)
|
||||
self.tearDownPortProfile(tenant_id, port_profile_id1)
|
||||
self.tearDownPortProfile(tenant_id, port_profile_id2)
|
||||
|
||||
LOG.debug("test_list_portprofile - tenant id: %s - END", tenant_id)
|
||||
|
||||
def test_show_portprofile(self, net_tenant_id=None):
|
||||
"""
|
||||
|
@ -652,12 +706,15 @@ class CoreAPITestFunc(unittest.TestCase):
|
|||
else:
|
||||
tenant_id = self.tenant_id
|
||||
port_profile_dict = self._l2network_plugin.create_portprofile(
|
||||
tenant_id, self.profile_name, self.vlan_id)
|
||||
tenant_id, self.profile_name, self.qos)
|
||||
port_profile_id = port_profile_dict['profile-id']
|
||||
result_port_profile = self._l2network_plugin.get_portprofile_details(
|
||||
tenant_id, port_profile_id)
|
||||
self.assertEqual(result_port_profile[const.PROFILE_VLAN_ID],
|
||||
self.vlan_id)
|
||||
port_profile = cdb.get_portprofile(tenant_id, port_profile_id)
|
||||
self.assertEqual(port_profile[const.PPQOS], self.qos)
|
||||
self.assertEqual(port_profile[const.PPNAME], self.profile_name)
|
||||
self.assertEqual(result_port_profile[const.PROFILE_QOS],
|
||||
self.qos)
|
||||
self.assertEqual(result_port_profile[const.PROFILE_NAME],
|
||||
self.profile_name)
|
||||
self.tearDownPortProfile(tenant_id, port_profile_id)
|
||||
|
@ -670,7 +727,7 @@ class CoreAPITestFunc(unittest.TestCase):
|
|||
"""
|
||||
|
||||
LOG.debug("test_show_portprofileDNE - START")
|
||||
self.assertRaises(cexc.PortProfileNotFound,
|
||||
self.assertRaises(Exception,
|
||||
self._l2network_plugin.get_portprofile_details,
|
||||
tenant_id, profile_id)
|
||||
LOG.debug("test_show_portprofileDNE - END")
|
||||
|
@ -683,10 +740,12 @@ class CoreAPITestFunc(unittest.TestCase):
|
|||
|
||||
LOG.debug("test_rename_portprofile - START")
|
||||
port_profile_dict = self._l2network_plugin.create_portprofile(
|
||||
tenant_id, self.profile_name, self.vlan_id)
|
||||
tenant_id, self.profile_name, self.qos)
|
||||
port_profile_id = port_profile_dict['profile-id']
|
||||
result_port_profile_dict = self._l2network_plugin.rename_portprofile(
|
||||
tenant_id, port_profile_id, new_profile_name)
|
||||
port_profile = cdb.get_portprofile(tenant_id, port_profile_id)
|
||||
self.assertEqual(port_profile[const.PPNAME], new_profile_name)
|
||||
self.assertEqual(result_port_profile_dict[const.PROFILE_NAME],
|
||||
new_profile_name)
|
||||
self.tearDownPortProfile(tenant_id, port_profile_id)
|
||||
|
@ -705,23 +764,32 @@ class CoreAPITestFunc(unittest.TestCase):
|
|||
tenant_id, profile_id, new_profile_name)
|
||||
LOG.debug("test_rename_portprofileDNE - END")
|
||||
|
||||
def test_associate_portprofile(self, tenant_id='test_tenant',
|
||||
net_id='0005', port_id='p00005'):
|
||||
def test_associate_portprofile(self, tenant_id='test_tenant'):
|
||||
"""
|
||||
Tests association of a port-profile
|
||||
"""
|
||||
|
||||
LOG.debug("test_associate_portprofile - START")
|
||||
new_net_dict = self._l2network_plugin.create_network(
|
||||
tenant_id, self.network_name)
|
||||
port_dict = self._l2network_plugin.create_port(
|
||||
tenant_id, new_net_dict[const.NET_ID],
|
||||
self.port_state)
|
||||
port_profile_dict = self._l2network_plugin.create_portprofile(
|
||||
tenant_id, self.profile_name, self.vlan_id)
|
||||
tenant_id, self.profile_name, self.qos)
|
||||
port_profile_id = port_profile_dict['profile-id']
|
||||
self._l2network_plugin.associate_portprofile(
|
||||
tenant_id, net_id, port_id, port_profile_id)
|
||||
self.assertEqual(
|
||||
self._l2network_plugin._portprofiles[port_profile_id]
|
||||
[const.PROFILE_ASSOCIATIONS][0], port_id)
|
||||
self.tearDownAssociatePortProfile(tenant_id, net_id,
|
||||
port_id, port_profile_id)
|
||||
tenant_id, new_net_dict[const.NET_ID],
|
||||
port_dict[const.PORT_ID], port_profile_id)
|
||||
port_profile_associate = cdb.get_pp_binding(tenant_id, port_profile_id)
|
||||
self.assertEqual(port_profile_associate[const.PORTID],
|
||||
port_dict[const.PORT_ID])
|
||||
self.tearDownAssociatePortProfile(
|
||||
tenant_id, new_net_dict[const.NET_ID],
|
||||
port_dict[const.PORT_ID], port_profile_id)
|
||||
self.tearDownNetworkPort(
|
||||
tenant_id, new_net_dict[const.NET_ID],
|
||||
port_dict[const.PORT_ID])
|
||||
LOG.debug("test_associate_portprofile - END")
|
||||
|
||||
def test_associate_portprofileDNE(self, tenant_id='test_tenant',
|
||||
|
@ -738,22 +806,32 @@ class CoreAPITestFunc(unittest.TestCase):
|
|||
LOG.debug("test_associate_portprofileDNE - END")
|
||||
|
||||
def test_disassociate_portprofile(self, tenant_id='test_tenant',
|
||||
net_id='0005', port_id='p00005'):
|
||||
):
|
||||
"""
|
||||
Tests disassociation of a port-profile
|
||||
"""
|
||||
|
||||
LOG.debug("test_disassociate_portprofile - START")
|
||||
new_net_dict = self._l2network_plugin.create_network(
|
||||
tenant_id, self.network_name)
|
||||
port_dict = self._l2network_plugin.create_port(
|
||||
tenant_id, new_net_dict[const.NET_ID],
|
||||
self.port_state)
|
||||
port_profile_dict = self._l2network_plugin.create_portprofile(
|
||||
tenant_id, self.profile_name, self.vlan_id)
|
||||
tenant_id, self.profile_name, self.qos)
|
||||
port_profile_id = port_profile_dict['profile-id']
|
||||
self._l2network_plugin.associate_portprofile(tenant_id, net_id,
|
||||
port_id, port_profile_id)
|
||||
self._l2network_plugin.associate_portprofile(
|
||||
tenant_id, new_net_dict[const.NET_ID],
|
||||
port_dict[const.PORT_ID], port_profile_id)
|
||||
self._l2network_plugin.disassociate_portprofile(
|
||||
tenant_id, net_id, port_id, port_profile_id)
|
||||
self.assertEqual(self._l2network_plugin._portprofiles
|
||||
[port_profile_id][const.PROFILE_ASSOCIATIONS], [])
|
||||
tenant_id, new_net_dict[const.NET_ID],
|
||||
port_dict[const.PORT_ID], port_profile_id)
|
||||
port_profile_associate = cdb.get_pp_binding(tenant_id, port_profile_id)
|
||||
self.assertEqual(port_profile_associate, [])
|
||||
self.tearDownPortProfile(tenant_id, port_profile_id)
|
||||
self.tearDownNetworkPort(
|
||||
tenant_id, new_net_dict[const.NET_ID],
|
||||
port_dict[const.PORT_ID])
|
||||
LOG.debug("test_disassociate_portprofile - END")
|
||||
|
||||
def test_disassociate_portprofileDNE(self, tenant_id='test_tenant',
|
||||
|
@ -768,24 +846,7 @@ class CoreAPITestFunc(unittest.TestCase):
|
|||
tenant_id, net_id, port_id, profile_id)
|
||||
LOG.debug("test_disassociate_portprofileDNE - END")
|
||||
|
||||
# def test_disassociate_portprofile_Unassociated
|
||||
|
||||
def test_get_tenant(self, net_tenant_id=None):
|
||||
"""
|
||||
Tests get tenant
|
||||
"""
|
||||
|
||||
LOG.debug("test_get_tenant - START")
|
||||
if net_tenant_id:
|
||||
tenant_id = net_tenant_id
|
||||
else:
|
||||
tenant_id = self.tenant_id
|
||||
tenant_dict = self._l2network_plugin._get_tenant(tenant_id)
|
||||
self.assertEqual(tenant_dict[const.TENANT_ID], tenant_id)
|
||||
self.assertEqual(tenant_dict[const.TENANT_NAME], tenant_id)
|
||||
LOG.debug("test_get_tenant - END")
|
||||
|
||||
def test_get_vlan_name(self, net_tenant_id=None, vlan_name="NewVlan",
|
||||
def test_get_vlan_name(self, net_tenant_id=None, vlan_id="NewVlan",
|
||||
vlan_prefix=conf.VLAN_NAME_PREFIX):
|
||||
"""
|
||||
Tests get vlan name
|
||||
|
@ -797,8 +858,8 @@ class CoreAPITestFunc(unittest.TestCase):
|
|||
else:
|
||||
tenant_id = self.tenant_id
|
||||
result_vlan_name = self._l2network_plugin._get_vlan_name(tenant_id,
|
||||
vlan_name)
|
||||
expected_output = vlan_prefix + tenant_id + "-" + vlan_name
|
||||
vlan_id)
|
||||
expected_output = vlan_prefix + vlan_id
|
||||
self.assertEqual(result_vlan_name, expected_output)
|
||||
LOG.debug("test_get_vlan_name - END")
|
||||
|
||||
|
@ -823,39 +884,11 @@ class CoreAPITestFunc(unittest.TestCase):
|
|||
port_state)
|
||||
LOG.debug("test_validate_port_state - END")
|
||||
|
||||
def test_validate_attachment(self, net_tenant_id=None,
|
||||
remote_interface_id="new_interface"):
|
||||
"""
|
||||
Tests validate attachment
|
||||
"""
|
||||
|
||||
LOG.debug("test_validate_attachment - START")
|
||||
if net_tenant_id:
|
||||
tenant_id = net_tenant_id
|
||||
else:
|
||||
tenant_id = self.tenant_id
|
||||
net_name = self.network_name
|
||||
new_network_dict = self._l2network_plugin.create_network(tenant_id,
|
||||
net_name)
|
||||
network_id = new_network_dict[const.NET_ID]
|
||||
new_port_dict = self._l2network_plugin.create_port(tenant_id,
|
||||
network_id)
|
||||
port_id = new_port_dict[const.PORT_ID]
|
||||
self._l2network_plugin.plug_interface(
|
||||
tenant_id, new_network_dict[const.NET_ID], port_id,
|
||||
remote_interface_id)
|
||||
self.assertRaises(exc.AlreadyAttached,
|
||||
self._l2network_plugin._validate_attachment,
|
||||
tenant_id, network_id, port_id, remote_interface_id)
|
||||
self.tearDownNetworkPortInterface(
|
||||
tenant_id, new_network_dict[const.NET_ID], port_id)
|
||||
LOG.debug("test_validate_attachment - END")
|
||||
|
||||
def setUp(self):
|
||||
self.tenant_id = "test_tenant"
|
||||
self.network_name = "test_network"
|
||||
self.profile_name = "test_tenant_port_profile"
|
||||
self.vlan_id = "test_tenant_vlanid300"
|
||||
self.qos = "test_qos"
|
||||
self.port_state = const.PORT_UP
|
||||
self.net_id = '00005'
|
||||
self.port_id = 'p0005'
|
||||
|
@ -865,6 +898,10 @@ class CoreAPITestFunc(unittest.TestCase):
|
|||
"""
|
||||
Clean up functions after the tests
|
||||
"""
|
||||
def tearDown(self):
|
||||
"""Clear the test environment"""
|
||||
# Remove database contents
|
||||
db.clear_db()
|
||||
|
||||
def tearDownNetwork(self, tenant_id, network_dict_id):
|
||||
self._l2network_plugin.delete_network(tenant_id, network_dict_id)
|
||||
|
@ -885,8 +922,41 @@ class CoreAPITestFunc(unittest.TestCase):
|
|||
def tearDownPortProfile(self, tenant_id, port_profile_id):
|
||||
self._l2network_plugin.delete_portprofile(tenant_id, port_profile_id)
|
||||
|
||||
def tearDownPortProfileBinding(self, tenant_id, port_profile_id):
|
||||
self._l2network_plugin.delete_portprofile(tenant_id, port_profile_id)
|
||||
|
||||
def tearDownAssociatePortProfile(self, tenant_id, net_id, port_id,
|
||||
port_profile_id):
|
||||
self._l2network_plugin.disassociate_portprofile(
|
||||
tenant_id, net_id, port_id, port_profile_id)
|
||||
self.tearDownPortProfile(tenant_id, port_profile_id)
|
||||
|
||||
def _make_net_dict(self, net_id, net_name, ports):
|
||||
res = {const.NET_ID: net_id, const.NET_NAME: net_name}
|
||||
res[const.NET_PORTS] = ports
|
||||
return res
|
||||
|
||||
def _make_port_dict(self, port_id, port_state, net_id, attachment):
|
||||
res = {const.PORT_ID: port_id, const.PORT_STATE: port_state}
|
||||
res[const.NET_ID] = net_id
|
||||
res[const.ATTACHMENT] = attachment
|
||||
return res
|
||||
|
||||
def _make_portprofile_dict(self, tenant_id, profile_id, profile_name,
|
||||
qos):
|
||||
profile_associations = self._make_portprofile_assc_list(
|
||||
tenant_id, profile_id)
|
||||
res = {const.PROFILE_ID: str(profile_id),
|
||||
const.PROFILE_NAME: profile_name,
|
||||
const.PROFILE_ASSOCIATIONS: profile_associations,
|
||||
const.PROFILE_VLAN_ID: None,
|
||||
const.PROFILE_QOS: qos}
|
||||
return res
|
||||
|
||||
def _make_portprofile_assc_list(self, tenant_id, profile_id):
|
||||
plist = cdb.get_pp_binding(tenant_id, profile_id)
|
||||
assc_list = []
|
||||
for port in plist:
|
||||
assc_list.append(port[const.PORTID])
|
||||
|
||||
return assc_list
|
||||
|
|
|
@ -259,11 +259,10 @@ class TestNexusPlugin(unittest.TestCase):
|
|||
self.tearDownNetwork(tenant_id, new_net_dict[const.NET_ID])
|
||||
LOG.debug("test_get_vlan_id_for_network - END")
|
||||
|
||||
"""
|
||||
Clean up functions after the tests
|
||||
"""
|
||||
|
||||
def tearDownNetwork(self, tenant_id, network_dict_id):
|
||||
"""
|
||||
Clean up functions after the tests
|
||||
"""
|
||||
self._cisco_nexus_plugin.delete_network(tenant_id, network_dict_id)
|
||||
|
||||
# def test_create_network(self):
|
||||
|
|
|
@ -24,13 +24,13 @@ from quantum.plugins.cisco.ucs import cisco_ucs_network_driver
|
|||
|
||||
LOG = logging.getLogger('quantum.tests.test_ucs_driver')
|
||||
|
||||
create_vlan_output = "<configConfMos cookie=\"cookie_placeholder\" "\
|
||||
CREATE_VLAN_OUTPUT = "<configConfMos cookie=\"cookie_placeholder\" "\
|
||||
"inHierarchical=\"true\"> <inConfigs><pair key=\"fabric/lan/net-New Vlan\"> "\
|
||||
"<fabricVlan defaultNet=\"no\" dn=\"fabric/lan/net-New Vlan\" id=\"200\" "\
|
||||
"name=\"New Vlan\" status=\"created\"></fabricVlan> </pair> </inConfigs> "\
|
||||
"</configConfMos>"
|
||||
|
||||
create_profile_output = "<configConfMos cookie=\"cookie_placeholder\" "\
|
||||
CREATE_PROFILE_OUTPUT = "<configConfMos cookie=\"cookie_placeholder\" "\
|
||||
"inHierarchical=\"true\"> <inConfigs><pair key=\"fabric/lan/profiles/vnic-"\
|
||||
"New Profile\"> <vnicProfile descr=\"Profile created by Cisco OpenStack "\
|
||||
"Quantum Plugin\" dn=\"fabric/lan/profiles/vnic-New Profile\" maxPorts="\
|
||||
|
@ -39,7 +39,7 @@ create_profile_output = "<configConfMos cookie=\"cookie_placeholder\" "\
|
|||
"name=\"New Vlan\" rn=\"if-New Vlan\" > </vnicEtherIf> </vnicProfile> "\
|
||||
"</pair> </inConfigs> </configConfMos>"
|
||||
|
||||
change_vlan_output = "<configConfMos cookie=\"cookie_placeholder\" "\
|
||||
CHANGE_VLAN_OUTPUT = "<configConfMos cookie=\"cookie_placeholder\" "\
|
||||
"inHierarchical=\"true\"> <inConfigs><pair key=\""\
|
||||
"fabric/lan/profiles/vnic-New Profile\"> <vnicProfile descr=\"Profile "\
|
||||
"created by Cisco OpenStack Quantum Plugin\" "\
|
||||
|
@ -50,18 +50,18 @@ change_vlan_output = "<configConfMos cookie=\"cookie_placeholder\" "\
|
|||
"<vnicEtherIf defaultNet=\"yes\" name=\"New Vlan\" rn=\"if-New Vlan\" > "\
|
||||
"</vnicEtherIf> </vnicProfile> </pair></inConfigs> </configConfMos>"
|
||||
|
||||
delete_vlan_output = "<configConfMos cookie=\"cookie_placeholder\" "\
|
||||
DELETE_VLAN_OUTPUT = "<configConfMos cookie=\"cookie_placeholder\" "\
|
||||
"inHierarchical=\"true\"> <inConfigs><pair key=\"fabric/lan/net-New Vlan\"> "\
|
||||
"<fabricVlan dn=\"fabric/lan/net-New Vlan\" status=\"deleted\"> "\
|
||||
"</fabricVlan> </pair> </inConfigs></configConfMos>"
|
||||
|
||||
delete_profile_output = "<configConfMos cookie=\"cookie_placeholder\" "\
|
||||
DELETE_PROFILE_OUTPUT = "<configConfMos cookie=\"cookie_placeholder\" "\
|
||||
"inHierarchical=\"false\"> <inConfigs><pair key=\""\
|
||||
"fabric/lan/profiles/vnic-New Profile\"> <vnicProfile "\
|
||||
"dn=\"fabric/lan/profiles/vnic-New Profile\" status=\"deleted\"> "\
|
||||
"</vnicProfile></pair> </inConfigs> </configConfMos>"
|
||||
|
||||
associate_profile_output = "<configConfMos cookie=\"cookie_placeholder\" "\
|
||||
ASSOCIATE_PROFILE_OUTPUT = "<configConfMos cookie=\"cookie_placeholder\" "\
|
||||
"inHierarchical=\"true\"> <inConfigs> <pair key="\
|
||||
"\"fabric/lan/profiles/vnic-New Profile/cl-New Profile Client\">"\
|
||||
" <vmVnicProfCl dcName=\".*\" descr=\"\" dn=\"fabric/lan/profiles/vnic-"\
|
||||
|
@ -73,83 +73,86 @@ associate_profile_output = "<configConfMos cookie=\"cookie_placeholder\" "\
|
|||
class TestUCSDriver(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self._ucsmDriver = cisco_ucs_network_driver.CiscoUCSMDriver()
|
||||
self.ucsm_driver = cisco_ucs_network_driver.CiscoUCSMDriver()
|
||||
self.vlan_name = 'New Vlan'
|
||||
self.vlan_id = '200'
|
||||
self.profile_name = 'New Profile'
|
||||
self.old_vlan_name = 'Old Vlan'
|
||||
self.profile_client_name = 'New Profile Client'
|
||||
|
||||
def test_create_vlan_post_data(self, expected_output=create_vlan_output):
|
||||
def test_create_vlan_post_data(self, expected_output=CREATE_VLAN_OUTPUT):
|
||||
"""
|
||||
Tests creation of vlan post Data
|
||||
"""
|
||||
|
||||
LOG.debug("test_create_vlan")
|
||||
vlan_details = self._ucsmDriver._create_vlan_post_data(
|
||||
vlan_details = self.ucsm_driver._create_vlan_post_data(
|
||||
self.vlan_name, self.vlan_id)
|
||||
self.assertEqual(vlan_details, expected_output)
|
||||
LOG.debug("test_create_vlan - END")
|
||||
|
||||
def test_create_profile_post_data(
|
||||
self, expected_output=create_profile_output):
|
||||
self, expected_output=CREATE_PROFILE_OUTPUT):
|
||||
"""
|
||||
Tests creation of profile post Data
|
||||
"""
|
||||
|
||||
LOG.debug("test_create_profile_post_data - START")
|
||||
profile_details = self._ucsmDriver._create_profile_post_data(
|
||||
profile_details = self.ucsm_driver._create_profile_post_data(
|
||||
self.profile_name, self.vlan_name)
|
||||
self.assertEqual(profile_details, expected_output)
|
||||
LOG.debug("test_create_profile_post - END")
|
||||
|
||||
def test_change_vlan_in_profile_post_data(
|
||||
self, expected_output=change_vlan_output):
|
||||
def test_change_vlan_profile_data(
|
||||
self, expected_output=CHANGE_VLAN_OUTPUT):
|
||||
"""
|
||||
Tests creation of change vlan in profile post Data
|
||||
"""
|
||||
|
||||
LOG.debug("test_create_profile_post_data - START")
|
||||
profile_details = self._ucsmDriver._change_vlan_in_profile_post_data(
|
||||
profile_details = self.ucsm_driver._change_vlaninprof_post_data(
|
||||
self.profile_name, self.old_vlan_name, self.vlan_name)
|
||||
self.assertEqual(profile_details, expected_output)
|
||||
LOG.debug("test_create_profile_post - END")
|
||||
|
||||
def test_delete_vlan_post_data(self, expected_output=delete_vlan_output):
|
||||
LOG.debug("test_create_profile_post_data - START")
|
||||
def test_delete_vlan_post_data(self, expected_output=DELETE_VLAN_OUTPUT):
|
||||
"""
|
||||
Tests deletion of vlan post Data
|
||||
"""
|
||||
|
||||
vlan_details = self._ucsmDriver._create_vlan_post_data(
|
||||
LOG.debug("test_create_profile_post_data - START")
|
||||
|
||||
self.ucsm_driver._create_vlan_post_data(
|
||||
self.vlan_name, self.vlan_id)
|
||||
vlan_delete_details = self._ucsmDriver._delete_vlan_post_data(
|
||||
vlan_delete_details = self.ucsm_driver._delete_vlan_post_data(
|
||||
self.vlan_name)
|
||||
self.assertEqual(vlan_delete_details, expected_output)
|
||||
LOG.debug("test_create_profile_post - END")
|
||||
|
||||
def test_delete_profile_post_data(
|
||||
self, expected_output=delete_profile_output):
|
||||
self, expected_output=DELETE_PROFILE_OUTPUT):
|
||||
"""
|
||||
Tests deletion of profile post Data
|
||||
"""
|
||||
|
||||
LOG.debug("test_create_profile_post_data - START")
|
||||
profile_details = self._ucsmDriver._create_profile_post_data(
|
||||
#profile_details = self.ucsm_driver._create_profile_post_data(
|
||||
# self.profile_name, self.vlan_name)
|
||||
self.ucsm_driver._create_profile_post_data(
|
||||
self.profile_name, self.vlan_name)
|
||||
profile_delete_details = self._ucsmDriver._delete_profile_post_data(
|
||||
profile_delete_details = self.ucsm_driver._delete_profile_post_data(
|
||||
self.profile_name)
|
||||
self.assertEqual(profile_delete_details, expected_output)
|
||||
LOG.debug("test_create_profile_post - END")
|
||||
|
||||
def test_create_profile_client_post_data(
|
||||
self, expected_output=associate_profile_output):
|
||||
def test_create_profile_client_data(
|
||||
self, expected_output=ASSOCIATE_PROFILE_OUTPUT):
|
||||
"""
|
||||
Tests creation of profile client post Data
|
||||
"""
|
||||
|
||||
LOG.debug("test_create_profile_client_post_data - START")
|
||||
profile_details = self._ucsmDriver._create_profile_client_post_data(
|
||||
LOG.debug("test_create_profile_client_data - START")
|
||||
profile_details = self.ucsm_driver._create_pclient_post_data(
|
||||
self.profile_name, self.profile_client_name)
|
||||
self.assertEqual(profile_details, expected_output)
|
||||
LOG.debug("test_create_profile_post - END")
|
||||
|
@ -160,6 +163,6 @@ class TestUCSDriver(unittest.TestCase):
|
|||
"""
|
||||
|
||||
LOG.debug("test_get_next_dynamic_nic - START")
|
||||
dynamic_nic_id = self._ucsmDriver._get_next_dynamic_nic()
|
||||
dynamic_nic_id = self.ucsm_driver._get_next_dynamic_nic()
|
||||
self.assertTrue(len(dynamic_nic_id) > 0)
|
||||
LOG.debug("test_get_next_dynamic_nic - END")
|
||||
|
|
|
@ -32,7 +32,7 @@ class UCSVICTestPlugin(unittest.TestCase):
|
|||
|
||||
self.tenant_id = "test_tenant_cisco12"
|
||||
self.net_name = "test_network_cisco12"
|
||||
self.net_id = 000007
|
||||
self.net_id = 000011
|
||||
self.vlan_name = "q-" + str(self.net_id) + "vlan"
|
||||
self.vlan_id = 266
|
||||
self.port_id = "4"
|
||||
|
@ -238,12 +238,12 @@ class UCSVICTestPlugin(unittest.TestCase):
|
|||
self.assertEqual(new_port_profile[const.PROFILE_NAME], profile_name)
|
||||
self.tearDownNetworkPort(self.tenant_id, self.net_id, self.port_id)
|
||||
|
||||
def _test_get_port_details_state_down(self, port_state):
|
||||
def _test_show_port_state_down(self, port_state):
|
||||
"""
|
||||
Tests whether user is able to retrieve a remote interface
|
||||
that is attached to this particular port when port state is down.
|
||||
"""
|
||||
LOG.debug("UCSVICTestPlugin:_test_get_port_details_state_down()" +
|
||||
LOG.debug("UCSVICTestPlugin:_test_show_port_state_down()" +
|
||||
"called\n")
|
||||
self._cisco_ucs_plugin.create_network(self.tenant_id, self.net_name,
|
||||
self.net_id, self.vlan_name,
|
||||
|
@ -268,8 +268,8 @@ class UCSVICTestPlugin(unittest.TestCase):
|
|||
def test_get_port_details_state_up(self):
|
||||
self._test_get_port_details_state_up(const.PORT_UP)
|
||||
|
||||
def test_get_port_details_state_down(self):
|
||||
self._test_get_port_details_state_down(const.PORT_DOWN)
|
||||
def test_show_port_state_down(self):
|
||||
self._test_show_port_state_down(const.PORT_DOWN)
|
||||
|
||||
def test_create_port_profile(self):
|
||||
LOG.debug("UCSVICTestPlugin:test_create_port_profile() called\n")
|
||||
|
@ -313,7 +313,6 @@ class UCSVICTestPlugin(unittest.TestCase):
|
|||
self.tenant_id, self.net_id, self.port_id)
|
||||
self.assertEqual(port[const.ATTACHMENT], remote_interface_id)
|
||||
port_profile = port[const.PORT_PROFILE]
|
||||
profile_name = port_profile[const.PROFILE_NAME]
|
||||
new_vlan_name = self._cisco_ucs_plugin._get_vlan_name_for_network(
|
||||
self.tenant_id, self.net_id)
|
||||
new_vlan_id = self._cisco_ucs_plugin._get_vlan_id_for_network(
|
||||
|
@ -346,7 +345,6 @@ class UCSVICTestPlugin(unittest.TestCase):
|
|||
self.tenant_id, self.net_id, self.port_id)
|
||||
self.assertEqual(port[const.ATTACHMENT], None)
|
||||
port_profile = port[const.PORT_PROFILE]
|
||||
profile_name = port_profile[const.PROFILE_NAME]
|
||||
self.assertEqual(port_profile[const.PROFILE_VLAN_NAME],
|
||||
conf.DEFAULT_VLAN_NAME)
|
||||
self.assertEqual(port_profile[const.PROFILE_VLAN_ID],
|
||||
|
@ -394,12 +392,12 @@ class UCSVICTestPlugin(unittest.TestCase):
|
|||
def test_get_network_NetworkNotFound(self):
|
||||
self.assertRaises(exc.NetworkNotFound,
|
||||
self._cisco_ucs_plugin._get_network,
|
||||
*(self.tenant_id, self.net_id))
|
||||
self.tenant_id, self.net_id)
|
||||
|
||||
def test_delete_network_NetworkNotFound(self):
|
||||
self.assertRaises(exc.NetworkNotFound,
|
||||
self._cisco_ucs_plugin.delete_network,
|
||||
*(self.tenant_id, self.net_id))
|
||||
self.tenant_id, self.net_id)
|
||||
|
||||
def test_delete_port_PortInUse(self):
|
||||
self._test_delete_port_PortInUse("4")
|
||||
|
@ -414,7 +412,7 @@ class UCSVICTestPlugin(unittest.TestCase):
|
|||
self.port_id,
|
||||
remote_interface_id)
|
||||
self.assertRaises(exc.PortInUse, self._cisco_ucs_plugin.delete_port,
|
||||
*(self.tenant_id, self.net_id, self.port_id))
|
||||
self.tenant_id, self.net_id, self.port_id)
|
||||
self.tearDownNetworkPortInterface(self.tenant_id, self.net_id,
|
||||
self.port_id)
|
||||
|
||||
|
@ -423,7 +421,7 @@ class UCSVICTestPlugin(unittest.TestCase):
|
|||
self.net_id, self.vlan_name,
|
||||
self.vlan_id)
|
||||
self.assertRaises(exc.PortNotFound, self._cisco_ucs_plugin.delete_port,
|
||||
*(self.tenant_id, self.net_id, self.port_id))
|
||||
self.tenant_id, self.net_id, self.port_id)
|
||||
self.tearDownNetwork(self.tenant_id, self.net_id)
|
||||
|
||||
def test_plug_interface_PortInUse(self):
|
||||
|
@ -441,16 +439,16 @@ class UCSVICTestPlugin(unittest.TestCase):
|
|||
self.port_id,
|
||||
remote_interface_id1)
|
||||
self.assertRaises(exc.PortInUse, self._cisco_ucs_plugin.plug_interface,
|
||||
*(self.tenant_id, self.net_id, self.port_id,
|
||||
remote_interface_id2))
|
||||
self.tenant_id, self.net_id, self.port_id,
|
||||
remote_interface_id2)
|
||||
self.tearDownNetworkPortInterface(self.tenant_id, self.net_id,
|
||||
self.port_id)
|
||||
|
||||
def test_validate_attachment_AlreadyAttached(self):
|
||||
def test_attachment_exists(self):
|
||||
LOG.debug("UCSVICTestPlugin:testValidateAttachmentAlreadyAttached")
|
||||
self._test_validate_attachment_AlreadyAttached("4")
|
||||
self._test_attachment_exists("4")
|
||||
|
||||
def _test_validate_attachment_AlreadyAttached(self, remote_interface_id):
|
||||
def _test_attachment_exists(self, remote_interface_id):
|
||||
LOG.debug("UCSVICTestPlugin:_test_validate_attachmentAlreadyAttached")
|
||||
self._cisco_ucs_plugin.create_network(self.tenant_id, self.net_name,
|
||||
self.net_id, self.vlan_name,
|
||||
|
@ -461,8 +459,8 @@ class UCSVICTestPlugin(unittest.TestCase):
|
|||
self.port_id,
|
||||
remote_interface_id)
|
||||
self.assertRaises(
|
||||
exc.AlreadyAttached, self._cisco_ucs_plugin._validate_attachment,
|
||||
*(self.tenant_id, self.net_id, self.port_id, remote_interface_id))
|
||||
exc.PortInUse, self._cisco_ucs_plugin._validate_attachment,
|
||||
self.tenant_id, self.net_id, self.port_id, remote_interface_id)
|
||||
self.tearDownNetworkPortInterface(self.tenant_id, self.net_id,
|
||||
self.port_id)
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
"""
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2011 Cisco Systems, Inc. All rights reserved.
|
||||
|
@ -16,3 +17,4 @@
|
|||
#
|
||||
# @author: Sumit Naiksatam, Cisco Systems, Inc.
|
||||
#
|
||||
"""
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
"""
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2011 Cisco Systems, Inc. All rights reserved.
|
||||
|
@ -16,11 +17,13 @@
|
|||
#
|
||||
# @author: Rohit Agarwalla, Cisco Systems Inc.
|
||||
#
|
||||
import sys
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
|
||||
|
||||
def get_next_dynic(argv=[]):
|
||||
"""Get the next available dynamic nic on this host"""
|
||||
cmd = ["ifconfig", "-a"]
|
||||
f_cmd_output = subprocess.Popen(cmd, stdout=subprocess.PIPE).\
|
||||
communicate()[0]
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
"""
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2011 Cisco Systems, Inc. All rights reserved.
|
||||
|
@ -16,6 +17,7 @@
|
|||
#
|
||||
# @author: Sumit Naiksatam, Cisco Systems, Inc.
|
||||
#
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
|
@ -23,15 +25,15 @@ from quantum.plugins.cisco.common import cisco_configparser as confp
|
|||
|
||||
CONF_FILE = "../conf/ucs.ini"
|
||||
|
||||
cp = confp.CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) \
|
||||
CP = confp.CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) \
|
||||
+ "/" + CONF_FILE)
|
||||
|
||||
section = cp['UCSM']
|
||||
UCSM_IP_ADDRESS = section['ip_address']
|
||||
DEFAULT_VLAN_NAME = section['default_vlan_name']
|
||||
DEFAULT_VLAN_ID = section['default_vlan_id']
|
||||
MAX_UCSM_PORT_PROFILES = section['max_ucsm_port_profiles']
|
||||
PROFILE_NAME_PREFIX = section['profile_name_prefix']
|
||||
SECTION = CP['UCSM']
|
||||
UCSM_IP_ADDRESS = SECTION['ip_address']
|
||||
DEFAULT_VLAN_NAME = SECTION['default_vlan_name']
|
||||
DEFAULT_VLAN_ID = SECTION['default_vlan_id']
|
||||
MAX_UCSM_PORT_PROFILES = SECTION['max_ucsm_port_profiles']
|
||||
PROFILE_NAME_PREFIX = SECTION['profile_name_prefix']
|
||||
|
||||
section = cp['DRIVER']
|
||||
UCSM_DRIVER = section['name']
|
||||
SECTION = CP['DRIVER']
|
||||
UCSM_DRIVER = SECTION['name']
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
"""
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2011 Cisco Systems, Inc. All rights reserved.
|
||||
|
@ -16,16 +17,15 @@
|
|||
#
|
||||
# @author: Sumit Naiksatam, Cisco Systems Inc.
|
||||
#
|
||||
"""
|
||||
|
||||
"""
|
||||
Implements a UCSM XML API Client
|
||||
"""
|
||||
|
||||
import httplib
|
||||
import logging as LOG
|
||||
import string
|
||||
import subprocess
|
||||
from xml.etree import ElementTree as et
|
||||
import urllib
|
||||
|
||||
from quantum.plugins.cisco.common import cisco_constants as const
|
||||
from quantum.plugins.cisco.common import cisco_exceptions as cexc
|
||||
|
@ -114,11 +114,13 @@ PROFILE_NAME + "\" status=\"deleted\"> </vnicProfile>" \
|
|||
|
||||
|
||||
class CiscoUCSMDriver():
|
||||
"""UCSM Driver"""
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def _post_data(self, ucsm_ip, ucsm_username, ucsm_password, data):
|
||||
"""Send command to UCSM in http request"""
|
||||
conn = httplib.HTTPConnection(ucsm_ip)
|
||||
login_data = "<aaaLogin inName=\"" + ucsm_username + \
|
||||
"\" inPassword=\"" + ucsm_password + "\" />"
|
||||
|
@ -129,8 +131,8 @@ class CiscoUCSMDriver():
|
|||
LOG.debug(response.reason)
|
||||
LOG.debug(response_data)
|
||||
# TODO (Sumit): If login is not successful, throw exception
|
||||
xmlTree = et.XML(response_data)
|
||||
cookie = xmlTree.attrib["outCookie"]
|
||||
xml_tree = et.XML(response_data)
|
||||
cookie = xml_tree.attrib["outCookie"]
|
||||
|
||||
data = data.replace(COOKIE_VALUE, cookie)
|
||||
LOG.debug("POST: %s" % data)
|
||||
|
@ -150,65 +152,76 @@ class CiscoUCSMDriver():
|
|||
LOG.debug(response_data)
|
||||
|
||||
def _create_vlan_post_data(self, vlan_name, vlan_id):
|
||||
"""Create command"""
|
||||
data = CREATE_VLAN.replace(VLAN_NAME, vlan_name)
|
||||
data = data.replace(VLAN_ID, vlan_id)
|
||||
return data
|
||||
|
||||
def _create_profile_post_data(self, profile_name, vlan_name):
|
||||
"""Create command"""
|
||||
data = CREATE_PROFILE.replace(PROFILE_NAME, profile_name)
|
||||
data = data.replace(VLAN_NAME, vlan_name)
|
||||
return data
|
||||
|
||||
def _create_profile_client_post_data(self, profile_name,
|
||||
def _create_pclient_post_data(self, profile_name,
|
||||
profile_client_name):
|
||||
"""Create command"""
|
||||
data = ASSOCIATE_PROFILE.replace(PROFILE_NAME, profile_name)
|
||||
data = data.replace(PROFILE_CLIENT, profile_client_name)
|
||||
return data
|
||||
|
||||
def _change_vlan_in_profile_post_data(self, profile_name, old_vlan_name,
|
||||
def _change_vlaninprof_post_data(self, profile_name, old_vlan_name,
|
||||
new_vlan_name):
|
||||
"""Create command"""
|
||||
data = CHANGE_VLAN_IN_PROFILE.replace(PROFILE_NAME, profile_name)
|
||||
data = data.replace(OLD_VLAN_NAME, old_vlan_name)
|
||||
data = data.replace(VLAN_NAME, new_vlan_name)
|
||||
return data
|
||||
|
||||
def _delete_vlan_post_data(self, vlan_name):
|
||||
"""Create command"""
|
||||
data = DELETE_VLAN.replace(VLAN_NAME, vlan_name)
|
||||
return data
|
||||
|
||||
def _delete_profile_post_data(self, profile_name):
|
||||
"""Create command"""
|
||||
data = DELETE_PROFILE.replace(PROFILE_NAME, profile_name)
|
||||
return data
|
||||
|
||||
def _get_next_dynamic_nic(self):
|
||||
"""Get an avaialble dynamic nic on the host"""
|
||||
dynamic_nic_id = gvif.get_next_dynic()
|
||||
if len(dynamic_nic_id) > 0:
|
||||
return dynamic_nic_id
|
||||
else:
|
||||
raise cisco_exceptions.NoMoreNics(net_id=net_id, port_id=port_id)
|
||||
raise cexc.NoMoreNics()
|
||||
|
||||
def create_vlan(self, vlan_name, vlan_id, ucsm_ip, ucsm_username,
|
||||
ucsm_password):
|
||||
"""Create request for UCSM"""
|
||||
data = self._create_vlan_post_data(vlan_name, vlan_id)
|
||||
self._post_data(ucsm_ip, ucsm_username, ucsm_password, data)
|
||||
|
||||
def create_profile(self, profile_name, vlan_name, ucsm_ip, ucsm_username,
|
||||
ucsm_password):
|
||||
"""Create request for UCSM"""
|
||||
data = self._create_profile_post_data(profile_name, vlan_name)
|
||||
self._post_data(ucsm_ip, ucsm_username, ucsm_password, data)
|
||||
data = self._create_profile_client_post_data(profile_name,
|
||||
data = self._create_pclient_post_data(profile_name,
|
||||
profile_name[-16:])
|
||||
self._post_data(ucsm_ip, ucsm_username, ucsm_password, data)
|
||||
|
||||
def change_vlan_in_profile(self, profile_name, old_vlan_name,
|
||||
new_vlan_name, ucsm_ip, ucsm_username,
|
||||
ucsm_password):
|
||||
data = self._change_vlan_in_profile_post_data(profile_name,
|
||||
"""Create request for UCSM"""
|
||||
data = self._change_vlaninprof_post_data(profile_name,
|
||||
old_vlan_name,
|
||||
new_vlan_name)
|
||||
self._post_data(ucsm_ip, ucsm_username, ucsm_password, data)
|
||||
|
||||
def get_dynamic_nic(self, host):
|
||||
"""Get an avaialble dynamic nic on the host"""
|
||||
# TODO (Sumit): Check availability per host
|
||||
# TODO (Sumit): If not available raise exception
|
||||
# TODO (Sumit): This simple logic assumes that create-port and
|
||||
|
@ -222,14 +235,17 @@ class CiscoUCSMDriver():
|
|||
return dynamic_nic_name
|
||||
|
||||
def delete_vlan(self, vlan_name, ucsm_ip, ucsm_username, ucsm_password):
|
||||
"""Create request for UCSM"""
|
||||
data = self._delete_vlan_post_data(vlan_name)
|
||||
self._post_data(ucsm_ip, ucsm_username, ucsm_password, data)
|
||||
|
||||
def delete_profile(self, profile_name, ucsm_ip, ucsm_username,
|
||||
ucsm_password):
|
||||
"""Create request for UCSM"""
|
||||
data = self._delete_profile_post_data(profile_name)
|
||||
self._post_data(ucsm_ip, ucsm_username, ucsm_password, data)
|
||||
|
||||
def release_dynamic_nic(self, host):
|
||||
"""Release a reserved dynamic nic on the host"""
|
||||
# TODO (Sumit): Release on a specific host
|
||||
pass
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
"""
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2011 Cisco Systems, Inc. All rights reserved.
|
||||
|
@ -16,6 +17,7 @@
|
|||
#
|
||||
# @author: Sumit Naiksatam, Cisco Systems, Inc.
|
||||
#
|
||||
"""
|
||||
|
||||
import logging as LOG
|
||||
|
||||
|
@ -33,6 +35,7 @@ LOG.getLogger(const.LOGGER_COMPONENT_NAME)
|
|||
|
||||
|
||||
class UCSVICPlugin(L2DevicePluginBase):
|
||||
"""UCS Device Plugin"""
|
||||
_networks = {}
|
||||
|
||||
def __init__(self):
|
||||
|
@ -238,41 +241,48 @@ class UCSVICPlugin(L2DevicePluginBase):
|
|||
port_profile[const.PROFILE_VLAN_ID] = conf.DEFAULT_VLAN_ID
|
||||
|
||||
def _get_profile_name(self, port_id):
|
||||
profile_name = conf.PROFILE_NAME_PREFIX + 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 _validate_port_state(self, port_state):
|
||||
"""Check the port state"""
|
||||
if port_state.upper() not in (const.PORT_UP, const.PORT_DOWN):
|
||||
raise exc.StateInvalid(port_state=port_state)
|
||||
return True
|
||||
|
||||
def _validate_attachment(self, tenant_id, network_id, port_id,
|
||||
remote_interface_id):
|
||||
"""Check if the VIF can be attached"""
|
||||
network = self._get_network(tenant_id, network_id)
|
||||
for port in network[const.NET_PORTS].values():
|
||||
if port[const.ATTACHMENT] == remote_interface_id:
|
||||
raise exc.AlreadyAttached(net_id=network_id,
|
||||
port_id=port_id,
|
||||
att_id=port[const.ATTACHMENT],
|
||||
att_port_id=port[const.PORT_ID])
|
||||
raise exc.PortInUse(net_id=network_id,
|
||||
port_id=port_id,
|
||||
att_id=port[const.ATTACHMENT])
|
||||
|
||||
def _get_network(self, tenant_id, network_id):
|
||||
"""Get the network object ref"""
|
||||
network = self._networks.get(network_id)
|
||||
if not network:
|
||||
raise exc.NetworkNotFound(net_id=network_id)
|
||||
return network
|
||||
|
||||
def _get_vlan_name_for_network(self, tenant_id, network_id):
|
||||
"""Return the VLAN name as set by the L2 network plugin"""
|
||||
net = self._get_network(tenant_id, network_id)
|
||||
vlan_name = net[const.NET_VLAN_NAME]
|
||||
return vlan_name
|
||||
|
||||
def _get_vlan_id_for_network(self, tenant_id, network_id):
|
||||
"""Return the VLAN id as set by the L2 network plugin"""
|
||||
net = self._get_network(tenant_id, network_id)
|
||||
vlan_id = net[const.NET_VLAN_ID]
|
||||
return vlan_id
|
||||
|
||||
def _get_port(self, tenant_id, network_id, port_id):
|
||||
"""Get the port object ref"""
|
||||
net = self._get_network(tenant_id, network_id)
|
||||
port = net[const.NET_PORTS].get(port_id)
|
||||
if not port:
|
||||
|
@ -281,6 +291,7 @@ class UCSVICPlugin(L2DevicePluginBase):
|
|||
|
||||
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)
|
||||
|
@ -293,6 +304,7 @@ class UCSVICPlugin(L2DevicePluginBase):
|
|||
return new_port_profile
|
||||
|
||||
def _delete_port_profile(self, port_id, profile_name):
|
||||
"""Delete port profile in UCSM"""
|
||||
self._client.delete_profile(profile_name, self._ucsm_ip,
|
||||
self._ucsm_username, self._ucsm_password)
|
||||
self._port_profile_counter -= 1
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
import logging
|
||||
import unittest
|
||||
|
||||
|
||||
import tests.unit.testlib_api as testlib
|
||||
|
||||
from quantum import api as server
|
||||
from quantum.db import api as db
|
||||
from quantum.common.test_lib import test_config
|
||||
|
@ -523,7 +523,6 @@ class APITest(unittest.TestCase):
|
|||
show_port_res.body, content_type)
|
||||
self.assertEqual({'id': port_id, 'state': new_port_state},
|
||||
port_data['port'])
|
||||
|
||||
# now set it back to the original value
|
||||
update_port_req = testlib.update_port_request(self.tenant_id,
|
||||
network_id, port_id,
|
||||
|
|
Loading…
Reference in New Issue