add apikey/securitykey in cloud-cli

This commit is contained in:
Edison Su 2011-08-19 11:22:36 -07:00
parent 8d4c7208a4
commit 18255e985c

View File

@ -26,122 +26,166 @@ import urllib2
import os import os
import xml.dom.minidom import xml.dom.minidom
import re import re
import base64
import hmac
import hashlib
import httplib
class CloudAPI: class CloudAPI:
@describe("server", "Management Server host name or address") @describe("server", "Management Server host name or address")
@describe("responseformat", "Response format: xml or json") @describe("apikey", "Management Server apiKey")
@describe("stripxml", "True if xml tags have to be stripped in the output, false otherwise") @describe("securitykey", "Management Server securityKey")
def __init__(self, @describe("responseformat", "Response format: xml or json")
server="127.0.0.1:8096", @describe("stripxml", "True if xml tags have to be stripped in the output, false otherwise")
responseformat="xml", def __init__(self,
stripxml="true" server="127.0.0.1:8096",
): responseformat="xml",
self.__dict__.update(locals()) stripxml="true",
apiKey=None,
securityKey=None
):
self.__dict__.update(locals())
def _make_request(self,command,parameters=None): def _make_request_with_keys(self,command,requests={}):
'''Command is a string, parameters is a dictionary''' requests["command"] = command
if ":" in self.server: requests["apiKey"] = self.apiKey
host,port = self.server.split(":") requests["response"] = "xml"
port = int(port) requests = zip(requests.keys(), requests.values())
else: requests.sort(key=lambda x: str.lower(x[0]))
host = self.server
port = 8096 requestUrl = "&".join(["=".join([request[0], urllib.quote_plus(str(request[1]))]) for request in requests])
hashStr = "&".join(["=".join([str.lower(request[0]), urllib.quote_plus(str.lower(str(request[1])))]) for request in requests])
url = "http://" + self.server + "/?"
if not parameters: parameters = {}
parameters["command"] = command
parameters["response"] = self.responseformat
querystring = urllib.urlencode(parameters)
url += querystring
f = urllib2.urlopen(url)
data = f.read()
if self.stripxml == "true":
data=re.sub("<\?.*\?>", "\n", data);
data=re.sub("</[a-z]*>", "\n", data);
data=data.replace(">", "=");
data=data.replace("=<", "\n");
data=data.replace("\n<", "\n");
data=re.sub("\n.*cloud-stack-version=.*", "", data);
data=data.replace("\n\n\n", "\n");
else:
data="\n"+data+"\n"
return data
return data sig = urllib.quote_plus(base64.encodestring(hmac.new(self.securityKey, hashStr, hashlib.sha1).digest()).strip())
requestUrl += "&signature=%s"%sig
return requestUrl
def _make_request_with_auth(self, command, requests):
self.connection = httplib.HTTPConnection("%s"%(self.server))
requests["command"] = command
requests["apiKey"] = self.apiKey
requests["response"] = self.responseformat
requests = zip(requests.keys(), requests.values())
requests.sort(key=lambda x: str.lower(x[0]))
requestUrl = "&".join(["=".join([request[0], urllib.quote_plus(str(request[1]))]) for request in requests])
hashStr = "&".join(["=".join([str.lower(request[0]), urllib.quote_plus(str.lower(str(request[1])))]) for request in requests])
sig = urllib.quote_plus(base64.encodestring(hmac.new(self.securityKey, hashStr, hashlib.sha1).digest()).strip())
requestUrl += "&signature=%s"%sig
self.connection.request("GET", "/client/api?%s"%requestUrl)
return self.connection.getresponse().read()
def _make_request(self,command,parameters=None):
'''Command is a string, parameters is a dictionary'''
if ":" in self.server:
host,port = self.server.split(":")
port = int(port)
else:
host = self.server
port = 8096
url = "http://" + self.server + "/?"
if not parameters: parameters = {}
if self.apiKey is not None and self.securityKey is not None:
return self._make_request_with_auth(command, parameters)
else:
parameters["command"] = command
parameters["response"] = self.responseformat
querystring = urllib.urlencode(parameters)
url += querystring
f = urllib2.urlopen(url)
data = f.read()
if self.stripxml == "true":
data=re.sub("<\?.*\?>", "\n", data);
data=re.sub("</[a-z]*>", "\n", data);
data=data.replace(">", "=");
data=data.replace("=<", "\n");
data=data.replace("\n<", "\n");
data=re.sub("\n.*cloud-stack-version=.*", "", data);
data=data.replace("\n\n\n", "\n");
return data
def load_dynamic_methods(): def load_dynamic_methods():
'''creates smart function objects for every method in the commands.xml file''' '''creates smart function objects for every method in the commands.xml file'''
def getText(nodelist): def getText(nodelist):
rc = [] rc = []
for node in nodelist: for node in nodelist:
if node.nodeType == node.TEXT_NODE: rc.append(node.data) if node.nodeType == node.TEXT_NODE: rc.append(node.data)
return ''.join(rc) return ''.join(rc)
# FIXME figure out installation and packaging # FIXME figure out installation and packaging
xmlfile = os.path.join("/etc/cloud/cli/","commands.xml") xmlfile = os.path.join("/etc/cloud/cli/","commands.xml")
dom = xml.dom.minidom.parse(xmlfile) dom = xml.dom.minidom.parse(xmlfile)
for cmd in dom.getElementsByTagName("command"): for cmd in dom.getElementsByTagName("command"):
name = getText(cmd.getElementsByTagName('name')[0].childNodes).strip() name = getText(cmd.getElementsByTagName('name')[0].childNodes).strip()
assert name assert name
description = getText(cmd.getElementsByTagName('description')[0].childNodes).strip() description = getText(cmd.getElementsByTagName('description')[0].childNodes).strip()
if description: if description:
description = '"""%s"""' % description description = '"""%s"""' % description
else: description = '' else: description = ''
arguments = [] arguments = []
options = [] options = []
descriptions = [] descriptions = []
for param in cmd.getElementsByTagName("request")[0].getElementsByTagName("arg"): for param in cmd.getElementsByTagName("request")[0].getElementsByTagName("arg"):
argname = getText(param.getElementsByTagName('name')[0].childNodes).strip() argname = getText(param.getElementsByTagName('name')[0].childNodes).strip()
assert argname assert argname
required = getText(param.getElementsByTagName('required')[0].childNodes).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)
#import ipdb; ipdb.set_trace() #import ipdb; ipdb.set_trace()
requestDescription = param.getElementsByTagName('description') requestDescription = param.getElementsByTagName('description')
if requestDescription: if requestDescription:
descriptionParam = getText(requestDescription[0].childNodes) descriptionParam = getText(requestDescription[0].childNodes)
else: else:
descriptionParam = '' descriptionParam = ''
if descriptionParam: descriptions.append( (argname,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)
code = """ code = """
def %s(%s): def %s(%s):
%s %s
parms = locals() parms = locals()
del parms["self"] del parms["self"]
for arg in %r: for arg in %r:
if locals()[arg] is None: if locals()[arg] is None:
raise TypeError, "%%s is a required option"%%arg raise TypeError, "%%s is a required option"%%arg
for k,v in parms.items(): for k,v in parms.items():
if v is None: del parms[k] if v is None: del parms[k]
output = self._make_request("%s",parms) output = self._make_request("%s",parms)
return output return output
"""%(name,funcparams,description,arguments,name) """%(name,funcparams,description,arguments,name)
namespace = {} namespace = {}
exec code.strip() in namespace exec code.strip() in namespace
func = namespace[name] func = namespace[name]
for argname,description in descriptions: for argname,description in descriptions:
func = describe(argname,description)(func) func = describe(argname,description)(func)
yield (name,func) yield (name,func)
for name,meth in load_dynamic_methods(): for name,meth in load_dynamic_methods():