From bbbdf82de385d360b0a0f7f969a3a586d0f85ff0 Mon Sep 17 00:00:00 2001 From: Salvatore Orlando Date: Wed, 24 Aug 2011 19:10:03 +0100 Subject: [PATCH] Templated output for CLI completed! --- quantum/cli.py | 341 +++++++++++++----------------------- quantum/cli_output.template | 33 +++- quantum/client.py | 1 + 3 files changed, 153 insertions(+), 222 deletions(-) diff --git a/quantum/cli.py b/quantum/cli.py index fa326d9d4..fdda75899 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 - - -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 + _handle_exception(ex) - -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) - - -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 + except Exception as ex: + _handle_exception(ex) -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"] - - output = prepare_output("detail_net", tenant_id, - dict(network=res)) - print output - + res['ports'] = ports + for port in ports["ports"]: + att_data = client.list_port_attachments(network_id, port['id']) + port['attachment'] = att_data["attachment"] -def rename_net(manager, *args): - tid, nid, name = args - manager.rename_network(tid, nid, name) - print "Renamed Virtual Network with ID:%s" % nid + output = prepare_output("detail_net", tenant_id, dict(network=res)) + print output + except Exception as ex: + _handle_exception(ex) -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 - - -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"] + 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 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"] - - -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) + 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 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) - - -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)) + 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 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) - - -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) + 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 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 plug_iface(client, *args): + tenant_id, network_id, port_id, attachment = args + try: + 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 api_unplug_iface(client, *args): - tid, nid, pid = args +def unplug_iface(client, *args): + tenant_id, network_id, port_id = 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) + 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 0c9084010..96baef735 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 d993d68e6..f6e1b6bfe 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 -- 2.45.2