mirror of
				https://github.com/apache/cloudstack.git
				synced 2025-10-26 08:42:29 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			244 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			244 lines
		
	
	
		
			11 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 * 
 | |
| 
 | |
| 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 __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"] = "xml"
 | |
|         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_without_auth(self, command, requests={}):
 | |
|         requests["command"] = command
 | |
|         requests["response"] = "xml" 
 | |
|         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 getText(self, elements):
 | |
|         if len(elements) < 1:
 | |
|             return None
 | |
|         if not elements[0].hasChildNodes():
 | |
|             return None
 | |
|         if elements[0].childNodes[0].nodeValue is None:
 | |
|             return None
 | |
|         return elements[0].childNodes[0].nodeValue.strip()
 | |
|     
 | |
|     def getclassFromName(self, cmd, name):
 | |
|         module = inspect.getmodule(cmd)
 | |
|         return getattr(module, name)()
 | |
|     def parseOneInstance(self, element, instance):
 | |
|         ItemsNeedToCheck = {}
 | |
|         for attribute in dir(instance):
 | |
|             if attribute != "__doc__" and attribute != "__init__" and attribute != "__module__":
 | |
|                 ItemsNeedToCheck[attribute] = getattr(instance, attribute)
 | |
|         for attribute, value in ItemsNeedToCheck.items():
 | |
|             if type(value) == types.ListType:
 | |
|                 subItem = []
 | |
|                 for subElement in element.getElementsByTagName(attribute):
 | |
|                     newInstance = self.getclassFromName(instance, attribute)
 | |
|                     self.parseOneInstance(subElement, newInstance)
 | |
|                     subItem.append(newInstance)
 | |
|                 setattr(instance, attribute, subItem)
 | |
|                 continue
 | |
|             else:
 | |
|                 item = element.getElementsByTagName(attribute)
 | |
|                 if len(item) == 0:
 | |
|                     continue
 | |
|                 
 | |
|                 returnValue = self.getText(item)
 | |
|                 setattr(instance, attribute, returnValue)
 | |
|         
 | |
|     def hasErrorCode(self, elements, responseName):
 | |
|         errorCode = elements[0].getElementsByTagName("errorcode")
 | |
|         if len(errorCode) > 0:
 | |
|             erroCodeText = self.getText(errorCode)
 | |
|             errorText = elements[0].getElementsByTagName("errortext")
 | |
|             if len(errorText) > 0:
 | |
|                 errorText = self.getText(errorText)
 | |
|             errMsg = "errorCode: %s, errorText:%s"%(erroCodeText, errorText)
 | |
|             raise cloudstackException.cloudstackAPIException(responseName, errMsg)
 | |
|     
 | |
|     def paraseReturnXML(self, result, response):
 | |
|         responseName = response.__class__.__name__.lower()
 | |
|         cls = response.__class__
 | |
|        
 | |
|         responseLists = []
 | |
|         morethanOne = False
 | |
|         
 | |
|         dom = xml.dom.minidom.parseString(result)
 | |
|         elements = dom.getElementsByTagName(responseName)
 | |
|         if len(elements) == 0:
 | |
|             return responseLists
 | |
|         
 | |
|         self.hasErrorCode(elements, responseName)
 | |
|         
 | |
|         count = elements[0].getElementsByTagName("count")
 | |
|         if len(count) > 0:
 | |
|             morethanOne = True
 | |
|             for node in elements[0].childNodes:
 | |
|                 if node.nodeName == "count":
 | |
|                     continue
 | |
|                 newInstance = cls()
 | |
|                 self.parseOneInstance(node, newInstance)
 | |
|                 responseLists.append(newInstance)
 | |
|                 
 | |
|         else:
 | |
|             if elements[0].hasChildNodes():
 | |
|                 newInstance = cls()
 | |
|                 self.parseOneInstance(elements[0], newInstance)
 | |
