merge trunk

This commit is contained in:
Salvatore Orlando 2011-08-30 17:06:19 +01:00
commit fff680ee63
50 changed files with 3841 additions and 518 deletions

165
bin/cli Executable file
View File

@ -0,0 +1,165 @@
#!/usr/bin/env python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2011 Nicira Networks, Inc.
# Copyright 2011 Citrix Systems
#
# 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: Salvatore Orlando, Citrix
import Cheetah.Template as cheetah_template
import gettext
import logging
import logging.handlers
import os
import sys
from optparse import OptionParser
possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
os.pardir,
os.pardir))
if os.path.exists(os.path.join(possible_topdir, 'quantum', '__init__.py')):
sys.path.insert(0, possible_topdir)
gettext.install('quantum', unicode=1)
from quantum import cli_lib
from quantum.client import Client
#Configure logger for client - cli logger is a child of it
#NOTE(salvatore-orlando): logger name does not map to package
#this is deliberate. Simplifies logger configuration
LOG = logging.getLogger('quantum')
FORMAT = 'json'
commands = {
"list_nets": {
"func": cli_lib.list_nets,
"args": ["tenant-id"]},
"create_net": {
"func": cli_lib.create_net,
"args": ["tenant-id", "net-name"]},
"delete_net": {
"func": cli_lib.delete_net,
"args": ["tenant-id", "net-id"]},
"show_net": {
"func": cli_lib.show_net,
"args": ["tenant-id", "net-id"]},
"rename_net": {
"func": cli_lib.rename_net,
"args": ["tenant-id", "net-id", "new-name"]},
"list_ports": {
"func": cli_lib.list_ports,
"args": ["tenant-id", "net-id"]},
"create_port": {
"func": cli_lib.create_port,
"args": ["tenant-id", "net-id"]},
"delete_port": {
"func": cli_lib.delete_port,
"args": ["tenant-id", "net-id", "port-id"]},
"set_port_state": {
"func": cli_lib.set_port_state,
"args": ["tenant-id", "net-id", "port-id", "new_state"]},
"show_port": {
"func": cli_lib.show_port,
"args": ["tenant-id", "net-id", "port-id"]},
"plug_iface": {
"func": cli_lib.plug_iface,
"args": ["tenant-id", "net-id", "port-id", "iface-id"]},
"unplug_iface": {
"func": cli_lib.unplug_iface,
"args": ["tenant-id", "net-id", "port-id"]}, }
def help():
print "\nCommands:"
for k in commands.keys():
print " %s %s" % (k,
" ".join(["<%s>" % y for y in commands[k]["args"]]))
def build_args(cmd, cmdargs, arglist):
args = []
orig_arglist = arglist[:]
try:
for x in cmdargs:
args.append(arglist[0])
del arglist[0]
except:
LOG.error("Not enough arguments for \"%s\" (expected: %d, got: %d)" % (
cmd, len(cmdargs), len(orig_arglist)))
print "Usage:\n %s %s" % (cmd,
" ".join(["<%s>" % y for y in commands[cmd]["args"]]))
return None
if len(arglist) > 0:
LOG.error("Too many arguments for \"%s\" (expected: %d, got: %d)" % (
cmd, len(cmdargs), len(orig_arglist)))
print "Usage:\n %s %s" % (cmd,
" ".join(["<%s>" % y for y in commands[cmd]["args"]]))
return None
return args
if __name__ == "__main__":
usagestr = "Usage: %prog [OPTIONS] <command> [args]"
parser = OptionParser(usage=usagestr)
parser.add_option("-H", "--host", dest="host",
type="string", default="127.0.0.1", help="ip address of api host")
parser.add_option("-p", "--port", dest="port",
type="int", default=9696, help="api poort")
parser.add_option("-s", "--ssl", dest="ssl",
action="store_true", default=False, help="use ssl")
parser.add_option("-v", "--verbose", dest="verbose",
action="store_true", default=False, help="turn on verbose logging")
parser.add_option("-f", "--logfile", dest="logfile",
type="string", default="syslog", help="log file path")
options, args = parser.parse_args()
if options.verbose:
LOG.setLevel(logging.DEBUG)
else:
LOG.setLevel(logging.WARN)
#logging.handlers.WatchedFileHandler
if options.logfile == "syslog":
LOG.addHandler(logging.handlers.SysLogHandler(address='/dev/log'))
else:
LOG.addHandler(logging.handlers.WatchedFileHandler(options.logfile))
# Set permissions on log file
os.chmod(options.logfile, 0644)
if len(args) < 1:
parser.print_help()
help()
sys.exit(1)
cmd = args[0]
if cmd not in commands.keys():
LOG.error("Unknown command: %s" % cmd)
help()
sys.exit(1)
args = build_args(cmd, commands[cmd]["args"], args[1:])
if not args:
sys.exit(1)
LOG.info("Executing command \"%s\" with args: %s" % (cmd, args))
client = Client(options.host, options.port, options.ssl,
args[0], FORMAT)
commands[cmd]["func"](client, *args)
LOG.info("Command execution completed")
sys.exit(0)

View File

@ -0,0 +1,56 @@
"""
# 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: Ying Liu, Cisco Systems, Inc.
#
"""
def get_view_builder(req):
"""get view builder """
base_url = req.application_url
return ViewBuilder(base_url)
class ViewBuilder(object):
"""
ViewBuilder for Credential,
derived from quantum.views.networks
"""
def __init__(self, base_url):
"""
:param base_url: url of the root wsgi application
"""
self.base_url = base_url
def build(self, credential_data, is_detail=False):
"""Generic method used to generate a credential entity."""
if is_detail:
credential = self._build_detail(credential_data)
else:
credential = self._build_simple(credential_data)
return credential
def _build_simple(self, credential_data):
"""Return a simple description of credential."""
return dict(credential=dict(id=credential_data['credential_id']))
def _build_detail(self, credential_data):
"""Return a detailed description of credential."""
return dict(credential=dict(id=credential_data['credential_id'],
name=credential_data['user_name'],
password=credential_data['password']))

View File

@ -0,0 +1,47 @@
"""
# 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: Ying Liu, Cisco Systems, Inc.
#
"""
from quantum.plugins.cisco.common import cisco_constants as const
def get_view_builder(req):
"""get view builder """
base_url = req.application_url
return ViewBuilder(base_url)
class ViewBuilder(object):
"""
ViewBuilder for novatenant,
derived from quantum.views.networks
"""
def __init__(self, base_url):
"""
:param base_url: url of the root wsgi application
"""
self.base_url = base_url
def build_host(self, host_data):
"""Return host description."""
return dict(host_list=host_data[const.HOST_LIST])
def build_vif(self, vif_data):
"""Return VIF description."""
return dict(vif_desc=vif_data[const.VIF_DESC])

62
extensions/_pprofiles.py Normal file
View File

@ -0,0 +1,62 @@
"""
# 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: Ying Liu, Cisco Systems, Inc.
#
"""
def get_view_builder(req):
"""get view builder"""
base_url = req.application_url
return ViewBuilder(base_url)
class ViewBuilder(object):
"""
ViewBuilder for Portprofile,
derived from quantum.views.networks
"""
def __init__(self, base_url):
"""
:param base_url: url of the root wsgi application
"""
self.base_url = base_url
def build(self, portprofile_data, is_detail=False):
"""Generic method used to generate a portprofile entity."""
if is_detail:
portprofile = self._build_detail(portprofile_data)
else:
portprofile = self._build_simple(portprofile_data)
return portprofile
def _build_simple(self, portprofile_data):
"""Return a simple description of a portprofile"""
return dict(portprofile=dict(id=portprofile_data['profile_id']))
def _build_detail(self, portprofile_data):
"""Return a detailed info of a portprofile."""
if (portprofile_data['assignment'] == None):
return dict(portprofile=dict(id=portprofile_data['profile_id'],
name=portprofile_data['profile_name'],
qos_name=portprofile_data['qos_name']))
else:
return dict(portprofile=dict(id=portprofile_data['profile_id'],
name=portprofile_data['profile_name'],
qos_name=portprofile_data['qos_name'],
assignment=portprofile_data['assignment']))

56
extensions/_qos_view.py Normal file
View File

@ -0,0 +1,56 @@
"""
# 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: Ying Liu, Cisco Systems, Inc.
#
"""
def get_view_builder(req):
"""get view builder"""
base_url = req.application_url
return ViewBuilder(base_url)
class ViewBuilder(object):
"""
ViewBuilder for QoS,
derived from quantum.views.networks
"""
def __init__(self, base_url):
"""
:param base_url: url of the root wsgi application
"""
self.base_url = base_url
def build(self, qos_data, is_detail=False):
"""Generic method used to generate a QoS entity."""
if is_detail:
qos = self._build_detail(qos_data)
else:
qos = self._build_simple(qos_data)
return qos
def _build_simple(self, qos_data):
"""Return a simple description of qos."""
return dict(qos=dict(id=qos_data['qos_id']))
def _build_detail(self, qos_data):
"""Return a detailed description of qos."""
return dict(qos=dict(id=qos_data['qos_id'],
name=qos_data['qos_name'],
description=qos_data['qos_desc']))

166
extensions/credential.py Normal file
View File

@ -0,0 +1,166 @@
"""
# 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: Ying Liu, Cisco Systems, Inc.
#
"""
import logging
from webob import exc
from extensions import _credential_view as credential_view
from quantum.api import api_common as common
from quantum.common import extensions
from quantum.manager import QuantumManager
from quantum.plugins.cisco.common import cisco_exceptions as exception
from quantum.plugins.cisco.common import cisco_faults as faults
LOG = logging.getLogger('quantum.api.credentials')
class Credential(object):
"""extension class Credential"""
def __init__(self):
pass
@classmethod
def get_name(cls):
""" Returns Ext Resource Name """
return "Cisco Credential"
@classmethod
def get_alias(cls):
""" Returns Ext Resource Alias """
return "Cisco Credential"
@classmethod
def get_description(cls):
""" Returns Ext Resource Description """
return "Credential include username and password"
@classmethod
def get_namespace(cls):
""" Returns Ext Resource Namespace """
return "http://docs.ciscocloud.com/api/ext/credential/v1.0"
@classmethod
def get_updated(cls):
""" Returns Ext Resource Update Time """
return "2011-07-25T13:25:27-06:00"
@classmethod
def get_resources(cls):
""" Returns Ext Resources """
parent_resource = dict(member_name="tenant",
collection_name="extensions/csco/tenants")
controller = CredentialController(QuantumManager.get_plugin())
return [extensions.ResourceExtension('credentials', controller,
parent=parent_resource)]
class CredentialController(common.QuantumController):
""" credential API controller
based on QuantumController """
_credential_ops_param_list = [{
'param-name': 'credential_name',
'required': True}, {
'param-name': 'user_name',
'required': True}, {
'param-name': 'password',
'required': True}]
_serialization_metadata = {
"application/xml": {
"attributes": {
"credential": ["id", "name"],
},
},
}
def __init__(self, plugin):
self._resource_name = 'credential'
self._plugin = plugin
def index(self, request, tenant_id):
""" Returns a list of credential ids """
return self._items(request, tenant_id, is_detail=False)
def _items(self, request, tenant_id, is_detail):
""" Returns a list of credentials. """
credentials = self._plugin.get_all_credentials(tenant_id)
builder = credential_view.get_view_builder(request)
result = [builder.build(credential, is_detail)['credential']
for credential in credentials]
return dict(credentials=result)
# pylint: disable-msg=E1101,W0613
def show(self, request, tenant_id, id):
""" Returns credential details for the given credential id """
try:
credential = self._plugin.get_credential_details(
tenant_id, id)
builder = credential_view.get_view_builder(request)
#build response with details
result = builder.build(credential, True)
return dict(credentials=result)
except exception.CredentialNotFound as exp:
return faults.Fault(faults.CredentialNotFound(exp))
def create(self, request, tenant_id):
""" Creates a new credential for a given tenant """
try:
req_params = \
self._parse_request_params(request,
self._credential_ops_param_list)
except exc.HTTPError as exp:
return faults.Fault(exp)
credential = self._plugin.\
create_credential(tenant_id,
req_params['credential_name'],
req_params['user_name'],
req_params['password'])
builder = credential_view.get_view_builder(request)
result = builder.build(credential)
return dict(credentials=result)
def update(self, request, tenant_id, id):
""" Updates the name for the credential with the given id """
try:
req_params = \
self._parse_request_params(request,
self._credential_ops_param_list)
except exc.HTTPError as exp:
return faults.Fault(exp)
try:
credential = self._plugin.\
rename_credential(tenant_id,
id, req_params['credential_name'])
builder = credential_view.get_view_builder(request)
result = builder.build(credential, True)
return dict(credentials=result)
except exception.CredentialNotFound as exp:
return faults.Fault(faults.CredentialNotFound(exp))
def delete(self, request, tenant_id, id):
""" Destroys the credential with the given id """
try:
self._plugin.delete_credential(tenant_id, id)
return exc.HTTPAccepted()
except exception.CredentialNotFound as exp:
return faults.Fault(faults.CredentialNotFound(exp))

140
extensions/novatenant.py Normal file
View File

@ -0,0 +1,140 @@
"""
# 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: Ying Liu, Cisco Systems, Inc.
#
"""
from webob import exc
from extensions import _novatenant_view as novatenant_view
from quantum.api import api_common as common
from quantum.common import exceptions as qexception
from quantum.common import extensions
from quantum.manager import QuantumManager
from quantum.plugins.cisco.common import cisco_faults as faults
class Novatenant(object):
"""extension class Novatenant"""
def __init__(self):
pass
@classmethod
def get_name(cls):
""" Returns Ext Resource Name """
return "Cisco Nova Tenant"
@classmethod
def get_alias(cls):
""" Returns Ext Resource alias"""
return "Cisco Nova Tenant"
@classmethod
def get_description(cls):
""" Returns Ext Resource Description """
return "novatenant resource is used by nova side to invoke quantum api"
@classmethod
def get_namespace(cls):
""" Returns Ext Resource Namespace """
return "http://docs.ciscocloud.com/api/ext/novatenant/v1.0"
@classmethod
def get_updated(cls):
""" Returns Ext Resource Updated Time """
return "2011-08-09T13:25:27-06:00"
@classmethod
def get_resources(cls):
""" Returns Ext Resource """
parent_resource = dict(member_name="tenant",
collection_name="extensions/csco/tenants")
member_actions = {'get_host': "PUT",
'get_instance_port': "PUT"}
controller = NovatenantsController(QuantumManager.get_plugin())
return [extensions.ResourceExtension('novatenants', controller,
parent=parent_resource,
member_actions=member_actions)]
class NovatenantsController(common.QuantumController):
""" Novatenant API controller
based on QuantumController """
_Novatenant_ops_param_list = [{
'param-name': 'novatenant_name',
'required': True}]
_get_host_ops_param_list = [{
'param-name': 'instance_id',
'required': True}, {
'param-name': 'instance_desc',
'required': True}]
_serialization_metadata = {
"application/xml": {
"attributes": {
"novatenant": ["id", "name"],
},
},
}
def __init__(self, plugin):
self._resource_name = 'novatenant'
self._plugin = plugin
#added for cisco's extension
# pylint: disable-msg=E1101,W0613
def get_host(self, request, tenant_id, id):
content_type = request.best_match_content_type()
print "Content type:%s" % content_type
try:
req_params = \
self._parse_request_params(request,
self._get_host_ops_param_list)
except exc.HTTPError as exp:
return faults.Fault(exp)
instance_id = req_params['instance_id']
instance_desc = req_params['instance_desc']
try:
host = self._plugin.get_host(tenant_id, instance_id, instance_desc)
builder = novatenant_view.get_view_builder(request)
result = builder.build_host(host)
return result
except qexception.PortNotFound as exp:
return faults.Fault(faults.PortNotFound(exp))
def get_instance_port(self, request, tenant_id, id):
content_type = request.best_match_content_type()
print "Content type:%s" % content_type
try:
req_params = \
self._parse_request_params(request,
self._get_host_ops_param_list)
except exc.HTTPError as exp:
return faults.Fault(exp)
instance_id = req_params['instance_id']
instance_desc = req_params['instance_desc']
try:
vif = self._plugin. \
get_instance_port(tenant_id, instance_id, instance_desc)
builder = novatenant_view.get_view_builder(request)
result = builder.build_vif(vif)
return result
except qexception.PortNotFound as exp:
return faults.Fault(faults.PortNotFound(exp))

218
extensions/portprofile.py Normal file
View File

@ -0,0 +1,218 @@
"""
# 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: Ying Liu, Cisco Systems, Inc.
#
"""
from webob import exc
from extensions import _pprofiles as pprofiles_view
from quantum.api import api_common as common
from quantum.common import exceptions as qexception
from quantum.common import extensions
from quantum.manager import QuantumManager
from quantum.plugins.cisco.common import cisco_exceptions as exception
from quantum.plugins.cisco.common import cisco_faults as faults
class Portprofile(object):
"""extension class Portprofile"""
def __init__(self):
pass
@classmethod
def get_name(cls):
""" Returns Ext Resource Name """
return "Cisco Port Profile"
@classmethod
def get_alias(cls):
""" Returns Ext Resource alias """
return "Cisco Port Profile"
@classmethod
def get_description(cls):
""" Returns Ext Resource Description """
return "Portprofile include QoS information"
@classmethod
def get_namespace(cls):
""" Returns Ext Resource Namespace """
return "http://docs.ciscocloud.com/api/ext/portprofile/v1.0"
@classmethod
def get_updated(cls):
""" Returns Ext Resource Updated time """
return "2011-07-23T13:25:27-06:00"
@classmethod
def get_resources(cls):
""" Returns all defined resources """
parent_resource = dict(member_name="tenant",
collection_name="extensions/csco/tenants")
member_actions = {'associate_portprofile': "PUT",
'disassociate_portprofile': "PUT"}
controller = PortprofilesController(QuantumManager.get_plugin())
return [extensions.ResourceExtension('portprofiles', controller,
parent=parent_resource,
member_actions=member_actions)]
class PortprofilesController(common.QuantumController):
""" portprofile API controller
based on QuantumController """
def __init__(self, plugin):
self._resource_name = 'portprofile'
self._plugin = plugin
self._portprofile_ops_param_list = [{
'param-name': 'portprofile_name',
'required': True}, {
'param-name': 'qos_name',
'required': True}, {
'param-name': 'assignment',
'required': False}]
self._assignprofile_ops_param_list = [{
'param-name': 'network-id',
'required': True}, {
'param-name': 'port-id',
'required': True}]
self._serialization_metadata = {
"application/xml": {
"attributes": {
"portprofile": ["id", "name"],
},
},
}
def index(self, request, tenant_id):
""" Returns a list of portprofile ids """
return self._items(request, tenant_id, is_detail=False)
def _items(self, request, tenant_id, is_detail):
""" Returns a list of portprofiles. """
portprofiles = self._plugin.get_all_portprofiles(tenant_id)
builder = pprofiles_view.get_view_builder(request)
result = [builder.build(portprofile, is_detail)['portprofile']
for portprofile in portprofiles]
return dict(portprofiles=result)
# pylint: disable-msg=E1101
def show(self, request, tenant_id, id):
""" Returns portprofile details for the given portprofile id """
try:
portprofile = self._plugin.get_portprofile_details(
tenant_id, id)
builder = pprofiles_view.get_view_builder(request)
#build response with details
result = builder.build(portprofile, True)
return dict(portprofiles=result)
except exception.PortProfileNotFound as exp:
return faults.Fault(faults.PortprofileNotFound(exp))
def create(self, request, tenant_id):
""" Creates a new portprofile for a given tenant """
#look for portprofile name in request
try:
req_params = \
self._parse_request_params(request,
self._portprofile_ops_param_list)
except exc.HTTPError as exp:
return faults.Fault(exp)
portprofile = self._plugin.\
create_portprofile(tenant_id,
req_params['portprofile_name'],
req_params['qos_name'])
builder = pprofiles_view.get_view_builder(request)
result = builder.build(portprofile)
return dict(portprofiles=result)
def update(self, request, tenant_id, id):
""" Updates the name for the portprofile with the given id """
try:
req_params = \
self._parse_request_params(request,
self._portprofile_ops_param_list)
except exc.HTTPError as exp:
return faults.Fault(exp)
try:
portprofile = self._plugin.\
rename_portprofile(tenant_id,
id, req_params['portprofile_name'])
builder = pprofiles_view.get_view_builder(request)
result = builder.build(portprofile, True)
return dict(portprofiles=result)
except exception.PortProfileNotFound as exp:
return faults.Fault(faults.PortprofileNotFound(exp))
def delete(self, request, tenant_id, id):
""" Destroys the portprofile with the given id """
try:
self._plugin.delete_portprofile(tenant_id, id)
return exc.HTTPAccepted()
except exception.PortProfileNotFound as exp:
return faults.Fault(faults.PortprofileNotFound(exp))
def associate_portprofile(self, request, tenant_id, id):
""" associate a portprofile to the port """
content_type = request.best_match_content_type()
print "Content type:%s" % content_type
try:
req_params = \
self._parse_request_params(request,
self._assignprofile_ops_param_list)
except exc.HTTPError as exp:
return faults.Fault(exp)
net_id = req_params['network-id'].strip()
port_id = req_params['port-id'].strip()
try:
self._plugin.associate_portprofile(tenant_id,
net_id, port_id,
id)
return exc.HTTPAccepted()
except exception.PortProfileNotFound as exp:
return faults.Fault(faults.PortprofileNotFound(exp))
except qexception.PortNotFound as exp:
return faults.Fault(faults.PortNotFound(exp))
def disassociate_portprofile(self, request, tenant_id, id):
""" Disassociate a portprofile from a port """
content_type = request.best_match_content_type()
print "Content type:%s" % content_type
try:
req_params = \
self._parse_request_params(request,
self._assignprofile_ops_param_list)
except exc.HTTPError as exp:
return faults.Fault(exp)
net_id = req_params['network-id'].strip()
port_id = req_params['port-id'].strip()
try:
self._plugin. \
disassociate_portprofile(tenant_id,
net_id, port_id, id)
return exc.HTTPAccepted()
except exception.PortProfileNotFound as exp:
return faults.Fault(faults.PortprofileNotFound(exp))
except qexception.PortNotFound as exp:
return faults.Fault(faults.PortNotFound(exp))

