Fixed command line tool

This commit is contained in:
alena 2010-10-28 23:10:12 -07:00
parent ad3c18a46c
commit fe2fc63692
6 changed files with 32 additions and 285 deletions

View File

@ -1,63 +0,0 @@
'''Implements the Amazon API'''
import boto.ec2
import os
from cloudtool.utils import describe,OptionConflictError,OptionValueError
raise ImportError
class AmazonAPI:
@describe("access_key", "Amazon access key")
@describe("secret_key", "Amazon secret key")
@describe("region", "Amazon region")
@describe("endpoint", "Amazon endpoint")
def __init__(self,
access_key=os.environ.get("AWS_ACCESS_KEY_ID",None),
secret_key=os.environ.get("AWS_SECRET_ACCESS_KEY",None),
region=None,
endpoint=None):
if not access_key: raise OptionValueError,"you need to specify an access key"
if not secret_key: raise OptionValueError,"you need to specify a secret key"
if region and endpoint:
raise OptionConflictError,("mutually exclusive with --endpoint",'--region')
self.__dict__.update(locals())
def _get_regions(self):
return boto.ec2.regions(aws_access_key_id=self.access_key,aws_secret_access_key=self.secret_key)
def _get_region(self,name):
try: return [ x for x in self._get_regions() if x.name == name ][0]
except IndexError: raise KeyError,name
def _connect(self):
if self.region:
region = self._get_region(self.region)
self.connection = region.connect(
aws_access_key_id=self.access_key,
aws_secret_access_key=self.secret_key
)
else:
self.connection = boto.ec2.connection.EC2Connection(
host=self.endpoint,
aws_access_key_id=self.access_key,
aws_secret_access_key=self.secret_key
)
def list_regions(self):
"""Lists all regions"""
regions = self._get_regions()
for r in regions: print r
def get_all_images(self):
"""Lists all images"""
self._connect()
images = self.connection.get_all_images()
for i in images: print i
def get_region(self):
"""Gets the region you're connecting to"""
self._connect()
print self.connection.region
implementor = AmazonAPI

View File

@ -58,26 +58,32 @@ def load_dynamic_methods():
name = getText(cmd.getElementsByTagName('name')[0].childNodes).strip() name = getText(cmd.getElementsByTagName('name')[0].childNodes).strip()
assert name assert name
description = cmd.getElementsByTagName('name')[0].getAttribute("description") description = getText(cmd.getElementsByTagName('description')[0].childNodes).strip()
if description: description = '"""%s"""' % description if description:
description = '"""%s"""' % description
else: description = '' else: description = ''
arguments = [] arguments = []
options = [] options = []
descriptions = [] descriptions = []
for param in cmd.getElementsByTagName('arg'): for param in cmd.getElementsByTagName("request")[0].getElementsByTagName("arg"):
argname = getText(param.childNodes).strip() argname = getText(param.getElementsByTagName('name')[0].childNodes).strip()
assert argname assert argname
required = param.getAttribute("required").strip() required = getText(param.getElementsByTagName('required')[0].childNodes).strip()
if required == 'true': required = True if required == 'true': required = True
elif required == 'false': required = False elif required == 'false': required = False
else: raise AssertionError, "Not reached" else: raise AssertionError, "Not reached"
if required: arguments.append(argname) if required: arguments.append(argname)
options.append(argname) options.append(argname)
description = param.getAttribute("description").strip() #import ipdb; ipdb.set_trace()
if description: descriptions.append( (argname,description) ) requestDescription = param.getElementsByTagName('description')
if requestDescription:
descriptionParam = getText(requestDescription[0].childNodes)
else:
descriptionParam = ''
if descriptionParam: descriptions.append( (argname,descriptionParam) )
funcparams = ["self"] + [ "%s=None"%o for o in options ] funcparams = ["self"] + [ "%s=None"%o for o in options ]
funcparams = ", ".join(funcparams) funcparams = ", ".join(funcparams)
@ -106,7 +112,8 @@ def load_dynamic_methods():
yield (name,func) yield (name,func)
for name,meth in load_dynamic_methods(): setattr(CloudAPI,name,meth) for name,meth in load_dynamic_methods():
setattr(CloudAPI, name, meth)
implementor = CloudAPI implementor = CloudAPI

View File

