You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ta...@apache.org on 2013/11/08 11:33:52 UTC
[05/29] CLOUSTACK-5099: Utils.py-has-wrong-reference,
cleaned it. As well added Uniform naming convention Signed-off-by:
SrikanteswaraRao Talluri
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ec00a6fb/tools/marvin/build/lib/marvin/cloudstackAPI/updateZone.py
----------------------------------------------------------------------
diff --git a/tools/marvin/build/lib/marvin/cloudstackAPI/updateZone.py b/tools/marvin/build/lib/marvin/cloudstackAPI/updateZone.py
new file mode 100644
index 0000000..b1b4360
--- /dev/null
+++ b/tools/marvin/build/lib/marvin/cloudstackAPI/updateZone.py
@@ -0,0 +1,154 @@
+# 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.
+
+
+"""Updates a Zone."""
+from baseCmd import *
+from baseResponse import *
+class updateZoneCmd (baseCmd):
+ def __init__(self):
+ self.isAsync = "false"
+ """the ID of the Zone"""
+ """Required"""
+ self.id = None
+ """Allocation state of this cluster for allocation of new resources"""
+ self.allocationstate = None
+ """the details for the Zone"""
+ self.details = []
+ """the dhcp Provider for the Zone"""
+ self.dhcpprovider = None
+ """the first DNS for the Zone"""
+ self.dns1 = None
+ """the second DNS for the Zone"""
+ self.dns2 = None
+ """the dns search order list"""
+ self.dnssearchorder = []
+ """Network domain name for the networks in the zone; empty string will update domain with NULL value"""
+ self.domain = None
+ """the guest CIDR address for the Zone"""
+ self.guestcidraddress = None
+ """the first internal DNS for the Zone"""
+ self.internaldns1 = None
+ """the second internal DNS for the Zone"""
+ self.internaldns2 = None
+ """the first DNS for IPv6 network in the Zone"""
+ self.ip6dns1 = None
+ """the second DNS for IPv6 network in the Zone"""
+ self.ip6dns2 = None
+ """updates a private zone to public if set, but not vice-versa"""
+ self.ispublic = None
+ """true if local storage offering enabled, false otherwise"""
+ self.localstorageenabled = None
+ """the name of the Zone"""
+ self.name = None
+ self.required = ["id",]
+
+class updateZoneResponse (baseResponse):
+ def __init__(self):
+ """Zone id"""
+ self.id = None
+ """the allocation state of the cluster"""
+ self.allocationstate = None
+ """Zone description"""
+ self.description = None
+ """the dhcp Provider for the Zone"""
+ self.dhcpprovider = None
+ """the display text of the zone"""
+ self.displaytext = None
+ """the first DNS for the Zone"""
+ self.dns1 = None
+ """the second DNS for the Zone"""
+ self.dns2 = None
+ """Network domain name for the networks in the zone"""
+ self.domain = None
+ """the UUID of the containing domain, null for public zones"""
+ self.domainid = None
+ """the name of the containing domain, null for public zones"""
+ self.domainname = None
+ """the guest CIDR address for the Zone"""
+ self.guestcidraddress = None
+ """the first internal DNS for the Zone"""
+ self.internaldns1 = None
+ """the second internal DNS for the Zone"""
+ self.internaldns2 = None
+ """the first IPv6 DNS for the Zone"""
+ self.ip6dns1 = None
+ """the second IPv6 DNS for the Zone"""
+ self.ip6dns2 = None
+ """true if local storage offering enabled, false otherwise"""
+ self.localstorageenabled = None
+ """Zone name"""
+ self.name = None
+ """the network type of the zone; can be Basic or Advanced"""
+ self.networktype = None
+ """true if security groups support is enabled, false otherwise"""
+ self.securitygroupsenabled = None
+ """the vlan range of the zone"""
+ self.vlan = None
+ """Zone Token"""
+ self.zonetoken = None
+ """the capacity of the Zone"""
+ self.capacity = []
+ """the list of resource tags associated with zone."""
+ self.tags = []
+
+class capacity:
+ def __init__(self):
+ """"the total capacity available"""
+ self.capacitytotal = None
+ """"the capacity currently in use"""
+ self.capacityused = None
+ """"the Cluster ID"""
+ self.clusterid = None
+ """"the Cluster name"""
+ self.clustername = None
+ """"the percentage of capacity currently in use"""
+ self.percentused = None
+ """"the Pod ID"""
+ self.podid = None
+ """"the Pod name"""
+ self.podname = None
+ """"the capacity type"""
+ self.type = None
+ """"the Zone ID"""
+ self.zoneid = None
+ """"the Zone name"""
+ self.zonename = None
+
+class tags:
+ def __init__(self):
+ """"the account associated with the tag"""
+ self.account = None
+ """"customer associated with the tag"""
+ self.customer = None
+ """"the domain associated with the tag"""
+ self.domain = None
+ """"the ID of the domain associated with the tag"""
+ self.domainid = None
+ """"tag key name"""
+ self.key = None
+ """"the project name where tag belongs to"""
+ self.project = None
+ """"the project id the tag belongs to"""
+ self.projectid = None
+ """"id of the resource"""
+ self.resourceid = None
+ """"resource type"""
+ self.resourcetype = None
+ """"tag value"""
+ self.value = None
+
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ec00a6fb/tools/marvin/build/lib/marvin/cloudstackAPI/uploadCustomCertificate.py
----------------------------------------------------------------------
diff --git a/tools/marvin/build/lib/marvin/cloudstackAPI/uploadCustomCertificate.py b/tools/marvin/build/lib/marvin/cloudstackAPI/uploadCustomCertificate.py
new file mode 100644
index 0000000..d84f448
--- /dev/null
+++ b/tools/marvin/build/lib/marvin/cloudstackAPI/uploadCustomCertificate.py
@@ -0,0 +1,43 @@
+# 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.
+
+
+"""Uploads a custom certificate for the console proxy VMs to use for SSL. Can be used to upload a single certificate signed by a known CA. Can also be used, through multiple calls, to upload a chain of certificates from CA to the custom certificate itself."""
+from baseCmd import *
+from baseResponse import *
+class uploadCustomCertificateCmd (baseCmd):
+ def __init__(self):
+ self.isAsync = "true"
+ """The certificate to be uploaded."""
+ """Required"""
+ self.certificate = None
+ """DNS domain suffix that the certificate is granted for."""
+ """Required"""
+ self.domainsuffix = None
+ """An integer providing the location in a chain that the certificate will hold. Usually, this can be left empty. When creating a chain, the top level certificate should have an ID of 1, with each step in the chain incrementing by one. Example, CA with id = 1, Intermediate CA with id = 2, Site certificate with ID = 3"""
+ self.id = None
+ """A name / alias for the certificate."""
+ self.name = None
+ """The private key for the attached certificate."""
+ self.privatekey = None
+ self.required = ["certificate","domainsuffix",]
+
+class uploadCustomCertificateResponse (baseResponse):
+ def __init__(self):
+ """message of the certificate upload operation"""
+ self.message = None
+
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ec00a6fb/tools/marvin/build/lib/marvin/cloudstackAPI/uploadVolume.py
----------------------------------------------------------------------
diff --git a/tools/marvin/build/lib/marvin/cloudstackAPI/uploadVolume.py b/tools/marvin/build/lib/marvin/cloudstackAPI/uploadVolume.py
new file mode 100644
index 0000000..acd4a0e
--- /dev/null
+++ b/tools/marvin/build/lib/marvin/cloudstackAPI/uploadVolume.py
@@ -0,0 +1,162 @@
+# 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.
+
+
+"""Uploads a data disk."""
+from baseCmd import *
+from baseResponse import *
+class uploadVolumeCmd (baseCmd):
+ def __init__(self):
+ self.isAsync = "true"
+ """the format for the volume. Possible values include QCOW2, OVA, and VHD."""
+ """Required"""
+ self.format = None
+ """the name of the volume"""
+ """Required"""
+ self.name = None
+ """the URL of where the volume is hosted. Possible URL include http:// and https://"""
+ """Required"""
+ self.url = None
+ """the ID of the zone the volume is to be hosted on"""
+ """Required"""
+ self.zoneid = None
+ """an optional accountName. Must be used with domainId."""
+ self.account = None
+ """the MD5 checksum value of this volume"""
+ self.checksum = None
+ """an optional domainId. If the account parameter is used, domainId must also be used."""
+ self.domainid = None
+ """Image store uuid"""
+ self.imagestoreuuid = None
+ """Upload volume for the project"""
+ self.projectid = None
+ self.required = ["format","name","url","zoneid",]
+
+class uploadVolumeResponse (baseResponse):
+ def __init__(self):
+ """ID of the disk volume"""
+ self.id = None
+ """the account associated with the disk volume"""
+ self.account = None
+ """the date the volume was attached to a VM instance"""
+ self.attached = None
+ """the date the disk volume was created"""
+ self.created = None
+ """the boolean state of whether the volume is destroyed or not"""
+ self.destroyed = None
+ """the ID of the device on user vm the volume is attahed to. This tag is not returned when the volume is detached."""
+ self.deviceid = None
+ """bytes read rate of the disk volume"""
+ self.diskBytesReadRate = None
+ """bytes write rate of the disk volume"""
+ self.diskBytesWriteRate = None
+ """io requests read rate of the disk volume"""
+ self.diskIopsReadRate = None
+ """io requests write rate of the disk volume"""
+ self.diskIopsWriteRate = None
+ """the display text of the disk offering"""
+ self.diskofferingdisplaytext = None
+ """ID of the disk offering"""
+ self.diskofferingid = None
+ """name of the disk offering"""
+ self.diskofferingname = None
+ """an optional field whether to the display the volume to the end user or not."""
+ self.displayvolume = None
+ """the domain associated with the disk volume"""
+ self.domain = None
+ """the ID of the domain associated with the disk volume"""
+ self.domainid = None
+ """Hypervisor the volume belongs to"""
+ self.hypervisor = None
+ """true if the volume is extractable, false otherwise"""
+ self.isextractable = None
+ """max iops of the disk volume"""
+ self.maxiops = None
+ """min iops of the disk volume"""
+ self.miniops = None
+ """name of the disk volume"""
+ self.name = None
+ """The path of the volume"""
+ self.path = None
+ """the project name of the vpn"""
+ self.project = None
+ """the project id of the vpn"""
+ self.projectid = None
+ """the display text of the service offering for root disk"""
+ self.serviceofferingdisplaytext = None
+ """ID of the service offering for root disk"""
+ self.serviceofferingid = None
+ """name of the service offering for root disk"""
+ self.serviceofferingname = None
+ """size of the disk volume"""
+ self.size = None
+ """ID of the snapshot from which this volume was created"""
+ self.snapshotid = None
+ """the state of the disk volume"""
+ self.state = None
+ """the status of the volume"""
+ self.status = None
+ """name of the primary storage hosting the disk volume"""
+ self.storage = None
+ """id of the primary storage hosting the disk volume; returned to admin user only"""
+ self.storageid = None
+ """shared or local storage"""
+ self.storagetype = None
+ """type of the disk volume (ROOT or DATADISK)"""
+ self.type = None
+ """id of the virtual machine"""
+ self.virtualmachineid = None
+ """display name of the virtual machine"""
+ self.vmdisplayname = None
+ """name of the virtual machine"""
+ self.vmname = None
+ """state of the virtual machine"""
+ self.vmstate = None
+ """ID of the availability zone"""
+ self.zoneid = None
+ """name of the availability zone"""
+ self.zonename = None
+ """the list of resource tags associated with volume"""
+ self.tags = []
+ """the ID of the latest async job acting on this object"""
+ self.jobid = None
+ """the current status of the latest async job acting on this object"""
+ self.jobstatus = None
+
+class tags:
+ def __init__(self):
+ """"the account associated with the tag"""
+ self.account = None
+ """"customer associated with the tag"""
+ self.customer = None
+ """"the domain associated with the tag"""
+ self.domain = None
+ """"the ID of the domain associated with the tag"""
+ self.domainid = None
+ """"tag key name"""
+ self.key = None
+ """"the project name where tag belongs to"""
+ self.project = None
+ """"the project id the tag belongs to"""
+ self.projectid = None
+ """"id of the resource"""
+ self.resourceid = None
+ """"resource type"""
+ self.resourcetype = None
+ """"tag value"""
+ self.value = None
+
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ec00a6fb/tools/marvin/build/lib/marvin/cloudstackConnection.py
----------------------------------------------------------------------
diff --git a/tools/marvin/build/lib/marvin/cloudstackConnection.py b/tools/marvin/build/lib/marvin/cloudstackConnection.py
new file mode 100644
index 0000000..686c533
--- /dev/null
+++ b/tools/marvin/build/lib/marvin/cloudstackConnection.py
@@ -0,0 +1,235 @@
+# 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 requests
+import urllib
+import base64
+import hmac
+import hashlib
+import logging
+import time
+import cloudstackException
+from cloudstackAPI import *
+import jsonHelper
+from requests import ConnectionError
+from requests import HTTPError
+from requests import Timeout
+from requests import RequestException
+
+
+class cloudConnection(object):
+
+ """ Connections to make API calls to the cloudstack management server
+ """
+
+ def __init__(self, mgtSvr, port=8096, user=None, passwd=None,
+ apiKey=None, securityKey=None,
+ asyncTimeout=3600, logging=None, scheme='http',
+ path='client/api'):
+ self.loglevel() # Turn off requests logs
+ self.apiKey = apiKey
+ self.securityKey = securityKey
+ self.mgtSvr = mgtSvr
+ self.port = port
+ self.user = user
+ self.passwd = passwd
+ self.logging = logging
+ self.path = path
+ self.retries = 5
+ self.asyncTimeout = asyncTimeout
+ self.auth = True
+ if port == 8096 or \
+ (self.apiKey is None and self.securityKey is None):
+ self.auth = False
+ if scheme not in ['http', 'https']:
+ raise RequestException("Protocol must be HTTP")
+ self.protocol = scheme
+ self.baseurl = "%s://%s:%d/%s"\
+ % (self.protocol, self.mgtSvr, self.port, self.path)
+
+ def __copy__(self):
+ return cloudConnection(self.mgtSvr, self.port, self.user, self.passwd,
+ self.apiKey, self.securityKey,
+ self.asyncTimeout, self.logging, self.protocol,
+ self.path)
+
+ def loglevel(self, lvl=logging.WARNING):
+ """
+ Turns off the INFO/DEBUG logs from `requests`
+ """
+ requests_log = logging.getLogger("requests")
+ requests_log.setLevel(lvl)
+
+ 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.marvin_request(cmd, response_type=response)
+
+ if asyncResonse.jobstatus == 2:
+ raise cloudstackException.cloudstackAPIException(
+ "asyncquery", asyncResonse.jobresult)
+ elif asyncResonse.jobstatus == 1:
+ return asyncResonse
+
+ time.sleep(5)
+ if self.logging is not None:
+ self.logging.debug("job: %s still processing,"
+ " will timeout in %ds" % (jobid, timeout))
+ timeout = timeout - 5
+
+ raise cloudstackException.cloudstackAPIException(
+ "asyncquery", "Async job timeout %s" % jobid)
+
+ 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
+ """
+ params = zip(payload.keys(), payload.values())
+ params.sort(key=lambda k: str.lower(k[0]))
+ hashStr = "&".join(
+ ["=".join(
+ [str.lower(r[0]),
+ str.lower(
+ urllib.quote_plus(str(r[1]))
+ ).replace("+", "%20")]
+ ) for r in params]
+ )
+ signature = base64.encodestring(hmac.new(
+ self.securityKey, hashStr, hashlib.sha1).digest()).strip()
+ self.logging.debug("Computed Signature by Marvin: %s" % signature)
+ return signature
+
+ def request(self, command, auth=True, payload={}, method='GET'):
+ """
+ Makes requests using auth or over integration port
+ @param command: cloudstack API command name
+ eg: deployVirtualMachineCommand
+ @param 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["command"] = command
+ payload["response"] = "json"
+
+ if auth:
+ payload["apiKey"] = self.apiKey
+ signature = self.sign(payload)
+ payload["signature"] = signature
+
+ try:
+ if method == 'POST':
+ response = requests.post(
+ self.baseurl, params=payload, verify=False)
+ else:
+ response = requests.get(
+ self.baseurl, params=payload, verify=False)
+ except ConnectionError, c:
+ self.logging.debug("Connection refused. Reason: %s : %s" %
+ (self.baseurl, c))
+ raise c
+ except HTTPError, h:
+ self.logging.debug("Server returned error code: %s" % h)
+ raise h
+ except Timeout, t:
+ self.logging.debug("Connection timed out with %s" % t)
+ raise t
+ except RequestException, r:
+ self.logging.debug("Error returned by server %s" % r)
+ raise r
+ else:
+ return response
+
+ def sanitize_command(self, cmd):
+ """
+ Removes None values, Validates all required params are present
+ @param cmd: Cmd object eg: createPhysicalNetwork
+ @return:
+ """
+ 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)
+ 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, isAsync, requests
+
+ def marvin_request(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:
+ """
+ cmdname, isAsync, payload = self.sanitize_command(cmd)
+ self.logging.debug("sending %s request: %s %s" % (method, cmdname,
+ str(payload)))
+ response = self.request(
+ cmdname, self.auth, payload=payload, method=method)
+ self.logging.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)
+
+ if isAsync == "false":
+ return response
+ else:
+ asyncJobId = response.jobid
+ response = self.poll(asyncJobId, response_type)
+ return response.jobresult
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ec00a6fb/tools/marvin/build/lib/marvin/cloudstackException.py
----------------------------------------------------------------------
diff --git a/tools/marvin/build/lib/marvin/cloudstackException.py b/tools/marvin/build/lib/marvin/cloudstackException.py
new file mode 100644
index 0000000..6200003
--- /dev/null
+++ b/tools/marvin/build/lib/marvin/cloudstackException.py
@@ -0,0 +1,48 @@
+# 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.
+
+
+class cloudstackAPIException(Exception):
+ def __init__(self, cmd="", result=""):
+ self.errorMsg = "Execute cmd: %s failed, due to: %s" % (cmd, result)
+
+ def __str__(self):
+ return self.errorMsg
+
+
+class InvalidParameterException(Exception):
+ def __init__(self, msg=''):
+ self.errorMsg = msg
+
+ def __str__(self):
+ return self.errorMsg
+
+
+class dbException(Exception):
+ def __init__(self, msg=''):
+ self.errorMsg = msg
+
+ def __str__(self):
+ return self.errorMsg
+
+
+class internalError(Exception):
+ def __init__(self, msg=''):
+ self.errorMsg = msg
+
+ def __str__(self):
+ return self.errorMsg
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ec00a6fb/tools/marvin/build/lib/marvin/cloudstackTestCase.py
----------------------------------------------------------------------
diff --git a/tools/marvin/build/lib/marvin/cloudstackTestCase.py b/tools/marvin/build/lib/marvin/cloudstackTestCase.py
new file mode 100644
index 0000000..85ef542
--- /dev/null
+++ b/tools/marvin/build/lib/marvin/cloudstackTestCase.py
@@ -0,0 +1,40 @@
+# 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 unittest
+
+
+def user(Name, DomainName, AcctType):
+ def wrapper(cls):
+ orig_init = cls.__init__
+
+ def __init__(self, *args, **kws):
+ cls.UserName = Name
+ cls.DomainName = DomainName
+ cls.AcctType = AcctType
+ orig_init(self, *args, **kws)
+ cls.__init__ = __init__
+ return cls
+ return wrapper
+
+
+class cloudstackTestCase(unittest.case.TestCase):
+ clstestclient = None
+
+ @classmethod
+ def getClsTestClient(cls):
+ return cls.clstestclient
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ec00a6fb/tools/marvin/build/lib/marvin/cloudstackTestClient.py
----------------------------------------------------------------------
diff --git a/tools/marvin/build/lib/marvin/cloudstackTestClient.py b/tools/marvin/build/lib/marvin/cloudstackTestClient.py
new file mode 100644
index 0000000..36f7f8d
--- /dev/null
+++ b/tools/marvin/build/lib/marvin/cloudstackTestClient.py
@@ -0,0 +1,201 @@
+# 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 cloudstackConnection
+import asyncJobMgr
+import dbConnection
+from cloudstackAPI import *
+import random
+import string
+import hashlib
+
+
+class cloudstackTestClient(object):
+ def __init__(self, mgtSvr=None, port=8096, user=None, passwd=None,
+ apiKey=None, securityKey=None, asyncTimeout=3600,
+ defaultWorkerThreads=10, logging=None):
+ self.connection = \
+ cloudstackConnection.cloudConnection(mgtSvr, port, user, passwd,
+ apiKey, securityKey,
+ asyncTimeout, logging)
+ self.apiClient =\
+ cloudstackAPIClient.CloudStackAPIClient(self.connection)
+ self.dbConnection = None
+ self.asyncJobMgr = None
+ self.ssh = None
+ self.id = None
+ self.defaultWorkerThreads = defaultWorkerThreads
+
+ @property
+ def identifier(self):
+ return self.id
+
+ @identifier.setter
+ def identifier(self, id):
+ self.id = id
+
+ def dbConfigure(self, host="localhost", port=3306, user='cloud',
+ passwd='cloud', db='cloud'):
+ self.dbConnection = dbConnection.dbConnection(host, port, user, passwd,
+ db)
+
+ def isAdminContext(self):
+ """
+ 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
+ except:
+ return 0 # user
+
+ def random_gen(self, size=6, chars=string.ascii_uppercase + string.digits):
+ """Generate Random Strings of variable length"""
+ randomstr = ''.join(random.choice(chars) for x in range(size))
+ if self.identifier:
+ return ''.join([self.identifier, '-', randomstr])
+ return randomstr
+
+ 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
+ try:
+ accounts = self.apiClient.listAccounts(cmd)
+ acctId = accounts[0].id
+ except:
+ createAcctCmd = createAccount.createAccountCmd()
+ createAcctCmd.accounttype = acctType
+ createAcctCmd.domainid = domId
+ createAcctCmd.email = "test-" + self.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
+
+ newUserConnection =\
+ cloudstackConnection.cloudConnection(self.connection.mgtSvr,
+ self.connection.port,
+ self.connection.user,
+ self.connection.passwd,
+ apiKey, securityKey,
+ self.connection.asyncTimeout,
+ self.connection.logging)
+ self.userApiClient =\
+ cloudstackAPIClient.CloudStackAPIClient(newUserConnection)
+ self.userApiClient.connection = newUserConnection
+ self.userApiClient.hypervisor = self.apiClient.hypervisor
+ return self.userApiClient
+
+ def close(self):
+ if self.connection is not None:
+ self.connection.close()
+
+ def getDbConnection(self):
+ return self.dbConnection
+
+ def executeSql(self, sql=None):
+ if sql is None or self.dbConnection is None:
+ return None
+
+ return self.dbConnection.execute()
+
+ def executeSqlFromFile(self, sqlFile=None):
+ if sqlFile is None or self.dbConnection is None:
+ return None
+ return self.dbConnection.executeSqlFromFile(sqlFile)
+
+ def getApiClient(self):
+ self.apiClient.id = self.identifier
+ return self.apiClient
+
+ def getUserApiClient(self, account, domain, type=0):
+ """
+ 0 - user
+ 1 - admin
+ 2 - domain admin
+ """
+ self.createUserApiClient(account, domain, type)
+ if hasattr(self, "userApiClient"):
+ return self.userApiClient
+ return None
+
+ 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)
+
+ 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
+ '''
+ if self.asyncJobMgr is None:
+ self.asyncJobMgr = 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)
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ec00a6fb/tools/marvin/build/lib/marvin/codegenerator.py
----------------------------------------------------------------------
diff --git a/tools/marvin/build/lib/marvin/codegenerator.py b/tools/marvin/build/lib/marvin/codegenerator.py
new file mode 100644
index 0000000..96729f6
--- /dev/null
+++ b/tools/marvin/build/lib/marvin/codegenerator.py
@@ -0,0 +1,463 @@
+# 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 xml.dom.minidom
+import json
+from optparse import OptionParser
+from textwrap import dedent
+import os
+import sys
+import urllib2
+
+
+class cmdParameterProperty(object):
+ def __init__(self):
+ self.name = None
+ self.required = False
+ self.desc = ""
+ self.type = "planObject"
+ self.subProperties = []
+
+
+class cloudStackCmd(object):
+ def __init__(self):
+ self.name = ""
+ self.desc = ""
+ self.async = "false"
+ self.request = []
+ self.response = []
+
+
+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
+ the ApiDocWriter. This class provides helper methods for these uses.
+ """
+ space = ' '
+ newline = '\n'
+ cmdsName = []
+
+ def __init__(self, outputFolder):
+ self.cmd = None
+ self.code = ""
+ self.required = []
+ self.subclass = []
+ self.outputFolder = outputFolder
+ lic = """\
+ # 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.
+
+ """
+ self.license = dedent(lic)
+
+ def addAttribute(self, attr, pro):
+ value = pro.value
+ if pro.required:
+ self.required.append(attr)
+ desc = pro.desc
+ if desc is not None:
+ self.code += self.space
+ self.code += "''' " + pro.desc + " '''"
+ self.code += self.newline
+
+ self.code += self.space
+ self.code += attr + " = " + str(value)
+ self.code += self.newline
+
+ def generateSubClass(self, name, properties):
+ '''generate code for sub list'''
+ subclass = 'class %s:\n' % name
+ subclass += self.space + "def __init__(self):\n"
+ for pro in properties:
+ if pro.desc is not None:
+ subclass += self.space + self.space + '""""%s"""\n' % pro.desc
+ if len(pro.subProperties) > 0:
+ subclass += self.space + self.space
+ subclass += 'self.%s = []\n' % pro.name
+ self.generateSubClass(pro.name, pro.subProperties)
+ else:
+ subclass += self.space + self.space
+ subclass += 'self.%s = None\n' % pro.name
+
+ self.subclass.append(subclass)
+
+ def generate(self, cmd):
+
+ self.cmd = cmd
+ self.cmdsName.append(self.cmd.name)
+ self.code = self.license
+ self.code += self.newline
+ self.code += '"""%s"""\n' % self.cmd.desc
+ self.code += 'from baseCmd import *\n'
+ self.code += 'from baseResponse import *\n'
+ self.code += "class %sCmd (baseCmd):\n" % self.cmd.name
+ self.code += self.space + "def __init__(self):\n"
+
+ self.code += self.space + self.space
+ self.code += 'self.isAsync = "%s"\n' % str(self.cmd.async).lower()
+
+ for req in self.cmd.request:
+ if req.desc is not None:
+ self.code += self.space + self.space + '"""%s"""\n' % req.desc
+ if req.required == "true":
+ self.code += self.space + self.space + '"""Required"""\n'
+
+ value = "None"
+ if req.type == "list" or req.type == "map":
+ value = "[]"
+
+ self.code += self.space + self.space
+ self.code += 'self.%s = %s\n' % (req.name, value)
+ if req.required == "true":
+ self.required.append(req.name)
+
+ self.code += self.space + self.space + "self.required = ["
+ for require in self.required:
+ self.code += '"' + require + '",'
+ self.code += "]\n"
+ self.required = []
+
+ """generate response code"""
+ subItems = {}
+ self.code += self.newline
+ self.code += 'class %sResponse (baseResponse):\n' % self.cmd.name
+ self.code += self.space + "def __init__(self):\n"
+ if len(self.cmd.response) == 0:
+ self.code += self.space + self.space + "pass"
+ else:
+ for res in self.cmd.response:
+ if res.desc is not None:
+ self.code += self.space + self.space
+ self.code += '"""%s"""\n' % res.desc
+
+ if len(res.subProperties) > 0:
+ self.code += self.space + self.space
+ self.code += 'self.%s = []\n' % res.name
+ self.generateSubClass(res.name, res.subProperties)
+ else:
+ self.code += self.space + self.space
+ self.code += 'self.%s = None\n' % res.name
+ self.code += self.newline
+
+ for subclass in self.subclass:
+ self.code += subclass + "\n"
+
+ fp = open(self.outputFolder + "/cloudstackAPI/%s.py" % self.cmd.name,
+ "w")
+ fp.write(self.code)
+ fp.close()
+ self.code = ""
+ self.subclass = []
+
+ def finalize(self):
+ '''generate an api call'''
+
+ header = '"""Test Client for CloudStack API"""\n'
+ imports = "import copy\n"
+ initCmdsList = '__all__ = ['
+ body = ''
+ body += "class CloudStackAPIClient(object):\n"
+ body += self.space + 'def __init__(self, connection):\n'
+ body += self.space + self.space + 'self.connection = connection\n'
+ body += self.space + self.space + 'self._id = None\n'
+ body += self.newline
+
+ body += self.space + 'def __copy__(self):\n'
+ body += self.space + self.space
+ body += 'return CloudStackAPIClient(copy.copy(self.connection))\n'
+ body += self.newline
+
+ # The `id` property will be used to link the test with the cloud
+ # resource being created
+ # @property
+ # def id(self):
+ # return self._id
+ #
+ # @id.setter
+ # def id(self, identifier):
+ # self._id = identifier
+
+ 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.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.newline
+
+ for cmdName in self.cmdsName:
+ body += self.space
+ body += 'def %s(self, command, method="GET"):\n' % cmdName
+ body += self.space + self.space
+ body += 'response = %sResponse()\n' % cmdName
+ body += self.space + self.space
+ body += 'response = self.connection.marvin_request(command,'
+ body += ' response_type=response, method=method)\n'
+ body += self.space + self.space + 'return response\n'
+ body += self.newline
+
+ imports += 'from %s import %sResponse\n' % (cmdName, cmdName)
+ initCmdsList += '"%s",' % cmdName
+
+ fp = open(self.outputFolder + '/cloudstackAPI/cloudstackAPIClient.py',
+ 'w')
+ fp.write(self.license)
+ for item in [header, imports, body]:
+ fp.write(item)
+ fp.close()
+
+ '''generate __init__.py'''
+ initCmdsList = self.license + initCmdsList + '"cloudstackAPIClient"]'
+ fp = open(self.outputFolder + '/cloudstackAPI/__init__.py', 'w')
+ fp.write(initCmdsList)
+ fp.close()
+
+ fp = open(self.outputFolder + '/cloudstackAPI/baseCmd.py', 'w')
+ basecmd = self.license
+ basecmd += '"""Base Command"""\n'
+ basecmd += 'class baseCmd(object):\n'
+ basecmd += self.space + 'pass\n'
+ fp.write(basecmd)
+ fp.close()
+
+ fp = open(self.outputFolder + '/cloudstackAPI/baseResponse.py', 'w')
+ basecmd = self.license
+ basecmd += '"""Base class for response"""\n'
+ basecmd += 'class baseResponse(object):\n'
+ basecmd += self.space + 'pass\n'
+ fp.write(basecmd)
+ fp.close()
+
+ def constructResponseFromXML(self, response):
+ paramProperty = cmdParameterProperty()
+ paramProperty.name = getText(response.getElementsByTagName('name'))
+ paramProperty.desc = getText(response.
+ getElementsByTagName('description'))
+ if paramProperty.name.find('(*)') != -1:
+ '''This is a list'''
+ paramProperty.name = paramProperty.name.split('(*)')[0]
+ argList = response.getElementsByTagName('arguments')[0].\
+ getElementsByTagName('arg')
+ for subresponse in argList:
+ subProperty = self.constructResponseFromXML(subresponse)
+ paramProperty.subProperties.append(subProperty)
+ return paramProperty
+
+ def loadCmdFromXML(self, dom):
+ cmds = []
+ for cmd in dom.getElementsByTagName("command"):
+ csCmd = cloudStackCmd()
+ csCmd.name = getText(cmd.getElementsByTagName('name'))
+ assert csCmd.name
+
+ desc = getText(cmd.getElementsByTagName('description'))
+ if desc:
+ csCmd.desc = desc
+
+ async = getText(cmd.getElementsByTagName('isAsync'))
+ if async:
+ csCmd.async = async
+
+ argList = cmd.getElementsByTagName("request")[0].\
+ getElementsByTagName("arg")
+ for param in argList:
+ paramProperty = cmdParameterProperty()
+
+ paramProperty.name =\
+ getText(param.getElementsByTagName('name'))
+ assert paramProperty.name
+
+ required = param.getElementsByTagName('required')
+ if required:
+ paramProperty.required = getText(required)
+
+ 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]
+ for response in responseEle.getElementsByTagName("arg"):
+ if response.parentNode != responseEle:
+ continue
+
+ paramProperty = self.constructResponseFromXML(response)
+ csCmd.response.append(paramProperty)
+
+ cmds.append(csCmd)
+ return cmds
+
+ def generateCodeFromXML(self, apiSpecFile):
+ dom = xml.dom.minidom.parse(apiSpecFile)
+ cmds = self.loadCmdFromXML(dom)
+ for cmd in cmds:
+ self.generate(cmd)
+ self.finalize()
+
+ def constructResponseFromJSON(self, response):
+ paramProperty = cmdParameterProperty()
+ if 'name' in response:
+ paramProperty.name = response['name']
+ assert paramProperty.name, "%s has no property name" % response
+
+ if 'description' in response:
+ paramProperty.desc = response['description']
+ if 'type' in response:
+ if response['type'] in ['list', 'map', 'set']:
+ #Here list becomes a subproperty
+ if 'response' in response:
+ for innerResponse in response['response']:
+ subProperty =\
+ self.constructResponseFromJSON(innerResponse)
+ paramProperty.subProperties.append(subProperty)
+ paramProperty.type = response['type']
+ return paramProperty
+
+ def loadCmdFromJSON(self, apiStream):
+ if apiStream is None:
+ raise Exception("No APIs found through discovery")
+
+ jsonOut = apiStream.readlines()
+ assert len(jsonOut) > 0
+ apiDict = json.loads(jsonOut[0])
+ if not 'listapisresponse' in apiDict:
+ raise Exception("API discovery plugin response failed")
+ if not 'count' in apiDict['listapisresponse']:
+ raise Exception("Malformed api response")
+
+ apilist = apiDict['listapisresponse']['api']
+ cmds = []
+ for cmd in apilist:
+ csCmd = cloudStackCmd()
+ if 'name' in cmd:
+ csCmd.name = cmd['name']
+ assert csCmd.name
+
+ if 'description' in cmd:
+ csCmd.desc = cmd['description']
+
+ if 'isasync' in cmd:
+ csCmd.async = cmd['isasync']
+
+ for param in cmd['params']:
+ paramProperty = cmdParameterProperty()
+
+ if 'name' in param:
+ paramProperty.name = param['name']
+ assert paramProperty.name
+
+ if 'required' in param:
+ paramProperty.required = param['required']
+
+ if 'description' in param:
+ paramProperty.desc = param['description']
+
+ if 'type' in param:
+ paramProperty.type = param['type']
+
+ csCmd.request.append(paramProperty)
+
+ for response in cmd['response']:
+ #FIXME: ExtractImage related APIs return empty dicts in response
+ if len(response) > 0:
+ paramProperty = self.constructResponseFromJSON(response)
+ csCmd.response.append(paramProperty)
+
+ cmds.append(csCmd)
+ return cmds
+
+ def generateCodeFromJSON(self, endpointUrl):
+ """
+ Api Discovery plugin returns the supported APIs of a CloudStack
+ endpoint.
+ @return: The classes in cloudstackAPI/ formed from api discovery json
+ """
+ if endpointUrl.find('response=json') >= 0:
+ apiStream = urllib2.urlopen(endpointUrl)
+ cmds = self.loadCmdFromJSON(apiStream)
+ for cmd in cmds:
+ self.generate(cmd)
+ self.finalize()
+
+
+def getText(elements):
+ return elements[0].childNodes[0].nodeValue.strip()
+
+if __name__ == "__main__":
+ parser = OptionParser()
+ parser.add_option("-o", "--output", dest="output",
+ help="The path to the generated code entities, default\
+ is .")
+ parser.add_option("-s", "--specfile", dest="spec",
+ help="The path and name of the api spec xml file,\
+ default is /etc/cloud/cli/commands.xml")
+ parser.add_option("-e", "--endpoint", dest="endpoint",
+ help="The endpoint mgmt server (with open 8096) where\
+ apis are discovered, default is localhost")
+
+ (options, args) = parser.parse_args()
+
+ folder = "."
+ if options.output is not None:
+ folder = options.output
+ apiModule = folder + "/cloudstackAPI"
+ if not os.path.exists(apiModule):
+ try:
+ os.mkdir(apiModule)
+ except:
+ print "Failed to create folder %s, due to %s" % (apiModule,
+ sys.exc_info())
+ print parser.print_help()
+ exit(2)
+
+ apiSpecFile = "/etc/cloud/cli/commands.xml"
+ if options.spec is not None:
+ apiSpecFile = options.spec
+ if not os.path.exists(apiSpecFile):
+ print "the spec file %s does not exists" % apiSpecFile
+ print parser.print_help()
+ exit(1)
+
+ cg = codeGenerator(folder)
+ if options.spec is not None:
+ cg.generateCodeFromXML(apiSpecFile)
+ elif options.endpoint is not None:
+ endpointUrl = 'http://%s:8096/client/api?command=listApis&\
+response=json' % options.endpoint
+ cg.generateCodeFromJSON(endpointUrl)
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ec00a6fb/tools/marvin/build/lib/marvin/configGenerator.py
----------------------------------------------------------------------
diff --git a/tools/marvin/build/lib/marvin/configGenerator.py b/tools/marvin/build/lib/marvin/configGenerator.py
new file mode 100644
index 0000000..a966ae0
--- /dev/null
+++ b/tools/marvin/build/lib/marvin/configGenerator.py
@@ -0,0 +1,870 @@
+# 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 json
+import os
+from optparse import OptionParser
+import jsonHelper
+
+
+class managementServer(object):
+ def __init__(self):
+ self.mgtSvrIp = None
+ self.port = 8096
+ self.apiKey = None
+ self.securityKey = None
+
+
+class dbServer(object):
+ def __init__(self):
+ self.dbSvr = None
+ self.port = 3306
+ self.user = "cloud"
+ self.passwd = "cloud"
+ self.db = "cloud"
+
+
+class configuration(object):
+ def __init__(self):
+ self.name = None
+ self.value = None
+
+
+class logger(object):
+ def __init__(self):
+ '''TestCase/TestClient'''
+ self.name = None
+ self.file = None
+
+
+class cloudstackConfiguration(object):
+ def __init__(self):
+ self.zones = []
+ self.mgtSvr = []
+ self.dbSvr = None
+ self.globalConfig = []
+ self.logger = []
+
+
+class zone(object):
+ def __init__(self):
+ self.dns1 = None
+ self.internaldns1 = None
+ self.name = None
+ '''Basic or Advanced'''
+ self.networktype = None
+ self.dns2 = None
+ self.internaldns2 = None
+ self.securitygroupenabled = None
+ self.localstorageenabled = None
+ '''default public network, in advanced mode'''
+ self.ipranges = []
+ self.physical_networks = []
+ self.pods = []
+ self.secondaryStorages = []
+ self.cacheStorages = []
+
+
+class traffictype(object):
+ def __init__(self, typ, labeldict=None):
+ self.typ = typ # Guest/Management/Public
+ if labeldict:
+ self.xen = labeldict['xen'] if 'xen' in labeldict.keys() else None
+ self.kvm = labeldict['kvm'] if 'kvm' in labeldict.keys() else None
+ self.vmware = labeldict['vmware']\
+ if 'vmware' in labeldict.keys() else None
+ self.simulator = labeldict['simulator']\
+ if 'simulator' in labeldict.keys() else None
+ #{
+ # 'xen' : 'cloud-xen',
+ # 'kvm' : 'cloud-kvm',
+ # 'vmware' : 'cloud-vmware'
+ #}
+
+
+class pod(object):
+ def __init__(self):
+ self.gateway = None
+ self.name = None
+ self.netmask = None
+ self.startip = None
+ self.endip = None
+ self.zoneid = None
+ self.clusters = []
+ self.vmwaredc = []
+ '''Used in basic network mode'''
+ self.guestIpRanges = []
+
+
+class VmwareDc(object):
+ def __init__(self):
+ self.zoneid = None
+ self.name = None
+ self.vcenter = None
+ self.username = None
+ self.password = None
+
+
+class cluster(object):
+ def __init__(self):
+ self.clustername = None
+ self.clustertype = None
+ self.hypervisor = None
+ self.zoneid = None
+ self.podid = None
+ self.password = None
+ self.url = None
+ self.username = None
+ self.hosts = []
+ self.primaryStorages = []
+
+
+class host(object):
+ def __init__(self):
+ self.hypervisor = None
+ self.password = None
+ self.url = None
+ self.username = None
+ self.zoneid = None
+ self.podid = None
+ self.clusterid = None
+ self.clustername = None
+ self.cpunumber = None
+ self.cpuspeed = None
+ self.hostmac = None
+ self.hosttags = None
+ self.memory = None
+
+
+class physical_network(object):
+ def __init__(self):
+ self.name = None
+ self.tags = []
+ self.traffictypes = []
+ self.broadcastdomainrange = 'Zone'
+ self.vlan = None
+ self.isolationmethods = []
+ '''enable default virtual router provider'''
+ vrouter = provider()
+ vrouter.name = 'VirtualRouter'
+ self.providers = [vrouter]
+
+
+class provider(object):
+ def __init__(self, name=None):
+ self.name = name
+ self.state = None
+ self.broadcastdomainrange = 'ZONE'
+ self.zoneid = None
+ self.servicelist = []
+ self.devices = []
+
+
+class network(object):
+ def __init__(self):
+ self.displaytext = None
+ self.name = None
+ self.zoneid = None
+ self.acltype = None
+ self.domainid = None
+ self.networkdomain = None
+ self.networkofferingid = None
+ self.ipranges = []
+
+
+class iprange(object):
+ def __init__(self):
+ '''tagged/untagged'''
+ self.gateway = None
+ self.netmask = None
+ self.startip = None
+ self.endip = None
+ self.vlan = None
+ '''for account specific '''
+ self.account = None
+ self.domain = None
+
+
+class primaryStorage(object):
+ def __init__(self):
+ self.name = None
+ self.url = None
+
+
+class secondaryStorage(object):
+ def __init__(self):
+ self.url = None
+ self.provider = None
+ self.details = None
+
+
+class cacheStorage(object):
+ def __init__(self):
+ self.url = None
+ self.provider = None
+ self.details = None
+
+
+class s3(object):
+ def __init__(self):
+ self.accesskey = None
+ self.secretkey = None
+ self.bucket = None
+ self.endpoint = None
+ self.sockettimeout = None
+ self.connectiontimeout = None
+ self.maxerrorrety = None
+ self.usehttps = None
+
+
+class netscaler(object):
+ def __init__(self, hostname=None, username='nsroot', password='nsroot'):
+ self.hostname = hostname
+ self.username = username
+ self.password = password
+ self.networkdevicetype = 'NetscalerVPXLoadBalancer'
+ self.publicinterface = '1/1'
+ self.privateinterface = '1/1'
+ self.numretries = '2'
+ self.lbdevicecapacity = '50'
+ self.lbdevicededicated = 'false'
+
+ def getUrl(self):
+ return repr(self)
+
+ def __repr__(self):
+ req = zip(self.__dict__.keys(), self.__dict__.values())
+ return self.hostname+"?" + "&".join(["=".join([r[0], r[1]])
+ for r in req])
+
+
+class srx(object):
+ def __init__(self, hostname=None, username='root', password='admin'):
+ self.hostname = hostname
+ self.username = username
+ self.password = password
+ self.networkdevicetype = 'JuniperSRXFirewall'
+ self.publicinterface = '1/1'
+ self.privateinterface = '1/1'
+ self.numretries = '2'
+ self.fwdevicededicated = 'false'
+ self.timeout = '300'
+ self.publicnetwork = 'untrusted'
+ self.privatenetwork = 'trusted'
+
+ def getUrl(self):
+ return repr(self)
+
+ def __repr__(self):
+ req = zip(self.__dict__.keys(), self.__dict__.values())
+ return self.hostname+"?" + "&".join(["=".join([r[0], r[1]])
+ for r in req])
+
+
+class bigip(object):
+ def __init__(self, hostname=None, username='root', password='default'):
+ self.hostname = hostname
+ self.username = username
+ self.password = password
+ self.networkdevicetype = 'F5BigIpLoadBalancer'
+ self.publicinterface = '1/1'
+ self.privateinterface = '1/1'
+ self.numretries = '2'
+ self.lbdevicededicated = 'false'
+ self.lbdevicecapacity = '50'
+
+ def getUrl(self):
+ return repr(self)
+
+ def __repr__(self):
+ req = zip(self.__dict__.keys(), self.__dict__.values())
+ return self.hostname+"?" + "&".join(["=".join([r[0], r[1]])
+ for r in req])
+
+
+def getDeviceUrl(obj):
+ req = zip(obj.__dict__.keys(), obj.__dict__.values())
+ if obj.hostname:
+ return "http://" + obj.hostname+"?" + "&".join(["=".join([r[0],
+ r[1]])
+ for r in req])
+ else:
+ return None
+
+
+def describe_setup_in_basic_mode():
+ '''sample code to generate setup configuration file'''
+ zs = cloudstackConfiguration()
+
+ for l in range(1):
+ z = zone()
+ z.dns1 = "8.8.8.8"
+ z.dns2 = "8.8.4.4"
+ z.internaldns1 = "192.168.110.254"
+ z.internaldns2 = "192.168.110.253"
+ z.name = "test"+str(l)
+ z.networktype = 'Basic'
+ z.securitygroupenabled = 'True'
+
+ #If security groups are reqd
+ sgprovider = provider()
+ sgprovider.broadcastdomainrange = 'Pod'
+ sgprovider.name = 'SecurityGroupProvider'
+
+ pn = physical_network()
+ pn.name = "test-network"
+ pn.traffictypes = [traffictype("Guest"), traffictype("Management")]
+ pn.providers.append(sgprovider)
+
+ z.physical_networks.append(pn)
+
+ '''create 10 pods'''
+ for i in range(2):
+ p = pod()
+ p.name = "test" + str(l) + str(i)
+ p.gateway = "192.168.%d.1" % i
+ p.netmask = "255.255.255.0"
+ p.startip = "192.168.%d.150" % i
+ p.endip = "192.168.%d.220" % i
+
+ '''add two pod guest ip ranges'''
+ for j in range(2):
+ ip = iprange()
+ ip.gateway = p.gateway
+ ip.netmask = p.netmask
+ ip.startip = "192.168.%d.%d" % (i, j*20)
+ ip.endip = "192.168.%d.%d" % (i, j*20+10)
+
+ p.guestIpRanges.append(ip)
+
+ '''add 10 clusters'''
+ for j in range(2):
+ c = cluster()
+ c.clustername = "test"+str(l)+str(i) + str(j)
+ c.clustertype = "CloudManaged"
+ c.hypervisor = "Simulator"
+
+ '''add 10 hosts'''
+ for k in range(2):
+ h = host()
+ h.username = "root"
+ h.password = "password"
+ memory = 8*1024*1024*1024
+ localstorage = 1*1024*1024*1024*1024
+ h.url = "http://sim/%d%d%d%d" % (l, i, j, k)
+ c.hosts.append(h)
+
+ '''add 2 primary storages'''
+ for m in range(2):
+ primary = primaryStorage()
+ primary.name = "primary"+str(l) + str(i) + str(j) + str(m)
+ primary.url = "nfs://localhost/path%s" % (str(l) + str(i) +
+ str(j) + str(m))
+ c.primaryStorages.append(primary)
+
+ p.clusters.append(c)
+
+ z.pods.append(p)
+
+ '''add two secondary'''
+ for i in range(5):
+ secondary = secondaryStorage()
+ secondary.url = "nfs://localhost/path"+str(l) + str(i)
+ z.secondaryStorages.append(secondary)
+
+ zs.zones.append(z)
+
+ '''Add one mgt server'''
+ mgt = managementServer()
+ mgt.mgtSvrIp = "localhost"
+ zs.mgtSvr.append(mgt)
+
+ '''Add a database'''
+ db = dbServer()
+ db.dbSvr = "localhost"
+
+ zs.dbSvr = db
+
+ '''add global configuration'''
+ global_settings = {'expunge.delay': '60',
+ 'expunge.interval': '60',
+ 'expunge.workers': '3',
+ }
+ for k, v in global_settings.iteritems():
+ cfg = configuration()
+ cfg.name = k
+ cfg.value = v
+ zs.globalConfig.append(cfg)
+
+ ''''add loggers'''
+ testClientLogger = logger()
+ testClientLogger.name = "TestClient"
+ testClientLogger.file = "/tmp/testclient.log"
+
+ testCaseLogger = logger()
+ testCaseLogger.name = "TestCase"
+ testCaseLogger.file = "/tmp/testcase.log"
+
+ zs.logger.append(testClientLogger)
+ zs.logger.append(testCaseLogger)
+
+ return zs
+
+
+def describe_setup_in_eip_mode():
+ """
+ Setting up an EIP/ELB enabled zone with netscaler provider
+ """
+ zs = cloudstackConfiguration()
+
+ for l in range(1):
+ z = zone()
+ z.dns1 = "8.8.8.8"
+ z.dns2 = "8.8.4.4"
+ z.internaldns1 = "192.168.110.254"
+ z.internaldns2 = "192.168.110.253"
+ z.name = "test"+str(l)
+ z.networktype = 'Basic'
+
+ ips = iprange()
+ ips.vlan = "49"
+ ips.startip = "10.147.49.200"
+ ips.endip = "10.147.49.250"
+ ips.gateway = "10.147.49.1"
+ ips.netmask = "255.255.255.0"
+ z.ipranges.append(ips)
+
+ #If security groups are reqd
+ sgprovider = provider()
+ sgprovider.broadcastdomainrange = 'Pod'
+ sgprovider.name = 'SecurityGroupProvider'
+
+ nsprovider = provider()
+ nsprovider.name = 'Netscaler'
+ ns = netscaler()
+ ns.hostname = '10.147.40.100'
+ nsprovider.devices.append(ns)
+
+ pn = physical_network()
+ pn.name = "test-network"
+ pn.traffictypes = [traffictype("Guest",
+ {"xen": "cloud-guest"}),
+ traffictype("Management"),
+ traffictype("Public", {"xen": "cloud-public"})]
+ pn.providers.extend([sgprovider, nsprovider])
+ z.physical_networks.append(pn)
+
+ '''create 10 pods'''
+ for i in range(2):
+ p = pod()
+ p.name = "test" + str(l) + str(i)
+ p.gateway = "192.168.%d.1" % i
+ p.netmask = "255.255.255.0"
+ p.startip = "192.168.%d.150" % i
+ p.endip = "192.168.%d.220" % i
+
+ '''add two pod guest ip ranges'''
+ for j in range(2):
+ ip = iprange()
+ ip.gateway = p.gateway
+ ip.netmask = p.netmask
+ ip.startip = "192.168.%d.%d" % (i, j*20)
+ ip.endip = "192.168.%d.%d" % (i, j*20+10)
+
+ p.guestIpRanges.append(ip)
+
+ '''add 10 clusters'''
+ for j in range(2):
+ c = cluster()
+ c.clustername = "test"+str(l)+str(i) + str(j)
+ c.clustertype = "CloudManaged"
+ c.hypervisor = "Simulator"
+
+ '''add 10 hosts'''
+ for k in range(2):
+ h = host()
+ h.username = "root"
+ h.password = "password"
+ h.url = "http://Sim/%d%d%d%d" % (l, i, j, k)
+ c.hosts.append(h)
+
+ '''add 2 primary storages'''
+ for m in range(2):
+ primary = primaryStorage()
+ primary.name = "primary"+str(l) + str(i) + str(j) + str(m)
+ primary.url = "nfs://localhost/path%s" % (str(l) + str(i)
+ + str(j)
+ + str(m))
+ c.primaryStorages.append(primary)
+
+ p.clusters.append(c)
+
+ z.pods.append(p)
+
+ '''add two secondary'''
+ for i in range(5):
+ secondary = secondaryStorage()
+ secondary.url = "nfs://localhost/path"+str(l) + str(i)
+ z.secondaryStorages.append(secondary)
+
+ zs.zones.append(z)
+
+ '''Add one mgt server'''
+ mgt = managementServer()
+ mgt.mgtSvrIp = "localhost"
+ zs.mgtSvr.append(mgt)
+
+ '''Add a database'''
+ db = dbServer()
+ db.dbSvr = "localhost"
+
+ zs.dbSvr = db
+
+ '''add global configuration'''
+ global_settings = {'expunge.delay': '60',
+ 'expunge.interval': '60',
+ 'expunge.workers': '3',
+ }
+ for k, v in global_settings.iteritems():
+ cfg = configuration()
+ cfg.name = k
+ cfg.value = v
+ zs.globalConfig.append(cfg)
+
+ ''''add loggers'''
+ testClientLogger = logger()
+ testClientLogger.name = "TestClient"
+ testClientLogger.file = "/tmp/testclient.log"
+
+ testCaseLogger = logger()
+ testCaseLogger.name = "TestCase"
+ testCaseLogger.file = "/tmp/testcase.log"
+
+ zs.logger.append(testClientLogger)
+ zs.logger.append(testCaseLogger)
+
+ return zs
+
+
+def describe_setup_in_advanced_mode():
+ '''sample code to generate setup configuration file'''
+ zs = cloudstackConfiguration()
+
+ for l in range(1):
+ z = zone()
+ z.dns1 = "8.8.8.8"
+ z.dns2 = "8.8.4.4"
+ z.internaldns1 = "192.168.110.254"
+ z.internaldns2 = "192.168.110.253"
+ z.name = "test"+str(l)
+ z.networktype = 'Advanced'
+ z.guestcidraddress = "10.1.1.0/24"
+ z.vlan = "100-2000"
+
+ pn = physical_network()
+ pn.name = "test-network"
+ pn.traffictypes = [traffictype("Guest"), traffictype("Management"),
+ traffictype("Public")]
+
+ vpcprovider = provider('VpcVirtualRouter')
+
+ nsprovider = provider('Netscaler')
+ nsprovider.devices.append(netscaler(hostname='10.147.40.100'))
+
+ srxprovider = provider('JuniperSRX')
+ srxprovider.devices.append(srx(hostname='10.147.40.3'))
+
+ f5provider = provider('F5BigIp')
+ f5provider.devices.append(bigip(hostname='10.147.40.3'))
+
+ pn.providers.extend([vpcprovider, nsprovider, srxprovider, f5provider])
+ z.physical_networks.append(pn)
+
+ '''create 10 pods'''
+ for i in range(2):
+ p = pod()
+ p.name = "test" + str(l) + str(i)
+ p.gateway = "192.168.%d.1" % i
+ p.netmask = "255.255.255.0"
+ p.startip = "192.168.%d.200" % i
+ p.endip = "192.168.%d.220" % i
+
+ '''add 10 clusters'''
+ for j in range(2):
+ c = cluster()
+ c.clustername = "test"+str(l)+str(i) + str(j)
+ c.clustertype = "CloudManaged"
+ c.hypervisor = "Simulator"
+
+ '''add 10 hosts'''
+ for k in range(2):
+ h = host()
+ h.username = "root"
+ h.password = "password"
+ memory = 8 * 1024 * 1024 * 1024
+ localstorage = 1 * 1024 * 1024 * 1024 * 1024
+ #h.url = "http://sim/%d%d%d%d/cpucore=1&cpuspeed=8000&\
+ # memory=%d&localstorage=%d"%(l, i, j, k, memory,
+ # localstorage)
+ h.url = "http://sim/%d%d%d%d" % (l, i, j, k)
+ c.hosts.append(h)
+
+ '''add 2 primary storages'''
+ for m in range(2):
+ primary = primaryStorage()
+ primary.name = "primary"+str(l) + str(i) + str(j) + str(m)
+ #primary.url = "nfs://localhost/path%s/size=%d" %
+ # (str(l) + str(i) + str(j) + str(m), size)
+ primary.url = "nfs://localhost/path%s" % (str(l) + str(i)
+ + str(j)
+ + str(m))
+ c.primaryStorages.append(primary)
+
+ p.clusters.append(c)
+
+ z.pods.append(p)
+
+ '''add two secondary'''
+ for i in range(5):
+ secondary = secondaryStorage()
+ secondary.url = "nfs://localhost/path"+str(l) + str(i)
+ z.secondaryStorages.append(secondary)
+
+ '''add default public network'''
+ ips = iprange()
+ ips.vlan = "26"
+ ips.startip = "172.16.26.2"
+ ips.endip = "172.16.26.100"
+ ips.gateway = "172.16.26.1"
+ ips.netmask = "255.255.255.0"
+ z.ipranges.append(ips)
+
+ zs.zones.append(z)
+
+ '''Add one mgt server'''
+ mgt = managementServer()
+ mgt.mgtSvrIp = "localhost"
+ zs.mgtSvr.append(mgt)
+
+ '''Add a database'''
+ db = dbServer()
+ db.dbSvr = "localhost"
+
+ zs.dbSvr = db
+
+ '''add global configuration'''
+ global_settings = {'expunge.delay': '60',
+ 'expunge.interval': '60',
+ 'expunge.workers': '3',
+ }
+ for k, v in global_settings.iteritems():
+ cfg = configuration()
+ cfg.name = k
+ cfg.value = v
+ zs.globalConfig.append(cfg)
+
+ ''''add loggers'''
+ testClientLogger = logger()
+ testClientLogger.name = "TestClient"
+ testClientLogger.file = "/tmp/testclient.log"
+
+ testCaseLogger = logger()
+ testCaseLogger.name = "TestCase"
+ testCaseLogger.file = "/tmp/testcase.log"
+
+ zs.logger.append(testClientLogger)
+ zs.logger.append(testCaseLogger)
+
+ return zs
+
+'''sample code to generate setup configuration file'''
+
+
+def describe_setup_in_advancedsg_mode():
+ zs = cloudstackConfiguration()
+
+ for l in range(1):
+ z = zone()
+ z.dns1 = "8.8.8.8"
+ z.dns2 = "8.8.4.4"
+ z.internaldns1 = "192.168.110.254"
+ z.internaldns2 = "192.168.110.253"
+ z.name = "test"+str(l)
+ z.networktype = 'Advanced'
+ z.vlan = "100-2000"
+ z.securitygroupenabled = "true"
+
+ pn = physical_network()
+ pn.name = "test-network"
+ pn.traffictypes = [traffictype("Guest"), traffictype("Management")]
+
+ #If security groups are reqd
+ sgprovider = provider()
+ sgprovider.broadcastdomainrange = 'ZONE'
+ sgprovider.name = 'SecurityGroupProvider'
+
+ pn.providers.append(sgprovider)
+ z.physical_networks.append(pn)
+
+ '''create 10 pods'''
+ for i in range(2):
+ p = pod()
+ p.name = "test" + str(l) + str(i)
+ p.gateway = "192.168.%d.1" % i
+ p.netmask = "255.255.255.0"
+ p.startip = "192.168.%d.200" % i
+ p.endip = "192.168.%d.220" % i
+
+ '''add 10 clusters'''
+ for j in range(2):
+ c = cluster()
+ c.clustername = "test"+str(l)+str(i) + str(j)
+ c.clustertype = "CloudManaged"
+ c.hypervisor = "Simulator"
+
+ '''add 10 hosts'''
+ for k in range(2):
+ h = host()
+ h.username = "root"
+ h.password = "password"
+ memory = 8 * 1024 * 1024 * 1024
+ localstorage = 1 * 1024 * 1024 * 1024 * 1024
+ #h.url = "http://sim/%d%d%d%d/cpucore=1&cpuspeed=8000&\
+ #memory=%d&localstorage=%d" % (l, i, j, k, memory,
+ #localstorage)
+ h.url = "http://sim/%d%d%d%d" % (l, i, j, k)
+ c.hosts.append(h)
+
+ '''add 2 primary storages'''
+ for m in range(2):
+ primary = primaryStorage()
+ primary.name = "primary"+str(l) + str(i) + str(j) + str(m)
+ #primary.url = "nfs://localhost/path%s/size=%d" % \
+ #(str(l) + str(i) + str(j) + str(m), size)
+ primary.url = "nfs://localhost/path%s" % \
+ (str(l) + str(i) + str(j) + str(m))
+ c.primaryStorages.append(primary)
+
+ p.clusters.append(c)
+
+ z.pods.append(p)
+
+ '''add two secondary'''
+ for i in range(5):
+ secondary = secondaryStorage()
+ secondary.url = "nfs://localhost/path"+str(l) + str(i)
+ z.secondaryStorages.append(secondary)
+
+ '''add default guest network'''
+ ips = iprange()
+ ips.vlan = "26"
+ ips.startip = "172.16.26.2"
+ ips.endip = "172.16.26.100"
+ ips.gateway = "172.16.26.1"
+ ips.netmask = "255.255.255.0"
+ z.ipranges.append(ips)
+
+ zs.zones.append(z)
+
+ '''Add one mgt server'''
+ mgt = managementServer()
+ mgt.mgtSvrIp = "localhost"
+ zs.mgtSvr.append(mgt)
+
+ '''Add a database'''
+ db = dbServer()
+ db.dbSvr = "localhost"
+
+ zs.dbSvr = db
+
+ '''add global configuration'''
+ global_settings = {'expunge.delay': '60',
+ 'expunge.interval': '60',
+ 'expunge.workers': '3',
+ }
+ for k, v in global_settings.iteritems():
+ cfg = configuration()
+ cfg.name = k
+ cfg.value = v
+ zs.globalConfig.append(cfg)
+
+ ''''add loggers'''
+ testClientLogger = logger()
+ testClientLogger.name = "TestClient"
+ testClientLogger.file = "/tmp/testclient.log"
+
+ testCaseLogger = logger()
+ testCaseLogger.name = "TestCase"
+ testCaseLogger.file = "/tmp/testcase.log"
+
+ zs.logger.append(testClientLogger)
+ zs.logger.append(testCaseLogger)
+
+ return zs
+
+
+def generate_setup_config(config, file=None):
+ describe = config
+ if file is None:
+ return json.dumps(jsonHelper.jsonDump.dump(describe))
+ else:
+ fp = open(file, 'w')
+ json.dump(jsonHelper.jsonDump.dump(describe), fp, indent=4)
+ fp.close()
+
+
+def get_setup_config(file):
+ if not os.path.exists(file):
+ raise IOError("config file %s not found. \
+please specify a valid config file" % file)
+ config = cloudstackConfiguration()
+ configLines = []
+ with open(file, 'r') as fp:
+ for line in fp:
+ ws = line.strip()
+ if not ws.startswith("#"):
+ configLines.append(ws)
+ config = json.loads("\n".join(configLines))
+ return jsonHelper.jsonLoader(config)
+
+if __name__ == "__main__":
+ parser = OptionParser()
+
+ parser.add_option("-i", "--input", action="store", default=None,
+ dest="inputfile", help="input file")
+ parser.add_option("-a", "--advanced", action="store_true", default=False,
+ dest="advanced", help="use advanced networking")
+ parser.add_option("-s", "--advancedsg", action="store_true", default=False,
+ dest="advancedsg", help="use advanced networking \
+with security groups")
+ 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()
+
+ if options.inputfile:
+ config = get_setup_config(options.inputfile)
+ if options.advanced:
+ config = describe_setup_in_advanced_mode()
+ elif options.advancedsg:
+ config = describe_setup_in_advancedsg_mode()
+ else:
+ config = describe_setup_in_basic_mode()
+
+ generate_setup_config(config, options.output)
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ec00a6fb/tools/marvin/build/lib/marvin/dbConnection.py
----------------------------------------------------------------------
diff --git a/tools/marvin/build/lib/marvin/dbConnection.py b/tools/marvin/build/lib/marvin/dbConnection.py
new file mode 100644
index 0000000..99014ab
--- /dev/null
+++ b/tools/marvin/build/lib/marvin/dbConnection.py
@@ -0,0 +1,86 @@
+# 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 mysql
+import contextlib
+from mysql import connector
+from mysql.connector import errors
+from contextlib import closing
+import cloudstackException
+import sys
+import os
+
+
+class dbConnection(object):
+ def __init__(self, host="localhost", port=3306, user='cloud',
+ passwd='cloud', db='cloud'):
+ self.host = host
+ self.port = port
+ self.user = str(user) # Workaround: http://bugs.mysql.com/?id=67306
+ self.passwd = passwd
+ self.database = db
+
+ def execute(self, sql=None, params=None):
+ if sql is None:
+ return None
+
+ resultRow = []
+ with contextlib.\
+ closing(mysql.connector.connect(host=str(self.host),
+ port=int(self.port),
+ user=str(self.user),
+ password=str(self.passwd),
+ db=str(self.database))) as conn:
+ conn.autocommit = True
+ with contextlib.closing(conn.cursor(buffered=True)) as cursor:
+ cursor.execute(sql, params)
+ try:
+ resultRow = cursor.fetchall()
+ except errors.InterfaceError:
+ #Raised on empty result - DML
+ resultRow = []
+ return resultRow
+
+ def executeSqlFromFile(self, fileName=None):
+ if fileName is None:
+ raise cloudstackException.\
+ InvalidParameterException("file can't not none")
+
+ if not os.path.exists(fileName):
+ raise cloudstackException.\
+ InvalidParameterException("%s not exists" % fileName)
+
+ sqls = open(fileName, "r").read()
+ return self.execute(sqls)
+
+if __name__ == "__main__":
+ db = dbConnection()
+ '''
+ try:
+
+ result = db.executeSqlFromFile("/tmp/server-setup.sql")
+ if result is not None:
+ for r in result:
+ print r[0], r[1]
+ except cloudstackException.dbException, e:
+ print e
+ '''
+ print db.execute("update vm_template set name='fjkd' where id=200")
+ for i in range(10):
+ result = db.execute("select job_status, created, \
+last_updated from async_job where id=%d" % i)
+ print result