164
extensions/qos.py Normal file
View File

@ -0,0 +1,164 @@
"""
# 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: Ying Liu, Cisco Systems, Inc.
#
"""
import logging
from webob import exc
from extensions import _qos_view as qos_view
from quantum.api import api_common as common
from quantum.common import extensions
from quantum.manager import QuantumManager
from quantum.plugins.cisco.common import cisco_exceptions as exception
from quantum.plugins.cisco.common import cisco_faults as faults
LOG = logging.getLogger('quantum.api.qoss')
class Qos(object):
"""Qos extension file"""
def __init__(self):
pass
@classmethod
def get_name(cls):
""" Returns Ext Resource Name """
return "Cisco qos"
@classmethod
def get_alias(cls):
""" Returns Ext Resource Alias """
return "Cisco qos"
@classmethod
def get_description(cls):
""" Returns Ext Resource Description """
return "qos include username and password"
@classmethod
def get_namespace(cls):
""" Returns Ext Resource Namespace """
return "http://docs.ciscocloud.com/api/ext/qos/v1.0"
@classmethod
def get_updated(cls):
""" Returns Ext Resource update """
return "2011-07-25T13:25:27-06:00"
@classmethod
def get_resources(cls):
""" Returns Ext Resources """
parent_resource = dict(member_name="tenant",
collection_name="extensions/csco/tenants")
controller = QosController(QuantumManager.get_plugin())
return [extensions.ResourceExtension('qoss', controller,
parent=parent_resource)]
class QosController(common.QuantumController):
""" qos API controller
based on QuantumController """
_qos_ops_param_list = [{
'param-name': 'qos_name',
'required': True}, {
'param-name': 'qos_desc',
'required': True}]
_serialization_metadata = {
"application/xml": {
"attributes": {
"qos": ["id", "name"],
},
},
}
def __init__(self, plugin):
self._resource_name = 'qos'
self._plugin = plugin
def index(self, request, tenant_id):
""" Returns a list of qos ids """
return self._items(request, tenant_id, is_detail=False)
def _items(self, request, tenant_id, is_detail):
""" Returns a list of qoss. """
qoss = self._plugin.get_all_qoss(tenant_id)
builder = qos_view.get_view_builder(request)
result = [builder.build(qos, is_detail)['qos']
for qos in qoss]
return dict(qoss=result)
# pylint: disable-msg=E1101
def show(self, request, tenant_id, id):
""" Returns qos details for the given qos id """
try:
qos = self._plugin.get_qos_details(
tenant_id, id)
builder = qos_view.get_view_builder(request)
#build response with details
result = builder.build(qos, True)
return dict(qoss=result)
except exception.QosNotFound as exp:
return faults.Fault(faults.QosNotFound(exp))
def create(self, request, tenant_id):
""" Creates a new qos for a given tenant """
#look for qos name in request
try:
req_params = \
self._parse_request_params(request,
self._qos_ops_param_list)
except exc.HTTPError as exp:
return faults.Fault(exp)
qos = self._plugin.\
create_qos(tenant_id,
req_params['qos_name'],
req_params['qos_desc'])
builder = qos_view.get_view_builder(request)
result = builder.build(qos)
return dict(qoss=result)
def update(self, request, tenant_id, id):
""" Updates the name for the qos with the given id """
try:
req_params = \
self._parse_request_params(request,
self._qos_ops_param_list)
except exc.HTTPError as exp:
return faults.Fault(exp)
try:
qos = self._plugin.\
rename_qos(tenant_id,
id, req_params['qos_name'])
builder = qos_view.get_view_builder(request)
result = builder.build(qos, True)
return dict(qoss=result)
except exception.QosNotFound as exp:
return faults.Fault(faults.QosNotFound(exp))
def delete(self, request, tenant_id, id):
""" Destroys the qos with the given id """
try:
self._plugin.delete_qos(tenant_id, id)
return exc.HTTPAccepted()
except exception.QosNotFound as exp:
return faults.Fault(faults.QosNotFound(exp))

View File

@ -63,6 +63,7 @@ class Controller(common.QuantumController):
except exc.HTTPError as e:
return faults.Fault(e)
try:
LOG.debug("PLUGGING INTERFACE:%s", request_params['id'])
self._plugin.plug_interface(tenant_id, network_id, id,
request_params['id'])
return exc.HTTPNoContent()

View File

@ -23,7 +23,7 @@ def get_view_builder(req):
class ViewBuilder(object):
def __init__(self, base_url):
def __init__(self, base_url=None):
"""
:param base_url: url of the root wsgi application
"""

View File

@ -23,7 +23,7 @@ def get_view_builder(req):
class ViewBuilder(object):
def __init__(self, base_url):
def __init__(self, base_url=None):
"""
:param base_url: url of the root wsgi application
"""

View File

@ -1,392 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2011 Nicira Networks, Inc.
# Copyright 2011 Citrix Systems
#
# 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.
import httplib
import logging as LOG
import json
import socket
import sys
import urllib
from manager import QuantumManager
from optparse import OptionParser
from client import Client
FORMAT = "json"
### -- Core CLI functions
def list_nets(manager, *args):
tenant_id = args[0]
networks = manager.get_all_networks(tenant_id)
print "Virtual Networks on Tenant:%s\n" % tenant_id
for net in networks:
id = net["net-id"]
name = net["net-name"]
print "\tNetwork ID:%s \n\tNetwork Name:%s \n" % (id, name)
def api_list_nets(client, *args):
tenant_id = args[0]
res = client.list_networks()
LOG.debug(res)
print "Virtual Networks on Tenant:%s\n" % tenant_id
for n in res["networks"]:
net_id = n["id"]
print "\tNetwork ID:%s\n" % (net_id)
# TODO(bgh): we should make this call pass back the name too
# name = n["net-name"]
# LOG.info("\tNetwork ID:%s \n\tNetwork Name:%s \n" % (id, name))
def create_net(manager, *args):
tid, name = args
new_net_id = manager.create_network(tid, name)
print "Created a new Virtual Network with ID:%s\n" % new_net_id
def api_create_net(client, *args):
tid, name = args
data = {'network': {'net-name': '%s' % name}}
res = client.create_network(data)
LOG.debug(res)
nid = None
try:
nid = res["network"]["id"]
except Exception, e:
print "Failed to create network"
# TODO(bgh): grab error details from ws request result
return
print "Created a new Virtual Network with ID:%s\n" % nid
def delete_net(manager, *args):
tid, nid = args
manager.delete_network(tid, nid)
print "Deleted Virtual Network with ID:%s" % nid
def api_delete_net(client, *args):
tid, nid = args
try:
res = client.delete_network(nid)
print "Deleted Virtual Network with ID:%s" % nid
except Exception, e:
print "Failed to delete network"
LOG.error("Failed to delete network: %s" % e)
def detail_net(manager, *args):
tid, nid = args
iface_list = manager.get_network_details(tid, nid)
print "Remote Interfaces on Virtual Network:%s\n" % nid
for iface in iface_list:
print "\tRemote interface:%s" % iface
def api_detail_net(client, *args):
tid, nid = args
try:
res = client.show_network_details(nid)["network"]
except Exception, e:
LOG.error("Failed to get network details: %s" % e)
return
try:
ports = client.list_ports(nid)
except Exception, e:
LOG.error("Failed to list ports: %s" % e)
return
print "Network %s (%s)" % (res['name'], res['id'])
print "Remote Interfaces on Virtual Network:%s\n" % nid
for port in ports["ports"]:
pid = port["id"]
res = client.show_port_attachment(nid, pid)
LOG.debug(res)
remote_iface = res["attachment"]["id"]
print "\tRemote interface:%s" % remote_iface
def rename_net(manager, *args):
tid, nid, name = args
manager.rename_network(tid, nid, name)
print "Renamed Virtual Network with ID:%s" % nid
def api_rename_net(client, *args):
tid, nid, name = args
data = {'network': {'name': '%s' % name}}
try:
res = client.update_network(nid, data)
except Exception, e:
LOG.error("Failed to rename network %s: %s" % (nid, e))
return
LOG.debug(res)
print "Renamed Virtual Network with ID:%s" % nid
def list_ports(manager, *args):
tid, nid = args
ports = manager.get_all_ports(tid, nid)
print "Ports on Virtual Network:%s\n" % nid
for port in ports:
print "\tVirtual Port:%s" % port["port-id"]
def api_list_ports(client, *args):
tid, nid = args
try:
ports = client.list_ports(nid)
except Exception, e:
LOG.error("Failed to list ports: %s" % e)
return
LOG.debug(ports)
print "Ports on Virtual Network:%s\n" % nid
for port in ports["ports"]:
print "\tVirtual Port:%s" % port["id"]
def create_port(manager, *args):
tid, nid = args
new_port = manager.create_port(tid, nid)
print "Created Virtual Port:%s " \
"on Virtual Network:%s" % (new_port, nid)
def api_create_port(client, *args):
tid, nid = args
try:
res = client.create_port(nid)
except Exception, e:
LOG.error("Failed to create port: %s" % e)
return
new_port = res["port"]["id"]
print "Created Virtual Port:%s " \
"on Virtual Network:%s" % (new_port, nid)
def delete_port(manager, *args):
tid, nid, pid = args
manager.delete_port(tid, nid, pid)
LOG.info("Deleted Virtual Port:%s " \
"on Virtual Network:%s" % (pid, nid))
def api_delete_port(client, *args):
tid, nid, pid = args
try:
res = client.delete_port(nid, pid)
except Exception, e:
LOG.error("Failed to delete port: %s" % e)
return
LOG.info("Deleted Virtual Port:%s " \
"on Virtual Network:%s" % (pid, nid))
print "Deleted Virtual Port:%s " \
"on Virtual Network:%s" % (pid, nid)
def detail_port(manager, *args):
tid, nid, pid = args
port_detail = manager.get_port_details(tid, nid, pid)
print "Virtual Port:%s on Virtual Network:%s " \
"contains remote interface:%s" % (pid, nid, port_detail)
def api_detail_port(client, *args):
tid, nid, pid = args
try:
port = client.show_port_details(nid, pid)["port"]
att = client.show_port_attachment(nid, pid)
except Exception, e:
LOG.error("Failed to get port details: %s" % e)
return
id = port['id']
interface_id = att['id']
LOG.debug(port)
print "Virtual Port:%s on Virtual Network:%s " \
"contains remote interface:%s" % (pid, nid, interface_id)
def plug_iface(manager, *args):
tid, nid, pid, vid = args
manager.plug_interface(tid, nid, pid, vid)
print "Plugged remote interface:%s " \
"into Virtual Network:%s" % (vid, nid)
def api_plug_iface(client, *args):
tid, nid, pid, vid = args
try:
data = {'attachment': {'id': '%s' % vid}}
res = client.attach_resource(nid, pid, data)
except Exception, e:
LOG.error("Failed to plug iface \"%s\" to port \"%s\": %s" % (vid,
pid, e))
return
LOG.debug(res)
print "Plugged interface \"%s\" to port:%s on network:%s" % (vid, pid, nid)
def unplug_iface(manager, *args):
tid, nid, pid = args
manager.unplug_interface(tid, nid, pid)
print "UnPlugged remote interface " \
"from Virtual Port:%s Virtual Network:%s" % (pid, nid)
def api_unplug_iface(client, *args):
tid, nid, pid = args
try:
res = client.detach_resource(nid, pid)
except Exception, e:
LOG.error("Failed to unplug iface from port \"%s\": %s" % (pid, e))
return
LOG.debug(res)
print "Unplugged interface from port:%s on network:%s" % (pid, nid)
commands = {
"list_nets": {
"func": list_nets,
"api_func": api_list_nets,
"args": ["tenant-id"]},
"create_net": {
"func": create_net,
"api_func": api_create_net,
"args": ["tenant-id", "net-name"]},
"delete_net": {
"func": delete_net,
"api_func": api_delete_net,
"args": ["tenant-id", "net-id"]},
"detail_net": {
"func": detail_net,
"api_func": api_detail_net,
"args": ["tenant-id", "net-id"]},
"rename_net": {
"func": rename_net,
"api_func": api_rename_net,
"args": ["tenant-id", "net-id", "new-name"]},
"list_ports": {
"func": list_ports,
"api_func": api_list_ports,
"args": ["tenant-id", "net-id"]},
"create_port": {
"func": create_port,
"api_func": api_create_port,
"args": ["tenant-id", "net-id"]},
"delete_port": {
"func": delete_port,
"api_func": api_delete_port,
"args": ["tenant-id", "net-id", "port-id"]},
"detail_port": {
"func": detail_port,
"api_func": api_detail_port,
"args": ["tenant-id", "net-id", "port-id"]},
"plug_iface": {
"func": plug_iface,
"api_func": api_plug_iface,
"args": ["tenant-id", "net-id", "port-id", "iface-id"]},
"unplug_iface": {
"func": unplug_iface,
"api_func": api_unplug_iface,
"args": ["tenant-id", "net-id", "port-id"]}, }
def help():
print "\nCommands:"
for k in commands.keys():
print " %s %s" % (k,
" ".join(["<%s>" % y for y in commands[k]["args"]]))
def build_args(cmd, cmdargs, arglist):
args = []
orig_arglist = arglist[:]
try:
for x in cmdargs:
args.append(arglist[0])
del arglist[0]
except Exception, e:
LOG.error("Not enough arguments for \"%s\" (expected: %d, got: %d)" % (
cmd, len(cmdargs), len(orig_arglist)))
print "Usage:\n %s %s" % (cmd,
" ".join(["<%s>" % y for y in commands[cmd]["args"]]))
return None
if len(arglist) > 0:
LOG.error("Too many arguments for \"%s\" (expected: %d, got: %d)" % (
cmd, len(cmdargs), len(orig_arglist)))
print "Usage:\n %s %s" % (cmd,
" ".join(["<%s>" % y for y in commands[cmd]["args"]]))
return None
return args
if __name__ == "__main__":
usagestr = "Usage: %prog [OPTIONS] <command> [args]"
parser = OptionParser(usage=usagestr)
parser.add_option("-l", "--load-plugin", dest="load_plugin",
action="store_true", default=False,
help="Load plugin directly instead of using WS API")
parser.add_option("-H", "--host", dest="host",
type="string", default="127.0.0.1", help="ip address of api host")
parser.add_option("-p", "--port", dest="port",
type="int", default=9696, help="api poort")
parser.add_option("-s", "--ssl", dest="ssl",
action="store_true", default=False, help="use ssl")
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)
if len(args) < 1:
parser.print_help()
help()
sys.exit(1)
cmd = args[0]
if cmd not in commands.keys():
LOG.error("Unknown command: %s" % cmd)
help()
sys.exit(1)
args = build_args(cmd, commands[cmd]["args"], args[1:])
if not args:
sys.exit(1)
LOG.debug("Executing command \"%s\" with args: %s" % (cmd, args))
if not options.load_plugin:
client = Client(options.host, options.port, options.ssl,
args[0], FORMAT)
if "api_func" not in commands[cmd]:
LOG.error("API version of \"%s\" is not yet implemented" % cmd)
sys.exit(1)
commands[cmd]["api_func"](client, *args)
else:
quantum = QuantumManager()
manager = quantum.get_plugin()
commands[cmd]["func"](manager, *args)
sys.exit(0)

228
quantum/cli_lib.py Executable file
View File

@ -0,0 +1,228 @@
#!/usr/bin/env python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2011 Nicira Networks, Inc.
# Copyright 2011 Citrix Systems
#
# 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: Salvatore Orlando, Citrix
import Cheetah.Template as cheetah_template
import logging
import os
import sys
FORMAT = "json"
CLI_TEMPLATE = "cli_output.template"
LOG = logging.getLogger('quantum.cli_lib')
def _handle_exception(ex):
LOG.exception(sys.exc_info())
print "Exception:%s - %s" % (sys.exc_info()[0], sys.exc_info()[1])
status_code = None
message = None
# Retrieve dict at 1st element of tuple at last argument
if ex.args and isinstance(ex.args[-1][0], dict):
status_code = ex.args[-1][0].get('status_code', None)
message = ex.args[-1][0].get('message', None)
msg_1 = "Command failed with error code: %s" \
% (status_code or '<missing>')
msg_2 = "Error message:%s" % (message or '<missing>')
LOG.exception(msg_1 + "-" + msg_2)
print msg_1
print msg_2
def prepare_output(cmd, tenant_id, response):
""" Fills a cheetah template with the response """
#add command and tenant to response for output generation
LOG.debug("Preparing output for response:%s", response)
response['cmd'] = cmd
response['tenant_id'] = tenant_id
template_path = os.path.join(os.path.dirname(__file__), CLI_TEMPLATE)
template_file = open(template_path).read()
output = str(cheetah_template.Template(template_file,
searchList=response))
LOG.debug("Finished preparing output for command:%s", cmd)
return output
def list_nets(client, *args):
tenant_id = args[0]
res = client.list_networks()
LOG.debug("Operation 'list_networks' executed.")
output = prepare_output("list_nets", tenant_id, res)
print output
def create_net(client, *args):
tenant_id, name = args
data = {'network': {'name': name}}
new_net_id = None
try:
res = client.create_network(data)
new_net_id = res["network"]["id"]
LOG.debug("Operation 'create_network' executed.")
output = prepare_output("create_net", tenant_id,
dict(network_id=new_net_id))
print output
except Exception as ex:
_handle_exception(ex)
def delete_net(client, *args):
tenant_id, network_id = args
try:
client.delete_network(network_id)
LOG.debug("Operation 'delete_network' executed.")
output = prepare_output("delete_net", tenant_id,
dict(network_id=network_id))
print output
except Exception as ex:
_handle_exception(ex)
def show_net(client, *args):
tenant_id, network_id = args
try:
#NOTE(salvatore-orlando) changed for returning exclusively
# output for GET /networks/{net-id} API operation
res = client.show_network_details(network_id)["network"]
LOG.debug("Operation 'show_network_details' executed.")
output = prepare_output("show_net", tenant_id, dict(network=res))
print output
except Exception as ex:
_handle_exception(ex)
def rename_net(client, *args):
tenant_id, network_id, name = args
data = {'network': {'name': '%s' % name}}
try:
client.update_network(network_id, data)
LOG.debug("Operation 'update_network' executed.")
# Response has no body. Use data for populating output
data['network']['id'] = network_id
output = prepare_output("rename_net", tenant_id, data)
print output
except Exception as ex:
_handle_exception(ex)
def list_ports(client, *args):
tenant_id, network_id = args
try:
ports = client.list_ports(network_id)
LOG.debug("Operation 'list_ports' executed.")
data = ports
data['network_id'] = network_id
output = prepare_output("list_ports", tenant_id, data)
print output
except Exception as ex:
_handle_exception(ex)
def create_port(client, *args):
tenant_id, network_id = args
try:
res = client.create_port(network_id)
LOG.debug("Operation 'create_port' executed.")
new_port_id = res["port"]["id"]
output = prepare_output("create_port", tenant_id,
dict(network_id=network_id,
port_id=new_port_id))
print output
except Exception as ex:
_handle_exception(ex)
def delete_port(client, *args):
tenant_id, network_id, port_id = args
try:
client.delete_port(network_id, port_id)
LOG.debug("Operation 'delete_port' executed.")
output = prepare_output("delete_port", tenant_id,
dict(network_id=network_id,
port_id=port_id))
print output
except Exception as ex:
_handle_exception(ex)
return
def show_port(client, *args):
tenant_id, network_id, port_id = args
try:
port = client.show_port_details(network_id, port_id)["port"]
LOG.debug("Operation 'list_port_details' executed.")
#NOTE(salvatore-orland): current API implementation does not
#return attachment with GET operation on port. Once API alignment
#branch is merged, update client to use the detail action.
# (danwent) Until then, just make additonal webservice call.
attach = client.show_port_attachment(network_id, port_id)['attachment']
if "id" in attach:
port['attachment'] = attach['id']
else:
port['attachment'] = '<none>'
output = prepare_output("show_port", tenant_id,
dict(network_id=network_id,
port=port))
print output
except Exception as ex:
_handle_exception(ex)
def set_port_state(client, *args):
tenant_id, network_id, port_id, new_state = args
data = {'port': {'state': '%s' % new_state}}
try:
client.set_port_state(network_id, port_id, data)
LOG.debug("Operation 'set_port_state' executed.")
# Response has no body. Use data for populating output
data['network_id'] = network_id
data['port']['id'] = port_id
output = prepare_output("set_port_state", tenant_id, data)
print output
except Exception as ex:
_handle_exception(ex)
def plug_iface(client, *args):
tenant_id, network_id, port_id, attachment = args
try:
data = {'attachment': {'id': '%s' % attachment}}
client.attach_resource(network_id, port_id, data)
LOG.debug("Operation 'attach_resource' executed.")
output = prepare_output("plug_iface", tenant_id,
dict(network_id=network_id,
port_id=port_id,
attachment=attachment))
print output
except Exception as ex:
_handle_exception(ex)
def unplug_iface(client, *args):
tenant_id, network_id, port_id = args
try:
client.detach_resource(network_id, port_id)
LOG.debug("Operation 'detach_resource' executed.")
output = prepare_output("unplug_iface", tenant_id,
dict(network_id=network_id,
port_id=port_id))
print output
except Exception as ex:
_handle_exception(ex)

