import httplib import urllib import base64 import hmac import hashlib import json import xml.dom.minidom import types import time import inspect import cloudstackException from cloudstackAPI import * import jsonHelper class cloudConnection(object): def __init__(self, mgtSvr, port=8096, apiKey = None, securityKey = None, asyncTimeout=3600, logging=None): self.apiKey = apiKey self.securityKey = securityKey self.mgtSvr = mgtSvr self.connection = httplib.HTTPConnection("%s:%d"%(mgtSvr,port)) self.port = port self.logging = logging if port == 8096: self.auth = False else: self.auth = True self.asyncTimeout = asyncTimeout def close(self): try: self.connection.close() except: pass def __copy__(self): return cloudConnection(self.mgtSvr, self.port, self.apiKey, self.securityKey, self.asyncTimeout, self.logging) def make_request_with_auth(self, command, requests={}): requests["command"] = command requests["apiKey"] = self.apiKey requests["response"] = "json" 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]), str.lower(urllib.quote_plus(str(request[1]))).replace("+", "%20")]) 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_without_auth(self, command, requests={}): requests["command"] = command requests["response"] = "json" requests = zip(requests.keys(), requests.values()) requestUrl = "&".join(["=".join([request[0], urllib.quote_plus(str(request[1]))]) for request in requests]) self.connection.request("GET", "/&%s"%requestUrl) return self.connection.getresponse().read() def pollAsyncJob(self, jobId, response): cmd = queryAsyncJobResult.queryAsyncJobResultCmd() cmd.jobid = jobId while self.asyncTimeout > 0: asyncResonse = self.make_request(cmd, response, True) if asyncResonse.jobstatus == 2: raise cloudstackException.cloudstackAPIException("asyncquery", asyncResonse.jobresult) elif asyncResonse.jobstatus == 1: return asyncResonse time.sleep(5) self.asyncTimeout = self.asyncTimeout - 5 raise cloudstackException.cloudstackAPIException("asyncquery", "Async job timeout") def make_request(self, cmd, response = None, raw=False): commandName = cmd.__class__.__name__.replace("Cmd", "") isAsync = "false" requests = {} required = [] for attribute in dir(cmd): if attribute != "__doc__" and attribute != "__init__" and attribute != "__module__": if attribute == "isAsync": isAsync = getattr(cmd, attribute) elif attribute == "required": required = getattr(cmd, attribute) else: requests[attribute] = getattr(cmd, attribute) for requiredPara in required: if requests[requiredPara] is None: raise cloudstackException.cloudstackAPIException(commandName, "%s is required"%requiredPara) '''remove none value''' for param, value in requests.items(): if value is None: requests.pop(param) elif isinstance(value, list): if len(value) == 0: requests.pop(param) else: if not isinstance(value[0], dict): requests[param] = ",".join(value) else: requests.pop(param) i = 0 for v in value: for key, val in v.iteritems(): requests["%s[%d].%s"%(param,i,key)] = val i = i + 1 if self.logging is not None: self.logging.debug("sending command: " + str(requests)) result = None if self.auth: result = self.make_request_with_auth(commandName, requests) else: result = self.make_request_without_auth(commandName, requests) if self.logging is not None: self.logging.debug("got result: " + result) if result is None: return None result = jsonHelper.getResultObj(result, response) if raw or isAsync == "false": return result else: asynJobId = result.jobid result = self.pollAsyncJob(asynJobId, response) return result.jobresult if __name__ == '__main__': xml = '407i-1-407-RS3i-1-407-RS3system1ROOT2011-07-30T14:45:19-0700Runningfalse1CA13kvm-50-2054CentOS 5.5(64-bit) no GUI (KVM)CentOS 5.5(64-bit) no GUI (KVM)false1Small Instance15005121120NetworkFilesystem380203255.255.255.065.19.181.165.19.181.110vlan://65vlan://65GuestDirecttrue06:52:da:00:00:08KVM' conn = cloudConnection(None) print conn.paraseReturnXML(xml, deployVirtualMachine.deployVirtualMachineResponse())