merge trunk
This commit is contained in:
commit
fff680ee63
165
bin/cli
Executable file
165
bin/cli
Executable 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)
|
56
extensions/_credential_view.py
Normal file
56
extensions/_credential_view.py
Normal 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']))
|
47
extensions/_novatenant_view.py
Normal file
47
extensions/_novatenant_view.py
Normal 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
62
extensions/_pprofiles.py
Normal 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
56
extensions/_qos_view.py
Normal 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
166
extensions/credential.py
Normal 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
140
extensions/novatenant.py
Normal 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
218
extensions/portprofile.py
Normal 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
164
extensions/qos.py
Normal 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))
|
@ -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()
|
||||
|
@ -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
|
||||
"""
|
||||
|
@ -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
|
||||
"""
|
||||
|
392
quantum/cli.py
392
quantum/cli.py
@ -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
228
quantum/cli_lib.py
Executable 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)
|
56
quantum/cli_output.template
Normal file
56
quantum/cli_output.template
Normal 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
|
||||
|
@ -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})
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
------------------------------------------------
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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")
|
||||
|
148
quantum/plugins/cisco/common/cisco_faults.py
Normal file
148
quantum/plugins/cisco/common/cisco_faults.py
Normal 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.')
|
@ -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
|
||||
|
||||
|
24
quantum/plugins/cisco/conf/quantum.conf.ciscoext
Normal file
24
quantum/plugins/cisco/conf/quantum.conf.ciscoext
Normal 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
|
@ -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).\
|
||||
|
93
quantum/plugins/cisco/db/nexus_db.py
Normal file
93
quantum/plugins/cisco/db/nexus_db.py
Normal 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()
|
38
quantum/plugins/cisco/db/nexus_models.py
Normal file
38
quantum/plugins/cisco/db/nexus_models.py
Normal 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)
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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']
|
||||
|
@ -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']
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
964
quantum/plugins/cisco/tests/unit/test_cisco_extension.py
Normal file
964
quantum/plugins/cisco/tests/unit/test_cisco_extension.py
Normal 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
|
@ -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):
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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(
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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")
|
||||
|
15
tests/unit/client_tools/__init__.py
Normal file
15
tests/unit/client_tools/__init__.py
Normal 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.
|
65
tests/unit/client_tools/stubs.py
Normal file
65
tests/unit/client_tools/stubs.py
Normal 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
|
@ -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
420
tests/unit/test_cli.py
Normal 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)
|
@ -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)
|
||||
|
@ -1,5 +1,6 @@
|
||||
eventlet>=0.9.12
|
||||
Routes>=1.12.3
|
||||
Cheetah>=2.0.1
|
||||
nose
|
||||
Paste
|
||||
PasteDeploy
|
||||
|
Loading…
x
Reference in New Issue
Block a user