@ -11,25 +11,27 @@ import cloudtool.utils as utils
def main(argv=None): def main(argv=None):
#import ipdb; ipdb.set_trace()
if argv == None: if argv == None:
argv = sys.argv argv = sys.argv
prelim_args = [ x for x in argv[1:] if not x.startswith('-') ] prelim_args = [ x for x in argv[0:] if not x.startswith('-') ]
parser = utils.get_parser() parser = utils.get_parser()
api = __import__("cloudapis") api = __import__("cloudapis")
apis = getattr(api, "implementor") apis = getattr(api, "implementor")
if len(prelim_args) == 0: if len(prelim_args) == 1:
parser.error("you need to specify an API as the first argument\n\nSupported APIs:\n" + "\n".join(utils.get_api_list(apis)))
elif len(prelim_args) == 1:
commandlist = utils.get_command_list(apis) commandlist = utils.get_command_list(apis)
parser.error("you need to specify a command name as the second argument\n\nCommands supported by the %s API:\n"%prelim_args[0] + "\n".join(commandlist)) parser.error("you need to specify a command name as the first argument\n\nCommands supported by the %s API:\n"%prelim_args[0] + "\n".join(commandlist))
command = utils.lookup_command_in_api(apis,prelim_args[1]) command = utils.lookup_command_in_api(apis,prelim_args[1])
if not command: parser.error("command %r not supported by the %s API"%(prelim_args[1],prelim_args[0])) if not command: parser.error("command %r not supported by the %s API"%(prelim_args[1],prelim_args[0]))
parser = utils.get_parser(apis.__init__,command)
argv = argv[1:] argv = argv[1:]
if len(argv) == 1:
argv.append("--help")
parser = utils.get_parser(apis.__init__,command)
opts,args,api_optionsdict,cmd_optionsdict = parser.parse_args(argv) opts,args,api_optionsdict,cmd_optionsdict = parser.parse_args(argv)
@ -38,7 +40,7 @@ def main(argv=None):
except utils.OptParseError,e: except utils.OptParseError,e:
parser.error(str(e)) parser.error(str(e))
command = utils.lookup_command_in_api(api,args[1]) command = utils.lookup_command_in_api(api,args[0])
# we now discard the first two arguments as those necessarily are the api and command names # we now discard the first two arguments as those necessarily are the api and command names
args = args[2:] args = args[2:]

View File

@ -112,51 +112,18 @@ def get_parser(api_callable=None,cmd_callable=None): # this should probably be t
group = parser.add_option_group("General options") group = parser.add_option_group("General options")
group.add_option('-v', '--verbose', dest="verbose", help="Print extra output") group.add_option('-v', '--verbose', dest="verbose", help="Print extra output")
# now we need to derive the short options. we initialize the known fixed longopts and shortopts
longopts = [ '--verbose' ]
# we add the known long options, sorted and grouped to guarantee a stable short opt set regardless of order
if api_callable and api_options:
longopts += sorted([ x[0][0] for x in api_options ])
if cmd_callable and cmd_options:
longopts += sorted([ x[0][0] for x in cmd_options ])
# we use this function to derive a suitable short option and remember the already-used short options
def derive_shortopt(longopt,usedopts):
"""longopt begins with a dash"""
shortopt = None
for x in xrange(2,10000):
try: shortopt = "-" + longopt[x]
except IndexError:
shortopt = None
break
if shortopt in usedopts: continue
usedopts.append(shortopt)
break
return shortopt
# now we loop through the long options and assign a suitable short option, saving the short option for later use
long_to_short = {}
alreadyusedshorts = []
for longopt in longopts:
long_to_short[longopt] = derive_shortopt(longopt,alreadyusedshorts)
parser.api_dests = [] parser.api_dests = []
if api_callable and api_options: if api_callable and api_options:
group = parser.add_option_group("Options for the %s API"%api_name) group = parser.add_option_group("Options for the %s API"%api_name)
for a in api_options: for a in api_options:
shortopt = long_to_short[a[0][0]] group.add_option(a[0][0],**a[1])
if shortopt: group.add_option(shortopt,a[0][0],**a[1])
else: group.add_option(a[0][0],**a[1])
parser.api_dests.append(a[1]["dest"]) parser.api_dests.append(a[1]["dest"])
parser.cmd_dests = [] parser.cmd_dests = []
if cmd_callable and cmd_options: if cmd_callable and cmd_options:
group = parser.add_option_group("Options for the %s command"%cmd_name) group = parser.add_option_group("Options for the %s command"%cmd_name)
for a in cmd_options: for a in cmd_options:
shortopt = long_to_short[a[0][0]] group.add_option(a[0][0],**a[1])
if shortopt: group.add_option(shortopt,a[0][0],**a[1])
else: group.add_option(a[0][0],**a[1])
parser.cmd_dests.append(a[1]["dest"]) parser.cmd_dests.append(a[1]["dest"])
return parser return parser
@ -178,7 +145,7 @@ def get_command_list(api):
for cmd_name in dir(api): for cmd_name in dir(api):
cmd = getattr(api,cmd_name) cmd = getattr(api,cmd_name)
if callable(cmd) and not cmd_name.startswith("_"): if callable(cmd) and not cmd_name.startswith("_"):
if cmd.__doc__: docstring = cmd.__doc__ if cmd.__doc__:docstring = cmd.__doc__
else: docstring = '' else:docstring = ''
cmds.append( " %s %s"%(cmd_name.replace('_','-'),docstring) ) cmds.append( " %s" % (cmd_name.replace('_','-')) )
return cmds return cmds

