cloudstack/tools/testClient/cloudstackConnection.py
Prasanna Santhanam 94eac37d30 The HTTPConnection object times out too soon when status is being polled. This
depends on python's internal socket implementation. Added an explicit 3m
timeout. Test code MUST NOT induce sleeps longer than 3m, instead check status
periodically to keep the HTTPConnection alive.
reviewed-by: Chirag Jog <chirag@clogeny.com>
2012-02-23 18:35:15 +05:30

143 lines
6.6 KiB
Python

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), timeout=180)
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())