mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
add apikey/securitykey in cloud-cli
This commit is contained in:
parent
8d4c7208a4
commit
18255e985c
@ -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():
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user