| 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: %s %s"%(commandName, 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 = '<?xml version="1.0" encoding="ISO-8859-1"?><deployVirtualMachineResponse><virtualmachine><id>407</id><name>i-1-407-RS3</name><displayname>i-1-407-RS3</displayname><account>system</account><domainid>1</domainid><domain>ROOT</domain><created>2011-07-30T14:45:19-0700</created><state>Running</state><haenable>false</haenable><zoneid>1</zoneid><zonename>CA1</zonename><hostid>3</hostid><hostname>kvm-50-205</hostname><templateid>4</templateid><templatename>CentOS 5.5(64-bit) no GUI (KVM)</templatename><templatedisplaytext>CentOS 5.5(64-bit) no GUI (KVM)</templatedisplaytext><passwordenabled>false</passwordenabled><serviceofferingid>1</serviceofferingid><serviceofferingname>Small Instance</serviceofferingname><cpunumber>1</cpunumber><cpuspeed>500</cpuspeed><memory>512</memory><guestosid>112</guestosid><rootdeviceid>0</rootdeviceid><rootdevicetype>NetworkFilesystem</rootdevicetype><nic><id>380</id><networkid>203</networkid><netmask>255.255.255.0</netmask><gateway>65.19.181.1</gateway><ipaddress>65.19.181.110</ipaddress><isolationuri>vlan://65</isolationuri><broadcasturi>vlan://65</broadcasturi><traffictype>Guest</traffictype><type>Direct</type><isdefault>true</isdefault><macaddress>06:52:da:00:00:08</macaddress></nic><hypervisor>KVM</hypervisor></virtualmachine></deployVirtualMachineResponse>' |
| conn = cloudConnection(None) |
| |
| print conn.paraseReturnXML(xml, deployVirtualMachine.deployVirtualMachineResponse()) |