From de4177e2614db8b02f98b71298403f7218ff399a Mon Sep 17 00:00:00 2001 From: Salvatore Orlando Date: Wed, 10 Aug 2011 18:22:17 +0100 Subject: [PATCH 01/52] skeleton for cli unit tests --- tests/unit/test_cli.py | 41 +++++++++++++++++++++++++++++++++++++++++ tools/pip-requires | 1 + 2 files changed, 42 insertions(+) create mode 100644 tests/unit/test_cli.py diff --git a/tests/unit/test_cli.py b/tests/unit/test_cli.py new file mode 100644 index 0000000000..b662d6715d --- /dev/null +++ b/tests/unit/test_cli.py @@ -0,0 +1,41 @@ +# 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 + +LOG = logging.getLogger('quantum.tests.test_cli') + +class CLITest(unittest.TestCase): + + def setUp(self): + """Prepare the test environment""" + pass + + def tearDown(self): + """Clear the test environment""" + pass diff --git a/tools/pip-requires b/tools/pip-requires index fc1b29f9fd..931a350433 100644 --- a/tools/pip-requires +++ b/tools/pip-requires @@ -1,5 +1,6 @@ eventlet>=0.9.12 Routes>=1.12.3 +mox==0.5.3 nose Paste PasteDeploy From 4898f5b7a8c8b45201c620021a13fb3f8221ce72 Mon Sep 17 00:00:00 2001 From: Salvatore Orlando Date: Thu, 11 Aug 2011 00:52:15 +0100 Subject: [PATCH 02/52] Stubout work in progress --- quantum/client.py | 11 ++++++++-- tests/unit/client_tools/stubs.py | 37 ++++++++++++++++++++++++++++++++ tests/unit/test_cli.py | 18 ++++++++++++++++ 3 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 tests/unit/client_tools/stubs.py diff --git a/quantum/client.py b/quantum/client.py index ca05236faa..3bc04ec452 100644 --- a/quantum/client.py +++ b/quantum/client.py @@ -19,6 +19,7 @@ import httplib import socket import urllib + from quantum.common.wsgi import Serializer @@ -91,6 +92,13 @@ 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 + conn.request(method, action, body, headers) + return conn.getresponse() + + def do_request(self, method, action, body=None, headers=None, params=None): """ @@ -132,8 +140,7 @@ class Client(object): else: c = connection_type(self.host, self.port) - c.request(method, action, body, headers) - res = c.getresponse() + res = self._send_request(c, method, action, body, headers) status_code = self.get_status_code(res) if status_code in (httplib.OK, httplib.CREATED, diff --git a/tests/unit/client_tools/stubs.py b/tests/unit/client_tools/stubs.py new file mode 100644 index 0000000000..04a2e3cc4c --- /dev/null +++ b/tests/unit/client_tools/stubs.py @@ -0,0 +1,37 @@ +# 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 client +from tests.unit import testlib_api + + +def stubout_send_request(stubs, api): + """Simulates a failure in fetch image_glance_disk.""" + + def fake_send_request(self, conn, method, action, body, headers): + # ignore headers and connection + req = testlib_api.create_request(action, body, + "application/json", method) + res = req.get_response(api) + return res + + stubs.Set(client.Client, '_send_request', fake_send_request) + +class FakeHTTPConnection: + """ stub HTTP connection class for CLI testing """ + pass diff --git a/tests/unit/test_cli.py b/tests/unit/test_cli.py index b662d6715d..d772ed32d7 100644 --- a/tests/unit/test_cli.py +++ b/tests/unit/test_cli.py @@ -23,10 +23,14 @@ import logging +import stubout import sys import unittest from quantum import api as server +from quantum import cli +from quantum.db import api as db +from tests.unit.client_tools import stubs as client_stubs LOG = logging.getLogger('quantum.tests.test_cli') @@ -34,8 +38,22 @@ 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" + # Stubout do_request + self.stubs = stubout.StubOutForTesting() + client_stubs.stubout_send_request(self.stubs, self.api) + # Redirect stdout + # Pre-populate data pass def tearDown(self): """Clear the test environment""" + db.clear_db() + + def test_list_networks_api(self): pass From 1dbd3f67b9e58fb52b6d559f637a46baf332e4ee Mon Sep 17 00:00:00 2001 From: Salvatore Orlando Date: Thu, 11 Aug 2011 00:59:00 +0100 Subject: [PATCH 03/52] I'm too tired --- tests/unit/test_cli.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/unit/test_cli.py b/tests/unit/test_cli.py index d772ed32d7..341c3a81ab 100644 --- a/tests/unit/test_cli.py +++ b/tests/unit/test_cli.py @@ -29,6 +29,7 @@ import unittest from quantum import api as server from quantum import cli +from quantum.client import Client from quantum.db import api as db from tests.unit.client_tools import stubs as client_stubs @@ -41,6 +42,9 @@ class CLITest(unittest.TestCase): options = {} options['plugin_provider'] = 'quantum.plugins.SamplePlugin.FakePlugin' self.api = server.APIRouterV01(options) + #self.client = Client("host", "port", False, + # args[0], FORMAT) + self.tenant_id = "test_tenant" self.network_name_1 = "test_network_1" self.network_name_2 = "test_network_2" @@ -56,4 +60,5 @@ class CLITest(unittest.TestCase): db.clear_db() def test_list_networks_api(self): + cli.api_list_nets(client) pass From 512af84eeea381b57d1556d997fee284151141d6 Mon Sep 17 00:00:00 2001 From: Salvatore Orlando Date: Thu, 11 Aug 2011 16:29:56 +0100 Subject: [PATCH 04/52] Introducting cheetah Updating list_nets in CLI Writing unit tests for list_nets Stubbing out with FakeConnection now --- quantum/api/views/networks.py | 2 +- quantum/api/views/ports.py | 2 +- quantum/cli.py | 39 +++++++++++++---------- tests/unit/client_tools/stubs.py | 47 +++++++++++++++++++++++++-- tests/unit/test_cli.py | 54 ++++++++++++++++++++++++++------ tools/pip-requires | 1 + 6 files changed, 115 insertions(+), 30 deletions(-) diff --git a/quantum/api/views/networks.py b/quantum/api/views/networks.py index eaa9901ff9..2691c8ffea 100644 --- a/quantum/api/views/networks.py +++ b/quantum/api/views/networks.py @@ -25,7 +25,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 """ diff --git a/quantum/api/views/ports.py b/quantum/api/views/ports.py index b743888ce3..baeabc8498 100644 --- a/quantum/api/views/ports.py +++ b/quantum/api/views/ports.py @@ -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 """ diff --git a/quantum/cli.py b/quantum/cli.py index a015565d87..091daf2cac 100644 --- a/quantum/cli.py +++ b/quantum/cli.py @@ -17,6 +17,7 @@ # @author: Somik Behera, Nicira Networks, Inc. # @author: Brad Hall, Nicira Networks, Inc. +import Cheetah.Template as cheetah_template import httplib import logging as LOG import json @@ -24,36 +25,43 @@ import socket import sys import urllib +from client import Client from manager import QuantumManager from optparse import OptionParser -from client import Client +from quantum.api.views.networks import ViewBuilder as NetworkBuilder +from quantum.api.views.ports import ViewBuilder as PortBuilder FORMAT = "json" +CLI_TEMPLATE = "../quantum/cli_output.template" ### -- Core CLI functions +def prepare_output(cmd, tenant_id, response): + #add command and tenant to response for output generation + response['cmd'] = cmd + response['tenant_id'] = tenant_id + template_file = open(CLI_TEMPLATE).read() + output = str(cheetah_template.Template(template_file, + searchList=response)) + return output + 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) + builder=NetworkBuilder() + nw_list = [builder.build(network, net_detail=True, port_detail=False)['network'] + for network in networks] + res = dict(networks=nw_list) + output = prepare_output("list_nets", tenant_id, res) + print output 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)) + output = prepare_output("list_nets", tenant_id, res) + print output def create_net(manager, *args): @@ -310,7 +318,6 @@ commands = { "api_func": api_unplug_iface, "args": ["tenant-id", "net-id", "port-id"]}, } - def help(): print "\nCommands:" for k in commands.keys(): @@ -386,6 +393,6 @@ if __name__ == "__main__": commands[cmd]["api_func"](client, *args) else: quantum = QuantumManager() - manager = quantum.get_manager() + manager = quantum.get_plugin() commands[cmd]["func"](manager, *args) sys.exit(0) diff --git a/tests/unit/client_tools/stubs.py b/tests/unit/client_tools/stubs.py index 04a2e3cc4c..df327b51d4 100644 --- a/tests/unit/client_tools/stubs.py +++ b/tests/unit/client_tools/stubs.py @@ -16,6 +16,7 @@ """ Stubs for client tools unit tests """ +from quantum import api as server from quantum import client from tests.unit import testlib_api @@ -24,14 +25,56 @@ def stubout_send_request(stubs, api): """Simulates a failure in fetch image_glance_disk.""" def fake_send_request(self, conn, method, action, body, headers): - # ignore headers and connection + # ignore headers and connection req = testlib_api.create_request(action, body, "application/json", method) res = req.get_response(api) return res stubs.Set(client.Client, '_send_request', fake_send_request) + +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 """ - pass + 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 macking a webob.Response look like a + httplib.Response + + """ + return res.body + + setattr(res, 'read', _fake_read) + return res + diff --git a/tests/unit/test_cli.py b/tests/unit/test_cli.py index 341c3a81ab..838bdcb10b 100644 --- a/tests/unit/test_cli.py +++ b/tests/unit/test_cli.py @@ -23,7 +23,6 @@ import logging -import stubout import sys import unittest @@ -31,9 +30,11 @@ from quantum import api as server from quantum import cli from quantum.client import Client from quantum.db import api as db +from quantum.manager import QuantumManager from tests.unit.client_tools import stubs as client_stubs LOG = logging.getLogger('quantum.tests.test_cli') +FORMAT = 'json' class CLITest(unittest.TestCase): @@ -42,23 +43,56 @@ class CLITest(unittest.TestCase): options = {} options['plugin_provider'] = 'quantum.plugins.SamplePlugin.FakePlugin' self.api = server.APIRouterV01(options) - #self.client = Client("host", "port", False, - # args[0], FORMAT) self.tenant_id = "test_tenant" self.network_name_1 = "test_network_1" self.network_name_2 = "test_network_2" - # Stubout do_request - self.stubs = stubout.StubOutForTesting() - client_stubs.stubout_send_request(self.stubs, self.api) + # Prepare client and plugin manager + self.client = Client(tenant = self.tenant_id, format = FORMAT, + testingStub = client_stubs.FakeHTTPConnection) + self.manager = QuantumManager(options).get_plugin() # Redirect stdout - # Pre-populate data - pass + self.fake_stdout = client_stubs.FakeStdout() + sys.stdout = self.fake_stdout + # 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) 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 test_list_networks(self): + try: + cli.list_nets(self.manager, self.tenant_id) + LOG.debug("Operation completed. Verifying result") + LOG.debug(self.fake_stdout.content) + self._verify_list_networks() + except: + LOG.exception("Exception caught: %s", sys.exc_info()) + self.fail("test_list_network_api failed due to an exception") + + def test_list_networks_api(self): - cli.api_list_nets(client) - pass + try: + cli.api_list_nets(self.client, self.tenant_id) + LOG.debug("Operation completed. Verifying result") + LOG.debug(self.fake_stdout.content) + self._verify_list_networks() + except: + LOG.exception("Exception caught: %s", sys.exc_info()) + self.fail("test_list_network_api failed due to an exception") + diff --git a/tools/pip-requires b/tools/pip-requires index 931a350433..1f5813373d 100644 --- a/tools/pip-requires +++ b/tools/pip-requires @@ -1,5 +1,6 @@ eventlet>=0.9.12 Routes>=1.12.3 +Cheetah>=2.0.1 mox==0.5.3 nose Paste From 5fdf286bce4a94fdb60051eb37242c8b4f658b1e Mon Sep 17 00:00:00 2001 From: Salvatore Orlando Date: Fri, 12 Aug 2011 00:01:09 +0100 Subject: [PATCH 05/52] Adding missing files to branch --- quantum/cli_output.template | 8 ++++++++ tests/unit/client_tools/__init__.py | 15 +++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 quantum/cli_output.template create mode 100644 tests/unit/client_tools/__init__.py diff --git a/quantum/cli_output.template b/quantum/cli_output.template new file mode 100644 index 0000000000..02faf06afd --- /dev/null +++ b/quantum/cli_output.template @@ -0,0 +1,8 @@ +## Cheetah template for cli output +#if $cmd == 'list_nets' +Virtual Networks on Tenant $tenant_id +#for $network in $networks +\tNetwork ID: $network.id +#end for +#end if + diff --git a/tests/unit/client_tools/__init__.py b/tests/unit/client_tools/__init__.py new file mode 100644 index 0000000000..bafb9e291f --- /dev/null +++ b/tests/unit/client_tools/__init__.py @@ -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. \ No newline at end of file From f52588c0409132435489226e8682e9b848394457 Mon Sep 17 00:00:00 2001 From: Salvatore Orlando Date: Fri, 12 Aug 2011 01:02:12 +0100 Subject: [PATCH 06/52] Adding more templates More tests Small change in client to return error details in exception upon API failure --- quantum/cli.py | 56 ++++++++++++++++++++++--------------- quantum/cli_output.template | 4 +++ quantum/client.py | 4 ++- tests/unit/test_cli.py | 46 +++++++++++++++++++++++++++--- 4 files changed, 83 insertions(+), 27 deletions(-) diff --git a/quantum/cli.py b/quantum/cli.py index 091daf2cac..df4b71cd29 100644 --- a/quantum/cli.py +++ b/quantum/cli.py @@ -33,11 +33,10 @@ from quantum.api.views.ports import ViewBuilder as PortBuilder FORMAT = "json" CLI_TEMPLATE = "../quantum/cli_output.template" - -### -- Core CLI functions - +#TODO(salvatore-orlando): do proper logging! def prepare_output(cmd, tenant_id, response): + """ Fills a cheetah template with the response """ #add command and tenant to response for output generation response['cmd'] = cmd response['tenant_id'] = tenant_id @@ -65,37 +64,50 @@ def api_list_nets(client, *args): 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 + tenant_id, name = args + new_net_id = manager.create_network(tenant_id, name)['net-id'] + output = prepare_output("create_net", tenant_id, + dict(network_id=new_net_id)) + print output 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 + tenant_id, name = args + data = {'network': {'net-name': name}} + new_net_id = None try: - nid = res["networks"]["network"]["id"] - except Exception, e: - print "Failed to create network" - # TODO(bgh): grab error details from ws request result + res = client.create_network(data) + new_net_id = res["networks"]["network"]["id"] + except Exception as ex: + 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) + print "Failed to create network: %s" % status_code or '' + print "Error message:%s" % message or '' return - print "Created a new Virtual Network with ID:%s\n" % nid + output = prepare_output("create_net", tenant_id, + dict(network_id=new_net_id)) + print output def delete_net(manager, *args): - tid, nid = args - manager.delete_network(tid, nid) - print "Deleted Virtual Network with ID:%s" % nid + tenant_id, network_id = args + manager.delete_network(tenant_id, network_id) + output = prepare_output("delete_net", tenant_id, + dict(network_id=network_id)) + print output def api_delete_net(client, *args): - tid, nid = args + tenant_id, network_id = args try: - res = client.delete_network(nid) - print "Deleted Virtual Network with ID:%s" % nid + client.delete_network(network_id) + output = prepare_output("delete_net", tenant_id, + dict(network_id=network_id)) + print output except Exception, e: print "Failed to delete network" LOG.error("Failed to delete network: %s" % e) diff --git a/quantum/cli_output.template b/quantum/cli_output.template index 02faf06afd..2bbeb8721f 100644 --- a/quantum/cli_output.template +++ b/quantum/cli_output.template @@ -4,5 +4,9 @@ Virtual Networks on Tenant $tenant_id #for $network in $networks \tNetwork 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 #end if diff --git a/quantum/client.py b/quantum/client.py index 3bc04ec452..d993d68e66 100644 --- a/quantum/client.py +++ b/quantum/client.py @@ -148,7 +148,9 @@ class Client(object): httplib.NO_CONTENT): return self.deserialize(res) else: - raise Exception("Server returned error: %s" % res.read()) + ex = Exception("Server returned error: %s" % status_code) + ex.args = ([dict(status_code=status_code, message=res.read())],) + raise ex except (socket.error, IOError), e: raise Exception("Unable to connect to " diff --git a/tests/unit/test_cli.py b/tests/unit/test_cli.py index 838bdcb10b..5b26debe59 100644 --- a/tests/unit/test_cli.py +++ b/tests/unit/test_cli.py @@ -54,9 +54,6 @@ class CLITest(unittest.TestCase): # Redirect stdout self.fake_stdout = client_stubs.FakeStdout() sys.stdout = self.fake_stdout - # 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) def tearDown(self): """Clear the test environment""" @@ -74,20 +71,41 @@ class CLITest(unittest.TestCase): # 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 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.manager, self.tenant_id) LOG.debug("Operation completed. Verifying result") LOG.debug(self.fake_stdout.content) self._verify_list_networks() except: LOG.exception("Exception caught: %s", sys.exc_info()) - self.fail("test_list_network_api failed due to an exception") + self.fail("test_list_network failed due to an exception") def test_list_networks_api(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.api_list_nets(self.client, self.tenant_id) LOG.debug("Operation completed. Verifying result") LOG.debug(self.fake_stdout.content) @@ -96,3 +114,23 @@ class CLITest(unittest.TestCase): LOG.exception("Exception caught: %s", sys.exc_info()) self.fail("test_list_network_api failed due to an exception") + def test_create_network(self): + try: + cli.create_net(self.manager, self.tenant_id, "test") + LOG.debug("Operation completed. Verifying result") + LOG.debug(self.fake_stdout.content) + self._verify_create_network() + except: + LOG.exception("Exception caught: %s", sys.exc_info()) + self.fail("test_create_network failed due to an exception") + + + def test_create_network_api(self): + try: + cli.api_create_net(self.client, self.tenant_id, "test") + LOG.debug("Operation completed. Verifying result") + LOG.debug(self.fake_stdout.content) + self._verify_create_network() + except: + LOG.exception("Exception caught: %s", sys.exc_info()) + self.fail("test_create_network_api failed due to an exception") From a8def0e9fbeb053b6e36f0b0d7d00d66f2731ec3 Mon Sep 17 00:00:00 2001 From: Salvatore Orlando Date: Tue, 16 Aug 2011 00:23:46 +0100 Subject: [PATCH 07/52] Partial commit --- quantum/cli.py | 24 ++++++++++-------- quantum/cli_output.template | 6 +++++ tests/unit/test_cli.py | 50 ++++++++++++++++++++++++++++++++++++- 3 files changed, 68 insertions(+), 12 deletions(-) diff --git a/quantum/cli.py b/quantum/cli.py index df4b71cd29..fa326d9d42 100644 --- a/quantum/cli.py +++ b/quantum/cli.py @@ -116,33 +116,35 @@ def api_delete_net(client, *args): def detail_net(manager, *args): tid, nid = args iface_list = manager.get_network_details(tid, nid) + output = prepare_output("detail_net", tenant_id, + dict(network=iface_list)) + #TODO(salvatore-orlando): delete here 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 + tenant_id, network_id = args try: - res = client.list_network_details(nid)["networks"]["network"] + res = client.list_network_details(network_id)["networks"]["network"] except Exception, e: LOG.error("Failed to get network details: %s" % e) return - try: - ports = client.list_ports(nid) + ports = client.list_ports(network_id) 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 + res['ports'] = ports for port in ports["ports"]: - pid = port["id"] - res = client.list_port_attachments(nid, pid) - LOG.debug(res) - remote_iface = res["attachment"] - print "\tRemote interface:%s" % remote_iface + att_data = client.list_port_attachments(network_id, port['id']) + port['attachment'] = att_data["attachment"] + + output = prepare_output("detail_net", tenant_id, + dict(network=res)) + print output def rename_net(manager, *args): diff --git a/quantum/cli_output.template b/quantum/cli_output.template index 2bbeb8721f..0c9084010d 100644 --- a/quantum/cli_output.template +++ b/quantum/cli_output.template @@ -8,5 +8,11 @@ Virtual Networks on Tenant $tenant_id 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 == 'detail_net' +Network $network.name ($network.id) +Remote Interfaces on Virtual Network +#for $port in $network.port +Port $port.id: $port.attachment +#end for #end if diff --git a/tests/unit/test_cli.py b/tests/unit/test_cli.py index 5b26debe59..47b7d97a03 100644 --- a/tests/unit/test_cli.py +++ b/tests/unit/test_cli.py @@ -84,6 +84,18 @@ class CLITest(unittest.TestCase): # 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 test_list_networks(self): try: @@ -123,7 +135,6 @@ class CLITest(unittest.TestCase): except: LOG.exception("Exception caught: %s", sys.exc_info()) self.fail("test_create_network failed due to an exception") - def test_create_network_api(self): try: @@ -134,3 +145,40 @@ class CLITest(unittest.TestCase): except: LOG.exception("Exception caught: %s", sys.exc_info()) self.fail("test_create_network_api failed due to an exception") + + def _prepare_test_delete_network(self): + # Pre-populate data for testing using db api + db.network_create(self.tenant_id, self.network_name_1) + net_id = db.network_list(self.tenant_id)[0]['uuid'] + return net_id + + def test_delete_network(self): + try: + network_id = self._prepare_test_delete_network() + cli.delete_net(self.manager, self.tenant_id, network_id) + LOG.debug("Operation completed. Verifying result") + LOG.debug(self.fake_stdout.content) + self._verify_delete_network(network_id) + except: + LOG.exception("Exception caught: %s", sys.exc_info()) + self.fail("test_delete_network failed due to an exception") + + + def test_delete_network_api(self): + try: + network_id = self._prepare_test_delete_network() + cli.api_delete_net(self.client, self.tenant_id, network_id) + LOG.debug("Operation completed. Verifying result") + LOG.debug(self.fake_stdout.content) + self._verify_delete_network(network_id) + except: + LOG.exception("Exception caught: %s", sys.exc_info()) + self.fail("test_delete_network_api failed due to an exception") + + def test_detail_network_api(self): + # Load some data into the datbase + net = db.network_create(self.tenant_id, self.network_name_1) + db.port_create(net['uuid']) + port = db.port_create(net['uuid']) + cli.api_detail_net(self.client, self.tenant_id, net['uuid']) + db.port_set_attachment(port['uuid'], net['uuid'], "test_iface_id") \ No newline at end of file From 74837113e60007fcca498c2479039ac592557e65 Mon Sep 17 00:00:00 2001 From: Ying Liu Date: Wed, 17 Aug 2011 12:26:32 -0700 Subject: [PATCH 08/52] add extension change to ying's branch --- cisco_demo/demo_client.py | 385 ++++++++++++ cisco_demo/demo_client.py.bk | 127 ++++ cisco_demo/test_client.py | 83 +++ extensions/_credential_view.py | 35 ++ extensions/_exceptions.py | 160 +++++ extensions/_faults.py | 157 +++++ extensions/_novatenant_view.py | 28 + extensions/_pprofiles.py | 40 ++ extensions/_qos_view.py | 35 ++ extensions/credential.py | 159 +++++ extensions/novatenant.py | 161 +++++ extensions/portprofile.py | 207 +++++++ extensions/qos.py | 154 +++++ quantum/plugins.ini | 5 +- quantum/plugins/cisco/CiscoPlugin.py | 562 ++++++++++++++++++ quantum/plugins/cisco/conf/db_conn.ini | 6 +- .../plugins/cisco/conf/l2network_plugin.ini | 4 +- quantum/plugins/cisco/conf/plugins.ini | 2 +- test_scripts/__init__.py | 0 test_scripts/miniclient.py | 98 +++ test_scripts/tests.py | 150 +++++ 21 files changed, 2550 insertions(+), 8 deletions(-) create mode 100755 cisco_demo/demo_client.py create mode 100755 cisco_demo/demo_client.py.bk create mode 100644 cisco_demo/test_client.py create mode 100644 extensions/_credential_view.py create mode 100644 extensions/_exceptions.py create mode 100644 extensions/_faults.py create mode 100644 extensions/_novatenant_view.py create mode 100644 extensions/_pprofiles.py create mode 100644 extensions/_qos_view.py create mode 100644 extensions/credential.py create mode 100644 extensions/novatenant.py create mode 100644 extensions/portprofile.py create mode 100644 extensions/qos.py create mode 100644 quantum/plugins/cisco/CiscoPlugin.py create mode 100644 test_scripts/__init__.py create mode 100644 test_scripts/miniclient.py create mode 100644 test_scripts/tests.py diff --git a/cisco_demo/demo_client.py b/cisco_demo/demo_client.py new file mode 100755 index 0000000000..74b4a6a7a0 --- /dev/null +++ b/cisco_demo/demo_client.py @@ -0,0 +1,385 @@ + +import os +import sys + +import gettext + +#gettext.install('quantum', unicode=1) +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 test_scripts.miniclient import MiniClient +from test_client import ExtClient +from quantum.common.wsgi import Serializer + +HOST = '127.0.0.1' +PORT = 9696 +USE_SSL = False +TENANT_ID = 'ucs_user' + + +test_network_data = \ + {'network': {'net-name': 'cisco_test_network', + 'valn-id': 28}} +test_portprofile_data = \ + {'portprofile': {'portprofile_name': 'cisco_test_portprofile', + 'qos_name': 2, + 'qos_name': 'test-qos'}} +test_cred_data = \ + {'credential': {'credential_name': 'cred3', + 'user_name': 'newUser', + 'password': 'newPasswd' + }} +test_qos_data = \ + {'qos': {'qos_name': 'plantimum', + 'qos_desc': {'PPS': 50, 'TTL': 5}}} + + +#we put this assignment under portprofile resources +#therefore we need to create such a test data +test_port_assign_data = {'portprofile': {'network-id': '001', + 'port-id': '1'}} +test_attach_data = {'port': {'attachment-id': 'v01'}} + +test_act_data = {"get_available_host":123} + +test_instance_data={'novatenant':{'instance_id' : 1, + 'instance_desc' : {'key1' : '1', + 'key2' : '2' + }}} + +def test_get_host(format='json'): + client = ExtClient(HOST, PORT, USE_SSL) + content_type = "application/" + format + body = Serializer().serialize(test_instance_data, content_type) + res = client.do_request(TENANT_ID, + 'PUT', "/novatenants/001/get_host." + format, body=body) + print "XML Response" + print_response(res) + print "COMPLETED" + print "----------------------------" + +def test_get_instance_port(format='json'): + client = ExtClient(HOST, PORT, USE_SSL) + content_type = "application/" + format + body = Serializer().serialize(test_instance_data, content_type) + res = client.do_request(TENANT_ID, + 'PUT', "/novatenants/001/get_instance_port." + format, body=body) + print "XML Response" + print_response(res) + print "COMPLETED" + print "----------------------------" + +def test_action_ext(format='json'): + client = ExtClient(HOST, PORT, USE_SSL) + content_type = "application/" + format + action_name = 'get_available_host' + action_params = dict(name='test') + body = Serializer().serialize(test_act_data, content_type) + + + res = client.do_request(TENANT_ID, 'POST', "/act_resources/1/action." + format, body=body) + content = print_response(res) + +def print_response(res): + content = res.read() + print "Status: %s" % res.status + print "Content: %s" % content + return content + + +def create_cisco_network(format='xml'): + + client = MiniClient(HOST, PORT, USE_SSL) + print "CREATE NETWORK -- FORMAT:%s" % format + print "----------------------------" + content_type = "application/" + format + body = Serializer().serialize(test_network_data, content_type) + res = client.do_request(TENANT_ID, + 'POST', "/networks." + format, body=body) + print "XML Response" + print_response(res) + print "COMPLETED" + print "----------------------------" + + +def create_cisco_portprofile(format='xml'): + client = ExtClient(HOST, PORT, USE_SSL) + content_type = "application/" + format + print "List all Profile -- FORMat%s" % format + print "----------------------------" + res = client.do_request(TENANT_ID, 'GET', "/portprofiles." + format) + content = print_response(res) + portprofile_data = Serializer().deserialize(content, content_type) + print portprofile_data + + print "List a specific Profile -- FORMAT:%s" % format + profile_id = portprofile_data['portprofiles'][0]['id'] + #profile_id='001' + print "profile_id " + profile_id + res = client.do_request(TENANT_ID, + 'GET', "/portprofiles/" + + profile_id + "." + format) + print_response(res) + + print "CREATE Profile -- FORMAT:%s" % format + print "----------------------------" + content_type = "application/" + format + body = Serializer().serialize(test_portprofile_data, content_type) + print "***BODY is " + print body + res = client.do_request(TENANT_ID, 'POST', + "/portprofiles." + format, body=body) + print "XML Response" + print_response(res) + print "COMPLETED" + print "----------------------------" + +def test_credential (format='xml'): + client = ExtClient(HOST, PORT, USE_SSL) + content_type = "application/" + format + print "----------------------------" + print "List all credentials -- FORMat%s" % format + print "----------------------------" + res = client.do_request(TENANT_ID, 'GET', "/credentials." + format) + content = print_response(res) + credential_data = Serializer().deserialize(content, content_type) + print credential_data + + print "----------------------------" + print "CREATE Credential -- FORMAT:%s" % format + print "----------------------------" + content_type = "application/" + format + body = Serializer().serialize(test_cred_data, content_type) + print "***BODY is " + print body + res = client.do_request(TENANT_ID, 'POST', + "/credentials." + format, body=body) + print "XML Response" + print_response(res) + + print "----------------------------" + print "List all credentials -- FORMat%s" % format + print "----------------------------" + res = client.do_request(TENANT_ID, 'GET', "/credentials." + format) + content = print_response(res) + credential_data = Serializer().deserialize(content, content_type) + print credential_data + print "----------------------------" + print "List a specific cred -- FORMAT:%s" % format + print "----------------------------" + cred_id = credential_data['credentials'][0]['id'] + #cred_id='001' + print "cred_id " + cred_id + res = client.do_request(TENANT_ID, + 'GET', "/credentials/" + + cred_id + "." + format) + print_response(res) + + print "----------------------------" + print "TEST DELETE Credential -- FORMAT:%s" % format + print "----------------------------" + res = client.do_request(TENANT_ID, 'DELETE', + "/credentials/" + cred_id + "." + format) + print_response(res) + + print "----------------------------" + print "List all credentials -- FORMat%s" % format + print "----------------------------" + res = client.do_request(TENANT_ID, 'GET', "/credentials." + format) + content = print_response(res) + credential_data = Serializer().deserialize(content, content_type) + print credential_data + + print "COMPLETED" + print "----------------------------" + +def test_qos (format='xml'): + client = ExtClient(HOST, PORT, USE_SSL) + content_type = "application/" + format + print "----------------------------" + print "List all qoss -- FORMat%s" % format + print "----------------------------" + res = client.do_request(TENANT_ID, 'GET', "/qoss." + format) + content = print_response(res) + qos_data = Serializer().deserialize(content, content_type) + print qos_data + + print "----------------------------" + print "CREATE qos -- FORMAT:%s" % format + print "----------------------------" + content_type = "application/" + format + body = Serializer().serialize(test_qos_data, content_type) + print "***BODY is " + print body + res = client.do_request(TENANT_ID, 'POST', + "/qoss." + format, body=body) + print "XML Response" + print_response(res) + + print "----------------------------" + print "List all qoss -- FORMat%s" % format + print "----------------------------" + res = client.do_request(TENANT_ID, 'GET', "/qoss." + format) + content = print_response(res) + qos_data = Serializer().deserialize(content, content_type) + print qos_data + print "----------------------------" + print "List a specific cred -- FORMAT:%s" % format + print "----------------------------" + qos_id = qos_data['qoss'][0]['id'] + #cred_id='001' + print "qos_id " + qos_id + res = client.do_request(TENANT_ID, + 'GET', "/qoss/" + + qos_id + "." + format) + print_response(res) + + print "----------------------------" + print "TEST DELETE qos -- FORMAT:%s" % format + print "----------------------------" + res = client.do_request(TENANT_ID, 'DELETE', + "/qoss/" + qos_id + "." + format) + print_response(res) + + print "----------------------------" + print "List all qoss -- FORMat%s" % format + print "----------------------------" + res = client.do_request(TENANT_ID, 'GET', "/qoss." + format) + content = print_response(res) + qos_data = Serializer().deserialize(content, content_type) + print qos_data + + print "COMPLETED" + print "----------------------------" + +def test_delete_network(format='xml'): + client = MiniClient(HOST, PORT, USE_SSL) + content_type = "application/" + format + print "TEST DELETE NETWORK -- FORMAT:%s" % format + print "----------------------------" + print "--> Step 1 - List All Networks" + res = client.do_request(TENANT_ID, 'GET', "/networks." + format) + content = print_response(res) + network_data = Serializer().deserialize(content, content_type) + print network_data + net_id = network_data['networks'][0]['id'] + print "--> Step 2 - Delete network %s" % net_id + res = client.do_request(TENANT_ID, 'DELETE', + "/networks/" + net_id + "." + format) + print_response(res) + print "--> Step 3 - List All Networks (Again)" + res = client.do_request(TENANT_ID, 'GET', "/networks." + format) + print_response(res) + print "COMPLETED" + print "----------------------------" + + +def test_delete_portprofile(format='xml'): + client = ExtClient(HOST, PORT, USE_SSL) + content_type = "application/" + format + print "TEST DELETE PROFILE -- FORMAT:%s" % format + print "----------------------------" + print "--> Step 1 - List All Profiles" + res = client.do_request(TENANT_ID, 'GET', "/portprofiles." + format) + content = print_response(res) + portprofile_data = Serializer().deserialize(content, content_type) + print portprofile_data + profile_id = portprofile_data['portprofiles'][0]['id'] + print "--> Step 2 - Delete portprofile %s" % profile_id + res = client.do_request(TENANT_ID, 'DELETE', + "/portprofiles/" + profile_id + "." + format) + print_response(res) + print "--> Step 3 - List All Profiles (Again)" + res = client.do_request(TENANT_ID, 'GET', "/portprofiles." + format) + print_response(res) + print "COMPLETED" + print "----------------------------" + + +def test_create_port(format='xml'): + client = MiniClient(HOST, PORT, USE_SSL) + print "TEST CREATE PORT -- FORMAT:%s" % format + print "----------------------------" + print "--> Step 1 - List Ports for network 001" + res = client.do_request(TENANT_ID, 'GET', "/networks/001/ports." + format) + print_response(res) + print "--> Step 2 - Create Port for network 001" + res = client.do_request(TENANT_ID, 'POST', "/networks/001/ports." + format) + print_response(res) + print "--> Step 3 - List Ports for network 001 (again)" + res = client.do_request(TENANT_ID, 'GET', "/networks/001/ports." + format) + print_response(res) + print "COMPLETED" + print "----------------------------" + + +#assuming network 001 and ports 1 are created in the plug-in +def test_attach_resource(format='xml'): + client = MiniClient(HOST, PORT, USE_SSL) + print "TEST attach resources to port" + content_type = "application/" + format + body = Serializer().serialize(test_attach_data, content_type) + #attach virtual interface to the port + res = client.do_request(TENANT_ID, 'PUT', + "/networks/001/ports/1/attachment." + + format, body=body) + print_response(res) + #list existing interface of the port + res = client.do_request(TENANT_ID, 'GET', + "/networks/001/ports/1/attachment." + format) + print_response(res) + #de_attach virtual interface from the port + res = client.do_request(TENANT_ID, 'DELETE', + "/networks/001/ports/1/attachment." + format) + print_response(res) + #list existing interface of the port + res = client.do_request(TENANT_ID, 'GET', + "/networks/001/ports/1/attachment." + format) + print_response(res) + + +#assuming network 001, ports 1 and portprofile 002 are created in the plug-in +def test_assign_portprofile(format='xml'): + client = ExtClient(HOST, PORT, USE_SSL) + print "TEST attach resources to port" + content_type = "application/" + format + body = Serializer().serialize(test_port_assign_data, content_type) + print "body is " + body + res = client.do_request(TENANT_ID, 'PUT', + "/portprofiles/001/associate_portprofile." + + format, body=body) + print_response(res) + res = client.do_request(TENANT_ID, 'POST', + "/portprofiles/001/disassociate_portprofile." + + format, body=body) + + print_response(res) + + +def main(): + create_cisco_portprofile('json') + test_attach_resource('json') + + test_delete_portprofile('json') + test_credential('json') + test_qos('json') + ##test_action_ext('json') + test_get_host('json') + test_get_instance_port('json') + + #create_cisco_network('json') + #test_create_port('json') + #create_cisco_portprofile('json') + #test_assign_portprofile('json') + pass + + +# Standard boilerplate to call the main() function. +if __name__ == '__main__': + main() diff --git a/cisco_demo/demo_client.py.bk b/cisco_demo/demo_client.py.bk new file mode 100755 index 0000000000..3c7c928d4b --- /dev/null +++ b/cisco_demo/demo_client.py.bk @@ -0,0 +1,127 @@ +''' +Created on Jun 08, 2011 + +@author: ying +''' + +import os +import sys + +import gettext + +#gettext.install('quantum', unicode=1) +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 test_scripts.miniclient import MiniClient +from quantum.common.wsgi import Serializer + +HOST = '127.0.0.1' +PORT = 9696 +USE_SSL = False +TENANT_ID = 'ucs_user' + +test_network_data = \ + {'network': {'network-name': 'cisco_test_network', + 'valn-id': 28 }} + +test_portprofile_data = \ + {'portprofile': {'portprofile-name': 'cisco_test_portprofile', + 'vlan-id': 28, + 'vlan-name': 'test-vlan' }} + +def print_response(res): + content = res.read() + print "Status: %s" %res.status + print "Content: %s" %content + return content + + +def create_cisco_network(format = 'xml'): + client = MiniClient(HOST, PORT, USE_SSL) + print "CREATE NETWORK -- FORMAT:%s" %format + print "----------------------------" + content_type = "application/" + format + body = Serializer().serialize(test_network_data, content_type) + res = client.do_request(TENANT_ID,'POST', "/networks." + format, body=body) + print "XML Response" + print_response(res) + print "COMPLETED" + print "----------------------------" + +def create_cisco_portprofile(format = 'xml'): + client = MiniClient(HOST, PORT, USE_SSL) + print "CREATE Profile -- FORMAT:%s" %format + print "----------------------------" + content_type = "application/" + format + body = Serializer().serialize(test_portprofile_data, content_type) + print "**********BODY is**********" + print body + print "***************************" + res = client.do_request(TENANT_ID,'POST', "/portprofiles." + format, body=body) + print "XML Response" + print_response(res) + print "COMPLETED" + print "----------------------------" + +def test_delete_network(format = 'xml'): + client = MiniClient(HOST, PORT, USE_SSL) + content_type = "application/" + format + print "TEST DELETE NETWORK -- FORMAT:%s" %format + print "----------------------------" + print "--> Step 1 - List All Networks" + res = client.do_request(TENANT_ID,'GET', "/networks." + format) + content = print_response(res) + network_data = Serializer().deserialize(content, content_type) + print network_data + net_id = network_data['networks'][0]['id'] + print "--> Step 2 - Delete network %s" %net_id + res = client.do_request(TENANT_ID,'DELETE', + "/networks/" + net_id + "." + format) + print_response(res) + print "--> Step 3 - List All Networks (Again)" + res = client.do_request(TENANT_ID,'GET', "/networks." + format) + print_response(res) + print "COMPLETED" + print "----------------------------" + + +def test_delete_portprofile(format = 'xml'): + client = MiniClient(HOST, PORT, USE_SSL) + content_type = "application/" + format + print "TEST DELETE PROFILE -- FORMAT:%s" %format + print "----------------------------" + print "--> Step 1 - List All Profiles" + res = client.do_request(TENANT_ID,'GET', "/portprofiles." + format) + content = print_response(res) + portprofile_data = Serializer().deserialize(content, content_type) + print portprofile_data + profile_id = portprofile_data['portprofiles'][0]['id'] + print "--> Step 2 - Delete portprofile %s" %profile_id + res = client.do_request(TENANT_ID,'DELETE', + "/portprofiles/" + profile_id + "." + format) + print_response(res) + print "--> Step 3 - List All Profiles (Again)" + res = client.do_request(TENANT_ID,'GET', "/portprofiles." + format) + print_response(res) + print "COMPLETED" + print "----------------------------" + +def main(): + + create_cisco_network('xml') + + create_cisco_portprofile('xml') + #test_delete_network('json') + test_delete_portprofile('json') + pass + + +# Standard boilerplate to call the main() function. +if __name__ == '__main__': + main() diff --git a/cisco_demo/test_client.py b/cisco_demo/test_client.py new file mode 100644 index 0000000000..4273e7d4a7 --- /dev/null +++ b/cisco_demo/test_client.py @@ -0,0 +1,83 @@ +"""A base client class - derived from Quantum.MiniClient""" + +import httplib +import socket +import urllib + + +class ExtClient(object): + + action_prefix = '/v0.1/extensions/csco/tenants/{tenant_id}' + #action_prefix = '/v0.1/tenants/{tenant_id}' + def __init__(self, host, port, use_ssl): + """ + Creates a new client to some service. + + :param host: The host where service resides + :param port: The port where service resides + :param use_ssl: Should we use HTTPS? + """ + self.host = host + self.port = port + self.use_ssl = use_ssl + self.connection = None + + def get_connection_type(self): + """ + Returns the proper connection type + """ + if self.use_ssl: + return httplib.HTTPSConnection + else: + return httplib.HTTPConnection + + def do_request(self, tenant, method, action, body=None, + headers=None, params=None): + """ + Connects to the server and issues a request. + Returns the result data, or raises an appropriate exception if + HTTP status code is not 2xx + + :param method: HTTP method ("GET", "POST", "PUT", etc...) + :param body: string of data to send, or None (default) + :param headers: mapping of key/value pairs to add as headers + :param params: dictionary of key/value pairs to add to append + to action + + """ + action = ExtClient.action_prefix + action + action = action.replace('{tenant_id}', tenant) + if type(params) is dict: + action += '?' + urllib.urlencode(params) + + try: + connection_type = self.get_connection_type() + headers = headers or {} + + # Open connection and send request + c = connection_type(self.host, self.port) + c.request(method, action, body, headers) + res = c.getresponse() + status_code = self.get_status_code(res) + if status_code in (httplib.OK, + httplib.CREATED, + httplib.ACCEPTED, + httplib.NO_CONTENT): + return res + else: + raise Exception("Server returned error: %s" % res.read()) + + except (socket.error, IOError), e: + raise Exception("Unable to connect to " + "server. Got error: %s" % e) + + def get_status_code(self, response): + """ + Returns the integer status code from the response, which + can be either a Webob.Response (used in testing) or httplib.Response + """ + if hasattr(response, 'status_int'): + return response.status_int + else: + return response.status + diff --git a/extensions/_credential_view.py b/extensions/_credential_view.py new file mode 100644 index 0000000000..e324d3fc32 --- /dev/null +++ b/extensions/_credential_view.py @@ -0,0 +1,35 @@ +def get_view_builder(req): + 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.""" + print "credential-DATA:%s" % credential_data + 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 model of a server.""" + return dict(credential=dict(id=credential_data['credential_id'])) + + def _build_detail(self, credential_data): + """Return a simple model of a server.""" + + return dict(credential=dict(id=credential_data['credential_id'], + name=credential_data['user_name'], + password=credential_data['password'])) \ No newline at end of file diff --git a/extensions/_exceptions.py b/extensions/_exceptions.py new file mode 100644 index 0000000000..5ae8850f54 --- /dev/null +++ b/extensions/_exceptions.py @@ -0,0 +1,160 @@ +# 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 + + +class ExtensionException(Exception): + """Quantum Cisco api Exception + + Taken from nova.exception.NovaException + To correctly use this class, inherit from it and define + a 'message' property. That message will get printf'd + with the keyword arguments provided to the constructor. + + """ + message = _("An unknown exception occurred.") + + def __init__(self, **kwargs): + try: + self._error_string = self.message % kwargs + + except Exception: + # at least get the core message out if something happened + self._error_string = self.message + + def __str__(self): + return self._error_string + + +class ProcessExecutionError(IOError): + def __init__(self, stdout=None, stderr=None, exit_code=None, cmd=None, + description=None): + if description is None: + description = "Unexpected error while running command." + if exit_code is None: + exit_code = '-' + message = "%s\nCommand: %s\nExit code: %s\nStdout: %r\nStderr: %r" % ( + description, cmd, exit_code, stdout, stderr) + IOError.__init__(self, message) + + +class Error(Exception): + def __init__(self, message=None): + super(Error, self).__init__(message) + + +class ApiError(Error): + def __init__(self, message='Unknown', code='Unknown'): + self.message = message + self.code = code + super(ApiError, self).__init__('%s: %s' % (code, message)) + + +class NotFound(ExtensionException): + pass + + +class ClassNotFound(NotFound): + message = _("Class %(class_name)s could not be found") + + +class PortprofileNotFound(NotFound): + message = _("Portprofile %(_id)s could not be found") + + +class NovatenantNotFound(NotFound): + message = _("Novatenant %(_id)s could not be found") + + +class PortNotFound(NotFound): + message = _("Port %(port_id)s could not be found " \ + "on Network %(net_id)s") + + +class CredentialNotFound(NotFound): + message = _("Credential %(_id)s could not be found") + + +class QosNotFound(NotFound): + message = _("QoS %(_id)s could not be found") + + +""" + + +class PortprofileInUse(ExtensionException): + message = _("Unable to complete operation on Portprofile %(net_id)s. " \ + "There is one or more attachments plugged into its ports.") + + +class PortInUse(ExtensionException): + message = _("Unable to complete operation on port %(port_id)s " \ + "for Portprofile %(net_id)s. The attachment '%(att_id)s" \ + "is plugged into the logical port.") + +class AlreadyAttached(ExtensionException): + message = _("Unable to plug the attachment %(att_id)s into port " \ + "%(port_id)s for Portprofile %(net_id)s. The attachment is " \ + "already plugged into port %(att_port_id)s") + +""" + + +class Duplicate(Error): + pass + + +class NotAuthorized(Error): + pass + + +class NotEmpty(Error): + pass + + +class Invalid(Error): + pass + + +class InvalidContentType(Invalid): + message = _("Invalid content type %(content_type)s.") + + +class BadInputError(Exception): + """Error resulting from a client sending bad input to a server""" + pass + + +class MissingArgumentError(Error): + pass + + +def wrap_exception(f): + def _wrap(*args, **kw): + try: + return f(*args, **kw) + except Exception, e: + if not isinstance(e, Error): + #exc_type, exc_value, exc_traceback = sys.exc_info() + logging.exception('Uncaught exception') + #logging.error(traceback.extract_stack(exc_traceback)) + raise Error(str(e)) + raise + _wrap.func_name = f.func_name + return _wrap diff --git a/extensions/_faults.py b/extensions/_faults.py new file mode 100644 index 0000000000..95ee9aed65 --- /dev/null +++ b/extensions/_faults.py @@ -0,0 +1,157 @@ +# 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 +import webob.exc + +from quantum.api import api_common as common +from quantum.common import wsgi + + +class Fault(webob.exc.HTTPException): + """Error codes for API faults""" + + _fault_names = { + 400: "malformedRequest", + 401: "unauthorized", + 420: "networkNotFound", + 421: "PortprofileInUse", + 430: "portNotFound", + 431: "requestedStateInvalid", + 432: "portInUse", + 440: "alreadyAttached", + 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 ctor.""" + #print ("*********TEST2") + # 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, + 'detail': self.wrapped_exc.detail}} + # 'code' is an attribute on the fault tag itself + metadata = {'application/xml': {'attributes': {fault_name: 'code'}}} + default_xmlns = common.XML_NS_V10 + serializer = wsgi.Serializer(metadata, default_xmlns) + content_type = req.best_match_content_type() + self.wrapped_exc.body = 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 + """ + #print ("*********TEST1") + 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.') diff --git a/extensions/_novatenant_view.py b/extensions/_novatenant_view.py new file mode 100644 index 0000000000..3a1b3f8ca9 --- /dev/null +++ b/extensions/_novatenant_view.py @@ -0,0 +1,28 @@ + + +import os + + +def get_view_builder(req): + 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_desc=host_data['host_desc']) + + def build_vif(self, vif_data): + """Return VIF description.""" + return dict(vif_desc=vif_data['vif_desc']) diff --git a/extensions/_pprofiles.py b/extensions/_pprofiles.py new file mode 100644 index 0000000000..997cb26e2a --- /dev/null +++ b/extensions/_pprofiles.py @@ -0,0 +1,40 @@ +def get_view_builder(req): + 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.""" + print "portprofile_DATA:%s" % portprofile_data + 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 model 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'])) diff --git a/extensions/_qos_view.py b/extensions/_qos_view.py new file mode 100644 index 0000000000..877d82d0f4 --- /dev/null +++ b/extensions/_qos_view.py @@ -0,0 +1,35 @@ +def get_view_builder(req): + 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.""" + print "qos_DATA:%s" % qos_data + 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 model of a server.""" + return dict(qos=dict(id=qos_data['qos_id'])) + + def _build_detail(self, qos_data): + """Return a simple model of a server.""" + + return dict(qos=dict(id=qos_data['qos_id'], + name=qos_data['qos_name'], + description=qos_data['qos_desc'])) diff --git a/extensions/credential.py b/extensions/credential.py new file mode 100644 index 0000000000..46f25b6f15 --- /dev/null +++ b/extensions/credential.py @@ -0,0 +1,159 @@ +# 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 extensions import _exceptions as exception +from extensions import _faults as faults + +from quantum.api import api_common as common +from quantum.common import wsgi +from quantum.common import extensions +from quantum.manager import QuantumManager + +LOG = logging.getLogger('quantum.api.credentials') + + +class Credential(object): + + def __init__(self): + pass + + def get_name(self): + return "Cisco Credential" + + def get_alias(self): + return "Cisco Credential" + + def get_description(self): + return "Credential include username and password" + + def get_namespace(self): + return "" + + def get_updated(self): + return "2011-07-25T13:25:27-06:00" + + def get_resources(self): + 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' + super(CredentialController, self).__init__(plugin) + + def index(self, request, tenant_id): + """ Returns a list of credential ids """ + #TODO: this should be for a given tenant!!! + 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) + + 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 e: + return faults.Fault(faults.CredentialNotFound(e)) + + #return faults.Fault(e) + + def create(self, request, tenant_id): + """ Creates a new credential for a given tenant """ + #look for credential name in request + try: + req_params = \ + self._parse_request_params(request, + self._credential_ops_param_list) + except exc.HTTPError as e: + return faults.Fault(e) + 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 e: + return faults.Fault(e) + 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 e: + return faults.Fault(faults.CredentialNotFound(e)) + + 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 e: + return faults.Fault(faults.CredentialNotFound(e)) + \ No newline at end of file diff --git a/extensions/novatenant.py b/extensions/novatenant.py new file mode 100644 index 0000000000..91a48e8fd7 --- /dev/null +++ b/extensions/novatenant.py @@ -0,0 +1,161 @@ +# 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. + +from webob import exc + +from extensions import _novatenant_view as novatenant_view +from extensions import _exceptions as exception +from extensions import _faults as faults + +from quantum.api import api_common as common +from quantum.common import wsgi +from quantum.common import extensions +from quantum.manager import QuantumManager + + +class Novatenant(object): + + def __init__(self): + pass + + def get_name(self): + return "Cisco Nova Tenant" + + def get_alias(self): + return "Cisco Nova Tenant" + + def get_description(self): + return "novatenant resource is used by nova side to invoke quantum api" + + def get_namespace(self): + return "" + + def get_updated(self): + return "2011-08-09T13:25:27-06:00" + + def get_resources(self): + 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' + super(NovatenantsController, self).__init__(plugin) + + def index(self, request, tenant_id): + """ Returns a list of novatenant ids """ + return "novatenant is a dummy resource" + + def _items(self, request, tenant_id, is_detail): + """ Returns a list of novatenants. """ + return "novatenant is a dummy resource" + + def show(self, request, tenant_id, id): + """ Returns novatenant details for the given novatenant id """ + return "novatenant is a dummy resource" + + def create(self, request, tenant_id): + """ Creates a new novatenant for a given tenant """ + return "novatenant is a dummy resource" + + def update(self, request, tenant_id, id): + """ Updates the name for the novatenant with the given id """ + return "novatenant is a dummy resource" + + def delete(self, request, tenant_id, id): + """ Destroys the Novatenant with the given id """ + return "novatenant is a dummy resource" + + #added for cisco's extension + 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 e: + return faults.Fault(e) + 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 + #return exc.HTTPAccepted() + except exception.NovatenantNotFound as e: + return faults.Fault(faults.NovatenantNotFound(e)) + except exception.PortNotFound as e: + return faults.Fault(faults.PortNotFound(e)) + + #added for Cisco extension + 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 e: + return faults.Fault(e) + 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 + + return exc.HTTPAccepted() + except exception.NovatenantNotFound as e: + return faults.Fault(faults.NovatenantNotFound(e)) + except exception.PortNotFound as e: + return faults.Fault(faults.PortNotFound(e)) diff --git a/extensions/portprofile.py b/extensions/portprofile.py new file mode 100644 index 0000000000..7cd2b3633d --- /dev/null +++ b/extensions/portprofile.py @@ -0,0 +1,207 @@ +# 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. + +from webob import exc + +from extensions import _pprofiles as pprofiles_view +from extensions import _exceptions as exception +from extensions import _faults as faults + +from quantum.api import api_common as common +from quantum.common import wsgi +from quantum.common import extensions +from quantum.manager import QuantumManager + + +class Portprofile(object): + + def __init__(self): + pass + + def get_name(self): + return "Cisco Port Profile" + + def get_alias(self): + return "Cisco Port Profile" + + def get_description(self): + return "Portprofile include QoS information" + + def get_namespace(self): + return "" + + def get_updated(self): + return "2011-07-23T13:25:27-06:00" + + def get_resources(self): + parent_resource = dict(member_name="tenant", + collection_name="extensions/csco/tenants") + member_actions = {'associate_portprofile': "PUT", + 'disassociate_portprofile': "POST"} + 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 """ + + _portprofile_ops_param_list = [{ + 'param-name': 'portprofile_name', + 'required': True}, { + 'param-name': 'qos_name', + 'required': True}, { + 'param-name': 'assignment', + 'required': False}] + + _assignprofile_ops_param_list = [{ + 'param-name': 'network-id', + 'required': True}, { + 'param-name': 'port-id', + 'required': True}] + + _serialization_metadata = { + "application/xml": { + "attributes": { + "portprofile": ["id", "name"], + }, + }, + } + + def __init__(self, plugin): + self._resource_name = 'portprofile' + super(PortprofilesController, self).__init__(plugin) + + def index(self, request, tenant_id): + """ Returns a list of portprofile ids """ + #TODO: this should be for a given tenant!!! + 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) + + 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 e: + return faults.Fault(faults.PortprofileNotFound(e)) + #return faults.Fault(e) + + 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 e: + return faults.Fault(e) + 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 e: + return faults.Fault(e) + 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 e: + return faults.Fault(faults.PortprofileNotFound(e)) + + 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 e: + return faults.Fault(faults.PortprofileNotFound(e)) + + #added for cisco's extension + def associate_portprofile(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._assignprofile_ops_param_list) + except exc.HTTPError as e: + return faults.Fault(e) + net_id = req_params['network-id'].strip() + #print "*****net id "+net_id + 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 e: + return faults.Fault(faults.PortprofileNotFound(e)) + except exception.PortNotFound as e: + return faults.Fault(faults.PortNotFound(e)) + + #added for Cisco extension + def disassociate_portprofile(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._assignprofile_ops_param_list) + except exc.HTTPError as e: + return faults.Fault(e) + net_id = req_params['network-id'].strip() + #print "*****net id "+net_id + 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 e: + return faults.Fault(faults.PortprofileNotFound(e)) + except exception.PortNotFound as e: + return faults.Fault(faults.PortNotFound(e)) diff --git a/extensions/qos.py b/extensions/qos.py new file mode 100644 index 0000000000..5351cc00b1 --- /dev/null +++ b/extensions/qos.py @@ -0,0 +1,154 @@ +# 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 extensions import _exceptions as exception +from extensions import _faults as faults + +from quantum.api import api_common as common +from quantum.common import wsgi +from quantum.common import extensions +from quantum.manager import QuantumManager + +LOG = logging.getLogger('quantum.api.qoss') + + +class Qos(object): + + def __init__(self): + pass + + def get_name(self): + return "Cisco qos" + + def get_alias(self): + return "Cisco qos" + + def get_description(self): + return "qos include username and password" + + def get_namespace(self): + return "" + + def get_updated(self): + return "2011-07-25T13:25:27-06:00" + + def get_resources(self): + 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' + super(QosController, self).__init__(plugin) + + def index(self, request, tenant_id): + """ Returns a list of qos ids """ + #TODO: this should be for a given tenant!!! + 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) + + 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 e: + return faults.Fault(faults.QosNotFound(e)) + + #return faults.Fault(e) + + 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 e: + return faults.Fault(e) + 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 e: + return faults.Fault(e) + 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 e: + return faults.Fault(faults.QosNotFound(e)) + + 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 e: + return faults.Fault(faults.QosNotFound(e)) diff --git a/quantum/plugins.ini b/quantum/plugins.ini index 307d2b48d2..58db5dbc14 100644 --- a/quantum/plugins.ini +++ b/quantum/plugins.ini @@ -1,3 +1,4 @@ [PLUGIN] -# Quantum plugin provider module -provider = quantum.plugins.SamplePlugin.FakePlugin +provider = quantum.plugins.cisco.l2network_plugin.L2Network +#provider = quantum.plugins.cisco.CiscoPlugin.CiscoPaloPlugin2 +#provider = quantum.plugins.SamplePlugin.FakePlugin diff --git a/quantum/plugins/cisco/CiscoPlugin.py b/quantum/plugins/cisco/CiscoPlugin.py new file mode 100644 index 0000000000..bed81abf7e --- /dev/null +++ b/quantum/plugins/cisco/CiscoPlugin.py @@ -0,0 +1,562 @@ +from quantum.common import exceptions as exc +from extensions import _exceptions as extexc + + +class CiscoPaloPlugin2(object): + """ + This plugin has internal data structure + derived from quantum fakeplugin + """ + + #static data for networks and ports + _port_dict_1 = { + 1: {'port-id': 1, + 'port-state': 'DOWN', + 'attachment': None, + 'portprofile': None}, + 2: {'port-id': 2, + 'port-state': 'UP', + 'attachment': None, + 'portprofile': None}} + _port_dict_2 = { + 1: {'port-id': 1, + 'port-state': 'UP', + 'attachment': 'SomeFormOfVIFID', + 'portprofile': '001'}, + 2: {'port-id': 2, + 'port-state': 'DOWN', + 'attachment': None, + 'portprofile': '001'}} + _networks = {'001': + { + 'net-id': '001', + 'net-name': 'pippotest', + 'net-ports': _port_dict_1}, + '002': + { + 'net-id': '002', + 'net-name': 'cicciotest', + 'net-ports': _port_dict_2}} + _portprofiles = {'001': + { + 'profile_id': '001', + 'profile_name': 'pprofiletest', + 'assignment': ['1', '2'], + 'qos_name': '001'}, + '002': + { + 'profile_id': '002', + 'profile_name': 'cicciotest', + 'qos_name': '002', + 'assignment': None}} + + _credentials = {'001': + { + 'credential_id': '001', + 'credential_name': 'cred1', + 'user_name': 'ying', + 'password': 'yingTest'}, + '002': + { + 'credential_id': '002', + 'credential_name': 'cred2', + 'user_name': 'admin', + 'password': 'adminTest'}} + _qoss = {'001': + { + 'qos_id': '001', + 'qos_name': 'silver', + 'qos_desc': {'pps':170, 'TTL':20}}, + '002': + { + 'qos_id': '002', + 'qos_name': 'gold', + 'qos_desc': {'pps':340, 'TTL':10}}} + + _host = {'host_desc': { + "host_key1": "host_value1", + "host_key2": "host_value2"}} + _vif = {'vif_desc': { + "vif_key1": "vif_value1", + "vif_key2": "vif_value2"} + } + + + supported_extension_aliases = ["Cisco Credential", "Cisco Port Profile", "Cisco qos", "Cisco Nova Tenant"] + + + """ + def supports_extension(self, extension): + #return extension.get_alias() == "Cisco Port Profile" + return extension.get_alias() == "Cisco Credential" + """ + def __init__(self): + CiscoPaloPlugin2._net_counter = \ + len(CiscoPaloPlugin2._networks) + + CiscoPaloPlugin2._profile_counter = \ + len(CiscoPaloPlugin2._portprofiles) + + CiscoPaloPlugin2._credential_counter = \ + len(CiscoPaloPlugin2._credentials) + + CiscoPaloPlugin2._qos_counter = \ + len(CiscoPaloPlugin2._qoss) + def _get_network(self, tenant_id, network_id): + + network = CiscoPaloPlugin2._networks.get(network_id) + if not network: + raise exc.NetworkNotFound(net_id=network_id) + return network + + + + def _get_credential(self, tenant_id, credential_id): + credential = CiscoPaloPlugin2._credentials.get(credential_id) + if not credential: + raise extexc.CredentialNotFound(credential_id=credential_id) + return credential + + def _get_qos(self, tenant_id, qos_id): + qos = CiscoPaloPlugin2._qoss.get(qos_id) + if not qos: + raise extexc.QosNotFound(qos_id=qos_id) + return qos + + def _get_port(self, tenant_id, network_id, port_id): + net = self._get_network(tenant_id, network_id) + port = net['net-ports'].get(int(port_id)) + if not port: + raise exc.PortNotFound(net_id=network_id, port_id=port_id) + return port + + def _validate_port_state(self, port_state): + if port_state.upper() not in ('UP', 'DOWN'): + raise exc.StateInvalid(port_state=port_state) + return True + + def _validate_attachment(self, tenant_id, network_id, port_id, + remote_interface_id): + network = self._get_network(tenant_id, network_id) + for port in network['net-ports'].values(): + if port['attachment'] == remote_interface_id: + raise exc.AlreadyAttached(net_id=network_id, + port_id=port_id, + att_id=port['attachment'], + att_port_id=port['port-id']) + + def get_all_networks(self, tenant_id): + """ + Returns a dictionary containing all + for + the specified tenant. + """ + print("get_all_networks() called\n") + return CiscoPaloPlugin2._networks.values() + + def get_network_details(self, tenant_id, net_id): + """ + retrieved a list of all the remote vifs that + are attached to the network + """ + print("get_network_details() called\n") + return self._get_network(tenant_id, net_id) + + def create_network(self, tenant_id, net_name): + """ + Creates a new Virtual Network, and assigns it + a symbolic name. + """ + print("create_network() called\n") + CiscoPaloPlugin2._net_counter += 1 + new_net_id = ("0" * (3 - len(str(CiscoPaloPlugin2._net_counter)))) + \ + str(CiscoPaloPlugin2._net_counter) + print new_net_id + new_net_dict = {'net-id': new_net_id, + 'net-name': net_name, + 'net-ports': {}} + CiscoPaloPlugin2._networks[new_net_id] = new_net_dict + # return network_id of the created network + return new_net_dict + + def delete_network(self, tenant_id, net_id): + """ + Deletes the network with the specified network identifier + belonging to the specified tenant. + """ + print("delete_network() called\n") + net = CiscoPaloPlugin2._networks.get(net_id) + # Verify that no attachments are plugged into the network + if net: + if net['net-ports']: + for port in net['net-ports'].values(): + if port['attachment']: + raise exc.NetworkInUse(net_id=net_id) + CiscoPaloPlugin2._networks.pop(net_id) + return net + # Network not found + raise exc.NetworkNotFound(net_id=net_id) + + def rename_network(self, tenant_id, net_id, new_name): + """ + Updates the symbolic name belonging to a particular + Virtual Network. + """ + print("rename_network() called\n") + net = self._get_network(tenant_id, net_id) + net['net-name'] = new_name + return net + + def _get_portprofile(self, tenant_id, portprofile_id): + portprofile = CiscoPaloPlugin2._portprofiles.get(portprofile_id) + if not portprofile: + raise extexc.PortprofileNotFound(portprofile_id=portprofile_id) + return portprofile + + def get_all_portprofiles(self, tenant_id): + """ + Returns a dictionary containing all + for + the specified tenant. + """ + print("get_all_portprofiles() called\n") + return CiscoPaloPlugin2._portprofiles.values() + + def get_portprofile_details(self, tenant_id, profile_id): + """ + retrieved a list of all the remote vifs that + are attached to the portprofile + """ + print("get_portprofile_details() called\n") + return self._get_portprofile(tenant_id, profile_id) + + def create_portprofile(self, tenant_id, profile_name, vlan_id): + """ + Creates a new Virtual portprofile, and assigns it + a symbolic name. + """ + print("create_portprofile() called\n") + CiscoPaloPlugin2._profile_counter += 1 + new_profile_id = ("0" * \ + (3 - \ + len(str(CiscoPaloPlugin2._profile_counter)))) + \ + str(CiscoPaloPlugin2._profile_counter) + print new_profile_id + new_profile_dict = {'profile_id': new_profile_id, + 'profile_name': profile_name, + 'qos_name': vlan_id, + 'assignment': None} + CiscoPaloPlugin2._portprofiles[new_profile_id] = new_profile_dict + # return portprofile_id of the created portprofile + return new_profile_dict + + def delete_portprofile(self, tenant_id, profile_id): + """ + Deletes the portprofile with the specified portprofile identifier + belonging to the specified tenant. + """ + print("delete_portprofile() called\n") + profile = CiscoPaloPlugin2._portprofiles.get(profile_id) + # Verify that no attachments are plugged into the portprofile + if profile: + CiscoPaloPlugin2._portprofiles.pop(profile_id) + return profile + # portprofile not found + raise extexc.PortprofileNotFound(profile_id=profile_id) + + def rename_portprofile(self, tenant_id, profile_id, new_name): + """ + Updates the symbolic name belonging to a particular + Virtual portprofile. + """ + print("rename_portprofile() called\n") + profile = self._get_portprofile(tenant_id, profile_id) + profile['profile_name'] = new_name + return profile + + + + def associate_portprofile(self, tenant_id, net_id, port_id, pprofile_id): + """ + Assign portprofile to the specified port on the + specified Virtual Network. + """ + print("assign_portprofile() called\n") + print("net_id " + net_id) + # Validate attachment + #self._validate_attachment(tenant_id, net_id, port_id, + # remote_interface_id) + #TODO: modify the exception + port = self._get_port(tenant_id, net_id, port_id) + if (not port['portprofile'] == None): + raise exc.PortInUse(net_id=net_id, port_id=port_id, + att_id=port['portprofile']) + port['portprofile'] = pprofile_id + + def disassociate_portprofile(self, tenant_id, net_id, port_id, portprofile_id): + """ + De-assign a portprofile from the specified port on the + specified Virtual Network. + """ + print("deassign_portprofile() called\n") + #print("*******net_id is "+net_id) + port = self._get_port(tenant_id, net_id, port_id) + + port['portprofile'] = None + #TODO: + #modify assignment[portprofile_id] to remove this port + + #TODO: add new data structure to + #hold all the assignment for a specific portprofile + def get_portprofile_assignment(self, tenant_id, net_id, port_id): + print("get portprofile assignment called\n") + port = self._get_port(tenant_id, net_id, port_id) + ppid = port['portprofile'] + if (ppid == None): + print("***no portprofile attached") + return "no portprofile attached" + else: + print("***attached portprofile id is " + ppid) + return ("attached portprofile " + ppid) + + + def get_all_credentials(self, tenant_id): + """ + Returns a dictionary containing all + for + the specified tenant. + """ + print("get_all_credentials() called\n") + return CiscoPaloPlugin2._credentials.values() + + def get_credential_details(self, tenant_id, credential_id): + """ + retrieved a list of all the remote vifs that + are attached to the credential + """ + print("get_credential_details() called\n") + return self._get_credential(tenant_id, credential_id) + + def create_credential(self, tenant_id, credential_name, user_name, password): + """ + Creates a new Virtual credential, and assigns it + a symbolic name. + """ + print("create_credential() called\n") + CiscoPaloPlugin2._credential_counter += 1 + new_credential_id = ("0" * \ + (3 - \ + len(str(CiscoPaloPlugin2._credential_counter)))) + \ + str(CiscoPaloPlugin2._credential_counter) + print new_credential_id + new_credential_dict = {'credential_id': new_credential_id, + 'credential_name': credential_name, + 'user_name': user_name, + 'password': password} + CiscoPaloPlugin2._credentials[new_credential_id] = new_credential_dict + # return credential_id of the created credential + return new_credential_dict + + def delete_credential(self, tenant_id, credential_id): + """ + Deletes the credential with the specified credential identifier + belonging to the specified tenant. + """ + print("delete_credential() called\n") + credential = CiscoPaloPlugin2._credentials.get(credential_id) + + if credential: + CiscoPaloPlugin2._credentials.pop(credential_id) + return credential + # credential not found + raise extexc.CredentialNotFound(credential_id=credential_id) + + def rename_credential(self, tenant_id, credential_id, new_name): + """ + Updates the symbolic name belonging to a particular + Virtual credential. + """ + print("rename_credential() called\n") + credential = self._get_credential(tenant_id, credential_id) + credential['credential_name'] = new_name + return credential + + + def get_all_qoss(self, tenant_id): + """ + Returns a dictionary containing all + for + the specified tenant. + """ + print("get_all_qoss() called\n") + return CiscoPaloPlugin2._qoss.values() + + def get_qos_details(self, tenant_id, qos_id): + """ + retrieved a list of all the remote vifs that + are attached to the qos + """ + print("get_qos_details() called\n") + return self._get_qos(tenant_id, qos_id) + + def create_qos(self, tenant_id, qos_name, qos_desc): + """ + Creates a new Virtual qos, and assigns it + a symbolic name. + """ + print("create_qos() called\n") + CiscoPaloPlugin2._qos_counter += 1 + new_qos_id = ("0" * \ + (3 - \ + len(str(CiscoPaloPlugin2._qos_counter)))) + \ + str(CiscoPaloPlugin2._qos_counter) + print new_qos_id + new_qos_dict = {'qos_id': new_qos_id, + 'qos_name': qos_name, + 'qos_desc': qos_desc} + + print("************************") + print("test dictionary data") + print(qos_desc['TTL']) + print("************************") + + CiscoPaloPlugin2._qoss[new_qos_id] = new_qos_dict + # return qos_id of the created qos + return new_qos_dict + + def delete_qos(self, tenant_id, qos_id): + """ + Deletes the qos with the specified qos identifier + belonging to the specified tenant. + """ + print("delete_qos() called\n") + qos = CiscoPaloPlugin2._qoss.get(qos_id) + # Verify that no attachments are plugged into the qos + if qos: + CiscoPaloPlugin2._qoss.pop(qos_id) + return qos + # qos not found + raise extexc.QosNotFound(qos_id=qos_id) + + def rename_qos(self, tenant_id, qos_id, new_name): + """ + Updates the symbolic name belonging to a particular + Virtual qos. + """ + print("rename_qos() called\n") + qos = self._get_qos(tenant_id, qos_id) + qos['qos_name'] = new_name + return qos + + + + + def get_all_ports(self, tenant_id, net_id): + """ + Retrieves all port identifiers belonging to the + specified Virtual Network. + """ + print("get_all_ports() called\n") + network = self._get_network(tenant_id, net_id) + ports_on_net = network['net-ports'].values() + return ports_on_net + + def get_port_details(self, tenant_id, net_id, port_id): + """ + This method allows the user to retrieve a remote interface + that is attached to this particular port. + """ + print("get_port_details() called\n") + return self._get_port(tenant_id, net_id, port_id) + + def create_port(self, tenant_id, net_id, port_state=None): + """ + Creates a port on the specified Virtual Network. + """ + print("create_port() called\n") + net = self._get_network(tenant_id, net_id) + # check port state + # TODO(salvatore-orlando): Validate port state in API? + self._validate_port_state(port_state) + ports = net['net-ports'] + new_port_id = max(ports.keys()) + 1 + new_port_dict = {'port-id': new_port_id, + 'port-state': port_state, + 'attachment': None, + 'portprofile': None} + ports[new_port_id] = new_port_dict + return new_port_dict + + def update_port(self, tenant_id, net_id, port_id, port_state): + """ + Updates the state of a port on the specified Virtual Network. + """ + print("create_port() called\n") + port = self._get_port(tenant_id, net_id, port_id) + self._validate_port_state(port_state) + port['port-state'] = port_state + return port + + def delete_port(self, tenant_id, net_id, port_id): + """ + Deletes a port on a specified Virtual Network, + if the port contains a remote interface attachment, + the remote interface is first un-plugged and then the port + is deleted. + """ + print("delete_port() called\n") + net = self._get_network(tenant_id, net_id) + port = self._get_port(tenant_id, net_id, port_id) + if port['attachment']: + raise exc.PortInUse(net_id=net_id, port_id=port_id, + att_id=port['attachment']) + try: + net['net-ports'].pop(int(port_id)) + except KeyError: + raise exc.PortNotFound(net_id=net_id, port_id=port_id) + + def get_interface_details(self, tenant_id, net_id, port_id): + print("get interface detail called\n") + port = self._get_port(tenant_id, net_id, port_id) + vid = port['attachment'] + if (vid == None): + print("***no interface is attached") + return "no interface attached" + else: + print("***interface id is " + vid) + return ("attached interface " + vid) + + def plug_interface(self, tenant_id, net_id, port_id, remote_interface_id): + """ + Attaches a remote interface to the specified port on the + specified Virtual Network. + """ + print("plug_interface() called\n") + # Validate attachment + self._validate_attachment(tenant_id, net_id, port_id, + remote_interface_id) + port = self._get_port(tenant_id, net_id, port_id) + if port['attachment']: + raise exc.PortInUse(net_id=net_id, port_id=port_id, + att_id=port['attachment']) + port['attachment'] = remote_interface_id + + def unplug_interface(self, tenant_id, net_id, port_id): + """ + Detaches a remote interface from the specified port on the + specified Virtual Network. + """ + print("unplug_interface() called\n") + port = self._get_port(tenant_id, net_id, port_id) + # TODO(salvatore-orlando): + # Should unplug on port without attachment raise an Error? + port['attachment'] = None + + def get_host(self, tenant_id, instance_id, instance_desc): + print("associate an instance to a port....") + print("get key2: " + instance_desc['key2']) + return CiscoPaloPlugin2._host + def get_instance_port(self, tenant_id, instance_id, instance_desc): + print("get instance associated port....") + print("get key1: " + instance_desc['key1']) + return CiscoPaloPlugin2._vif \ No newline at end of file diff --git a/quantum/plugins/cisco/conf/db_conn.ini b/quantum/plugins/cisco/conf/db_conn.ini index 4a5d7e3713..fdc7ace15e 100644 --- a/quantum/plugins/cisco/conf/db_conn.ini +++ b/quantum/plugins/cisco/conf/db_conn.ini @@ -1,5 +1,5 @@ [DATABASE] name = quantum_l2network -user = -pass = -host = +user =root +pass =nova +host =localhost diff --git a/quantum/plugins/cisco/conf/l2network_plugin.ini b/quantum/plugins/cisco/conf/l2network_plugin.ini index 3a740a9713..f51c1ae331 100644 --- a/quantum/plugins/cisco/conf/l2network_plugin.ini +++ b/quantum/plugins/cisco/conf/l2network_plugin.ini @@ -1,6 +1,6 @@ [VLANS] -vlan_start= -vlan_end= +vlan_start=100 +vlan_end=300 vlan_name_prefix=q- [PORTS] diff --git a/quantum/plugins/cisco/conf/plugins.ini b/quantum/plugins/cisco/conf/plugins.ini index 8b4b476a0a..a4b62c8903 100644 --- a/quantum/plugins/cisco/conf/plugins.ini +++ b/quantum/plugins/cisco/conf/plugins.ini @@ -1,3 +1,3 @@ [PLUGINS] -ucs_plugin=quantum.plugins.cisco.ucs.cisco_ucs_plugin.UCSVICPlugin +#ucs_plugin=quantum.plugins.cisco.ucs.cisco_ucs_plugin.UCSVICPlugin #nexus_plugin=quantum.plugins.cisco.nexus.cisco_nexus_plugin.NexusPlugin diff --git a/test_scripts/__init__.py b/test_scripts/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test_scripts/miniclient.py b/test_scripts/miniclient.py new file mode 100644 index 0000000000..fb1ebc8fec --- /dev/null +++ b/test_scripts/miniclient.py @@ -0,0 +1,98 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 Citrix Systems +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import httplib +import socket +import urllib + +class MiniClient(object): + + """A base client class - derived from Glance.BaseClient""" + + action_prefix = '/v0.1/tenants/{tenant_id}' + + def __init__(self, host, port, use_ssl): + """ + Creates a new client to some service. + + :param host: The host where service resides + :param port: The port where service resides + :param use_ssl: Should we use HTTPS? + """ + self.host = host + self.port = port + self.use_ssl = use_ssl + self.connection = None + + def get_connection_type(self): + """ + Returns the proper connection type + """ + if self.use_ssl: + return httplib.HTTPSConnection + else: + return httplib.HTTPConnection + + def do_request(self, tenant, method, action, body=None, + headers=None, params=None): + """ + Connects to the server and issues a request. + Returns the result data, or raises an appropriate exception if + HTTP status code is not 2xx + + :param method: HTTP method ("GET", "POST", "PUT", etc...) + :param body: string of data to send, or None (default) + :param headers: mapping of key/value pairs to add as headers + :param params: dictionary of key/value pairs to add to append + to action + + """ + action = MiniClient.action_prefix + action + action = action.replace('{tenant_id}',tenant) + if type(params) is dict: + action += '?' + urllib.urlencode(params) + + try: + connection_type = self.get_connection_type() + headers = headers or {} + + # Open connection and send request + c = connection_type(self.host, self.port) + c.request(method, action, body, headers) + res = c.getresponse() + status_code = self.get_status_code(res) + if status_code in (httplib.OK, + httplib.CREATED, + httplib.ACCEPTED, + httplib.NO_CONTENT): + return res + else: + raise Exception("Server returned error: %s" % res.read()) + + except (socket.error, IOError), e: + raise Exception("Unable to connect to " + "server. Got error: %s" % e) + + def get_status_code(self, response): + """ + Returns the integer status code from the response, which + can be either a Webob.Response (used in testing) or httplib.Response + """ + if hasattr(response, 'status_int'): + return response.status_int + else: + return response.status \ No newline at end of file diff --git a/test_scripts/tests.py b/test_scripts/tests.py new file mode 100644 index 0000000000..589d9da224 --- /dev/null +++ b/test_scripts/tests.py @@ -0,0 +1,150 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 Citrix Systems +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import gettext + +gettext.install('quantum', unicode=1) + +from miniclient import MiniClient +from quantum.common.wsgi import Serializer + +HOST = '127.0.0.1' +PORT = 9696 +USE_SSL = False +TENANT_ID = 'totore' + +test_network_data = \ + {'network': {'network-name': 'test' }} + +def print_response(res): + content = res.read() + print "Status: %s" %res.status + print "Content: %s" %content + return content + +def test_list_networks_and_ports(format = 'xml'): + client = MiniClient(HOST, PORT, USE_SSL) + print "TEST LIST NETWORKS AND PORTS -- FORMAT:%s" %format + print "----------------------------" + print "--> Step 1 - List All Networks" + res = client.do_request(TENANT_ID,'GET', "/networks." + format) + print_response(res) + print "--> Step 2 - Details for Network 001" + res = client.do_request(TENANT_ID,'GET', "/networks/001." + format) + print_response(res) + print "--> Step 3 - Ports for Network 001" + res = client.do_request(TENANT_ID,'GET', "/networks/001/ports." + format) + print_response(res) + print "--> Step 4 - Details for Port 1" + res = client.do_request(TENANT_ID,'GET', "/networks/001/ports/1." + format) + print_response(res) + print "COMPLETED" + print "----------------------------" + +def test_create_network(format = 'xml'): + client = MiniClient(HOST, PORT, USE_SSL) + print "TEST CREATE NETWORK -- FORMAT:%s" %format + print "----------------------------" + print "--> Step 1 - Create Network" + content_type = "application/" + format + body = Serializer().serialize(test_network_data, content_type) + res = client.do_request(TENANT_ID,'POST', "/networks." + format, body=body) + print_response(res) + print "--> Step 2 - List All Networks" + res = client.do_request(TENANT_ID,'GET', "/networks." + format) + print_response(res) + print "COMPLETED" + print "----------------------------" + +def test_rename_network(format = 'xml'): + client = MiniClient(HOST, PORT, USE_SSL) + content_type = "application/" + format + print "TEST RENAME NETWORK -- FORMAT:%s" %format + print "----------------------------" + print "--> Step 1 - Retrieve network" + res = client.do_request(TENANT_ID,'GET', "/networks/001." + format) + print_response(res) + print "--> Step 2 - Rename network to 'test_renamed'" + test_network_data['network']['network-name'] = 'test_renamed' + body = Serializer().serialize(test_network_data, content_type) + res = client.do_request(TENANT_ID,'PUT', "/networks/001." + format, body=body) + print_response(res) + print "--> Step 2 - Retrieve network (again)" + res = client.do_request(TENANT_ID,'GET', "/networks/001." + format) + print_response(res) + print "COMPLETED" + print "----------------------------" + +def test_delete_network(format = 'xml'): + client = MiniClient(HOST, PORT, USE_SSL) + content_type = "application/" + format + print "TEST DELETE NETWORK -- FORMAT:%s" %format + print "----------------------------" + print "--> Step 1 - List All Networks" + res = client.do_request(TENANT_ID,'GET', "/networks." + format) + content = print_response(res) + network_data = Serializer().deserialize(content, content_type) + print network_data + net_id = network_data['networks'][0]['id'] + print "--> Step 2 - Delete network %s" %net_id + res = client.do_request(TENANT_ID,'DELETE', + "/networks/" + net_id + "." + format) + print_response(res) + print "--> Step 3 - List All Networks (Again)" + res = client.do_request(TENANT_ID,'GET', "/networks." + format) + print_response(res) + print "COMPLETED" + print "----------------------------" + + +def test_create_port(format = 'xml'): + client = MiniClient(HOST, PORT, USE_SSL) + print "TEST CREATE PORT -- FORMAT:%s" %format + print "----------------------------" + print "--> Step 1 - List Ports for network 001" + res = client.do_request(TENANT_ID,'GET', "/networks/001/ports." + format) + print_response(res) + print "--> Step 2 - Create Port for network 001" + res = client.do_request(TENANT_ID,'POST', "/networks/001/ports." + format) + print_response(res) + print "--> Step 3 - List Ports for network 001 (again)" + res = client.do_request(TENANT_ID,'GET', "/networks/001/ports." + format) + print_response(res) + print "COMPLETED" + print "----------------------------" + + +def main(): + test_list_networks_and_ports('xml') + test_list_networks_and_ports('json') + test_create_network('xml') + test_create_network('json') + test_rename_network('xml') + test_rename_network('json') + # NOTE: XML deserializer does not work properly + # disabling XML test - this is NOT a server-side issue + #test_delete_network('xml') + test_delete_network('json') + test_create_port('xml') + test_create_port('json') + + pass + + +# Standard boilerplate to call the main() function. +if __name__ == '__main__': + main() \ No newline at end of file From d6db34f7a1ee0cfdb64a9f8aa1cb094222228ba0 Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Wed, 17 Aug 2011 16:08:22 -0700 Subject: [PATCH 09/52] Changes to support credentials, qos, and novatenant extensions. --- .../plugins/cisco/common/cisco_constants.py | 32 ++-- .../plugins/cisco/common/cisco_exceptions.py | 16 ++ quantum/plugins/cisco/l2network_plugin.py | 151 +++++++++++++++++- 3 files changed, 188 insertions(+), 11 deletions(-) diff --git a/quantum/plugins/cisco/common/cisco_constants.py b/quantum/plugins/cisco/common/cisco_constants.py index 29bddd8156..6010863cef 100644 --- a/quantum/plugins/cisco/common/cisco_constants.py +++ b/quantum/plugins/cisco/common/cisco_constants.py @@ -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,15 @@ 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 + + diff --git a/quantum/plugins/cisco/common/cisco_exceptions.py b/quantum/plugins/cisco/common/cisco_exceptions.py index f0103d27b1..176e74ba1c 100644 --- a/quantum/plugins/cisco/common/cisco_exceptions.py +++ b/quantum/plugins/cisco/common/cisco_exceptions.py @@ -89,6 +89,22 @@ class VlanIDNotAvailable(exceptions.QuantumException): """VLAN ID is reserved""" message = _("No available Vlan ID found") + +class QoSLevelNotFound(exceptions.QuantumException): + message = _("QoS level %(qos_id)s could not be found " \ + "for tenant %(tenant_id)s") + + +class QoSLevelInvalidDelete(exceptions.QuantumException): + message = _("QoS level %(qos_id)s could not be deleted " \ + "for tenant %(tenant_id)s since association exists") + + +class CredentialNotFound(exceptions.QuantumException): + message = _("Credential %(credential_id)s could not be found " \ + "for tenant %(tenant_id)s") + + try: _("test") except NameError: diff --git a/quantum/plugins/cisco/l2network_plugin.py b/quantum/plugins/cisco/l2network_plugin.py index 4d28400af5..a7b2a0481a 100644 --- a/quantum/plugins/cisco/l2network_plugin.py +++ b/quantum/plugins/cisco/l2network_plugin.py @@ -21,6 +21,7 @@ import inspect import logging as LOG +import platform from quantum.common import exceptions as exc from quantum.common import utils @@ -28,6 +29,7 @@ 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_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,11 @@ 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 +51,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 +261,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,6 +275,7 @@ class L2Network(QuantumPluginBase): def get_portprofile_details(self, tenant_id, profile_id): """Get port profile details""" + LOG.debug("get_portprofile_details() called\n") portprofile = cdb.get_portprofile(tenant_id, profile_id) new_pp = self._make_portprofile_dict(tenant_id, portprofile[const.UUID], @@ -274,16 +285,19 @@ 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, portprofile[const.UUID], portprofile[const.PPNAME], portprofile[const.PPQOS]) + print("***Sumit: %s\n", new_pp) return new_pp def delete_portprofile(self, tenant_id, profile_id): """Delete portprofile""" + LOG.debug("delete_portprofile() called\n") try: portprofile = cdb.get_portprofile(tenant_id, profile_id) except Exception, exc: @@ -299,6 +313,7 @@ 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: @@ -314,6 +329,7 @@ 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: @@ -325,6 +341,7 @@ 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: @@ -333,9 +350,10 @@ class L2Network(QuantumPluginBase): cdb.remove_pp_binding(tenant_id, port_id, portprofile_id) - def create_default_port_profile(self, tenant_id, network_id, profile_name, + def create_default_portprofile(self, tenant_id, network_id, profile_name, qos): "Create default port profile""" + LOG.debug("create_default_portprofile() called\n") portprofile = cdb.add_portprofile(tenant_id, profile_name, const.NO_VLAN_ID, qos) new_pp = self._make_portprofile_dict(tenant_id, @@ -347,6 +365,105 @@ class L2Network(QuantumPluginBase): cdb.add_pp_binding(tenant_id, port_id, portprofile[const.UUID], True) return new_pp + 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") + return self._get_qos_level(tenant_id, qos_id) + + 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") + qos_level = self._get_qos_level(tenant_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) + 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") + return self._get_credential(tenant_id, credential_id) + + 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") + credential = self._get_credential(tenant_id, credential_id) + self._credentials.pop(credential_id) + cred.Store.deleteCredential(credential_id) + + def rename_credential(self, tenant_id, credential_id, new_name): + """Do nothing for this resource""" + LOG.debug("rename_credential() called\n") + pass + + 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 """ @@ -419,3 +536,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.QoSLevelNotFound(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 From 8fed131856ef756c1aab737261b30bf7a3da1b55 Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Wed, 17 Aug 2011 16:21:27 -0700 Subject: [PATCH 10/52] Pylint and pep8 fixes. --- quantum/plugins/cisco/common/cisco_constants.py | 2 -- quantum/plugins/cisco/l2network_plugin.py | 14 ++------------ 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/quantum/plugins/cisco/common/cisco_constants.py b/quantum/plugins/cisco/common/cisco_constants.py index 6010863cef..67ba05d581 100644 --- a/quantum/plugins/cisco/common/cisco_constants.py +++ b/quantum/plugins/cisco/common/cisco_constants.py @@ -130,5 +130,3 @@ UCSPROFILE = 'portprofile' MAX_CREDENTIALS = 65568 MAX_QOS_LEVELS = 1024 - - diff --git a/quantum/plugins/cisco/l2network_plugin.py b/quantum/plugins/cisco/l2network_plugin.py index a7b2a0481a..29fc354242 100644 --- a/quantum/plugins/cisco/l2network_plugin.py +++ b/quantum/plugins/cisco/l2network_plugin.py @@ -44,7 +44,6 @@ class L2Network(QuantumPluginBase): _qos_levels = {} _credentials = {} - def __init__(self): self._vlan_counter = int(conf.VLAN_START) - 1 self._model = utils.import_object(conf.MODEL_CLASS) @@ -443,11 +442,7 @@ class L2Network(QuantumPluginBase): 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() - } - } + host_list = {const.HOST_LIST: {const.HOST_1: platform.node()}} return host_list def get_instance_port(self, tenant_id, instance_id, instance_desc): @@ -456,12 +451,7 @@ class L2Network(QuantumPluginBase): """ LOG.debug("get_instance_port() called\n") vif_desc = {const.VIF_DESC: - { - const.DEVICENAME: "eth2", - const.UCSPROFILE: "default" - } - } - + {const.DEVICENAME: "eth2", const.UCSPROFILE: "default"}} return vif_desc """ From 4f7cdf415c147480f5fac3870f398001dd02b2af Mon Sep 17 00:00:00 2001 From: Ying Liu Date: Wed, 17 Aug 2011 17:15:21 -0700 Subject: [PATCH 11/52] fix some pylint issues --- extensions/_credential_view.py | 20 ++++++++++++++++++++ extensions/_exceptions.py | 2 ++ extensions/_faults.py | 2 ++ extensions/_novatenant_view.py | 25 ++++++++++++++++++++----- extensions/_pprofiles.py | 20 ++++++++++++++++++++ extensions/_qos_view.py | 20 ++++++++++++++++++++ extensions/credential.py | 3 ++- extensions/novatenant.py | 11 +++++++---- extensions/portprofile.py | 23 ++++++++++++++++++----- extensions/qos.py | 3 ++- quantum/plugins.ini | 4 ++-- 11 files changed, 115 insertions(+), 18 deletions(-) diff --git a/extensions/_credential_view.py b/extensions/_credential_view.py index e324d3fc32..062e8fa934 100644 --- a/extensions/_credential_view.py +++ b/extensions/_credential_view.py @@ -1,3 +1,23 @@ +""" +# 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): base_url = req.application_url return ViewBuilder(base_url) diff --git a/extensions/_exceptions.py b/extensions/_exceptions.py index 5ae8850f54..99bc55da11 100644 --- a/extensions/_exceptions.py +++ b/extensions/_exceptions.py @@ -1,3 +1,4 @@ +""" # vim: tabstop=4 shiftwidth=4 softtabstop=4 # # Copyright 2011 Cisco Systems, Inc. All rights reserved. @@ -16,6 +17,7 @@ # # @author: Ying Liu, Cisco Systems, Inc. # +""" import logging diff --git a/extensions/_faults.py b/extensions/_faults.py index 95ee9aed65..51866d5bc9 100644 --- a/extensions/_faults.py +++ b/extensions/_faults.py @@ -1,3 +1,4 @@ +""" # vim: tabstop=4 shiftwidth=4 softtabstop=4 # # Copyright 2011 Cisco Systems, Inc. All rights reserved. @@ -16,6 +17,7 @@ # # @author: Ying Liu, Cisco Systems, Inc. # +""" import webob.dec import webob.exc diff --git a/extensions/_novatenant_view.py b/extensions/_novatenant_view.py index 3a1b3f8ca9..bcfe1f476b 100644 --- a/extensions/_novatenant_view.py +++ b/extensions/_novatenant_view.py @@ -1,8 +1,23 @@ - - -import os - - +""" +# 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): base_url = req.application_url return ViewBuilder(base_url) diff --git a/extensions/_pprofiles.py b/extensions/_pprofiles.py index 997cb26e2a..da541274f9 100644 --- a/extensions/_pprofiles.py +++ b/extensions/_pprofiles.py @@ -1,3 +1,23 @@ +""" +# 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): base_url = req.application_url return ViewBuilder(base_url) diff --git a/extensions/_qos_view.py b/extensions/_qos_view.py index 877d82d0f4..63fc9f3a07 100644 --- a/extensions/_qos_view.py +++ b/extensions/_qos_view.py @@ -1,3 +1,23 @@ +""" +# 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): base_url = req.application_url return ViewBuilder(base_url) diff --git a/extensions/credential.py b/extensions/credential.py index 46f25b6f15..782fddaadd 100644 --- a/extensions/credential.py +++ b/extensions/credential.py @@ -1,3 +1,4 @@ +""" # vim: tabstop=4 shiftwidth=4 softtabstop=4 # # Copyright 2011 Cisco Systems, Inc. All rights reserved. @@ -16,7 +17,7 @@ # # @author: Ying Liu, Cisco Systems, Inc. # - +""" import logging from webob import exc diff --git a/extensions/novatenant.py b/extensions/novatenant.py index 91a48e8fd7..9d37fe2ca4 100644 --- a/extensions/novatenant.py +++ b/extensions/novatenant.py @@ -1,7 +1,7 @@ +""" # vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2011 OpenStack LLC. -# All Rights Reserved. +# +# 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 @@ -14,7 +14,10 @@ # 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 diff --git a/extensions/portprofile.py b/extensions/portprofile.py index 7cd2b3633d..fce20facd0 100644 --- a/extensions/portprofile.py +++ b/extensions/portprofile.py @@ -1,7 +1,7 @@ +""" # vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2011 OpenStack LLC. -# All Rights Reserved. +# +# 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 @@ -14,6 +14,10 @@ # 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 @@ -33,21 +37,27 @@ class Portprofile(object): pass def get_name(self): + """ Returns Ext Resource Name """ return "Cisco Port Profile" def get_alias(self): + """ Returns Ext Resource alias """ return "Cisco Port Profile" def get_description(self): + """ Returns Ext Resource Description """ return "Portprofile include QoS information" def get_namespace(self): + """ Returns Ext Resource Namespace """ return "" def get_updated(self): + """ Returns Ext Resource Updateed time """ return "2011-07-23T13:25:27-06:00" def get_resources(self): + """ Returns all defined resources """ parent_resource = dict(member_name="tenant", collection_name="extensions/csco/tenants") member_actions = {'associate_portprofile': "PUT", @@ -61,7 +71,7 @@ class Portprofile(object): class PortprofilesController(common.QuantumController): """ portprofile API controller based on QuantumController """ - + _portprofile_ops_param_list = [{ 'param-name': 'portprofile_name', 'required': True}, { @@ -83,9 +93,10 @@ class PortprofilesController(common.QuantumController): }, }, } - + def __init__(self, plugin): self._resource_name = 'portprofile' + self._plugin = plugin super(PortprofilesController, self).__init__(plugin) def index(self, request, tenant_id): @@ -160,6 +171,7 @@ class PortprofilesController(common.QuantumController): #added for cisco's extension 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 @@ -184,6 +196,7 @@ class PortprofilesController(common.QuantumController): #added for Cisco extension 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 diff --git a/extensions/qos.py b/extensions/qos.py index 5351cc00b1..777883d8cf 100644 --- a/extensions/qos.py +++ b/extensions/qos.py @@ -1,3 +1,4 @@ +""" # vim: tabstop=4 shiftwidth=4 softtabstop=4 # # Copyright 2011 Cisco Systems, Inc. All rights reserved. @@ -16,7 +17,7 @@ # # @author: Ying Liu, Cisco Systems, Inc. # - +""" import logging from webob import exc diff --git a/quantum/plugins.ini b/quantum/plugins.ini index 58db5dbc14..27c13c73f3 100644 --- a/quantum/plugins.ini +++ b/quantum/plugins.ini @@ -1,4 +1,4 @@ [PLUGIN] -provider = quantum.plugins.cisco.l2network_plugin.L2Network -#provider = quantum.plugins.cisco.CiscoPlugin.CiscoPaloPlugin2 +#provider = quantum.plugins.cisco.l2network_plugin.L2Network +provider = quantum.plugins.cisco.CiscoPlugin.CiscoPaloPlugin2 #provider = quantum.plugins.SamplePlugin.FakePlugin From a7ef6583c0d275d2d24d8467922ad09c39569ce3 Mon Sep 17 00:00:00 2001 From: Ying Liu Date: Thu, 18 Aug 2011 15:57:36 -0700 Subject: [PATCH 12/52] pylint and pep8 fix --- extensions/_credential_view.py | 2 +- extensions/_pprofiles.py | 2 +- extensions/credential.py | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/extensions/_credential_view.py b/extensions/_credential_view.py index 1c1cc3ac2c..453cd8b24d 100644 --- a/extensions/_credential_view.py +++ b/extensions/_credential_view.py @@ -39,7 +39,7 @@ class ViewBuilder(object): def build(self, credential_data, is_detail=False): """Generic method used to generate a credential entity.""" - print "credential-DATA:%s" % credential_data + if is_detail: credential = self._build_detail(credential_data) else: diff --git a/extensions/_pprofiles.py b/extensions/_pprofiles.py index c3d8147603..ba94c472bc 100644 --- a/extensions/_pprofiles.py +++ b/extensions/_pprofiles.py @@ -39,7 +39,7 @@ class ViewBuilder(object): def build(self, portprofile_data, is_detail=False): """Generic method used to generate a portprofile entity.""" - print "portprofile_DATA:%s" % portprofile_data + if is_detail: portprofile = self._build_detail(portprofile_data) else: diff --git a/extensions/credential.py b/extensions/credential.py index 1e64222166..8b51c81c2d 100644 --- a/extensions/credential.py +++ b/extensions/credential.py @@ -100,7 +100,6 @@ class CredentialController(common.QuantumController): def index(self, request, tenant_id): """ Returns a list of credential ids """ - #TODO: this should be for a given tenant!!! return self._items(request, tenant_id, is_detail=False) def _items(self, request, tenant_id, is_detail): From 5834bcc8e20654feb4e22cab53c83502a315f071 Mon Sep 17 00:00:00 2001 From: Ying Liu Date: Thu, 18 Aug 2011 16:33:08 -0700 Subject: [PATCH 13/52] change the configuration files to the default values --- quantum/plugins.ini | 4 +--- quantum/plugins/cisco/conf/db_conn.ini | 6 +++--- quantum/plugins/cisco/conf/l2network_plugin.ini | 4 ++-- quantum/plugins/cisco/conf/plugins.ini | 2 +- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/quantum/plugins.ini b/quantum/plugins.ini index 27c13c73f3..20a83de77c 100644 --- a/quantum/plugins.ini +++ b/quantum/plugins.ini @@ -1,4 +1,2 @@ [PLUGIN] -#provider = quantum.plugins.cisco.l2network_plugin.L2Network -provider = quantum.plugins.cisco.CiscoPlugin.CiscoPaloPlugin2 -#provider = quantum.plugins.SamplePlugin.FakePlugin +provider = quantum.plugins.SamplePlugin.FakePlugin diff --git a/quantum/plugins/cisco/conf/db_conn.ini b/quantum/plugins/cisco/conf/db_conn.ini index fdc7ace15e..28461f7663 100644 --- a/quantum/plugins/cisco/conf/db_conn.ini +++ b/quantum/plugins/cisco/conf/db_conn.ini @@ -1,5 +1,5 @@ [DATABASE] name = quantum_l2network -user =root -pass =nova -host =localhost +user = +pass = +host = diff --git a/quantum/plugins/cisco/conf/l2network_plugin.ini b/quantum/plugins/cisco/conf/l2network_plugin.ini index f51c1ae331..3a740a9713 100644 --- a/quantum/plugins/cisco/conf/l2network_plugin.ini +++ b/quantum/plugins/cisco/conf/l2network_plugin.ini @@ -1,6 +1,6 @@ [VLANS] -vlan_start=100 -vlan_end=300 +vlan_start= +vlan_end= vlan_name_prefix=q- [PORTS] diff --git a/quantum/plugins/cisco/conf/plugins.ini b/quantum/plugins/cisco/conf/plugins.ini index a4b62c8903..8b4b476a0a 100644 --- a/quantum/plugins/cisco/conf/plugins.ini +++ b/quantum/plugins/cisco/conf/plugins.ini @@ -1,3 +1,3 @@ [PLUGINS] -#ucs_plugin=quantum.plugins.cisco.ucs.cisco_ucs_plugin.UCSVICPlugin +ucs_plugin=quantum.plugins.cisco.ucs.cisco_ucs_plugin.UCSVICPlugin #nexus_plugin=quantum.plugins.cisco.nexus.cisco_nexus_plugin.NexusPlugin From 770bce2913103ec3e35da6d5415b3b38c935ff05 Mon Sep 17 00:00:00 2001 From: Ying Liu Date: Thu, 18 Aug 2011 18:57:51 -0700 Subject: [PATCH 14/52] remove cisco_demo and test_scripts directory, which were used by our local tests --- cisco_demo/demo_client.py | 386 ----------------------------------- cisco_demo/demo_client.py.bk | 127 ------------ cisco_demo/test_client.py | 83 -------- test_scripts/__init__.py | 0 test_scripts/miniclient.py | 98 --------- test_scripts/tests.py | 150 -------------- 6 files changed, 844 deletions(-) delete mode 100755 cisco_demo/demo_client.py delete mode 100755 cisco_demo/demo_client.py.bk delete mode 100644 cisco_demo/test_client.py delete mode 100644 test_scripts/__init__.py delete mode 100644 test_scripts/miniclient.py delete mode 100644 test_scripts/tests.py diff --git a/cisco_demo/demo_client.py b/cisco_demo/demo_client.py deleted file mode 100755 index 4f91abc93e..0000000000 --- a/cisco_demo/demo_client.py +++ /dev/null @@ -1,386 +0,0 @@ - -import os -import sys - -import gettext - -#gettext.install('quantum', unicode=1) -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 test_scripts.miniclient import MiniClient -from test_client import ExtClient -from quantum.common.wsgi import Serializer - -HOST = '127.0.0.1' -PORT = 9696 -USE_SSL = False -TENANT_ID = 'ucs_user' - - -test_network_data = \ - {'network': {'net-name': 'cisco_test_network', - 'valn-id': 28}} -test_portprofile_data = \ - {'portprofile': {'portprofile_name': 'cisco_test_portprofile', - 'qos_name': 2, - 'qos_name': 'test-qos'}} -test_cred_data = \ - {'credential': {'credential_name': 'cred3', - 'user_name': 'newUser', - 'password': 'newPasswd' - }} -test_qos_data = \ - {'qos': {'qos_name': 'plantimum', - 'qos_desc': {'PPS': 50, 'TTL': 5}}} - - -#we put this assignment under portprofile resources -#therefore we need to create such a test data -test_port_assign_data = {'portprofile': {'network-id': '001', - 'port-id': '1'}} -test_attach_data = {'port': {'attachment-id': 'v01'}} - -test_act_data = {"get_available_host":123} - -test_instance_data={'novatenant':{'instance_id' : 1, - 'instance_desc' : {'key1' : '1', - 'key2' : '2' - }}} - -def test_get_host(format='json'): - client = ExtClient(HOST, PORT, USE_SSL) - content_type = "application/" + format - body = Serializer().serialize(test_instance_data, content_type) - res = client.do_request(TENANT_ID, - 'PUT', "/novatenants/001/get_host." + format, body=body) - print "XML Response" - print_response(res) - print "COMPLETED" - print "----------------------------" - -def test_get_instance_port(format='json'): - client = ExtClient(HOST, PORT, USE_SSL) - content_type = "application/" + format - body = Serializer().serialize(test_instance_data, content_type) - res = client.do_request(TENANT_ID, - 'PUT', "/novatenants/001/get_instance_port." + format, body=body) - print "XML Response" - print_response(res) - print "COMPLETED" - print "----------------------------" - -def test_action_ext(format='json'): - client = ExtClient(HOST, PORT, USE_SSL) - content_type = "application/" + format - action_name = 'get_available_host' - action_params = dict(name='test') - body = Serializer().serialize(test_act_data, content_type) - - - res = client.do_request(TENANT_ID, 'POST', "/act_resources/1/action." + format, body=body) - content = print_response(res) - -def print_response(res): - content = res.read() - print "Status: %s" % res.status - print "Content: %s" % content - return content - - -def create_cisco_network(format='xml'): - - client = MiniClient(HOST, PORT, USE_SSL) - print "CREATE NETWORK -- FORMAT:%s" % format - print "----------------------------" - content_type = "application/" + format - body = Serializer().serialize(test_network_data, content_type) - res = client.do_request(TENANT_ID, - 'POST', "/networks." + format, body=body) - print "XML Response" - print_response(res) - print "COMPLETED" - print "----------------------------" - - -def create_cisco_portprofile(format='xml'): - client = ExtClient(HOST, PORT, USE_SSL) - content_type = "application/" + format - print "List all Profile -- FORMat%s" % format - print "----------------------------" - res = client.do_request(TENANT_ID, 'GET', "/portprofiles." + format) - content = print_response(res) - portprofile_data = Serializer().deserialize(content, content_type) - print portprofile_data - - """ - print "List a specific Profile -- FORMAT:%s" % format - profile_id = portprofile_data['portprofiles'][0]['id'] - #profile_id='001' - print "profile_id " + profile_id - res = client.do_request(TENANT_ID, - 'GET', "/portprofiles/" - + profile_id + "." + format) - print_response(res) - """ - print "CREATE Profile -- FORMAT:%s" % format - print "----------------------------" - content_type = "application/" + format - body = Serializer().serialize(test_portprofile_data, content_type) - print "***BODY is " - print body - res = client.do_request(TENANT_ID, 'POST', - "/portprofiles." + format, body=body) - print "XML Response" - print_response(res) - print "COMPLETED" - print "----------------------------" - -def test_credential (format='xml'): - client = ExtClient(HOST, PORT, USE_SSL) - content_type = "application/" + format - print "----------------------------" - print "List all credentials -- FORMat%s" % format - print "----------------------------" - res = client.do_request(TENANT_ID, 'GET', "/credentials." + format) - content = print_response(res) - credential_data = Serializer().deserialize(content, content_type) - print credential_data - - print "----------------------------" - print "CREATE Credential -- FORMAT:%s" % format - print "----------------------------" - content_type = "application/" + format - body = Serializer().serialize(test_cred_data, content_type) - print "***BODY is " - print body - res = client.do_request(TENANT_ID, 'POST', - "/credentials." + format, body=body) - print "XML Response" - print_response(res) - - print "----------------------------" - print "List all credentials -- FORMat%s" % format - print "----------------------------" - res = client.do_request(TENANT_ID, 'GET', "/credentials." + format) - content = print_response(res) - credential_data = Serializer().deserialize(content, content_type) - print credential_data - print "----------------------------" - print "List a specific cred -- FORMAT:%s" % format - print "----------------------------" - cred_id = credential_data['credentials'][0]['id'] - #cred_id='001' - print "cred_id " + cred_id - res = client.do_request(TENANT_ID, - 'GET', "/credentials/" - + cred_id + "." + format) - print_response(res) - - print "----------------------------" - print "TEST DELETE Credential -- FORMAT:%s" % format - print "----------------------------" - res = client.do_request(TENANT_ID, 'DELETE', - "/credentials/" + cred_id + "." + format) - print_response(res) - - print "----------------------------" - print "List all credentials -- FORMat%s" % format - print "----------------------------" - res = client.do_request(TENANT_ID, 'GET', "/credentials." + format) - content = print_response(res) - credential_data = Serializer().deserialize(content, content_type) - print credential_data - - print "COMPLETED" - print "----------------------------" - -def test_qos (format='xml'): - client = ExtClient(HOST, PORT, USE_SSL) - content_type = "application/" + format - print "----------------------------" - print "List all qoss -- FORMat%s" % format - print "----------------------------" - res = client.do_request(TENANT_ID, 'GET', "/qoss." + format) - content = print_response(res) - qos_data = Serializer().deserialize(content, content_type) - print qos_data - - print "----------------------------" - print "CREATE qos -- FORMAT:%s" % format - print "----------------------------" - content_type = "application/" + format - body = Serializer().serialize(test_qos_data, content_type) - print "***BODY is " - print body - res = client.do_request(TENANT_ID, 'POST', - "/qoss." + format, body=body) - print "XML Response" - print_response(res) - - print "----------------------------" - print "List all qoss -- FORMat%s" % format - print "----------------------------" - res = client.do_request(TENANT_ID, 'GET', "/qoss." + format) - content = print_response(res) - qos_data = Serializer().deserialize(content, content_type) - print qos_data - print "----------------------------" - print "List a specific cred -- FORMAT:%s" % format - print "----------------------------" - qos_id = qos_data['qoss'][0]['id'] - #cred_id='001' - print "qos_id " + qos_id - res = client.do_request(TENANT_ID, - 'GET', "/qoss/" - + qos_id + "." + format) - print_response(res) - - print "----------------------------" - print "TEST DELETE qos -- FORMAT:%s" % format - print "----------------------------" - res = client.do_request(TENANT_ID, 'DELETE', - "/qoss/" + qos_id + "." + format) - print_response(res) - - print "----------------------------" - print "List all qoss -- FORMat%s" % format - print "----------------------------" - res = client.do_request(TENANT_ID, 'GET', "/qoss." + format) - content = print_response(res) - qos_data = Serializer().deserialize(content, content_type) - print qos_data - - print "COMPLETED" - print "----------------------------" - -def test_delete_network(format='xml'): - client = MiniClient(HOST, PORT, USE_SSL) - content_type = "application/" + format - print "TEST DELETE NETWORK -- FORMAT:%s" % format - print "----------------------------" - print "--> Step 1 - List All Networks" - res = client.do_request(TENANT_ID, 'GET', "/networks." + format) - content = print_response(res) - network_data = Serializer().deserialize(content, content_type) - print network_data - net_id = network_data['networks'][0]['id'] - print "--> Step 2 - Delete network %s" % net_id - res = client.do_request(TENANT_ID, 'DELETE', - "/networks/" + net_id + "." + format) - print_response(res) - print "--> Step 3 - List All Networks (Again)" - res = client.do_request(TENANT_ID, 'GET', "/networks." + format) - print_response(res) - print "COMPLETED" - print "----------------------------" - - -def test_delete_portprofile(format='xml'): - client = ExtClient(HOST, PORT, USE_SSL) - content_type = "application/" + format - print "TEST DELETE PROFILE -- FORMAT:%s" % format - print "----------------------------" - print "--> Step 1 - List All Profiles" - res = client.do_request(TENANT_ID, 'GET', "/portprofiles." + format) - content = print_response(res) - portprofile_data = Serializer().deserialize(content, content_type) - print portprofile_data - profile_id = portprofile_data['portprofiles'][0]['id'] - print "--> Step 2 - Delete portprofile %s" % profile_id - res = client.do_request(TENANT_ID, 'DELETE', - "/portprofiles/" + profile_id + "." + format) - print_response(res) - print "--> Step 3 - List All Profiles (Again)" - res = client.do_request(TENANT_ID, 'GET', "/portprofiles." + format) - print_response(res) - print "COMPLETED" - print "----------------------------" - - -def test_create_port(format='xml'): - client = MiniClient(HOST, PORT, USE_SSL) - print "TEST CREATE PORT -- FORMAT:%s" % format - print "----------------------------" - print "--> Step 1 - List Ports for network 001" - res = client.do_request(TENANT_ID, 'GET', "/networks/001/ports." + format) - print_response(res) - print "--> Step 2 - Create Port for network 001" - res = client.do_request(TENANT_ID, 'POST', "/networks/001/ports." + format) - print_response(res) - print "--> Step 3 - List Ports for network 001 (again)" - res = client.do_request(TENANT_ID, 'GET', "/networks/001/ports." + format) - print_response(res) - print "COMPLETED" - print "----------------------------" - - -#assuming network 001 and ports 1 are created in the plug-in -def test_attach_resource(format='xml'): - client = MiniClient(HOST, PORT, USE_SSL) - print "TEST attach resources to port" - content_type = "application/" + format - body = Serializer().serialize(test_attach_data, content_type) - #attach virtual interface to the port - res = client.do_request(TENANT_ID, 'PUT', - "/networks/001/ports/1/attachment." - + format, body=body) - print_response(res) - #list existing interface of the port - res = client.do_request(TENANT_ID, 'GET', - "/networks/001/ports/1/attachment." + format) - print_response(res) - #de_attach virtual interface from the port - res = client.do_request(TENANT_ID, 'DELETE', - "/networks/001/ports/1/attachment." + format) - print_response(res) - #list existing interface of the port - res = client.do_request(TENANT_ID, 'GET', - "/networks/001/ports/1/attachment." + format) - print_response(res) - - -#assuming network 001, ports 1 and portprofile 002 are created in the plug-in -def test_assign_portprofile(format='xml'): - client = ExtClient(HOST, PORT, USE_SSL) - print "TEST attach resources to port" - content_type = "application/" + format - body = Serializer().serialize(test_port_assign_data, content_type) - print "body is " + body - res = client.do_request(TENANT_ID, 'PUT', - "/portprofiles/001/associate_portprofile." - + format, body=body) - print_response(res) - res = client.do_request(TENANT_ID, 'POST', - "/portprofiles/001/disassociate_portprofile." - + format, body=body) - - print_response(res) - - -def main(): - create_cisco_portprofile('json') - #test_attach_resource('json') - - test_delete_portprofile('json') - test_credential('json') - test_qos('json') - ##test_action_ext('json') - test_get_host('json') - test_get_instance_port('json') - - create_cisco_network('json') - test_create_port('json') - create_cisco_portprofile('json') - test_assign_portprofile('json') - pass - - -# Standard boilerplate to call the main() function. -if __name__ == '__main__': - main() diff --git a/cisco_demo/demo_client.py.bk b/cisco_demo/demo_client.py.bk deleted file mode 100755 index 3c7c928d4b..0000000000 --- a/cisco_demo/demo_client.py.bk +++ /dev/null @@ -1,127 +0,0 @@ -''' -Created on Jun 08, 2011 - -@author: ying -''' - -import os -import sys - -import gettext - -#gettext.install('quantum', unicode=1) -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 test_scripts.miniclient import MiniClient -from quantum.common.wsgi import Serializer - -HOST = '127.0.0.1' -PORT = 9696 -USE_SSL = False -TENANT_ID = 'ucs_user' - -test_network_data = \ - {'network': {'network-name': 'cisco_test_network', - 'valn-id': 28 }} - -test_portprofile_data = \ - {'portprofile': {'portprofile-name': 'cisco_test_portprofile', - 'vlan-id': 28, - 'vlan-name': 'test-vlan' }} - -def print_response(res): - content = res.read() - print "Status: %s" %res.status - print "Content: %s" %content - return content - - -def create_cisco_network(format = 'xml'): - client = MiniClient(HOST, PORT, USE_SSL) - print "CREATE NETWORK -- FORMAT:%s" %format - print "----------------------------" - content_type = "application/" + format - body = Serializer().serialize(test_network_data, content_type) - res = client.do_request(TENANT_ID,'POST', "/networks." + format, body=body) - print "XML Response" - print_response(res) - print "COMPLETED" - print "----------------------------" - -def create_cisco_portprofile(format = 'xml'): - client = MiniClient(HOST, PORT, USE_SSL) - print "CREATE Profile -- FORMAT:%s" %format - print "----------------------------" - content_type = "application/" + format - body = Serializer().serialize(test_portprofile_data, content_type) - print "**********BODY is**********" - print body - print "***************************" - res = client.do_request(TENANT_ID,'POST', "/portprofiles." + format, body=body) - print "XML Response" - print_response(res) - print "COMPLETED" - print "----------------------------" - -def test_delete_network(format = 'xml'): - client = MiniClient(HOST, PORT, USE_SSL) - content_type = "application/" + format - print "TEST DELETE NETWORK -- FORMAT:%s" %format - print "----------------------------" - print "--> Step 1 - List All Networks" - res = client.do_request(TENANT_ID,'GET', "/networks." + format) - content = print_response(res) - network_data = Serializer().deserialize(content, content_type) - print network_data - net_id = network_data['networks'][0]['id'] - print "--> Step 2 - Delete network %s" %net_id - res = client.do_request(TENANT_ID,'DELETE', - "/networks/" + net_id + "." + format) - print_response(res) - print "--> Step 3 - List All Networks (Again)" - res = client.do_request(TENANT_ID,'GET', "/networks." + format) - print_response(res) - print "COMPLETED" - print "----------------------------" - - -def test_delete_portprofile(format = 'xml'): - client = MiniClient(HOST, PORT, USE_SSL) - content_type = "application/" + format - print "TEST DELETE PROFILE -- FORMAT:%s" %format - print "----------------------------" - print "--> Step 1 - List All Profiles" - res = client.do_request(TENANT_ID,'GET', "/portprofiles." + format) - content = print_response(res) - portprofile_data = Serializer().deserialize(content, content_type) - print portprofile_data - profile_id = portprofile_data['portprofiles'][0]['id'] - print "--> Step 2 - Delete portprofile %s" %profile_id - res = client.do_request(TENANT_ID,'DELETE', - "/portprofiles/" + profile_id + "." + format) - print_response(res) - print "--> Step 3 - List All Profiles (Again)" - res = client.do_request(TENANT_ID,'GET', "/portprofiles." + format) - print_response(res) - print "COMPLETED" - print "----------------------------" - -def main(): - - create_cisco_network('xml') - - create_cisco_portprofile('xml') - #test_delete_network('json') - test_delete_portprofile('json') - pass - - -# Standard boilerplate to call the main() function. -if __name__ == '__main__': - main() diff --git a/cisco_demo/test_client.py b/cisco_demo/test_client.py deleted file mode 100644 index 4273e7d4a7..0000000000 --- a/cisco_demo/test_client.py +++ /dev/null @@ -1,83 +0,0 @@ -"""A base client class - derived from Quantum.MiniClient""" - -import httplib -import socket -import urllib - - -class ExtClient(object): - - action_prefix = '/v0.1/extensions/csco/tenants/{tenant_id}' - #action_prefix = '/v0.1/tenants/{tenant_id}' - def __init__(self, host, port, use_ssl): - """ - Creates a new client to some service. - - :param host: The host where service resides - :param port: The port where service resides - :param use_ssl: Should we use HTTPS? - """ - self.host = host - self.port = port - self.use_ssl = use_ssl - self.connection = None - - def get_connection_type(self): - """ - Returns the proper connection type - """ - if self.use_ssl: - return httplib.HTTPSConnection - else: - return httplib.HTTPConnection - - def do_request(self, tenant, method, action, body=None, - headers=None, params=None): - """ - Connects to the server and issues a request. - Returns the result data, or raises an appropriate exception if - HTTP status code is not 2xx - - :param method: HTTP method ("GET", "POST", "PUT", etc...) - :param body: string of data to send, or None (default) - :param headers: mapping of key/value pairs to add as headers - :param params: dictionary of key/value pairs to add to append - to action - - """ - action = ExtClient.action_prefix + action - action = action.replace('{tenant_id}', tenant) - if type(params) is dict: - action += '?' + urllib.urlencode(params) - - try: - connection_type = self.get_connection_type() - headers = headers or {} - - # Open connection and send request - c = connection_type(self.host, self.port) - c.request(method, action, body, headers) - res = c.getresponse() - status_code = self.get_status_code(res) - if status_code in (httplib.OK, - httplib.CREATED, - httplib.ACCEPTED, - httplib.NO_CONTENT): - return res - else: - raise Exception("Server returned error: %s" % res.read()) - - except (socket.error, IOError), e: - raise Exception("Unable to connect to " - "server. Got error: %s" % e) - - def get_status_code(self, response): - """ - Returns the integer status code from the response, which - can be either a Webob.Response (used in testing) or httplib.Response - """ - if hasattr(response, 'status_int'): - return response.status_int - else: - return response.status - diff --git a/test_scripts/__init__.py b/test_scripts/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/test_scripts/miniclient.py b/test_scripts/miniclient.py deleted file mode 100644 index fb1ebc8fec..0000000000 --- a/test_scripts/miniclient.py +++ /dev/null @@ -1,98 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2011 Citrix Systems -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import httplib -import socket -import urllib - -class MiniClient(object): - - """A base client class - derived from Glance.BaseClient""" - - action_prefix = '/v0.1/tenants/{tenant_id}' - - def __init__(self, host, port, use_ssl): - """ - Creates a new client to some service. - - :param host: The host where service resides - :param port: The port where service resides - :param use_ssl: Should we use HTTPS? - """ - self.host = host - self.port = port - self.use_ssl = use_ssl - self.connection = None - - def get_connection_type(self): - """ - Returns the proper connection type - """ - if self.use_ssl: - return httplib.HTTPSConnection - else: - return httplib.HTTPConnection - - def do_request(self, tenant, method, action, body=None, - headers=None, params=None): - """ - Connects to the server and issues a request. - Returns the result data, or raises an appropriate exception if - HTTP status code is not 2xx - - :param method: HTTP method ("GET", "POST", "PUT", etc...) - :param body: string of data to send, or None (default) - :param headers: mapping of key/value pairs to add as headers - :param params: dictionary of key/value pairs to add to append - to action - - """ - action = MiniClient.action_prefix + action - action = action.replace('{tenant_id}',tenant) - if type(params) is dict: - action += '?' + urllib.urlencode(params) - - try: - connection_type = self.get_connection_type() - headers = headers or {} - - # Open connection and send request - c = connection_type(self.host, self.port) - c.request(method, action, body, headers) - res = c.getresponse() - status_code = self.get_status_code(res) - if status_code in (httplib.OK, - httplib.CREATED, - httplib.ACCEPTED, - httplib.NO_CONTENT): - return res - else: - raise Exception("Server returned error: %s" % res.read()) - - except (socket.error, IOError), e: - raise Exception("Unable to connect to " - "server. Got error: %s" % e) - - def get_status_code(self, response): - """ - Returns the integer status code from the response, which - can be either a Webob.Response (used in testing) or httplib.Response - """ - if hasattr(response, 'status_int'): - return response.status_int - else: - return response.status \ No newline at end of file diff --git a/test_scripts/tests.py b/test_scripts/tests.py deleted file mode 100644 index 589d9da224..0000000000 --- a/test_scripts/tests.py +++ /dev/null @@ -1,150 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2011 Citrix Systems -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import gettext - -gettext.install('quantum', unicode=1) - -from miniclient import MiniClient -from quantum.common.wsgi import Serializer - -HOST = '127.0.0.1' -PORT = 9696 -USE_SSL = False -TENANT_ID = 'totore' - -test_network_data = \ - {'network': {'network-name': 'test' }} - -def print_response(res): - content = res.read() - print "Status: %s" %res.status - print "Content: %s" %content - return content - -def test_list_networks_and_ports(format = 'xml'): - client = MiniClient(HOST, PORT, USE_SSL) - print "TEST LIST NETWORKS AND PORTS -- FORMAT:%s" %format - print "----------------------------" - print "--> Step 1 - List All Networks" - res = client.do_request(TENANT_ID,'GET', "/networks." + format) - print_response(res) - print "--> Step 2 - Details for Network 001" - res = client.do_request(TENANT_ID,'GET', "/networks/001." + format) - print_response(res) - print "--> Step 3 - Ports for Network 001" - res = client.do_request(TENANT_ID,'GET', "/networks/001/ports." + format) - print_response(res) - print "--> Step 4 - Details for Port 1" - res = client.do_request(TENANT_ID,'GET', "/networks/001/ports/1." + format) - print_response(res) - print "COMPLETED" - print "----------------------------" - -def test_create_network(format = 'xml'): - client = MiniClient(HOST, PORT, USE_SSL) - print "TEST CREATE NETWORK -- FORMAT:%s" %format - print "----------------------------" - print "--> Step 1 - Create Network" - content_type = "application/" + format - body = Serializer().serialize(test_network_data, content_type) - res = client.do_request(TENANT_ID,'POST', "/networks." + format, body=body) - print_response(res) - print "--> Step 2 - List All Networks" - res = client.do_request(TENANT_ID,'GET', "/networks." + format) - print_response(res) - print "COMPLETED" - print "----------------------------" - -def test_rename_network(format = 'xml'): - client = MiniClient(HOST, PORT, USE_SSL) - content_type = "application/" + format - print "TEST RENAME NETWORK -- FORMAT:%s" %format - print "----------------------------" - print "--> Step 1 - Retrieve network" - res = client.do_request(TENANT_ID,'GET', "/networks/001." + format) - print_response(res) - print "--> Step 2 - Rename network to 'test_renamed'" - test_network_data['network']['network-name'] = 'test_renamed' - body = Serializer().serialize(test_network_data, content_type) - res = client.do_request(TENANT_ID,'PUT', "/networks/001." + format, body=body) - print_response(res) - print "--> Step 2 - Retrieve network (again)" - res = client.do_request(TENANT_ID,'GET', "/networks/001." + format) - print_response(res) - print "COMPLETED" - print "----------------------------" - -def test_delete_network(format = 'xml'): - client = MiniClient(HOST, PORT, USE_SSL) - content_type = "application/" + format - print "TEST DELETE NETWORK -- FORMAT:%s" %format - print "----------------------------" - print "--> Step 1 - List All Networks" - res = client.do_request(TENANT_ID,'GET', "/networks." + format) - content = print_response(res) - network_data = Serializer().deserialize(content, content_type) - print network_data - net_id = network_data['networks'][0]['id'] - print "--> Step 2 - Delete network %s" %net_id - res = client.do_request(TENANT_ID,'DELETE', - "/networks/" + net_id + "." + format) - print_response(res) - print "--> Step 3 - List All Networks (Again)" - res = client.do_request(TENANT_ID,'GET', "/networks." + format) - print_response(res) - print "COMPLETED" - print "----------------------------" - - -def test_create_port(format = 'xml'): - client = MiniClient(HOST, PORT, USE_SSL) - print "TEST CREATE PORT -- FORMAT:%s" %format - print "----------------------------" - print "--> Step 1 - List Ports for network 001" - res = client.do_request(TENANT_ID,'GET', "/networks/001/ports." + format) - print_response(res) - print "--> Step 2 - Create Port for network 001" - res = client.do_request(TENANT_ID,'POST', "/networks/001/ports." + format) - print_response(res) - print "--> Step 3 - List Ports for network 001 (again)" - res = client.do_request(TENANT_ID,'GET', "/networks/001/ports." + format) - print_response(res) - print "COMPLETED" - print "----------------------------" - - -def main(): - test_list_networks_and_ports('xml') - test_list_networks_and_ports('json') - test_create_network('xml') - test_create_network('json') - test_rename_network('xml') - test_rename_network('json') - # NOTE: XML deserializer does not work properly - # disabling XML test - this is NOT a server-side issue - #test_delete_network('xml') - test_delete_network('json') - test_create_port('xml') - test_create_port('json') - - pass - - -# Standard boilerplate to call the main() function. -if __name__ == '__main__': - main() \ No newline at end of file From ed84b41a3458a81f8db7c00704e0b773768de50a Mon Sep 17 00:00:00 2001 From: Ying Liu Date: Fri, 19 Aug 2011 00:14:44 -0700 Subject: [PATCH 15/52] remove all configuration files --- extensions/_faults.py | 2 +- quantum/plugins.ini | 2 -- quantum/plugins/cisco/conf/credentials.ini | 15 --------------- quantum/plugins/cisco/conf/db_conn.ini | 5 ----- quantum/plugins/cisco/conf/l2network_plugin.ini | 16 ---------------- quantum/plugins/cisco/conf/nexus.ini | 10 ---------- quantum/plugins/cisco/conf/nova.ini | 8 -------- quantum/plugins/cisco/conf/plugins.ini | 3 --- quantum/plugins/cisco/conf/ucs.ini | 10 ---------- 9 files changed, 1 insertion(+), 70 deletions(-) delete mode 100644 quantum/plugins.ini delete mode 100644 quantum/plugins/cisco/conf/credentials.ini delete mode 100644 quantum/plugins/cisco/conf/db_conn.ini delete mode 100644 quantum/plugins/cisco/conf/l2network_plugin.ini delete mode 100644 quantum/plugins/cisco/conf/nexus.ini delete mode 100644 quantum/plugins/cisco/conf/nova.ini delete mode 100644 quantum/plugins/cisco/conf/plugins.ini delete mode 100644 quantum/plugins/cisco/conf/ucs.ini diff --git a/extensions/_faults.py b/extensions/_faults.py index cb44fd1873..6bdd3a48b9 100644 --- a/extensions/_faults.py +++ b/extensions/_faults.py @@ -63,7 +63,7 @@ class Fault(webob.exc.HTTPException): default_xmlns = common.XML_NS_V10 serializer = wsgi.Serializer(metadata, default_xmlns) content_type = req.best_match_content_type() - self.wrapped_exc.body = serializer.serialize(fault_data, content_type) + #self.wrapped_exc.body = serializer.serialize(fault_data, content_type) self.wrapped_exc.content_type = content_type return self.wrapped_exc diff --git a/quantum/plugins.ini b/quantum/plugins.ini deleted file mode 100644 index 20a83de77c..0000000000 --- a/quantum/plugins.ini +++ /dev/null @@ -1,2 +0,0 @@ -[PLUGIN] -provider = quantum.plugins.SamplePlugin.FakePlugin diff --git a/quantum/plugins/cisco/conf/credentials.ini b/quantum/plugins/cisco/conf/credentials.ini deleted file mode 100644 index 96e912cc70..0000000000 --- a/quantum/plugins/cisco/conf/credentials.ini +++ /dev/null @@ -1,15 +0,0 @@ -#Provide the UCSM credentials -[] -username= -password= - -#Provide the Nova DB credentials, the IP address should be the same as in nova.ini -[] -username= -password= - -#Provide the Nexus credentials, if you are using Nexus -[] -username= -password= - diff --git a/quantum/plugins/cisco/conf/db_conn.ini b/quantum/plugins/cisco/conf/db_conn.ini deleted file mode 100644 index 28461f7663..0000000000 --- a/quantum/plugins/cisco/conf/db_conn.ini +++ /dev/null @@ -1,5 +0,0 @@ -[DATABASE] -name = quantum_l2network -user = -pass = -host = diff --git a/quantum/plugins/cisco/conf/l2network_plugin.ini b/quantum/plugins/cisco/conf/l2network_plugin.ini deleted file mode 100644 index 3a740a9713..0000000000 --- a/quantum/plugins/cisco/conf/l2network_plugin.ini +++ /dev/null @@ -1,16 +0,0 @@ -[VLANS] -vlan_start= -vlan_end= -vlan_name_prefix=q- - -[PORTS] -max_ports=100 - -[PORTPROFILES] -max_port_profiles=65568 - -[NETWORKS] -max_networks=65568 - -[MODEL] -model_class=quantum.plugins.cisco.l2network_model.L2NetworkModel diff --git a/quantum/plugins/cisco/conf/nexus.ini b/quantum/plugins/cisco/conf/nexus.ini deleted file mode 100644 index a4efcb2060..0000000000 --- a/quantum/plugins/cisco/conf/nexus.ini +++ /dev/null @@ -1,10 +0,0 @@ -[SWITCH] -# Change the following to reflect the Nexus switch details -nexus_ip_address= -#Port number of the Interface connected from the Nexus 7K Switch to UCSM 6120, e.g.: 3/23 -nexus_port= -#Port number where the SSH will be running at the Nexus Switch, e.g.: 22 (Default) -nexus_ssh_port=22 - -[DRIVER] -name=quantum.plugins.cisco.nexus.cisco_nexus_network_driver.CiscoNEXUSDriver diff --git a/quantum/plugins/cisco/conf/nova.ini b/quantum/plugins/cisco/conf/nova.ini deleted file mode 100644 index 7ef5d43968..0000000000 --- a/quantum/plugins/cisco/conf/nova.ini +++ /dev/null @@ -1,8 +0,0 @@ -[NOVA] -#Change the following details to reflect your OpenStack Nova configuration. If you are running this service on the same machine as the Nova DB, you do not have to change the IP address. -db_server_ip=127.0.0.1 -db_name=nova -db_username= -db_password= -nova_host_name= -nova_proj_name= diff --git a/quantum/plugins/cisco/conf/plugins.ini b/quantum/plugins/cisco/conf/plugins.ini deleted file mode 100644 index 8b4b476a0a..0000000000 --- a/quantum/plugins/cisco/conf/plugins.ini +++ /dev/null @@ -1,3 +0,0 @@ -[PLUGINS] -ucs_plugin=quantum.plugins.cisco.ucs.cisco_ucs_plugin.UCSVICPlugin -#nexus_plugin=quantum.plugins.cisco.nexus.cisco_nexus_plugin.NexusPlugin diff --git a/quantum/plugins/cisco/conf/ucs.ini b/quantum/plugins/cisco/conf/ucs.ini deleted file mode 100644 index 4310253131..0000000000 --- a/quantum/plugins/cisco/conf/ucs.ini +++ /dev/null @@ -1,10 +0,0 @@ -[UCSM] -#change the following to the appropriate UCSM IP address -ip_address= -default_vlan_name=default -default_vlan_id=1 -max_ucsm_port_profiles=1024 -profile_name_prefix=q- - -[DRIVER] -name=quantum.plugins.cisco.ucs.cisco_ucs_network_driver.CiscoUCSMDriver From 4de94fa15460636993f542551047d3d85e6e8c57 Mon Sep 17 00:00:00 2001 From: Ying Liu Date: Fri, 19 Aug 2011 00:41:25 -0700 Subject: [PATCH 16/52] remove ying's test ciscoplugin --- quantum/plugins/cisco/CiscoPlugin.py | 562 --------------------------- 1 file changed, 562 deletions(-) delete mode 100644 quantum/plugins/cisco/CiscoPlugin.py diff --git a/quantum/plugins/cisco/CiscoPlugin.py b/quantum/plugins/cisco/CiscoPlugin.py deleted file mode 100644 index 9300f34a2d..0000000000 --- a/quantum/plugins/cisco/CiscoPlugin.py +++ /dev/null @@ -1,562 +0,0 @@ -from quantum.common import exceptions as exc -from extensions import _exceptions as extexc - - -class CiscoPaloPlugin2(object): - """ - This plugin has internal data structure - derived from quantum fakeplugin - """ - - #static data for networks and ports - _port_dict_1 = { - 1: {'port-id': 1, - 'port-state': 'DOWN', - 'attachment': None, - 'portprofile': None}, - 2: {'port-id': 2, - 'port-state': 'UP', - 'attachment': None, - 'portprofile': None}} - _port_dict_2 = { - 1: {'port-id': 1, - 'port-state': 'UP', - 'attachment': 'SomeFormOfVIFID', - 'portprofile': '001'}, - 2: {'port-id': 2, - 'port-state': 'DOWN', - 'attachment': None, - 'portprofile': '001'}} - _networks = {'001': - { - 'net-id': '001', - 'net-name': 'pippotest', - 'net-ports': _port_dict_1}, - '002': - { - 'net-id': '002', - 'net-name': 'cicciotest', - 'net-ports': _port_dict_2}} - _portprofiles = {'001': - { - 'profile_id': '001', - 'profile_name': 'pprofiletest', - 'assignment': ['1', '2'], - 'qos_name': '001'}, - '002': - { - 'profile_id': '002', - 'profile_name': 'cicciotest', - 'qos_name': '002', - 'assignment': None}} - - _credentials = {'001': - { - 'credential_id': '001', - 'credential_name': 'cred1', - 'user_name': 'ying', - 'password': 'yingTest'}, - '002': - { - 'credential_id': '002', - 'credential_name': 'cred2', - 'user_name': 'admin', - 'password': 'adminTest'}} - _qoss = {'001': - { - 'qos_id': '001', - 'qos_name': 'silver', - 'qos_desc': {'pps':170, 'TTL':20}}, - '002': - { - 'qos_id': '002', - 'qos_name': 'gold', - 'qos_desc': {'pps':340, 'TTL':10}}} - - _host = {'host_list': { - "host_key1": "host_value1", - "host_key2": "host_value2"}} - _vif = {'vif_desc': { - "vif_key1": "vif_value1", - "vif_key2": "vif_value2"} - } - - - supported_extension_aliases = ["Cisco Credential", "Cisco Port Profile", "Cisco qos", "Cisco Nova Tenant"] - - - """ - def supports_extension(self, extension): - #return extension.get_alias() == "Cisco Port Profile" - return extension.get_alias() == "Cisco Credential" - """ - def __init__(self): - CiscoPaloPlugin2._net_counter = \ - len(CiscoPaloPlugin2._networks) - - CiscoPaloPlugin2._profile_counter = \ - len(CiscoPaloPlugin2._portprofiles) - - CiscoPaloPlugin2._credential_counter = \ - len(CiscoPaloPlugin2._credentials) - - CiscoPaloPlugin2._qos_counter = \ - len(CiscoPaloPlugin2._qoss) - def _get_network(self, tenant_id, network_id): - - network = CiscoPaloPlugin2._networks.get(network_id) - if not network: - raise exc.NetworkNotFound(net_id=network_id) - return network - - - - def _get_credential(self, tenant_id, credential_id): - credential = CiscoPaloPlugin2._credentials.get(credential_id) - if not credential: - raise extexc.CredentialNotFound(credential_id=credential_id) - return credential - - def _get_qos(self, tenant_id, qos_id): - qos = CiscoPaloPlugin2._qoss.get(qos_id) - if not qos: - raise extexc.QosNotFound(qos_id=qos_id) - return qos - - def _get_port(self, tenant_id, network_id, port_id): - net = self._get_network(tenant_id, network_id) - port = net['net-ports'].get(int(port_id)) - if not port: - raise exc.PortNotFound(net_id=network_id, port_id=port_id) - return port - - def _validate_port_state(self, port_state): - if port_state.upper() not in ('UP', 'DOWN'): - raise exc.StateInvalid(port_state=port_state) - return True - - def _validate_attachment(self, tenant_id, network_id, port_id, - remote_interface_id): - network = self._get_network(tenant_id, network_id) - for port in network['net-ports'].values(): - if port['attachment'] == remote_interface_id: - raise exc.AlreadyAttached(net_id=network_id, - port_id=port_id, - att_id=port['attachment'], - att_port_id=port['port-id']) - - def get_all_networks(self, tenant_id): - """ - Returns a dictionary containing all - for - the specified tenant. - """ - print("get_all_networks() called\n") - return CiscoPaloPlugin2._networks.values() - - def get_network_details(self, tenant_id, net_id): - """ - retrieved a list of all the remote vifs that - are attached to the network - """ - print("get_network_details() called\n") - return self._get_network(tenant_id, net_id) - - def create_network(self, tenant_id, net_name): - """ - Creates a new Virtual Network, and assigns it - a symbolic name. - """ - print("create_network() called\n") - CiscoPaloPlugin2._net_counter += 1 - new_net_id = ("0" * (3 - len(str(CiscoPaloPlugin2._net_counter)))) + \ - str(CiscoPaloPlugin2._net_counter) - print new_net_id - new_net_dict = {'net-id': new_net_id, - 'net-name': net_name, - 'net-ports': {}} - CiscoPaloPlugin2._networks[new_net_id] = new_net_dict - # return network_id of the created network - return new_net_dict - - def delete_network(self, tenant_id, net_id): - """ - Deletes the network with the specified network identifier - belonging to the specified tenant. - """ - print("delete_network() called\n") - net = CiscoPaloPlugin2._networks.get(net_id) - # Verify that no attachments are plugged into the network - if net: - if net['net-ports']: - for port in net['net-ports'].values(): - if port['attachment']: - raise exc.NetworkInUse(net_id=net_id) - CiscoPaloPlugin2._networks.pop(net_id) - return net - # Network not found - raise exc.NetworkNotFound(net_id=net_id) - - def rename_network(self, tenant_id, net_id, new_name): - """ - Updates the symbolic name belonging to a particular - Virtual Network. - """ - print("rename_network() called\n") - net = self._get_network(tenant_id, net_id) - net['net-name'] = new_name - return net - - def _get_portprofile(self, tenant_id, portprofile_id): - portprofile = CiscoPaloPlugin2._portprofiles.get(portprofile_id) - if not portprofile: - raise extexc.PortprofileNotFound(portprofile_id=portprofile_id) - return portprofile - - def get_all_portprofiles(self, tenant_id): - """ - Returns a dictionary containing all - for - the specified tenant. - """ - print("get_all_portprofiles() called\n") - return CiscoPaloPlugin2._portprofiles.values() - - def get_portprofile_details(self, tenant_id, profile_id): - """ - retrieved a list of all the remote vifs that - are attached to the portprofile - """ - print("get_portprofile_details() called\n") - return self._get_portprofile(tenant_id, profile_id) - - def create_portprofile(self, tenant_id, profile_name, vlan_id): - """ - Creates a new Virtual portprofile, and assigns it - a symbolic name. - """ - print("create_portprofile() called\n") - CiscoPaloPlugin2._profile_counter += 1 - new_profile_id = ("0" * \ - (3 - \ - len(str(CiscoPaloPlugin2._profile_counter)))) + \ - str(CiscoPaloPlugin2._profile_counter) - print new_profile_id - new_profile_dict = {'profile_id': new_profile_id, - 'profile_name': profile_name, - 'qos_name': vlan_id, - 'assignment': None} - CiscoPaloPlugin2._portprofiles[new_profile_id] = new_profile_dict - # return portprofile_id of the created portprofile - return new_profile_dict - - def delete_portprofile(self, tenant_id, profile_id): - """ - Deletes the portprofile with the specified portprofile identifier - belonging to the specified tenant. - """ - print("delete_portprofile() called\n") - profile = CiscoPaloPlugin2._portprofiles.get(profile_id) - # Verify that no attachments are plugged into the portprofile - if profile: - CiscoPaloPlugin2._portprofiles.pop(profile_id) - return profile - # portprofile not found - raise extexc.PortprofileNotFound(profile_id=profile_id) - - def rename_portprofile(self, tenant_id, profile_id, new_name): - """ - Updates the symbolic name belonging to a particular - Virtual portprofile. - """ - print("rename_portprofile() called\n") - profile = self._get_portprofile(tenant_id, profile_id) - profile['profile_name'] = new_name - return profile - - - - def associate_portprofile(self, tenant_id, net_id, port_id, pprofile_id): - """ - Assign portprofile to the specified port on the - specified Virtual Network. - """ - print("assign_portprofile() called\n") - print("net_id " + net_id) - # Validate attachment - #self._validate_attachment(tenant_id, net_id, port_id, - # remote_interface_id) - #TODO: modify the exception - port = self._get_port(tenant_id, net_id, port_id) - if (not port['portprofile'] == None): - raise exc.PortInUse(net_id=net_id, port_id=port_id, - att_id=port['portprofile']) - port['portprofile'] = pprofile_id - - def disassociate_portprofile(self, tenant_id, net_id, port_id, portprofile_id): - """ - De-assign a portprofile from the specified port on the - specified Virtual Network. - """ - print("deassign_portprofile() called\n") - #print("*******net_id is "+net_id) - port = self._get_port(tenant_id, net_id, port_id) - - port['portprofile'] = None - #TODO: - #modify assignment[portprofile_id] to remove this port - - #TODO: add new data structure to - #hold all the assignment for a specific portprofile - def get_portprofile_assignment(self, tenant_id, net_id, port_id): - print("get portprofile assignment called\n") - port = self._get_port(tenant_id, net_id, port_id) - ppid = port['portprofile'] - if (ppid == None): - print("***no portprofile attached") - return "no portprofile attached" - else: - print("***attached portprofile id is " + ppid) - return ("attached portprofile " + ppid) - - - def get_all_credentials(self, tenant_id): - """ - Returns a dictionary containing all - for - the specified tenant. - """ - print("get_all_credentials() called\n") - return CiscoPaloPlugin2._credentials.values() - - def get_credential_details(self, tenant_id, credential_id): - """ - retrieved a list of all the remote vifs that - are attached to the credential - """ - print("get_credential_details() called\n") - return self._get_credential(tenant_id, credential_id) - - def create_credential(self, tenant_id, credential_name, user_name, password): - """ - Creates a new Virtual credential, and assigns it - a symbolic name. - """ - print("create_credential() called\n") - CiscoPaloPlugin2._credential_counter += 1 - new_credential_id = ("0" * \ - (3 - \ - len(str(CiscoPaloPlugin2._credential_counter)))) + \ - str(CiscoPaloPlugin2._credential_counter) - print new_credential_id - new_credential_dict = {'credential_id': new_credential_id, - 'credential_name': credential_name, - 'user_name': user_name, - 'password': password} - CiscoPaloPlugin2._credentials[new_credential_id] = new_credential_dict - # return credential_id of the created credential - return new_credential_dict - - def delete_credential(self, tenant_id, credential_id): - """ - Deletes the credential with the specified credential identifier - belonging to the specified tenant. - """ - print("delete_credential() called\n") - credential = CiscoPaloPlugin2._credentials.get(credential_id) - - if credential: - CiscoPaloPlugin2._credentials.pop(credential_id) - return credential - # credential not found - raise extexc.CredentialNotFound(credential_id=credential_id) - - def rename_credential(self, tenant_id, credential_id, new_name): - """ - Updates the symbolic name belonging to a particular - Virtual credential. - """ - print("rename_credential() called\n") - credential = self._get_credential(tenant_id, credential_id) - credential['credential_name'] = new_name - return credential - - - def get_all_qoss(self, tenant_id): - """ - Returns a dictionary containing all - for - the specified tenant. - """ - print("get_all_qoss() called\n") - return CiscoPaloPlugin2._qoss.values() - - def get_qos_details(self, tenant_id, qos_id): - """ - retrieved a list of all the remote vifs that - are attached to the qos - """ - print("get_qos_details() called\n") - return self._get_qos(tenant_id, qos_id) - - def create_qos(self, tenant_id, qos_name, qos_desc): - """ - Creates a new Virtual qos, and assigns it - a symbolic name. - """ - print("create_qos() called\n") - CiscoPaloPlugin2._qos_counter += 1 - new_qos_id = ("0" * \ - (3 - \ - len(str(CiscoPaloPlugin2._qos_counter)))) + \ - str(CiscoPaloPlugin2._qos_counter) - print new_qos_id - new_qos_dict = {'qos_id': new_qos_id, - 'qos_name': qos_name, - 'qos_desc': qos_desc} - - print("************************") - print("test dictionary data") - print(qos_desc['TTL']) - print("************************") - - CiscoPaloPlugin2._qoss[new_qos_id] = new_qos_dict - # return qos_id of the created qos - return new_qos_dict - - def delete_qos(self, tenant_id, qos_id): - """ - Deletes the qos with the specified qos identifier - belonging to the specified tenant. - """ - print("delete_qos() called\n") - qos = CiscoPaloPlugin2._qoss.get(qos_id) - # Verify that no attachments are plugged into the qos - if qos: - CiscoPaloPlugin2._qoss.pop(qos_id) - return qos - # qos not found - raise extexc.QosNotFound(qos_id=qos_id) - - def rename_qos(self, tenant_id, qos_id, new_name): - """ - Updates the symbolic name belonging to a particular - Virtual qos. - """ - print("rename_qos() called\n") - qos = self._get_qos(tenant_id, qos_id) - qos['qos_name'] = new_name - return qos - - - - - def get_all_ports(self, tenant_id, net_id): - """ - Retrieves all port identifiers belonging to the - specified Virtual Network. - """ - print("get_all_ports() called\n") - network = self._get_network(tenant_id, net_id) - ports_on_net = network['net-ports'].values() - return ports_on_net - - def get_port_details(self, tenant_id, net_id, port_id): - """ - This method allows the user to retrieve a remote interface - that is attached to this particular port. - """ - print("get_port_details() called\n") - return self._get_port(tenant_id, net_id, port_id) - - def create_port(self, tenant_id, net_id, port_state=None): - """ - Creates a port on the specified Virtual Network. - """ - print("create_port() called\n") - net = self._get_network(tenant_id, net_id) - # check port state - # TODO(salvatore-orlando): Validate port state in API? - self._validate_port_state(port_state) - ports = net['net-ports'] - new_port_id = max(ports.keys()) + 1 - new_port_dict = {'port-id': new_port_id, - 'port-state': port_state, - 'attachment': None, - 'portprofile': None} - ports[new_port_id] = new_port_dict - return new_port_dict - - def update_port(self, tenant_id, net_id, port_id, port_state): - """ - Updates the state of a port on the specified Virtual Network. - """ - print("create_port() called\n") - port = self._get_port(tenant_id, net_id, port_id) - self._validate_port_state(port_state) - port['port-state'] = port_state - return port - - def delete_port(self, tenant_id, net_id, port_id): - """ - Deletes a port on a specified Virtual Network, - if the port contains a remote interface attachment, - the remote interface is first un-plugged and then the port - is deleted. - """ - print("delete_port() called\n") - net = self._get_network(tenant_id, net_id) - port = self._get_port(tenant_id, net_id, port_id) - if port['attachment']: - raise exc.PortInUse(net_id=net_id, port_id=port_id, - att_id=port['attachment']) - try: - net['net-ports'].pop(int(port_id)) - except KeyError: - raise exc.PortNotFound(net_id=net_id, port_id=port_id) - - def get_interface_details(self, tenant_id, net_id, port_id): - print("get interface detail called\n") - port = self._get_port(tenant_id, net_id, port_id) - vid = port['attachment'] - if (vid == None): - print("***no interface is attached") - return "no interface attached" - else: - print("***interface id is " + vid) - return ("attached interface " + vid) - - def plug_interface(self, tenant_id, net_id, port_id, remote_interface_id): - """ - Attaches a remote interface to the specified port on the - specified Virtual Network. - """ - print("plug_interface() called\n") - # Validate attachment - self._validate_attachment(tenant_id, net_id, port_id, - remote_interface_id) - port = self._get_port(tenant_id, net_id, port_id) - if port['attachment']: - raise exc.PortInUse(net_id=net_id, port_id=port_id, - att_id=port['attachment']) - port['attachment'] = remote_interface_id - - def unplug_interface(self, tenant_id, net_id, port_id): - """ - Detaches a remote interface from the specified port on the - specified Virtual Network. - """ - print("unplug_interface() called\n") - port = self._get_port(tenant_id, net_id, port_id) - # TODO(salvatore-orlando): - # Should unplug on port without attachment raise an Error? - port['attachment'] = None - - def get_host(self, tenant_id, instance_id, instance_desc): - print("associate an instance to a port....") - print("get key2: " + instance_desc['key2']) - return CiscoPaloPlugin2._host - def get_instance_port(self, tenant_id, instance_id, instance_desc): - print("get instance associated port....") - print("get key1: " + instance_desc['key1']) - return CiscoPaloPlugin2._vif \ No newline at end of file From 1caa7874b02899d80f0b0ddffef0bbca12ed231c Mon Sep 17 00:00:00 2001 From: Ying Liu Date: Fri, 19 Aug 2011 08:00:37 -0700 Subject: [PATCH 17/52] add all conf/*.ini back --- quantum/plugins/cisco/conf/credentials.ini | 15 +++++++++++++++ quantum/plugins/cisco/conf/db_conn.ini | 5 +++++ quantum/plugins/cisco/conf/l2network_plugin.ini | 16 ++++++++++++++++ quantum/plugins/cisco/conf/nexus.ini | 10 ++++++++++ quantum/plugins/cisco/conf/nova.ini | 8 ++++++++ quantum/plugins/cisco/conf/plugins.ini | 3 +++ quantum/plugins/cisco/conf/ucs.ini | 10 ++++++++++ 7 files changed, 67 insertions(+) create mode 100644 quantum/plugins/cisco/conf/credentials.ini create mode 100644 quantum/plugins/cisco/conf/db_conn.ini create mode 100644 quantum/plugins/cisco/conf/l2network_plugin.ini create mode 100644 quantum/plugins/cisco/conf/nexus.ini create mode 100644 quantum/plugins/cisco/conf/nova.ini create mode 100644 quantum/plugins/cisco/conf/plugins.ini create mode 100644 quantum/plugins/cisco/conf/ucs.ini diff --git a/quantum/plugins/cisco/conf/credentials.ini b/quantum/plugins/cisco/conf/credentials.ini new file mode 100644 index 0000000000..96e912cc70 --- /dev/null +++ b/quantum/plugins/cisco/conf/credentials.ini @@ -0,0 +1,15 @@ +#Provide the UCSM credentials +[] +username= +password= + +#Provide the Nova DB credentials, the IP address should be the same as in nova.ini +[] +username= +password= + +#Provide the Nexus credentials, if you are using Nexus +[] +username= +password= + diff --git a/quantum/plugins/cisco/conf/db_conn.ini b/quantum/plugins/cisco/conf/db_conn.ini new file mode 100644 index 0000000000..4a5d7e3713 --- /dev/null +++ b/quantum/plugins/cisco/conf/db_conn.ini @@ -0,0 +1,5 @@ +[DATABASE] +name = quantum_l2network +user = +pass = +host = diff --git a/quantum/plugins/cisco/conf/l2network_plugin.ini b/quantum/plugins/cisco/conf/l2network_plugin.ini new file mode 100644 index 0000000000..3a740a9713 --- /dev/null +++ b/quantum/plugins/cisco/conf/l2network_plugin.ini @@ -0,0 +1,16 @@ +[VLANS] +vlan_start= +vlan_end= +vlan_name_prefix=q- + +[PORTS] +max_ports=100 + +[PORTPROFILES] +max_port_profiles=65568 + +[NETWORKS] +max_networks=65568 + +[MODEL] +model_class=quantum.plugins.cisco.l2network_model.L2NetworkModel diff --git a/quantum/plugins/cisco/conf/nexus.ini b/quantum/plugins/cisco/conf/nexus.ini new file mode 100644 index 0000000000..a4efcb2060 --- /dev/null +++ b/quantum/plugins/cisco/conf/nexus.ini @@ -0,0 +1,10 @@ +[SWITCH] +# Change the following to reflect the Nexus switch details +nexus_ip_address= +#Port number of the Interface connected from the Nexus 7K Switch to UCSM 6120, e.g.: 3/23 +nexus_port= +#Port number where the SSH will be running at the Nexus Switch, e.g.: 22 (Default) +nexus_ssh_port=22 + +[DRIVER] +name=quantum.plugins.cisco.nexus.cisco_nexus_network_driver.CiscoNEXUSDriver diff --git a/quantum/plugins/cisco/conf/nova.ini b/quantum/plugins/cisco/conf/nova.ini new file mode 100644 index 0000000000..7ef5d43968 --- /dev/null +++ b/quantum/plugins/cisco/conf/nova.ini @@ -0,0 +1,8 @@ +[NOVA] +#Change the following details to reflect your OpenStack Nova configuration. If you are running this service on the same machine as the Nova DB, you do not have to change the IP address. +db_server_ip=127.0.0.1 +db_name=nova +db_username= +db_password= +nova_host_name= +nova_proj_name= diff --git a/quantum/plugins/cisco/conf/plugins.ini b/quantum/plugins/cisco/conf/plugins.ini new file mode 100644 index 0000000000..8b4b476a0a --- /dev/null +++ b/quantum/plugins/cisco/conf/plugins.ini @@ -0,0 +1,3 @@ +[PLUGINS] +ucs_plugin=quantum.plugins.cisco.ucs.cisco_ucs_plugin.UCSVICPlugin +#nexus_plugin=quantum.plugins.cisco.nexus.cisco_nexus_plugin.NexusPlugin diff --git a/quantum/plugins/cisco/conf/ucs.ini b/quantum/plugins/cisco/conf/ucs.ini new file mode 100644 index 0000000000..4310253131 --- /dev/null +++ b/quantum/plugins/cisco/conf/ucs.ini @@ -0,0 +1,10 @@ +[UCSM] +#change the following to the appropriate UCSM IP address +ip_address= +default_vlan_name=default +default_vlan_id=1 +max_ucsm_port_profiles=1024 +profile_name_prefix=q- + +[DRIVER] +name=quantum.plugins.cisco.ucs.cisco_ucs_network_driver.CiscoUCSMDriver From 4a8599cc90373a3a4f5ebc04869f3e1a02bc23fd Mon Sep 17 00:00:00 2001 From: Ying Liu Date: Fri, 19 Aug 2011 08:14:17 -0700 Subject: [PATCH 18/52] add plugins.ini back --- quantum/plugins.ini | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 quantum/plugins.ini diff --git a/quantum/plugins.ini b/quantum/plugins.ini new file mode 100644 index 0000000000..307d2b48d2 --- /dev/null +++ b/quantum/plugins.ini @@ -0,0 +1,3 @@ +[PLUGIN] +# Quantum plugin provider module +provider = quantum.plugins.SamplePlugin.FakePlugin From 84d0f0a4f7b280cdab2cb84773aaa10416a738c1 Mon Sep 17 00:00:00 2001 From: rohitagarwalla Date: Fri, 19 Aug 2011 09:06:43 -0700 Subject: [PATCH 19/52] added nexus exception in cisco_exceptions.py added log to methods in l2network_db.py added nexus_db.py and nexus_models.py - persistence modules for nexus plugin --- .../plugins/cisco/common/cisco_exceptions.py | 5 + quantum/plugins/cisco/db/l2network_db.py | 26 +++- quantum/plugins/cisco/db/nexus_db.py | 93 +++++++++++++ quantum/plugins/cisco/db/nexus_models.py | 40 ++++++ .../plugins/cisco/tests/unit/test_database.py | 131 ++++++++++++++++++ 5 files changed, 293 insertions(+), 2 deletions(-) create mode 100644 quantum/plugins/cisco/db/nexus_db.py create mode 100644 quantum/plugins/cisco/db/nexus_models.py diff --git a/quantum/plugins/cisco/common/cisco_exceptions.py b/quantum/plugins/cisco/common/cisco_exceptions.py index 176e74ba1c..472b6647fc 100644 --- a/quantum/plugins/cisco/common/cisco_exceptions.py +++ b/quantum/plugins/cisco/common/cisco_exceptions.py @@ -105,6 +105,11 @@ class CredentialNotFound(exceptions.QuantumException): "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") except NameError: diff --git a/quantum/plugins/cisco/db/l2network_db.py b/quantum/plugins/cisco/db/l2network_db.py index b2198c8eb8..8f85afb55e 100644 --- a/quantum/plugins/cisco/db/l2network_db.py +++ b/quantum/plugins/cisco/db/l2network_db.py @@ -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 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: vlanids = session.query(l2network_models.VlanID).\ @@ -125,6 +132,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).\ @@ -136,6 +144,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).\ @@ -148,6 +157,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).\ @@ -164,6 +174,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).\ @@ -178,6 +189,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).\ @@ -196,6 +208,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).\ @@ -207,6 +220,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).\ @@ -220,6 +234,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).\ @@ -236,6 +251,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).\ @@ -248,9 +264,10 @@ def remove_portprofile(tenantid, ppid): pass -def update_portprofile(tenantid, ppid, newppname=None, newvlanid=None, +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).\ @@ -272,6 +289,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).\ @@ -283,6 +301,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).\ @@ -295,6 +314,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).\ @@ -312,6 +332,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).\ @@ -325,9 +346,10 @@ def remove_pp_binding(tenantid, portid, ppid): pass -def update_pp_binding(tenantid, ppid, newtenantid=None, newportid=None, +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).\ diff --git a/quantum/plugins/cisco/db/nexus_db.py b/quantum/plugins/cisco/db/nexus_db.py new file mode 100644 index 0000000000..054ad6b2ed --- /dev/null +++ b/quantum/plugins/cisco/db/nexus_db.py @@ -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 +import nexus_models + +from quantum.plugins.cisco.common import cisco_exceptions as c_exc + + +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() diff --git a/quantum/plugins/cisco/db/nexus_models.py b/quantum/plugins/cisco/db/nexus_models.py new file mode 100644 index 0000000000..51a210990d --- /dev/null +++ b/quantum/plugins/cisco/db/nexus_models.py @@ -0,0 +1,40 @@ +# 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, ForeignKey("vlan_bindings.vlan_id"), \ + # nullable=False) + 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 "" % \ + (self.port_id, self.vlan_id) diff --git a/quantum/plugins/cisco/tests/unit/test_database.py b/quantum/plugins/cisco/tests/unit/test_database.py index 63b900d8dc..eac638234a 100644 --- a/quantum/plugins/cisco/tests/unit/test_database.py +++ b/quantum/plugins/cisco/tests/unit/test_database.py @@ -26,11 +26,78 @@ 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, port_id): + """get nexus port binding""" + binding = [] + try: + for bind in nexus_db.get_nexusport_binding(port_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(bind.port_id) + bind_dict["vlan-id"] = str(bind.vlan_id) + return bind_dict + except Exception, exc: + LOG.error("Failed to create ucsm binding: %s" % str(exc)) + + def delete_nexusportbinding(self, port_id): + """delete nexus port binding""" + try: + res = nexus_db.remove_nexusport_binding(port_id) + LOG.debug("Deleted nexus port binding : %s" % res.port_id) + bind_dict = {} + bind_dict["port-id"] = str(res.port_id) + return bind_dict + except Exception, exc: + raise Exception("Failed to delete dynamic vnic: %s" % str(exc)) + + def update_nexusportbinding(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(bind.port_id) + bind_dict["vlan-id"] = str(bind.vlan_id) + return bind_dict + except Exception, exc: + raise Exception("Failed to update dynamic vnic: %s" % str(exc)) + + class L2networkDB(object): """Class conisting of methods to call L2network db methods""" def get_all_vlan_bindings(self): @@ -422,6 +489,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 ucs 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(binding1["port-id"]) + 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_nexusportbinding(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 ucsm binding table""" + LOG.debug("Tearing Down Nexus port Bindings") + binds = self.dbtest.get_all_nexusportbindings() + for bind in binds: + port_id = bind["port-id"] + self.dbtest.delete_nexusportbinding(port_id) + + class L2networkDBTest(unittest.TestCase): """Class conisting of L2network DB unit tests""" def setUp(self): From ea89f123382617f0c86843b63ae1ed6c162a48d0 Mon Sep 17 00:00:00 2001 From: Edgar Magana Date: Fri, 19 Aug 2011 10:13:53 -0700 Subject: [PATCH 20/52] Adding the Nexus support to the Persistence Framwork Modification of the Nexus Unit Case to be running with Persistence Framework pep8 passed pylint 8.81/10 --- quantum/plugins/cisco/README | 7 ++++--- quantum/plugins/cisco/conf/nexus.ini | 5 +++-- .../cisco/nexus/cisco_nexus_configuration.py | 3 ++- .../cisco/nexus/cisco_nexus_network_driver.py | 14 +++++++++----- .../plugins/cisco/nexus/cisco_nexus_plugin.py | 17 +++++++++++++---- .../cisco/tests/unit/test_nexus_plugin.py | 3 ++- 6 files changed, 33 insertions(+), 16 deletions(-) diff --git a/quantum/plugins/cisco/README b/quantum/plugins/cisco/README index 2ef3a0c082..f7674401a0 100755 --- a/quantum/plugins/cisco/README +++ b/quantum/plugins/cisco/README @@ -118,9 +118,10 @@ 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 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 the SSH will be running at Nexus Switch, e.g.: 22 (Default) nexus_ssh_port=22 diff --git a/quantum/plugins/cisco/conf/nexus.ini b/quantum/plugins/cisco/conf/nexus.ini index a4efcb2060..50d8e54beb 100644 --- a/quantum/plugins/cisco/conf/nexus.ini +++ b/quantum/plugins/cisco/conf/nexus.ini @@ -1,8 +1,9 @@ [SWITCH] # Change the following to reflect the Nexus switch details nexus_ip_address= -#Port number of the Interface connected from the Nexus 7K Switch to UCSM 6120, e.g.: 3/23 -nexus_port= +#Interfaces connected from the Nexus 7K Switch to the two UCSM 6120s, e.g.: 1/10 and 1/11 +nexus_first_port= +nexus_second_port= #Port number where the SSH will be running at the Nexus Switch, e.g.: 22 (Default) nexus_ssh_port=22 diff --git a/quantum/plugins/cisco/nexus/cisco_nexus_configuration.py b/quantum/plugins/cisco/nexus/cisco_nexus_configuration.py index f0394dcb24..13457e7da3 100644 --- a/quantum/plugins/cisco/nexus/cisco_nexus_configuration.py +++ b/quantum/plugins/cisco/nexus/cisco_nexus_configuration.py @@ -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'] diff --git a/quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py b/quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py index 3f92353492..f533c9f766 100644 --- a/quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py +++ b/quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py @@ -103,7 +103,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 @@ -111,10 +112,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 @@ -122,4 +125,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) diff --git a/quantum/plugins/cisco/nexus/cisco_nexus_plugin.py b/quantum/plugins/cisco/nexus/cisco_nexus_plugin.py index 84085ff3f0..62f3806f32 100644 --- a/quantum/plugins/cisco/nexus/cisco_nexus_plugin.py +++ b/quantum/plugins/cisco/nexus/cisco_nexus_plugin.py @@ -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 diff --git a/quantum/plugins/cisco/tests/unit/test_nexus_plugin.py b/quantum/plugins/cisco/tests/unit/test_nexus_plugin.py index d77985b175..e9f95f1fca 100644 --- a/quantum/plugins/cisco/tests/unit/test_nexus_plugin.py +++ b/quantum/plugins/cisco/tests/unit/test_nexus_plugin.py @@ -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') @@ -34,6 +35,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 +68,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) From 47da978a3ddf42591339fe5f2250b119459796e1 Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Fri, 19 Aug 2011 10:55:46 -0700 Subject: [PATCH 21/52] Raising exceptions in extension resources handling (where missing). --- quantum/plugins/cisco/l2network_plugin.py | 56 ++++++++++++++++++----- 1 file changed, 45 insertions(+), 11 deletions(-) diff --git a/quantum/plugins/cisco/l2network_plugin.py b/quantum/plugins/cisco/l2network_plugin.py index 29fc354242..21fd16fd0d 100644 --- a/quantum/plugins/cisco/l2network_plugin.py +++ b/quantum/plugins/cisco/l2network_plugin.py @@ -275,7 +275,12 @@ class L2Network(QuantumPluginBase): def get_portprofile_details(self, tenant_id, profile_id): """Get port profile details""" LOG.debug("get_portprofile_details() called\n") - portprofile = cdb.get_portprofile(tenant_id, profile_id) + 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], @@ -291,7 +296,6 @@ class L2Network(QuantumPluginBase): portprofile[const.UUID], portprofile[const.PPNAME], portprofile[const.PPQOS]) - print("***Sumit: %s\n", new_pp) return new_pp def delete_portprofile(self, tenant_id, profile_id): @@ -299,7 +303,7 @@ class L2Network(QuantumPluginBase): 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) @@ -315,7 +319,7 @@ class L2Network(QuantumPluginBase): 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) @@ -331,7 +335,7 @@ class L2Network(QuantumPluginBase): 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) @@ -343,7 +347,7 @@ class L2Network(QuantumPluginBase): 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) @@ -372,7 +376,12 @@ class L2Network(QuantumPluginBase): def get_qos_details(self, tenant_id, qos_id): """Get QoS Details""" LOG.debug("get_qos_details() called\n") - return self._get_qos_level(tenant_id, qos_id) + try: + qos_level = self._get_qos_level(tenant_id, qos_id) + except Exception, excp: + raise cexc.QoSLevelNotFound(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""" @@ -388,7 +397,11 @@ class L2Network(QuantumPluginBase): def delete_qos(self, tenant_id, qos_id): """Delete a QoS level""" LOG.debug("delete_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.QoSLevelNotFound(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, @@ -400,6 +413,11 @@ class L2Network(QuantumPluginBase): """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.QoSLevelNotFound(tenant_id=tenant_id, + qos_id=qos_id) qos_level[const.QOS_LEVEL_NAME] = new_name return qos_level @@ -411,7 +429,12 @@ class L2Network(QuantumPluginBase): def get_credential_details(self, tenant_id, credential_id): """Get a particular credential""" LOG.debug("get_credential_details() called\n") - return self._get_credential(tenant_id, credential_id) + 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): @@ -430,14 +453,25 @@ class L2Network(QuantumPluginBase): def delete_credential(self, tenant_id, credential_id): """Delete a credential""" LOG.debug("delete_credential() called\n") - credential = self._get_credential(tenant_id, credential_id) + 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): """Do nothing for this resource""" LOG.debug("rename_credential() called\n") - pass + 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""" From 7d11fe01f1ae815dae7ac8b17c1dae16684bb207 Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Fri, 19 Aug 2011 11:02:53 -0700 Subject: [PATCH 22/52] Changing exception name to QosNotFound. --- quantum/plugins/cisco/common/cisco_exceptions.py | 2 +- quantum/plugins/cisco/l2network_plugin.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/quantum/plugins/cisco/common/cisco_exceptions.py b/quantum/plugins/cisco/common/cisco_exceptions.py index 472b6647fc..a50e2c86b2 100644 --- a/quantum/plugins/cisco/common/cisco_exceptions.py +++ b/quantum/plugins/cisco/common/cisco_exceptions.py @@ -90,7 +90,7 @@ class VlanIDNotAvailable(exceptions.QuantumException): message = _("No available Vlan ID found") -class QoSLevelNotFound(exceptions.QuantumException): +class QosNotFound(exceptions.QuantumException): message = _("QoS level %(qos_id)s could not be found " \ "for tenant %(tenant_id)s") diff --git a/quantum/plugins/cisco/l2network_plugin.py b/quantum/plugins/cisco/l2network_plugin.py index 21fd16fd0d..6a0f7a5686 100644 --- a/quantum/plugins/cisco/l2network_plugin.py +++ b/quantum/plugins/cisco/l2network_plugin.py @@ -379,7 +379,7 @@ class L2Network(QuantumPluginBase): try: qos_level = self._get_qos_level(tenant_id, qos_id) except Exception, excp: - raise cexc.QoSLevelNotFound(tenant_id=tenant_id, + raise cexc.QosNotFound(tenant_id=tenant_id, qos_id=qos_id) return qos_level @@ -400,7 +400,7 @@ class L2Network(QuantumPluginBase): try: qos_level = self._get_qos_level(tenant_id, qos_id) except Exception, excp: - raise cexc.QoSLevelNotFound(tenant_id=tenant_id, + raise cexc.QosNotFound(tenant_id=tenant_id, qos_id=qos_id) associations = qos_level[const.QOS_LEVEL_ASSOCIATIONS] if len(associations) > 0: @@ -416,7 +416,7 @@ class L2Network(QuantumPluginBase): try: qos_level = self._get_qos_level(tenant_id, qos_id) except Exception, excp: - raise cexc.QoSLevelNotFound(tenant_id=tenant_id, + raise cexc.QosNotFound(tenant_id=tenant_id, qos_id=qos_id) qos_level[const.QOS_LEVEL_NAME] = new_name return qos_level @@ -565,7 +565,7 @@ class L2Network(QuantumPluginBase): """Return a QoS level based on the ID""" qos_level = self._qos_levels.get(qos_id) if not qos_level: - raise cexc.QoSLevelNotFound(tenant_id=tenant_id, + raise cexc.QosNotFound(tenant_id=tenant_id, qos_id=qos_id) return qos_level From 7b215b44d8c19c1ca5172c78b8ea7963bcad1b75 Mon Sep 17 00:00:00 2001 From: Ying Liu Date: Fri, 19 Aug 2011 13:37:33 -0700 Subject: [PATCH 23/52] replace exception handler by using cisco_exceptions --- extensions/credential.py | 3 ++- extensions/novatenant.py | 11 ++++------- extensions/portprofile.py | 18 ++++++++++-------- extensions/qos.py | 3 ++- 4 files changed, 18 insertions(+), 17 deletions(-) diff --git a/extensions/credential.py b/extensions/credential.py index 8b51c81c2d..85043940b4 100644 --- a/extensions/credential.py +++ b/extensions/credential.py @@ -22,7 +22,8 @@ import logging from webob import exc from extensions import _credential_view as credential_view -from extensions import _exceptions as exception +from quantum.plugins.cisco.common import cisco_exceptions as exception +#from extensions import _exceptions as exception from extensions import _faults as faults from quantum.api import api_common as common diff --git a/extensions/novatenant.py b/extensions/novatenant.py index eddab4c17f..5cbfc4bd0a 100644 --- a/extensions/novatenant.py +++ b/extensions/novatenant.py @@ -21,7 +21,8 @@ from webob import exc from extensions import _novatenant_view as novatenant_view -from extensions import _exceptions as exception +from quantum.common import exceptions as qexception +#from extensions import _exceptions as exception from extensions import _faults as faults from quantum.api import api_common as common @@ -144,9 +145,7 @@ class NovatenantsController(common.QuantumController): result = builder.build_host(host) return result #return exc.HTTPAccepted() - except exception.NovatenantNotFound as exp: - return faults.Fault(faults.NovatenantNotFound(exp)) - except exception.PortNotFound as exp: + except qexception.PortNotFound as exp: return faults.Fault(faults.PortNotFound(exp)) def get_instance_port(self, request, tenant_id, id): @@ -169,7 +168,5 @@ class NovatenantsController(common.QuantumController): result = builder.build_vif(vif) return result - except exception.NovatenantNotFound as exp: - return faults.Fault(faults.NovatenantNotFound(exp)) - except exception.PortNotFound as exp: + except qexception.PortNotFound as exp: return faults.Fault(faults.PortNotFound(exp)) diff --git a/extensions/portprofile.py b/extensions/portprofile.py index 8186f6903d..b0fbb65dd6 100644 --- a/extensions/portprofile.py +++ b/extensions/portprofile.py @@ -22,7 +22,9 @@ from webob import exc from extensions import _pprofiles as pprofiles_view -from extensions import _exceptions as exception +from quantum.plugins.cisco.common import cisco_exceptions as exception +from quantum.common import exceptions as qexception +#from extensions import _exceptions as exception from extensions import _faults as faults from quantum.api import api_common as common @@ -126,7 +128,7 @@ class PortprofilesController(common.QuantumController): #build response with details result = builder.build(portprofile, True) return dict(portprofiles=result) - except exception.PortprofileNotFound as exp: + except exception.PortProfileNotFound as exp: return faults.Fault(faults.PortprofileNotFound(exp)) #return faults.Fault(exp) @@ -163,7 +165,7 @@ class PortprofilesController(common.QuantumController): builder = pprofiles_view.get_view_builder(request) result = builder.build(portprofile, True) return dict(portprofiles=result) - except exception.PortprofileNotFound as exp: + except exception.PortProfileNotFound as exp: return faults.Fault(faults.PortprofileNotFound(exp)) def delete(self, request, tenant_id, id): @@ -171,7 +173,7 @@ class PortprofilesController(common.QuantumController): try: self._plugin.delete_portprofile(tenant_id, id) return exc.HTTPAccepted() - except exception.PortprofileNotFound as exp: + except exception.PortProfileNotFound as exp: return faults.Fault(faults.PortprofileNotFound(exp)) def associate_portprofile(self, request, tenant_id, id): @@ -193,9 +195,9 @@ class PortprofilesController(common.QuantumController): net_id, port_id, id) return exc.HTTPAccepted() - except exception.PortprofileNotFound as exp: + except exception.PortProfileNotFound as exp: return faults.Fault(faults.PortprofileNotFound(exp)) - except exception.PortNotFound as exp: + except qexception.PortNotFound as exp: return faults.Fault(faults.PortNotFound(exp)) def disassociate_portprofile(self, request, tenant_id, id): @@ -217,7 +219,7 @@ class PortprofilesController(common.QuantumController): disassociate_portprofile(tenant_id, net_id, port_id, id) return exc.HTTPAccepted() - except exception.PortprofileNotFound as exp: + except exception.PortProfileNotFound as exp: return faults.Fault(faults.PortprofileNotFound(exp)) - except exception.PortNotFound as exp: + except qexception.PortNotFound as exp: return faults.Fault(faults.PortNotFound(exp)) diff --git a/extensions/qos.py b/extensions/qos.py index a11f41af77..3c0f3da782 100644 --- a/extensions/qos.py +++ b/extensions/qos.py @@ -22,7 +22,8 @@ import logging from webob import exc from extensions import _qos_view as qos_view -from extensions import _exceptions as exception +from quantum.plugins.cisco.common import cisco_exceptions as exception +from extensions import _exceptions as exte from extensions import _faults as faults from quantum.api import api_common as common From dca478bd025ea3af28b3eae9362a0baf868b4576 Mon Sep 17 00:00:00 2001 From: Shweta P Date: Fri, 19 Aug 2011 19:42:04 -0700 Subject: [PATCH 24/52] Adding Entension API unt tests --- etc/quantum.conf.mocktest | 24 + quantum/plugins/cisco/README | 7 +- .../cisco/tests/unit/test_cisco_extension.py | 849 ++++++++++++++++++ 3 files changed, 878 insertions(+), 2 deletions(-) create mode 100644 etc/quantum.conf.mocktest create mode 100644 quantum/plugins/cisco/tests/unit/test_cisco_extension.py diff --git a/etc/quantum.conf.mocktest b/etc/quantum.conf.mocktest new file mode 100644 index 0000000000..d094b89d00 --- /dev/null +++ b/etc/quantum.conf.mocktest @@ -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 = tests.unit.test_mockext:app_factory diff --git a/quantum/plugins/cisco/README b/quantum/plugins/cisco/README index f7674401a0..e15c9ac389 100755 --- a/quantum/plugins/cisco/README +++ b/quantum/plugins/cisco/README @@ -206,7 +206,7 @@ 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): @@ -217,7 +217,10 @@ result the quantum/plugins/cisco/run_tests.py script. 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 Additional installation required on Nova Compute ------------------------------------------------ diff --git a/quantum/plugins/cisco/tests/unit/test_cisco_extension.py b/quantum/plugins/cisco/tests/unit/test_cisco_extension.py new file mode 100644 index 0000000000..14f614c6e9 --- /dev/null +++ b/quantum/plugins/cisco/tests/unit/test_cisco_extension.py @@ -0,0 +1,849 @@ +# 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 json +import os.path +import routes +import unittest +import logging +import webob +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, + 'etc', 'quantum.conf.mocktest') +EXTENSIONS_PATH = os.path.join(os.path.dirname(__file__), os.pardir, + os.pardir, + "extensions") + +LOG = logging.getLogger('quantum.plugins.cisco.tests.test_cisco_extensions') + + +class ExtensionsTestApp(wsgi.Router): + + def __init__(self, options={}): + 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): + parent_resource = dict(member_name="tenant", + collection_name="extensions/csco/tenants") + member_actions = {'associate_portprofile': "PUT", + 'disassociate_portprofile': "POST"} + 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): + + 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): + + 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): + + 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): + + 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'): + + 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): + + 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): + + 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'): + + 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): + + 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'): + + 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'): + + 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): + + 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): + + 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): + + 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'): + + 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): + + 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.post( + 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): + self.test_app.delete(delete_profile_path) + + def tear_down_associate_profile(self, delete_profile_path, + dissociate_profile_path, req_body): + self.test_app.post(dissociate_profile_path, req_body, + content_type=self.contenttype) + self.tear_down_profile(delete_profile_path) + + def tearDown(self): + db.clear_db() + + +class NovatenantExtensionTest(unittest.TestCase): + + def setUp(self): + 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): + 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): + 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): + 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): + + 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): + + 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): + + 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): + 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): + 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'): + 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): + + 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'): + 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): + 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): + + 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'): + 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): + self.test_app.delete(delete_profile_path) + + +class CredentialExtensionTest(unittest.TestCase): + + def setUp(self): + 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): + #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): + 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): + 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): + 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'): + 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): + 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): + 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'): + 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): + 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'): + 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 From 359b89542c6f224d266621a65a56722d44b82b78 Mon Sep 17 00:00:00 2001 From: Shweta P Date: Fri, 19 Aug 2011 19:47:37 -0700 Subject: [PATCH 25/52] Updated conf file --- etc/quantum.conf.mocktest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/quantum.conf.mocktest b/etc/quantum.conf.mocktest index d094b89d00..925a5ae903 100644 --- a/etc/quantum.conf.mocktest +++ b/etc/quantum.conf.mocktest @@ -21,4 +21,4 @@ pipeline = extensions extensions_test_app paste.filter_factory = quantum.common.extensions:plugin_aware_extension_middleware_factory [app:extensions_test_app] -paste.app_factory = tests.unit.test_mockext:app_factory +paste.app_factory = tests.unit.test_cisco_extension:app_factory From 3768e6c6eee73f2210982e21214a5862acb3ff91 Mon Sep 17 00:00:00 2001 From: Shweta P Date: Fri, 19 Aug 2011 20:01:52 -0700 Subject: [PATCH 26/52] Moved the conf file uncer the cisco directory --- etc/quantum.conf.mocktest | 24 ------------------------ 1 file changed, 24 deletions(-) delete mode 100644 etc/quantum.conf.mocktest diff --git a/etc/quantum.conf.mocktest b/etc/quantum.conf.mocktest deleted file mode 100644 index 925a5ae903..0000000000 --- a/etc/quantum.conf.mocktest +++ /dev/null @@ -1,24 +0,0 @@ -[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 = tests.unit.test_cisco_extension:app_factory From 058958c76cbac3248be1208caccbd759391e93bc Mon Sep 17 00:00:00 2001 From: Shweta P Date: Fri, 19 Aug 2011 20:02:49 -0700 Subject: [PATCH 27/52] Moved the conf file uncer the cisco directory --- .../plugins/cisco/conf/quantum.conf.ciscoext | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 quantum/plugins/cisco/conf/quantum.conf.ciscoext diff --git a/quantum/plugins/cisco/conf/quantum.conf.ciscoext b/quantum/plugins/cisco/conf/quantum.conf.ciscoext new file mode 100644 index 0000000000..925a5ae903 --- /dev/null +++ b/quantum/plugins/cisco/conf/quantum.conf.ciscoext @@ -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 = tests.unit.test_cisco_extension:app_factory From a22d933645a13a9d16c93d3e0305b53511053901 Mon Sep 17 00:00:00 2001 From: Shweta P Date: Fri, 19 Aug 2011 21:05:25 -0700 Subject: [PATCH 28/52] Review Changes --- quantum/plugins/cisco/tests/unit/test_cisco_extension.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/quantum/plugins/cisco/tests/unit/test_cisco_extension.py b/quantum/plugins/cisco/tests/unit/test_cisco_extension.py index 14f614c6e9..36e8d52342 100644 --- a/quantum/plugins/cisco/tests/unit/test_cisco_extension.py +++ b/quantum/plugins/cisco/tests/unit/test_cisco_extension.py @@ -41,18 +41,17 @@ 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, - 'etc', 'quantum.conf.mocktest') + os.pardir, 'etc', 'quantum.conf.ciscoext') EXTENSIONS_PATH = os.path.join(os.path.dirname(__file__), os.pardir, - os.pardir, - "extensions") + os.pardir, "extensions") LOG = logging.getLogger('quantum.plugins.cisco.tests.test_cisco_extensions') class ExtensionsTestApp(wsgi.Router): - def __init__(self, options={}): + def __init__(self, options=None): + options = options or {} mapper = routes.Mapper() controller = StubBaseAppController() mapper.resource("dummy_resource", "/dummy_resources", From 3f1b36e1e48754b30c3f8a8c927008cee1ced648 Mon Sep 17 00:00:00 2001 From: Shweta P Date: Fri, 19 Aug 2011 21:55:50 -0700 Subject: [PATCH 29/52] Change profile-id --- .../cisco/tests/unit/test_l2networkApi.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/quantum/plugins/cisco/tests/unit/test_l2networkApi.py b/quantum/plugins/cisco/tests/unit/test_l2networkApi.py index 7ba966fb80..aff7b6c13e 100644 --- a/quantum/plugins/cisco/tests/unit/test_l2networkApi.py +++ b/quantum/plugins/cisco/tests/unit/test_l2networkApi.py @@ -612,7 +612,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) @@ -639,7 +639,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) # port_profile = cdb.get_portprofile(tenant_id, port_profile_id) self.assertRaises(Exception, cdb.get_portprofile, port_profile_id) @@ -669,7 +669,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( @@ -699,8 +699,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] @@ -739,7 +739,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) @@ -773,7 +773,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) @@ -809,7 +809,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) @@ -854,7 +854,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) From 69dfdc95755208663ccfb170b3c50102e31e287e Mon Sep 17 00:00:00 2001 From: rohitagarwalla Date: Fri, 19 Aug 2011 23:54:02 -0700 Subject: [PATCH 30/52] fixing the the test_database.py tests --- .../plugins/cisco/tests/unit/test_database.py | 59 ++++++++++--------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/quantum/plugins/cisco/tests/unit/test_database.py b/quantum/plugins/cisco/tests/unit/test_database.py index eac638234a..2ae7f0271f 100644 --- a/quantum/plugins/cisco/tests/unit/test_database.py +++ b/quantum/plugins/cisco/tests/unit/test_database.py @@ -48,11 +48,11 @@ class NexusDB(object): LOG.error("Failed to get all bindings: %s" % str(exc)) return bindings - def get_nexusportbinding(self, port_id): + def get_nexusportbinding(self, vlan_id): """get nexus port binding""" binding = [] try: - for bind in nexus_db.get_nexusport_binding(port_id): + 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) @@ -67,35 +67,40 @@ class NexusDB(object): 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(bind.port_id) - bind_dict["vlan-id"] = str(bind.vlan_id) - return bind_dict - except Exception, exc: - LOG.error("Failed to create ucsm binding: %s" % str(exc)) - - def delete_nexusportbinding(self, port_id): - """delete nexus port binding""" - try: - res = nexus_db.remove_nexusport_binding(port_id) - LOG.debug("Deleted nexus port binding : %s" % res.port_id) - bind_dict = {} + 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: - raise Exception("Failed to delete dynamic vnic: %s" % str(exc)) + LOG.error("Failed to create nexus binding: %s" % str(exc)) - def update_nexusportbinding(self, port_id, new_vlan_id): + 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(bind.port_id) - bind_dict["vlan-id"] = str(bind.vlan_id) + 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 dynamic vnic: %s" % str(exc)) + raise Exception("Failed to update nexus port binding vnic: %s" + % str(exc)) class L2networkDB(object): @@ -200,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""" @@ -492,7 +497,7 @@ class QuantumDB(object): class NexusDBTest(unittest.TestCase): """Class conisting of nexus DB unit tests""" def setUp(self): - """Setup for ucs db tests""" + """Setup for nexus db tests""" l2network_db.initialize() self.dbtest = NexusDB() LOG.debug("Setup") @@ -522,7 +527,7 @@ class NexusDBTest(unittest.TestCase): def testc_delete_nexusportbinding(self): """delete nexus port binding""" binding1 = self.dbtest.create_nexusportbinding("port1", 10) - self.dbtest.delete_nexusportbinding(binding1["port-id"]) + self.dbtest.delete_nexusportbinding(10) bindings = self.dbtest.get_all_nexusportbindings() count = 0 for bind in bindings: @@ -534,7 +539,7 @@ class NexusDBTest(unittest.TestCase): def testd_update_nexusportbinding(self): """update nexus port binding""" binding1 = self.dbtest.create_nexusportbinding("port1", 10) - binding1 = self.dbtest.update_nexusportbinding(binding1["port-id"], \ + binding1 = self.dbtest.update_nexusport_binding(binding1["port-id"], \ 20) bindings = self.dbtest.get_all_nexusportbindings() count = 0 @@ -545,12 +550,12 @@ class NexusDBTest(unittest.TestCase): self.tearDown_nexusportbinding() def tearDown_nexusportbinding(self): - """tear down ucsm binding table""" + """tear down nexusport binding table""" LOG.debug("Tearing Down Nexus port Bindings") binds = self.dbtest.get_all_nexusportbindings() for bind in binds: - port_id = bind["port-id"] - self.dbtest.delete_nexusportbinding(port_id) + vlan_id = bind["vlan-id"] + self.dbtest.delete_nexusportbinding(vlan_id) class L2networkDBTest(unittest.TestCase): From 71d40685d1b7230489b417c5552876e8a60bcad7 Mon Sep 17 00:00:00 2001 From: Ying Liu Date: Mon, 22 Aug 2011 13:02:00 -0700 Subject: [PATCH 31/52] clean code and fix some comments. --- extensions/_exceptions.py | 21 --------------------- extensions/_faults.py | 3 ++- extensions/credential.py | 7 ++----- extensions/novatenant.py | 12 +++++------- extensions/portprofile.py | 5 +---- 5 files changed, 10 insertions(+), 38 deletions(-) diff --git a/extensions/_exceptions.py b/extensions/_exceptions.py index aeae4b647e..2310d44e6d 100644 --- a/extensions/_exceptions.py +++ b/extensions/_exceptions.py @@ -109,27 +109,6 @@ class QosNotFound(NotFound): message = _("QoS %(_id)s could not be found") -""" - - -class PortprofileInUse(ExtensionException): - message = _("Unable to complete operation on Portprofile %(net_id)s. " \ - "There is one or more attachments plugged into its ports.") - - -class PortInUse(ExtensionException): - message = _("Unable to complete operation on port %(port_id)s " \ - "for Portprofile %(net_id)s. The attachment '%(att_id)s" \ - "is plugged into the logical port.") - -class AlreadyAttached(ExtensionException): - message = _("Unable to plug the attachment %(att_id)s into port " \ - "%(port_id)s for Portprofile %(net_id)s. The attachment is " \ - "already plugged into port %(att_port_id)s") - -""" - - class Duplicate(Error): """Duplication Error""" pass diff --git a/extensions/_faults.py b/extensions/_faults.py index 6bdd3a48b9..18dd77864e 100644 --- a/extensions/_faults.py +++ b/extensions/_faults.py @@ -49,7 +49,8 @@ class Fault(webob.exc.HTTPException): @webob.dec.wsgify(RequestClass=wsgi.Request) def __call__(self, req): - """Generate a WSGI response based on the exception passed to ctor.""" + """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") diff --git a/extensions/credential.py b/extensions/credential.py index 85043940b4..0b69284818 100644 --- a/extensions/credential.py +++ b/extensions/credential.py @@ -23,7 +23,6 @@ import logging from webob import exc from extensions import _credential_view as credential_view from quantum.plugins.cisco.common import cisco_exceptions as exception -#from extensions import _exceptions as exception from extensions import _faults as faults from quantum.api import api_common as common @@ -60,7 +59,7 @@ class Credential(object): @classmethod def get_updated(cls): - """ Returns Ext Resource Name """ + """ Returns Ext Resource Update Time """ return "2011-07-25T13:25:27-06:00" @classmethod @@ -97,7 +96,6 @@ class CredentialController(common.QuantumController): def __init__(self, plugin): self._resource_name = 'credential' self._plugin = plugin - #super(CredentialController, self).__init__(plugin) def index(self, request, tenant_id): """ Returns a list of credential ids """ @@ -126,7 +124,6 @@ class CredentialController(common.QuantumController): def create(self, request, tenant_id): """ Creates a new credential for a given tenant """ - #look for credential name in request try: req_params = \ self._parse_request_params(request, @@ -168,4 +165,4 @@ class CredentialController(common.QuantumController): return exc.HTTPAccepted() except exception.CredentialNotFound as exp: return faults.Fault(faults.CredentialNotFound(exp)) - \ No newline at end of file + diff --git a/extensions/novatenant.py b/extensions/novatenant.py index 5cbfc4bd0a..3eaa89c248 100644 --- a/extensions/novatenant.py +++ b/extensions/novatenant.py @@ -22,7 +22,6 @@ from webob import exc from extensions import _novatenant_view as novatenant_view from quantum.common import exceptions as qexception -#from extensions import _exceptions as exception from extensions import _faults as faults from quantum.api import api_common as common @@ -42,27 +41,27 @@ class Novatenant(object): @classmethod def get_alias(cls): - """ Returns Ext Resource Name """ + """ Returns Ext Resource alias""" return "Cisco Nova Tenant" @classmethod def get_description(cls): - """ Returns Ext Resource Name """ + """ Returns Ext Resource Description """ return "novatenant resource is used by nova side to invoke quantum api" @classmethod def get_namespace(cls): - """ Returns Ext Resource Name """ + """ Returns Ext Resource Namespace """ return "http://docs.ciscocloud.com/api/ext/novatenant/v1.0" @classmethod def get_updated(cls): - """ Returns Ext Resource Name """ + """ Returns Ext Resource Updated Time """ return "2011-08-09T13:25:27-06:00" @classmethod def get_resources(cls): - """ Returns Ext Resource Name """ + """ Returns Ext Resource """ parent_resource = dict(member_name="tenant", collection_name="extensions/csco/tenants") member_actions = {'get_host': "PUT", @@ -144,7 +143,6 @@ class NovatenantsController(common.QuantumController): builder = novatenant_view.get_view_builder(request) result = builder.build_host(host) return result - #return exc.HTTPAccepted() except qexception.PortNotFound as exp: return faults.Fault(faults.PortNotFound(exp)) diff --git a/extensions/portprofile.py b/extensions/portprofile.py index b0fbb65dd6..8621c2ac7d 100644 --- a/extensions/portprofile.py +++ b/extensions/portprofile.py @@ -24,7 +24,6 @@ from webob import exc from extensions import _pprofiles as pprofiles_view from quantum.plugins.cisco.common import cisco_exceptions as exception from quantum.common import exceptions as qexception -#from extensions import _exceptions as exception from extensions import _faults as faults from quantum.api import api_common as common @@ -59,7 +58,7 @@ class Portprofile(object): @classmethod def get_updated(cls): - """ Returns Ext Resource Updateed time """ + """ Returns Ext Resource Updated time """ return "2011-07-23T13:25:27-06:00" @classmethod @@ -130,7 +129,6 @@ class PortprofilesController(common.QuantumController): return dict(portprofiles=result) except exception.PortProfileNotFound as exp: return faults.Fault(faults.PortprofileNotFound(exp)) - #return faults.Fault(exp) def create(self, request, tenant_id): """ Creates a new portprofile for a given tenant """ @@ -188,7 +186,6 @@ class PortprofilesController(common.QuantumController): except exc.HTTPError as exp: return faults.Fault(exp) net_id = req_params['network-id'].strip() - #print "*****net id "+net_id port_id = req_params['port-id'].strip() try: self._plugin.associate_portprofile(tenant_id, From 3ed7419816e0fca047a6cf995e9374c2b8f2e5d7 Mon Sep 17 00:00:00 2001 From: Ying Liu Date: Mon, 22 Aug 2011 13:13:29 -0700 Subject: [PATCH 32/52] clean up code and fix some comments --- extensions/novatenant.py | 1 - extensions/portprofile.py | 2 -- extensions/qos.py | 1 - 3 files changed, 4 deletions(-) diff --git a/extensions/novatenant.py b/extensions/novatenant.py index 3eaa89c248..c4ab55db0b 100644 --- a/extensions/novatenant.py +++ b/extensions/novatenant.py @@ -97,7 +97,6 @@ class NovatenantsController(common.QuantumController): def __init__(self, plugin): self._resource_name = 'novatenant' self._plugin = plugin - #super(NovatenantsController, self).__init__(plugin) def index(self, request, tenant_id): """ Returns a list of novatenant ids """ diff --git a/extensions/portprofile.py b/extensions/portprofile.py index 8621c2ac7d..c20eea3ac9 100644 --- a/extensions/portprofile.py +++ b/extensions/portprofile.py @@ -81,7 +81,6 @@ class PortprofilesController(common.QuantumController): def __init__(self, plugin): self._resource_name = 'portprofile' self._plugin = plugin - #super(PortprofilesController, self).__init__(plugin) self._portprofile_ops_param_list = [{ 'param-name': 'portprofile_name', @@ -209,7 +208,6 @@ class PortprofilesController(common.QuantumController): except exc.HTTPError as exp: return faults.Fault(exp) net_id = req_params['network-id'].strip() - #print "*****net id "+net_id port_id = req_params['port-id'].strip() try: self._plugin. \ diff --git a/extensions/qos.py b/extensions/qos.py index 3c0f3da782..bcff6de8af 100644 --- a/extensions/qos.py +++ b/extensions/qos.py @@ -94,7 +94,6 @@ class QosController(common.QuantumController): def __init__(self, plugin): self._resource_name = 'qos' self._plugin = plugin - #super(QosController, self).__init__(plugin) def index(self, request, tenant_id): """ Returns a list of qos ids """ From c72cb36ef93246051b2e1ac498161c3301b600df Mon Sep 17 00:00:00 2001 From: Edgar Magana Date: Mon, 22 Aug 2011 16:04:55 -0700 Subject: [PATCH 33/52] Rewording of the README file to clarify the use of the SSh port --- quantum/plugins/cisco/README | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/quantum/plugins/cisco/README b/quantum/plugins/cisco/README index e15c9ac389..586997e73c 100755 --- a/quantum/plugins/cisco/README +++ b/quantum/plugins/cisco/README @@ -122,7 +122,8 @@ nexus_ip_address=10.0.0.1 # Use shortened interface syntax, e.g. "1/10" not "Ethernet1/10". nexus_first_port=1/10 nexus_second_port=1/11 -#Port number where the SSH will be running at Nexus Switch, e.g.: 22 (Default) +#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] From 4ee1ac41453dbc800740da1a59320f79a01c4946 Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Mon, 22 Aug 2011 16:17:33 -0700 Subject: [PATCH 34/52] Code clean up as per reviewr's request; documentation strings, unused code, etc. --- quantum/plugins/cisco/common/cisco_exceptions.py | 10 ++++++---- quantum/plugins/cisco/db/nexus_models.py | 2 -- quantum/plugins/cisco/l2network_plugin.py | 8 ++++---- .../plugins/cisco/l2network_plugin_configuration.py | 9 +++++++++ 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/quantum/plugins/cisco/common/cisco_exceptions.py b/quantum/plugins/cisco/common/cisco_exceptions.py index a50e2c86b2..3d4a819b28 100644 --- a/quantum/plugins/cisco/common/cisco_exceptions.py +++ b/quantum/plugins/cisco/common/cisco_exceptions.py @@ -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,21 +85,24 @@ 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") diff --git a/quantum/plugins/cisco/db/nexus_models.py b/quantum/plugins/cisco/db/nexus_models.py index 51a210990d..bd6c765ec9 100644 --- a/quantum/plugins/cisco/db/nexus_models.py +++ b/quantum/plugins/cisco/db/nexus_models.py @@ -27,8 +27,6 @@ class NexusPortBinding(BASE, L2NetworkBase): id = Column(Integer, primary_key=True, autoincrement=True) port_id = Column(String(255)) - #vlan_id = Column(Integer, ForeignKey("vlan_bindings.vlan_id"), \ - # nullable=False) vlan_id = Column(Integer, nullable=False) def __init__(self, port_id, vlan_id): diff --git a/quantum/plugins/cisco/l2network_plugin.py b/quantum/plugins/cisco/l2network_plugin.py index 6a0f7a5686..7174193523 100644 --- a/quantum/plugins/cisco/l2network_plugin.py +++ b/quantum/plugins/cisco/l2network_plugin.py @@ -462,7 +462,7 @@ class L2Network(QuantumPluginBase): cred.Store.deleteCredential(credential_id) def rename_credential(self, tenant_id, credential_id, new_name): - """Do nothing for this resource""" + """Rename the particular credential resource""" LOG.debug("rename_credential() called\n") try: credential = self._get_credential(tenant_id, credential_id) @@ -528,13 +528,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 @@ -542,7 +542,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), diff --git a/quantum/plugins/cisco/l2network_plugin_configuration.py b/quantum/plugins/cisco/l2network_plugin_configuration.py index acbca503b3..3fffd1d720 100644 --- a/quantum/plugins/cisco/l2network_plugin_configuration.py +++ b/quantum/plugins/cisco/l2network_plugin_configuration.py @@ -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'] From 36c4a0462ced7a69cb1a287038e778a723bf69e9 Mon Sep 17 00:00:00 2001 From: Ying Liu Date: Tue, 23 Aug 2011 15:15:16 -0700 Subject: [PATCH 35/52] remove unnecessary code and sync faults and exception handling --- extensions/_faults.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/extensions/_faults.py b/extensions/_faults.py index 18dd77864e..5b9c233ec4 100644 --- a/extensions/_faults.py +++ b/extensions/_faults.py @@ -20,7 +20,6 @@ """ import webob.dec -from quantum.api import api_common as common from quantum.common import wsgi @@ -57,14 +56,11 @@ class Fault(webob.exc.HTTPException): fault_data = { fault_name: { 'code': code, - 'message': self.wrapped_exc.explanation, - 'detail': self.wrapped_exc.detail}} + 'message': self.wrapped_exc.explanation}} # 'code' is an attribute on the fault tag itself - metadata = {'application/xml': {'attributes': {fault_name: 'code'}}} - default_xmlns = common.XML_NS_V10 - serializer = wsgi.Serializer(metadata, default_xmlns) content_type = req.best_match_content_type() - #self.wrapped_exc.body = serializer.serialize(fault_data, content_type) + self.wrapped_exc.body = wsgi.Serializer().\ + serialize(fault_data, content_type) self.wrapped_exc.content_type = content_type return self.wrapped_exc From 4e1d511d7661e1156fcb608145f0530979789d31 Mon Sep 17 00:00:00 2001 From: Shweta P Date: Wed, 24 Aug 2011 00:02:10 -0700 Subject: [PATCH 36/52] Review Changes --- quantum/plugins/cisco/README | 17 ++- .../plugins/cisco/conf/quantum.conf.ciscoext | 4 +- .../cisco/tests/unit/test_cisco_extension.py | 144 ++++++++++++++++-- .../cisco/tests/unit/test_l2networkApi.py | 71 +++------ .../cisco/tests/unit/test_nexus_plugin.py | 18 +-- .../cisco/tests/unit/test_ucs_driver.py | 3 +- .../cisco/tests/unit/test_ucs_plugin.py | 90 ++++++++++- 7 files changed, 261 insertions(+), 86 deletions(-) diff --git a/quantum/plugins/cisco/README b/quantum/plugins/cisco/README index 586997e73c..9b8e622c4a 100755 --- a/quantum/plugins/cisco/README +++ b/quantum/plugins/cisco/README @@ -186,7 +186,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 @@ -197,7 +198,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. or @@ -211,7 +213,9 @@ result the quantum/plugins/cisco/run_tests.py script. 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 @@ -223,6 +227,13 @@ result the quantum/plugins/cisco/run_tests.py script. 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 ------------------------------------------------ 1. Create a table in the "nova" database for ports. This can be diff --git a/quantum/plugins/cisco/conf/quantum.conf.ciscoext b/quantum/plugins/cisco/conf/quantum.conf.ciscoext index 925a5ae903..116a6d9a73 100644 --- a/quantum/plugins/cisco/conf/quantum.conf.ciscoext +++ b/quantum/plugins/cisco/conf/quantum.conf.ciscoext @@ -12,7 +12,7 @@ bind_host = 0.0.0.0 bind_port = 9696 # Path to the extensions -api_extensions_path = ../extensions +api_extensions_path = ../../../../extensions [pipeline:extensions_app_with_filter] pipeline = extensions extensions_test_app @@ -21,4 +21,4 @@ pipeline = extensions extensions_test_app paste.filter_factory = quantum.common.extensions:plugin_aware_extension_middleware_factory [app:extensions_test_app] -paste.app_factory = tests.unit.test_cisco_extension:app_factory +paste.app_factory = quantum.plugins.cisco.tests.unit.test_cisco_extension:app_factory diff --git a/quantum/plugins/cisco/tests/unit/test_cisco_extension.py b/quantum/plugins/cisco/tests/unit/test_cisco_extension.py index 36e8d52342..a6bbe3c649 100644 --- a/quantum/plugins/cisco/tests/unit/test_cisco_extension.py +++ b/quantum/plugins/cisco/tests/unit/test_cisco_extension.py @@ -17,12 +17,12 @@ # @authors: Shweta Padubidri, Cisco Systems, Inc. # Peter Strunk , Cisco Systems, Inc. # Shubhangi Satras , Cisco Systems, Inc. -import json -import os.path -import routes 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 @@ -41,9 +41,9 @@ 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, 'etc', 'quantum.conf.ciscoext') -EXTENSIONS_PATH = os.path.join(os.path.dirname(__file__), os.pardir, - os.pardir, "extensions") + 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') @@ -62,6 +62,9 @@ class ExtensionsTestApp(wsgi.Router): 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", @@ -89,6 +92,8 @@ class PortprofileExtensionTest(unittest.TestCase): 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( @@ -121,6 +126,8 @@ class PortprofileExtensionTest(unittest.TestCase): 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, @@ -138,6 +145,8 @@ class PortprofileExtensionTest(unittest.TestCase): 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, @@ -147,6 +156,8 @@ class PortprofileExtensionTest(unittest.TestCase): 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, @@ -165,6 +176,8 @@ class PortprofileExtensionTest(unittest.TestCase): 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) @@ -174,6 +187,8 @@ class PortprofileExtensionTest(unittest.TestCase): 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( @@ -197,6 +212,8 @@ class PortprofileExtensionTest(unittest.TestCase): 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( @@ -217,6 +234,8 @@ class PortprofileExtensionTest(unittest.TestCase): 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', @@ -231,6 +250,8 @@ class PortprofileExtensionTest(unittest.TestCase): 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( @@ -248,6 +269,8 @@ class PortprofileExtensionTest(unittest.TestCase): 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) @@ -257,6 +280,8 @@ class PortprofileExtensionTest(unittest.TestCase): 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 @@ -268,6 +293,8 @@ class PortprofileExtensionTest(unittest.TestCase): def _create_network(self, name=None): + """ Test create network""" + LOG.debug("Creating network - START") if name: net_name = name @@ -286,6 +313,8 @@ class PortprofileExtensionTest(unittest.TestCase): 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}} @@ -301,6 +330,8 @@ class PortprofileExtensionTest(unittest.TestCase): 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") @@ -336,6 +367,8 @@ class PortprofileExtensionTest(unittest.TestCase): 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'}} @@ -350,6 +383,8 @@ class PortprofileExtensionTest(unittest.TestCase): 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") @@ -388,21 +423,33 @@ class PortprofileExtensionTest(unittest.TestCase): 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.post(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", @@ -421,6 +468,9 @@ class NovatenantExtensionTest(unittest.TestCase): '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" @@ -431,6 +481,9 @@ class NovatenantExtensionTest(unittest.TestCase): 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( @@ -440,6 +493,9 @@ class NovatenantExtensionTest(unittest.TestCase): 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" @@ -454,6 +510,8 @@ 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()) @@ -470,6 +528,8 @@ class QosExtensionTest(unittest.TestCase): 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, @@ -488,6 +548,8 @@ class QosExtensionTest(unittest.TestCase): 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', @@ -497,6 +559,9 @@ class QosExtensionTest(unittest.TestCase): 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, @@ -524,6 +589,9 @@ class QosExtensionTest(unittest.TestCase): 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, @@ -541,6 +609,9 @@ class QosExtensionTest(unittest.TestCase): 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) @@ -550,6 +621,8 @@ class QosExtensionTest(unittest.TestCase): 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, @@ -567,6 +640,9 @@ class QosExtensionTest(unittest.TestCase): 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}}}) @@ -578,6 +654,9 @@ class QosExtensionTest(unittest.TestCase): 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, @@ -597,6 +676,8 @@ class QosExtensionTest(unittest.TestCase): 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}}}) @@ -612,6 +693,9 @@ class QosExtensionTest(unittest.TestCase): 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) @@ -620,12 +704,18 @@ class QosExtensionTest(unittest.TestCase): 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( @@ -640,10 +730,12 @@ class CredentialExtensionTest(unittest.TestCase): self.test_credential_data = {'credential': {'credential_name': 'cred8', 'user_name': 'newUser2', - 'password': 'newPasswd1' - }} + '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) @@ -653,8 +745,7 @@ class CredentialExtensionTest(unittest.TestCase): req_body2 = json.dumps({'credential': {'credential_name': 'cred9', 'user_name': 'newUser2', - 'password': 'newPasswd2' - }}) + 'password': 'newPasswd2'}}) create_response2 = self.test_app.post( self.credential_path, req_body2, content_type=self.contenttype) @@ -677,6 +768,9 @@ class CredentialExtensionTest(unittest.TestCase): 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( @@ -693,6 +787,9 @@ class CredentialExtensionTest(unittest.TestCase): 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', @@ -701,6 +798,9 @@ class CredentialExtensionTest(unittest.TestCase): 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( @@ -716,6 +816,9 @@ class CredentialExtensionTest(unittest.TestCase): 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) @@ -724,6 +827,9 @@ class CredentialExtensionTest(unittest.TestCase): 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) @@ -735,8 +841,7 @@ class CredentialExtensionTest(unittest.TestCase): rename_req_body = json.dumps({'credential': {'credential_name': 'cred3', 'user_name': 'RenamedUser', - 'password': 'Renamedpassword' - }}) + 'password': 'Renamedpassword'}}) rename_path_temp = self.cred_second_path +\ resp_body['credentials']['credential']['id'] rename_path = str(rename_path_temp) @@ -747,6 +852,9 @@ class CredentialExtensionTest(unittest.TestCase): 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( @@ -763,12 +871,14 @@ class CredentialExtensionTest(unittest.TestCase): 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' - }}) + '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, @@ -777,6 +887,9 @@ class CredentialExtensionTest(unittest.TestCase): 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( @@ -792,6 +905,9 @@ class CredentialExtensionTest(unittest.TestCase): 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) diff --git a/quantum/plugins/cisco/tests/unit/test_l2networkApi.py b/quantum/plugins/cisco/tests/unit/test_l2networkApi.py index aff7b6c13e..c6bafa6fcb 100644 --- a/quantum/plugins/cisco/tests/unit/test_l2networkApi.py +++ b/quantum/plugins/cisco/tests/unit/test_l2networkApi.py @@ -19,13 +19,12 @@ import logging import unittest -#import time from quantum.common import exceptions as exc from quantum.plugins.cisco.common import cisco_constants as const from quantum.plugins.cisco.common import cisco_exceptions as cexc from quantum.plugins.cisco import l2network_plugin from quantum.plugins.cisco import l2network_plugin_configuration as conf -#from quantum.plugins.cisco.common import cisco_utils as utils +from quantum.plugins.cisco.common import cisco_utils as utils from quantum.plugins.cisco.db import api as db from quantum.plugins.cisco.db import l2network_db as cdb @@ -72,7 +71,6 @@ class CoreAPITestFunc(unittest.TestCase): tenant_id, new_net_dict[const.NET_ID]) self.assertRaises(exc.NetworkNotFound, db.network_get, new_net_dict[const.NET_ID]) - #self.assertEqual(net, None) self.assertEqual( new_net_dict[const.NET_ID], delete_net_dict[const.NET_ID]) LOG.debug("test_delete_network - END") @@ -303,11 +301,6 @@ class CoreAPITestFunc(unittest.TestCase): port_dict[const.PORT_ID]) self.assertRaises(exc.PortNotFound, db.port_get, new_net_dict[const.NET_ID], port_dict[const.PORT_ID]) - #self.assertEqual(port, None) - # self.assertEqual(delete_port_dict[const.PORT_STATE], port_state) -# self.assertEqual(delete_port_dict[const.NET_ID], new_net_dict[NET_ID]) -# self.assertEqual(delete_port_dict[const.PORT_ID], -# new_net_dict[PORT_ID]) self.tearDownNetwork(tenant_id, new_net_dict[const.NET_ID]) self.assertEqual(delete_port_dict[const.PORT_ID], port_dict[const.PORT_ID]) @@ -470,10 +463,6 @@ class CoreAPITestFunc(unittest.TestCase): port_dict[const.PORT_ID], remote_interface) port = db.port_get(new_net_dict[const.NET_ID], port_dict[const.PORT_ID]) - # self.assertEqual( - # self._l2network_plugin._networks[new_net_dict[const.NET_ID]] - # [const.NET_PORTS][port_dict[const.PORT_ID]] - # [const.ATTACHMENT], remote_interface) self.assertEqual(port[const.INTERFACEID], remote_interface) self.tearDownNetworkPortInterface( tenant_id, new_net_dict[const.NET_ID], @@ -553,9 +542,6 @@ class CoreAPITestFunc(unittest.TestCase): port_dict[const.PORT_ID]) port = db.port_get(new_net_dict[const.NET_ID], port_dict[const.PORT_ID]) - # self.assertEqual(self._l2network_plugin._networks - # [new_net_dict[const.NET_ID]][const.NET_PORTS] - # [port_dict[const.PORT_ID]][const.ATTACHMENT], None) self.assertEqual(port[const.INTERFACEID], None) self.tearDownNetworkPort(tenant_id, new_net_dict[const.NET_ID], port_dict[const.PORT_ID]) @@ -616,12 +602,6 @@ class CoreAPITestFunc(unittest.TestCase): port_profile = cdb.get_portprofile(tenant_id, port_profile_id) self.assertEqual(port_profile[const.PPNAME], profile_name) self.assertEqual(port_profile[const.PPQOS], qos) - # self.assertEqual( - # self._l2network_plugin._portprofiles[port_profile_id]['vlan-id'], - # vlan_id) - #self.assertEqual( - # self._l2network_plugin._portprofiles[port_profile_id] - # ['profile-name'], profile_name) self.tearDownPortProfile(tenant_id, port_profile_id) LOG.debug("test_create_portprofile - tenant id: %s - END", net_tenant_id) @@ -641,10 +621,7 @@ class CoreAPITestFunc(unittest.TestCase): tenant_id, self.profile_name, self.qos) port_profile_id = port_profile_dict['profile_id'] self._l2network_plugin.delete_portprofile(tenant_id, port_profile_id) -# port_profile = cdb.get_portprofile(tenant_id, port_profile_id) self.assertRaises(Exception, cdb.get_portprofile, port_profile_id) -# self.assertEqual(port_profile, {}) -# self.assertEqual(self._l2network_plugin._portprofiles, {}) LOG.debug("test_delete_portprofile - tenant id: %s - END", net_tenant_id) @@ -714,14 +691,6 @@ class CoreAPITestFunc(unittest.TestCase): new_pplist.append(new_pp) self.assertTrue(new_pplist[0] in port_profile_list) self.assertTrue(new_pplist[1] in port_profile_list) -# self.assertEqual(self._l2network_plugin._portprofiles - # [port_profile_id1]['vlan-id'], self.vlan_id) - # self.assertEqual(self._l2network_plugin._portprofiles - # [port_profile_id1]['profile-name'], self.profile_name) - # self.assertEqual(self._l2network_plugin._portprofiles - # [port_profile_id2]['vlan-id'], vlan_id2) - # self.assertEqual(self._l2network_plugin._portprofiles - # [port_profile_id2]['profile-name'], profile_name2) self.tearDownPortProfile(tenant_id, port_profile_id1) self.tearDownPortProfile(tenant_id, port_profile_id2) @@ -816,9 +785,6 @@ class CoreAPITestFunc(unittest.TestCase): port_profile_associate = cdb.get_pp_binding(tenant_id, port_profile_id) self.assertEqual(port_profile_associate[const.PORTID], port_dict[const.PORT_ID]) - #self.assertEqual( - # self._l2network_plugin._portprofiles[port_profile_id] - # [const.PROFILE_ASSOCIATIONS][0], port_id) self.tearDownAssociatePortProfile( tenant_id, new_net_dict[const.NET_ID], port_dict[const.PORT_ID], port_profile_id) @@ -863,8 +829,6 @@ class CoreAPITestFunc(unittest.TestCase): port_dict[const.PORT_ID], port_profile_id) port_profile_associate = cdb.get_pp_binding(tenant_id, port_profile_id) self.assertEqual(port_profile_associate, []) -# self.assertEqual(self._l2network_plugin._portprofiles - # [port_profile_id][const.PROFILE_ASSOCIATIONS], []) self.tearDownPortProfile(tenant_id, port_profile_id) self.tearDownNetworkPort( tenant_id, new_net_dict[const.NET_ID], @@ -883,7 +847,6 @@ class CoreAPITestFunc(unittest.TestCase): tenant_id, net_id, port_id, profile_id) LOG.debug("test_disassociate_portprofileDNE - END") -# def test_disassociate_portprofile_Unassociated def test_get_vlan_name(self, net_tenant_id=None, vlan_id="NewVlan", vlan_prefix=conf.VLAN_NAME_PREFIX): """ @@ -923,22 +886,17 @@ 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" - # self.vlan_id = "test_tenant_vlanid300" self.qos = "test_qos" self.port_state = const.PORT_UP self.net_id = '00005' self.port_id = 'p0005' self.remote_interface = 'new_interface' - #sql_query = "drop database quantum_l2network" - #sql_query_2 = "create database quantum_l2network" - #self._utils = utils.DBUtils() - #self._utils.execute_db_query(sql_query) - #time.sleep(10) - #self._utils.execute_db_query(sql_query_2) - #time.sleep(10) self._l2network_plugin = l2network_plugin.L2Network() """ @@ -950,29 +908,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) diff --git a/quantum/plugins/cisco/tests/unit/test_nexus_plugin.py b/quantum/plugins/cisco/tests/unit/test_nexus_plugin.py index e9f95f1fca..454f5b703f 100644 --- a/quantum/plugins/cisco/tests/unit/test_nexus_plugin.py +++ b/quantum/plugins/cisco/tests/unit/test_nexus_plugin.py @@ -27,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" @@ -265,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) diff --git a/quantum/plugins/cisco/tests/unit/test_ucs_driver.py b/quantum/plugins/cisco/tests/unit/test_ucs_driver.py index eaf646ff52..9da92e5b06 100644 --- a/quantum/plugins/cisco/tests/unit/test_ucs_driver.py +++ b/quantum/plugins/cisco/tests/unit/test_ucs_driver.py @@ -73,6 +73,7 @@ ASSOCIATE_PROFILE_OUTPUT = " Date: Wed, 24 Aug 2011 09:55:47 -0700 Subject: [PATCH 37/52] delete quantum/common/test_lib.py to prepare for quantum merge --- quantum/common/test_lib.py | 278 ------------------------------------- 1 file changed, 278 deletions(-) delete mode 100644 quantum/common/test_lib.py diff --git a/quantum/common/test_lib.py b/quantum/common/test_lib.py deleted file mode 100644 index 2ccd681ce0..0000000000 --- a/quantum/common/test_lib.py +++ /dev/null @@ -1,278 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2010 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. - -# Colorizer Code is borrowed from Twisted: -# Copyright (c) 2001-2010 Twisted Matrix Laboratories. -# -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -import gettext -import os -import unittest -import sys -import logging - -from nose import result -from nose import core -from nose import config - - -class _AnsiColorizer(object): - """ - A colorizer is an object that loosely wraps around a stream, allowing - callers to write text to the stream in a particular color. - - Colorizer classes must implement C{supported()} and C{write(text, color)}. - """ - _colors = dict(black=30, red=31, green=32, yellow=33, - blue=34, magenta=35, cyan=36, white=37) - - def __init__(self, stream): - self.stream = stream - - def supported(cls, stream=sys.stdout): - """ - A class method that returns True if the current platform supports - coloring terminal output using this method. Returns False otherwise. - """ - if not stream.isatty(): - return False # auto color only on TTYs - try: - import curses - except ImportError: - return False - else: - try: - try: - return curses.tigetnum("colors") > 2 - except curses.error: - curses.setupterm() - return curses.tigetnum("colors") > 2 - except: - raise - # guess false in case of error - return False - supported = classmethod(supported) - - def write(self, text, color): - """ - Write the given text to the stream in the given color. - - @param text: Text to be written to the stream. - - @param color: A string label for a color. e.g. 'red', 'white'. - """ - color = self._colors[color] - self.stream.write('\x1b[%s;1m%s\x1b[0m' % (color, text)) - - -class _Win32Colorizer(object): - """ - See _AnsiColorizer docstring. - """ - def __init__(self, stream): - from win32console import GetStdHandle, STD_OUT_HANDLE, \ - FOREGROUND_RED, FOREGROUND_BLUE, FOREGROUND_GREEN, \ - FOREGROUND_INTENSITY - red, green, blue, bold = (FOREGROUND_RED, FOREGROUND_GREEN, - FOREGROUND_BLUE, FOREGROUND_INTENSITY) - self.stream = stream - self.screenBuffer = GetStdHandle(STD_OUT_HANDLE) - self._colors = { - 'normal': red | green | blue, - 'red': red | bold, - 'green': green | bold, - 'blue': blue | bold, - 'yellow': red | green | bold, - 'magenta': red | blue | bold, - 'cyan': green | blue | bold, - 'white': red | green | blue | bold} - - def supported(cls, stream=sys.stdout): - try: - import win32console - screenBuffer = win32console.GetStdHandle( - win32console.STD_OUT_HANDLE) - except ImportError: - return False - import pywintypes - try: - screenBuffer.SetConsoleTextAttribute( - win32console.FOREGROUND_RED | - win32console.FOREGROUND_GREEN | - win32console.FOREGROUND_BLUE) - except pywintypes.error: - return False - else: - return True - supported = classmethod(supported) - - def write(self, text, color): - color = self._colors[color] - self.screenBuffer.SetConsoleTextAttribute(color) - self.stream.write(text) - self.screenBuffer.SetConsoleTextAttribute(self._colors['normal']) - - -class _NullColorizer(object): - """ - See _AnsiColorizer docstring. - """ - def __init__(self, stream): - self.stream = stream - - def supported(cls, stream=sys.stdout): - return True - supported = classmethod(supported) - - def write(self, text, color): - self.stream.write(text) - - -class QuantumTestResult(result.TextTestResult): - def __init__(self, *args, **kw): - result.TextTestResult.__init__(self, *args, **kw) - self._last_case = None - self.colorizer = None - # NOTE(vish, tfukushima): reset stdout for the terminal check - stdout = sys.__stdout__ - for colorizer in [_Win32Colorizer, _AnsiColorizer, _NullColorizer]: - if colorizer.supported(): - self.colorizer = colorizer(self.stream) - break - sys.stdout = stdout - - def getDescription(self, test): - return str(test) - - # NOTE(vish, tfukushima): copied from unittest with edit to add color - def addSuccess(self, test): - unittest.TestResult.addSuccess(self, test) - if self.showAll: - self.colorizer.write("OK", 'green') - self.stream.writeln() - elif self.dots: - self.stream.write('.') - self.stream.flush() - - # NOTE(vish, tfukushima): copied from unittest with edit to add color - def addFailure(self, test, err): - unittest.TestResult.addFailure(self, test, err) - if self.showAll: - self.colorizer.write("FAIL", 'red') - self.stream.writeln() - elif self.dots: - self.stream.write('F') - self.stream.flush() - - # NOTE(vish, tfukushima): copied from unittest with edit to add color - def addError(self, test, err): - """Overrides normal addError to add support for errorClasses. - If the exception is a registered class, the error will be added - to the list for that class, not errors. - """ - stream = getattr(self, 'stream', None) - ec, ev, tb = err - try: - exc_info = self._exc_info_to_string(err, test) - except TypeError: - # This is for compatibility with Python 2.3. - exc_info = self._exc_info_to_string(err) - for cls, (storage, label, isfail) in self.errorClasses.items(): - if result.isclass(ec) and issubclass(ec, cls): - if isfail: - test.passwd = False - storage.append((test, exc_info)) - # Might get patched into a streamless result - if stream is not None: - if self.showAll: - message = [label] - detail = result._exception_details(err[1]) - if detail: - message.append(detail) - stream.writeln(": ".join(message)) - elif self.dots: - stream.write(label[:1]) - return - self.errors.append((test, exc_info)) - test.passed = False - if stream is not None: - if self.showAll: - self.colorizer.write("ERROR", 'red') - self.stream.writeln() - elif self.dots: - stream.write('E') - - def startTest(self, test): - unittest.TestResult.startTest(self, test) - current_case = test.test.__class__.__name__ - - if self.showAll: - if current_case != self._last_case: - self.stream.writeln(current_case) - self._last_case = current_case - - self.stream.write( - ' %s' % str(test.test._testMethodName).ljust(60)) - self.stream.flush() - - -class QuantumTestRunner(core.TextTestRunner): - def _makeResult(self): - return QuantumTestResult(self.stream, - self.descriptions, - self.verbosity, - self.config) - - -def run_tests(c): - logger = logging.getLogger() - hdlr = logging.StreamHandler() - formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s') - hdlr.setFormatter(formatter) - logger.addHandler(hdlr) - logger.setLevel(logging.DEBUG) - - runner = QuantumTestRunner(stream=c.stream, - verbosity=c.verbosity, - config=c) - return not core.run(config=c, testRunner=runner) - -# describes parameters used by different unit/functional tests -# a plugin-specific testing mechanism should import this dictionary -# and override the values in it if needed (e.g., run_tests.py in -# quantum/plugins/openvswitch/ ) -test_config = { - "plugin_name": "quantum.plugins.SamplePlugin.FakePlugin", -} From bbbdf82de385d360b0a0f7f969a3a586d0f85ff0 Mon Sep 17 00:00:00 2001 From: Salvatore Orlando Date: Wed, 24 Aug 2011 19:10:03 +0100 Subject: [PATCH 38/52] Templated output for CLI completed! --- quantum/cli.py | 345 +++++++++++++----------------------- quantum/cli_output.template | 33 +++- quantum/client.py | 1 + 3 files changed, 155 insertions(+), 224 deletions(-) diff --git a/quantum/cli.py b/quantum/cli.py index fa326d9d42..fdda75899e 100644 --- a/quantum/cli.py +++ b/quantum/cli.py @@ -16,25 +16,30 @@ # 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 httplib import logging as LOG -import json -import socket import sys -import urllib from client import Client -from manager import QuantumManager from optparse import OptionParser -from quantum.api.views.networks import ViewBuilder as NetworkBuilder -from quantum.api.views.ports import ViewBuilder as PortBuilder FORMAT = "json" CLI_TEMPLATE = "../quantum/cli_output.template" #TODO(salvatore-orlando): do proper logging! +def _handle_exception(ex): + 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) + print "Failed to create network: %s" % status_code or '' + print "Error message:%s" % message or '' + + def prepare_output(cmd, tenant_id, response): """ Fills a cheetah template with the response """ #add command and tenant to response for output generation @@ -45,293 +50,197 @@ def prepare_output(cmd, tenant_id, response): searchList=response)) return output -def list_nets(manager, *args): - tenant_id = args[0] - networks = manager.get_all_networks(tenant_id) - builder=NetworkBuilder() - nw_list = [builder.build(network, net_detail=True, port_detail=False)['network'] - for network in networks] - res = dict(networks=nw_list) - output = prepare_output("list_nets", tenant_id, res) - print output - - -def api_list_nets(client, *args): +def list_nets(client, *args): tenant_id = args[0] res = client.list_networks() output = prepare_output("list_nets", tenant_id, res) print output -def create_net(manager, *args): - tenant_id, name = args - new_net_id = manager.create_network(tenant_id, name)['net-id'] - output = prepare_output("create_net", tenant_id, - dict(network_id=new_net_id)) - print output - - -def api_create_net(client, *args): +def create_net(client, *args): tenant_id, name = args data = {'network': {'net-name': name}} new_net_id = None try: res = client.create_network(data) new_net_id = res["networks"]["network"]["id"] + output = prepare_output("create_net", tenant_id, + dict(network_id=new_net_id)) + print output except Exception as ex: - 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) - print "Failed to create network: %s" % status_code or '' - print "Error message:%s" % message or '' - return - output = prepare_output("create_net", tenant_id, - dict(network_id=new_net_id)) - print output + _handle_exception(ex) - -def delete_net(manager, *args): - tenant_id, network_id = args - manager.delete_network(tenant_id, network_id) - output = prepare_output("delete_net", tenant_id, - dict(network_id=network_id)) - print output - - -def api_delete_net(client, *args): +def delete_net(client, *args): tenant_id, network_id = args try: client.delete_network(network_id) output = prepare_output("delete_net", tenant_id, dict(network_id=network_id)) print output - except Exception, e: - print "Failed to delete network" - LOG.error("Failed to delete network: %s" % e) + except Exception as ex: + _handle_exception(ex) -def detail_net(manager, *args): - tid, nid = args - iface_list = manager.get_network_details(tid, nid) - output = prepare_output("detail_net", tenant_id, - dict(network=iface_list)) - #TODO(salvatore-orlando): delete here - 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): +def detail_net(client, *args): tenant_id, network_id = args try: res = client.list_network_details(network_id)["networks"]["network"] - except Exception, e: - LOG.error("Failed to get network details: %s" % e) - return - try: ports = client.list_ports(network_id) - except Exception, e: - LOG.error("Failed to list ports: %s" % e) - return + res['ports'] = ports + for port in ports["ports"]: + att_data = client.list_port_attachments(network_id, port['id']) + port['attachment'] = att_data["attachment"] - res['ports'] = ports - for port in ports["ports"]: - att_data = client.list_port_attachments(network_id, port['id']) - port['attachment'] = att_data["attachment"] - - output = prepare_output("detail_net", tenant_id, - dict(network=res)) - print output + output = prepare_output("detail_net", tenant_id, dict(network=res)) + print output + except Exception as ex: + _handle_exception(ex) -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 +def rename_net(client, *args): + tenant_id, network_id, name = args data = {'network': {'net-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 + client.update_network(network_id, data) + # Response has no body. Use data for populating output + data['id'] = network_id + output = prepare_output("rename_net", tenant_id, dict(network=data)) + print output + except Exception as ex: + _handle_exception(ex) -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 +def list_ports(client, *args): + tenant_id, network_id = 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"] + ports = client.list_ports(network_id) + output = prepare_output("list_ports", tenant_id, dict(ports=ports)) + print output + except Exception as ex: + _handle_exception(ex) -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 +def create_port(client, *args): + tenant_id, network_id = args try: - res = client.create_port(nid) - except Exception, e: - LOG.error("Failed to create port: %s" % e) - return - new_port = res["ports"]["port"]["id"] - print "Created Virtual Port:%s " \ - "on Virtual Network:%s" % (new_port, nid) + res = client.create_port(network_id) + new_port_id = res["ports"]["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(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 +def delete_port(client, *args): + tenant_id, network_id, port_id = args try: - res = client.delete_port(nid, pid) - except Exception, e: - LOG.error("Failed to delete port: %s" % e) + client.delete_port(network_id, port_id) + 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 - 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 +def detail_port(client, *args): + tenant_id, network_id, port_id = args try: - port = client.list_port_details(nid, pid)["ports"]["port"] - except Exception, e: - LOG.error("Failed to get port details: %s" % e) - return - - id = port["id"] - attachment = port["attachment"] - LOG.debug(port) - print "Virtual Port:%s on Virtual Network:%s " \ - "contains remote interface:%s" % (pid, nid, attachment) + port = client.list_port_details(network_id, port_id)["ports"]["port"] + #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 + port['attachment'] = '' + output = prepare_output("detail_port", tenant_id, + dict(network_id=network_id, + port=port)) + print output + except Exception as ex: + _handle_exception(ex) -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 +def set_port_state(client, *args): + tenant_id, network_id, port_id, new_state = args + data = {'port': {'port-state': '%s' % new_state}} try: - data = {'port': {'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, output)) - return - LOG.debug(res) - print "Plugged interface \"%s\" to port:%s on network:%s" % (vid, pid, nid) + client.set_port_state(network_id, port_id, data) + # Response has no body. Use data for populating output + data['id'] = port_id + output = prepare_output("set_port_state", tenant_id, + dict(network_id=network_id, port=data)) + print output + except Exception as ex: + _handle_exception(ex) -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 +def plug_iface(client, *args): + tenant_id, network_id, port_id, attachment = 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) + data = {'port': {'attachment': '%s' % attachment}} + client.attach_resource(network_id, port_id, data) + output = prepare_output("plug_interface", 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) + output = prepare_output("unplug_interface", tenant_id, + dict(network_id = network_id, + port_id = port_id)) + print output + except Exception as ex: + _handle_exception(ex) 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"]}, + "set_port_state": { + "func": set_port_state, + "args": ["tenant-id", "net-id", "port-id","new_state"]}, "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(): @@ -346,7 +255,7 @@ def build_args(cmd, cmdargs, arglist): for x in cmdargs: args.append(arglist[0]) del arglist[0] - except Exception, e: + except: LOG.error("Not enough arguments for \"%s\" (expected: %d, got: %d)" % ( cmd, len(cmdargs), len(orig_arglist))) print "Usage:\n %s %s" % (cmd, @@ -364,9 +273,6 @@ def build_args(cmd, cmdargs, arglist): if __name__ == "__main__": usagestr = "Usage: %prog [OPTIONS] [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", @@ -398,15 +304,10 @@ if __name__ == "__main__": 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) + + client = Client(options.host, options.port, options.ssl, + args[0], FORMAT) + commands[cmd]["func"](client, *args) + + LOG.debug("Command execution completed") sys.exit(0) diff --git a/quantum/cli_output.template b/quantum/cli_output.template index 0c9084010d..96baef7352 100644 --- a/quantum/cli_output.template +++ b/quantum/cli_output.template @@ -9,10 +9,39 @@ 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 == 'detail_net' -Network $network.name ($network.id) +Network: $network.name ($network.id) Remote Interfaces on Virtual Network #for $port in $network.port -Port $port.id: $port.attachment +\tLogical Port $port.id: $port.attachment #end for +#elif $cmd == 'rename_net' +Renamed Virtual Network with ID: $network.id for Tenant $tenant_id, +New name is: $network.name +#elif $cmd == 'list_ports' +Ports on Virtual Network: $network_id +#for $port in $ports +\tLogical Port: $port.id +#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 == 'detail_port' +Logical Port ID: $port.id +On Virtual Network: $network_id +Administrative State: $port.state +Remote Interface: $port.attachment +#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 diff --git a/quantum/client.py b/quantum/client.py index d993d68e66..f6e1b6bfe3 100644 --- a/quantum/client.py +++ b/quantum/client.py @@ -148,6 +148,7 @@ class Client(object): httplib.NO_CONTENT): return self.deserialize(res) else: + # Create exception with HTTP status code and message ex = Exception("Server returned error: %s" % status_code) ex.args = ([dict(status_code=status_code, message=res.read())],) raise ex From 8e3a228fa3208281b2d02e84a0d90cc9e84ffaab Mon Sep 17 00:00:00 2001 From: rohitagarwalla Date: Wed, 24 Aug 2011 14:11:10 -0700 Subject: [PATCH 39/52] fixing relative import in nexus_db.py --- quantum/plugins/cisco/db/nexus_db.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quantum/plugins/cisco/db/nexus_db.py b/quantum/plugins/cisco/db/nexus_db.py index 054ad6b2ed..f2410990cc 100644 --- a/quantum/plugins/cisco/db/nexus_db.py +++ b/quantum/plugins/cisco/db/nexus_db.py @@ -20,9 +20,9 @@ import logging as LOG from sqlalchemy.orm import exc import quantum.plugins.cisco.db.api as db -import nexus_models from quantum.plugins.cisco.common import cisco_exceptions as c_exc +from quantum.plugins.cisco.db import nexus_models def get_all_nexusport_bindings(): From 22fb01352647aed9b7efe90c8e255a5bdf92d023 Mon Sep 17 00:00:00 2001 From: Salvatore Orlando Date: Thu, 25 Aug 2011 01:21:19 +0100 Subject: [PATCH 40/52] Added logging to syslog or file specified at command line removed plugin direct mode fixed unit tests to reflect changes in cli code fixex pep8 errors todo: complete unit tests auto-detect function names from stack trace --- quantum/cli.py | 73 +++++++++++++++------- quantum/cli_output.template | 1 + quantum/client.py | 6 +- tests/unit/client_tools/__init__.py | 2 +- tests/unit/client_tools/stubs.py | 39 ++++-------- tests/unit/test_cli.py | 93 +++++++++-------------------- 6 files changed, 96 insertions(+), 118 deletions(-) diff --git a/quantum/cli.py b/quantum/cli.py index fdda75899e..dbdb91a39a 100644 --- a/quantum/cli.py +++ b/quantum/cli.py @@ -19,7 +19,8 @@ # @author: Salvatore Orlando, Citrix import Cheetah.Template as cheetah_template -import logging as LOG +import logging +import os import sys from client import Client @@ -27,18 +28,22 @@ from optparse import OptionParser FORMAT = "json" CLI_TEMPLATE = "../quantum/cli_output.template" -#TODO(salvatore-orlando): do proper logging! +LOG = logging.getLogger('cli') + def _handle_exception(ex): 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): + 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) - print "Failed to create network: %s" % status_code or '' - print "Error message:%s" % message or '' - + msg_1 = "Command failed with error code: %s" % status_code or '' + msg_2 = "Error message:%s" % message or '' + 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 """ @@ -48,11 +53,14 @@ def prepare_output(cmd, tenant_id, response): template_file = open(CLI_TEMPLATE).read() output = str(cheetah_template.Template(template_file, searchList=response)) - return output + 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 @@ -64,16 +72,19 @@ def create_net(client, *args): try: res = client.create_network(data) new_net_id = res["networks"]["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 @@ -85,10 +96,13 @@ def detail_net(client, *args): tenant_id, network_id = args try: res = client.list_network_details(network_id)["networks"]["network"] + LOG.debug("Operation 'list_network_details' executed.") ports = client.list_ports(network_id) + LOG.debug("Operation 'list_ports' executed.") res['ports'] = ports for port in ports["ports"]: att_data = client.list_port_attachments(network_id, port['id']) + LOG.debug("Operation 'list_attachments' executed.") port['attachment'] = att_data["attachment"] output = prepare_output("detail_net", tenant_id, dict(network=res)) @@ -102,6 +116,7 @@ def rename_net(client, *args): data = {'network': {'net-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['id'] = network_id output = prepare_output("rename_net", tenant_id, dict(network=data)) @@ -114,6 +129,7 @@ def list_ports(client, *args): tenant_id, network_id = args try: ports = client.list_ports(network_id) + LOG.debug("Operation 'list_ports' executed.") output = prepare_output("list_ports", tenant_id, dict(ports=ports)) print output except Exception as ex: @@ -124,6 +140,7 @@ 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["ports"]["port"]["id"] output = prepare_output("create_port", tenant_id, dict(network_id=network_id, @@ -137,6 +154,7 @@ 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)) @@ -150,8 +168,9 @@ def detail_port(client, *args): tenant_id, network_id, port_id = args try: port = client.list_port_details(network_id, port_id)["ports"]["port"] - #NOTE(salvatore-orland): current API implementation does not - #return attachment with GET operation on port. Once API alignment + 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 port['attachment'] = '' output = prepare_output("detail_port", tenant_id, @@ -167,6 +186,7 @@ def set_port_state(client, *args): data = {'port': {'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['id'] = port_id output = prepare_output("set_port_state", tenant_id, @@ -181,10 +201,11 @@ def plug_iface(client, *args): try: data = {'port': {'attachment': '%s' % attachment}} client.attach_resource(network_id, port_id, data) + LOG.debug("Operation 'attach_resource' executed.") output = prepare_output("plug_interface", tenant_id, - dict(network_id = network_id, - port_id = port_id, - attachment = attachment)) + dict(network_id=network_id, + port_id=port_id, + attachment=attachment)) print output except Exception as ex: _handle_exception(ex) @@ -194,9 +215,10 @@ 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_interface", tenant_id, - dict(network_id = network_id, - port_id = port_id)) + dict(network_id=network_id, + port_id=port_id)) print output except Exception as ex: _handle_exception(ex) @@ -229,7 +251,7 @@ commands = { "args": ["tenant-id", "net-id", "port-id"]}, "set_port_state": { "func": set_port_state, - "args": ["tenant-id", "net-id", "port-id","new_state"]}, + "args": ["tenant-id", "net-id", "port-id", "new_state"]}, "detail_port": { "func": detail_port, "args": ["tenant-id", "net-id", "port-id"]}, @@ -281,13 +303,22 @@ if __name__ == "__main__": 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("-lf", "--logfile", dest="logfile", + type="string", default="syslog", help="log file path") options, args = parser.parse_args() if options.verbose: - LOG.basicConfig(level=LOG.DEBUG) + LOG.setLevel(logging.DEBUG) else: - LOG.basicConfig(level=LOG.WARN) + 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() @@ -303,11 +334,11 @@ if __name__ == "__main__": 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)) + 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.debug("Command execution completed") + + LOG.info("Command execution completed") sys.exit(0) diff --git a/quantum/cli_output.template b/quantum/cli_output.template index 96baef7352..18f0409265 100644 --- a/quantum/cli_output.template +++ b/quantum/cli_output.template @@ -21,6 +21,7 @@ New name is: $network.name Ports on Virtual Network: $network_id #for $port in $ports \tLogical Port: $port.id +#end for #elif $cmd == 'create_port' Created new Logical Port with ID: $port_id on Virtual Network: $network_id diff --git a/quantum/client.py b/quantum/client.py index f6e1b6bfe3..9ac991ec31 100644 --- a/quantum/client.py +++ b/quantum/client.py @@ -97,8 +97,7 @@ class Client(object): # facilitate stubout for testing conn.request(method, action, body, headers) return conn.getresponse() - - + def do_request(self, method, action, body=None, headers=None, params=None): """ @@ -150,7 +149,8 @@ class Client(object): else: # Create exception with HTTP status code and message ex = Exception("Server returned error: %s" % status_code) - ex.args = ([dict(status_code=status_code, message=res.read())],) + ex.args = ([dict(status_code=status_code, + message=res.read())],) raise ex except (socket.error, IOError), e: diff --git a/tests/unit/client_tools/__init__.py b/tests/unit/client_tools/__init__.py index bafb9e291f..848908a953 100644 --- a/tests/unit/client_tools/__init__.py +++ b/tests/unit/client_tools/__init__.py @@ -12,4 +12,4 @@ # 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. \ No newline at end of file +# under the License. diff --git a/tests/unit/client_tools/stubs.py b/tests/unit/client_tools/stubs.py index df327b51d4..8a01a8fb57 100644 --- a/tests/unit/client_tools/stubs.py +++ b/tests/unit/client_tools/stubs.py @@ -13,35 +13,21 @@ # 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 quantum import client from tests.unit import testlib_api -def stubout_send_request(stubs, api): - """Simulates a failure in fetch image_glance_disk.""" +class FakeStdout: - def fake_send_request(self, conn, method, action, body, headers): - # ignore headers and connection - req = testlib_api.create_request(action, body, - "application/json", method) - res = req.get_response(api) - return res - - stubs.Set(client.Client, '_send_request', fake_send_request) - - -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: @@ -50,31 +36,30 @@ class FakeStdout: class FakeHTTPConnection: - """ stub HTTP connection class for CLI testing """ + """ 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') + 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 macking a webob.Response look like a + """ Trick for macking a webob.Response look like a httplib.Response - + """ return res.body setattr(res, 'read', _fake_read) - return res - + return res diff --git a/tests/unit/test_cli.py b/tests/unit/test_cli.py index 47b7d97a03..5bbe754f0b 100644 --- a/tests/unit/test_cli.py +++ b/tests/unit/test_cli.py @@ -16,9 +16,9 @@ # under the License. # @author: Salvatore Orlando, Citrix Systems -""" Module containing unit tests for Quantum +""" Module containing unit tests for Quantum command line interface - + """ @@ -30,12 +30,12 @@ from quantum import api as server from quantum import cli from quantum.client import Client from quantum.db import api as db -from quantum.manager import QuantumManager 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): @@ -48,23 +48,21 @@ class CLITest(unittest.TestCase): 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) - self.manager = QuantumManager(options).get_plugin() + 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] + 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)) @@ -96,89 +94,52 @@ class CLITest(unittest.TestCase): # 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: + + def test_list_networks_api(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.manager, self.tenant_id) + + cli.list_nets(self.client, self.tenant_id) LOG.debug("Operation completed. Verifying result") LOG.debug(self.fake_stdout.content) self._verify_list_networks() - except: - LOG.exception("Exception caught: %s", sys.exc_info()) - self.fail("test_list_network failed due to an exception") - - - def test_list_networks_api(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.api_list_nets(self.client, self.tenant_id) - LOG.debug("Operation completed. Verifying result") - LOG.debug(self.fake_stdout.content) - self._verify_list_networks() - except: + except: LOG.exception("Exception caught: %s", sys.exc_info()) self.fail("test_list_network_api failed due to an exception") - def test_create_network(self): - try: - cli.create_net(self.manager, self.tenant_id, "test") + def test_create_network_api(self): + try: + cli.create_net(self.client, self.tenant_id, "test") LOG.debug("Operation completed. Verifying result") LOG.debug(self.fake_stdout.content) self._verify_create_network() - except: - LOG.exception("Exception caught: %s", sys.exc_info()) - self.fail("test_create_network failed due to an exception") - - def test_create_network_api(self): - try: - cli.api_create_net(self.client, self.tenant_id, "test") - LOG.debug("Operation completed. Verifying result") - LOG.debug(self.fake_stdout.content) - self._verify_create_network() - except: + except: LOG.exception("Exception caught: %s", sys.exc_info()) self.fail("test_create_network_api failed due to an exception") - + def _prepare_test_delete_network(self): # Pre-populate data for testing using db api db.network_create(self.tenant_id, self.network_name_1) net_id = db.network_list(self.tenant_id)[0]['uuid'] return net_id - def test_delete_network(self): - try: + def test_delete_network_api(self): + try: network_id = self._prepare_test_delete_network() - cli.delete_net(self.manager, self.tenant_id, network_id) + cli.delete_net(self.client, self.tenant_id, network_id) LOG.debug("Operation completed. Verifying result") LOG.debug(self.fake_stdout.content) self._verify_delete_network(network_id) - except: - LOG.exception("Exception caught: %s", sys.exc_info()) - self.fail("test_delete_network failed due to an exception") - - - def test_delete_network_api(self): - try: - network_id = self._prepare_test_delete_network() - cli.api_delete_net(self.client, self.tenant_id, network_id) - LOG.debug("Operation completed. Verifying result") - LOG.debug(self.fake_stdout.content) - self._verify_delete_network(network_id) - except: + except: LOG.exception("Exception caught: %s", sys.exc_info()) self.fail("test_delete_network_api failed due to an exception") - + def test_detail_network_api(self): # Load some data into the datbase net = db.network_create(self.tenant_id, self.network_name_1) - db.port_create(net['uuid']) + db.port_create(net['uuid']) port = db.port_create(net['uuid']) - cli.api_detail_net(self.client, self.tenant_id, net['uuid']) - db.port_set_attachment(port['uuid'], net['uuid'], "test_iface_id") \ No newline at end of file + cli.detail_net(self.client, self.tenant_id, net['uuid']) + db.port_set_attachment(port['uuid'], net['uuid'], "test_iface_id") From 5ccc126263e1104e8852dd2850b0b42c0804aa4f Mon Sep 17 00:00:00 2001 From: Salvatore Orlando Date: Thu, 25 Aug 2011 01:52:32 +0100 Subject: [PATCH 41/52] Adding unit test for rename_network --- quantum/cli.py | 8 +++--- quantum/cli_output.template | 2 +- quantum/client.py | 16 ++++++----- tests/unit/test_cli.py | 56 ++++++++++++++++++++++++------------- 4 files changed, 51 insertions(+), 31 deletions(-) diff --git a/quantum/cli.py b/quantum/cli.py index dbdb91a39a..15f64fab6f 100644 --- a/quantum/cli.py +++ b/quantum/cli.py @@ -38,8 +38,8 @@ def _handle_exception(ex): 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 '' - msg_2 = "Error message:%s" % message or '' + msg_1 = "Command failed with error code: %s" % (status_code or '') + msg_2 = "Error message:%s" % (message or '') LOG.exception(msg_1 + "-" + msg_2) print msg_1 print msg_2 @@ -118,8 +118,8 @@ def rename_net(client, *args): client.update_network(network_id, data) LOG.debug("Operation 'update_network' executed.") # Response has no body. Use data for populating output - data['id'] = network_id - output = prepare_output("rename_net", tenant_id, dict(network=data)) + data['network']['id'] = network_id + output = prepare_output("rename_net", tenant_id, data) print output except Exception as ex: _handle_exception(ex) diff --git a/quantum/cli_output.template b/quantum/cli_output.template index 18f0409265..1e1abbd2bd 100644 --- a/quantum/cli_output.template +++ b/quantum/cli_output.template @@ -16,7 +16,7 @@ Remote Interfaces on Virtual Network #end for #elif $cmd == 'rename_net' Renamed Virtual Network with ID: $network.id for Tenant $tenant_id, -New name is: $network.name +New name is: $network['net-name'] #elif $cmd == 'list_ports' Ports on Virtual Network: $network_id #for $port in $ports diff --git a/quantum/client.py b/quantum/client.py index 9ac991ec31..5898d92b71 100644 --- a/quantum/client.py +++ b/quantum/client.py @@ -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 +LOG = logging.getLogger('client') + class api_call(object): """A Decorator to add support for format and tenant overriding""" @@ -112,7 +115,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") @@ -124,12 +127,10 @@ class Client(object): if type(params) is dict: action += '?' + urllib.urlencode(params) - try: 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) @@ -138,7 +139,6 @@ class Client(object): c = connection_type(self.host, self.port, **certs) else: c = connection_type(self.host, self.port) - res = self._send_request(c, method, action, body, headers) status_code = self.get_status_code(res) if status_code in (httplib.OK, @@ -148,11 +148,13 @@ class Client(object): return self.deserialize(res) else: # Create exception with HTTP status code and message + error_message = res.read() + LOG.debug("Server returned error: %s", status_code) + LOG.debug("Error message: %s", error_message) ex = Exception("Server returned error: %s" % status_code) ex.args = ([dict(status_code=status_code, - message=res.read())],) + message=error_message)],) raise ex - except (socket.error, IOError), e: raise Exception("Unable to connect to " "server. Got error: %s" % e) @@ -172,7 +174,7 @@ class Client(object): return Serializer().serialize(data, self.content_type()) def deserialize(self, data): - if self.get_status_code(data) == 202: + if self.get_status_code(data) in (202, 204): return data.read() return Serializer().deserialize(data.read(), self.content_type()) diff --git a/tests/unit/test_cli.py b/tests/unit/test_cli.py index 5bbe754f0b..f9aee4317e 100644 --- a/tests/unit/test_cli.py +++ b/tests/unit/test_cli.py @@ -95,7 +95,19 @@ class CLITest(unittest.TestCase): # 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_api(self): + 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, + 'net-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 test_list_networks(self): try: # Pre-populate data for testing using db api db.network_create(self.tenant_id, self.network_name_1) @@ -107,9 +119,9 @@ class CLITest(unittest.TestCase): self._verify_list_networks() except: LOG.exception("Exception caught: %s", sys.exc_info()) - self.fail("test_list_network_api failed due to an exception") + self.fail("test_list_networks failed due to an exception") - def test_create_network_api(self): + def test_create_network(self): try: cli.create_net(self.client, self.tenant_id, "test") LOG.debug("Operation completed. Verifying result") @@ -117,29 +129,35 @@ class CLITest(unittest.TestCase): self._verify_create_network() except: LOG.exception("Exception caught: %s", sys.exc_info()) - self.fail("test_create_network_api failed due to an exception") + self.fail("test_create_network failed due to an exception") - def _prepare_test_delete_network(self): - # Pre-populate data for testing using db api - db.network_create(self.tenant_id, self.network_name_1) - net_id = db.network_list(self.tenant_id)[0]['uuid'] - return net_id - - def test_delete_network_api(self): + def test_delete_network(self): try: - network_id = self._prepare_test_delete_network() + 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) LOG.debug("Operation completed. Verifying result") LOG.debug(self.fake_stdout.content) self._verify_delete_network(network_id) except: LOG.exception("Exception caught: %s", sys.exc_info()) - self.fail("test_delete_network_api failed due to an exception") + self.fail("test_delete_network failed due to an exception") - def test_detail_network_api(self): - # Load some data into the datbase + def test_detail_network(self): + # Load some data into the datbase + net = db.network_create(self.tenant_id, self.network_name_1) + db.port_create(net['uuid']) + port = db.port_create(net['uuid']) + cli.detail_net(self.client, self.tenant_id, net['uuid']) + db.port_set_attachment(port['uuid'], net['uuid'], "test_iface_id") + + def test_rename_network(self): + try: net = db.network_create(self.tenant_id, self.network_name_1) - db.port_create(net['uuid']) - port = db.port_create(net['uuid']) - cli.detail_net(self.client, self.tenant_id, net['uuid']) - db.port_set_attachment(port['uuid'], net['uuid'], "test_iface_id") + network_id = net['uuid'] + cli.rename_net(self.client, self.tenant_id, + network_id, self.network_name_2) + self._verify_rename_network() + except: + LOG.exception("Exception caught: %s", sys.exc_info()) + self.fail("test_rename_network failed due to an exception") From 38b54064816233a51ee827c8eaf7d536788bf860 Mon Sep 17 00:00:00 2001 From: Salvatore Orlando Date: Thu, 25 Aug 2011 12:49:38 +0100 Subject: [PATCH 42/52] Completing Unit Tests --- quantum/cli.py | 12 ++- quantum/cli_output.template | 5 + tests/unit/test_cli.py | 177 ++++++++++++++++++++++++++++++++++-- 3 files changed, 179 insertions(+), 15 deletions(-) diff --git a/quantum/cli.py b/quantum/cli.py index 15f64fab6f..5ebdde2683 100644 --- a/quantum/cli.py +++ b/quantum/cli.py @@ -130,7 +130,9 @@ def list_ports(client, *args): try: ports = client.list_ports(network_id) LOG.debug("Operation 'list_ports' executed.") - output = prepare_output("list_ports", tenant_id, dict(ports=ports)) + data = ports + data['network_id'] = network_id + output = prepare_output("list_ports", tenant_id, data) print output except Exception as ex: _handle_exception(ex) @@ -167,7 +169,7 @@ def delete_port(client, *args): def detail_port(client, *args): tenant_id, network_id, port_id = args try: - port = client.list_port_details(network_id, port_id)["ports"]["port"] + port = client.list_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 @@ -188,9 +190,9 @@ def set_port_state(client, *args): 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['id'] = port_id - output = prepare_output("set_port_state", tenant_id, - dict(network_id=network_id, port=data)) + 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) diff --git a/quantum/cli_output.template b/quantum/cli_output.template index 1e1abbd2bd..e2857bdd21 100644 --- a/quantum/cli_output.template +++ b/quantum/cli_output.template @@ -30,6 +30,11 @@ for tenant: $tenant_id 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['port-state'] +on Virtual Network: $network_id +for tenant: $tenant_id #elif $cmd == 'detail_port' Logical Port ID: $port.id On Virtual Network: $network_id diff --git a/tests/unit/test_cli.py b/tests/unit/test_cli.py index f9aee4317e..2b814eadab 100644 --- a/tests/unit/test_cli.py +++ b/tests/unit/test_cli.py @@ -106,6 +106,73 @@ class CLITest(unittest.TestCase): # 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, 'port-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_detail_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':''} + # Fill CLI template + output = cli.prepare_output('detail_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 test_list_networks(self): try: @@ -114,35 +181,38 @@ class CLITest(unittest.TestCase): db.network_create(self.tenant_id, self.network_name_2) cli.list_nets(self.client, self.tenant_id) - LOG.debug("Operation completed. Verifying result") - LOG.debug(self.fake_stdout.content) - self._verify_list_networks() 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") - LOG.debug("Operation completed. Verifying result") - LOG.debug(self.fake_stdout.content) - self._verify_create_network() 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) - LOG.debug("Operation completed. Verifying result") - LOG.debug(self.fake_stdout.content) - self._verify_delete_network(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_detail_network(self): # Load some data into the datbase net = db.network_create(self.tenant_id, self.network_name_1) @@ -157,7 +227,94 @@ class CLITest(unittest.TestCase): network_id = net['uuid'] cli.rename_net(self.client, self.tenant_id, network_id, self.network_name_2) - self._verify_rename_network() 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_detail_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.detail_port(self.client, self.tenant_id, network_id, port_id) + except: + LOG.exception("Exception caught: %s", sys.exc_info()) + self.fail("test_detail_port failed due to an exception") + + LOG.debug("Operation completed. Verifying result") + LOG.debug(self.fake_stdout.content) + self._verify_detail_port(network_id, port_id) From 99a136b03a5db18ed36cb7cbb937ae65740c9725 Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Thu, 25 Aug 2011 11:39:44 -0700 Subject: [PATCH 43/52] Changing the order of imports (to satisfy convention). --- quantum/plugins/cisco/common/cisco_credentials.py | 2 +- quantum/plugins/cisco/l2network_model.py | 2 +- quantum/plugins/cisco/l2network_plugin.py | 2 +- quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py | 2 +- quantum/plugins/cisco/ucs/cisco_ucs_plugin.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/quantum/plugins/cisco/common/cisco_credentials.py b/quantum/plugins/cisco/common/cisco_credentials.py index f3c63065ce..299c5d8f02 100644 --- a/quantum/plugins/cisco/common/cisco_credentials.py +++ b/quantum/plugins/cisco/common/cisco_credentials.py @@ -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) diff --git a/quantum/plugins/cisco/l2network_model.py b/quantum/plugins/cisco/l2network_model.py index f99a97bccf..1ed4b56bd5 100644 --- a/quantum/plugins/cisco/l2network_model.py +++ b/quantum/plugins/cisco/l2network_model.py @@ -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) diff --git a/quantum/plugins/cisco/l2network_plugin.py b/quantum/plugins/cisco/l2network_plugin.py index 7039923f16..c85c46786c 100644 --- a/quantum/plugins/cisco/l2network_plugin.py +++ b/quantum/plugins/cisco/l2network_plugin.py @@ -27,8 +27,8 @@ 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 diff --git a/quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py b/quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py index faba86fcbd..439d447581 100644 --- a/quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py +++ b/quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py @@ -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 diff --git a/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py b/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py index f6b7daf5ff..a867304ab4 100644 --- a/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py +++ b/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py @@ -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 From ea6c9343a9d91b8235b1e0b9108ec07c46c8d05b Mon Sep 17 00:00:00 2001 From: Ying Liu Date: Thu, 25 Aug 2011 12:30:20 -0700 Subject: [PATCH 44/52] move faults/exceptions to l2network package, remove unecessary faults definitions change the portprofile action api's method fix imports order and other comments issues --- extensions/_credential_view.py | 6 +- extensions/_exceptions.py | 160 ------------------ extensions/_faults.py | 153 ----------------- extensions/_novatenant_view.py | 5 +- extensions/_pprofiles.py | 2 +- extensions/_qos_view.py | 4 +- extensions/credential.py | 14 +- extensions/novatenant.py | 33 +--- extensions/portprofile.py | 9 +- extensions/qos.py | 7 +- .../cisco/tests/unit/test_cisco_extension.py | 16 +- 11 files changed, 34 insertions(+), 375 deletions(-) delete mode 100644 extensions/_exceptions.py delete mode 100644 extensions/_faults.py diff --git a/extensions/_credential_view.py b/extensions/_credential_view.py index 453cd8b24d..3c8ce49a49 100644 --- a/extensions/_credential_view.py +++ b/extensions/_credential_view.py @@ -47,12 +47,12 @@ class ViewBuilder(object): return credential def _build_simple(self, credential_data): - """Return a simple model of a server.""" + """Return a simple description of credential.""" return dict(credential=dict(id=credential_data['credential_id'])) def _build_detail(self, credential_data): - """Return a simple model of a server.""" + """Return a detailed description of credential.""" return dict(credential=dict(id=credential_data['credential_id'], name=credential_data['user_name'], - password=credential_data['password'])) \ No newline at end of file + password=credential_data['password'])) diff --git a/extensions/_exceptions.py b/extensions/_exceptions.py deleted file mode 100644 index 2310d44e6d..0000000000 --- a/extensions/_exceptions.py +++ /dev/null @@ -1,160 +0,0 @@ -""" -# 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 - - -# pylint: disable-msg=E0602 -class ExtensionException(Exception): - """Quantum Cisco api Exception - - Taken from nova.exception.NovaException - To correctly use this class, inherit from it and define - a 'message' property. That message will get printf'd - with the keyword arguments provided to the constructor. - - """ - message = _("An unknown exception occurred.") - - def __init__(self, **kwargs): - try: - self._error_string = self.message % kwargs - - except Exception: - # at least get the core message out if something happened - self._error_string = self.message - - def __str__(self): - """Error Msg""" - return self._error_string - - -class ProcessExecutionError(IOError): - """Process Exe Error""" - def __init__(self, stdout=None, stderr=None, exit_code=None, cmd=None, - description=None): - if description is None: - description = "Unexpected error while running command." - if exit_code is None: - exit_code = '-' - message = "%s\nCommand: %s\nExit code: %s\nStdout: %r\nStderr: %r" % ( - description, cmd, exit_code, stdout, stderr) - IOError.__init__(self, message) - - -class Error(Exception): - """Error Class""" - def __init__(self, message=None): - super(Error, self).__init__(message) - - -class ApiError(Error): - """Api Error""" - def __init__(self, message='Unknown', code='Unknown'): - self.message = message - self.code = code - super(ApiError, self).__init__('%s: %s' % (code, message)) - - -class NotFound(ExtensionException): - """Error Msg""" - pass - - -class ClassNotFound(NotFound): - """Extension Error Msg""" - message = _("Class %(class_name)s could not be found") - - -class PortprofileNotFound(NotFound): - """Extension Error Msg""" - message = _("Portprofile %(_id)s could not be found") - - -class NovatenantNotFound(NotFound): - """Extension Error Msg""" - message = _("Novatenant %(_id)s could not be found") - - -class PortNotFound(NotFound): - """Extension Error""" - message = _("Port %(port_id)s could not be found " \ - "on Network %(net_id)s") - - -class CredentialNotFound(NotFound): - """Extension Error""" - message = _("Credential %(_id)s could not be found") - - -class QosNotFound(NotFound): - """Extension Error""" - message = _("QoS %(_id)s could not be found") - - -class Duplicate(Error): - """Duplication Error""" - pass - - -class NotAuthorized(Error): - "Not Auth Error" - pass - - -class NotEmpty(Error): - """Not Empty Error""" - pass - - -class Invalid(Error): - """Invalid Error""" - pass - - -class InvalidContentType(Invalid): - message = _("Invalid content type %(content_type)s.") - - -class BadInputError(Exception): - """Error resulting from a client sending bad input to a server""" - pass - - -class MissingArgumentError(Error): - """Miss arg error""" - pass - - -def wrap_exception(afunc): - """Wrap Exception""" - def _wrap(*args, **kw): - """Internal Wrap Exception func""" - try: - return afunc(*args, **kw) - except Exception, exp: - if not isinstance(exp, Error): - #exc_type, exc_value, exc_traceback = sys.exc_info() - logging.exception('Uncaught exception') - #logging.error(traceback.extract_stack(exc_traceback)) - raise Error(str(exp)) - raise - _wrap.func_name = afunc.func_name - return _wrap diff --git a/extensions/_faults.py b/extensions/_faults.py deleted file mode 100644 index 5b9c233ec4..0000000000 --- a/extensions/_faults.py +++ /dev/null @@ -1,153 +0,0 @@ -""" -# 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", - 420: "networkNotFound", - 421: "PortprofileInUse", - 430: "portNotFound", - 431: "requestedStateInvalid", - 432: "portInUse", - 440: "alreadyAttached", - 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.') diff --git a/extensions/_novatenant_view.py b/extensions/_novatenant_view.py index 6843361fb2..a25654916e 100644 --- a/extensions/_novatenant_view.py +++ b/extensions/_novatenant_view.py @@ -18,6 +18,7 @@ # @author: Ying Liu, Cisco Systems, Inc. # """ +from quantum.plugins.cisco.common import cisco_constants as const def get_view_builder(req): @@ -39,8 +40,8 @@ class ViewBuilder(object): def build_host(self, host_data): """Return host description.""" - return dict(host_list=host_data['host_list']) + return dict(host_list=host_data[const.HOST_LIST]) def build_vif(self, vif_data): """Return VIF description.""" - return dict(vif_desc=vif_data['vif_desc']) + return dict(vif_desc=vif_data[const.VIF_DESC]) diff --git a/extensions/_pprofiles.py b/extensions/_pprofiles.py index ba94c472bc..cf851bae08 100644 --- a/extensions/_pprofiles.py +++ b/extensions/_pprofiles.py @@ -47,7 +47,7 @@ class ViewBuilder(object): return portprofile def _build_simple(self, portprofile_data): - """Return a simple model of a portprofile""" + """Return a simple description of a portprofile""" return dict(portprofile=dict(id=portprofile_data['profile_id'])) def _build_detail(self, portprofile_data): diff --git a/extensions/_qos_view.py b/extensions/_qos_view.py index ca3f76caf1..3ad0d30c3c 100644 --- a/extensions/_qos_view.py +++ b/extensions/_qos_view.py @@ -46,11 +46,11 @@ class ViewBuilder(object): return qos def _build_simple(self, qos_data): - """Return a simple model of a server.""" + """Return a simple description of qos.""" return dict(qos=dict(id=qos_data['qos_id'])) def _build_detail(self, qos_data): - """Return a simple model of a server.""" + """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'])) diff --git a/extensions/credential.py b/extensions/credential.py index 0b69284818..31c49bdd09 100644 --- a/extensions/credential.py +++ b/extensions/credential.py @@ -21,13 +21,13 @@ import logging from webob import exc -from extensions import _credential_view as credential_view -from quantum.plugins.cisco.common import cisco_exceptions as exception -from extensions import _faults as faults +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') @@ -36,7 +36,7 @@ class Credential(object): """extension class Credential""" def __init__(self): pass - + @classmethod def get_name(cls): """ Returns Ext Resource Name """ @@ -67,7 +67,6 @@ class Credential(object): """ 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)] @@ -84,7 +83,7 @@ class CredentialController(common.QuantumController): 'required': True}, { 'param-name': 'password', 'required': True}] - + _serialization_metadata = { "application/xml": { "attributes": { @@ -96,7 +95,7 @@ class CredentialController(common.QuantumController): 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) @@ -165,4 +164,3 @@ class CredentialController(common.QuantumController): return exc.HTTPAccepted() except exception.CredentialNotFound as exp: return faults.Fault(faults.CredentialNotFound(exp)) - diff --git a/extensions/novatenant.py b/extensions/novatenant.py index c4ab55db0b..84453ccfb5 100644 --- a/extensions/novatenant.py +++ b/extensions/novatenant.py @@ -21,12 +21,11 @@ from webob import exc from extensions import _novatenant_view as novatenant_view -from quantum.common import exceptions as qexception -from extensions import _faults as faults - 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): @@ -97,33 +96,9 @@ class NovatenantsController(common.QuantumController): def __init__(self, plugin): self._resource_name = 'novatenant' self._plugin = plugin - - def index(self, request, tenant_id): - """ Returns a list of novatenant ids """ - return "novatenant is a dummy resource" - - def _items(self, request, tenant_id, is_detail): - """ Returns a list of novatenants. """ - return "novatenant is a dummy resource" - - # pylint: disable-msg=E1101,W0613 - def show(self, request, tenant_id, id): - """ Returns novatenant details for the given novatenant id """ - return "novatenant is a dummy resource" - - def create(self, request, tenant_id): - """ Creates a new novatenant for a given tenant """ - return "novatenant is a dummy resource" - - def update(self, request, tenant_id, id): - """ Updates the name for the novatenant with the given id """ - return "novatenant is a dummy resource" - - def delete(self, request, tenant_id, id): - """ Destroys the Novatenant with the given id """ - return "novatenant is a dummy resource" - + #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 diff --git a/extensions/portprofile.py b/extensions/portprofile.py index c20eea3ac9..4dd9c7b41c 100644 --- a/extensions/portprofile.py +++ b/extensions/portprofile.py @@ -22,13 +22,12 @@ from webob import exc from extensions import _pprofiles as pprofiles_view -from quantum.plugins.cisco.common import cisco_exceptions as exception -from quantum.common import exceptions as qexception -from extensions import _faults as faults - 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): @@ -67,7 +66,7 @@ class Portprofile(object): parent_resource = dict(member_name="tenant", collection_name="extensions/csco/tenants") member_actions = {'associate_portprofile': "PUT", - 'disassociate_portprofile': "POST"} + 'disassociate_portprofile': "PUT"} controller = PortprofilesController(QuantumManager.get_plugin()) return [extensions.ResourceExtension('portprofiles', controller, parent=parent_resource, diff --git a/extensions/qos.py b/extensions/qos.py index bcff6de8af..6e8cb72334 100644 --- a/extensions/qos.py +++ b/extensions/qos.py @@ -22,13 +22,12 @@ import logging from webob import exc from extensions import _qos_view as qos_view -from quantum.plugins.cisco.common import cisco_exceptions as exception -from extensions import _exceptions as exte -from extensions import _faults as faults - 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') diff --git a/quantum/plugins/cisco/tests/unit/test_cisco_extension.py b/quantum/plugins/cisco/tests/unit/test_cisco_extension.py index a6bbe3c649..e1f2391bf4 100644 --- a/quantum/plugins/cisco/tests/unit/test_cisco_extension.py +++ b/quantum/plugins/cisco/tests/unit/test_cisco_extension.py @@ -68,7 +68,7 @@ class PortprofileExtensionTest(unittest.TestCase): parent_resource = dict(member_name="tenant", collection_name="extensions/csco/tenants") member_actions = {'associate_portprofile': "PUT", - 'disassociate_portprofile': "POST"} + 'disassociate_portprofile': "PUT"} controller = portprofile.PortprofilesController( QuantumManager.get_plugin()) res_ext = extensions.ResourceExtension('portprofiles', controller, @@ -206,7 +206,7 @@ class PortprofileExtensionTest(unittest.TestCase): rename_response = self.test_app.put(rename_path, rename_req_body) self.assertEqual(200, rename_response.status_int) - # Clean Up - Delete the Port Profile + # Clean Up - Delete the Port Profile self.tear_down_profile(rename_path) LOG.debug("test_update_portprofile - END") @@ -410,7 +410,7 @@ class PortprofileExtensionTest(unittest.TestCase): "/disassociate_portprofile" disassociate_path = str(disassociate_path_temp) - disassociate_response = self.test_app.post( + disassociate_response = self.test_app.put( disassociate_path, req_assign_body, content_type=self.contenttype) self.assertEqual(202, disassociate_response.status_int) @@ -433,7 +433,7 @@ class PortprofileExtensionTest(unittest.TestCase): """ Tear down associate profile""" - self.test_app.post(dissociate_profile_path, req_body, + self.test_app.put(dissociate_profile_path, req_body, content_type=self.contenttype) self.tear_down_profile(delete_profile_path) @@ -475,8 +475,8 @@ class NovatenantExtensionTest(unittest.TestCase): 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) + host_path, req_body, + content_type=self.contenttype) self.assertEqual(200, host_response.status_int) LOG.debug("test_get_host - END") @@ -487,8 +487,8 @@ class NovatenantExtensionTest(unittest.TestCase): 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='*') + host_path, 'BAD_REQUEST', + content_type=self.contenttype, status='*') self.assertEqual(400, host_response.status_int) LOG.debug("test_get_hostBADRequest - END") From 6b477714ba576b8a858b9ad222b14e7fe77e58ca Mon Sep 17 00:00:00 2001 From: Ying Liu Date: Thu, 25 Aug 2011 12:34:01 -0700 Subject: [PATCH 45/52] add cisco_faults under l2network package. --- quantum/plugins/cisco/common/cisco_faults.py | 148 +++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 quantum/plugins/cisco/common/cisco_faults.py diff --git a/quantum/plugins/cisco/common/cisco_faults.py b/quantum/plugins/cisco/common/cisco_faults.py new file mode 100644 index 0000000000..515d67598a --- /dev/null +++ b/quantum/plugins/cisco/common/cisco_faults.py @@ -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.') From 12bb903815e11d23562cac925ce95f18230e9053 Mon Sep 17 00:00:00 2001 From: Dan Wendlandt Date: Fri, 26 Aug 2011 01:02:41 -0700 Subject: [PATCH 46/52] lp834491: change plugin to work with API code after the API alignment merge --- .../plugins/openvswitch/ovs_quantum_plugin.py | 25 ++++++++++--------- quantum/plugins/openvswitch/run_tests.py | 3 +++ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/quantum/plugins/openvswitch/ovs_quantum_plugin.py b/quantum/plugins/openvswitch/ovs_quantum_plugin.py index d58b39de85..928e164644 100644 --- a/quantum/plugins/openvswitch/ovs_quantum_plugin.py +++ b/quantum/plugins/openvswitch/ovs_quantum_plugin.py @@ -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) diff --git a/quantum/plugins/openvswitch/run_tests.py b/quantum/plugins/openvswitch/run_tests.py index 15a7583b43..38e361392b 100644 --- a/quantum/plugins/openvswitch/run_tests.py +++ b/quantum/plugins/openvswitch/run_tests.py @@ -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") From 673edc3141d5f41e687b0c242a18283bf6b23cb2 Mon Sep 17 00:00:00 2001 From: Salvatore Orlando Date: Fri, 26 Aug 2011 09:41:19 +0100 Subject: [PATCH 47/52] Addressing comments from Dan Also solved issue with output from plug_iface and unplug_iface --- bin/cli | 8 +++---- quantum/cli_lib.py | 24 +++++++-------------- quantum/cli_output.template | 37 +++++++++++++++++--------------- quantum/client.py | 1 - tests/unit/client_tools/stubs.py | 2 +- tests/unit/test_cli.py | 35 +++++++++++------------------- tools/pip-requires | 1 - 7 files changed, 45 insertions(+), 63 deletions(-) diff --git a/bin/cli b/bin/cli index 20ef7b2aeb..6fd3e3ad54 100755 --- a/bin/cli +++ b/bin/cli @@ -55,8 +55,8 @@ commands = { "delete_net": { "func": cli_lib.delete_net, "args": ["tenant-id", "net-id"]}, - "detail_net": { - "func": cli_lib.detail_net, + "show_net": { + "func": cli_lib.show_net, "args": ["tenant-id", "net-id"]}, "rename_net": { "func": cli_lib.rename_net, @@ -73,8 +73,8 @@ commands = { "set_port_state": { "func": cli_lib.set_port_state, "args": ["tenant-id", "net-id", "port-id", "new_state"]}, - "detail_port": { - "func": cli_lib.detail_port, + "show_port": { + "func": cli_lib.show_port, "args": ["tenant-id", "net-id", "port-id"]}, "plug_iface": { "func": cli_lib.plug_iface, diff --git a/quantum/cli_lib.py b/quantum/cli_lib.py index cea8d3ae72..bffda703b2 100755 --- a/quantum/cli_lib.py +++ b/quantum/cli_lib.py @@ -95,22 +95,14 @@ def delete_net(client, *args): _handle_exception(ex) -def detail_net(client, *args): +def show_net(client, *args): tenant_id, network_id = args try: - #NOTE(salvatore-orlando): Implementing non-efficient version - #for now, at least until plugins will not provide correct behaviour - #for the show_network_details operation + #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.") - ports = client.list_ports(network_id) - LOG.debug("Operation 'list_ports' executed.") - res.update(ports) - for port in ports['ports']: - att_data = client.show_port_attachment(network_id, port['id']) - LOG.debug("Operation 'show_port_attachment' executed.") - port['attachment'] = att_data['attachment'].get('id', None) - output = prepare_output("detail_net", tenant_id, dict(network=res)) + output = prepare_output("show_net", tenant_id, dict(network=res)) print output except Exception as ex: _handle_exception(ex) @@ -171,7 +163,7 @@ def delete_port(client, *args): return -def detail_port(client, *args): +def show_port(client, *args): tenant_id, network_id, port_id = args try: port = client.show_port_details(network_id, port_id)["port"] @@ -180,7 +172,7 @@ def detail_port(client, *args): #return attachment with GET operation on port. Once API alignment #branch is merged, update client to use the detail action port['attachment'] = '' - output = prepare_output("detail_port", tenant_id, + output = prepare_output("show_port", tenant_id, dict(network_id=network_id, port=port)) print output @@ -209,7 +201,7 @@ def plug_iface(client, *args): data = {'attachment': {'id': '%s' % attachment}} client.attach_resource(network_id, port_id, data) LOG.debug("Operation 'attach_resource' executed.") - output = prepare_output("plug_interface", tenant_id, + output = prepare_output("plug_iface", tenant_id, dict(network_id=network_id, port_id=port_id, attachment=attachment)) @@ -223,7 +215,7 @@ def unplug_iface(client, *args): try: client.detach_resource(network_id, port_id) LOG.debug("Operation 'detach_resource' executed.") - output = prepare_output("unplug_interface", tenant_id, + output = prepare_output("unplug_iface", tenant_id, dict(network_id=network_id, port_id=port_id)) print output diff --git a/quantum/cli_output.template b/quantum/cli_output.template index 12f394e19e..107dceb93c 100644 --- a/quantum/cli_output.template +++ b/quantum/cli_output.template @@ -1,45 +1,48 @@ ## Cheetah template for cli output #if $cmd == 'list_nets' -Virtual Networks on Tenant $tenant_id +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 +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 == 'detail_net' -Network: $network.name ($network.id) -Remote Interfaces on Virtual Network -#for $port in $network.ports - Logical Port $port.id: $port.attachment -#end for +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 for Tenant $tenant_id, +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 +for Tenant: $tenant_id #elif $cmd == 'delete_port' Deleted Logical Port with ID: $port_id on Virtual Network: $network_id -for tenant: $tenant_id +for Tenant: $tenant_id #elif $cmd == 'set_port_state' Updated state for Logical Port with ID: $port.id -New state is: $port.state +new state is: $port.state on Virtual Network: $network_id for tenant: $tenant_id -#elif $cmd == 'detail_port' +#elif $cmd == 'show_port' Logical Port ID: $port.id -On Virtual Network: $network_id -Administrative State: $port.state -Remote Interface: $port.attachment +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 diff --git a/quantum/client.py b/quantum/client.py index f55244c6e6..92c1be23d1 100644 --- a/quantum/client.py +++ b/quantum/client.py @@ -230,7 +230,6 @@ class Client(object): """ if status_code in (202, 204): return data - #server.networks.Controller._serialization_metadata return Serializer(self._serialization_metadata).\ deserialize(data, self.content_type()) diff --git a/tests/unit/client_tools/stubs.py b/tests/unit/client_tools/stubs.py index 8a01a8fb57..081436bd1a 100644 --- a/tests/unit/client_tools/stubs.py +++ b/tests/unit/client_tools/stubs.py @@ -55,7 +55,7 @@ class FakeHTTPConnection: res = self._req.get_response(self._api) def _fake_read(): - """ Trick for macking a webob.Response look like a + """ Trick for making a webob.Response look like a httplib.Response """ diff --git a/tests/unit/test_cli.py b/tests/unit/test_cli.py index 6c71e2cbad..ba7838c943 100644 --- a/tests/unit/test_cli.py +++ b/tests/unit/test_cli.py @@ -107,19 +107,12 @@ class CLITest(unittest.TestCase): # Must add newline at the end to match effect of print call self.assertEquals(self.fake_stdout.make_string(), output + '\n') - def _verify_detail_network(self): + 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) - ports = db.port_list(nw['uuid']) - for port in ports: - port = db.port_get(port['uuid'], nw['uuid']) - network['ports'] = [dict(id=port['uuid'], - state=port['state'], - attachment=port['interface_id']) - for port in ports] # Fill CLI template - output = cli.prepare_output('detail_net', self.tenant_id, + 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 @@ -177,7 +170,7 @@ class CLITest(unittest.TestCase): # Must add newline at the end to match effect of print call self.assertEquals(self.fake_stdout.make_string(), output + '\n') - def _verify_detail_port(self, network_id, port_id): + 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. @@ -185,7 +178,7 @@ class CLITest(unittest.TestCase): port_data = {'id': port.uuid, 'state': port.state, 'attachment': ''} # Fill CLI template - output = cli.prepare_output('detail_port', self.tenant_id, + output = cli.prepare_output('show_port', self.tenant_id, dict(network_id=network_id, port=port_data)) # Verify! @@ -196,7 +189,7 @@ class CLITest(unittest.TestCase): # Verification - get raw result from db port = db.port_get(port_id, network_id) # Fill CLI template - output = cli.prepare_output("plug_interface", self.tenant_id, + output = cli.prepare_output("plug_iface", self.tenant_id, dict(network_id=network_id, port_id=port['uuid'], attachment=port['interface_id'])) @@ -208,7 +201,7 @@ class CLITest(unittest.TestCase): # Verification - get raw result from db port = db.port_get(port_id, network_id) # Fill CLI template - output = cli.prepare_output("unplug_interface", self.tenant_id, + output = cli.prepare_output("unplug_iface", self.tenant_id, dict(network_id=network_id, port_id=port['uuid'])) # Verify! @@ -254,22 +247,18 @@ class CLITest(unittest.TestCase): LOG.debug(self.fake_stdout.content) self._verify_delete_network(network_id) - def test_detail_network(self): + def test_show_network(self): try: # Load some data into the datbase net = db.network_create(self.tenant_id, self.network_name_1) - db.port_create(net['uuid']) - # Create a 2nd port and plug attachment in it - port = db.port_create(net['uuid']) - db.port_set_attachment(port['uuid'], net['uuid'], "test_iface_id") - cli.detail_net(self.client, self.tenant_id, net['uuid']) + 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_detail_network() + self._verify_show_network() def test_rename_network(self): try: @@ -351,7 +340,7 @@ class CLITest(unittest.TestCase): LOG.debug(self.fake_stdout.content) self._verify_set_port_state(network_id, port_id) - def test_detail_port(self): + def test_show_port(self): network_id = None port_id = None try: @@ -360,14 +349,14 @@ class CLITest(unittest.TestCase): network_id = net['uuid'] port = db.port_create(network_id) port_id = port['uuid'] - cli.detail_port(self.client, self.tenant_id, network_id, port_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_detail_port failed due to an exception") LOG.debug("Operation completed. Verifying result") LOG.debug(self.fake_stdout.content) - self._verify_detail_port(network_id, port_id) + self._verify_show_port(network_id, port_id) def test_plug_iface(self): network_id = None diff --git a/tools/pip-requires b/tools/pip-requires index 6a4d430838..baa07210c1 100644 --- a/tools/pip-requires +++ b/tools/pip-requires @@ -1,7 +1,6 @@ eventlet>=0.9.12 Routes>=1.12.3 Cheetah>=2.0.1 -mox==0.5.3 nose Paste PasteDeploy From 976007b95188af757e5fbf7b75e6d7dc9b5fe7af Mon Sep 17 00:00:00 2001 From: Salvatore Orlando Date: Fri, 26 Aug 2011 10:56:43 +0100 Subject: [PATCH 48/52] Cleaning pep8 --- quantum/plugins/cisco/common/cisco_faults.py | 20 ++++++++++---------- tests/unit/test_extensions.py | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/quantum/plugins/cisco/common/cisco_faults.py b/quantum/plugins/cisco/common/cisco_faults.py index 515d67598a..ed50ed65ac 100644 --- a/quantum/plugins/cisco/common/cisco_faults.py +++ b/quantum/plugins/cisco/common/cisco_faults.py @@ -71,7 +71,7 @@ class PortprofileNotFound(webob.exc.HTTPClientError): """ code = 450 title = 'Portprofile Not Found' - explanation = ('Unable to find a Portprofile with' + explanation = ('Unable to find a Portprofile with' + ' the specified identifier.') @@ -87,8 +87,8 @@ class PortNotFound(webob.exc.HTTPClientError): 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` @@ -100,10 +100,10 @@ class CredentialNotFound(webob.exc.HTTPClientError): """ code = 451 title = 'Credential Not Found' - explanation = ('Unable to find a Credential with' + explanation = ('Unable to find a Credential with' + ' the specified identifier.') - - + + class QosNotFound(webob.exc.HTTPClientError): """ subclass of :class:`~HTTPClientError` @@ -115,10 +115,10 @@ class QosNotFound(webob.exc.HTTPClientError): """ code = 452 title = 'QoS Not Found' - explanation = ('Unable to find a QoS with' + explanation = ('Unable to find a QoS with' + ' the specified identifier.') - - + + class NovatenantNotFound(webob.exc.HTTPClientError): """ subclass of :class:`~HTTPClientError` @@ -130,7 +130,7 @@ class NovatenantNotFound(webob.exc.HTTPClientError): """ code = 453 title = 'Nova tenant Not Found' - explanation = ('Unable to find a Novatenant with' + explanation = ('Unable to find a Novatenant with' + ' the specified identifier.') diff --git a/tests/unit/test_extensions.py b/tests/unit/test_extensions.py index 1860c5666a..a33897e47e 100644 --- a/tests/unit/test_extensions.py +++ b/tests/unit/test_extensions.py @@ -72,10 +72,10 @@ class ResourceExtensionTest(unittest.TestCase): index_response = test_app.get("/tweedles") self.assertEqual(200, index_response.status_int) self.assertEqual("resource index", index_response.body) - + show_response = test_app.get("/tweedles/25266") self.assertEqual({'data': {'id': "25266"}}, show_response.json) - + def test_resource_extension_with_custom_member_action(self): controller = self.ResourceExtensionController() member = {'custom_member_action': "GET"} From 329940fe4a927a8c7b16b388a1cfea849fb2a246 Mon Sep 17 00:00:00 2001 From: Ying Liu Date: Fri, 26 Aug 2011 11:21:46 -0700 Subject: [PATCH 49/52] fix pep8 warnings --- extensions/_credential_view.py | 8 ++-- extensions/_novatenant_view.py | 8 ++-- extensions/_pprofiles.py | 7 ++-- extensions/_qos_view.py | 6 +-- extensions/credential.py | 4 +- extensions/novatenant.py | 28 ++++++------- extensions/portprofile.py | 41 ++++++++++---------- extensions/qos.py | 14 +++---- quantum/plugins/cisco/common/cisco_faults.py | 20 +++++----- 9 files changed, 64 insertions(+), 72 deletions(-) diff --git a/extensions/_credential_view.py b/extensions/_credential_view.py index 3c8ce49a49..0175ecd84f 100644 --- a/extensions/_credential_view.py +++ b/extensions/_credential_view.py @@ -28,7 +28,7 @@ def get_view_builder(req): class ViewBuilder(object): """ - ViewBuilder for Credential, + ViewBuilder for Credential, derived from quantum.views.networks """ def __init__(self, base_url): @@ -39,20 +39,18 @@ class ViewBuilder(object): 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'])) diff --git a/extensions/_novatenant_view.py b/extensions/_novatenant_view.py index a25654916e..b32ff8b644 100644 --- a/extensions/_novatenant_view.py +++ b/extensions/_novatenant_view.py @@ -29,7 +29,7 @@ def get_view_builder(req): class ViewBuilder(object): """ - ViewBuilder for novatenant, + ViewBuilder for novatenant, derived from quantum.views.networks """ def __init__(self, base_url): @@ -37,11 +37,11 @@ class ViewBuilder(object): :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]) + return dict(vif_desc=vif_data[const.VIF_DESC]) diff --git a/extensions/_pprofiles.py b/extensions/_pprofiles.py index cf851bae08..285cef0b6e 100644 --- a/extensions/_pprofiles.py +++ b/extensions/_pprofiles.py @@ -28,7 +28,7 @@ def get_view_builder(req): class ViewBuilder(object): """ - ViewBuilder for Portprofile, + ViewBuilder for Portprofile, derived from quantum.views.networks """ def __init__(self, base_url): @@ -39,17 +39,16 @@ class ViewBuilder(object): 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): diff --git a/extensions/_qos_view.py b/extensions/_qos_view.py index 3ad0d30c3c..24469e4bc8 100644 --- a/extensions/_qos_view.py +++ b/extensions/_qos_view.py @@ -28,7 +28,7 @@ def get_view_builder(req): class ViewBuilder(object): """ - ViewBuilder for QoS, + ViewBuilder for QoS, derived from quantum.views.networks """ def __init__(self, base_url): @@ -44,11 +44,11 @@ class ViewBuilder(object): 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'], diff --git a/extensions/credential.py b/extensions/credential.py index 31c49bdd09..287cb4263b 100644 --- a/extensions/credential.py +++ b/extensions/credential.py @@ -125,7 +125,7 @@ class CredentialController(common.QuantumController): """ Creates a new credential for a given tenant """ try: req_params = \ - self._parse_request_params(request, + self._parse_request_params(request, self._credential_ops_param_list) except exc.HTTPError as exp: return faults.Fault(exp) @@ -142,7 +142,7 @@ class CredentialController(common.QuantumController): """ Updates the name for the credential with the given id """ try: req_params = \ - self._parse_request_params(request, + self._parse_request_params(request, self._credential_ops_param_list) except exc.HTTPError as exp: return faults.Fault(exp) diff --git a/extensions/novatenant.py b/extensions/novatenant.py index 84453ccfb5..f6ef130986 100644 --- a/extensions/novatenant.py +++ b/extensions/novatenant.py @@ -35,33 +35,33 @@ class Novatenant(object): @classmethod def get_name(cls): - """ Returns Ext Resource Name """ + """ 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", + parent_resource = dict(member_name="tenant", collection_name="extensions/csco/tenants") member_actions = {'get_host': "PUT", 'get_instance_port': "PUT"} @@ -78,13 +78,13 @@ class NovatenantsController(common.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": { @@ -96,13 +96,13 @@ class NovatenantsController(common.QuantumController): 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, @@ -110,7 +110,6 @@ class NovatenantsController(common.QuantumController): 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) @@ -119,11 +118,10 @@ class NovatenantsController(common.QuantumController): 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, @@ -131,7 +129,6 @@ class NovatenantsController(common.QuantumController): 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. \ @@ -139,6 +136,5 @@ class NovatenantsController(common.QuantumController): 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)) diff --git a/extensions/portprofile.py b/extensions/portprofile.py index 4dd9c7b41c..8ecf65061a 100644 --- a/extensions/portprofile.py +++ b/extensions/portprofile.py @@ -34,36 +34,36 @@ 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", + parent_resource = dict(member_name="tenant", collection_name="extensions/csco/tenants") member_actions = {'associate_portprofile': "PUT", 'disassociate_portprofile': "PUT"} @@ -71,16 +71,16 @@ class Portprofile(object): 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}, { @@ -88,13 +88,13 @@ class PortprofilesController(common.QuantumController): '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": { @@ -102,7 +102,7 @@ class PortprofilesController(common.QuantumController): }, }, } - + def index(self, request, tenant_id): """ Returns a list of portprofile ids """ return self._items(request, tenant_id, is_detail=False) @@ -114,7 +114,7 @@ class PortprofilesController(common.QuantumController): 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 """ @@ -133,7 +133,7 @@ class PortprofilesController(common.QuantumController): #look for portprofile name in request try: req_params = \ - self._parse_request_params(request, + self._parse_request_params(request, self._portprofile_ops_param_list) except exc.HTTPError as exp: return faults.Fault(exp) @@ -149,7 +149,7 @@ class PortprofilesController(common.QuantumController): """ Updates the name for the portprofile with the given id """ try: req_params = \ - self._parse_request_params(request, + self._parse_request_params(request, self._portprofile_ops_param_list) except exc.HTTPError as exp: return faults.Fault(exp) @@ -171,12 +171,12 @@ class PortprofilesController(common.QuantumController): 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, @@ -194,12 +194,11 @@ class PortprofilesController(common.QuantumController): 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, diff --git a/extensions/qos.py b/extensions/qos.py index 6e8cb72334..db624fe75e 100644 --- a/extensions/qos.py +++ b/extensions/qos.py @@ -36,7 +36,7 @@ class Qos(object): """Qos extension file""" def __init__(self): pass - + @classmethod def get_name(cls): """ Returns Ext Resource Name """ @@ -56,7 +56,7 @@ class Qos(object): 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 """ @@ -65,9 +65,9 @@ class Qos(object): @classmethod def get_resources(cls): """ Returns Ext Resources """ - parent_resource = dict(member_name="tenant", + parent_resource = dict(member_name="tenant", collection_name="extensions/csco/tenants") - + controller = QosController(QuantumManager.get_plugin()) return [extensions.ResourceExtension('qoss', controller, parent=parent_resource)] @@ -93,7 +93,7 @@ class QosController(common.QuantumController): 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) @@ -124,7 +124,7 @@ class QosController(common.QuantumController): #look for qos name in request try: req_params = \ - self._parse_request_params(request, + self._parse_request_params(request, self._qos_ops_param_list) except exc.HTTPError as exp: return faults.Fault(exp) @@ -140,7 +140,7 @@ class QosController(common.QuantumController): """ Updates the name for the qos with the given id """ try: req_params = \ - self._parse_request_params(request, + self._parse_request_params(request, self._qos_ops_param_list) except exc.HTTPError as exp: return faults.Fault(exp) diff --git a/quantum/plugins/cisco/common/cisco_faults.py b/quantum/plugins/cisco/common/cisco_faults.py index 515d67598a..ed50ed65ac 100644 --- a/quantum/plugins/cisco/common/cisco_faults.py +++ b/quantum/plugins/cisco/common/cisco_faults.py @@ -71,7 +71,7 @@ class PortprofileNotFound(webob.exc.HTTPClientError): """ code = 450 title = 'Portprofile Not Found' - explanation = ('Unable to find a Portprofile with' + explanation = ('Unable to find a Portprofile with' + ' the specified identifier.') @@ -87,8 +87,8 @@ class PortNotFound(webob.exc.HTTPClientError): 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` @@ -100,10 +100,10 @@ class CredentialNotFound(webob.exc.HTTPClientError): """ code = 451 title = 'Credential Not Found' - explanation = ('Unable to find a Credential with' + explanation = ('Unable to find a Credential with' + ' the specified identifier.') - - + + class QosNotFound(webob.exc.HTTPClientError): """ subclass of :class:`~HTTPClientError` @@ -115,10 +115,10 @@ class QosNotFound(webob.exc.HTTPClientError): """ code = 452 title = 'QoS Not Found' - explanation = ('Unable to find a QoS with' + explanation = ('Unable to find a QoS with' + ' the specified identifier.') - - + + class NovatenantNotFound(webob.exc.HTTPClientError): """ subclass of :class:`~HTTPClientError` @@ -130,7 +130,7 @@ class NovatenantNotFound(webob.exc.HTTPClientError): """ code = 453 title = 'Nova tenant Not Found' - explanation = ('Unable to find a Novatenant with' + explanation = ('Unable to find a Novatenant with' + ' the specified identifier.') From fa4e2c4c7d2ad62f9827345046cb9628a13f1458 Mon Sep 17 00:00:00 2001 From: Dan Wendlandt Date: Fri, 26 Aug 2011 13:22:18 -0700 Subject: [PATCH 50/52] make CLI show_port command display interface-id, add additional test case --- quantum/cli_lib.py | 9 +++++++-- tests/unit/test_cli.py | 29 ++++++++++++++++++++++++++--- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/quantum/cli_lib.py b/quantum/cli_lib.py index bffda703b2..bfee9ac43c 100755 --- a/quantum/cli_lib.py +++ b/quantum/cli_lib.py @@ -170,8 +170,13 @@ def show_port(client, *args): 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 - port['attachment'] = '' + #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'] = '' output = prepare_output("show_port", tenant_id, dict(network_id=network_id, port=port)) diff --git a/tests/unit/test_cli.py b/tests/unit/test_cli.py index ba7838c943..8fe388c6e5 100644 --- a/tests/unit/test_cli.py +++ b/tests/unit/test_cli.py @@ -176,7 +176,10 @@ class CLITest(unittest.TestCase): # attachment in separate bug fix. port = db.port_get(port_id, network_id) port_data = {'id': port.uuid, 'state': port.state, - 'attachment': ''} + 'attachment': ""} + 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, @@ -340,7 +343,7 @@ class CLITest(unittest.TestCase): LOG.debug(self.fake_stdout.content) self._verify_set_port_state(network_id, port_id) - def test_show_port(self): + def test_show_port_no_attach(self): network_id = None port_id = None try: @@ -352,7 +355,27 @@ class CLITest(unittest.TestCase): cli.show_port(self.client, self.tenant_id, network_id, port_id) except: LOG.exception("Exception caught: %s", sys.exc_info()) - self.fail("test_detail_port failed due to an exception") + 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) From a74d433e15a6b8423da714fd97e8d04f676a6b33 Mon Sep 17 00:00:00 2001 From: Dan Wendlandt Date: Mon, 29 Aug 2011 18:16:39 -0700 Subject: [PATCH 51/52] lp834694 fix integrity error when deleting network with unattached ports. Add unit test. --- quantum/db/api.py | 7 +++++++ tests/unit/test_api.py | 26 ++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/quantum/db/api.py b/quantum/db/api.py index ae93204d4d..89fd058914 100644 --- a/quantum/db/api.py +++ b/quantum/db/api.py @@ -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 diff --git a/tests/unit/test_api.py b/tests/unit/test_api.py index a374dffceb..2fe27974a1 100644 --- a/tests/unit/test_api.py +++ b/tests/unit/test_api.py @@ -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') From 8e86ccf37dc8c54dd5a3f7df1b21db417f9dd7aa Mon Sep 17 00:00:00 2001 From: Dan Wendlandt Date: Mon, 29 Aug 2011 18:59:14 -0700 Subject: [PATCH 52/52] lp835216 client lib was not passing in kwargs when creating exceptions --- quantum/client.py | 42 ++++++++++++++++++++++++------------ quantum/common/exceptions.py | 15 +++++++++++++ 2 files changed, 43 insertions(+), 14 deletions(-) diff --git a/quantum/client.py b/quantum/client.py index 92c1be23d1..ffcb3a3b67 100644 --- a/quantum/client.py +++ b/quantum/client.py @@ -32,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): @@ -131,7 +131,7 @@ class Client(object): 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 @@ -190,7 +190,7 @@ class Client(object): 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 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, @@ -254,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): @@ -268,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): @@ -289,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): @@ -297,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): @@ -312,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): @@ -327,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): @@ -335,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}) diff --git a/quantum/common/exceptions.py b/quantum/common/exceptions.py index 816851f7a5..46d15b28b4 100644 --- a/quantum/common/exceptions.py +++ b/quantum/common/exceptions.py @@ -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