View File

@ -0,0 +1,56 @@
## Cheetah template for cli output
#if $cmd == 'list_nets'
Virtual Networks for Tenant $tenant_id
#for $network in $networks
Network ID: $network.id
#end for
#elif $cmd == 'create_net'
Created a new Virtual Network with ID: $network_id
for Tenant $tenant_id
#elif $cmd == 'delete_net'
Deleted Virtual Network with ID: $network_id
for Tenant $tenant_id
#elif $cmd == 'show_net'
Network ID: $network.id
Network Name: $network.name
for Tenant: $tenant_id
#elif $cmd == 'rename_net'
Renamed Virtual Network with ID: $network.id
New name is: $network.name
for Tenant $tenant_id,
#elif $cmd == 'list_ports'
Ports on Virtual Network: $network_id
for Tenant: $tenant_id
#for $port in $ports
Logical Port: $port.id
#end for
#elif $cmd == 'create_port'
Created new Logical Port with ID: $port_id
on Virtual Network: $network_id
for Tenant: $tenant_id
#elif $cmd == 'delete_port'
Deleted Logical Port with ID: $port_id
on Virtual Network: $network_id
for Tenant: $tenant_id
#elif $cmd == 'set_port_state'
Updated state for Logical Port with ID: $port.id
new state is: $port.state
on Virtual Network: $network_id
for tenant: $tenant_id
#elif $cmd == 'show_port'
Logical Port ID: $port.id
administrative State: $port.state
interface: $port.attachment
on Virtual Network: $network_id
for Tenant: $tenant_id
#elif $cmd == 'plug_iface'
Plugged interface $attachment
into Logical Port: $port_id
on Virtual Network: $network_id
for Tenant: $tenant_id
#elif $cmd == 'unplug_iface'
Unplugged interface from Logical Port: $port_id
on Virtual Network: $network_id
for Tenant: $tenant_id
#end if

View File

@ -16,12 +16,15 @@
# under the License.
# @author: Tyler Smith, Cisco Systems
import logging
import httplib
import socket
import urllib
from quantum.common.wsgi import Serializer
from quantum.common import exceptions
from quantum.common import exceptions
from quantum.common.wsgi import Serializer
LOG = logging.getLogger('quantum.client')
EXCEPTIONS = {
400: exceptions.BadInputError,
401: exceptions.NotAuthorized,
@ -29,8 +32,8 @@ EXCEPTIONS = {
421: exceptions.NetworkInUse,
430: exceptions.PortNotFound,
431: exceptions.StateInvalid,
432: exceptions.PortInUse,
440: exceptions.AlreadyAttached}
432: exceptions.PortInUseClient,
440: exceptions.AlreadyAttachedClient}
class ApiCall(object):
@ -60,6 +63,17 @@ class Client(object):
"""A base client class - derived from Glance.BaseClient"""
#Metadata for deserializing xml
_serialization_metadata = {
"application/xml": {
"attributes": {
"network": ["id", "name"],
"port": ["id", "state"],
"attachment": ["id"]},
"plurals": {"networks": "network",
"ports": "port"}},
}
# Action query strings
networks_path = "/networks"
network_path = "/networks/%s"
@ -105,8 +119,19 @@ class Client(object):
else:
return httplib.HTTPConnection
def _send_request(self, conn, method, action, body, headers):
# Salvatore: Isolating this piece of code in its own method to
# facilitate stubout for testing
if self.logger:
self.logger.debug("Quantum Client Request:\n" \
+ method + " " + action + "\n")
if body:
self.logger.debug(body)
conn.request(method, action, body, headers)
return conn.getresponse()
def do_request(self, method, action, body=None,
headers=None, params=None):
headers=None, params=None, exception_args={}):
"""
Connects to the server and issues a request.
Returns the result data, or raises an appropriate exception if
@ -119,7 +144,7 @@ class Client(object):
to action
"""
LOG.debug("Client issuing request: %s", action)
# Ensure we have a tenant id
if not self.tenant:
raise Exception("Tenant ID not set")
@ -131,7 +156,6 @@ class Client(object):
if type(params) is dict:
action += '?' + urllib.urlencode(params)
if body:
body = self.serialize(body)
@ -139,7 +163,6 @@ class Client(object):
connection_type = self.get_connection_type()
headers = headers or {"Content-Type":
"application/%s" % self.format}
# Open connection and send request, handling SSL certs
certs = {'key_file': self.key_file, 'cert_file': self.cert_file}
certs = dict((x, certs[x]) for x in certs if certs[x] != None)
@ -148,15 +171,7 @@ class Client(object):
conn = connection_type(self.host, self.port, **certs)
else:
conn = connection_type(self.host, self.port)
if self.logger:
self.logger.debug("Quantum Client Request:\n" \
+ method + " " + action + "\n")
if body:
self.logger.debug(body)
conn.request(method, action, body, headers)
res = conn.getresponse()
res = self._send_request(conn, method, action, body, headers)
status_code = self.get_status_code(res)
data = res.read()
@ -170,13 +185,21 @@ class Client(object):
httplib.NO_CONTENT):
return self.deserialize(data, status_code)
else:
error_message = res.read()
LOG.debug("Server returned error: %s", status_code)
LOG.debug("Error message: %s", error_message)
# Create exception with HTTP status code and message
if res.status in EXCEPTIONS:
raise EXCEPTIONS[res.status]()
raise Exception("Server returned error: %s" % res.read())
raise EXCEPTIONS[res.status](**exception_args)
# Add error code and message to exception arguments
ex = Exception("Server returned error: %s" % status_code)
ex.args = ([dict(status_code=status_code,
message=error_message)],)
raise ex
except (socket.error, IOError), e:
raise Exception("Unable to connect to "
"server. Got error: %s" % e)
msg = "Unable to connect to server. Got error: %s" % e
LOG.exception(msg)
raise Exception(msg)
def get_status_code(self, response):
"""
@ -205,9 +228,10 @@ class Client(object):
"""
Deserializes a an xml or json string into a dictionary
"""
if status_code == 202:
if status_code in (202, 204):
return data
return Serializer().deserialize(data, self.content_type())
return Serializer(self._serialization_metadata).\
deserialize(data, self.content_type())
def content_type(self, format=None):
"""
@ -230,7 +254,8 @@ class Client(object):
"""
Fetches the details of a certain network
"""
return self.do_request("GET", self.network_path % (network))
return self.do_request("GET", self.network_path % (network),
exception_args={"net_id": network})
@ApiCall
def create_network(self, body=None):
@ -244,14 +269,16 @@ class Client(object):
"""
Updates a network
"""
return self.do_request("PUT", self.network_path % (network), body=body)
return self.do_request("PUT", self.network_path % (network), body=body,
exception_args={"net_id": network})
@ApiCall
def delete_network(self, network):
"""
Deletes the specified network
"""
return self.do_request("DELETE", self.network_path % (network))
return self.do_request("DELETE", self.network_path % (network),
exception_args={"net_id": network})
@ApiCall
def list_ports(self, network):
@ -265,7 +292,8 @@ class Client(object):
"""
Fetches the details of a certain port
"""
return self.do_request("GET", self.port_path % (network, port))
return self.do_request("GET", self.port_path % (network, port),
exception_args={"net_id": network, "port_id": port})
@ApiCall
def create_port(self, network, body=None):
@ -273,14 +301,16 @@ class Client(object):
Creates a new port on a given network
"""
body = self.serialize(body)
return self.do_request("POST", self.ports_path % (network), body=body)
return self.do_request("POST", self.ports_path % (network), body=body,
exception_args={"net_id": network})
@ApiCall
def delete_port(self, network, port):
"""
Deletes the specified port from a network
"""
return self.do_request("DELETE", self.port_path % (network, port))
return self.do_request("DELETE", self.port_path % (network, port),
exception_args={"net_id": network, "port_id": port})
@ApiCall
def set_port_state(self, network, port, body=None):
@ -288,14 +318,18 @@ class Client(object):
Sets the state of the specified port
"""
return self.do_request("PUT",
self.port_path % (network, port), body=body)
self.port_path % (network, port), body=body,
exception_args={"net_id": network,
"port_id": port,
"port_state": str(body)})
@ApiCall
def show_port_attachment(self, network, port):
"""
Fetches the attachment-id associated with the specified port
"""
return self.do_request("GET", self.attachment_path % (network, port))
return self.do_request("GET", self.attachment_path % (network, port),
exception_args={"net_id": network, "port_id": port})
@ApiCall
def attach_resource(self, network, port, body=None):
@ -303,7 +337,10 @@ class Client(object):
Sets the attachment-id of the specified port
"""
return self.do_request("PUT",
self.attachment_path % (network, port), body=body)
self.attachment_path % (network, port), body=body,
exception_args={"net_id": network,
"port_id": port,
"attach_id": str(body)})
@ApiCall
def detach_resource(self, network, port):
@ -311,4 +348,5 @@ class Client(object):
Removes the attachment-id of the specified port
"""
return self.do_request("DELETE",
self.attachment_path % (network, port))
self.attachment_path % (network, port),
exception_args={"net_id": network, "port_id": port})

View File

@ -111,6 +111,21 @@ class AlreadyAttached(QuantumException):
"already plugged into port %(att_port_id)s")
# NOTE: on the client side, we often do not know all of the information
# that is known on the server, thus, we create separate exception for
# those scenarios
class PortInUseClient(QuantumException):
message = _("Unable to complete operation on port %(port_id)s " \
"for network %(net_id)s. An attachment " \
"is plugged into the logical port.")
class AlreadyAttachedClient(QuantumException):
message = _("Unable to plug the attachment %(att_id)s into port " \
"%(port_id)s for network %(net_id)s. The attachment is " \
"already plugged into another port.")
class Duplicate(Error):
pass

View File

@ -142,6 +142,13 @@ def network_destroy(net_id):
net = session.query(models.Network).\
filter_by(uuid=net_id).\
one()
ports = session.query(models.Port).\
filter_by(network_id=net_id).\
all()
for p in ports:
session.delete(p)
session.delete(net)
session.flush()
return net

View File

@ -118,10 +118,12 @@ nexus_plugin=quantum.plugins.cisco.nexus.cisco_nexus_plugin.NexusPlugin
# This will be the address at which Quantum sends and receives configuration
# information via SSHv2.
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)
# Port numbers on the Nexus switch to each one of the UCSM 6120s is connected
# Use shortened interface syntax, e.g. "1/10" not "Ethernet1/10".
nexus_first_port=1/10
nexus_second_port=1/11
#Port number where SSH will be running on the Nexus switch. Typically this is 22
#unless you've configured your switch otherwise.
nexus_ssh_port=22
[DRIVER]
@ -191,7 +193,8 @@ result the quantum/plugins/cisco/run_tests.py script.
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
In bash : export PLUGIN_DIR=quantum/plugins/cisco
tcsh/csh : setenv PLUGIN_DIR quantum/plugins/cisco
./run_tests.sh quantum.plugins.cisco.tests.unit.test_l2networkApi
or
@ -202,7 +205,8 @@ result the quantum/plugins/cisco/run_tests.py script.
2. Specific Plugin unit test (needs environment setup as indicated in the
pre-requisites):
export PLUGIN_DIR=quantum/plugins/cisco
In bash : export PLUGIN_DIR=quantum/plugins/cisco
tcsh/csh : setenv PLUGIN_DIR quantum/plugins/cisco
./run_tests.sh quantum.plugins.cisco.tests.unit.<name_of_the file>
or
@ -212,18 +216,30 @@ result the quantum/plugins/cisco/run_tests.py script.
E.g.:
python quantum/plugins/cisco/run_tests.py
quantum.plugins.cisco.tests.unit.test_ucs_plugin.py
quantum.plugins.cisco.tests.unit.test_ucs_plugin
3. All unit tests (needs environment setup as indicated in the pre-requisites):
export PLUGIN_DIR=quantum/plugins/cisco
In bash : export PLUGIN_DIR=quantum/plugins/cisco
tcsh/csh : setenv 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
4. Testing the Extension API
The script is placed alongwith the other cisco unit tests. The location may
change later.
Location quantum/plugins/cisco/tests/unit/test_cisco_extension.py
The script can be executed by :
./run_tests.sh quantum.plugins.cisco.tests.unit.test_cisco_extension
or
python run_tests.py quantum.plugins.cisco.tests.unit.test_cisco_extension
Additional installation required on Nova Compute
------------------------------------------------

View File

@ -58,22 +58,22 @@ TENANT_QOS_LEVELS = 'tenant-qos-levels'
TENANT_CREDENTIALS = 'tenant-credentials'
PORT_PROFILE = 'port-profile'
PROFILE_ID = 'profile-id'
PROFILE_NAME = 'profile-name'
PROFILE_ID = 'profile_id'
PROFILE_NAME = 'profile_name'
PROFILE_VLAN_NAME = 'profile-vlan-name'
PROFILE_VLAN_ID = 'vlan-id'
PROFILE_QOS = 'profile-qos'
PROFILE_QOS = 'qos_name'
PROFILE_ASSOCIATIONS = 'assignment'
QOS_LEVEL_ID = 'qos-id'
QOS_LEVEL_NAME = 'qos-name'
QOS_LEVEL_ID = 'qos_id'
QOS_LEVEL_NAME = 'qos_name'
QOS_LEVEL_ASSOCIATIONS = 'qos-level-associations'
QOS_LEVEL_DESCRIPTION = 'qos-desc'
QOS_LEVEL_DESCRIPTION = 'qos_desc'
CREDENTIAL_ID = 'credential-id'
CREDENTIAL_NAME = 'credential-name'
CREDENTIAL_USERNAME = 'credential-username'
CREDENTIAL_PASSWORD = 'credential-password'
CREDENTIAL_ID = 'credential_id'
CREDENTIAL_NAME = 'credential_name'
CREDENTIAL_USERNAME = 'user_name'
CREDENTIAL_PASSWORD = 'password'
MASKED_PASSWORD = '********'
USERNAME = 'username'
@ -120,3 +120,13 @@ PARAM_LIST = 'param-list'
DEVICE_IP = 'device-ip'
NO_VLAN_ID = 0
HOST_LIST = 'host_list'
HOST_1 = 'host_1'
VIF_DESC = 'vif_desc'
DEVICENAME = 'device'
UCSPROFILE = 'portprofile'
MAX_CREDENTIALS = 65568
MAX_QOS_LEVELS = 1024

View File

@ -22,8 +22,8 @@
import logging as LOG
import os
from quantum.plugins.cisco.common import cisco_constants as const
from quantum.plugins.cisco.common import cisco_configparser as confp
from quantum.plugins.cisco.common import cisco_constants as const
LOG.basicConfig(level=LOG.WARN)
LOG.getLogger(const.LOGGER_COMPONENT_NAME)

View File

@ -1,4 +1,3 @@
"""
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Copyright 2011 Cisco Systems, Inc. All rights reserved.
@ -17,7 +16,7 @@
#
# @author: Sumit Naiksatam, Cisco Systems, Inc.
# @author: Rohit Agarwalla, Cisco Systems, Inc.
"""
"""
Exceptions used by the Cisco plugin
"""
@ -86,8 +85,32 @@ class VlanIDNotFound(exceptions.QuantumException):
class VlanIDNotAvailable(exceptions.QuantumException):
"""VLAN ID is reserved"""
message = _("No available Vlan ID found")
"""No VLAN ID available"""
message = _("No Vlan ID available")
class QosNotFound(exceptions.QuantumException):
"""QoS level with this ID cannot be found"""
message = _("QoS level %(qos_id)s could not be found " \
"for tenant %(tenant_id)s")
class QoSLevelInvalidDelete(exceptions.QuantumException):
"""QoS is associated with a port profile, hence cannot be deleted"""
message = _("QoS level %(qos_id)s could not be deleted " \
"for tenant %(tenant_id)s since association exists")
class CredentialNotFound(exceptions.QuantumException):
"""Credential with this ID cannot be found"""
message = _("Credential %(credential_id)s could not be found " \
"for tenant %(tenant_id)s")
class NexusPortBindingNotFound(exceptions.QuantumException):
"""NexusPort Binding is not present"""
message = _("Nexus Port Binding %(port_id) is not present")
try:
_("test")

View File