|                 responseLists.append(newInstance)
 | |
|         
 | |
|         return responseLists, morethanOne
 | |
|     
 | |
|     def paraseResultFromElement(self, elements, response):
 | |
|         responseName = response.__class__.__name__.lower()
 | |
|         cls = response.__class__
 | |
|       
 | |
|         responseLists = []
 | |
|         morethanOne = False
 | |
|       
 | |
|         newInstance = cls()
 | |
|         self.parseOneInstance(elements[0], newInstance)
 | |
|         responseLists.append(newInstance)
 | |
|         
 | |
|         return responseLists, morethanOne
 | |
|     def getAsyncJobId(self, response, resultXml):
 | |
|         responseName = response.__class__.__name__.lower()
 | |
|         dom = xml.dom.minidom.parseString(resultXml)
 | |
|         elements = dom.getElementsByTagName(responseName)
 | |
|         if len(elements) == 0:
 | |
|             raise cloudstackException.cloudstackAPIException("can't find %s"%responseName)
 | |
|         
 | |
|         self.hasErrorCode(elements, responseName)
 | |
|         
 | |
|         jobIdEle = elements[0].getElementsByTagName("jobid")
 | |
|         if len(jobIdEle) == 0:
 | |
|             errMsg = 'can not find jobId in the result:%s'%resultXml
 | |
|             
 | |
|             raise cloudstackException.cloudstackAPIException(errMsg)
 | |
|         
 | |
|         jobId = self.getText(jobIdEle)
 | |
|         return jobId
 | |
|     
 | |
|     def pollAsyncJob(self, cmd, response, jobId):
 | |
|         commandName = cmd.__class__.__name__.replace("Cmd", "")
 | |
|         cmd = queryAsyncJobResult.queryAsyncJobResultCmd()
 | |
|         cmd.jobid = jobId
 | |
|         
 | |
|         while self.asyncTimeout > 0:
 | |
|             asyncResponse = queryAsyncJobResult.queryAsyncJobResultResponse()
 | |
|             responseName = asyncResponse.__class__.__name__.lower()
 | |
|             asyncResponseXml = self.make_request(cmd, asyncResponse, True)
 | |
|             dom = xml.dom.minidom.parseString(asyncResponseXml)
 | |
|             elements = dom.getElementsByTagName(responseName)
 | |
|             if len(elements) == 0:
 | |
|                 raise cloudstackException.cloudstackAPIException("can't find %s"%responseName)
 | |
|         
 | |
|             self.hasErrorCode(elements, responseName)
 | |
|             
 | |
|             jobstatus =  self.getText(elements[0].getElementsByTagName("jobstatus"))
 | |
|             
 | |
|             if jobstatus == "2":
 | |
|                 jobResult = self.getText(elements[0].getElementsByTagName("jobresult"))
 | |
|                 raise cloudstackException.cloudstackAPIException(commandName, jobResult)
 | |
|             elif jobstatus == "1":
 | |
|                 jobResultEle = elements[0].getElementsByTagName("jobresult")
 | |
|                 
 | |
|                 return self.paraseResultFromElement(jobResultEle, response)
 | |
|                 
 | |
|             time.sleep(5)
 | |
|             
 | |
|         raise cloudstackException.cloudstackAPIException(commandName, "Async job timeout")
 | |
|     def make_request(self, cmd, response, 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)
 | |
|         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
 | |
|         
 | |
|         if raw:
 | |
|             return result
 | |
|         if isAsync == "false":
 | |
|             result,num = self.paraseReturnXML(result, response)
 | |
|         else:
 | |
|             jobId = self.getAsyncJobId(response, result)
 | |
|             result,num = self.pollAsyncJob(cmd, response, jobId)
 | |
|         if num:
 | |
|             return result
 | |
|         else:
 | |
|             if len(result) != 0:
 | |
|                return result[0]
 | |
|             return None
 | |
|         
 | |
| 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()) |