diff --git a/quantum/cli.py b/quantum/cli.py index 89edb19216..a015565d87 100644 --- a/quantum/cli.py +++ b/quantum/cli.py @@ -137,7 +137,7 @@ def api_rename_net(client, *args): try: res = client.update_network(nid, data) except Exception, e: - LOG.error("Failed to rename network %s: %s" % (nid,e)) + LOG.error("Failed to rename network %s: %s" % (nid, e)) return LOG.debug(res) print "Renamed Virtual Network with ID:%s" % nid @@ -378,7 +378,8 @@ if __name__ == "__main__": 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) + 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) diff --git a/quantum/client.py b/quantum/client.py index 1c470df227..eaced5d9d2 100644 --- a/quantum/client.py +++ b/quantum/client.py @@ -21,6 +21,7 @@ import socket import urllib from quantum.common.wsgi import Serializer + class api_call(object): """A Decorator to add support for format and tenant overriding""" def __init__(self, f): @@ -28,7 +29,7 @@ class api_call(object): def __get__(self, instance, owner): def with_params(*args, **kwargs): - # Backup the format and tenant, then temporarily change them if needed + # Temporarily set format and tenant for this request (format, tenant) = (instance.format, instance.tenant) if 'format' in kwargs: @@ -41,12 +42,13 @@ class api_call(object): return ret return with_params + class Client(object): """A base client class - derived from Glance.BaseClient""" action_prefix = '/v0.1/tenants/{tenant_id}' - + """Action query strings""" networks_path = "/networks" network_path = "/networks/%s" @@ -54,8 +56,8 @@ class Client(object): port_path = "/networks/%s/ports/%s" attachment_path = "/networks/%s/ports/%s/attachment" - def __init__(self, host = "127.0.0.1", port = 9696, use_ssl = False, - tenant=None, format="xml", testingStub=None, key_file=None, cert_file=None): + def __init__(self, host="127.0.0.1", port=9696, use_ssl=False, tenant=None, + format="xml", testingStub=None, key_file=None, cert_file=None): """ Creates a new client to some service. @@ -64,7 +66,7 @@ class Client(object): :param use_ssl: True to use SSL, False to use HTTP :param tenant: The tenant ID to make requests with :param format: The format to query the server with - :param testingStub: A class that stubs basic server attributes for tests + :param testingStub: A class that stubs basic server methods for tests :param key_file: The SSL key file to use if use_ssl is true :param cert_file: The SSL cert file to use if use_ssl is true """ @@ -92,7 +94,7 @@ class Client(object): def do_request(self, method, action, body=None, headers=None, params=None): """ - Connects to the server and issues a request. + Connects to the server and issues a request. Returns the result data, or raises an appropriate exception if HTTP status code is not 2xx @@ -103,7 +105,7 @@ class Client(object): to action """ - + # Ensure we have a tenant id if not self.tenant: raise Exception("Tenant ID not set") @@ -111,7 +113,7 @@ class Client(object): # Add format and tenant_id action += ".%s" % self.format action = Client.action_prefix + action - action = action.replace('{tenant_id}',self.tenant) + action = action.replace('{tenant_id}', self.tenant) if type(params) is dict: action += '?' + urllib.urlencode(params) @@ -119,10 +121,10 @@ class Client(object): try: connection_type = self.get_connection_type() headers = headers or {} - + # 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) + certs = {'key_file': self.key_file, 'cert_file': self.cert_file} + certs = dict((x, certs[x]) for x in certs if certs[x] != None) if self.use_ssl and len(certs): c = connection_type(self.host, self.port, **certs) @@ -180,7 +182,7 @@ class Client(object): """ Queries the server for the details of a certain network """ - return self.do_request("GET", (self.network_path%network)) + return self.do_request("GET", self.network_path % (network)) @api_call def create_network(self, body=None): @@ -196,7 +198,7 @@ class Client(object): Updates a network on the server """ body = self.serialize(body) - return self.do_request("PUT", self.network_path % (network),body=body) + return self.do_request("PUT", self.network_path % (network), body=body) @api_call def delete_network(self, network): @@ -217,7 +219,7 @@ class Client(object): """ Queries the server for a list of ports on a given network """ - return self.do_request("GET", self.port_path % (network,port)) + return self.do_request("GET", self.port_path % (network, port)) @api_call def create_port(self, network): @@ -231,7 +233,7 @@ class Client(object): """ Deletes a port from a network on the server """ - return self.do_request("DELETE", self.port_path % (network,port)) + return self.do_request("DELETE", self.port_path % (network, port)) @api_call def set_port_state(self, network, port, body=None): @@ -240,15 +242,15 @@ class Client(object): """ body = self.serialize(body) return self.do_request("PUT", - self.port_path % (network,port), body=body) + self.port_path % (network, port), body=body) @api_call def list_port_attachments(self, network, port): """ Deletes a port from a network on the server """ - return self.do_request("GET", self.attachment_path % (network,port)) - + return self.do_request("GET", self.attachment_path % (network, port)) + @api_call def attach_resource(self, network, port, body=None): """ @@ -256,11 +258,12 @@ class Client(object): """ body = self.serialize(body) return self.do_request("PUT", - self.attachment_path % (network,port), body=body) + self.attachment_path % (network, port), body=body) @api_call def detach_resource(self, network, port): """ Deletes a port from a network on the server """ - return self.do_request("DELETE", self.attachment_path % (network,port)) + return self.do_request("DELETE", + self.attachment_path % (network, port)) diff --git a/tests/unit/api.py b/tests/unit/api.py index 551d0672eb..aed6c4bacf 100644 --- a/tests/unit/api.py +++ b/tests/unit/api.py @@ -29,12 +29,13 @@ LOG = logging.getLogger('quantum.tests.test_api') TENANT_1 = 'totore' TENANT_2 = 'totore2' + class ServerStub(): """This class stubs a basic server for the API client to talk to""" class Response(object): """This class stubs a basic response to send the API client""" - def __init__(self, content = None, status = None): + def __init__(self, content=None, status=None): self.content = content self.status = status @@ -43,7 +44,7 @@ class ServerStub(): def status(self): return status - + # To test error codes, set the host to 10.0.0.1, and the port to the code def __init__(self, host, port=9696, key_file="", cert_file=""): self.host = host @@ -60,7 +61,7 @@ class ServerStub(): return status or 200 def getresponse(self): - res = self.Response(status = self.status()) + res = self.Response(status=self.status()) # If the host is 10.0.0.1, return the port as an error code if self.host == "10.0.0.1": @@ -70,20 +71,23 @@ class ServerStub(): # Extract important information from the action string to assure sanity match = re.search('tenants/(.+?)/(.+)\.(json|xml)$', self.action) - (tenant,path,format) = (match.group(1),match.group(2),match.group(3)) + tenant = match.group(1) + path = match.group(2) + format = match.group(3) - data = {'data': {'method':self.method, 'action':self.action, - 'body':self.body,'tenant':tenant, 'path':path, - 'format':format, 'key_file':self.key_file, - 'cert_file':self.cert_file}} - - # Serialize it to the proper format so the API client can deserialize it + data = {'data': {'method': self.method, 'action': self.action, + 'body': self.body, 'tenant': tenant, 'path': path, + 'format': format, 'key_file': self.key_file, + 'cert_file': self.cert_file}} + + # Serialize it to the proper format so the API client can handle it if data['data']['format'] == 'json': res.content = Serializer().serialize(data, "application/json") else: res.content = Serializer().serialize(data, "application/xml") return res + class APITest(unittest.TestCase): def setUp(self): @@ -92,14 +96,14 @@ class APITest(unittest.TestCase): PORT = 9696 USE_SSL = False - self.client = Client(HOST,PORT,USE_SSL,TENANT_1,'json',ServerStub) + self.client = Client(HOST, PORT, USE_SSL, TENANT_1, 'json', ServerStub) def _assert_sanity(self, call, status, method, path, data=[], params={}): """ Perform common assertions to test the sanity of client requests """ # Handle an error case first if status != 200: - (self.client.host,self.client.port) = ("10.0.0.1", status) + (self.client.host, self.client.port) = ("10.0.0.1", status) self.assertRaises(Exception, call, *data, **params) return @@ -113,7 +117,6 @@ class APITest(unittest.TestCase): return data - def _test_list_networks(self, tenant=TENANT_1, format='json', status=200): LOG.debug("_test_list_networks - tenant:%s "\ "- format:%s - START", format, tenant) @@ -122,14 +125,14 @@ class APITest(unittest.TestCase): status, "GET", "networks", - data = [], - params = {'tenant':tenant, 'format':format},) + data=[], + params={'tenant': tenant, 'format': format}) LOG.debug("_test_list_networks - tenant:%s "\ "- format:%s - END", format, tenant) def _test_list_network_details(self, - tenant=TENANT_1,format='json',status=200): + tenant=TENANT_1, format='json', status=200): LOG.debug("_test_list_network_details - tenant:%s "\ "- format:%s - START", format, tenant) @@ -137,8 +140,8 @@ class APITest(unittest.TestCase): status, "GET", "networks/001", - data = ["001"], - params = {'tenant':tenant, 'format':format}) + data=["001"], + params={'tenant': tenant, 'format': format}) LOG.debug("_test_list_network_details - tenant:%s "\ "- format:%s - END", format, tenant) @@ -151,8 +154,8 @@ class APITest(unittest.TestCase): status, "POST", "networks", - data = [{'network': {'net-name': 'testNetwork'}}], - params = {'tenant':tenant, 'format':format}) + data=[{'network': {'net-name': 'testNetwork'}}], + params={'tenant': tenant, 'format': format}) LOG.debug("_test_create_network - tenant:%s "\ "- format:%s - END", format, tenant) @@ -165,11 +168,9 @@ class APITest(unittest.TestCase): status, "PUT", "networks/001", - data = [ - "001", - {'network': {'net-name': 'newName'}} - ], - params = {'tenant':tenant, 'format':format}) + data=["001", + {'network': {'net-name': 'newName'}}], + params={'tenant': tenant, 'format': format}) LOG.debug("_test_update_network - tenant:%s "\ "- format:%s - END", format, tenant) @@ -182,13 +183,13 @@ class APITest(unittest.TestCase): status, "DELETE", "networks/001", - data = ["001"], - params = {'tenant':tenant, 'format':format}) + data=["001"], + params={'tenant': tenant, 'format': format}) LOG.debug("_test_delete_network - tenant:%s "\ "- format:%s - END", format, tenant) - def _test_list_ports(self, tenant = TENANT_1, format = 'json', status=200): + def _test_list_ports(self, tenant=TENANT_1, format='json', status=200): LOG.debug("_test_list_ports - tenant:%s "\ "- format:%s - START", format, tenant) @@ -196,8 +197,8 @@ class APITest(unittest.TestCase): status, "GET", "networks/001/ports", - data = ["001"], - params = {'tenant':tenant, 'format':format}) + data=["001"], + params={'tenant': tenant, 'format': format}) LOG.debug("_test_list_ports - tenant:%s "\ "- format:%s - END", format, tenant) @@ -211,13 +212,13 @@ class APITest(unittest.TestCase): status, "GET", "networks/001/ports/001", - data = ["001","001"], - params = {'tenant':tenant, 'format':format}) + data=["001", "001"], + params={'tenant': tenant, 'format': format}) LOG.debug("_test_list_port_details - tenant:%s "\ "- format:%s - END", format, tenant) - def _test_create_port(self, tenant = TENANT_1, format = 'json', status=200): + def _test_create_port(self, tenant=TENANT_1, format='json', status=200): LOG.debug("_test_create_port - tenant:%s "\ "- format:%s - START", format, tenant) @@ -225,14 +226,13 @@ class APITest(unittest.TestCase): status, "POST", "networks/001/ports", - data = ["001"], - params = {'tenant':tenant, 'format':format}) - + data=["001"], + params={'tenant': tenant, 'format': format}) LOG.debug("_test_create_port - tenant:%s "\ "- format:%s - END", format, tenant) - def _test_delete_port(self, tenant = TENANT_1, format = 'json', status=200): + def _test_delete_port(self, tenant=TENANT_1, format='json', status=200): LOG.debug("_test_delete_port - tenant:%s "\ "- format:%s - START", format, tenant) @@ -240,13 +240,12 @@ class APITest(unittest.TestCase): status, "DELETE", "networks/001/ports/001", - data = ["001","001"], - params = {'tenant':tenant, 'format':format}) + data=["001", "001"], + params={'tenant': tenant, 'format': format}) LOG.debug("_test_delete_port - tenant:%s "\ "- format:%s - END", format, tenant) - def _test_set_port_state(self, tenant=TENANT_1, format='json', status=200): LOG.debug("_test_set_port_state - tenant:%s "\ "- format:%s - START", format, tenant) @@ -255,14 +254,15 @@ class APITest(unittest.TestCase): status, "PUT", "networks/001/ports/001", - data = ["001","001",{'port':{'state':'ACTIVE'}}], - params = {'tenant':tenant, 'format':format}) + data=["001", "001", + {'port': {'state': 'ACTIVE'}}], + params={'tenant': tenant, 'format': format}) LOG.debug("_test_set_port_state - tenant:%s "\ "- format:%s - END", format, tenant) def _test_list_port_attachments(self, - tenant=TENANT_1, format='json', status=200): + tenant=TENANT_1, format='json', status=200): LOG.debug("_test_list_port_attachments - tenant:%s "\ "- format:%s - START", format, tenant) @@ -270,13 +270,14 @@ class APITest(unittest.TestCase): status, "GET", "networks/001/ports/001/attachment", - data = ["001","001"], - params = {'tenant':tenant, 'format':format}) + data=["001", "001"], + params={'tenant': tenant, 'format': format}) LOG.debug("_test_list_port_attachments - tenant:%s "\ "- format:%s - END", format, tenant) - def _test_attach_resource(self, tenant=TENANT_1, format='json', status=200): + def _test_attach_resource(self, tenant=TENANT_1, + format='json', status=200): LOG.debug("_test_attach_resource - tenant:%s "\ "- format:%s - START", format, tenant) @@ -284,13 +285,15 @@ class APITest(unittest.TestCase): status, "PUT", "networks/001/ports/001/attachment", - data = ["001","001",{'resource':{'id':'1234'}}], - params = {'tenant':tenant, 'format':format}) + data=["001", "001", + {'resource': {'id': '1234'}}], + params={'tenant': tenant, 'format': format}) LOG.debug("_test_attach_resource - tenant:%s "\ "- format:%s - END", format, tenant) - def _test_detach_resource(self, tenant=TENANT_1, format='json', status=200): + def _test_detach_resource(self, tenant=TENANT_1, + format='json', status=200): LOG.debug("_test_detach_resource - tenant:%s "\ "- format:%s - START", format, tenant) @@ -298,13 +301,14 @@ class APITest(unittest.TestCase): status, "DELETE", "networks/001/ports/001/attachment", - data = ["001","001"], - params = {'tenant':tenant, 'format':format}) + data=["001", "001"], + params={'tenant': tenant, 'format': format}) LOG.debug("_test_detach_resource - tenant:%s "\ "- format:%s - END", format, tenant) - def _test_ssl_certificates(self, tenant=TENANT_1, format='json', status=200): + def _test_ssl_certificates(self, tenant=TENANT_1, + format='json', status=200): LOG.debug("_test_ssl_certificates - tenant:%s "\ "- format:%s - START", format, tenant) @@ -317,8 +321,8 @@ class APITest(unittest.TestCase): status, "GET", "networks", - data = [], - params = {'tenant':tenant, 'format':format}) + data=[], + params={'tenant': tenant, 'format': format}) self.assertEquals(data["key_file"], cert_file) self.assertEquals(data["cert_file"], cert_file) @@ -326,7 +330,6 @@ class APITest(unittest.TestCase): LOG.debug("_test_ssl_certificates - tenant:%s "\ "- format:%s - END", format, tenant) - def test_list_networks_json(self): self._test_list_networks(format='json') @@ -342,8 +345,6 @@ class APITest(unittest.TestCase): def test_list_networks_error_401(self): self._test_list_networks(status=401) - - def test_list_network_details_json(self): self._test_list_network_details(format='json') @@ -362,8 +363,6 @@ class APITest(unittest.TestCase): def test_list_network_details_error_420(self): self._test_list_network_details(status=420) - - def test_create_network_json(self): self._test_create_network(format='json') @@ -385,9 +384,6 @@ class APITest(unittest.TestCase): def test_create_network_error_422(self): self._test_create_network(status=422) - - - def test_update_network_json(self): self._test_update_network(format='json') @@ -412,8 +408,6 @@ class APITest(unittest.TestCase): def test_update_network_error_422(self): self._test_update_network(status=422) - - def test_delete_network_json(self): self._test_delete_network(format='json') @@ -435,8 +429,6 @@ class APITest(unittest.TestCase): def test_delete_network_error_421(self): self._test_delete_network(status=421) - - def test_list_ports_json(self): self._test_list_ports(format='json') @@ -455,8 +447,6 @@ class APITest(unittest.TestCase): def test_list_ports_error_420(self): self._test_list_ports(status=420) - - def test_list_port_details_json(self): self._test_list_ports(format='json') @@ -478,8 +468,6 @@ class APITest(unittest.TestCase): def test_list_port_details_error_430(self): self._test_list_ports(status=430) - - def test_create_port_json(self): self._test_create_port(format='json') @@ -507,8 +495,6 @@ class APITest(unittest.TestCase): def test_create_port_error_431(self): self._test_create_port(status=431) - - def test_delete_port_json(self): self._test_delete_port(format='json') @@ -533,8 +519,6 @@ class APITest(unittest.TestCase): def test_delete_port_error_432(self): self._test_delete_port(status=432) - - def test_set_port_state_json(self): self._test_set_port_state(format='json') @@ -562,8 +546,6 @@ class APITest(unittest.TestCase): def test_set_port_state_error_431(self): self._test_set_port_state(status=431) - - def test_list_port_attachments_json(self): self._test_list_port_attachments(format='json') @@ -588,8 +570,6 @@ class APITest(unittest.TestCase): def test_list_port_attachments_error_430(self): self._test_list_port_attachments(status=430) - - def test_attach_resource_json(self): self._test_attach_resource(format='json') @@ -620,8 +600,6 @@ class APITest(unittest.TestCase): def test_attach_resource_error_440(self): self._test_attach_resource(status=440) - - def test_detach_resource_json(self): self._test_detach_resource(format='json') @@ -643,7 +621,5 @@ class APITest(unittest.TestCase): def test_detach_resource_error_430(self): self._test_detach_resource(status=430) - def test_ssl_certificates(self): self._test_ssl_certificates() -