Return-Path: X-Original-To: apmail-cloudstack-commits-archive@www.apache.org Delivered-To: apmail-cloudstack-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id E58CD11AF1 for ; Mon, 28 Jul 2014 15:41:25 +0000 (UTC) Received: (qmail 58478 invoked by uid 500); 28 Jul 2014 15:41:18 -0000 Delivered-To: apmail-cloudstack-commits-archive@cloudstack.apache.org Received: (qmail 58328 invoked by uid 500); 28 Jul 2014 15:41:18 -0000 Mailing-List: contact commits-help@cloudstack.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@cloudstack.apache.org Delivered-To: mailing list commits@cloudstack.apache.org Received: (qmail 57992 invoked by uid 99); 28 Jul 2014 15:41:18 -0000 Received: from tyr.zones.apache.org (HELO tyr.zones.apache.org) (140.211.11.114) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 28 Jul 2014 15:41:18 +0000 Received: by tyr.zones.apache.org (Postfix, from userid 65534) id 4327D9B7FA6; Mon, 28 Jul 2014 15:41:18 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: dahn@apache.org To: commits@cloudstack.apache.org Date: Mon, 28 Jul 2014 15:41:25 -0000 Message-Id: <3cd468823789413ba01f1c685d81c01a@git.apache.org> In-Reply-To: References: X-Mailer: ASF-Git Admin Mailer Subject: [08/18] Marvin + test changes from master Signed-off-by: SrikanteswaraRao Talluri http://git-wip-us.apache.org/repos/asf/cloudstack/blob/798a6aa2/tools/marvin/marvin/cloudstackConnection.py ---------------------------------------------------------------------- diff --git a/tools/marvin/marvin/cloudstackConnection.py b/tools/marvin/marvin/cloudstackConnection.py index fb03e3b..d006002 100644 --- a/tools/marvin/marvin/cloudstackConnection.py +++ b/tools/marvin/marvin/cloudstackConnection.py @@ -21,21 +21,35 @@ import base64 import hmac import hashlib import time -import cloudstackException from cloudstackAPI import * import jsonHelper +from marvin.codes import ( + FAILED, + INVALID_RESPONSE, + INVALID_INPUT, + JOB_FAILED, + JOB_INPROGRESS, + JOB_CANCELLED, + JOB_SUCCEEDED +) from requests import ( ConnectionError, HTTPError, Timeout, RequestException - ) +) +from marvin.cloudstackException import GetDetailExceptionInfo -class cloudConnection(object): +class CSConnection(object): + + ''' + @Desc: Connection Class to make API\Command calls to the + CloudStack Management Server + Sends the GET\POST requests to CS based upon the + information provided and retrieves the parsed response. + ''' - """ Connections to make API calls to the cloudstack management server - """ def __init__(self, mgmtDet, asyncTimeout=3600, logger=None, path='client/api'): self.apiKey = mgmtDet.apiKey @@ -44,68 +58,93 @@ class cloudConnection(object): self.port = mgmtDet.port self.user = mgmtDet.user self.passwd = mgmtDet.passwd - self.certCAPath = mgmtDet.certCAPath - self.certPath = mgmtDet.certPath + self.certPath = () + if mgmtDet.certCAPath != "NA" and mgmtDet.certPath != "NA": + self.certPath = (mgmtDet.certCAPath, mgmtDet.certPath) self.logger = logger self.path = path self.retries = 5 + self.__lastError = '' self.mgtDetails = mgmtDet - self.protocol = "http" self.asyncTimeout = asyncTimeout self.auth = True if self.port == 8096 or \ (self.apiKey is None and self.securityKey is None): self.auth = False - if mgmtDet.useHttps == "True": - self.protocol = "https" - self.baseurl = "%s://%s:%d/%s"\ + self.protocol = "https" if mgmtDet.useHttps == "True" else "http" + self.httpsFlag = True if self.protocol == "https" else False + self.baseUrl = "%s://%s:%d/%s"\ % (self.protocol, self.mgtSvr, self.port, self.path) def __copy__(self): - return cloudConnection(self.mgtDetails, - self.asyncTimeout, - self.logger, - self.path) - - def poll(self, jobid, response): - """ - polls the completion of a given jobid - @param jobid: - @param response: - @return: - """ - cmd = queryAsyncJobResult.queryAsyncJobResultCmd() - cmd.jobid = jobid - timeout = self.asyncTimeout - - while timeout > 0: - asyncResonse = self.marvinRequest(cmd, response_type=response) + return CSConnection(self.mgtDetails, + self.asyncTimeout, + self.logger, + self.path) - if asyncResonse.jobstatus == 2: - raise cloudstackException.cloudstackAPIException( - "asyncquery", asyncResonse.jobresult) - elif asyncResonse.jobstatus == 1: - return asyncResonse - - time.sleep(5) - if self.logger is not None: - self.logger.debug("job: %s still processing," - "will timeout in %ds" % (jobid, timeout)) - timeout = timeout - 5 + def __poll(self, jobid, response_cmd): + ''' + @Name : __poll + @Desc: polls for the completion of a given jobid + @Input 1. jobid: Monitor the Jobid for CS + 2. response_cmd:response command for request cmd + @return: FAILED if jobid is cancelled,failed + Else return async_response + ''' + try: + cmd = queryAsyncJobResult.queryAsyncJobResultCmd() + cmd.jobid = jobid + timeout = self.asyncTimeout + start_time = time.time() + end_time = time.time() + async_response = FAILED + self.logger.debug("=== Jobid: %s Started ===" % (str(jobid))) + while timeout > 0: + async_response = self.\ + marvinRequest(cmd, response_type=response_cmd) + if async_response != FAILED: + job_status = async_response.jobstatus + if job_status in [JOB_FAILED, + JOB_CANCELLED, + JOB_SUCCEEDED]: + break + time.sleep(5) + timeout -= 5 + self.logger.debug("=== JobId:%s is Still Processing, " + "Will TimeOut in:%s ====" % (str(jobid), + str(timeout))) + end_time = time.time() + tot_time = int(start_time - end_time) + self.logger.debug( + "===Jobid:%s ; StartTime:%s ; EndTime:%s ; " + "TotalTime:%s===" % + (str(jobid), str(time.ctime(start_time)), + str(time.ctime(end_time)), str(tot_time))) + return async_response + except Exception as e: + self.__lastError = e + self.logger.exception("==== __poll: Exception Occurred :%s ====" % + str(self.__lastError)) + return FAILED - raise cloudstackException.cloudstackAPIException( - "asyncquery", "Async job timeout %s" % jobid) + def getLastError(self): + ''' + @Name : getLastError + @Desc : Returns the last error from marvinRequest + ''' + return self.__lastError - def sign(self, payload): + def __sign(self, payload): """ - signs a given request URL when the apiKey and secretKey are known - - @param payload: dict of GET params to be signed - @return: the signature of the payload + @Name : __sign + @Desc:signs a given request URL when the apiKey and + secretKey are known + @Input: payload: dictionary of params be signed + @Output: the signature of the payload """ params = zip(payload.keys(), payload.values()) params.sort(key=lambda k: str.lower(k[0])) - hashStr = "&".join( + hash_str = "&".join( ["=".join( [str.lower(r[0]), str.lower( @@ -114,168 +153,219 @@ class cloudConnection(object): ) for r in params] ) signature = base64.encodestring(hmac.new( - self.securityKey, hashStr, hashlib.sha1).digest()).strip() - self.logger.debug("Computed Signature by Marvin: %s" % signature) + self.securityKey, hash_str, hashlib.sha1).digest()).strip() return signature - def request(self, command, auth=True, payload={}, method='GET'): + def __sendPostReqToCS(self, url, payload): + ''' + @Name : __sendPostReqToCS + @Desc : Sends the POST Request to CS + @Input : url: URL to send post req + payload:Payload information as part of request + @Output: Returns response from POST output + else FAILED + ''' + try: + response = requests.post(url, + params=payload, + cert=self.certPath, + verify=self.httpsFlag) + return response + except Exception as e: + self.__lastError = e + self.logger.\ + exception("__sendPostReqToCS : Exception " + "Occurred: %s" % str(self.__lastError)) + return FAILED + + def __sendGetReqToCS(self, url, payload): + ''' + @Name : __sendGetReqToCS + @Desc : Sends the GET Request to CS + @Input : url: URL to send post req + payload:Payload information as part of request + @Output: Returns response from GET output + else FAILED + ''' + try: + response = requests.get(url, + params=payload, + cert=self.certPath, + verify=self.httpsFlag) + return response + except Exception as e: + self.__lastError = e + self.logger.exception("__sendGetReqToCS : Exception Occurred: %s" % + str(self.__lastError)) + return FAILED + + def __sendCmdToCS(self, command, auth=True, payload={}, method='GET'): """ - Makes requests using auth or over integration port - @param command: cloudstack API command name + @Name : __sendCmdToCS + @Desc : Makes requests to CS using the Inputs provided + @Input: command: cloudstack API command name eg: deployVirtualMachineCommand - @param auth: Authentication (apikey,secretKey) => True + auth: Authentication (apikey,secretKey) => True else False for integration.api.port - @param payload: request data composed as a dictionary - @param method: GET/POST via HTTP - @return: + payload: request data composed as a dictionary + method: GET/POST via HTTP + @output: FAILED or else response from CS """ - payload["command"] = command - payload["response"] = "json" - - if auth: - payload["apiKey"] = self.apiKey - signature = self.sign(payload) - payload["signature"] = signature - try: - #https_flag : Signifies whether to verify connection over \ - #http or https, \ - #initialized to False, will be set to true if user provided https - #connection - https_flag = False - cert_path = () - if self.protocol == "https": - https_flag = True - if self.certCAPath != "NA" and self.certPath != "NA": - cert_path = (self.certCAPath, self.certPath) + payload["command"] = command + payload["response"] = "json" - #Verify whether protocol is "http", then call the request over http - if self.protocol == "http": + if auth: + payload["apiKey"] = self.apiKey + payload["signature"] = self.__sign(payload) + + # Verify whether protocol is "http" or "https", then send the + # request + if self.protocol in ["http", "https"]: + self.logger.debug("Payload: %s" % str(payload)) if method == 'POST': - response = requests.post(self.baseurl, params=payload, - verify=https_flag) - else: - response = requests.get(self.baseurl, params=payload, - verify=https_flag) + self.logger.debug("=======Sending POST Cmd : %s=======" + % str(command)) + return self.__sendPostReqToCS(self.baseUrl, payload) + if method == "GET": + self.logger.debug("========Sending GET Cmd : %s=======" + % str(command)) + return self.__sendGetReqToCS(self.baseUrl, payload) else: - ''' - If protocol is https, then create the connection url with \ - user provided certificates \ - provided as part of cert - ''' - try: - if method == 'POST': - response = requests.post(self.baseurl, - params=payload, - cert=cert_path, - verify=https_flag) - else: - response = requests.get(self.baseurl, params=payload, - cert=cert_path, - verify=https_flag) - except Exception, e: - ''' - If an exception occurs with user provided CA certs, \ - then try with default certs, \ - we dont need to mention here the cert path - ''' - self.logger.debug("Creating CS connection over https \ - didnt worked with user provided certs \ - , so trying with no certs %s" % e) - if method == 'POST': - response = requests.post(self.baseurl, - params=payload, - verify=https_flag) - else: - response = requests.get(self.baseurl, - params=payload, - verify=https_flag) - except ConnectionError, c: - self.logger.debug("Connection refused. Reason: %s : %s" % - (self.baseurl, c)) - raise c - except HTTPError, h: - self.logger.debug("Http Error.Server returned error code: %s" % h) - raise h - except Timeout, t: - self.logger.debug("Connection timed out with %s" % t) - raise t - except RequestException, r: - self.logger.debug("RequestException from server %s" % r) - raise r - except Exception, e: - self.logger.debug("Error returned by server %s" % r) - raise e - else: - return response + self.logger.exception("__sendCmdToCS: Invalid Protocol") + return FAILED + except Exception as e: + self.logger.exception("__sendCmdToCS: Exception:%s" % + GetDetailExceptionInfo(e)) + return FAILED - def sanitizeCommand(self, cmd): + def __sanitizeCmd(self, cmd): """ - Removes None values, Validates all required params are present - @param cmd: Cmd object eg: createPhysicalNetwork - @return: + @Name : __sanitizeCmd + @Desc : Removes None values, Validates all required params are present + @Input: cmd: Cmd object eg: createPhysicalNetwork + @Output: Returns command name, asynchronous or not,request payload + FAILED for failed cases """ - requests = {} - required = [] - for attribute in dir(cmd): - if not attribute.startswith('__'): - if attribute == "isAsync": - isAsync = getattr(cmd, attribute) - elif attribute == "required": - required = getattr(cmd, attribute) - else: - requests[attribute] = getattr(cmd, attribute) - - cmdname = cmd.__class__.__name__.replace("Cmd", "") - for requiredPara in required: - if requests[requiredPara] is None: - raise cloudstackException.cloudstackAPIException( - cmdname, "%s is required" % requiredPara) - 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) + try: + cmd_name = '' + payload = {} + required = [] + isAsync = "false" + for attribute in dir(cmd): + if not attribute.startswith('__'): + if attribute == "isAsync": + isAsync = getattr(cmd, attribute) + elif attribute == "required": + required = getattr(cmd, attribute) else: - requests.pop(param) - i = 0 - for val in value: - for k, v in val.iteritems(): - requests["%s[%d].%s" % (param, i, k)] = v - i = i + 1 - return cmdname.strip(), isAsync, requests + payload[attribute] = getattr(cmd, attribute) + cmd_name = cmd.__class__.__name__.replace("Cmd", "") + for required_param in required: + if payload[required_param] is None: + self.logger.debug("CmdName: %s Parameter : %s is Required" + % (cmd_name, required_param)) + return FAILED + for param, value in payload.items(): + if value is None: + payload.pop(param) + elif isinstance(value, list): + if len(value) == 0: + payload.pop(param) + else: + if not isinstance(value[0], dict): + payload[param] = ",".join(value) + else: + payload.pop(param) + i = 0 + for val in value: + for k, v in val.iteritems(): + payload["%s[%d].%s" % (param, i, k)] = v + i += 1 + return cmd_name.strip(), isAsync, payload + except Exception as e: + self.logger.\ + exception("__sanitizeCmd: CmdName : " + "%s : Exception:%s" % (cmd_name, + GetDetailExceptionInfo(e))) + return FAILED + + def __parseAndGetResponse(self, cmd_response, response_cls, is_async): + ''' + @Name : __parseAndGetResponse + @Desc : Verifies the Response(from CS) and returns an + appropriate json parsed Response + @Input: cmd_response: Command Response from cs + response_cls : Mapping class for this Response + is_async: Whether the cmd is async or not. + @Output:Response output from CS + ''' + try: + ret = jsonHelper.getResultObj(cmd_response.json(), response_cls) + except TypeError: + ret = jsonHelper.getResultObj(cmd_response.json, response_cls) + + ''' + If the response is asynchronous, poll and return response + else return response as it is + ''' + if is_async == "false": + self.logger.debug("Response : %s" % str(ret)) + return ret + else: + response = self.__poll(ret.jobid, response_cls) + self.logger.debug("Response : %s" % str(response)) + return response.jobresult if response != FAILED else FAILED def marvinRequest(self, cmd, response_type=None, method='GET', data=''): """ - Requester for marvin command objects - @param cmd: marvin's command from cloudstackAPI - @param response_type: response type of the command in cmd - @param method: HTTP GET/POST, defaults to GET - @return: + @Name : marvinRequest + @Desc: Handles Marvin Requests + @Input cmd: marvin's command from cloudstackAPI + response_type: response type of the command in cmd + method: HTTP GET/POST, defaults to GET + @Output: Response received from CS + FAILED In case of Error\Exception """ - cmdname, isAsync, payload = self.sanitizeCommand(cmd) - self.logger.debug("sending %s request: %s %s" % (method, cmdname, - str(payload))) - response = self.request(cmdname, - self.auth, - payload=payload, - method=method) - if response is None: - return None - self.logger.debug("Request: %s Response: %s" % (response.url, - response.text)) try: - response = jsonHelper.getResultObj(response.json(), response_type) - except TypeError: - response = jsonHelper.getResultObj(response.json, response_type) + ''' + 1. Verify the Inputs Provided + ''' + if (cmd is None or cmd == '')or \ + (response_type is None or response_type == ''): + self.logger.exception("marvinRequest : Invalid Command Input") + return FAILED - if isAsync == "false": - return response - else: - asyncJobId = response.jobid - response = self.poll(asyncJobId, response_type) - return response.jobresult + ''' + 2. Sanitize the Command + ''' + sanitize_cmd_out = self.__sanitizeCmd(cmd) + + if sanitize_cmd_out == FAILED: + return FAILED + + cmd_name, is_async, payload = sanitize_cmd_out + ''' + 3. Send Command to CS + ''' + cmd_response = self.__sendCmdToCS(cmd_name, + self.auth, + payload=payload, + method=method) + if cmd_response == FAILED: + raise self.__lastError + + ''' + 4. Check if the Command Response received above is valid or Not. + If not return Invalid Response + ''' + ret = self.__parseAndGetResponse(cmd_response, + response_type, + is_async) + if ret == FAILED: + raise self.__lastError + return ret + except Exception as e: + self.logger.exception("marvinRequest : CmdName: %s Exception: %s" % + (str(cmd), GetDetailExceptionInfo(e))) + return FAILED http://git-wip-us.apache.org/repos/asf/cloudstack/blob/798a6aa2/tools/marvin/marvin/cloudstackException.py ---------------------------------------------------------------------- diff --git a/tools/marvin/marvin/cloudstackException.py b/tools/marvin/marvin/cloudstackException.py index 6200003..c2eb57a 100644 --- a/tools/marvin/marvin/cloudstackException.py +++ b/tools/marvin/marvin/cloudstackException.py @@ -15,8 +15,13 @@ # specific language governing permissions and limitations # under the License. +import sys +import traceback +from marvin.codes import (INVALID_INPUT, EXCEPTION_OCCURRED) + + +class CloudstackAPIException(Exception): -class cloudstackAPIException(Exception): def __init__(self, cmd="", result=""): self.errorMsg = "Execute cmd: %s failed, due to: %s" % (cmd, result) @@ -25,6 +30,7 @@ class cloudstackAPIException(Exception): class InvalidParameterException(Exception): + def __init__(self, msg=''): self.errorMsg = msg @@ -33,6 +39,7 @@ class InvalidParameterException(Exception): class dbException(Exception): + def __init__(self, msg=''): self.errorMsg = msg @@ -41,8 +48,18 @@ class dbException(Exception): class internalError(Exception): + def __init__(self, msg=''): self.errorMsg = msg def __str__(self): return self.errorMsg + + +def GetDetailExceptionInfo(e): + if e is not None: + exc_type, exc_value, exc_traceback = sys.exc_info() + return str(repr(traceback.format_exception( + exc_type, exc_value, exc_traceback))) + else: + return EXCEPTION_OCCURRED http://git-wip-us.apache.org/repos/asf/cloudstack/blob/798a6aa2/tools/marvin/marvin/cloudstackTestCase.py ---------------------------------------------------------------------- diff --git a/tools/marvin/marvin/cloudstackTestCase.py b/tools/marvin/marvin/cloudstackTestCase.py index 6456bb1..5cb4a10 100644 --- a/tools/marvin/marvin/cloudstackTestCase.py +++ b/tools/marvin/marvin/cloudstackTestCase.py @@ -16,7 +16,7 @@ # under the License. import unittest -from marvin.integration.lib.utils import verifyElementInList +from marvin.lib.utils import verifyElementInList from marvin.codes import PASS @@ -37,7 +37,7 @@ def user(Name, DomainName, AcctType): class cloudstackTestCase(unittest.case.TestCase): clstestclient = None - def assertElementInList(inp, toverify, responsevar=None, pos=0, + def assertElementInList(inp, toverify, responsevar=None, pos=0, assertmsg="TC Failed for reason"): ''' @Name: assertElementInList @@ -46,7 +46,7 @@ class cloudstackTestCase(unittest.case.TestCase): Takes one additional argument of what message to assert with when failed ''' - out = verifyElementInList(inp, toverify, responsevar, pos) + out = verifyElementInList(inp, toverify, responsevar, pos) unittest.TestCase.assertEquals(out[0], PASS, "msg:%s" % out[1]) @classmethod http://git-wip-us.apache.org/repos/asf/cloudstack/blob/798a6aa2/tools/marvin/marvin/cloudstackTestClient.py ---------------------------------------------------------------------- diff --git a/tools/marvin/marvin/cloudstackTestClient.py b/tools/marvin/marvin/cloudstackTestClient.py index 4ac510b..53d48ab 100644 --- a/tools/marvin/marvin/cloudstackTestClient.py +++ b/tools/marvin/marvin/cloudstackTestClient.py @@ -15,201 +15,433 @@ # specific language governing permissions and limitations # under the License. -import cloudstackConnection -import asyncJobMgr -import dbConnection -from cloudstackAPI import * -import random -import string -import hashlib -from configGenerator import ConfigManager -from marvin.integration.lib.utils import random_gen - -''' -@Desc : CloudStackTestClient is encapsulated class for getting various \ - clients viz., apiclient,dbconnection etc -@Input : mgmtDetails : Management Server Details - dbSvrDetails: Database Server details of Management \ +from marvin.cloudstackConnection import CSConnection +from marvin.asyncJobMgr import asyncJobMgr +from marvin.dbConnection import DbConnection +from marvin.cloudstackAPI import * +from marvin.codes import (FAILED, PASS, ADMIN, DOMAIN_ADMIN, + USER, SUCCESS, XEN_SERVER) +from marvin.configGenerator import ConfigManager +from marvin.cloudstackException import GetDetailExceptionInfo +from marvin.lib.utils import (random_gen, validateList) +from marvin.cloudstackAPI.cloudstackAPIClient import CloudStackAPIClient + + +class CSTestClient(object): + + ''' + @Desc : CloudStackTestClient is encapsulated entity for creating and + getting various clients viz., apiclient, + user api client, dbconnection, test Data parsed + information etc + @Input : + mgmt_details : Management Server Details + dbsvr_details: Database Server details of Management \ Server. Retrieved from configuration file. - asyncTimeout : - defaultWorkerThreads : - logger : provides logging facilities for this library -''' - - -class cloudstackTestClient(object): - def __init__(self, mgmtDetails, - dbSvrDetails, asyncTimeout=3600, - defaultWorkerThreads=10, - logger=None): - self.mgmtDetails = mgmtDetails - self.connection = \ - cloudstackConnection.cloudConnection(self.mgmtDetails, - asyncTimeout, - logger) - self.apiClient =\ - cloudstackAPIClient.CloudStackAPIClient(self.connection) - self.dbConnection = None - if dbSvrDetails is not None: - self.createDbConnection(dbSvrDetails.dbSvr, dbSvrDetails.port, - dbSvrDetails.user, - dbSvrDetails.passwd, dbSvrDetails.db) - ''' - Provides the Configuration Object to users through getConfigParser - The purpose of this object is to parse the config - and provide dictionary of the config so users can - use that configuration.Users can later call getConfig - on this object and it will return the default parsed - config dictionary from default configuration file, - they can overwrite it with providing their own - configuration file as well. - ''' - self.configObj = ConfigManager() - self.asyncJobMgr = None - self.id = None - self.defaultWorkerThreads = defaultWorkerThreads + async_timeout : Timeout for Async queries + default_worker_threads : Number of worker threads + logger : provides logging facilities for this library + zone : The zone on which test suites using this test client will run + ''' + + def __init__(self, mgmt_details, + dbsvr_details, + async_timeout=3600, + logger=None, + test_data_filepath=None, + zone=None, + hypervisor_type=None): + self.__mgmtDetails = mgmt_details + self.__dbSvrDetails = dbsvr_details + self.__csConnection = None + self.__dbConnection = None + self.__testClient = None + self.__asyncTimeOut = async_timeout + self.__logger = logger + self.__apiClient = None + self.__userApiClient = None + self.__asyncJobMgr = None + self.__id = None + self.__hypervisor = hypervisor_type + self.__testDataFilePath = test_data_filepath + self.__parsedTestDataConfig = None + self.__zone = zone + self.__setHypervisorInfo() @property def identifier(self): - return self.id + return self.__id @identifier.setter def identifier(self, id): - self.id = id + self.__id = id + + def getParsedTestDataConfig(self): + ''' + @Name : getParsedTestDataConfig + @Desc : Provides the TestData Config needed for + Tests are to Run + @Output : Returns the Parsed Test Data Dictionary + ''' + return self.__parsedTestDataConfig + + def getZoneForTests(self): + ''' + @Name : getZoneForTests + @Desc : Provides the Zone against which Tests are to run + If zone name provided to marvin plugin is none + it will get it from Test Data Config File + Even, if it is not available, return None + @Output : Returns the Zone Name + ''' + return self.__zone + + def getHypervisorInfo(self): + ''' + @Name : getHypervisorInfo + @Desc : Provides the hypervisor Information to test users + @Output : Return Hypervisor Information + ''' + return self.__hypervisor + + def __setHypervisorInfo(self): + ''' + @Name : __setHypervisorInfo + @Desc: Set the HyperVisor details; + default to XenServer + ''' + try: + if not self.__hypervisor: + self.__hypervisor = XEN_SERVER + return SUCCESS + except Exception as e: + print "\n Exception Occurred Under __setHypervisorInfo " \ + "%s" % GetDetailExceptionInfo(e) + return FAILED + + def __createApiClient(self): + try: + ''' + Step1 : Create a CS Connection Object + ''' + self.__csConnection = CSConnection(self.__mgmtDetails, + self.__asyncTimeOut, + self.__logger) - def createDbConnection(self, host="localhost", port=3306, user='cloud', - passwd='cloud', db='cloud'): - self.dbConnection = dbConnection.dbConnection(host, port, user, - passwd, db) + ''' + Step2 : Create API Client with earlier created connection object + ''' + self.__apiClient = CloudStackAPIClient(self.__csConnection) + + ''' + Step3: If API Key is not provided as part of Management Details, + then verify and register + ''' + if self.__mgmtDetails.apiKey is None: + list_user = listUsers.listUsersCmd() + list_user.account = "admin" + list_user_res = self.__apiClient.listUsers(list_user) + if list_user_res is None or\ + (validateList(list_user_res)[0] != PASS): + self.__logger.error("__createApiClient: API " + "Client Creation Failed") + return FAILED + user_id = list_user_res[0].id + api_key = list_user_res[0].apikey + security_key = list_user_res[0].secretkey + if api_key is None: + ret = self.__getKeys(user_id) + if ret != FAILED: + self.__mgmtDetails.port = 8080 + self.__mgmtDetails.apiKey = ret[0] + self.__mgmtDetails.securityKey = ret[1] + else: + self.__logger.error("__createApiClient: API Client " + "Creation Failed while " + "Registering User") + return FAILED + else: + self.__mgmtDetails.port = 8080 + self.__mgmtDetails.apiKey = api_key + self.__mgmtDetails.securityKey = security_key + ''' + Now Create the Connection objects and Api Client using + new details + ''' + self.__csConnection = CSConnection(self.__mgmtDetails, + self.__asyncTimeOut, + self.__logger) + self.__apiClient = CloudStackAPIClient(self.__csConnection) + return SUCCESS + except Exception as e: + self.__logger.exception(" Exception Occurred Under " + "__createApiClient: %s" % + GetDetailExceptionInfo(e)) + return FAILED + + def __createDbConnection(self): + ''' + @Name : ___createDbConnection + @Desc : Creates the CloudStack DB Connection + ''' + host = "localhost" if self.__dbSvrDetails.dbSvr is None \ + else self.__dbSvrDetails.dbSvr + port = 3306 if self.__dbSvrDetails.port is None \ + else self.__dbSvrDetails.port + user = "cloud" if self.__dbSvrDetails.user is None \ + else self.__dbSvrDetails.user + passwd = 'cloud' if self.__dbSvrDetails.passd is None \ + else self.__dbSvrDetails.passd + db = 'cloud' if self.__dbSvrDetails.db is None \ + else self.__dbSvrDetails.db + self.__dbConnection = DbConnection(host, port, user, passwd, db) + + def __getKeys(self, userid): + ''' + @Name : ___getKeys + @Desc : Retrieves the API and Secret Key for the provided Userid + @Input: userid: Userid to register + @Output: FAILED or tuple with apikey and secretkey + ''' + try: + register_user = registerUserKeys.registerUserKeysCmd() + register_user.id = userid + register_user_res = \ + self.__apiClient.registerUserKeys(register_user) + if not register_user_res: + return FAILED + return (register_user_res.apikey, register_user_res.secretkey) + except Exception as e: + self.__logger.exception("Exception Occurred Under __geKeys : " + "%s" % GetDetailExceptionInfo(e)) + return FAILED + + def createTestClient(self): + ''' + @Name : createTestClient + @Desc : Creates the Test Client. + The test Client is used by test suites + Here we create ParsedTestData Config. + Creates a DB Connection. + Creates an API Client + @Output : FAILED In case of an issue\Failure + SUCCESS in case of Success of this function + ''' + try: + ''' + 1. Create Config Object + Provides the Configuration Object to test suites through + getConfigParser. The purpose of this config object is to + parse the default config and provide dictionary of the + config so users can use that configuration. + Users can later call getConfig on this object and it will + return the default parsed config dictionary from default + configuration file. They can overwrite it with + providing their own configuration file as well. + ''' + ''' + 1. Check Config,Zone,Hypervisor Information + ''' + self.__configObj = ConfigManager(self.__testDataFilePath) + + if not self.__configObj or not self.__hypervisor: + self.__logger.error("createTestClient : " + "Either Hypervisor is None or " + "Not able to create " + "ConfigManager Object") + return FAILED + + self.__parsedTestDataConfig = self.__configObj.getConfig() + self.__logger.debug("Parsing Test data successful") + + ''' + 2. Create DB Connection + ''' + self.__createDbConnection() + ''' + 3. Creates API Client + ''' + ret = self.__createApiClient() + if ret == FAILED: + self.__logger.\ + error("==== Test Client Creation Failed ====") + else: + self.__logger.\ + debug("==== Test Client Creation Successful ====") + return ret + except Exception as e: + self.__logger.exception("Exception Occurred " + "Under createTestClient " + ": %s" % GetDetailExceptionInfo(e)) + return FAILED def isAdminContext(self): """ - A user is a regular user if he fails to listDomains; + @Name : isAdminContext + @Desc:A user is a regular user if he fails to listDomains; if he is a domain-admin, he can list only domains that are non-ROOT; if he is an admin, he can list the ROOT domain successfully """ try: listdom = listDomains.listDomainsCmd() listdom.name = 'ROOT' - listdomres = self.apiClient.listDomains(listdom) - rootdom = listdomres[0].name - if rootdom == 'ROOT': - return 1 # admin - else: - return 2 # domain-admin + listdomres = self.__apiClient.listDomains(listdom) + if listdomres != FAILED: + rootdom = listdomres[0].name + if rootdom == 'ROOT': + return ADMIN + else: + return DOMAIN_ADMIN + return USER except: - return 0 # user + return USER - def createUserApiClient(self, UserName, DomainName, acctType=0): - if not self.isAdminContext(): - return self.apiClient - - listDomain = listDomains.listDomainsCmd() - listDomain.listall = True - listDomain.name = DomainName - try: - domains = self.apiClient.listDomains(listDomain) - domId = domains[0].id - except: - cdomain = createDomain.createDomainCmd() - cdomain.name = DomainName - domain = self.apiClient.createDomain(cdomain) - domId = domain.id - - cmd = listAccounts.listAccountsCmd() - cmd.name = UserName - cmd.domainid = domId + def __createUserApiClient(self, UserName, DomainName, acctType=0): + ''' + @Name : ___createUserApiClient + @Desc : Creates a User API Client with given + UserName\DomainName Parameters + @Input: UserName: Username to be created in cloudstack + DomainName: Domain under which the above account be created + accType: Type of Account EX: Root,Non Root etc + @Output: Return the API client for the user + ''' try: - accounts = self.apiClient.listAccounts(cmd) - acctId = accounts[0].id - except: - createAcctCmd = createAccount.createAccountCmd() - createAcctCmd.accounttype = acctType - createAcctCmd.domainid = domId - createAcctCmd.email = "test-" + random_gen()\ - + "@cloudstack.org" - createAcctCmd.firstname = UserName - createAcctCmd.lastname = UserName - createAcctCmd.password = 'password' - createAcctCmd.username = UserName - acct = self.apiClient.createAccount(createAcctCmd) - acctId = acct.id - - listuser = listUsers.listUsersCmd() - listuser.username = UserName - - listuserRes = self.apiClient.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.apiClient.registerUserKeys(registerUser) - apiKey = registerUserRes.apikey - securityKey = registerUserRes.secretkey - - mgtDetails = self.mgmtDetails - mgtDetails.apiKey = apiKey - mgtDetails.securityKey = securityKey - - newUserConnection =\ - cloudstackConnection.cloudConnection(mgtDetails, - self.connection.asyncTimeout, - self.connection.logger) - self.userApiClient =\ - cloudstackAPIClient.CloudStackAPIClient(newUserConnection) - self.userApiClient.connection = newUserConnection - self.userApiClient.hypervisor = self.apiClient.hypervisor - return self.userApiClient + if not self.isAdminContext(): + return self.__apiClient + + listDomain = listDomains.listDomainsCmd() + listDomain.listall = True + listDomain.name = DomainName + try: + domains = self.__apiClient.listDomains(listDomain) + domId = domains[0].id + except: + cdomain = createDomain.createDomainCmd() + cdomain.name = DomainName + domain = self.__apiClient.createDomain(cdomain) + domId = domain.id + + cmd = listAccounts.listAccountsCmd() + cmd.name = UserName + cmd.domainid = domId + try: + accounts = self.__apiClient.listAccounts(cmd) + acctId = accounts[0].id + except: + createAcctCmd = createAccount.createAccountCmd() + createAcctCmd.accounttype = acctType + createAcctCmd.domainid = domId + createAcctCmd.email = "test-" + random_gen()\ + + "@cloudstack.org" + createAcctCmd.firstname = UserName + createAcctCmd.lastname = UserName + createAcctCmd.password = 'password' + createAcctCmd.username = UserName + acct = self.__apiClient.createAccount(createAcctCmd) + acctId = acct.id + + listuser = listUsers.listUsersCmd() + listuser.username = UserName + + listuserRes = self.__apiClient.listUsers(listuser) + userId = listuserRes[0].id + apiKey = listuserRes[0].apikey + securityKey = listuserRes[0].secretkey + + if apiKey is None: + ret = self.__getKeys(userId) + if ret != FAILED: + mgtDetails = self.__mgmtDetails + mgtDetails.apiKey = ret[0] + mgtDetails.securityKey = ret[1] + else: + self.__logger.error("__createUserApiClient: " + "User API Client Creation." + " While Registering User Failed") + return FAILED + else: + mgtDetails = self.__mgmtDetails + mgtDetails.apiKey = apiKey + mgtDetails.securityKey = securityKey + + newUserConnection =\ + CSConnection(mgtDetails, + self.__csConnection.asyncTimeout, + self.__csConnection.logger) + self.__userApiClient = CloudStackAPIClient(newUserConnection) + self.__userApiClient.connection = newUserConnection + self.__userApiClient.hypervisor = self.__hypervisor + return self.__userApiClient + except Exception as e: + self.__logger.exception("Exception Occurred " + "Under getUserApiClient : %s" % + GetDetailExceptionInfo(e)) + return FAILED def close(self): - if self.connection is not None: - self.connection.close() + if self.__csConnection is not None: + self.__csConnection.close() def getDbConnection(self): - return self.dbConnection + ''' + @Name : getDbConnection + @Desc : Retrieves the DB Connection Handle + ''' + return self.__dbConnection def getConfigParser(self): - return self.configObj + ''' + @Name : getConfigParser + @Desc : Provides the ConfigManager Interface to TestClients + ''' + return self.__configObj def getApiClient(self): - self.apiClient.id = self.identifier - return self.apiClient + if self.__apiClient: + self.__apiClient.id = self.identifier + return self.__apiClient + return None - def getUserApiClient(self, account, domain, type=0): + def getUserApiClient(self, UserName=None, DomainName=None, type=0): """ - 0 - user - 1 - admin - 2 - domain admin + @Name : getUserApiClient + @Desc : Provides the User API Client to test Users + 0 - user ; 1 - admin;2 - domain admin + @OutPut : FAILED In case of an issue + else User API Client """ - self.createUserApiClient(account, domain, type) - if hasattr(self, "userApiClient"): - return self.userApiClient - return None + if UserName is None or DomainName is None: + return FAILED + return self.__createUserApiClient(UserName, DomainName, type) def submitCmdsAndWait(self, cmds, workers=1): - '''FixME, httplib has issue if more than one thread submitted''' - if self.asyncJobMgr is None: - self.asyncJobMgr = asyncJobMgr.asyncJobMgr(self.apiClient, - self.dbConnection) - return self.asyncJobMgr.submitCmdsAndWait(cmds, workers) + ''' + @Desc : FixME, httplib has issue if more than one thread submitted + ''' + if self.__asyncJobMgr is None: + self.__asyncJobMgr = asyncJobMgr(self.__apiClient, + self.__dbConnection) + return self.__asyncJobMgr.submitCmdsAndWait(cmds, workers) def submitJob(self, job, ntimes=1, nums_threads=10, interval=1): ''' - submit one job and execute the same job ntimes, with nums_threads - of threads + @Desc : submit one job and execute the same job + ntimes, with nums_threads of threads ''' - if self.asyncJobMgr is None: - self.asyncJobMgr = asyncJobMgr.asyncJobMgr(self.apiClient, - self.dbConnection) - self.asyncJobMgr.submitJobExecuteNtimes(job, ntimes, nums_threads, - interval) + if self.__asyncJobMgr is None: + self.__asyncJobMgr = asyncJobMgr(self.__apiClient, + self.__dbConnection) + self.__asyncJobMgr.submitJobExecuteNtimes(job, ntimes, + nums_threads, + interval) def submitJobs(self, jobs, nums_threads=10, interval=1): - '''submit n jobs, execute them with nums_threads of threads''' - if self.asyncJobMgr is None: - self.asyncJobMgr = asyncJobMgr.asyncJobMgr(self.apiClient, - self.dbConnection) - self.asyncJobMgr.submitJobs(jobs, nums_threads, interval) + ''' + @Desc :submit n jobs, execute them with nums_threads + of threads + ''' + if self.__asyncJobMgr is None: + self.__asyncJobMgr = asyncJobMgr(self.__apiClient, + self.__dbConnection) + self.__asyncJobMgr.submitJobs(jobs, nums_threads, interval) http://git-wip-us.apache.org/repos/asf/cloudstack/blob/798a6aa2/tools/marvin/marvin/codegenerator.py ---------------------------------------------------------------------- diff --git a/tools/marvin/marvin/codegenerator.py b/tools/marvin/marvin/codegenerator.py index e0f056f..1e02ddf 100644 --- a/tools/marvin/marvin/codegenerator.py +++ b/tools/marvin/marvin/codegenerator.py @@ -25,6 +25,7 @@ import urllib2 class cmdParameterProperty(object): + def __init__(self): self.name = None self.required = False @@ -34,6 +35,7 @@ class cmdParameterProperty(object): class cloudStackCmd(object): + def __init__(self): self.name = "" self.desc = "" @@ -42,7 +44,8 @@ class cloudStackCmd(object): self.response = [] -class codeGenerator(object): +class CodeGenerator(object): + """ Apache CloudStack- marvin python classes can be generated from the json returned by API discovery or from the xml spec of commands generated by @@ -208,12 +211,12 @@ class codeGenerator(object): body += self.space + '@property' + self.newline body += self.space + 'def id(self):' + self.newline - body += self.space*2 + 'return self._id' + self.newline + body += self.space * 2 + 'return self._id' + self.newline body += self.newline body += self.space + '@id.setter' + self.newline body += self.space + 'def id(self, identifier):' + self.newline - body += self.space*2 + 'self._id = identifier' + self.newline + body += self.space * 2 + 'self._id = identifier' + self.newline body += self.newline for cmdName in self.cmdsName: @@ -340,7 +343,7 @@ class codeGenerator(object): paramProperty.desc = response['description'] if 'type' in response: if response['type'] in ['list', 'map', 'set']: - #Here list becomes a subproperty + # Here list becomes a subproperty if 'response' in response: for innerResponse in response['response']: subProperty =\ @@ -394,7 +397,7 @@ class codeGenerator(object): csCmd.request.append(paramProperty) for response in cmd['response']: - #FIXME: ExtractImage related APIs return empty dicts in response + # FIXME: ExtractImage related APIs return empty dicts in response if len(response) > 0: paramProperty = self.constructResponseFromJSON(response) csCmd.response.append(paramProperty) @@ -454,7 +457,7 @@ if __name__ == "__main__": print parser.print_help() exit(1) - cg = codeGenerator(folder) + cg = CodeGenerator(folder) if options.spec is not None: cg.generateCodeFromXML(apiSpecFile) elif options.endpoint is not None: http://git-wip-us.apache.org/repos/asf/cloudstack/blob/798a6aa2/tools/marvin/marvin/codes.py ---------------------------------------------------------------------- diff --git a/tools/marvin/marvin/codes.py b/tools/marvin/marvin/codes.py index 92d6cf9..28e907c 100644 --- a/tools/marvin/marvin/codes.py +++ b/tools/marvin/marvin/codes.py @@ -47,13 +47,32 @@ YES = "yes" FAILED = "FAILED" UNKNOWN_ERROR = "Unknown Error" EXCEPTION = "EXCEPTION" +INVALID_RESPONSE = "Invalid Response" +''' +Async Job Related Codes +''' +JOB_INPROGRESS = 0 +JOB_SUCCEEDED = 1 +JOB_FAILED = 2 +JOB_CANCELLED = 3 +''' +User Related Codes +''' BASIC_ZONE = "basic" ISOLATED_NETWORK = "ISOLATED" SHARED_NETWORK = "SHARED" VPC_NETWORK = "VPC" -ERROR_NO_HOST_FOR_MIGRATION = "Could not find suitable host for migration, please ensure setup has required no. of hosts" +ERROR_NO_HOST_FOR_MIGRATION = \ + "Could not find suitable host for migration, " \ + "please ensure setup has required no. of hosts" NAT_RULE = "nat rule" STATIC_NAT_RULE = "static nat rule" UNKNOWN = "UNKNOWN" FAULT = "FAULT" MASTER = "MASTER" +ADMIN = 1 +DOMAIN_ADMIN = 2 +USER = 0 +XEN_SERVER = "XenServer" +ADMIN_ACCOUNT='ADMIN_ACCOUNT' +USER_ACCOUNT='USER_ACCOUNT' http://git-wip-us.apache.org/repos/asf/cloudstack/blob/798a6aa2/tools/marvin/marvin/config/__init__.py ---------------------------------------------------------------------- diff --git a/tools/marvin/marvin/config/__init__.py b/tools/marvin/marvin/config/__init__.py new file mode 100644 index 0000000..13a8339 --- /dev/null +++ b/tools/marvin/marvin/config/__init__.py @@ -0,0 +1,16 @@ +# 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. http://git-wip-us.apache.org/repos/asf/cloudstack/blob/798a6aa2/tools/marvin/marvin/config/config.cfg ---------------------------------------------------------------------- diff --git a/tools/marvin/marvin/config/config.cfg b/tools/marvin/marvin/config/config.cfg index a278068..a4bbe9d 100644 --- a/tools/marvin/marvin/config/config.cfg +++ b/tools/marvin/marvin/config/config.cfg @@ -24,7 +24,7 @@ } , "project": - { + { "name": "Project", "displaytext": "Test project" }, @@ -35,6 +35,15 @@ "username": "test-account", "password": "password" }, + "user": { + "email": "user@test.com", + "firstname": "User", + "lastname": "User", + "username": "User", + # Random characters are appended for unique + # username + "password": "fr3sca", + }, "service_offering": { "name": "Tiny Instance", "displaytext": "Tiny Instance", @@ -74,6 +83,18 @@ "publicport": 22, "protocol": "TCP" }, + "template": { + "displaytext": "Public Template", + "name": "Public template", + "ostype": 'CentOS 5.3 (64-bit)', + "url": "", + "hypervisor": '', + "format": '', + "isfeatured": True, + "ispublic": True, + "isextractable": True, + "templatefilter": "self" + }, "shared_network": { "name": "Test Shared Network", "displaytext": "Test Shared Network", @@ -126,17 +147,28 @@ "name": "SharedNwOffering", "displaytext": "SharedNwOffering", "guestiptype": "Shared", - "supportedservices": "Dhcp,Dns,UserData", + "supportedservices": "Dhcp,Dns,SourceNat,PortForwarding,Vpn,Firewall,Lb,UserData,StaticNat", "specifyVlan" : "False", "specifyIpRanges" : "False", "traffictype": "GUEST", "serviceProviderList" : { "Dhcp": "VirtualRouter", "Dns": "VirtualRouter", - "UserData": "VirtualRouter" + "SourceNat": "VirtualRouter", + "PortForwarding": "VirtualRouter", + "Vpn": "VirtualRouter", + "Firewall": "VirtualRouter", + "Lb": "VirtualRouter", + "UserData": "VirtualRouter", + "StaticNat": "VirtualRouter" } }, "security_group" : { "name": "custom_Sec_Grp" }, + "natrule": { + "publicport": 22, + "privateport": 22, + "protocol": 'TCP', + }, "ingress_rule": { "protocol": "TCP", "startport": "22", http://git-wip-us.apache.org/repos/asf/cloudstack/blob/798a6aa2/tools/marvin/marvin/config/test_data.cfg ---------------------------------------------------------------------- diff --git a/tools/marvin/marvin/config/test_data.cfg b/tools/marvin/marvin/config/test_data.cfg new file mode 100644 index 0000000..5a3d8aa --- /dev/null +++ b/tools/marvin/marvin/config/test_data.cfg @@ -0,0 +1,427 @@ +# 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. + +{ + "region": { + "regionid": "2", + "regionname": "Region2", + "regionendpoint": "http://region2:8080/client" + }, + "zone": "NA", + + "domain": { "name": "domain" }, + + "project": { + "name": "Project", + "displaytext": "Test project" + }, + "account": { + "email": "test-account@test.com", + "firstname": "test", + "lastname": "test", + "username": "test-account", + "password": "password" + }, + "small": { + "displayname": "testserver", + "username": "root", + "password": "password", + "ssh_port": 22, + "hypervisor": "XenServer", + "privateport": 22, + "publicport": 22, + "protocol": 'TCP', + }, + "medium": { + "displayname": "testserver", + "username": "root", + "password": "password", + "ssh_port": 22, + "hypervisor": 'XenServer', + "privateport": 22, + "publicport": 22, + "protocol": 'TCP', + }, + "service_offerings": { + "name": "Tiny Instance", + "displaytext": "Tiny Instance", + "cpunumber": 1, + "cpuspeed": 100, + "memory": 128, + + "tiny": { + "name": "Tiny Instance", + "displaytext": "Tiny Instance", + "cpunumber": 1, + "cpuspeed": 100, + "memory": 128, + }, + "small": { + "name": "Small Instance", + "displaytext": "Small Instance", + "cpunumber": 1, + "cpuspeed": 100, + "memory": 256 + }, + "medium": { + "name": "Medium Instance", + "displaytext": "Medium Instance", + "cpunumber": 1, + "cpuspeed": 100, + "memory": 256, + }, + "big": { + "name": "BigInstance", + "displaytext": "BigInstance", + "cpunumber": 1, + "cpuspeed": 100, + "memory": 512, + } + }, + "disk_offering": { + "name": "Disk offering", + "displaytext": "Disk offering", + "disksize": 1 + }, + 'resized_disk_offering': { + "displaytext": "Resized", + "name": "Resized", + "disksize": 3 + }, + "network": { + "name": "Test Network", + "displaytext": "Test Network", + "acltype": "Account", + }, + "network2": { + "name": "Test Network Shared", + "displaytext": "Test Network Shared", + "vlan" :1201, + "gateway" :"172.16.15.1", + "netmask" :"255.255.255.0", + "startip" :"172.16.15.21", + "endip" :"172.16.15.41", + "acltype": "Account", + }, + "network_offering": { + "name": 'Test Network offering', + "displaytext": 'Test Network offering', + "guestiptype": 'Isolated', + "supportedservices": 'Dhcp,Dns,SourceNat,PortForwarding', + "traffictype": 'GUEST', + "availability": 'Optional', + "serviceProviderList" : { + "Dhcp": 'VirtualRouter', + "Dns": 'VirtualRouter', + "SourceNat": 'VirtualRouter', + "PortForwarding": 'VirtualRouter', + }, + }, + "isolated_network_offering": { + "name": "Network offering-DA services", + "displaytext": "Network offering-DA services", + "guestiptype": "Isolated", + "supportedservices": "Dhcp,Dns,SourceNat,PortForwarding,Vpn,Firewall,Lb,UserData,StaticNat", + "traffictype": "GUEST", + "availability": "Optional'", + "serviceProviderList": { + "Dhcp": "VirtualRouter", + "Dns": "VirtualRouter", + "SourceNat": "VirtualRouter", + "PortForwarding": "VirtualRouter", + "Vpn": "VirtualRouter", + "Firewall": "VirtualRouter", + "Lb": "VirtualRouter", + "UserData": "VirtualRouter", + "StaticNat": "VirtualRouter" + } + }, + "isolated_network": { + "name": "Isolated Network", + "displaytext": "Isolated Network" + }, + "virtual_machine": { + "displayname": "Test VM", + "username": "root", + "password": "password", + "ssh_port": 22, + "privateport": 22, + "publicport": 22, + "protocol": "TCP", + "affinity": { + "name": "webvms", + "type": "host anti-affinity", + }, + }, + "server_without_disk": { + "displayname": "Test VM-No Disk", + "username": "root", + "password": "password", + "ssh_port": 22, + "hypervisor": 'XenServer', + "privateport": 22, + "publicport": 22, + "protocol": 'TCP', + }, + "shared_network": { + "name": "MySharedNetwork - Test", + "displaytext": "MySharedNetwork", + "vlan" : "", + "gateway" :"", + "netmask" :"", + "startip" :"", + "endip" :"", + "acltype" : "Domain", + "scope":"all" + }, + "shared_network_offering_sg": { + "name": "MySharedOffering-sg", + "displaytext": "MySharedOffering-sg", + "guestiptype": "Shared", + "supportedservices": "Dhcp,Dns,UserData,SecurityGroup", + "specifyVlan" : "False", + "specifyIpRanges" : "False", + "traffictype": "GUEST", + "serviceProviderList" : { + "Dhcp": "VirtualRouter", + "Dns": "VirtualRouter", + "UserData": "VirtualRouter", + "SecurityGroup": "SecurityGroupProvider" + } + }, + "shared_network_sg": { + "name": "Shared-Network-SG-Test", + "displaytext": "Shared-Network_SG-Test", + "networkofferingid":"1", + "vlan" : "", + "gateway" :"", + "netmask" :"255.255.255.0", + "startip" :"", + "endip" :"", + "acltype" : "Domain", + "scope":"all" + }, + "vpc_offering": { + "name": "VPC off", + "displaytext": "VPC off", + "supportedservices": "Dhcp,Dns,SourceNat,PortForwarding,Vpn,Lb,UserData,StaticNat,NetworkACL" + }, + "vpc": { + "name": "TestVPC", + "displaytext": "TestVPC", + "cidr": "10.0.0.1/24" + }, + "clusters": { + 0: { + "clustername": "Xen Cluster", + "clustertype": "CloudManaged", + "hypervisor": "XenServer", + }, + 1: { + "clustername": "KVM Cluster", + "clustertype": "CloudManaged", + "hypervisor": "KVM", + }, + 2: { + "hypervisor": 'VMware', + "clustertype": 'ExternalManaged', + "username": 'administrator', + "password": 'fr3sca', + "url": 'http://192.168.100.17/CloudStack-Clogeny-Pune/Pune-1', + "clustername": 'VMWare Cluster', + }, + }, + "hosts": { + "xenserver": { + "hypervisor": 'XenServer', + "clustertype": 'CloudManaged', + "url": 'http://192.168.100.211', + "username": "root", + "password": "fr3sca", + }, + "kvm": { + "hypervisor": 'KVM', + "clustertype": 'CloudManaged', + "url": 'http://192.168.100.212', + "username": "root", + "password": "fr3sca", + }, + "vmware": { + "hypervisor": 'VMware', + "clustertype": 'ExternalManaged', + "url": 'http://192.168.100.203', + "username": "administrator", + "password": "fr3sca", + }, + }, + "network_offering_shared": { + "name": 'Test Network offering shared', + "displaytext": 'Test Network offering Shared', + "guestiptype": 'Shared', + "supportedservices": 'Dhcp,Dns,UserData', + "traffictype": 'GUEST', + "specifyVlan" : "True", + "specifyIpRanges" : "True", + "serviceProviderList" : { + "Dhcp": 'VirtualRouter', + "Dns": 'VirtualRouter', + "UserData": 'VirtualRouter', + }, + }, + "network_offering_internal_lb": { + "name": "Network offering for internal lb service", + "displaytext": "Network offering for internal lb service", + "guestiptype": "Isolated", + "traffictype": "Guest", + "supportedservices": "Vpn,Dhcp,Dns,Lb,UserData,SourceNat,StaticNat,PortForwarding,NetworkACL", + "serviceProviderList": { + "Dhcp": "VpcVirtualRouter", + "Dns": "VpcVirtualRouter", + "Vpn": "VpcVirtualRouter", + "UserData": "VpcVirtualRouter", + "Lb": "InternalLbVM", + "SourceNat": "VpcVirtualRouter", + "StaticNat": "VpcVirtualRouter", + "PortForwarding": "VpcVirtualRouter", + "NetworkACL": "VpcVirtualRouter", + }, + "serviceCapabilityList": { + "SourceNat": {"SupportedSourceNatTypes": "peraccount"}, + "Lb": {"lbSchemes": "internal", "SupportedLbIsolation": "dedicated"} + } + }, + + "natrule": { + "privateport": 22, + "publicport": 2222, + "protocol": "TCP" + }, + "lbrule": { + "name": "SSH", + "alg": "roundrobin", + "privateport": 22, + "publicport": 2222, + "protocol": 'TCP' + }, + + "iso1": { + "displaytext": "Test ISO 1", + "name": "ISO 1", + "url": "http://people.apache.org/~tsp/dummy.iso", + "isextractable": True, + "isfeatured": True, + "ispublic": True, + "ostype": "CentOS 5.3 (64-bit)", + }, + "iso2": { + "displaytext": "Test ISO 2", + "name": "ISO 2", + "url": "http://people.apache.org/~tsp/dummy.iso", + "isextractable": True, + "isfeatured": True, + "ispublic": True, + "ostype": "CentOS 5.3 (64-bit)", + "mode": 'HTTP_DOWNLOAD', + }, + "isfeatured": True, + "ispublic": True, + "isextractable": True, + "bootable": True, + "passwordenabled": True, + + "template": { + "displaytext": "xs", + "name": "xs", + "passwordenabled": False, + }, + "template_2": { + "displaytext": "Public Template", + "name": "Public template", + "ostype": "CentOS 5.3 (64-bit)", + "isfeatured": True, + "ispublic": True, + "isextractable": True, + "mode": "HTTP_DOWNLOAD", + }, + "templatefilter": 'self', + + "security_group" : { "name": "custom_Sec_Grp" }, + "ingress_rule": { + "protocol": "TCP", + "startport": "22", + "endport": "22", + "cidrlist": "0.0.0.0/0" + }, + "ostype": "CentOS 5.3 (64-bit)", + "sleep": 90, + "timeout": 10, + "advanced_sg": { + "zone": { + "name": "", + "dns1": "8.8.8.8", + "internaldns1": "192.168.100.1", + "networktype": "Advanced", + "securitygroupenabled": "true" + }, + "securitygroupenabled": "true" + }, + "vlan": { + "part": ["4090-4091", "4092-4095"], + "full": "4090-4095", + }, + "nfs": { + "url": "nfs://10.147.28.7/export/home/talluri/testprimary", + "name": "Primary XEN" + }, + "iscsi": { + "url": "iscsi://192.168.100.21/iqn.2012-01.localdomain.clo-cstack-cos6:iser/1", + "name": "Primary iSCSI" + }, + "volume": {"diskname": "Test Volume"}, + "volume_offerings": { + 0: {"diskname": "TestDiskServ"}, + }, + "diskdevice": ['/dev/vdc', '/dev/vdb', '/dev/hdb', '/dev/hdc', '/dev/xvdd', '/dev/cdrom', '/dev/sr0', '/dev/cdrom1' ], + + #test_vpc_vpn.py + "vpn_user": { + "username": "test", + "password": "password", + }, + "vpc": { + "name": "vpc_vpn", + "displaytext": "vpc-vpn", + "cidr": "10.1.1.0/24" + }, + "ntwk": { + "name": "tier1", + "displaytext": "vpc-tier1", + "gateway" : "10.1.1.1", + "netmask" : "255.255.255.192" + }, + "vpc2": { + "name": "vpc2_vpn", + "displaytext": "vpc2-vpn", + "cidr": "10.2.1.0/24" + }, + "ntwk2": { + "name": "tier2", + "displaytext": "vpc-tier2", + "gateway" : "10.2.1.1", + "netmask" : "255.255.255.192" + } +}