# Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import cloudstackException import json import inspect from marvin.cloudstackAPI import * class jsonLoader(object): '''The recursive class for building and representing objects with.''' def __init__(self, obj): for k in obj: v = obj[k] if isinstance(v, dict): setattr(self, k, jsonLoader(v)) elif isinstance(v, (list, tuple)): if len(v) > 0 and isinstance(v[0], dict): setattr(self, k, [jsonLoader(elem) for elem in v]) else: setattr(self, k, v) else: setattr(self, k, v) def __getattr__(self, val): if val in self.__dict__: return self.__dict__[val] else: return None def __repr__(self): return '{%s}' % str(', '.join('%s : %s' % (k, repr(v)) for (k, v) in self.__dict__.iteritems())) def __str__(self): return '{%s}' % str(', '.join('%s : %s' % (k, repr(v)) for (k, v) in self.__dict__.iteritems())) class jsonDump(object): @staticmethod def __serialize(obj): """Recursively walk object's hierarchy.""" if isinstance(obj, (bool, int, long, float, basestring)): return obj elif isinstance(obj, dict): obj = obj.copy() newobj = {} for key in obj: if obj[key] is not None: if (isinstance(obj[key], list) and len(obj[key]) == 0): continue newobj[key] = jsonDump.__serialize(obj[key]) return newobj elif isinstance(obj, list): return [jsonDump.__serialize(item) for item in obj] elif isinstance(obj, tuple): return tuple(jsonDump.__serialize([item for item in obj])) elif hasattr(obj, '__dict__'): return jsonDump.__serialize(obj.__dict__) else: return repr(obj) # Don't know how to handle, convert to string @staticmethod def dump(obj): return jsonDump.__serialize(obj) def getclassFromName(cmd, name): module = inspect.getmodule(cmd) return getattr(module, name)() def finalizeResultObj(result, responseName, responsecls): responsclsLoadable = (responsecls is None and responseName.endswith("response") and responseName != "queryasyncjobresultresponse") if responsclsLoadable: '''infer the response class from the name''' moduleName = responseName.replace("response", "") try: responsecls = getclassFromName(moduleName, responseName) except: pass responsNameValid = (responseName is not None and responseName == "queryasyncjobresultresponse" and responsecls is not None and result.jobresult is not None) if responsNameValid: result.jobresult = finalizeResultObj(result.jobresult, None, responsecls) return result elif responsecls is not None: for k, v in result.__dict__.iteritems(): if k in responsecls.__dict__: return result attr = result.__dict__.keys()[0] value = getattr(result, attr) if not isinstance(value, jsonLoader): return result findObj = False for k, v in value.__dict__.iteritems(): if k in responsecls.__dict__: findObj = True break if findObj: return value else: return result else: return result def getResultObj(returnObj, responsecls=None): if len(returnObj) == 0: return None responseName = filter(lambda a: a != u'cloudstack-version', returnObj.keys())[0] response = returnObj[responseName] if len(response) == 0: return None result = jsonLoader(response) if result.errorcode is not None: errMsg = "errorCode: %s, errorText:%s" % (result.errorcode, result.errortext) respname = responseName.replace("response", "") raise cloudstackException.CloudstackAPIException(respname, errMsg) if result.count is not None: for key in result.__dict__.iterkeys(): if key == "count": continue else: return getattr(result, key) else: return finalizeResultObj(result, responseName, responsecls) if __name__ == "__main__": result = '''{ "listnetworkserviceprovidersresponse" : { "count" : 1, "networkserviceprovider" : [ { "destinationphysicalnetworkid" : "0", "id" : "d827cae4-4998-4037-95a2-55b92b6318b1", "name" : "VirtualRouter", "physicalnetworkid" : "ad2948fc-1054-46c7-b1c7-61d990b86710", "servicelist" : [ "Vpn", "Dhcp", "Dns", "Gateway", "Firewall", "Lb", "SourceNat", "StaticNat", "PortForwarding", "UserData" ], "state" : "Disabled" } ] } }''' nsp = getResultObj(result) print nsp[0].id result = '''{ "listzonesresponse" : { "count" : 1, "zone" : [ { "allocationstate" : "Enabled", "dhcpprovider" : "DhcpServer", "dns1" : "8.8.8.8", "dns2" : "8.8.4.4", "id" : 1, "internaldns1" : "192.168.110.254", "internaldns2" : "192.168.110.253", "name" : "test0", "networktype" : "Basic", "securitygroupsenabled" : true, "zonetoken" : "5e818a11-6b00-3429-9a07-e27511d3169a" } ] } }''' zones = getResultObj(result) print zones[0].id res = authorizeSecurityGroupIngress.authorizeSecurityGroupIngressResponse() result = '''{ "queryasyncjobresultresponse" : { "jobid" : 10, "jobprocstatus" : 0, "jobresult" : { "securitygroup" : { "account" : "admin", "description" : "Default Security Group", "domain" : "ROOT", "domainid" : 1, "id" : 1, "ingressrule" : [ { "account" : "a", "endport" : 22, "protocol" : "tcp", "ruleid" : 1, "securitygroupname" : "default", "startport" : 22 }, { "account" : "b", "endport" : 22, "protocol" : "tcp", "ruleid" : 2, "securitygroupname" : "default", "startport" : 22 } ], "name" : "default" } }, "jobresultcode" : 0, "jobresulttype" : "object", "jobstatus" : 1 } }''' asynJob = getResultObj(result, res) print asynJob.jobid, repr(asynJob.jobresult) print asynJob.jobresult.ingressrule[0].account result = '''{ "queryasyncjobresultresponse" : { "errorcode" : 431, "errortext" : "Unable to execute API command queryasyncjobresultresponse \ due to missing parameter jobid" } }''' try: asynJob = getResultObj(result) except cloudstackException.CloudstackAPIException as e: print e result = '{ "queryasyncjobresultresponse" : {} }' asynJob = getResultObj(result) print asynJob result = '{}' asynJob = getResultObj(result) print asynJob result = '''{ "createzoneresponse" : { "zone" : { "id":1,"name":"test0","dns1":"8.8.8.8","dns2":"8.8.4.4", "internaldns1":"192.168.110.254","internaldns2":"192.168.110.253", "networktype":"Basic","securitygroupsenabled":true, "allocationstate":"Enabled", "zonetoken":"3442f287-e932-3111-960b-514d1f9c4610", "dhcpprovider":"DhcpServer" } } }''' res = createZone.createZoneResponse() zone = getResultObj(result, res) print zone.id result = '{ "attachvolumeresponse" : {"jobid":24} }' res = attachVolume.attachVolumeResponse() res = getResultObj(result, res) print res result = '{ "listtemplatesresponse" : { } }' print getResultObj(result, listTemplates.listTemplatesResponse()) result = '''{ "queryasyncjobresultresponse" : { "jobid":34,"jobstatus":2,"jobprocstatus":0,"jobresultcode":530, "jobresulttype":"object","jobresult":{ "errorcode":431, "errortext": "Please provide either a volume id, or a tuple(device id, instance id)" } } }''' print getResultObj(result, listTemplates.listTemplatesResponse()) result = '''{ "queryasyncjobresultresponse" : { "jobid":41,"jobstatus":1,"jobprocstatus":0, "jobresultcode":0,"jobresulttype":"object","jobresult":{ "virtualmachine":{ "id":37,"name":"i-2-37-TEST", "displayname":"i-2-37-TEST","account":"admin", "domainid":1,"domain":"ROOT", "created":"2011-08-25T11:13:42-0700", "state":"Running","haenable":false,"zoneid":1, "zonename":"test0","hostid":5, "hostname": "SimulatedAgent.1e629060-f547-40dd-b792-57cdc4b7d611", "templateid":10, "templatename":"CentOS 5.3(64-bit) no GUI (Simulator)", "templatedisplaytext": "CentOS 5.3(64-bit) no GUI (Simulator)", "passwordenabled":false,"serviceofferingid":7, "serviceofferingname":"Small Instance","cpunumber":1, "cpuspeed":500,"memory":512,"guestosid":11, "rootdeviceid":0,"rootdevicetype":"NetworkFilesystem", "securitygroup":[{"id":1,"name":"default", "description":"Default Security Group"}], "nic":[{"id":43,"networkid":204, "netmask":"255.255.255.0","gateway":"192.168.1.1", "ipaddress":"192.168.1.27", "isolationuri":"ec2://untagged", "broadcasturi":"vlan://untagged", "traffictype":"Guest","type":"Direct", "isdefault":true,"macaddress":"06:56:b8:00:00:53"}], "hypervisor":"Simulator" } } } }''' result = '''{ "queryasyncjobresultresponse" : { "accountid":"30910093-22e4-4d3c-a464-8b36b60c8001", "userid":"cb0aeca3-42ee-47c4-838a-2cd9053441f2", "cmd":"com.cloud.api.commands.DeployVMCmd","jobstatus":1, "jobprocstatus":0,"jobresultcode":0,"jobresulttype":"object", "jobresult":{ "virtualmachine":{ "id":"d2e4d724-e089-4e59-be8e-647674059016", "name":"i-2-14-TEST","displayname":"i-2-14-TEST", "account":"admin", "domainid":"8cfafe79-81eb-445e-8608-c5b7c31fc3a5", "domain":"ROOT","created":"2012-01-15T18:30:11+0530", "state":"Running","haenable":false, "zoneid":"30a397e2-1c85-40c0-8463-70278952b046", "zonename":"Sandbox-simulator", "hostid":"cc0105aa-a2a9-427a-8ad7-4d835483b8a9", "hostname": "SimulatedAgent.9fee20cc-95ca-48b1-8268-5513d6e83a1b", "templateid":"d92570fa-bf40-44db-9dff-45cc7042604d", "templatename":"CentOS 5.3(64-bit) no GUI (Simulator)", "templatedisplaytext":"CentOS 5.3(64-bit) no GUI (Simulator)", "passwordenabled":false, "serviceofferingid":"3734d632-797b-4f1d-ac62-33f9cf70d005", "serviceofferingname":"Sample SO","cpunumber":1,"cpuspeed":100, "memory":128, "guestosid":"1e36f523-23e5-4e90-869b-a1b5e9ba674d", "rootdeviceid":0,"rootdevicetype":"NetworkFilesystem", "nic":[{"id":"4d3ab903-f511-4dab-8a6d-c2a3b51de7e0", "networkid":"faeb7f24-a4b9-447d-bec6-c4956c4ab0f6", "netmask":"255.255.240.0","gateway":"10.6.240.1",' "ipaddress":"10.6.253.89","isolationuri":"vlan://211", "broadcasturi":"vlan://211","traffictype":"Guest", "type":"Isolated","isdefault":true, "macaddress":"02:00:04:74:00:09"}], "hypervisor":"Simulator" } }, "created":"2012-01-15T18:30:11+0530", "jobid":"f4a13f28-fcd6-4d7f-b9cd-ba7eb5a5701f" } }''' vm = getResultObj(result, deployVirtualMachine.deployVirtualMachineResponse()) print vm.jobresult.id cmd = deployVirtualMachine.deployVirtualMachineCmd() responsename = cmd.__class__.__name__.replace("Cmd", "Response") response = getclassFromName(cmd, responsename) print response.id