diff --git a/api/src/com/cloud/api/commands/AuthorizeSecurityGroupIngressCmd.java b/api/src/com/cloud/api/commands/AuthorizeSecurityGroupIngressCmd.java index d192f5d06b6..95f29b0d236 100644 --- a/api/src/com/cloud/api/commands/AuthorizeSecurityGroupIngressCmd.java +++ b/api/src/com/cloud/api/commands/AuthorizeSecurityGroupIngressCmd.java @@ -47,7 +47,7 @@ import com.cloud.utils.StringUtils; public class AuthorizeSecurityGroupIngressCmd extends BaseAsyncCmd { public static final Logger s_logger = Logger.getLogger(AuthorizeSecurityGroupIngressCmd.class.getName()); - private static final String s_name = "authorizesecuritygroupingress"; + private static final String s_name = "authorizesecuritygroupingressresponse"; // /////////////////////////////////////////////////// // ////////////// API parameters ///////////////////// diff --git a/server/src/com/cloud/api/doc/ApiXmlDocWriter.java b/server/src/com/cloud/api/doc/ApiXmlDocWriter.java index 2c8ed0c9bd0..6d6af87f2f5 100644 --- a/server/src/com/cloud/api/doc/ApiXmlDocWriter.java +++ b/server/src/com/cloud/api/doc/ApiXmlDocWriter.java @@ -400,6 +400,10 @@ public class ApiXmlDocWriter { if (!parameterAnnotation.description().isEmpty()) { reqArg.setDescription(parameterAnnotation.description()); } + + if (parameterAnnotation.type() == BaseCmd.CommandType.LIST || parameterAnnotation.type() == BaseCmd.CommandType.MAP) { + reqArg.setType(parameterAnnotation.type().toString().toLowerCase()); + } if (reqArg.isRequired() == true) { if (parameterAnnotation.name().equals("id")) { diff --git a/server/src/com/cloud/api/doc/Argument.java b/server/src/com/cloud/api/doc/Argument.java index 6fb2603cd36..2cb47d6c17a 100644 --- a/server/src/com/cloud/api/doc/Argument.java +++ b/server/src/com/cloud/api/doc/Argument.java @@ -24,6 +24,7 @@ public class Argument implements Comparable{ private String name; private String description; private Boolean required; + private String type; private List arguments; public Argument(String name) { @@ -41,6 +42,14 @@ public class Argument implements Comparable{ this.description = description; } + public String getType() { + return this.type; + } + + public void setType(String type) { + this.type = type; + } + public String getName() { return name; } diff --git a/tools/testClient/asyncJobMgr.py b/tools/testClient/asyncJobMgr.py index 3a53b552fdc..0872601962a 100644 --- a/tools/testClient/asyncJobMgr.py +++ b/tools/testClient/asyncJobMgr.py @@ -16,6 +16,7 @@ class jobStatus(object): self.startTime = None self.endTime = None self.duration = None + self.jobId = None class workThread(threading.Thread): def __init__(self, in_queue, out_dict, apiClient, db=None): threading.Thread.__init__(self) @@ -23,8 +24,6 @@ class workThread(threading.Thread): self.output = out_dict self.connection = copy.copy(apiClient.connection) self.db = None - if db is not None: - self.db = copy.copy(db) def run(self): while self.inqueue.qsize() > 0: @@ -46,8 +45,8 @@ class workThread(threading.Thread): jobId = self.connection.getAsyncJobId(responseInstance, result) result,morethanone = self.connection.pollAsyncJob(cmd, responseInstance, jobId) jobstatus.result = result - - + jobstatus.jobId = jobId + jobstatus.status = True except cloudstackException.cloudstackAPIException, e: jobstatus.result = str(e) @@ -56,27 +55,16 @@ class workThread(threading.Thread): jobstatus.status = False jobstatus.result = sys.exc_info() - if self.db is not None and jobId is not None: - result = self.db.execute("select job_status, created, last_updated from async_job where id=%s"%jobId) - if result is not None and len(result) > 0: - if result[0][0] == 1: - jobstatus.status = True - else: - jobstatus.status = False - jobstatus.startTime = result[0][1] - jobstatus.endTime = result[0][2] - delta = jobstatus.endTime - jobstatus.startTime - jobstatus.duration = delta.total_seconds() + #print job.id self.output.lock.acquire() self.output.dict[job.id] = jobstatus self.output.lock.release() self.inqueue.task_done() + '''release the resource''' self.connection.close() - if self.db is not None: - self.db.close() class jobThread(threading.Thread): def __init__(self, inqueue, interval): @@ -124,6 +112,21 @@ class asyncJobMgr(object): def waitForComplete(self): self.inqueue.join() + + for k,jobstatus in self.output.dict.iteritems(): + jobId = jobstatus.jobId + if jobId is not None and self.db is not None: + result = self.db.execute("select job_status, created, last_updated from async_job where id=%s"%jobId) + if result is not None and len(result) > 0: + if result[0][0] == 1: + jobstatus.status = True + else: + jobstatus.status = False + jobstatus.startTime = result[0][1] + jobstatus.endTime = result[0][2] + delta = jobstatus.endTime - jobstatus.startTime + jobstatus.duration = delta.total_seconds() + return self.output.dict '''put commands into a queue at first, then start workers numbers threads to execute this commands''' diff --git a/tools/testClient/cloudstackConnection.py b/tools/testClient/cloudstackConnection.py index 1d9c3074c7c..e0a6a22519d 100644 --- a/tools/testClient/cloudstackConnection.py +++ b/tools/testClient/cloudstackConnection.py @@ -43,7 +43,7 @@ class cloudConnection(object): 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]) + 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()) @@ -216,6 +216,20 @@ class cloudConnection(object): 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 diff --git a/tools/testClient/cloudstackTestClient.py b/tools/testClient/cloudstackTestClient.py index 5a843eb40ad..150e02b9046 100644 --- a/tools/testClient/cloudstackTestClient.py +++ b/tools/testClient/cloudstackTestClient.py @@ -16,7 +16,12 @@ class cloudstackTestClient(object): def dbConfigure(self, host="localhost", port=3306, user='cloud', passwd='cloud', db='cloud'): self.dbConnection = dbConnection.dbConnection(host, port, user, passwd, db) - + def close(self): + if self.connection is not None: + self.connection.close() + if self.dbConnection is not None: + self.dbConnection.close() + def getDbConnection(self): return self.dbConnection @@ -34,10 +39,10 @@ class cloudstackTestClient(object): def getApiClient(self): return self.apiClient - def submitCmdsAndWait(self, cmds): + def submitCmdsAndWait(self, cmds, workers=10): if self.asyncJobMgr is None: self.asyncJobMgr = asyncJobMgr.asyncJobMgr(self.apiClient, self.dbConnection) - return self.asyncJobMgr.submitCmdsAndWait(cmds) + return self.asyncJobMgr.submitCmdsAndWait(cmds, workers) '''submit one job and execute the same job ntimes, with nums_threads of threads''' def submitJob(self, job, ntimes=1, nums_threads=10, interval=1): diff --git a/tools/testClient/codegenerator.py b/tools/testClient/codegenerator.py index 36310da9518..aea53b8854b 100644 --- a/tools/testClient/codegenerator.py +++ b/tools/testClient/codegenerator.py @@ -7,6 +7,7 @@ class cmdParameterProperty(object): self.name = None self.required = False self.desc = "" + self.type = "planObject" self.subProperties = [] class cloudStackCmd: @@ -76,7 +77,12 @@ class codeGenerator: self.code += self.space + self.space + '"""%s"""\n'%req.desc if req.required == "true": self.code += self.space + self.space + '"""Required"""\n' - self.code += self.space + self.space + 'self.%s = None\n'%req.name + + value = "None" + if req.type == "list" or req.type == "map": + value = "[]" + + self.code += self.space + self.space + 'self.%s = %s\n'%(req.name,value) if req.required == "true": self.required.append(req.name) @@ -206,10 +212,14 @@ class codeGenerator: if required: paramProperty.required = getText(required) - requestDescription = param.getElementsByTagName('description') + requestDescription = param.getElementsByTagName('description') if requestDescription: paramProperty.desc = getText(requestDescription) + type = param.getElementsByTagName("type") + if type: + paramProperty.type = getText(type) + csCmd.request.append(paramProperty) responseEle = cmd.getElementsByTagName("response")[0] diff --git a/tools/testClient/configGenerator.py b/tools/testClient/configGenerator.py index ac6b17615d4..51b58861ab7 100644 --- a/tools/testClient/configGenerator.py +++ b/tools/testClient/configGenerator.py @@ -420,5 +420,5 @@ if __name__ == "__main__": parser.add_option("-o", "--output", action="store", default="./datacenterCfg", dest="output", help="the path where the json config file generated, by default is ./datacenterCfg") (options, args) = parser.parse_args() - config = describe_setup_in_advanced_mode() + config = describe_setup_in_basic_mode() generate_setup_config(config, options.output) diff --git a/tools/testClient/dbConnection.py b/tools/testClient/dbConnection.py index 326a03524fa..f4748f3c909 100644 --- a/tools/testClient/dbConnection.py +++ b/tools/testClient/dbConnection.py @@ -13,7 +13,7 @@ class dbConnection(object): try: self.db = pymysql.Connect(host=host, port=port, user=user, passwd=passwd, db=db) except: - raise cloudstackException.InvalidParameterException(sys.exc_value) + raise cloudstackException.InvalidParameterException(sys.exc_info()) def __copy__(self): return dbConnection(self.host, self.port, self.user, self.passwd, self.database) @@ -40,14 +40,12 @@ class dbConnection(object): resultRow.append(r) return resultRow except pymysql.MySQLError, e: - if cursor is not None: - cursor.close() raise cloudstackException.dbException("db Exception:%s"%e[1]) except: + raise cloudstackException.internalError(sys.exc_info()) + finally: if cursor is not None: cursor.close() - raise cloudstackException.internalError(sys.exc_value) - def executeSqlFromFile(self, fileName=None): if fileName is None: @@ -72,8 +70,7 @@ if __name__ == "__main__": print e ''' print db.execute("update vm_template set name='fjkd' where id=200") - result = db.execute("select created,last_updated from async_job where id=13") - print result - delta = result[0][1] - result[0][0] - print delta.total_seconds() - #print db.execute("update vm_template set name='fjkd' where id=200") \ No newline at end of file + for i in range(10): + result = db.execute("select job_status, created, last_updated from async_job where id=%d"%i) + print result + \ No newline at end of file diff --git a/tools/testClient/deployDataCenter.py b/tools/testClient/deployDataCenter.py index 47641573044..891d7f31b1e 100644 --- a/tools/testClient/deployDataCenter.py +++ b/tools/testClient/deployDataCenter.py @@ -165,7 +165,26 @@ class deployDataCenters(): self.createnetworks(zone.networks, zoneId) '''create secondary storage''' self.createSecondaryStorages(zone.secondaryStorages, zoneId) - + + def registerApiKey(self): + listuser = listUsers.listUsersCmd() + listuser.account = "admin" + listuserRes = self.testClient.getApiClient().listUsers(listuser) + userId = listuserRes[0].id + apiKey = listuserRes[0].apikey + securityKey = listuserRes[0].secretkey + if apiKey is None: + registerUser = registerUserKeys.registerUserKeysCmd() + registerUser.id = userId + registerUserRes = self.testClient.getApiClient().registerUserKeys(registerUser) + apiKey = registerUserRes.apikey + securityKey = registerUserRes.secretkey + + self.config.mgtSvr[0].port = 8080 + self.config.mgtSvr[0].apiKey = apiKey + self.config.mgtSvr[0].securityKey = securityKey + return apiKey, securityKey + def loadCfg(self): try: self.config = configGenerator.get_setup_config(self.configFile) @@ -193,8 +212,13 @@ class deployDataCenters(): fh = logging.FileHandler(testClientLogFile) testClientLogger.addHandler(fh) testClientLogger.setLevel(logging.DEBUG) + self.testClientLogger = testClientLogger - self.testClient = cloudstackTestClient.cloudstackTestClient(mgt.mgtSvrIp, mgt.port, mgt.apiKey, mgt.securityKey, logging=testClientLogger) + self.testClient = cloudstackTestClient.cloudstackTestClient(mgt.mgtSvrIp, mgt.port, mgt.apiKey, mgt.securityKey, logging=self.testClientLogger) + if mgt.apiKey is None: + apiKey, securityKey = self.registerApiKey() + self.testClient.close() + self.testClient = cloudstackTestClient.cloudstackTestClient(mgt.mgtSvrIp, 8080, apiKey, securityKey, logging=self.testClientLogger) '''config database''' dbSvr = self.config.dbSvr @@ -216,6 +240,7 @@ class deployDataCenters(): self.createZones(self.config.zones) self.updateConfiguration(self.config.globalConfig) + if __name__ == "__main__": parser = OptionParser() diff --git a/tools/testClient/testcase/test_1.py b/tools/testClient/testcase/test_1.py index a97bbb3b916..c1593c1c97b 100644 --- a/tools/testClient/testcase/test_1.py +++ b/tools/testClient/testcase/test_1.py @@ -15,4 +15,4 @@ class TestCase1(cloudstackTestCase): else: self.debug("we are there") - + diff --git a/tools/testClient/testcase/test_3.py b/tools/testClient/testcase/test_3.py index 676bf7a5fae..a41d9ecfad3 100644 --- a/tools/testClient/testcase/test_3.py +++ b/tools/testClient/testcase/test_3.py @@ -28,6 +28,31 @@ class TestCase1(cloudstackTestCase): def test_cloudstackapi(self): apiClient = self.testClient.getApiClient() + + getzone = listZones.listZonesCmd() + getzone.id = self.zoneId + zone = apiClient.listZones(getzone) + if zone[0].networktype == "Basic": + '''create a security group for admin''' + admincmd = listUsers.listUsersCmd() + admincmd.account = "admin" + admin = apiClient.listUsers(admincmd) + domainId = admin[0].domainid + + securitygroup = authorizeSecurityGroupIngress.authorizeSecurityGroupIngressCmd() + securitygroup.domainid = admin[0].domainid + securitygroup.account = admin[0].account + securitygroup.securitygroupid = 1 + securitygroup.protocol = "TCP" + securitygroup.startport = "22" + securitygroup.endport = "22" + ''' + groups = [{"account":"a","group":"default"}, {"account":"b", "group":"default"}] + securitygroup.usersecuritygrouplist = groups + ''' + cidrlist = ["192.168.1.1/24", "10.1.1.1/24"] + securitygroup.cidrlist = cidrlist + apiClient.authorizeSecurityGroupIngress(securitygroup) createvm = deployVirtualMachine.deployVirtualMachineCmd() createvm.serviceofferingid = self.svid @@ -46,4 +71,20 @@ class TestCase1(cloudstackTestCase): attach.id = volumeId attach.virtualmachineid = vmId - apiClient.attachVolume(attach) \ No newline at end of file + apiClient.attachVolume(attach) + + detach = detachVolume.detachVolumeCmd() + detach.id = volumeId + detach.virtualmachineid = vmId + apiClient.detachVolume(detach) + + snapshotcmd = createSnapshot.createSnapshotCmd() + snapshotcmd.volumeid = volumeId + snapshotrespose = apiClient.createSnapshot(snapshotcmd) + snapshotId = snapshotrespose.id + + createvolume = createVolume.createVolumeCmd() + createvolume.snapshotid = snapshotId + createvolume.name = "volumefrom_snapshot"+ str(snapshotId) + apiClient.createVolume(createvolume) + \ No newline at end of file diff --git a/tools/testClient/unitTest/test_async.py b/tools/testClient/unitTest/test_async.py index a8d825662d5..acd5b6d75d7 100644 --- a/tools/testClient/unitTest/test_async.py +++ b/tools/testClient/unitTest/test_async.py @@ -2,7 +2,7 @@ from cloudstackAPI import * import cloudstackException import cloudstackTestClient import sys - +import uuid class jobs(): def __init__(self, zoneId): @@ -26,10 +26,10 @@ if __name__ == "__main__": logger.setLevel(logging.DEBUG) testclient = cloudstackTestClient.cloudstackTestClient(mgtSvr="localhost", logging=logger) ''' - testclient = cloudstackTestClient.cloudstackTestClient(mgtSvr="localhost") + testclient = cloudstackTestClient.cloudstackTestClient(mgtSvr="localhost", port=8080, apiKey="rUJI62HcbyhAXpRgqERZHXlrJz9GiC55fmAm7j4WobLUTFkJyupBm87sbMki1-aRFox7TDs436xYvNW9fTHcew", securityKey="2_SIz9HULx5guCLypSoRoePCBFnTZGIrA3gQ0qhy__oca6dDacJwibMSQh-kVeJivJHeA55AwJZPJAu4U3V5KQ") testclient.dbConfigure() api = testclient.getApiClient() - + ''' testclient.submitJob(jobs(1), 10, 10, 1) js = [] @@ -37,18 +37,21 @@ if __name__ == "__main__": js.append(jobs(1)) testclient.submitJobs(js, 10, 1) - + ''' cmds = [] for i in range(20): - cmd = destroyVirtualMachine.destroyVirtualMachineCmd() - cmd.id = 4 + i + cmd = deployVirtualMachine.deployVirtualMachineCmd() + cmd.zoneid =1 + cmd.templateid = 10 + cmd.serviceofferingid = 16 + cmd.displayname = str(uuid.uuid4()) cmds.append(cmd) - asyncJobResult = testclient.submitCmdsAndWait(cmds) + asyncJobResult = testclient.submitCmdsAndWait(cmds, 6) for handle, jobStatus in asyncJobResult.iteritems(): if jobStatus.status: - print jobStatus.result.id, jobStatus.result.templatename, jobStatus.startTime, jobStatus.endTime + print jobStatus.result[0].id, jobStatus.result[0].templatename, jobStatus.startTime, jobStatus.endTime else: print jobStatus.result, jobStatus.startTime, jobStatus.endTime