@ -0,0 +1,148 @@
"""
# 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: Ying Liu, Cisco Systems, Inc.
#
"""
import webob.dec
from quantum.common import wsgi
class Fault(webob.exc.HTTPException):
"""Error codes for API faults"""
_fault_names = {
400: "malformedRequest",
401: "unauthorized",
421: "PortprofileInUse",
450: "PortprofileNotFound",
451: "CredentialNotFound",
452: "QoSNotFound",
453: "NovatenantNotFound",
470: "serviceUnavailable",
471: "pluginFault"}
def __init__(self, exception):
"""Create a Fault for the given webob.exc.exception."""
self.wrapped_exc = exception
@webob.dec.wsgify(RequestClass=wsgi.Request)
def __call__(self, req):
"""Generate a WSGI response based on the
exception passed to constructor."""
# Replace the body with fault details.
code = self.wrapped_exc.status_int
fault_name = self._fault_names.get(code, "quantumServiceFault")
fault_data = {
fault_name: {
'code': code,
'message': self.wrapped_exc.explanation}}
# 'code' is an attribute on the fault tag itself
content_type = req.best_match_content_type()
self.wrapped_exc.body = wsgi.Serializer().\
serialize(fault_data, content_type)
self.wrapped_exc.content_type = content_type
return self.wrapped_exc
class PortprofileNotFound(webob.exc.HTTPClientError):
"""
subclass of :class:`~HTTPClientError`
This indicates that the server did not find the Portprofile specified
in the HTTP request
code: 450, title: Portprofile not Found
"""
code = 450
title = 'Portprofile Not Found'
explanation = ('Unable to find a Portprofile with'
+ ' the specified identifier.')
class PortNotFound(webob.exc.HTTPClientError):
"""
subclass of :class:`~HTTPClientError`
This indicates that the server did not find the port specified
in the HTTP request for a given network
code: 430, title: Port not Found
"""
code = 430
title = 'Port not Found'
explanation = ('Unable to find a port with the specified identifier.')
class CredentialNotFound(webob.exc.HTTPClientError):
"""
subclass of :class:`~HTTPClientError`
This indicates that the server did not find the Credential specified
in the HTTP request
code: 460, title: Credential not Found
"""
code = 451
title = 'Credential Not Found'
explanation = ('Unable to find a Credential with'
+ ' the specified identifier.')
class QosNotFound(webob.exc.HTTPClientError):
"""
subclass of :class:`~HTTPClientError`
This indicates that the server did not find the QoS specified
in the HTTP request
code: 480, title: QoS not Found
"""
code = 452
title = 'QoS Not Found'
explanation = ('Unable to find a QoS with'
+ ' the specified identifier.')
class NovatenantNotFound(webob.exc.HTTPClientError):
"""
subclass of :class:`~HTTPClientError`
This indicates that the server did not find the Novatenant specified
in the HTTP request
code: 480, title: Nova tenant not Found
"""
code = 453
title = 'Nova tenant Not Found'
explanation = ('Unable to find a Novatenant with'
+ ' the specified identifier.')
class RequestedStateInvalid(webob.exc.HTTPClientError):
"""
subclass of :class:`~HTTPClientError`
This indicates that the server could not update the port state to
to the request value
code: 431, title: Requested State Invalid
"""
code = 431
title = 'Requested State Invalid'
explanation = ('Unable to update port state with specified value.')

View File

@ -1,8 +1,9 @@
[SWITCH]
# Change the following to reflect the Nexus switch details
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>
#Interfaces connected from the Nexus 7K Switch to the two UCSM 6120s, e.g.: 1/10 and 1/11
nexus_first_port=<put_interface_name_here>
nexus_second_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

View File

@ -0,0 +1,24 @@
[DEFAULT]
# Show more verbose log output (sets INFO log level output)
verbose = True
# Show debugging output in logs (sets DEBUG log level output)
debug = False
# Address to bind the API server
bind_host = 0.0.0.0
# Port the bind the API server to
bind_port = 9696
# Path to the extensions
api_extensions_path = ../../../../extensions
[pipeline:extensions_app_with_filter]
pipeline = extensions extensions_test_app
[filter:extensions]
paste.filter_factory = quantum.common.extensions:plugin_aware_extension_middleware_factory
[app:extensions_test_app]
paste.app_factory = quantum.plugins.cisco.tests.unit.test_cisco_extension:app_factory

View File