View File

@ -1,166 +0,0 @@
/**
* Copyright (C) 2010 Cloud.com, Inc. All rights reserved.
*
* This software is licensed under the GNU General Public License v3 or later.
*
* It is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.cloud.utils.commandlinetool;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;
import com.cloud.utils.Pair;
public class BuildCommandLineInputFile {
private static Properties api_commands = new Properties();
private static String dirName="";
public static void main (String[] args) {
Properties preProcessedCommands = new Properties();
Class clas = null;
Enumeration e = null;
String[] fileNames = null;
//load properties
List<String> argsList = Arrays.asList(args);
Iterator<String> iter = argsList.iterator();
while (iter.hasNext()) {
String arg = iter.next();
// populate the file names
if (arg.equals("-f")) {
fileNames = iter.next().split(",");
}
if (arg.equals("-d")) {
dirName = iter.next();
}
}
if ((fileNames == null) || (fileNames.length == 0)){
System.out.println("Please specify input file(s) separated by coma using -f option");
System.exit(2);
}
for (String fileName : fileNames) {
try {
FileInputStream in = new FileInputStream(fileName);
preProcessedCommands.load(in);
}catch (FileNotFoundException ex) {
System.out.println("Can't find file " + fileName);
System.exit(2);
} catch (IOException ex1) {
System.out.println("Error reading from file " + ex1);
System.exit(2);
}
}
for (Object key : preProcessedCommands.keySet()) {
String preProcessedCommand = preProcessedCommands.getProperty((String)key);
String[] commandParts = preProcessedCommand.split(";");
api_commands.put(key, commandParts[0]);
}
e = api_commands.propertyNames();
try {
DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = dbfac.newDocumentBuilder();
Document doc = docBuilder.newDocument();
Element root = doc.createElement("commands");
doc.appendChild(root);
while (e.hasMoreElements()) {
String key = (String) e.nextElement();
try {
clas = Class.forName(api_commands.getProperty(key));
Element child1 = doc.createElement("command");
root.appendChild(child1);
Element child2 = doc.createElement("name");
child1.appendChild(child2);
Text text = doc.createTextNode(key);
child2.appendChild(text);
Field m[] = clas.getDeclaredFields();
for (int i = 0; i < m.length; i++) {
if (m[i].getName().endsWith("s_properties")) {
m[i].setAccessible(true);
List<Pair<Enum, Boolean>> properties = (List<Pair<Enum, Boolean>>) m[i].get(null);
for (Pair property : properties){
if (!property.first().toString().equals("ACCOUNT_OBJ") && !property.first().toString().equals("USER_ID")){
Element child3 = doc.createElement("arg");
child1.appendChild(child3);
Class clas2 = property.first().getClass();
Method m2 = clas2.getMethod("getName");
text = doc.createTextNode(m2.invoke(property.first()).toString());
child3.appendChild(text);
child3.setAttribute("required", property.second().toString());
}
}
}
}
} catch (ClassNotFoundException ex2) {
System.out.println("Can't find class " + api_commands.getProperty(key));
System.exit(2);
}
}
TransformerFactory transfac = TransformerFactory.newInstance();
Transformer trans = transfac.newTransformer();
trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
trans.setOutputProperty(OutputKeys.INDENT, "yes");
StringWriter sw = new StringWriter();
StreamResult result = new StreamResult(sw);
DOMSource source = new DOMSource(doc);
trans.transform(source, result);
String xmlString = sw.toString();
//write xml to file
File f=new File(dirName + "/commands.xml");
Writer output = new BufferedWriter(new FileWriter(f));
output.write(xmlString);
output.close();
} catch (Exception ex) {
System.out.println(ex);
System.exit(2);
}
}
}

View File

@ -421,7 +421,7 @@ def generate_xml_api_description(task):
cp += jars cp += jars
cp = pathsep.join(cp) cp = pathsep.join(cp)
arguments = ["-f",",".join(properties),"-d",builddir] arguments = ["-f",",".join(properties),"-d",builddir]
ret = Utils.exec_command(["java","-cp",cp,"com.cloud.utils.commandlinetool.BuildCommandLineInputFile"]+arguments,log=True) ret = Utils.exec_command(["java","-cp",cp,"com.cloud.api.doc.ApiXmlDocWriter"]+arguments,log=True)
return ret return ret
props = " client/tomcatconf/commands.properties" props = " client/tomcatconf/commands.properties"
jarnames = ['utils','server','core', 'api'] jarnames = ['utils','server','core', 'api']