@ -22,6 +22,7 @@ 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 logging as LOG
import quantum.plugins.cisco.db.api as db
@ -34,6 +35,7 @@ def initialize():
def create_vlanids():
"""Prepopulates the vlan_bindings table"""
LOG.debug("create_vlanids() called")
session = db.get_session()
try:
vlanid = session.query(l2network_models.VlanID).\
@ -53,6 +55,7 @@ def create_vlanids():
def get_all_vlanids():
"""Gets all the vlanids"""
LOG.debug("get_all_vlanids() called")
session = db.get_session()
try:
vlanids = session.query(l2network_models.VlanID).\
@ -64,6 +67,7 @@ def get_all_vlanids():
def is_vlanid_used(vlan_id):
"""Checks if a vlanid is in use"""
LOG.debug("is_vlanid_used() called")
session = db.get_session()
try:
vlanid = session.query(l2network_models.VlanID).\
@ -76,6 +80,7 @@ def is_vlanid_used(vlan_id):
def release_vlanid(vlan_id):
"""Sets the vlanid state to be unused"""
LOG.debug("release_vlanid() called")
session = db.get_session()
try:
vlanid = session.query(l2network_models.VlanID).\
@ -92,6 +97,7 @@ def release_vlanid(vlan_id):
def delete_vlanid(vlan_id):
"""Deletes a vlanid entry from db"""
LOG.debug("delete_vlanid() called")
session = db.get_session()
try:
vlanid = session.query(l2network_models.VlanID).\
@ -106,6 +112,7 @@ def delete_vlanid(vlan_id):
def reserve_vlanid():
"""Reserves the first unused vlanid"""
LOG.debug("reserve_vlanid() called")
session = db.get_session()
try:
rvlan = session.query(l2network_models.VlanID).\
@ -124,6 +131,7 @@ def reserve_vlanid():
def get_all_vlan_bindings():
"""Lists all the vlan to network associations"""
LOG.debug("get_all_vlan_bindings() called")
session = db.get_session()
try:
bindings = session.query(l2network_models.VlanBinding).\
@ -135,6 +143,7 @@ def get_all_vlan_bindings():
def get_vlan_binding(netid):
"""Lists the vlan given a network_id"""
LOG.debug("get_vlan_binding() called")
session = db.get_session()
try:
binding = session.query(l2network_models.VlanBinding).\
@ -147,6 +156,7 @@ def get_vlan_binding(netid):
def add_vlan_binding(vlanid, vlanname, netid):
"""Adds a vlan to network association"""
LOG.debug("add_vlan_binding() called")
session = db.get_session()
try:
binding = session.query(l2network_models.VlanBinding).\
@ -163,6 +173,7 @@ def add_vlan_binding(vlanid, vlanname, netid):
def remove_vlan_binding(netid):
"""Removes a vlan to network association"""
LOG.debug("remove_vlan_binding() called")
session = db.get_session()
try:
binding = session.query(l2network_models.VlanBinding).\
@ -177,6 +188,7 @@ def remove_vlan_binding(netid):
def update_vlan_binding(netid, newvlanid=None, newvlanname=None):
"""Updates a vlan to network association"""
LOG.debug("update_vlan_binding() called")
session = db.get_session()
try:
binding = session.query(l2network_models.VlanBinding).\
@ -195,6 +207,7 @@ def update_vlan_binding(netid, newvlanid=None, newvlanname=None):
def get_all_portprofiles():
"""Lists all the port profiles"""
LOG.debug("get_all_portprofiles() called")
session = db.get_session()
try:
pps = session.query(l2network_models.PortProfile).\
@ -206,6 +219,7 @@ def get_all_portprofiles():
def get_portprofile(tenantid, ppid):
"""Lists a port profile"""
LOG.debug("get_portprofile() called")
session = db.get_session()
try:
pp = session.query(l2network_models.PortProfile).\
@ -219,6 +233,7 @@ def get_portprofile(tenantid, ppid):
def add_portprofile(tenantid, ppname, vlanid, qos):
"""Adds a port profile"""
LOG.debug("add_portprofile() called")
session = db.get_session()
try:
pp = session.query(l2network_models.PortProfile).\
@ -235,6 +250,7 @@ def add_portprofile(tenantid, ppname, vlanid, qos):
def remove_portprofile(tenantid, ppid):
"""Removes a port profile"""
LOG.debug("remove_portprofile() called")
session = db.get_session()
try:
pp = session.query(l2network_models.PortProfile).\
@ -250,6 +266,7 @@ def remove_portprofile(tenantid, ppid):
def update_portprofile(tenantid, ppid, newppname=None, newvlanid=None,
newqos=None):
"""Updates port profile"""
LOG.debug("update_portprofile() called")
session = db.get_session()
try:
pp = session.query(l2network_models.PortProfile).\
@ -271,6 +288,7 @@ def update_portprofile(tenantid, ppid, newppname=None, newvlanid=None,
def get_all_pp_bindings():
"""Lists all the port profiles"""
LOG.debug("get_all_pp_bindings() called")
session = db.get_session()
try:
bindings = session.query(l2network_models.PortProfileBinding).\
@ -282,6 +300,7 @@ def get_all_pp_bindings():
def get_pp_binding(tenantid, ppid):
"""Lists a port profile binding"""
LOG.debug("get_pp_binding() called")
session = db.get_session()
try:
binding = session.query(l2network_models.PortProfileBinding).\
@ -294,6 +313,7 @@ def get_pp_binding(tenantid, ppid):
def add_pp_binding(tenantid, portid, ppid, default):
"""Adds a port profile binding"""
LOG.debug("add_pp_binding() called")
session = db.get_session()
try:
binding = session.query(l2network_models.PortProfileBinding).\
@ -311,6 +331,7 @@ def add_pp_binding(tenantid, portid, ppid, default):
def remove_pp_binding(tenantid, portid, ppid):
"""Removes a port profile binding"""
LOG.debug("remove_pp_binding() called")
session = db.get_session()
try:
binding = session.query(l2network_models.PortProfileBinding).\
@ -327,6 +348,7 @@ def remove_pp_binding(tenantid, portid, ppid):
def update_pp_binding(tenantid, ppid, newtenantid=None, newportid=None,
newdefault=None):
"""Updates port profile binding"""
LOG.debug("update_pp_binding() called")
session = db.get_session()
try:
binding = session.query(l2network_models.PortProfileBinding).\

View File

@ -0,0 +1,93 @@
# 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 logging as LOG
from sqlalchemy.orm import exc
import quantum.plugins.cisco.db.api as db
from quantum.plugins.cisco.common import cisco_exceptions as c_exc
from quantum.plugins.cisco.db import nexus_models
def get_all_nexusport_bindings():
"""Lists all the nexusport bindings"""
LOG.debug("get_all_nexusport_bindings() called")
session = db.get_session()
try:
bindings = session.query(nexus_models.NexusPortBinding).\
all()
return bindings
except exc.NoResultFound:
return []
def get_nexusport_binding(vlan_id):
"""Lists a nexusport binding"""
LOG.debug("get_nexusport_binding() called")
session = db.get_session()
try:
binding = session.query(nexus_models.NexusPortBinding).\
filter_by(vlan_id=vlan_id).\
all()
return binding
except exc.NoResultFound:
raise c_exc.NexusPortBindingNotFound(vlan_id=vlan_id)
def add_nexusport_binding(port_id, vlan_id):
"""Adds a nexusport binding"""
LOG.debug("add_nexusport_binding() called")
session = db.get_session()
binding = nexus_models.NexusPortBinding(port_id, vlan_id)
session.add(binding)
session.flush()
return binding
def remove_nexusport_binding(vlan_id):
"""Removes a nexusport binding"""
LOG.debug("remove_nexusport_binding() called")
session = db.get_session()
try:
binding = session.query(nexus_models.NexusPortBinding).\
filter_by(vlan_id=vlan_id).\
all()
for bind in binding:
session.delete(bind)
session.flush()
return binding
except exc.NoResultFound:
pass
def update_nexusport_binding(port_id, new_vlan_id):
"""Updates nexusport binding"""
LOG.debug("update_nexusport_binding called")
session = db.get_session()
try:
binding = session.query(nexus_models.NexusPortBinding).\
filter_by(port_id=port_id).\
one()
if new_vlan_id:
binding["vlan_id"] = new_vlan_id
session.merge(binding)
session.flush()
return binding
except exc.NoResultFound:
raise c_exc.NexusPortBindingNotFound()

View File

@ -0,0 +1,38 @@
# 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 import Column, Integer, String
from quantum.plugins.cisco.db.l2network_models import L2NetworkBase
from quantum.plugins.cisco.db.models import BASE
class NexusPortBinding(BASE, L2NetworkBase):
"""Represents a binding of nexus port to vlan_id"""
__tablename__ = 'nexusport_bindings'
id = Column(Integer, primary_key=True, autoincrement=True)
port_id = Column(String(255))
vlan_id = Column(Integer, nullable=False)
def __init__(self, port_id, vlan_id):
self.port_id = port_id
self.vlan_id = vlan_id
def __repr__(self):
return "<NexusPortBinding (%s,%d)>" % \
(self.port_id, self.vlan_id)

View File

@ -23,9 +23,9 @@ import inspect
import logging as LOG
from quantum.common import utils
from quantum.plugins.cisco.l2network_model_base import L2NetworkModelBase
from quantum.plugins.cisco import l2network_plugin_configuration as conf
from quantum.plugins.cisco.common import cisco_constants as const
from quantum.plugins.cisco.l2network_model_base import L2NetworkModelBase
LOG.basicConfig(level=LOG.WARN)
LOG.getLogger(const.LOGGER_COMPONENT_NAME)

View File

@ -21,13 +21,15 @@
import inspect
import logging as LOG
import platform
from quantum.common import exceptions as exc
from quantum.common import utils
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.common import cisco_constants as const
from quantum.plugins.cisco.common import cisco_credentials as cred
from quantum.plugins.cisco.db import api as db
from quantum.plugins.cisco.db import l2network_db as cdb
@ -37,6 +39,10 @@ LOG.getLogger(const.LOGGER_COMPONENT_NAME)
class L2Network(QuantumPluginBase):
""" L2 Network Framework Plugin """
supported_extension_aliases = ["Cisco Credential", "Cisco Port Profile",
"Cisco qos", "Cisco Nova Tenant"]
_qos_levels = {}
_credentials = {}
def __init__(self):
self._vlan_counter = int(conf.VLAN_START) - 1
@ -44,6 +50,8 @@ class L2Network(QuantumPluginBase):
cdb.initialize()
# TODO (Sumit): The following should move to the segmentation module
cdb.create_vlanids()
self._qoslevels_counter = 0
self._credentials_counter = 0
"""
Core API implementation
@ -252,6 +260,7 @@ class L2Network(QuantumPluginBase):
"""
def get_all_portprofiles(self, tenant_id):
"""Get all port profiles"""
LOG.debug("get_all_portprofiles() called\n")
pplist = cdb.get_all_portprofiles()
new_pplist = []
for portprofile in pplist:
@ -265,7 +274,13 @@ class L2Network(QuantumPluginBase):
def get_portprofile_details(self, tenant_id, profile_id):
"""Get port profile details"""
portprofile = cdb.get_portprofile(tenant_id, profile_id)
LOG.debug("get_portprofile_details() called\n")
try:
portprofile = cdb.get_portprofile(tenant_id, profile_id)
except Exception, excp:
raise cexc.PortProfileNotFound(tenant_id=tenant_id,
portprofile_id=profile_id)
new_pp = self._make_portprofile_dict(tenant_id,
portprofile[const.UUID],
portprofile[const.PPNAME],
@ -274,6 +289,7 @@ class L2Network(QuantumPluginBase):
def create_portprofile(self, tenant_id, profile_name, qos):
"""Create port profile"""
LOG.debug("create_portprofile() called\n")
portprofile = cdb.add_portprofile(tenant_id, profile_name,
const.NO_VLAN_ID, qos)
new_pp = self._make_portprofile_dict(tenant_id,
@ -284,9 +300,10 @@ class L2Network(QuantumPluginBase):
def delete_portprofile(self, tenant_id, profile_id):
"""Delete portprofile"""
LOG.debug("delete_portprofile() called\n")
try:
portprofile = cdb.get_portprofile(tenant_id, profile_id)
except Exception, exc:
except Exception, excp:
raise cexc.PortProfileNotFound(tenant_id=tenant_id,
portprofile_id=profile_id)
@ -299,9 +316,10 @@ class L2Network(QuantumPluginBase):
def rename_portprofile(self, tenant_id, profile_id, new_name):
"""Rename port profile"""
LOG.debug("rename_portprofile() called\n")
try:
portprofile = cdb.get_portprofile(tenant_id, profile_id)
except Exception, exc:
except Exception, excp:
raise cexc.PortProfileNotFound(tenant_id=tenant_id,
portprofile_id=profile_id)
portprofile = cdb.update_portprofile(tenant_id, profile_id, new_name)
@ -314,9 +332,10 @@ class L2Network(QuantumPluginBase):
def associate_portprofile(self, tenant_id, net_id,
port_id, portprofile_id):
"""Associate port profile"""
LOG.debug("associate_portprofile() called\n")
try:
portprofile = cdb.get_portprofile(tenant_id, portprofile_id)
except Exception, exc:
except Exception, excp:
raise cexc.PortProfileNotFound(tenant_id=tenant_id,
portprofile_id=portprofile_id)
@ -325,14 +344,135 @@ class L2Network(QuantumPluginBase):
def disassociate_portprofile(self, tenant_id, net_id,
port_id, portprofile_id):
"""Disassociate port profile"""
LOG.debug("disassociate_portprofile() called\n")
try:
portprofile = cdb.get_portprofile(tenant_id, portprofile_id)
except Exception, exc:
except Exception, excp:
raise cexc.PortProfileNotFound(tenant_id=tenant_id,
portprofile_id=portprofile_id)
cdb.remove_pp_binding(tenant_id, port_id, portprofile_id)
def get_all_qoss(self, tenant_id):
"""Get all QoS levels"""
LOG.debug("get_all_qoss() called\n")
return self._qos_levels.values()
def get_qos_details(self, tenant_id, qos_id):
"""Get QoS Details"""
LOG.debug("get_qos_details() called\n")
try:
qos_level = self._get_qos_level(tenant_id, qos_id)
except Exception, excp:
raise cexc.QosNotFound(tenant_id=tenant_id,
qos_id=qos_id)
return qos_level
def create_qos(self, tenant_id, qos_name, qos_desc):
"""Create a QoS level"""
LOG.debug("create_qos() called\n")
qos_id = self._get_unique_qos_id(tenant_id)
new_qos_level_dict = {const.QOS_LEVEL_ID: qos_id,
const.QOS_LEVEL_NAME: qos_name,
const.QOS_LEVEL_ASSOCIATIONS: [],
const.QOS_LEVEL_DESCRIPTION: qos_desc}
self._qos_levels[qos_id] = new_qos_level_dict
return new_qos_level_dict
def delete_qos(self, tenant_id, qos_id):
"""Delete a QoS level"""
LOG.debug("delete_qos() called\n")
try:
qos_level = self._get_qos_level(tenant_id, qos_id)
except Exception, excp:
raise cexc.QosNotFound(tenant_id=tenant_id,
qos_id=qos_id)
associations = qos_level[const.QOS_LEVEL_ASSOCIATIONS]
if len(associations) > 0:
raise cexc.QoSLevelInvalidDelete(tenant_id=tenant_id,
qos_id=qos_id)
else:
self._qos_levels.pop(qos_id)
def rename_qos(self, tenant_id, qos_id, new_name):
"""Rename QoS level"""
LOG.debug("rename_qos() called\n")
qos_level = self._get_qos_level(tenant_id, qos_id)
try:
qos_level = self._get_qos_level(tenant_id, qos_id)
except Exception, excp:
raise cexc.QosNotFound(tenant_id=tenant_id,
qos_id=qos_id)
qos_level[const.QOS_LEVEL_NAME] = new_name
return qos_level
def get_all_credentials(self, tenant_id):
"""Get all credentials"""
LOG.debug("get_all_credentials() called\n")
return self._credentials.values()
def get_credential_details(self, tenant_id, credential_id):
"""Get a particular credential"""
LOG.debug("get_credential_details() called\n")
try:
credential = self._get_credential(tenant_id, credential_id)
except Exception, excp:
raise cexc.CredentialNotFound(tenant_id=tenant_id,
credential_id=credential_id)
return credential
def create_credential(self, tenant_id, credential_name, user_name,
password):
"""Create a new credential"""
LOG.debug("create_credential() called\n")
credential_id = self._get_unique_credential_id(tenant_id)
masked_password = const.MASKED_PASSWORD
new_credential_dict = {const.CREDENTIAL_ID: credential_id,
const.CREDENTIAL_NAME: credential_name,
const.CREDENTIAL_USERNAME: user_name,
const.CREDENTIAL_PASSWORD: masked_password}
self._credentials[credential_id] = new_credential_dict
cred.Store.putCredential(credential_id, user_name, password)
return new_credential_dict
def delete_credential(self, tenant_id, credential_id):
"""Delete a credential"""
LOG.debug("delete_credential() called\n")
try:
credential = self._get_credential(tenant_id, credential_id)
except Exception, excp:
raise cexc.CredentialNotFound(tenant_id=tenant_id,
credential_id=credential_id)
self._credentials.pop(credential_id)
cred.Store.deleteCredential(credential_id)
def rename_credential(self, tenant_id, credential_id, new_name):
"""Rename the particular credential resource"""
LOG.debug("rename_credential() called\n")
try:
credential = self._get_credential(tenant_id, credential_id)
except Exception, excp:
raise cexc.CredentialNotFound(tenant_id=tenant_id,
credential_id=credential_id)
credential[const.CREDENTIAL_NAME] = new_name
return credential
def get_host(self, tenant_id, instance_id, instance_desc):
"""Provides the hostname on which a dynamic vnic is reserved"""
LOG.debug("get_host() called\n")
host_list = {const.HOST_LIST: {const.HOST_1: platform.node()}}
return host_list
def get_instance_port(self, tenant_id, instance_id, instance_desc):
"""
Get the portprofile name and the device namei for the dynamic vnic
"""
LOG.debug("get_instance_port() called\n")
vif_desc = {const.VIF_DESC:
{const.DEVICENAME: "eth2", const.UCSPROFILE: "default"}}
return vif_desc
"""
Private functions
"""
@ -373,13 +513,13 @@ class L2Network(QuantumPluginBase):
return inspect.stack()[1 + offset][3]
def _make_net_dict(self, net_id, net_name, ports):
"""Helper funciton"""
"""Helper funciton to create network resource dictionary"""
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"""
"""Helper function to create port resource dictionary"""
res = {const.PORT_ID: port_id, const.PORT_STATE: port_state}
res[const.NET_ID] = net_id
res[const.ATTACHMENT] = attachment
@ -387,7 +527,7 @@ class L2Network(QuantumPluginBase):
def _make_portprofile_dict(self, tenant_id, profile_id, profile_name,
qos):
"""Helper funciton"""
"""Helper funciton to create port-profile resource dictionary"""
profile_associations = self._make_portprofile_assc_list(tenant_id,
profile_id)
res = {const.PROFILE_ID: str(profile_id),
@ -405,3 +545,35 @@ class L2Network(QuantumPluginBase):
assc_list.append(port[const.PORTID])
return assc_list
def _get_qos_level(self, tenant_id, qos_id):
"""Return a QoS level based on the ID"""
qos_level = self._qos_levels.get(qos_id)
if not qos_level:
raise cexc.QosNotFound(tenant_id=tenant_id,
qos_id=qos_id)
return qos_level
def _get_credential(self, tenant_id, credential_id):
"""Return a credential based on the ID"""
credential = self._credentials.get(credential_id)
if not credential:
raise cexc.CredentialNotFound(tenant_id=tenant_id,
credetial_id=credential_id)
return credential
def _get_unique_qos_id(self, tenant_id):
"""Get a unique QoS ID"""
self._qoslevels_counter += 1
self._qoslevels_counter %= int(const.MAX_QOS_LEVELS)
qos_id = tenant_id[16:] + "-qos-" + str(self._qoslevels_counter)
# TODO (Sumit): Need to check if the ID has already been allocated
return qos_id
def _get_unique_credential_id(self, tenant_id):
"""Get a unique credential ID"""
self._credentials_counter += 1
self._credentials_counter %= int(const.MAX_CREDENTIALS)
cred_id = tenant_id[16:] + "-crd-" + str(self._credentials_counter)
# TODO (Sumit): Need to check if the ID has already been allocated
return cred_id

View File

@ -29,6 +29,9 @@ CONF_PARSER_OBJ = confp.\
CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) + \
"/" + CONF_FILE)
"""
Reading the conf for the l2network_plugin
"""
SECTION_CONF = CONF_PARSER_OBJ['VLANS']
VLAN_NAME_PREFIX = SECTION_CONF['vlan_name_prefix']
VLAN_START = SECTION_CONF['vlan_start']
@ -52,6 +55,9 @@ CONF_PARSER_OBJ = confp.\
CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) + \
"/" + CONF_FILE)
"""
Reading the config for the device plugins
"""
PLUGINS = CONF_PARSER_OBJ.walk(CONF_PARSER_OBJ.dummy)
CONF_FILE = "conf/db_conn.ini"
@ -60,6 +66,9 @@ CONF_PARSER_OBJ = confp.\
CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) + \
"/" + CONF_FILE)
"""
Reading DB config for the Quantum DB
"""
SECTION_CONF = CONF_PARSER_OBJ['DATABASE']
DB_NAME = SECTION_CONF['name']
DB_USER = SECTION_CONF['user']

View File

@ -33,7 +33,8 @@ CP = confp.CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) \
SECTION = CP['SWITCH']
NEXUS_IP_ADDRESS = SECTION['nexus_ip_address']
NEXUS_PORT = SECTION['nexus_port']
NEXUS_FIRST_PORT = SECTION['nexus_first_port']
NEXUS_SECOND_PORT = SECTION['nexus_second_port']
NEXUS_SSH_PORT = SECTION['nexus_ssh_port']
SECTION = CP['DRIVER']

View File

@ -110,7 +110,8 @@ class CiscoNEXUSDriver():
mgr.edit_config(target='running', config=confstr)
def create_vlan(self, vlan_name, vlan_id, nexus_host, nexus_user,
nexus_password, nexus_interface, nexus_ssh_port):
nexus_password, nexus_first_interface,
nexus_second_interface, nexus_ssh_port):
"""
Creates a VLAN and Enable on trunk mode an interface on Nexus Switch
given the VLAN ID and Name and Interface Number
@ -118,10 +119,12 @@ class CiscoNEXUSDriver():
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)
self.enable_vlan_on_trunk_int(man, nexus_first_interface, vlan_id)
self.enable_vlan_on_trunk_int(man, nexus_second_interface, vlan_id)
def delete_vlan(self, vlan_id, nexus_host, nexus_user,
nexus_password, nexus_interface, nexus_ssh_port):
def delete_vlan(self, vlan_id, nexus_host, nexus_user, nexus_password,
nexus_first_interface, nexus_second_interface,
nexus_ssh_port):
"""
Delete a VLAN and Disables trunk mode an interface on Nexus Switch
given the VLAN ID and Interface Number
@ -129,4 +132,5 @@ class CiscoNEXUSDriver():
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)
self.disable_switch_port(man, nexus_first_interface)
self.disable_switch_port(man, nexus_second_interface)

View File

@ -28,6 +28,7 @@ from quantum.plugins.cisco.common import cisco_constants as const
from quantum.plugins.cisco.common import cisco_credentials as cred
from quantum.plugins.cisco.l2device_plugin_base import L2DevicePluginBase
from quantum.plugins.cisco.nexus import cisco_nexus_configuration as conf
from quantum.plugins.cisco.db import nexus_db as nxos_db
LOG.basicConfig(level=LOG.WARN)
LOG.getLogger(const.LOGGER_COMPONENT_NAME)
@ -48,7 +49,8 @@ class NexusPlugin(L2DevicePluginBase):
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_first_port = conf.NEXUS_FIRST_PORT
self._nexus_second_port = conf.NEXUS_SECOND_PORT
self._nexus_ssh_port = conf.NEXUS_SSH_PORT
def get_all_networks(self, tenant_id):
@ -68,8 +70,11 @@ 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_first_port, self._nexus_second_port,
self._nexus_ssh_port)
nxos_db.add_nexusport_binding(self._nexus_first_port, str(vlan_id))
nxos_db.add_nexusport_binding(self._nexus_second_port, str(vlan_id))
new_net_dict = {const.NET_ID: net_id,
const.NET_NAME: net_name,
@ -85,11 +90,15 @@ class NexusPlugin(L2DevicePluginBase):
from the relevant interfaces
"""
LOG.debug("NexusPlugin:delete_network() called\n")
net = self._networks.get(net_id)
vlan_id = self._get_vlan_id_for_network(tenant_id, net_id)
ports_id = nxos_db.get_nexusport_binding(vlan_id)
LOG.debug("NexusPlugin: Interfaces to be disassociated: %s" % ports_id)
nxos_db.remove_nexusport_binding(vlan_id)
net = self._networks.get(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_first_port, self._nexus_second_port,
self._nexus_ssh_port)
self._networks.pop(net_id)
return net

View File

@ -0,0 +1,964 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2011 OpenStack LLC.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
# @authors: Shweta Padubidri, Cisco Systems, Inc.
# Peter Strunk , Cisco Systems, Inc.
# Shubhangi Satras , Cisco Systems, Inc.
import unittest
import logging
import webob
import json
import os.path
import routes
from webtest import TestApp
from extensions import credential
from extensions import portprofile
from extensions import novatenant
from extensions import qos
from quantum.plugins.cisco.db import api as db
from quantum.common import wsgi
from quantum.common import config
from quantum.common import extensions
from quantum import api as server
from quantum.plugins.cisco.l2network_plugin import L2Network
from tests.unit.extension_stubs import StubBaseAppController
from quantum.common.extensions import (PluginAwareExtensionManager,
ExtensionMiddleware)
from quantum.manager import QuantumManager
from quantum.plugins.cisco import l2network_plugin
TEST_CONF_FILE = os.path.join(os.path.dirname(__file__), os.pardir,
os.pardir, 'conf', 'quantum.conf.ciscoext')
EXTENSIONS_PATH = os.path.join(os.path.dirname(__file__), os.pardir, os.pardir,
os.pardir, os.pardir, os.pardir, "extensions")
LOG = logging.getLogger('quantum.plugins.cisco.tests.test_cisco_extensions')
class ExtensionsTestApp(wsgi.Router):
def __init__(self, options=None):
options = options or {}
mapper = routes.Mapper()
controller = StubBaseAppController()
mapper.resource("dummy_resource", "/dummy_resources",
controller=controller)
super(ExtensionsTestApp, self).__init__(mapper)
class PortprofileExtensionTest(unittest.TestCase):
def setUp(self):
""" Set up function """
parent_resource = dict(member_name="tenant",
collection_name="extensions/csco/tenants")
member_actions = {'associate_portprofile': "PUT",
'disassociate_portprofile': "PUT"}
controller = portprofile.PortprofilesController(
QuantumManager.get_plugin())
res_ext = extensions.ResourceExtension('portprofiles', controller,
parent=parent_resource,
member_actions=member_actions)
self.test_app = setup_extensions_test_app(
SimpleExtensionManager(res_ext))
self.contenttype = 'application/json'
self.profile_path = '/extensions/csco/tenants/tt/portprofiles'
self.portprofile_path = '/extensions/csco/tenants/tt/portprofiles/'
self.test_port_profile = {'portprofile':
{'portprofile_name': 'cisco_test_portprofile',
'qos_name': 'test-qos1'}}
self.tenant_id = "test_tenant"
self.network_name = "test_network"
options = {}
options['plugin_provider'] = 'quantum.plugins.cisco.l2network_plugin'\
'.L2Network'
self.api = server.APIRouterV01(options)
self._l2network_plugin = l2network_plugin.L2Network()
def test_list_portprofile(self):
""" Test List Portprofile"""
LOG.debug("test_list_portprofile - START")
req_body1 = json.dumps(self.test_port_profile)
create_response1 = self.test_app.post(
self.profile_path, req_body1,
content_type=self.contenttype)
req_body2 = json.dumps({'portprofile':
{'portprofile_name': 'cisco_test_portprofile2',
'qos_name': 'test-qos2'}})
create_response2 = self.test_app.post(
self.profile_path, req_body2,
content_type=self.contenttype)
index_response = self.test_app.get(self.profile_path)
self.assertEqual(200, index_response.status_int)
# Clean Up - Delete the Port Profiles
resp_body1 = wsgi.Serializer().deserialize(create_response1.body,
self.contenttype)
portprofile_path1_temp = self.portprofile_path +\
resp_body1['portprofiles']['portprofile']['id']
portprofile_path1 = str(portprofile_path1_temp)
resp_body2 = wsgi.Serializer().deserialize(create_response2.body,
self.contenttype)
portprofile_path2_temp = self.portprofile_path +\
resp_body2['portprofiles']['portprofile']['id']
portprofile_path2 = str(portprofile_path2_temp)
self.tear_down_profile(portprofile_path1)
self.tear_down_profile(portprofile_path2)
LOG.debug("test_list_portprofile - END")
def test_create_portprofile(self):
""" Test create Portprofile"""
LOG.debug("test_create_portprofile - START")
req_body = json.dumps(self.test_port_profile)
index_response = self.test_app.post(self.profile_path, req_body,
content_type=self.contenttype)
self.assertEqual(200, index_response.status_int)
# Clean Up - Delete the Port Profile
resp_body = wsgi.Serializer().deserialize(index_response.body,
self.contenttype)
portprofile_path_temp = self.portprofile_path +\
resp_body['portprofiles']['portprofile']['id']
portprofile_path = str(portprofile_path_temp)
self.tear_down_profile(portprofile_path)
LOG.debug("test_create_portprofile - END")
def test_create_portprofileBADRequest(self):
""" Test create Portprofile Bad Request"""
LOG.debug("test_create_portprofileBADRequest - START")
index_response = self.test_app.post(self.profile_path, 'BAD_REQUEST',
content_type=self.contenttype,
status='*')
self.assertEqual(400, index_response.status_int)
LOG.debug("test_create_portprofileBADRequest - END")
def test_show_portprofile(self):
""" Test show Portprofile """
LOG.debug("test_show_portprofile - START")
req_body = json.dumps(self.test_port_profile)
index_response = self.test_app.post(self.profile_path, req_body,
content_type=self.contenttype)
resp_body = wsgi.Serializer().deserialize(index_response.body,
self.contenttype)
show_path_temp = self.portprofile_path +\
resp_body['portprofiles']['portprofile']['id']
show_port_path = str(show_path_temp)
show_response = self.test_app.get(show_port_path)
self.assertEqual(200, show_response.status_int)
# Clean Up - Delete the Port Profile
self.tear_down_profile(show_port_path)
LOG.debug("test_show_portprofile - END")
def test_show_portprofileDNE(self, portprofile_id='100'):
""" Test show Portprofile does not exist"""
LOG.debug("test_show_portprofileDNE - START")
show_path_temp = self.portprofile_path + portprofile_id
show_port_path = str(show_path_temp)
show_response = self.test_app.get(show_port_path, status='*')
self.assertEqual(450, show_response.status_int)
LOG.debug("test_show_portprofileDNE - END")
def test_update_portprofile(self):
""" Test update Portprofile"""
LOG.debug("test_update_portprofile - START")
req_body = json.dumps(self.test_port_profile)
index_response = self.test_app.post(
self.profile_path, req_body,
content_type=self.contenttype)
resp_body = wsgi.Serializer().deserialize(index_response.body,
self.contenttype)
rename_port_profile = {'portprofile':
{'portprofile_name': 'cisco_rename_portprofile',
'qos_name': 'test-qos1'}}
rename_req_body = json.dumps(rename_port_profile)
rename_path_temp = self.portprofile_path +\
resp_body['portprofiles']['portprofile']['id']
rename_path = str(rename_path_temp)
rename_response = self.test_app.put(rename_path, rename_req_body)
self.assertEqual(200, rename_response.status_int)
# Clean Up - Delete the Port Profile
self.tear_down_profile(rename_path)
LOG.debug("test_update_portprofile - END")
def test_update_portprofileBADRequest(self):
""" Test update Portprofile Bad Request"""
LOG.debug("test_update_portprofileBADRequest - START")
req_body = json.dumps(self.test_port_profile)
index_response = self.test_app.post(
self.profile_path, req_body,
content_type=self.contenttype)
resp_body = wsgi.Serializer().deserialize(index_response.body,
self.contenttype)
rename_path_temp = self.portprofile_path +\
resp_body['portprofiles']['portprofile']['id']
rename_path = str(rename_path_temp)
rename_response = self.test_app.put(rename_path, 'BAD_REQUEST',
status='*')
self.assertEqual(400, rename_response.status_int)
# Clean Up - Delete the Port Profile
self.tear_down_profile(rename_path)
LOG.debug("test_update_portprofileBADRequest - END")
def test_update_portprofileDNE(self, portprofile_id='100'):
""" Test update Portprofile does not exist"""
LOG.debug("test_update_portprofileiDNE - START")
rename_port_profile = {'portprofile':
{'portprofile_name': 'cisco_rename_portprofile',
'qos_name': 'test-qos1'}}
rename_req_body = json.dumps(rename_port_profile)
update_path_temp = self.portprofile_path + portprofile_id
update_path = str(update_path_temp)
update_response = self.test_app.put(update_path, rename_req_body,
status='*')
self.assertEqual(450, update_response.status_int)
LOG.debug("test_update_portprofileDNE - START")
def test_delete_portprofile(self):
""" Test delete Portprofile"""
LOG.debug("test_delete_portprofile - START")
req_body = json.dumps(self.test_port_profile)
index_response = self.test_app.post(
self.profile_path, req_body,
content_type=self.contenttype)
resp_body = wsgi.Serializer().deserialize(index_response.body,
self.contenttype)
delete_path_temp = self.portprofile_path +\
resp_body['portprofiles']['portprofile']['id']
delete_path = str(delete_path_temp)
delete_response = self.test_app.delete(delete_path)
self.assertEqual(202, delete_response.status_int)
LOG.debug("test_delete_portprofile - END")
def test_delete_portprofileDNE(self, portprofile_id='100'):
""" Test delete Portprofile does not exist"""
LOG.debug("test_delete_portprofileDNE - START")
delete_path_temp = self.portprofile_path + portprofile_id
delete_path = str(delete_path_temp)
delete_response = self.test_app.delete(delete_path, status='*')
self.assertEqual(450, delete_response.status_int)
LOG.debug("test_delete_portprofileDNE - END")
def create_request(self, path, body, content_type, method='GET'):
""" Test create request"""
LOG.debug("test_create_request - START")
req = webob.Request.blank(path)
req.method = method
req.headers = {}
req.headers['Accept'] = content_type
req.body = body
return req
LOG.debug("test_create_request - END")
def _create_network(self, name=None):
""" Test create network"""
LOG.debug("Creating network - START")
if name:
net_name = name
else:
net_name = self.network_name
net_path = "/tenants/tt/networks"
net_data = {'network': {'net-name': '%s' % net_name}}
req_body = wsgi.Serializer().serialize(net_data, self.contenttype)
network_req = self.create_request(net_path, req_body,
self.contenttype, 'POST')
network_res = network_req.get_response(self.api)
network_data = wsgi.Serializer().deserialize(network_res.body,
self.contenttype)
return network_data['networks']['network']['id']
LOG.debug("Creating network - END")
def _create_port(self, network_id, port_state):
""" Test create port"""
LOG.debug("Creating port for network %s - START", network_id)
port_path = "/tenants/tt/networks/%s/ports" % network_id
port_req_data = {'port': {'port-state': '%s' % port_state}}
req_body = wsgi.Serializer().serialize(port_req_data,
self.contenttype)
port_req = self.create_request(port_path, req_body,
self.contenttype, 'POST')
port_res = port_req.get_response(self.api)
port_data = wsgi.Serializer().deserialize(port_res.body,
self.contenttype)
return port_data['ports']['port']['id']
LOG.debug("Creating port for network - END")
def test_associate_portprofile(self):
""" Test associate portprofile"""
LOG.debug("test_associate_portprofile - START")
net_id = self._create_network()
port_id = self._create_port(net_id, "ACTIVE")
req_body = json.dumps(self.test_port_profile)
index_response = self.test_app.post(
self.profile_path, req_body,
content_type=self.contenttype)
resp_body = wsgi.Serializer().deserialize(index_response.body,
self.contenttype)
test_port_assign_data = {'portprofile': {'network-id': net_id,
'port-id': port_id}}
req_assign_body = json.dumps(test_port_assign_data)
associate_path_temp = self.portprofile_path +\
resp_body['portprofiles']['portprofile']['id'] +\
"/associate_portprofile"
associate_path = str(associate_path_temp)
associate_response = self.test_app.put(
associate_path, req_assign_body,
content_type=self.contenttype)
self.assertEqual(202, associate_response.status_int)
# Clean Up - Disassociate and Delete the Port Profile
disassociate_path_temp = self.portprofile_path +\
resp_body['portprofiles']['portprofile']['id'] +\
"/disassociate_portprofile"
disassociate_path = str(disassociate_path_temp)
delete_path_temp = self.portprofile_path +\
resp_body['portprofiles']['portprofile']['id']
delete_path = str(delete_path_temp)
self.tear_down_associate_profile(delete_path, disassociate_path,
req_assign_body)
LOG.debug("test_associate_portprofile - END")
def test_associate_portprofileDNE(self, portprofile_id='100'):
""" Test associate portprofile does not exist"""
LOG.debug("test_associate_portprofileDNE - START")
test_port_assign_data = {'portprofile': {'network-id': '001',
'port-id': '1'}}
req_assign_body = json.dumps(test_port_assign_data)
associate_path = self.portprofile_path + portprofile_id +\
"/associate_portprofile"
associate_response = self.test_app.put(
associate_path, req_assign_body,
content_type=self.contenttype, status='*')
self.assertEqual(450, associate_response.status_int)
LOG.debug("test_associate_portprofileDNE - END")
def test_disassociate_portprofile(self):
""" Test disassociate portprofile"""
LOG.debug("test_disassociate_portprofile - START")
net_id = self._create_network()
port_id = self._create_port(net_id, "ACTIVE")
req_body = json.dumps(self.test_port_profile)
index_response = self.test_app.post(
self.profile_path, req_body,
content_type=self.contenttype)
resp_body = wsgi.Serializer().deserialize(index_response.body,
self.contenttype)
test_port_assign_data = {'portprofile': {'network-id': net_id,
'port-id': port_id}}
req_assign_body = json.dumps(test_port_assign_data)
associate_path_temp = self.portprofile_path +\
resp_body['portprofiles']['portprofile']['id'] +\
"/associate_portprofile"
associate_path = str(associate_path_temp)
self.test_app.put(associate_path, req_assign_body,
content_type=self.contenttype)
disassociate_path_temp = self.portprofile_path +\
resp_body['portprofiles']['portprofile']['id'] +\
"/disassociate_portprofile"
disassociate_path = str(disassociate_path_temp)
disassociate_response = self.test_app.put(
disassociate_path, req_assign_body,
content_type=self.contenttype)
self.assertEqual(202, disassociate_response.status_int)
resp_body = wsgi.Serializer().deserialize(index_response.body,
self.contenttype)
delete_path_temp = self.portprofile_path +\
resp_body['portprofiles']['portprofile']['id']
delete_path = str(delete_path_temp)
self.tear_down_profile(delete_path)
LOG.debug("test_disassociate_portprofile - END")
def tear_down_profile(self, delete_profile_path):
""" Tear down profile"""
self.test_app.delete(delete_profile_path)
def tear_down_associate_profile(self, delete_profile_path,
dissociate_profile_path, req_body):
""" Tear down associate profile"""
self.test_app.put(dissociate_profile_path, req_body,
content_type=self.contenttype)
self.tear_down_profile(delete_profile_path)
def tearDown(self):
""" Tear down """
db.clear_db()
class NovatenantExtensionTest(unittest.TestCase):
def setUp(self):
""" Set up function"""
parent_resource = dict(member_name="tenant",
collection_name="extensions/csco/tenants")
member_actions = {'get_host': "PUT",
'get_instance_port': "PUT"}
controller = novatenant.NovatenantsController(
QuantumManager.get_plugin())
res_ext = extensions.ResourceExtension('novatenants', controller,
parent=parent_resource,
member_actions=member_actions)
self.test_app = setup_extensions_test_app(
SimpleExtensionManager(res_ext))
self.contenttype = 'application/json'
self.novatenants_path = '/extensions/csco/tenants/tt/novatenants/'
self.test_instance_data = {'novatenant': {'instance_id': 1,
'instance_desc': {'key1': '1',
'key2': '2'}}}
def test_get_host(self):
""" Test get host"""
LOG.debug("test_get_host - START")
req_body = json.dumps(self.test_instance_data)
host_path = self.novatenants_path + "001/get_host"
host_response = self.test_app.put(
host_path, req_body,
content_type=self.contenttype)
self.assertEqual(200, host_response.status_int)
LOG.debug("test_get_host - END")
def test_get_hostBADRequest(self):
""" Test get host bad request"""
LOG.debug("test_get_hostBADRequest - START")
host_path = self.novatenants_path + "001/get_host"
host_response = self.test_app.put(
host_path, 'BAD_REQUEST',
content_type=self.contenttype, status='*')
self.assertEqual(400, host_response.status_int)
LOG.debug("test_get_hostBADRequest - END")
def test_instance_port(self):
""" Test get instance port """
LOG.debug("test_instance_port - START")
req_body = json.dumps(self.test_instance_data)
instance_port_path = self.novatenants_path + "001/get_instance_port"
instance_port_response = self.test_app.put(
instance_port_path, req_body,
content_type=self.contenttype)
self.assertEqual(200, instance_port_response.status_int)
LOG.debug("test_instance_port - END")
class QosExtensionTest(unittest.TestCase):
def setUp(self):
""" Set up function """
parent_resource = dict(member_name="tenant",
collection_name="extensions/csco/tenants")
controller = qos.QosController(QuantumManager.get_plugin())
res_ext = extensions.ResourceExtension('qos', controller,
parent=parent_resource)
self.test_app = setup_extensions_test_app(
SimpleExtensionManager(res_ext))
self.contenttype = 'application/json'
self.qos_path = '/extensions/csco/tenants/tt/qos'
self.qos_second_path = '/extensions/csco/tenants/tt/qos/'
self.test_qos_data = {'qos': {'qos_name': 'cisco_test_qos',
'qos_desc': {'PPS': 50, 'TTL': 5}}}
def test_create_qos(self):
""" Test create qos """
LOG.debug("test_create_qos - START")
req_body = json.dumps(self.test_qos_data)
index_response = self.test_app.post(self.qos_path,
req_body,
content_type=self.contenttype)
self.assertEqual(200, index_response.status_int)
# Clean Up - Delete the qos
resp_body = wsgi.Serializer().deserialize(index_response.body,
self.contenttype)
qos_path_temp = self.qos_second_path +\
resp_body['qoss']['qos']['id']
qos_path = str(qos_path_temp)
self.tearDownQos(qos_path)
LOG.debug("test_create_qos - END")
def test_create_qosBADRequest(self):
""" Test create qos bad request """
LOG.debug("test_create_qosBADRequest - START")
index_response = self.test_app.post(self.qos_path,
'BAD_REQUEST',
content_type=self.contenttype,
status='*')
self.assertEqual(400, index_response.status_int)
LOG.debug("test_create_qosBADRequest - END")
def test_list_qoss(self):
""" Test list qoss """
LOG.debug("test_list_qoss - START")
req_body1 = json.dumps(self.test_qos_data)
create_resp1 = self.test_app.post(self.qos_path, req_body1,
content_type=self.contenttype)
req_body2 = json.dumps({'qos': {'qos_name': 'cisco_test_qos2',
'qos_desc': {'PPS': 50, 'TTL': 5}}})
create_resp2 = self.test_app.post(self.qos_path, req_body2,
content_type=self.contenttype)
index_response = self.test_app.get(self.qos_path)
self.assertEqual(200, index_response.status_int)
# Clean Up - Delete the qos's
resp_body1 = wsgi.Serializer().deserialize(create_resp1.body,
self.contenttype)
qos_path1_temp = self.qos_second_path +\
resp_body1['qoss']['qos']['id']
qos_path1 = str(qos_path1_temp)
resp_body2 = wsgi.Serializer().deserialize(create_resp2.body,
self.contenttype)
qos_path2_temp = self.qos_second_path +\
resp_body2['qoss']['qos']['id']
qos_path2 = str(qos_path2_temp)
self.tearDownQos(qos_path1)
self.tearDownQos(qos_path2)
LOG.debug("test_list_qoss - END")
def test_show_qos(self):
""" Test show qos """
LOG.debug("test_show_qos - START")
req_body = json.dumps(self.test_qos_data)
index_response = self.test_app.post(self.qos_path, req_body,
content_type=self.contenttype)
resp_body = wsgi.Serializer().deserialize(index_response.body,
self.contenttype)
show_path_temp = self.qos_second_path +\
resp_body['qoss']['qos']['id']
show_qos_path = str(show_path_temp)
show_response = self.test_app.get(show_qos_path)
self.assertEqual(200, show_response.status_int)
# Clean Up - Delete the qos
self.tearDownQos(show_qos_path)
LOG.debug("test_show_qos - END")
def test_show_qosDNE(self, qos_id='100'):
""" Test show qos does not exist"""
LOG.debug("test_show_qosDNE - START")
show_path_temp = self.qos_second_path + qos_id
show_qos_path = str(show_path_temp)
show_response = self.test_app.get(show_qos_path, status='*')
self.assertEqual(452, show_response.status_int)
LOG.debug("test_show_qosDNE - END")
def test_update_qos(self):
""" Test update qos """
LOG.debug("test_update_qos - START")
req_body = json.dumps(self.test_qos_data)
index_response = self.test_app.post(self.qos_path, req_body,
content_type=self.contenttype)
resp_body = wsgi.Serializer().deserialize(index_response.body,
self.contenttype)
rename_req_body = json.dumps({'qos': {'qos_name': 'cisco_rename_qos',
'qos_desc': {'PPS': 50, 'TTL': 5}}})
rename_path_temp = self.qos_second_path +\
resp_body['qoss']['qos']['id']
rename_path = str(rename_path_temp)
rename_response = self.test_app.put(rename_path, rename_req_body)
self.assertEqual(200, rename_response.status_int)
self.tearDownQos(rename_path)
LOG.debug("test_update_qos - END")
def test_update_qosDNE(self, qos_id='100'):
""" Test update qos does not exist """
LOG.debug("test_update_qosDNE - START")
rename_req_body = json.dumps({'qos': {'qos_name': 'cisco_rename_qos',
'qos_desc': {'PPS': 50, 'TTL': 5}}})
rename_path_temp = self.qos_second_path + qos_id
rename_path = str(rename_path_temp)
rename_response = self.test_app.put(rename_path, rename_req_body,
status='*')
self.assertEqual(452, rename_response.status_int)
LOG.debug("test_update_qosDNE - END")
def test_update_qosBADRequest(self):
""" Test update qos bad request """
LOG.debug("test_update_qosBADRequest - START")
req_body = json.dumps(self.test_qos_data)
index_response = self.test_app.post(self.qos_path, req_body,
content_type=self.contenttype)
resp_body = wsgi.Serializer().deserialize(index_response.body,
self.contenttype)
rename_path_temp = self.qos_second_path +\
resp_body['qoss']['qos']['id']
rename_path = str(rename_path_temp)
rename_response = self.test_app.put(rename_path, 'BAD_REQUEST',
status="*")
self.assertEqual(400, rename_response.status_int)
# Clean Up - Delete the Port Profile
self.tearDownQos(rename_path)
LOG.debug("test_update_qosBADRequest - END")
def test_delete_qos(self):
""" Test delte qos """
LOG.debug("test_delete_qos - START")
req_body = json.dumps({'qos': {'qos_name': 'cisco_test_qos',
'qos_desc': {'PPS': 50, 'TTL': 5}}})
index_response = self.test_app.post(self.qos_path, req_body,
content_type=self.contenttype)
resp_body = wsgi.Serializer().deserialize(index_response.body,
self.contenttype)
delete_path_temp = self.qos_second_path +\
resp_body['qoss']['qos']['id']
delete_path = str(delete_path_temp)
delete_response = self.test_app.delete(delete_path)
self.assertEqual(202, delete_response.status_int)
LOG.debug("test_delete_qos - END")
def test_delete_qosDNE(self, qos_id='100'):
""" Test delte qos does not exist"""
LOG.debug("test_delete_qosDNE - START")
delete_path_temp = self.qos_second_path + qos_id
delete_path = str(delete_path_temp)
delete_response = self.test_app.delete(delete_path, status='*')
self.assertEqual(452, delete_response.status_int)
LOG.debug("test_delete_qosDNE - END")
def tearDownQos(self, delete_profile_path):
""" Tear Down Qos """
self.test_app.delete(delete_profile_path)
class CredentialExtensionTest(unittest.TestCase):
def setUp(self):
""" Set up function """
parent_resource = dict(member_name="tenant",
collection_name="extensions/csco/tenants")
controller = credential.CredentialController(
QuantumManager.get_plugin())
res_ext = extensions.ResourceExtension('credentials', controller,
parent=parent_resource)
self.test_app = setup_extensions_test_app(
SimpleExtensionManager(res_ext))
self.contenttype = 'application/json'
self.credential_path = '/extensions/csco/tenants/tt/credentials'
self.cred_second_path = '/extensions/csco/tenants/tt/credentials/'
self.test_credential_data = {'credential':
{'credential_name': 'cred8',
'user_name': 'newUser2',
'password': 'newPasswd1'}}
def test_list_credentials(self):
""" Test list credentials """
#Create Credential before listing
LOG.debug("test_list_credentials - START")
req_body1 = json.dumps(self.test_credential_data)
create_response1 = self.test_app.post(
self.credential_path, req_body1,
content_type=self.contenttype)
req_body2 = json.dumps({'credential':
{'credential_name': 'cred9',
'user_name': 'newUser2',
'password': 'newPasswd2'}})
create_response2 = self.test_app.post(
self.credential_path, req_body2,
content_type=self.contenttype)
index_response = self.test_app.get(
self.credential_path)
self.assertEqual(200, index_response.status_int)
#CLean Up - Deletion of the Credentials
resp_body1 = wsgi.Serializer().deserialize(
create_response1.body, self.contenttype)
delete_path1_temp = self.cred_second_path +\
resp_body1['credentials']['credential']['id']
delete_path1 = str(delete_path1_temp)
resp_body2 = wsgi.Serializer().deserialize(
create_response2.body, self.contenttype)
delete_path2_temp = self.cred_second_path +\
resp_body2['credentials']['credential']['id']
delete_path2 = str(delete_path2_temp)
self.tearDownCredential(delete_path1)
self.tearDownCredential(delete_path2)
LOG.debug("test_list_credentials - END")
def test_create_credential(self):
""" Test create credential """
LOG.debug("test_create_credential - START")
req_body = json.dumps(self.test_credential_data)
index_response = self.test_app.post(
self.credential_path, req_body,
content_type=self.contenttype)
self.assertEqual(200, index_response.status_int)
#CLean Up - Deletion of the Credentials
resp_body = wsgi.Serializer().deserialize(
index_response.body, self.contenttype)
delete_path_temp = self.cred_second_path +\
resp_body['credentials']['credential']['id']
delete_path = str(delete_path_temp)
self.tearDownCredential(delete_path)
LOG.debug("test_create_credential - END")
def test_create_credentialBADRequest(self):
""" Test create credential bad request """
LOG.debug("test_create_credentialBADRequest - START")
index_response = self.test_app.post(
self.credential_path, 'BAD_REQUEST',
content_type=self.contenttype, status='*')
self.assertEqual(400, index_response.status_int)
LOG.debug("test_create_credentialBADRequest - END")
def test_show_credential(self):
""" Test show credential """
LOG.debug("test_show_credential - START")
req_body = json.dumps(self.test_credential_data)
index_response = self.test_app.post(
self.credential_path, req_body,
content_type=self.contenttype)
resp_body = wsgi.Serializer().deserialize(
index_response.body, self.contenttype)
show_path_temp = self.cred_second_path +\
resp_body['credentials']['credential']['id']
show_cred_path = str(show_path_temp)
show_response = self.test_app.get(show_cred_path)
self.assertEqual(200, show_response.status_int)
LOG.debug("test_show_credential - END")
def test_show_credentialDNE(self, credential_id='100'):
""" Test show credential does not exist """
LOG.debug("test_show_credentialDNE - START")
show_path_temp = self.cred_second_path + credential_id
show_cred_path = str(show_path_temp)
show_response = self.test_app.get(show_cred_path, status='*')
self.assertEqual(451, show_response.status_int)
LOG.debug("test_show_credentialDNE - END")
def test_update_credential(self):
""" Test update credential """
LOG.debug("test_update_credential - START")
req_body = json.dumps(self.test_credential_data)
index_response = self.test_app.post(
self.credential_path, req_body,
content_type=self.contenttype)
resp_body = wsgi.Serializer().deserialize(
index_response.body, self.contenttype)
rename_req_body = json.dumps({'credential':
{'credential_name': 'cred3',
'user_name': 'RenamedUser',
'password': 'Renamedpassword'}})
rename_path_temp = self.cred_second_path +\
resp_body['credentials']['credential']['id']
rename_path = str(rename_path_temp)
rename_response = self.test_app.put(rename_path, rename_req_body)
self.assertEqual(200, rename_response.status_int)
# Clean Up - Delete the Credentials
self.tearDownCredential(rename_path)
LOG.debug("test_update_credential - END")
def test_update_credBADReq(self):
""" Test update credential bad request """
LOG.debug("test_update_credBADReq - START")
req_body = json.dumps(self.test_credential_data)
index_response = self.test_app.post(
self.credential_path, req_body,
content_type=self.contenttype)
resp_body = wsgi.Serializer().deserialize(
index_response.body, self.contenttype)
rename_path_temp = self.cred_second_path +\
resp_body['credentials']['credential']['id']
rename_path = str(rename_path_temp)
rename_response = self.test_app.put(rename_path, 'BAD_REQUEST',
status='*')
self.assertEqual(400, rename_response.status_int)
LOG.debug("test_update_credBADReq - END")
def test_update_credentialDNE(self, credential_id='100'):
""" Test update credential does not exist"""
LOG.debug("test_update_credentialDNE - START")
rename_req_body = json.dumps({'credential':
{'credential_name': 'cred3',
'user_name': 'RenamedUser',
'password': 'Renamedpassword'}})
rename_path_temp = self.cred_second_path + credential_id
rename_path = str(rename_path_temp)
rename_response = self.test_app.put(rename_path, rename_req_body,
status='*')
self.assertEqual(451, rename_response.status_int)
LOG.debug("test_update_credentialDNE - END")
def test_delete_credential(self):
""" Test delete credential """
LOG.debug("test_delete_credential - START")
req_body = json.dumps(self.test_credential_data)
index_response = self.test_app.post(
self.credential_path, req_body,
content_type=self.contenttype)
resp_body = wsgi.Serializer().deserialize(
index_response.body, self.contenttype)
delete_path_temp = self.cred_second_path +\
resp_body['credentials']['credential']['id']
delete_path = str(delete_path_temp)
delete_response = self.test_app.delete(delete_path)
self.assertEqual(202, delete_response.status_int)
LOG.debug("test_delete_credential - END")
def test_delete_credentialDNE(self, credential_id='100'):
""" Test delete credential does not exist """
LOG.debug("test_delete_credentialDNE - START")
delete_path_temp = self.cred_second_path + credential_id
delete_path = str(delete_path_temp)
delete_response = self.test_app.delete(delete_path, status='*')
self.assertEqual(451, delete_response.status_int)
LOG.debug("test_delete_credentialDNE - END")
def tearDownCredential(self, delete_path):
self.test_app.delete(delete_path)
def app_factory(global_conf, **local_conf):
conf = global_conf.copy()
conf.update(local_conf)
return ExtensionsTestApp(conf)
def setup_extensions_middleware(extension_manager=None):
extension_manager = (extension_manager or
PluginAwareExtensionManager(EXTENSIONS_PATH,
L2Network()))
options = {'config_file': TEST_CONF_FILE}
conf, app = config.load_paste_app('extensions_test_app', options, None)
return ExtensionMiddleware(app, conf, ext_mgr=extension_manager)
def setup_extensions_test_app(extension_manager=None):
return TestApp(setup_extensions_middleware(extension_manager))
class SimpleExtensionManager(object):
def __init__(self, resource_ext=None, action_ext=None, request_ext=None):
self.resource_ext = resource_ext
self.action_ext = action_ext
self.request_ext = request_ext
def get_resources(self):
resource_exts = []
if self.resource_ext:
resource_exts.append(self.resource_ext)
return resource_exts
def get_actions(self):
action_exts = []
if self.action_ext:
action_exts.append(self.action_ext)
return action_exts
def get_request_extensions(self):
request_extensions = []
if self.request_ext:
request_extensions.append(self.request_ext)
return request_extensions

View File

@ -26,11 +26,83 @@ 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
import quantum.plugins.cisco.db.nexus_db as nexus_db
LOG.getLogger(const.LOGGER_COMPONENT_NAME)
class NexusDB(object):
"""Class consisting of methods to call nexus db methods"""
def get_all_nexusportbindings(self):
"""get all nexus port bindings"""
bindings = []
try:
for bind in nexus_db.get_all_nexusport_bindings():
LOG.debug("Getting nexus port binding : %s" % bind.port_id)
bind_dict = {}
bind_dict["port-id"] = str(bind.port_id)
bind_dict["vlan-id"] = str(bind.vlan_id)
bindings.append(bind_dict)
except Exception, exc:
LOG.error("Failed to get all bindings: %s" % str(exc))
return bindings
def get_nexusportbinding(self, vlan_id):
"""get nexus port binding"""
binding = []
try:
for bind in nexus_db.get_nexusport_binding(vlan_id):
LOG.debug("Getting nexus port binding : %s" % bind.port_id)
bind_dict = {}
bind_dict["port-id"] = str(bind.port_id)
bind_dict["vlan-id"] = str(bind.vlan_id)
binding.append(bind_dict)
except Exception, exc:
LOG.error("Failed to get all bindings: %s" % str(exc))
return binding
def create_nexusportbinding(self, port_id, vlan_id):
"""create nexus port binding"""
bind_dict = {}
try:
res = nexus_db.add_nexusport_binding(port_id, vlan_id)
LOG.debug("Created nexus port binding : %s" % res.port_id)
bind_dict["port-id"] = str(res.port_id)
bind_dict["vlan-id"] = str(res.vlan_id)
return bind_dict
except Exception, exc:
LOG.error("Failed to create nexus binding: %s" % str(exc))
def delete_nexusportbinding(self, vlan_id):
"""delete nexus port binding"""
bindings = []
try:
bind = nexus_db.remove_nexusport_binding(vlan_id)
for res in bind:
LOG.debug("Deleted nexus port binding: %s" % res.vlan_id)
bind_dict = {}
bind_dict["port-id"] = res.port_id
bindings.append(bind_dict)
return bindings
except Exception, exc:
raise Exception("Failed to delete nexus port binding: %s"
% str(exc))
def update_nexusport_binding(self, port_id, new_vlan_id):
"""update nexus port binding"""
try:
res = nexus_db.update_nexusport_binding(port_id, new_vlan_id)
LOG.debug("Updating nexus port binding : %s" % res.port_id)
bind_dict = {}
bind_dict["port-id"] = str(res.port_id)
bind_dict["vlan-id"] = str(res.vlan_id)
return bind_dict
except Exception, exc:
raise Exception("Failed to update nexus port binding vnic: %s"
% str(exc))
class L2networkDB(object):
"""Class conisting of methods to call L2network db methods"""
def get_all_vlan_bindings(self):
@ -133,7 +205,7 @@ class L2networkDB(object):
pp_list.append(pp_dict)
except Exception, exc:
LOG.error("Failed to get port profile: %s" % str(exc))
return pp
return pp_list
def create_portprofile(self, tenant_id, name, vlan_id, qos):
"""Create a portprofile"""
@ -422,6 +494,70 @@ class QuantumDB(object):
raise Exception("Failed to unplug interface: %s" % str(exc))
class NexusDBTest(unittest.TestCase):
"""Class conisting of nexus DB unit tests"""
def setUp(self):
"""Setup for nexus db tests"""
l2network_db.initialize()
self.dbtest = NexusDB()
LOG.debug("Setup")
def tearDown(self):
"""Tear Down"""
db.clear_db()
def testa_create_nexusportbinding(self):
"""create nexus port binding"""
binding1 = self.dbtest.create_nexusportbinding("port1", 10)
self.assertTrue(binding1["port-id"] == "port1")
self.tearDown_nexusportbinding()
def testb_getall_nexusportbindings(self):
"""get all nexus port binding"""
binding1 = self.dbtest.create_nexusportbinding("port1", 10)
binding2 = self.dbtest.create_nexusportbinding("port2", 10)
bindings = self.dbtest.get_all_nexusportbindings()
count = 0
for bind in bindings:
if "port" in bind["port-id"]:
count += 1
self.assertTrue(count == 2)
self.tearDown_nexusportbinding()
def testc_delete_nexusportbinding(self):
"""delete nexus port binding"""
binding1 = self.dbtest.create_nexusportbinding("port1", 10)
self.dbtest.delete_nexusportbinding(10)
bindings = self.dbtest.get_all_nexusportbindings()
count = 0
for bind in bindings:
if "port " in bind["port-id"]:
count += 1
self.assertTrue(count == 0)
self.tearDown_nexusportbinding()
def testd_update_nexusportbinding(self):
"""update nexus port binding"""
binding1 = self.dbtest.create_nexusportbinding("port1", 10)
binding1 = self.dbtest.update_nexusport_binding(binding1["port-id"], \
20)
bindings = self.dbtest.get_all_nexusportbindings()
count = 0
for bind in bindings:
if "20" in str(bind["vlan-id"]):
count += 1
self.assertTrue(count == 1)
self.tearDown_nexusportbinding()
def tearDown_nexusportbinding(self):
"""tear down nexusport binding table"""
LOG.debug("Tearing Down Nexus port Bindings")
binds = self.dbtest.get_all_nexusportbindings()
for bind in binds:
vlan_id = bind["vlan-id"]
self.dbtest.delete_nexusportbinding(vlan_id)
class L2networkDBTest(unittest.TestCase):
"""Class conisting of L2network DB unit tests"""
def setUp(self):

View File

@ -597,7 +597,7 @@ class CoreAPITestFunc(unittest.TestCase):
qos = self.qos
port_profile_dict = self._l2network_plugin.create_portprofile(
tenant_id, profile_name, qos)
port_profile_id = port_profile_dict['profile-id']
port_profile_id = port_profile_dict['profile_id']
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)
@ -618,7 +618,7 @@ class CoreAPITestFunc(unittest.TestCase):
tenant_id = self.tenant_id
port_profile_dict = self._l2network_plugin.create_portprofile(
tenant_id, self.profile_name, self.qos)
port_profile_id = port_profile_dict['profile-id']
port_profile_id = port_profile_dict['profile_id']
self._l2network_plugin.delete_portprofile(tenant_id, port_profile_id)
self.assertRaises(Exception, cdb.get_portprofile, port_profile_id)
LOG.debug("test_delete_portprofile - tenant id: %s - END",
@ -645,7 +645,7 @@ class CoreAPITestFunc(unittest.TestCase):
LOG.debug("test_delete_portprofileAssociated - START")
port_profile_dict = self._l2network_plugin.create_portprofile(
tenant_id, self.profile_name, self.qos)
port_profile_id = port_profile_dict['profile-id']
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(
@ -675,8 +675,8 @@ class CoreAPITestFunc(unittest.TestCase):
tenant_id, self.profile_name, self.qos)
port_profile_dict2 = self._l2network_plugin.create_portprofile(
tenant_id, profile_name2, qos2)
port_profile_id1 = port_profile_dict1['profile-id']
port_profile_id2 = port_profile_dict2['profile-id']
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)
port_profile_list = [port_profile_dict1, port_profile_dict2]
@ -707,7 +707,7 @@ class CoreAPITestFunc(unittest.TestCase):
tenant_id = self.tenant_id
port_profile_dict = self._l2network_plugin.create_portprofile(
tenant_id, self.profile_name, self.qos)
port_profile_id = port_profile_dict['profile-id']
port_profile_id = port_profile_dict['profile_id']
result_port_profile = self._l2network_plugin.get_portprofile_details(
tenant_id, port_profile_id)
port_profile = cdb.get_portprofile(tenant_id, port_profile_id)
@ -741,7 +741,7 @@ class CoreAPITestFunc(unittest.TestCase):
LOG.debug("test_rename_portprofile - START")
port_profile_dict = self._l2network_plugin.create_portprofile(
tenant_id, self.profile_name, self.qos)
port_profile_id = port_profile_dict['profile-id']
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)
@ -777,7 +777,7 @@ class CoreAPITestFunc(unittest.TestCase):
self.port_state)
port_profile_dict = self._l2network_plugin.create_portprofile(
tenant_id, self.profile_name, self.qos)
port_profile_id = port_profile_dict['profile-id']
port_profile_id = port_profile_dict['profile_id']
self._l2network_plugin.associate_portprofile(
tenant_id, new_net_dict[const.NET_ID],
port_dict[const.PORT_ID], port_profile_id)
@ -819,7 +819,7 @@ class CoreAPITestFunc(unittest.TestCase):
self.port_state)
port_profile_dict = self._l2network_plugin.create_portprofile(
tenant_id, self.profile_name, self.qos)
port_profile_id = port_profile_dict['profile-id']
port_profile_id = port_profile_dict['profile_id']
self._l2network_plugin.associate_portprofile(
tenant_id, new_net_dict[const.NET_ID],
port_dict[const.PORT_ID], port_profile_id)
@ -885,6 +885,9 @@ class CoreAPITestFunc(unittest.TestCase):
LOG.debug("test_validate_port_state - END")
def setUp(self):
"""
Set up function
"""
self.tenant_id = "test_tenant"
self.network_name = "test_network"
self.profile_name = "test_tenant_port_profile"
@ -904,29 +907,50 @@ class CoreAPITestFunc(unittest.TestCase):
db.clear_db()
def tearDownNetwork(self, tenant_id, network_dict_id):
"""
Tear down the Network
"""
self._l2network_plugin.delete_network(tenant_id, network_dict_id)
def tearDownPortOnly(self, tenant_id, network_dict_id, port_id):
"""
Tear doen the port
"""
self._l2network_plugin.delete_port(tenant_id, network_dict_id, port_id)
def tearDownNetworkPort(self, tenant_id, network_dict_id, port_id):
"""
Tear down Network Port
"""
self._l2network_plugin.delete_port(tenant_id, network_dict_id, port_id)
self.tearDownNetwork(tenant_id, network_dict_id)
def tearDownNetworkPortInterface(self, tenant_id, network_dict_id,
port_id):
"""
Tear down Network Port Interface
"""
self._l2network_plugin.unplug_interface(tenant_id,
network_dict_id, port_id)
self.tearDownNetworkPort(tenant_id, network_dict_id, port_id)
def tearDownPortProfile(self, tenant_id, port_profile_id):
"""
Tear down Port Profile
"""
self._l2network_plugin.delete_portprofile(tenant_id, port_profile_id)
def tearDownPortProfileBinding(self, tenant_id, port_profile_id):
"""
Tear down port profile binding
"""
self._l2network_plugin.delete_portprofile(tenant_id, port_profile_id)
def tearDownAssociatePortProfile(self, tenant_id, net_id, port_id,
port_profile_id):
"""
Tear down associate port profile
"""
self._l2network_plugin.disassociate_portprofile(
tenant_id, net_id, port_id, port_profile_id)
self.tearDownPortProfile(tenant_id, port_profile_id)

View File

@ -19,6 +19,7 @@ import logging
from quantum.common import exceptions as exc
from quantum.plugins.cisco.common import cisco_constants as const
from quantum.plugins.cisco.nexus import cisco_nexus_plugin
from quantum.plugins.cisco.db import l2network_db as cdb
LOG = logging.getLogger('quantum.tests.test_nexus')
@ -26,6 +27,9 @@ LOG = logging.getLogger('quantum.tests.test_nexus')
class TestNexusPlugin(unittest.TestCase):
def setUp(self):
"""
Set up function
"""
self.tenant_id = "test_tenant_cisco1"
self.net_name = "test_network_cisco1"
@ -34,6 +38,7 @@ class TestNexusPlugin(unittest.TestCase):
self.vlan_id = 267
self.port_id = "9"
self._cisco_nexus_plugin = cisco_nexus_plugin.NexusPlugin()
cdb.initialize()
def test_create_network(self, net_tenant_id=None, network_name=None,
network_id=None, net_vlan_name=None,
@ -66,7 +71,6 @@ class TestNexusPlugin(unittest.TestCase):
new_net_dict = self._cisco_nexus_plugin.create_network(
tenant_id, net_name, net_id, vlan_name, vlan_id)
self.assertEqual(new_net_dict[const.NET_ID], self.net_id)
self.assertEqual(new_net_dict[const.NET_NAME], self.net_name)
self.assertEqual(new_net_dict[const.NET_VLAN_NAME], self.vlan_name)
@ -264,18 +268,3 @@ class TestNexusPlugin(unittest.TestCase):
Clean up functions after the tests
"""
self._cisco_nexus_plugin.delete_network(tenant_id, network_dict_id)
# def test_create_network(self):
# _test_create_network(self._cisco_nexus_plugin)
# def test_delete_network(self):
# _test_delete_network(self._cisco_nexus_plugin)
# def test_rename_network(self):
# _test_rename_network(self._cisco_nexus_plugin)
# def test_show_network(self):
# _test_get_network_details(self._cisco_nexus_plugin)
# def test_list_networks(self):
# _test_list_all_networks(self._cisco_nexus_plugin)

View File

@ -73,6 +73,7 @@ ASSOCIATE_PROFILE_OUTPUT = "<configConfMos cookie=\"cookie_placeholder\" "\
class TestUCSDriver(unittest.TestCase):
def setUp(self):
""" Set up function"""
self.ucsm_driver = cisco_ucs_network_driver.CiscoUCSMDriver()
self.vlan_name = 'New Vlan'
self.vlan_id = '200'
@ -136,8 +137,6 @@ class TestUCSDriver(unittest.TestCase):
"""
LOG.debug("test_create_profile_post_data - START")
#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.ucsm_driver._delete_profile_post_data(

View File

@ -29,6 +29,9 @@ LOG.getLogger("cisco_plugin")
class UCSVICTestPlugin(unittest.TestCase):
def setUp(self):
"""
Set up function.
"""
self.tenant_id = "test_tenant_cisco12"
self.net_name = "test_network_cisco12"
@ -141,6 +144,9 @@ class UCSVICTestPlugin(unittest.TestCase):
self.tearDownNetwork(self.tenant_id, self.net_id)
def test_rename_network(self):
"""
Tests rename network.
"""
self._test_rename_network("new_test_network1")
def _test_create_port(self, port_state):
@ -166,6 +172,9 @@ class UCSVICTestPlugin(unittest.TestCase):
self.tearDownNetworkPort(self.tenant_id, self.net_id, self.port_id)
def test_create_port(self):
"""
Tests create port.
"""
self._test_create_port(const.PORT_UP)
def _test_delete_port(self, port_state):
@ -188,6 +197,9 @@ class UCSVICTestPlugin(unittest.TestCase):
self.tearDownNetwork(self.tenant_id, self.net_id)
def test_delete_port(self):
"""
Tests delete port.
"""
self._test_delete_port(const.PORT_UP)
def _test_update_port(self, port_state):
@ -207,9 +219,15 @@ class UCSVICTestPlugin(unittest.TestCase):
self.tearDownNetworkPort(self.tenant_id, self.net_id, self.port_id)
def test_update_port_state_up(self):
"""
Tests update port state up
"""
self._test_update_port(const.PORT_UP)
def test_update_port_state_down(self):
"""
Tests update port state down
"""
self._test_update_port(const.PORT_DOWN)
def _test_get_port_details_state_up(self, port_state):
@ -266,12 +284,21 @@ class UCSVICTestPlugin(unittest.TestCase):
self.tearDownNetworkPort(self.tenant_id, self.net_id, self.port_id)
def test_get_port_details_state_up(self):
"""
Tests get port details state up
"""
self._test_get_port_details_state_up(const.PORT_UP)
def test_show_port_state_down(self):
"""
Tests show port state down
"""
self._test_show_port_state_down(const.PORT_DOWN)
def test_create_port_profile(self):
"""
Tests create port profile
"""
LOG.debug("UCSVICTestPlugin:test_create_port_profile() called\n")
new_port_profile = self._cisco_ucs_plugin._create_port_profile(
self.tenant_id, self.net_id, self.port_id,
@ -284,6 +311,9 @@ class UCSVICTestPlugin(unittest.TestCase):
self._cisco_ucs_plugin._delete_port_profile(self.port_id, profile_name)
def test_delete_port_profile(self):
"""
Tests delete port profile
"""
LOG.debug("UCSVICTestPlugin:test_delete_port_profile() called\n")
self._cisco_ucs_plugin._create_port_profile(
self.tenant_id, self.net_id, self.port_id, self.vlan_name,
@ -322,7 +352,10 @@ class UCSVICTestPlugin(unittest.TestCase):
self.tearDownNetworkPortInterface(self.tenant_id, self.net_id,
self.port_id)
def test_plug_interface(self):
def test_plug_interface(self):
"""
Tests test plug interface
"""
self._test_plug_interface("4")
def _test_unplug_interface(self, remote_interface_id):
@ -351,10 +384,16 @@ class UCSVICTestPlugin(unittest.TestCase):
conf.DEFAULT_VLAN_ID)
self.tearDownNetworkPort(self.tenant_id, self.net_id, self.port_id)
def test_unplug_interface(self):
def test_unplug_interface(self):
"""
Tests unplug interface
"""
self._test_unplug_interface("4")
def test_get_vlan_name_for_network(self):
"""
Tests get vlan name for network
"""
LOG.debug("UCSVICTestPlugin:test_get_vlan_name_for_network() called\n")
net = self._cisco_ucs_plugin.create_network(
self.tenant_id, self.net_name, self.net_id,
@ -363,6 +402,9 @@ class UCSVICTestPlugin(unittest.TestCase):
self.tearDownNetwork(self.tenant_id, self.net_id)
def test_get_vlan_id_for_network(self):
"""
Tests get vlan id for network
"""
LOG.debug("UCSVICTestPlugin:test_get_vlan_id_for_network() called\n")
net = self._cisco_ucs_plugin.create_network(
self.tenant_id, self.net_name, self.net_id, self.vlan_name,
@ -371,6 +413,9 @@ class UCSVICTestPlugin(unittest.TestCase):
self.tearDownNetwork(self.tenant_id, self.net_id)
def test_get_network(self):
"""
Tests get network
"""
LOG.debug("UCSVICTestPlugin:test_get_network() called\n")
net = self._cisco_ucs_plugin.create_network(
self.tenant_id, self.net_name, self.net_id, self.vlan_name,
@ -379,6 +424,9 @@ class UCSVICTestPlugin(unittest.TestCase):
self.tearDownNetwork(self.tenant_id, self.net_id)
def test_get_port(self):
"""
Tests get port
"""
LOG.debug("UCSVICTestPlugin:test_get_port() called\n")
self._cisco_ucs_plugin.create_network(self.tenant_id, self.net_name,
self.net_id, self.vlan_name,
@ -390,19 +438,31 @@ class UCSVICTestPlugin(unittest.TestCase):
self.tearDownNetworkPort(self.tenant_id, self.net_id, self.port_id)
def test_get_network_NetworkNotFound(self):
"""
Tests get network not found
"""
self.assertRaises(exc.NetworkNotFound,
self._cisco_ucs_plugin._get_network,
self.tenant_id, self.net_id)
def test_delete_network_NetworkNotFound(self):
"""
Tests delete network not found
"""
self.assertRaises(exc.NetworkNotFound,
self._cisco_ucs_plugin.delete_network,
self.tenant_id, self.net_id)
def test_delete_port_PortInUse(self):
"""
Tests delete port in use
"""
self._test_delete_port_PortInUse("4")
def _test_delete_port_PortInUse(self, remote_interface_id):
"""
Tests delete port in use
"""
self._cisco_ucs_plugin.create_network(self.tenant_id, self.net_name,
self.net_id, self.vlan_name,
self.vlan_id)
@ -417,6 +477,9 @@ class UCSVICTestPlugin(unittest.TestCase):
self.port_id)
def test_delete_port_PortNotFound(self):
"""
Tests delete port not found
"""
self._cisco_ucs_plugin.create_network(self.tenant_id, self.net_name,
self.net_id, self.vlan_name,
self.vlan_id)
@ -425,10 +488,16 @@ class UCSVICTestPlugin(unittest.TestCase):
self.tearDownNetwork(self.tenant_id, self.net_id)
def test_plug_interface_PortInUse(self):
"""
Tests plug interface port in use
"""
self._test_plug_interface_PortInUse("6", "5")
def _test_plug_interface_PortInUse(self, remote_interface_id1,
remote_interface_id2):
"""
Tests plug interface port in use
"""
LOG.debug("UCSVICTestPlugin:_test_plug_interface_PortInUse() called\n")
self._cisco_ucs_plugin.create_network(self.tenant_id, self.net_name,
self.net_id, self.vlan_name,
@ -445,10 +514,16 @@ class UCSVICTestPlugin(unittest.TestCase):
self.port_id)
def test_attachment_exists(self):
"""
Tests attachment exists
"""
LOG.debug("UCSVICTestPlugin:testValidateAttachmentAlreadyAttached")
self._test_attachment_exists("4")
def _test_attachment_exists(self, remote_interface_id):
"""
Tests attachment exists
"""
LOG.debug("UCSVICTestPlugin:_test_validate_attachmentAlreadyAttached")
self._cisco_ucs_plugin.create_network(self.tenant_id, self.net_name,
self.net_id, self.vlan_name,
@ -465,14 +540,23 @@ class UCSVICTestPlugin(unittest.TestCase):
self.port_id)
def tearDownNetwork(self, tenant_id, net_id):
"""
Tear down network
"""
self._cisco_ucs_plugin.delete_network(tenant_id, net_id)
def tearDownNetworkPort(self, tenant_id, net_id, port_id):
"""
Tear down network port
"""
self._cisco_ucs_plugin.delete_port(tenant_id, net_id,
port_id)
self.tearDownNetwork(tenant_id, net_id)
def tearDownNetworkPortInterface(self, tenant_id, net_id, port_id):
"""
Tear down network port interface
"""
self._cisco_ucs_plugin.unplug_interface(tenant_id, net_id,
port_id)
self.tearDownNetworkPort(tenant_id, net_id, port_id)

View File

@ -27,8 +27,8 @@ import httplib
import logging as LOG
from xml.etree import ElementTree as et
from quantum.plugins.cisco.common import cisco_constants as const
from quantum.plugins.cisco.common import cisco_exceptions as cexc
from quantum.plugins.cisco.common import cisco_constants as const
from quantum.plugins.cisco.ucs import cisco_getvif as gvif

View File

@ -23,9 +23,9 @@ import logging as LOG
from quantum.common import exceptions as exc
from quantum.common import utils
from quantum.plugins.cisco.common import cisco_exceptions as cexc
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.ucs import cisco_ucs_configuration as conf

View File

@ -133,7 +133,7 @@ class OVSQuantumPlugin(QuantumPluginBase):
# Verify that no attachments are plugged into the network
for port in db.port_list(net_id):
if port['interface_id']:
if port.interface_id:
raise q_exc.NetworkInUse(net_id=net_id)
net = db.network_destroy(net_id)
ovs_db.remove_vlan_binding(net_id)
@ -150,31 +150,31 @@ class OVSQuantumPlugin(QuantumPluginBase):
return self._make_net_dict(str(net.uuid), net.name, None)
def _make_port_dict(self, port_id, port_state, net_id, attachment):
res = {'port-id': port_id,
'port-state': port_state}
if net_id:
res['net-id'] = net_id
if attachment:
res['attachment-id'] = attachment
return res
return {'port-id': port_id,
'port-state': port_state,
'net-id': net_id,
'attachment': attachment}
def get_all_ports(self, tenant_id, net_id):
ids = []
ports = db.port_list(net_id)
for p in ports:
LOG.debug("Appending port: %s" % p.uuid)
d = self._make_port_dict(str(p.uuid), p.state, None, None)
d = self._make_port_dict(str(p.uuid), p.state, p.network_id,
p.interface_id)
ids.append(d)
return ids
def create_port(self, tenant_id, net_id, port_state=None):
LOG.debug("Creating port with network_id: %s" % net_id)
port = db.port_create(net_id, port_state)
return self._make_port_dict(str(port.uuid), port.state, None, None)
return self._make_port_dict(str(port.uuid), port.state,
port.network_id, port.interface_id)
def delete_port(self, tenant_id, net_id, port_id):
port = db.port_destroy(port_id, net_id)
return self._make_port_dict(str(port.uuid), port.state, None, None)
return self._make_port_dict(str(port.uuid), port.state,
port.network_id, port.interface_id)
def update_port(self, tenant_id, net_id, port_id, port_state):
"""
@ -183,7 +183,8 @@ class OVSQuantumPlugin(QuantumPluginBase):
LOG.debug("update_port() called\n")
port = db.port_get(port_id, net_id)
db.port_set_state(port_id, net_id, port_state)
return self._make_port_dict(str(port.uuid), port.state, None, None)
return self._make_port_dict(str(port.uuid), port.state,
port.network_id, port.interface_id)
def get_port_details(self, tenant_id, net_id, port_id):
port = db.port_get(port_id, net_id)

View File

@ -65,6 +65,9 @@ if __name__ == '__main__':
# we should only invoked the tests once
invoke_once = len(sys.argv) > 1
test_config['plugin_name'] = "quantum.plugins.openvswitch." + \
"ovs_quantum_plugin.OVSQuantumPlugin"
cwd = os.getcwd()
working_dir = os.path.abspath("tests")

View File

@ -0,0 +1,15 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2011 OpenStack LLC
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

View File

@ -0,0 +1,65 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2011 OpenStack LLC
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
""" Stubs for client tools unit tests """
from quantum import api as server
from tests.unit import testlib_api
class FakeStdout:
def __init__(self):
self.content = []
def write(self, text):
self.content.append(text)
def make_string(self):
result = ''
for line in self.content:
result = result + line
return result
class FakeHTTPConnection:
""" stub HTTP connection class for CLI testing """
def __init__(self, _1, _2):
# Ignore host and port parameters
self._req = None
options = \
dict(plugin_provider='quantum.plugins.SamplePlugin.FakePlugin')
self._api = server.APIRouterV01(options)
def request(self, method, action, body, headers):
# TODO: remove version prefix from action!
parts = action.split('/', 2)
path = '/' + parts[2]
self._req = testlib_api.create_request(path, body, "application/json",
method)
def getresponse(self):
res = self._req.get_response(self._api)
def _fake_read():
""" Trick for making a webob.Response look like a
httplib.Response
"""
return res.body
setattr(res, 'read', _fake_read)
return res

View File

@ -261,6 +261,26 @@ class APITest(unittest.TestCase):
self.assertEqual(delete_network_res.status_int, 421)
LOG.debug("_test_delete_network_in_use - format:%s - END", format)
def _test_delete_network_with_unattached_port(self, format):
LOG.debug("_test_delete_network_with_unattached_port "\
"- format:%s - START", format)
content_type = "application/%s" % format
port_state = "ACTIVE"
network_id = self._create_network(format)
LOG.debug("Deleting network %(network_id)s"\
" of tenant %(tenant_id)s", locals())
port_id = self._create_port(network_id, port_state, format)
LOG.debug("Deleting network %(network_id)s"\
" of tenant %(tenant_id)s", locals())
delete_network_req = testlib.network_delete_request(self.tenant_id,
network_id,
format)
delete_network_res = delete_network_req.get_response(self.api)
self.assertEqual(delete_network_res.status_int, 204)
LOG.debug("_test_delete_network_with_unattached_port "\
"- format:%s - END", format)
def _test_list_ports(self, format):
LOG.debug("_test_list_ports - format:%s - START", format)
content_type = "application/%s" % format
@ -848,6 +868,12 @@ class APITest(unittest.TestCase):
def test_delete_network_in_use_xml(self):
self._test_delete_network_in_use('xml')
def test_delete_network_with_unattached_port_xml(self):
self._test_delete_network_with_unattached_port('xml')
def test_delete_network_with_unattached_port_json(self):
self._test_delete_network_with_unattached_port('json')
def test_list_ports_json(self):
self._test_list_ports('json')

420
tests/unit/test_cli.py Normal file
View File

@ -0,0 +1,420 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2010-2011 ????
# 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: Salvatore Orlando, Citrix Systems
""" Module containing unit tests for Quantum
command line interface
"""
import logging
import sys
import unittest
from quantum import api as server
from quantum import cli_lib as cli
from quantum.client import Client
from quantum.db import api as db
from tests.unit.client_tools import stubs as client_stubs
LOG = logging.getLogger('quantum.tests.test_cli')
FORMAT = 'json'
class CLITest(unittest.TestCase):
def setUp(self):
"""Prepare the test environment"""
options = {}
options['plugin_provider'] = 'quantum.plugins.SamplePlugin.FakePlugin'
self.api = server.APIRouterV01(options)
self.tenant_id = "test_tenant"
self.network_name_1 = "test_network_1"
self.network_name_2 = "test_network_2"
# Prepare client and plugin manager
self.client = Client(tenant=self.tenant_id, format=FORMAT,
testingStub=client_stubs.FakeHTTPConnection)
# Redirect stdout
self.fake_stdout = client_stubs.FakeStdout()
sys.stdout = self.fake_stdout
def tearDown(self):
"""Clear the test environment"""
db.clear_db()
sys.stdout = sys.__stdout__
def _verify_list_networks(self):
# Verification - get raw result from db
nw_list = db.network_list(self.tenant_id)
networks = [dict(id=nw.uuid, name=nw.name) for nw in nw_list]
# Fill CLI template
output = cli.prepare_output('list_nets', self.tenant_id,
dict(networks=networks))
# Verify!
# Must add newline at the end to match effect of print call
self.assertEquals(self.fake_stdout.make_string(), output + '\n')
def _verify_create_network(self):
# Verification - get raw result from db
nw_list = db.network_list(self.tenant_id)
if len(nw_list) != 1:
self.fail("No network created")
network_id = nw_list[0].uuid
# Fill CLI template
output = cli.prepare_output('create_net', self.tenant_id,
dict(network_id=network_id))
# Verify!
# Must add newline at the end to match effect of print call
self.assertEquals(self.fake_stdout.make_string(), output + '\n')
def _verify_delete_network(self, network_id):
# Verification - get raw result from db
nw_list = db.network_list(self.tenant_id)
if len(nw_list) != 0:
self.fail("DB should not contain any network")
# Fill CLI template
output = cli.prepare_output('delete_net', self.tenant_id,
dict(network_id=network_id))
# Verify!
# Must add newline at the end to match effect of print call
self.assertEquals(self.fake_stdout.make_string(), output + '\n')
def _verify_rename_network(self):
# Verification - get raw result from db
nw_list = db.network_list(self.tenant_id)
network_data = {'id': nw_list[0].uuid,
'name': nw_list[0].name}
# Fill CLI template
output = cli.prepare_output('rename_net', self.tenant_id,
dict(network=network_data))
# Verify!
# Must add newline at the end to match effect of print call
self.assertEquals(self.fake_stdout.make_string(), output + '\n')
def _verify_show_network(self):
# Verification - get raw result from db
nw = db.network_list(self.tenant_id)[0]
network = dict(id=nw.uuid, name=nw.name)
# Fill CLI template
output = cli.prepare_output('show_net', self.tenant_id,
dict(network=network))
# Verify!
# Must add newline at the end to match effect of print call
self.assertEquals(self.fake_stdout.make_string(), output + '\n')
def _verify_list_ports(self, network_id):
# Verification - get raw result from db
port_list = db.port_list(network_id)
ports = [dict(id=port.uuid, state=port.state)
for port in port_list]
# Fill CLI template
output = cli.prepare_output('list_ports', self.tenant_id,
dict(network_id=network_id,
ports=ports))
# Verify!
# Must add newline at the end to match effect of print call
self.assertEquals(self.fake_stdout.make_string(), output + '\n')
def _verify_create_port(self, network_id):
# Verification - get raw result from db
port_list = db.port_list(network_id)
if len(port_list) != 1:
self.fail("No port created")
port_id = port_list[0].uuid
# Fill CLI template
output = cli.prepare_output('create_port', self.tenant_id,
dict(network_id=network_id,
port_id=port_id))
# Verify!
# Must add newline at the end to match effect of print call
self.assertEquals(self.fake_stdout.make_string(), output + '\n')
def _verify_delete_port(self, network_id, port_id):
# Verification - get raw result from db
port_list = db.port_list(network_id)
if len(port_list) != 0:
self.fail("DB should not contain any port")
# Fill CLI template
output = cli.prepare_output('delete_port', self.tenant_id,
dict(network_id=network_id,
port_id=port_id))
# Verify!
# Must add newline at the end to match effect of print call
self.assertEquals(self.fake_stdout.make_string(), output + '\n')
def _verify_set_port_state(self, network_id, port_id):
# Verification - get raw result from db
port = db.port_get(port_id, network_id)
port_data = {'id': port.uuid, 'state': port.state}
# Fill CLI template
output = cli.prepare_output('set_port_state', self.tenant_id,
dict(network_id=network_id,
port=port_data))
# Verify!
# Must add newline at the end to match effect of print call
self.assertEquals(self.fake_stdout.make_string(), output + '\n')
def _verify_show_port(self, network_id, port_id):
# Verification - get raw result from db
# TODO(salvatore-orlando): Must resolve this issue with
# attachment in separate bug fix.
port = db.port_get(port_id, network_id)
port_data = {'id': port.uuid, 'state': port.state,
'attachment': "<none>"}
if port.interface_id is not None:
port_data['attachment'] = port.interface_id
# Fill CLI template
output = cli.prepare_output('show_port', self.tenant_id,
dict(network_id=network_id,
port=port_data))
# Verify!
# Must add newline at the end to match effect of print call
self.assertEquals(self.fake_stdout.make_string(), output + '\n')
def _verify_plug_iface(self, network_id, port_id):
# Verification - get raw result from db
port = db.port_get(port_id, network_id)
# Fill CLI template
output = cli.prepare_output("plug_iface", self.tenant_id,
dict(network_id=network_id,
port_id=port['uuid'],
attachment=port['interface_id']))
# Verify!
# Must add newline at the end to match effect of print call
self.assertEquals(self.fake_stdout.make_string(), output + '\n')
def _verify_unplug_iface(self, network_id, port_id):
# Verification - get raw result from db
port = db.port_get(port_id, network_id)
# Fill CLI template
output = cli.prepare_output("unplug_iface", self.tenant_id,
dict(network_id=network_id,
port_id=port['uuid']))
# Verify!
# Must add newline at the end to match effect of print call
self.assertEquals(self.fake_stdout.make_string(), output + '\n')
def test_list_networks(self):
try:
# Pre-populate data for testing using db api
db.network_create(self.tenant_id, self.network_name_1)
db.network_create(self.tenant_id, self.network_name_2)
cli.list_nets(self.client, self.tenant_id)
except:
LOG.exception("Exception caught: %s", sys.exc_info())
self.fail("test_list_networks failed due to an exception")
LOG.debug("Operation completed. Verifying result")
LOG.debug(self.fake_stdout.content)
self._verify_list_networks()
def test_create_network(self):
try:
cli.create_net(self.client, self.tenant_id, "test")
except:
LOG.exception("Exception caught: %s", sys.exc_info())
self.fail("test_create_network failed due to an exception")
LOG.debug("Operation completed. Verifying result")
LOG.debug(self.fake_stdout.content)
self._verify_create_network()
def test_delete_network(self):
try:
db.network_create(self.tenant_id, self.network_name_1)
network_id = db.network_list(self.tenant_id)[0]['uuid']
cli.delete_net(self.client, self.tenant_id, network_id)
except:
LOG.exception("Exception caught: %s", sys.exc_info())
self.fail("test_delete_network failed due to an exception")
LOG.debug("Operation completed. Verifying result")
LOG.debug(self.fake_stdout.content)
self._verify_delete_network(network_id)
def test_show_network(self):
try:
# Load some data into the datbase
net = db.network_create(self.tenant_id, self.network_name_1)
cli.show_net(self.client, self.tenant_id, net['uuid'])
except:
LOG.exception("Exception caught: %s", sys.exc_info())
self.fail("test_detail_network failed due to an exception")
LOG.debug("Operation completed. Verifying result")
LOG.debug(self.fake_stdout.content)
self._verify_show_network()
def test_rename_network(self):
try:
net = db.network_create(self.tenant_id, self.network_name_1)
network_id = net['uuid']
cli.rename_net(self.client, self.tenant_id,
network_id, self.network_name_2)
except:
LOG.exception("Exception caught: %s", sys.exc_info())
self.fail("test_rename_network failed due to an exception")
LOG.debug("Operation completed. Verifying result")
LOG.debug(self.fake_stdout.content)
self._verify_rename_network()
def test_list_ports(self):
try:
# Pre-populate data for testing using db api
net = db.network_create(self.tenant_id, self.network_name_1)
network_id = net['uuid']
db.port_create(network_id)
db.port_create(network_id)
cli.list_ports(self.client, self.tenant_id, network_id)
except:
LOG.exception("Exception caught: %s", sys.exc_info())
self.fail("test_list_ports failed due to an exception")
LOG.debug("Operation completed. Verifying result")
LOG.debug(self.fake_stdout.content)
self._verify_list_ports(network_id)
def test_create_port(self):
network_id = None
try:
# Pre-populate data for testing using db api
net = db.network_create(self.tenant_id, self.network_name_1)
network_id = net['uuid']
cli.create_port(self.client, self.tenant_id, network_id)
except:
LOG.exception("Exception caught: %s", sys.exc_info())
self.fail("test_create_port failed due to an exception")
LOG.debug("Operation completed. Verifying result")
LOG.debug(self.fake_stdout.content)
self._verify_create_port(network_id)
def test_delete_port(self):
network_id = None
port_id = None
try:
# Pre-populate data for testing using db api
net = db.network_create(self.tenant_id, self.network_name_1)
network_id = net['uuid']
port = db.port_create(network_id)
port_id = port['uuid']
cli.delete_port(self.client, self.tenant_id, network_id, port_id)
except:
LOG.exception("Exception caught: %s", sys.exc_info())
self.fail("test_delete_port failed due to an exception")
LOG.debug("Operation completed. Verifying result")
LOG.debug(self.fake_stdout.content)
self._verify_delete_port(network_id, port_id)
def test_set_port_state(self):
try:
net = db.network_create(self.tenant_id, self.network_name_1)
network_id = net['uuid']
port = db.port_create(network_id)
port_id = port['uuid']
# Default state is DOWN - change to ACTIVE.
cli.set_port_state(self.client, self.tenant_id, network_id,
port_id, 'ACTIVE')
except:
LOG.exception("Exception caught: %s", sys.exc_info())
self.fail("test_set_port_state failed due to an exception")
LOG.debug("Operation completed. Verifying result")
LOG.debug(self.fake_stdout.content)
self._verify_set_port_state(network_id, port_id)
def test_show_port_no_attach(self):
network_id = None
port_id = None
try:
# Pre-populate data for testing using db api
net = db.network_create(self.tenant_id, self.network_name_1)
network_id = net['uuid']
port = db.port_create(network_id)
port_id = port['uuid']
cli.show_port(self.client, self.tenant_id, network_id, port_id)
except:
LOG.exception("Exception caught: %s", sys.exc_info())
self.fail("test_show_port_no_attach failed due to an exception")
LOG.debug("Operation completed. Verifying result")
LOG.debug(self.fake_stdout.content)
self._verify_show_port(network_id, port_id)
def test_show_port_with_attach(self):
network_id = None
port_id = None
iface_id = "flavor crystals"
try:
# Pre-populate data for testing using db api
net = db.network_create(self.tenant_id, self.network_name_1)
network_id = net['uuid']
port = db.port_create(network_id)
port_id = port['uuid']
db.port_set_attachment(port_id, network_id, iface_id)
cli.show_port(self.client, self.tenant_id, network_id, port_id)
except:
LOG.exception("Exception caught: %s", sys.exc_info())
self.fail("test_show_port_with_attach failed due to an exception")
LOG.debug("Operation completed. Verifying result")
LOG.debug(self.fake_stdout.content)
self._verify_show_port(network_id, port_id)
def test_plug_iface(self):
network_id = None
port_id = None
try:
# Load some data into the datbase
net = db.network_create(self.tenant_id, self.network_name_1)
network_id = net['uuid']
port = db.port_create(net['uuid'])
port_id = port['uuid']
cli.plug_iface(self.client, self.tenant_id, network_id,
port_id, "test_iface_id")
except:
LOG.exception("Exception caught: %s", sys.exc_info())
self.fail("test_plug_iface failed due to an exception")
LOG.debug("Operation completed. Verifying result")
LOG.debug(self.fake_stdout.content)
self._verify_plug_iface(network_id, port_id)
def test_unplug_iface(self):
network_id = None
port_id = None
try:
# Load some data into the datbase
net = db.network_create(self.tenant_id, self.network_name_1)
network_id = net['uuid']
port = db.port_create(net['uuid'])
port_id = port['uuid']
db.port_set_attachment(port_id, network_id, "test_iface_id")
cli.unplug_iface(self.client, self.tenant_id, network_id, port_id)
except:
LOG.exception("Exception caught: %s", sys.exc_info())
self.fail("test_plug_iface failed due to an exception")
LOG.debug("Operation completed. Verifying result")
LOG.debug(self.fake_stdout.content)
self._verify_unplug_iface(network_id, port_id)

View File

@ -69,7 +69,6 @@ class ResourceExtensionTest(unittest.TestCase):
res_ext = extensions.ResourceExtension('tweedles',
self.ResourceExtensionController())
test_app = setup_extensions_test_app(SimpleExtensionManager(res_ext))
index_response = test_app.get("/tweedles")
self.assertEqual(200, index_response.status_int)
self.assertEqual("resource index", index_response.body)

View File

@ -1,5 +1,6 @@
eventlet>=0.9.12
Routes>=1.12.3
Cheetah>=2.0.1
nose
Paste
PasteDeploy