http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d002c52a/tools/marvin/marvin/lib/cloudstack/account.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/lib/cloudstack/account.py 
b/tools/marvin/marvin/lib/cloudstack/account.py
new file mode 100644
index 0000000..f3eaf18
--- /dev/null
+++ b/tools/marvin/marvin/lib/cloudstack/account.py
@@ -0,0 +1,85 @@
+# 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.
+
+
+from marvin.cloudstackAPI import 
createAccount,deleteAccount,listAccounts,disableAccount
+
+from marvin.lib.cloudstack.utils import random_gen
+
+class Account:
+    """ Account Life Cycle """
+    def __init__(self, items):
+        self.__dict__.update(items)
+
+    @classmethod
+    def create(cls, apiclient, services, admin=False, domainid=None):
+        """Creates an account"""
+        cmd = createAccount.createAccountCmd()
+
+        # 0 - User, 1 - Root Admin, 2 - Domain Admin
+        cmd.accounttype = 2 if (admin and domainid) else int(admin)
+
+        cmd.email = services["email"]
+        cmd.firstname = services["firstname"]
+        cmd.lastname = services["lastname"]
+
+        cmd.password = services["password"]
+        username = services["username"]
+        # Limit account username to 99 chars to avoid failure
+        # 6 chars start string + 85 chars apiclientid + 6 chars random string 
+ 2 chars joining hyphen string = 99
+        username = username[:6]
+        apiclientid = apiclient.id[-85:] if len(apiclient.id) > 85 else 
apiclient.id
+        cmd.username = "-".join([username,
+                             random_gen(id=apiclientid, size=6)])
+
+        if "accountUUID" in services:
+            cmd.accountid = "-".join([services["accountUUID"], random_gen()])
+
+        if "userUUID" in services:
+            cmd.userid = "-".join([services["userUUID"], random_gen()])
+
+
+        if domainid:
+            cmd.domainid = domainid
+        account = apiclient.createAccount(cmd)
+
+        return Account(account.__dict__)
+
+    def delete(self, apiclient):
+        """Delete an account"""
+        cmd = deleteAccount.deleteAccountCmd()
+        cmd.id = self.id
+        apiclient.deleteAccount(cmd)
+
+    @classmethod
+    def list(cls, apiclient, **kwargs):
+        """Lists accounts and provides detailed account information for
+        listed accounts"""
+
+        cmd = listAccounts.listAccountsCmd()
+        [setattr(cmd, k, v) for k, v in kwargs.items()]
+        if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+            cmd.listall = True
+        return(apiclient.listAccounts(cmd))
+
+    def disable(self, apiclient, lock=False):
+        """Disable an account"""
+        cmd = disableAccount.disableAccountCmd()
+        cmd.id = self.id
+        cmd.lock = lock
+        apiclient.disableAccount(cmd)
+

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d002c52a/tools/marvin/marvin/lib/cloudstack/autoscale.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/lib/cloudstack/autoscale.py 
b/tools/marvin/marvin/lib/cloudstack/autoscale.py
new file mode 100644
index 0000000..2d585ef
--- /dev/null
+++ b/tools/marvin/marvin/lib/cloudstack/autoscale.py
@@ -0,0 +1,175 @@
+# 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.
+
+from marvin.cloudstackAPI import 
listCounters,createCondition,listConditions,listAutoScalePolicies,createAutoScalePolicy,updateAutoScalePolicy,listAutoScaleVmProfiles,createAutoScaleVmProfile,\
+    
updateAutoScaleVmProfile,createAutoScaleVmGroup,listAutoScaleVmGroups,enableAutoScaleVmGroup,disableAutoScaleVmGroup,updateAutoScaleVmGroup
+class Autoscale:
+
+    """Manage Auto scale"""
+
+    def __init__(self, items):
+        self.__dict__.update(items)
+
+    @classmethod
+    def listCounters(cls, apiclient, **kwargs):
+        """Lists all available Counters."""
+
+        cmd = listCounters.listCountersCmd()
+        [setattr(cmd, k, v) for k, v in kwargs.items()]
+        return(apiclient.listCounters(cmd))
+
+    @classmethod
+    def createCondition(cls, apiclient, counterid, relationaloperator, 
threshold):
+        """creates condition."""
+
+        cmd = createCondition.createConditionCmd()
+        cmd.counterid = counterid
+        cmd.relationaloperator = relationaloperator
+        cmd.threshold = threshold
+        return(apiclient.createCondition(cmd))
+
+    @classmethod
+    def listConditions(cls, apiclient, **kwargs):
+        """Lists all available Conditions."""
+
+        cmd = listConditions.listConditionsCmd()
+        [setattr(cmd, k, v) for k, v in kwargs.items()]
+        return(apiclient.listConditions(cmd))
+
+    @classmethod
+    def listAutoscalePolicies(cls, apiclient, **kwargs):
+        """Lists all available Autoscale Policies."""
+
+        cmd = listAutoScalePolicies.listAutoScalePoliciesCmd()
+        [setattr(cmd, k, v) for k, v in kwargs.items()]
+        return(apiclient.listAutoScalePolicies(cmd))
+
+    @classmethod
+    def createAutoscalePolicy(cls, apiclient, action, conditionids, duration, 
quiettime=None):
+        """creates condition."""
+
+        cmd = createAutoScalePolicy.createAutoScalePolicyCmd()
+        cmd.action = action
+        cmd.conditionids = conditionids
+        cmd.duration = duration
+        if quiettime:
+            cmd.quiettime = quiettime
+
+        return(apiclient.createAutoScalePolicy(cmd))
+
+    @classmethod
+    def updateAutoscalePolicy(cls, apiclient, id, **kwargs):
+        """Updates Autoscale Policy."""
+
+        cmd = updateAutoScalePolicy.updateAutoScalePolicyCmd()
+        cmd.id = id
+        [setattr(cmd, k, v) for k, v in kwargs.items()]
+        return(apiclient.updateAutoScalePolicy(cmd))
+
+    @classmethod
+    def listAutoscaleVmPofiles(cls, apiclient, **kwargs):
+        """Lists all available AutoscaleVM  Profiles."""
+
+        cmd = listAutoScaleVmProfiles.listAutoScaleVmProfilesCmd()
+        [setattr(cmd, k, v) for k, v in kwargs.items()]
+        return(apiclient.listAutoScaleVmProfiles(cmd))
+
+    @classmethod
+    def createAutoscaleVmProfile(cls, apiclient, serviceofferingid, zoneid, 
templateid,
+                                 autoscaleuserid=None, 
destroyvmgraceperiod=None, counterparam=None):
+        """creates Autoscale VM Profile."""
+
+        cmd = createAutoScaleVmProfile.createAutoScaleVmProfileCmd()
+        cmd.serviceofferingid = serviceofferingid
+        cmd.zoneid = zoneid
+        cmd.templateid = templateid
+        if autoscaleuserid:
+            cmd.autoscaleuserid = autoscaleuserid
+
+        if destroyvmgraceperiod:
+            cmd.destroyvmgraceperiod = destroyvmgraceperiod
+
+        if counterparam:
+            for name, value in counterparam.items():
+                cmd.counterparam.append({
+                    'name': name,
+                    'value': value
+                })
+
+        return(apiclient.createAutoScaleVmProfile(cmd))
+
+    @classmethod
+    def updateAutoscaleVMProfile(cls, apiclient, id, **kwargs):
+        """Updates Autoscale Policy."""
+
+        cmd = updateAutoScaleVmProfile.updateAutoScaleVmProfileCmd()
+        cmd.id = id
+        [setattr(cmd, k, v) for k, v in kwargs.items()]
+        return(apiclient.updateAutoScaleVmProfile(cmd))
+
+    @classmethod
+    def createAutoscaleVmGroup(cls, apiclient, lbruleid, minmembers, 
maxmembers,
+                                 scaledownpolicyids, scaleuppolicyids, 
vmprofileid, interval=None):
+        """creates Autoscale VM Group."""
+
+        cmd = createAutoScaleVmGroup.createAutoScaleVmGroupCmd()
+        cmd.lbruleid = lbruleid
+        cmd.minmembers = minmembers
+        cmd.maxmembers = maxmembers
+        cmd.scaledownpolicyids = scaledownpolicyids
+        cmd.scaleuppolicyids = scaleuppolicyids
+        cmd.vmprofileid = vmprofileid
+        if interval:
+            cmd.interval = interval
+
+        return(apiclient.createAutoScaleVmGroup(cmd))
+
+    @classmethod
+    def listAutoscaleVmGroup(cls, apiclient, **kwargs):
+        """Lists all available AutoscaleVM  Group."""
+
+        cmd = listAutoScaleVmGroups.listAutoScaleVmGroupsCmd()
+        [setattr(cmd, k, v) for k, v in kwargs.items()]
+        return(apiclient.listAutoScaleVmGroups(cmd))
+
+    @classmethod
+    def enableAutoscaleVmGroup(cls, apiclient, id, **kwargs):
+        """Enables AutoscaleVM  Group."""
+
+        cmd = enableAutoScaleVmGroup.enableAutoScaleVmGroupCmd()
+        cmd.id = id
+        [setattr(cmd, k, v) for k, v in kwargs.items()]
+        return(apiclient.enableAutoScaleVmGroup(cmd))
+
+    @classmethod
+    def disableAutoscaleVmGroup(cls, apiclient, id, **kwargs):
+        """Disables AutoscaleVM  Group."""
+
+        cmd = disableAutoScaleVmGroup.disableAutoScaleVmGroupCmd()
+        cmd.id = id
+        [setattr(cmd, k, v) for k, v in kwargs.items()]
+        return(apiclient.disableAutoScaleVmGroup(cmd))
+
+    @classmethod
+    def updateAutoscaleVMGroup(cls, apiclient, id, **kwargs):
+        """Updates Autoscale VM Group."""
+
+        cmd = updateAutoScaleVmGroup.updateAutoScaleVmGroupCmd()
+        cmd.id = id
+        [setattr(cmd, k, v) for k, v in kwargs.items()]
+        return(apiclient.updateAutoScaleVmGroup(cmd))
+

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d002c52a/tools/marvin/marvin/lib/cloudstack/base.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/lib/cloudstack/base.py 
b/tools/marvin/marvin/lib/cloudstack/base.py
new file mode 100755
index 0000000..3b48b24
--- /dev/null
+++ b/tools/marvin/marvin/lib/cloudstack/base.py
@@ -0,0 +1,336 @@
+# 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.
+
+""" Base class for all Cloudstack resources
+    -Virtual machine, Volume, Snapshot etc
+"""
+
+from marvin.cloudstackAPI import *
+# Import System modules
+
+class Hypervisor:
+    """Manage Hypervisor"""
+
+    def __init__(self, items):
+        self.__dict__.update(items)
+
+    @classmethod
+    def list(cls, apiclient, **kwargs):
+        """Lists hypervisors"""
+
+        cmd = listHypervisors.listHypervisorsCmd()
+        [setattr(cmd, k, v) for k, v in kwargs.items()]
+        if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+            cmd.listall = True
+        return(apiclient.listHypervisors(cmd))
+
+
+class Configurations:
+    """Manage Configuration"""
+
+    @classmethod
+    def update(cls, apiclient, name, value=None):
+        """Updates the specified configuration"""
+
+        cmd = updateConfiguration.updateConfigurationCmd()
+        cmd.name = name
+        cmd.value = value
+        apiclient.updateConfiguration(cmd)
+
+    @classmethod
+    def list(cls, apiclient, **kwargs):
+        """Lists configurations"""
+
+        cmd = listConfigurations.listConfigurationsCmd()
+        [setattr(cmd, k, v) for k, v in kwargs.items()]
+        if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+            cmd.listall = True
+        return(apiclient.listConfigurations(cmd))
+
+    @classmethod
+    def listCapabilities(cls, apiclient, **kwargs):
+        """Lists capabilities"""
+        cmd = listCapabilities.listCapabilitiesCmd()
+        [setattr(cmd, k, v) for k, v in kwargs.items()]
+        return(apiclient.listCapabilities(cmd))
+
+
+
+class Tag:
+    """Manage tags"""
+
+    def __init__(self, items):
+        self.__dict__.update(items)
+
+    @classmethod
+    def create(cls, apiclient, resourceIds, resourceType, tags):
+        """Create tags"""
+
+        cmd = createTags.createTagsCmd()
+        cmd.resourceIds = resourceIds
+        cmd.resourcetype = resourceType
+        cmd.tags = []
+        for key, value in tags.items():
+            cmd.tags.append({
+                'key': key,
+                'value': value
+            })
+        return Tag(apiclient.createTags(cmd).__dict__)
+
+    def delete(self, apiclient, resourceIds, resourceType, tags):
+        """Delete tags"""
+
+        cmd = deleteTags.deleteTagsCmd()
+        cmd.resourceIds = resourceIds
+        cmd.resourcetype = resourceType
+        cmd.tags = []
+        for key, value in tags.items():
+            cmd.tags.append({
+                'key': key,
+                'value': value
+            })
+        apiclient.deleteTags(cmd)
+
+    @classmethod
+    def list(cls, apiclient, **kwargs):
+        """List all tags matching the criteria"""
+
+        cmd = listTags.listTagsCmd()
+        [setattr(cmd, k, v) for k, v in kwargs.items()]
+        if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+            cmd.listall = True
+        return(apiclient.listTags(cmd))
+
+
+class AffinityGroup:
+    def __init__(self, items):
+        self.__dict__.update(items)
+
+    @classmethod
+    def create(cls, apiclient, aff_grp, account=None, domainid=None):
+        cmd = createAffinityGroup.createAffinityGroupCmd()
+        cmd.name = aff_grp['name']
+        cmd.displayText = aff_grp['name']
+        cmd.type = aff_grp['type']
+        if account:
+            cmd.account = account
+        if domainid:
+            cmd.domainid = domainid
+        return AffinityGroup(apiclient.createAffinityGroup(cmd).__dict__)
+
+    def update(self, apiclient):
+        pass
+
+    def delete(self, apiclient):
+        cmd = deleteAffinityGroup.deleteAffinityGroupCmd()
+        cmd.id = self.id
+        return apiclient.deleteAffinityGroup(cmd)
+
+    @classmethod
+    def list(cls, apiclient, **kwargs):
+        cmd = listAffinityGroups.listAffinityGroupsCmd()
+        [setattr(cmd, k, v) for k, v in kwargs.items()]
+        if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+            cmd.listall = True
+        return apiclient.listAffinityGroups(cmd)
+
+
+
+
+class VNMC:
+    """Manage VNMC lifecycle"""
+    def __init__(self, items):
+        self.__dict__.update(items)
+
+    def create(cls, apiclient, hostname, username, password,
+               physicalnetworkid):
+        """Registers VNMC appliance"""
+
+        cmd = addCiscoVnmcResource.addCiscoVnmcResourceCmd()
+        cmd.hostname = hostname
+        cmd.username = username
+        cmd.password = password
+        cmd.physicalnetworkid = physicalnetworkid
+        return VNMC(apiclient.addCiscoVnmcResource(cmd))
+
+    def delete(self, apiclient):
+        """Removes VNMC appliance"""
+
+        cmd = deleteCiscoVnmcResource.deleteCiscoVnmcResourceCmd()
+        cmd.resourceid = self.resourceid
+        return apiclient.deleteCiscoVnmcResource(cmd)
+
+    @classmethod
+    def list(cls, apiclient, **kwargs):
+        """List VNMC appliances"""
+
+        cmd = listCiscoVnmcResources.listCiscoVnmcResourcesCmd()
+        [setattr(cmd, k, v) for k, v in kwargs.items()]
+        if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+            cmd.listall = True
+        return(apiclient.listCiscoVnmcResources(cmd))
+
+
+class SSHKeyPair:
+    """Manage SSH Key pairs"""
+
+    def __init__(self, items, services):
+        self.__dict__.update(items)
+
+    @classmethod
+    def create(cls, apiclient, name=None, account=None,
+               domainid=None, projectid=None):
+        """Creates SSH keypair"""
+        cmd = createSSHKeyPair.createSSHKeyPairCmd()
+        cmd.name = name
+        if account is not None:
+            cmd.account = account
+        if domainid is not None:
+            cmd.domainid = domainid
+        if projectid is not None:
+            cmd.projectid = projectid
+        return (apiclient.createSSHKeyPair(cmd))
+
+    @classmethod
+    def register(cls, apiclient, name, publickey):
+        """Registers SSH keypair"""
+        cmd = registerSSHKeyPair.registerSSHKeyPairCmd()
+        cmd.name = name
+        cmd.publickey = publickey
+        return (apiclient.registerSSHKeyPair(cmd))
+
+    def delete(self, apiclient):
+        """Delete SSH key pair"""
+        cmd = deleteSSHKeyPair.deleteSSHKeyPairCmd()
+        cmd.name = self.name
+        apiclient.deleteSSHKeyPair(cmd)
+
+    @classmethod
+    def list(cls, apiclient, **kwargs):
+        """List all SSH key pairs"""
+        cmd = listSSHKeyPairs.listSSHKeyPairsCmd()
+        [setattr(cmd, k, v) for k, v in kwargs.items()]
+        if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+            cmd.listall = True
+        return(apiclient.listSSHKeyPairs(cmd))
+
+
+class Capacities:
+    """Manage Capacities"""
+
+    @classmethod
+    def list(cls, apiclient, **kwargs):
+        """Lists capacities"""
+
+        cmd = listCapacity.listCapacityCmd()
+        [setattr(cmd, k, v) for k, v in kwargs.items()]
+        if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+            cmd.listall = True
+        return(apiclient.listCapacity(cmd))
+
+
+class Alert:
+    """Manage alerts"""
+
+    @classmethod
+    def list(cls, apiclient, **kwargs):
+        """Lists alerts"""
+
+        cmd = listAlerts.listAlertsCmd()
+        [setattr(cmd, k, v) for k, v in kwargs.items()]
+        if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+            cmd.listall = True
+        return(apiclient.listAlerts(cmd))
+
+
+class Resources:
+    """Manage resource limits"""
+
+    def __init__(self, items, services):
+        self.__dict__.update(items)
+
+    @classmethod
+    def list(cls, apiclient, **kwargs):
+        """Lists resource limits"""
+
+        cmd = listResourceLimits.listResourceLimitsCmd()
+        [setattr(cmd, k, v) for k, v in kwargs.items()]
+        if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+            cmd.listall = True
+        return(apiclient.listResourceLimits(cmd))
+
+    @classmethod
+    def updateLimit(cls, apiclient, **kwargs):
+        """Updates resource limits"""
+
+        cmd = updateResourceLimit.updateResourceLimitCmd()
+        [setattr(cmd, k, v) for k, v in kwargs.items()]
+        return(apiclient.updateResourceLimit(cmd))
+
+    @classmethod
+    def updateCount(cls, apiclient, **kwargs):
+        """Updates resource count"""
+
+        cmd = updateResourceCount.updateResourceCountCmd()
+        [setattr(cmd, k, v) for k, v in kwargs.items()]
+        return(apiclient.updateResourceCount(cmd))
+
+
+class SimulatorMock:
+    """Manage simulator mock lifecycle"""
+    def __init__(self, items):
+        self.__dict__.update(items)
+
+    @classmethod
+    def create(cls, apiclient, command, zoneid=None, podid=None,
+               clusterid=None, hostid=None, value="result:fail",
+               count=None, jsonresponse=None, method="GET"):
+        """Creates simulator mock"""
+        cmd = configureSimulator.configureSimulatorCmd()
+        cmd.zoneid = zoneid
+        cmd.podid = podid
+        cmd.clusterid = clusterid
+        cmd.hostid = hostid
+        cmd.name = command
+        cmd.value = value
+        cmd.count = count
+        cmd.jsonresponse = jsonresponse
+        try:
+            simulatormock = apiclient.configureSimulator(cmd, method=method)
+            if simulatormock is not None:
+                return SimulatorMock(simulatormock.__dict__)
+        except Exception as e:
+            raise e
+
+    def delete(self, apiclient):
+        """Removes simulator mock"""
+        cmd = cleanupSimulatorMock.cleanupSimulatorMockCmd()
+        cmd.id = self.id
+        return apiclient.cleanupSimulatorMock(cmd)
+
+    def query(self, apiclient):
+        """Queries simulator mock"""
+        cmd = querySimulatorMock.querySimulatorMockCmd()
+        cmd.id = self.id
+        try:
+            simulatormock = apiclient.querySimulatorMock(cmd)
+            if simulatormock is not None:
+                return SimulatorMock(simulatormock.__dict__)
+        except Exception as e:
+            raise e
+
+

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d002c52a/tools/marvin/marvin/lib/cloudstack/cluster.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/lib/cloudstack/cluster.py 
b/tools/marvin/marvin/lib/cloudstack/cluster.py
new file mode 100644
index 0000000..8a58553
--- /dev/null
+++ b/tools/marvin/marvin/lib/cloudstack/cluster.py
@@ -0,0 +1,68 @@
+# 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.
+
+from marvin.cloudstackAPI import addCluster,deleteCluster,listClusters
+class Cluster:
+    """Manage Cluster life cycle"""
+
+    def __init__(self, items):
+        self.__dict__.update(items)
+
+    @classmethod
+    def create(cls, apiclient, services, zoneid=None, podid=None, 
hypervisor=None):
+        """Create Cluster"""
+        cmd = addCluster.addClusterCmd()
+        cmd.clustertype = services["clustertype"]
+        cmd.hypervisor = hypervisor
+
+        if zoneid:
+            cmd.zoneid = zoneid
+        else:
+            cmd.zoneid = services["zoneid"]
+
+        if podid:
+            cmd.podid = podid
+        else:
+            cmd.podid = services["podid"]
+
+        if "username" in services:
+            cmd.username = services["username"]
+        if "password" in services:
+            cmd.password = services["password"]
+        if "url" in services:
+            cmd.url = services["url"]
+        if "clustername" in services:
+            cmd.clustername = services["clustername"]
+
+        return Cluster(apiclient.addCluster(cmd)[0].__dict__)
+
+    def delete(self, apiclient):
+        """Delete Cluster"""
+        cmd = deleteCluster.deleteClusterCmd()
+        cmd.id = self.id
+        apiclient.deleteCluster(cmd)
+        return
+
+    @classmethod
+    def list(cls, apiclient, **kwargs):
+        """List all Clusters matching criteria"""
+
+        cmd = listClusters.listClustersCmd()
+        [setattr(cmd, k, v) for k, v in kwargs.items()]
+        if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+            cmd.listall = True
+        return(apiclient.listClusters(cmd))

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d002c52a/tools/marvin/marvin/lib/cloudstack/common.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/lib/cloudstack/common.py 
b/tools/marvin/marvin/lib/cloudstack/common.py
new file mode 100644
index 0000000..22d17fd
--- /dev/null
+++ b/tools/marvin/marvin/lib/cloudstack/common.py
@@ -0,0 +1,1374 @@
+# 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.
+"""Common functions
+"""
+
+# Import Local Modules
+import random
+
+from marvin.cloudstackAPI import (listConfigurations,
+                                  listPhysicalNetworks,
+                                  listRegions,
+                                  addNetworkServiceProvider,
+                                  updateNetworkServiceProvider,
+                                  listDomains,
+                                  listZones,
+                                  listPods,
+                                  listOsTypes,
+                                  listTemplates,
+                                  updateResourceLimit,
+                                  listRouters,
+                                  listNetworks,
+                                  listClusters,
+                                  listSystemVms,
+                                  listStoragePools,
+                                  listVirtualMachines,
+                                  listLoadBalancerRuleInstances,
+                                  listFirewallRules,
+                                  listVolumes,
+                                  listIsos,
+                                  listAccounts,
+                                  listSnapshotPolicies,
+                                  listDiskOfferings,
+                                  listVlanIpRanges,
+                                  listUsageRecords,
+                                  listNetworkServiceProviders,
+                                  listHosts,
+                                  listPublicIpAddresses,
+                                  listPortForwardingRules,
+                                  listLoadBalancerRules,
+                                  listSnapshots,
+                                  listUsers,
+                                  listEvents,
+                                  listServiceOfferings,
+                                  listVirtualRouterElements,
+                                  listNetworkOfferings,
+                                  listResourceLimits,
+                                  listVPCOfferings)
+from marvin.sshClient import SshClient
+from marvin.codes import (PASS, FAILED, ISOLATED_NETWORK, VPC_NETWORK,
+                          BASIC_ZONE, FAIL, NAT_RULE, STATIC_NAT_RULE,
+                          RESOURCE_PRIMARY_STORAGE, RESOURCE_SECONDARY_STORAGE,
+                          RESOURCE_CPU, RESOURCE_MEMORY)
+from marvin.lib.cloudstack.utils import (validateList, xsplit, 
get_process_status)
+from marvin.lib.cloudstack.network import (PhysicalNetwork,
+                             PublicIPAddress,
+                             NATRule,
+                             StaticNATRule,
+                             NetScaler,
+                             FireWallRule,
+                             Network)
+from marvin.lib.cloudstack.volume import Volume
+from marvin.lib.cloudstack.account import Account
+from marvin.lib.cloudstack.project import Project
+from marvin.lib.cloudstack.snapshot import Snapshot
+from marvin.lib.cloudstack.vm import VirtualMachine
+from marvin.lib.cloudstack.template import Template
+from marvin.lib.cloudstack.host import Host
+from marvin.lib.cloudstack.base import Resources,Configurations
+from marvin.lib.cloudstack.networkoffering import NetworkOffering
+
+
+# Import System modules
+import time
+
+
+def is_config_suitable(apiclient, name, value):
+    """
+    Ensure if the deployment has the expected `value` for the global setting 
`name'
+    @return: true if value is set, else false
+    """
+    configs = Configurations.list(apiclient, name=name)
+    assert(
+        configs is not None and isinstance(
+            configs,
+            list) and len(
+            configs) > 0)
+    return configs[0].value == value
+
+
+def wait_for_cleanup(apiclient, configs=None):
+    """Sleeps till the cleanup configs passed"""
+
+    # Configs list consists of the list of global configs
+    if not isinstance(configs, list):
+        return
+    for config in configs:
+        cmd = listConfigurations.listConfigurationsCmd()
+        cmd.name = config
+        cmd.listall = True
+        try:
+            config_descs = apiclient.listConfigurations(cmd)
+        except Exception as e:
+            raise Exception("Failed to fetch configurations: %s" % e)
+
+        if not isinstance(config_descs, list):
+            raise Exception("List configs didn't returned a valid data")
+
+        config_desc = config_descs[0]
+        # Sleep for the config_desc.value time
+        time.sleep(int(config_desc.value))
+    return
+
+
+def add_netscaler(apiclient, zoneid, NSservice):
+    """ Adds Netscaler device and enables NS provider"""
+
+    cmd = listPhysicalNetworks.listPhysicalNetworksCmd()
+    cmd.zoneid = zoneid
+    physical_networks = apiclient.listPhysicalNetworks(cmd)
+    if isinstance(physical_networks, list):
+        physical_network = physical_networks[0]
+
+    cmd = listNetworkServiceProviders.listNetworkServiceProvidersCmd()
+    cmd.name = 'Netscaler'
+    cmd.physicalnetworkid = physical_network.id
+    nw_service_providers = apiclient.listNetworkServiceProviders(cmd)
+
+    if isinstance(nw_service_providers, list):
+        netscaler_provider = nw_service_providers[0]
+    else:
+        cmd1 = addNetworkServiceProvider.addNetworkServiceProviderCmd()
+        cmd1.name = 'Netscaler'
+        cmd1.physicalnetworkid = physical_network.id
+        netscaler_provider = apiclient.addNetworkServiceProvider(cmd1)
+
+    netscaler = NetScaler.add(
+        apiclient,
+        NSservice,
+        physicalnetworkid=physical_network.id
+    )
+    if netscaler_provider.state != 'Enabled':
+        cmd = updateNetworkServiceProvider.updateNetworkServiceProviderCmd()
+        cmd.id = netscaler_provider.id
+        cmd.state = 'Enabled'
+        apiclient.updateNetworkServiceProvider(cmd)
+
+    return netscaler
+
+
+def get_region(apiclient, region_id=None, region_name=None):
+    '''
+    @name : get_region
+    @Desc : Returns the Region Information for a given region  id or region 
name
+    @Input : region_name: Name of the Region
+             region_id : Id of the region
+    @Output : 1. Region  Information for the passed inputs else first Region
+              2. FAILED In case the cmd failed
+    '''
+    cmd = listRegions.listRegionsCmd()
+    if region_name is not None:
+        cmd.name = region_name
+    if region_id is not None:
+        cmd.id = region_id
+    cmd_out = apiclient.listRegions(cmd)
+    return FAILED if validateList(cmd_out)[0] != PASS else cmd_out[0]
+
+
+def get_domain(apiclient, domain_id=None, domain_name=None):
+    '''
+    @name : get_domain
+    @Desc : Returns the Domain Information for a given domain id or domain name
+    @Input : domain id : Id of the Domain
+             domain_name : Name of the Domain
+    @Output : 1. Domain  Information for the passed inputs else first Domain
+              2. FAILED In case the cmd failed
+    '''
+    cmd = listDomains.listDomainsCmd()
+
+    if domain_name is not None:
+        cmd.name = domain_name
+    if domain_id is not None:
+        cmd.id = domain_id
+    cmd_out = apiclient.listDomains(cmd)
+    if validateList(cmd_out)[0] != PASS:
+        return FAILED
+    return cmd_out[0]
+
+
+def get_zone(apiclient, zone_name=None, zone_id=None):
+    '''
+    @name : get_zone
+    @Desc :Returns the Zone Information for a given zone id or Zone Name
+    @Input : zone_name: Name of the Zone
+             zone_id : Id of the zone
+    @Output : 1. Zone Information for the passed inputs else first zone
+              2. FAILED In case the cmd failed
+    '''
+    cmd = listZones.listZonesCmd()
+    if zone_name is not None:
+        cmd.name = zone_name
+    if zone_id is not None:
+        cmd.id = zone_id
+
+    cmd_out = apiclient.listZones(cmd)
+
+    if validateList(cmd_out)[0] != PASS:
+        return FAILED
+    '''
+    Check if input zone name and zone id is None,
+    then return first element of List Zones command
+    '''
+    return cmd_out[0]
+
+
+def get_pod(apiclient, zone_id=None, pod_id=None, pod_name=None):
+    '''
+    @name : get_pod
+    @Desc :  Returns the Pod Information for a given zone id or Zone Name
+    @Input : zone_id: Id of the Zone
+             pod_name : Name of the Pod
+             pod_id : Id of the Pod
+    @Output : 1. Pod Information for the pod
+              2. FAILED In case the cmd failed
+    '''
+    cmd = listPods.listPodsCmd()
+
+    if pod_name is not None:
+        cmd.name = pod_name
+    if pod_id is not None:
+        cmd.id = pod_id
+    if zone_id is not None:
+        cmd.zoneid = zone_id
+
+    cmd_out = apiclient.listPods(cmd)
+
+    if validateList(cmd_out)[0] != PASS:
+        return FAILED
+    return cmd_out[0]
+def get_template(
+        apiclient, zone_id=None, ostype_desc=None, template_filter="featured", 
template_type='BUILTIN',
+        template_id=None, template_name=None, account=None, domain_id=None, 
project_id=None,
+        hypervisor=None):
+    '''
+    @Name : get_template
+    @Desc : Retrieves the template Information based upon inputs provided
+            Template is retrieved based upon either of the inputs matched
+            condition
+    @Input : returns a template"
+    @Output : FAILED in case of any failure
+              template Information matching the inputs
+    '''
+    cmd = listTemplates.listTemplatesCmd()
+    cmd.templatefilter = template_filter
+    if domain_id is not None:
+        cmd.domainid = domain_id
+    if zone_id is not None:
+        cmd.zoneid = zone_id
+    if template_id is not None:
+        cmd.id = template_id
+    if template_name is not None:
+        cmd.name = template_name
+    if hypervisor is not None:
+        cmd.hypervisor = hypervisor
+    if project_id is not None:
+        cmd.projectid = project_id
+    if account is not None:
+        cmd.account = account
+
+    '''
+    Get the Templates pertaining to the inputs provided
+    '''
+    list_templatesout = apiclient.listTemplates(cmd)
+    if validateList(list_templatesout)[0] != PASS:
+        return FAILED
+
+    for template in list_templatesout:
+        if template.isready and template.templatetype == template_type:
+            return template
+    '''
+    Return default first template, if no template matched
+    '''
+    return list_templatesout[0]
+
+
+
+def get_windows_template(
+        apiclient, zone_id=None, ostype_desc=None, template_filter="featured", 
template_type='USER',
+        template_id=None, template_name=None, account=None, domain_id=None, 
project_id=None,
+        hypervisor=None):
+    '''
+    @Name : get_template
+    @Desc : Retrieves the template Information based upon inputs provided
+            Template is retrieved based upon either of the inputs matched
+            condition
+    @Input : returns a template"
+    @Output : FAILED in case of any failure
+              template Information matching the inputs
+    '''
+    cmd = listTemplates.listTemplatesCmd()
+    cmd.templatefilter = template_filter
+    if domain_id is not None:
+        cmd.domainid = domain_id
+    if zone_id is not None:
+        cmd.zoneid = zone_id
+    if template_id is not None:
+        cmd.id = template_id
+    if template_name is not None:
+        cmd.name = template_name
+    if hypervisor is not None:
+        cmd.hypervisor = hypervisor
+    if project_id is not None:
+        cmd.projectid = project_id
+    if account is not None:
+        cmd.account = account
+
+
+    '''
+    Get the Templates pertaining to the inputs provided
+    '''
+    list_templatesout = apiclient.listTemplates(cmd)
+    #print("template result is %s"%(list_templatesout))
+    if list_templatesout is None:
+        return FAILED
+    if validateList(list_templatesout[0]) == FAIL :
+            return FAILED
+
+    for template in list_templatesout:
+        if template.isready and template.templatetype == "USER" and 
template.ostypename == ostype_desc:
+            return template
+    '''
+    Return default first template, if no template matched
+    '''
+
+    return FAILED
+
+
+
+def download_systemplates_sec_storage(server, services):
+    """Download System templates on sec storage"""
+
+    try:
+        # Login to management server
+        ssh = SshClient(
+            server["ipaddress"],
+            server["port"],
+            server["username"],
+            server["password"]
+        )
+    except Exception:
+        raise Exception("SSH access failed for server with IP address: %s" %
+                        server["ipaddess"])
+    # Mount Secondary Storage on Management Server
+    cmds = [
+        "mkdir -p %s" % services["mnt_dir"],
+        "mount -t nfs %s:/%s %s" % (
+            services["sec_storage"],
+            services["path"],
+            services["mnt_dir"]
+        ),
+        "%s -m %s -u %s -h %s -F" % (
+            services["command"],
+            services["mnt_dir"],
+            services["download_url"],
+            services["hypervisor"]
+        )
+    ]
+    for c in cmds:
+        result = ssh.execute(c)
+
+    res = str(result)
+
+    # Unmount the Secondary storage
+    ssh.execute("umount %s" % (services["mnt_dir"]))
+
+    if res.count("Successfully installed system VM template") == 1:
+        return
+    else:
+        raise Exception("Failed to download System Templates on Sec Storage")
+    return
+
+
+def wait_for_ssvms(apiclient, zoneid, podid, interval=60):
+    """After setup wait for SSVMs to come Up"""
+
+    time.sleep(interval)
+    timeout = 40
+    while True:
+        list_ssvm_response = list_ssvms(
+            apiclient,
+            systemvmtype='secondarystoragevm',
+            zoneid=zoneid,
+            podid=podid
+        )
+        ssvm = list_ssvm_response[0]
+        if ssvm.state != 'Running':
+            # Sleep to ensure SSVMs are Up and Running
+            time.sleep(interval)
+            timeout = timeout - 1
+        elif ssvm.state == 'Running':
+            break
+        elif timeout == 0:
+            raise Exception("SSVM failed to come up")
+            break
+
+    timeout = 40
+    while True:
+        list_ssvm_response = list_ssvms(
+            apiclient,
+            systemvmtype='consoleproxy',
+            zoneid=zoneid,
+            podid=podid
+        )
+        cpvm = list_ssvm_response[0]
+        if cpvm.state != 'Running':
+            # Sleep to ensure SSVMs are Up and Running
+            time.sleep(interval)
+            timeout = timeout - 1
+        elif cpvm.state == 'Running':
+            break
+        elif timeout == 0:
+            raise Exception("CPVM failed to come up")
+            break
+    return
+
+
+def get_builtin_template_info(apiclient, zoneid):
+    """Returns hypervisor specific infor for templates"""
+
+    list_template_response = Template.list(
+        apiclient,
+        templatefilter='featured',
+        zoneid=zoneid,
+    )
+
+    for b_template in list_template_response:
+        if b_template.templatetype == 'BUILTIN':
+            break
+
+    extract_response = Template.extract(apiclient,
+                                        b_template.id,
+                                        'HTTP_DOWNLOAD',
+                                        zoneid)
+
+    return extract_response.url, b_template.hypervisor, b_template.format
+
+
+def download_builtin_templates(apiclient, zoneid, hypervisor, host,
+                               linklocalip, interval=60):
+    """After setup wait till builtin templates are downloaded"""
+
+    # Change IPTABLES Rules
+    get_process_status(
+        host["ipaddress"],
+        host["port"],
+        host["username"],
+        host["password"],
+        linklocalip,
+        "iptables -P INPUT ACCEPT"
+    )
+    time.sleep(interval)
+    # Find the BUILTIN Templates for given Zone, Hypervisor
+    list_template_response = list_templates(
+        apiclient,
+        hypervisor=hypervisor,
+        zoneid=zoneid,
+        templatefilter='self'
+    )
+
+    if not isinstance(list_template_response, list):
+        raise Exception("Failed to download BUILTIN templates")
+
+    # Ensure all BUILTIN templates are downloaded
+    templateid = None
+    for template in list_template_response:
+        if template.templatetype == "BUILTIN":
+            templateid = template.id
+
+    # Sleep to ensure that template is in downloading state after adding
+    # Sec storage
+    time.sleep(interval)
+    while True:
+        template_response = list_templates(
+            apiclient,
+            id=templateid,
+            zoneid=zoneid,
+            templatefilter='self'
+        )
+        template = template_response[0]
+        # If template is ready,
+        # template.status = Download Complete
+        # Downloading - x% Downloaded
+        # Error - Any other string
+        if template.status == 'Download Complete':
+            break
+
+        elif 'Downloaded' in template.status:
+            time.sleep(interval)
+
+        elif 'Installing' not in template.status:
+            raise Exception("ErrorInDownload")
+
+    return
+
+
+def update_resource_limit(apiclient, resourcetype, account=None,
+                          domainid=None, max=None, projectid=None):
+    """Updates the resource limit to 'max' for given account"""
+
+    cmd = updateResourceLimit.updateResourceLimitCmd()
+    cmd.resourcetype = resourcetype
+    if account:
+        cmd.account = account
+    if domainid:
+        cmd.domainid = domainid
+    if max:
+        cmd.max = max
+    if projectid:
+        cmd.projectid = projectid
+    apiclient.updateResourceLimit(cmd)
+    return
+
+
+def list_os_types(apiclient, **kwargs):
+    """List all os types matching criteria"""
+
+    cmd = listOsTypes.listOsTypesCmd()
+    [setattr(cmd, k, v) for k, v in kwargs.items()]
+    if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+        cmd.listall=True
+    return(apiclient.listOsTypes(cmd))
+
+
+def list_routers(apiclient, **kwargs):
+    """List all Routers matching criteria"""
+
+    cmd = listRouters.listRoutersCmd()
+    [setattr(cmd, k, v) for k, v in kwargs.items()]
+    if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+        cmd.listall=True
+    return(apiclient.listRouters(cmd))
+
+
+def list_zones(apiclient, **kwargs):
+    """List all Zones matching criteria"""
+
+    cmd = listZones.listZonesCmd()
+    [setattr(cmd, k, v) for k, v in kwargs.items()]
+    if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+        cmd.listall=True
+    return(apiclient.listZones(cmd))
+
+
+def list_networks(apiclient, **kwargs):
+    """List all Networks matching criteria"""
+
+    cmd = listNetworks.listNetworksCmd()
+    [setattr(cmd, k, v) for k, v in kwargs.items()]
+    if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+        cmd.listall=True
+    return(apiclient.listNetworks(cmd))
+
+
+def list_clusters(apiclient, **kwargs):
+    """List all Clusters matching criteria"""
+
+    cmd = listClusters.listClustersCmd()
+    [setattr(cmd, k, v) for k, v in kwargs.items()]
+    if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+        cmd.listall=True
+    return(apiclient.listClusters(cmd))
+
+
+def list_ssvms(apiclient, **kwargs):
+    """List all SSVMs matching criteria"""
+
+    cmd = listSystemVms.listSystemVmsCmd()
+    [setattr(cmd, k, v) for k, v in kwargs.items()]
+    if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+        cmd.listall=True
+    return(apiclient.listSystemVms(cmd))
+
+
+def list_storage_pools(apiclient, **kwargs):
+    """List all storage pools matching criteria"""
+
+    cmd = listStoragePools.listStoragePoolsCmd()
+    [setattr(cmd, k, v) for k, v in kwargs.items()]
+    if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+        cmd.listall=True
+    return(apiclient.listStoragePools(cmd))
+
+
+def list_virtual_machines(apiclient, **kwargs):
+    """List all VMs matching criteria"""
+
+    cmd = listVirtualMachines.listVirtualMachinesCmd()
+    [setattr(cmd, k, v) for k, v in kwargs.items()]
+    if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+        cmd.listall=True
+    return(apiclient.listVirtualMachines(cmd))
+
+
+def list_hosts(apiclient, **kwargs):
+    """List all Hosts matching criteria"""
+
+    cmd = listHosts.listHostsCmd()
+    [setattr(cmd, k, v) for k, v in kwargs.items()]
+    if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+        cmd.listall=True
+    return(apiclient.listHosts(cmd))
+
+
+def list_configurations(apiclient, **kwargs):
+    """List configuration with specified name"""
+
+    cmd = listConfigurations.listConfigurationsCmd()
+    [setattr(cmd, k, v) for k, v in kwargs.items()]
+    if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+        cmd.listall=True
+    return(apiclient.listConfigurations(cmd))
+
+
+def list_publicIP(apiclient, **kwargs):
+    """List all Public IPs matching criteria"""
+
+    cmd = listPublicIpAddresses.listPublicIpAddressesCmd()
+    [setattr(cmd, k, v) for k, v in kwargs.items()]
+    if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+        cmd.listall=True
+    return(apiclient.listPublicIpAddresses(cmd))
+
+
+def list_nat_rules(apiclient, **kwargs):
+    """List all NAT rules matching criteria"""
+
+    cmd = listPortForwardingRules.listPortForwardingRulesCmd()
+    [setattr(cmd, k, v) for k, v in kwargs.items()]
+    if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+        cmd.listall=True
+    return(apiclient.listPortForwardingRules(cmd))
+
+
+def list_lb_rules(apiclient, **kwargs):
+    """List all Load balancing rules matching criteria"""
+
+    cmd = listLoadBalancerRules.listLoadBalancerRulesCmd()
+    [setattr(cmd, k, v) for k, v in kwargs.items()]
+    if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+        cmd.listall=True
+    return(apiclient.listLoadBalancerRules(cmd))
+
+
+def list_lb_instances(apiclient, **kwargs):
+    """List all Load balancing instances matching criteria"""
+
+    cmd = listLoadBalancerRuleInstances.listLoadBalancerRuleInstancesCmd()
+    [setattr(cmd, k, v) for k, v in kwargs.items()]
+    if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+        cmd.listall=True
+    return(apiclient.listLoadBalancerRuleInstances(cmd))
+
+
+def list_firewall_rules(apiclient, **kwargs):
+    """List all Firewall Rules matching criteria"""
+
+    cmd = listFirewallRules.listFirewallRulesCmd()
+    [setattr(cmd, k, v) for k, v in kwargs.items()]
+    if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+        cmd.listall=True
+    return(apiclient.listFirewallRules(cmd))
+
+
+def list_volumes(apiclient, **kwargs):
+    """List all volumes matching criteria"""
+
+    cmd = listVolumes.listVolumesCmd()
+    [setattr(cmd, k, v) for k, v in kwargs.items()]
+    if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+        cmd.listall=True
+    return(apiclient.listVolumes(cmd))
+
+
+def list_isos(apiclient, **kwargs):
+    """Lists all available ISO files."""
+
+    cmd = listIsos.listIsosCmd()
+    [setattr(cmd, k, v) for k, v in kwargs.items()]
+    if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+        cmd.listall=True
+    return(apiclient.listIsos(cmd))
+
+
+def list_snapshots(apiclient, **kwargs):
+    """List all snapshots matching criteria"""
+
+    cmd = listSnapshots.listSnapshotsCmd()
+    [setattr(cmd, k, v) for k, v in kwargs.items()]
+    if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+        cmd.listall=True
+    return(apiclient.listSnapshots(cmd))
+
+
+def list_templates(apiclient, **kwargs):
+    """List all templates matching criteria"""
+
+    cmd = listTemplates.listTemplatesCmd()
+    [setattr(cmd, k, v) for k, v in kwargs.items()]
+    if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+        cmd.listall=True
+    return(apiclient.listTemplates(cmd))
+
+
+def list_domains(apiclient, **kwargs):
+    """Lists domains"""
+
+    cmd = listDomains.listDomainsCmd()
+    [setattr(cmd, k, v) for k, v in kwargs.items()]
+    if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+        cmd.listall=True
+    return(apiclient.listDomains(cmd))
+
+
+def list_accounts(apiclient, **kwargs):
+    """Lists accounts and provides detailed account information for
+    listed accounts"""
+
+    cmd = listAccounts.listAccountsCmd()
+    [setattr(cmd, k, v) for k, v in kwargs.items()]
+    if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+        cmd.listall=True
+    return(apiclient.listAccounts(cmd))
+
+
+def list_users(apiclient, **kwargs):
+    """Lists users and provides detailed account information for
+    listed users"""
+
+    cmd = listUsers.listUsersCmd()
+    [setattr(cmd, k, v) for k, v in kwargs.items()]
+    if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+        cmd.listall=True
+    return(apiclient.listUsers(cmd))
+
+
+def list_snapshot_policy(apiclient, **kwargs):
+    """Lists snapshot policies."""
+
+    cmd = listSnapshotPolicies.listSnapshotPoliciesCmd()
+    [setattr(cmd, k, v) for k, v in kwargs.items()]
+    if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+        cmd.listall=True
+    return(apiclient.listSnapshotPolicies(cmd))
+
+
+def list_events(apiclient, **kwargs):
+    """Lists events"""
+
+    cmd = listEvents.listEventsCmd()
+    [setattr(cmd, k, v) for k, v in kwargs.items()]
+    if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+        cmd.listall=True
+    return(apiclient.listEvents(cmd))
+
+
+def list_disk_offering(apiclient, **kwargs):
+    """Lists all available disk offerings."""
+
+    cmd = listDiskOfferings.listDiskOfferingsCmd()
+    [setattr(cmd, k, v) for k, v in kwargs.items()]
+    if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+        cmd.listall=True
+    return(apiclient.listDiskOfferings(cmd))
+
+
+def list_service_offering(apiclient, **kwargs):
+    """Lists all available service offerings."""
+
+    cmd = listServiceOfferings.listServiceOfferingsCmd()
+    [setattr(cmd, k, v) for k, v in kwargs.items()]
+    if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+        cmd.listall=True
+    return(apiclient.listServiceOfferings(cmd))
+
+
+def list_vlan_ipranges(apiclient, **kwargs):
+    """Lists all VLAN IP ranges."""
+
+    cmd = listVlanIpRanges.listVlanIpRangesCmd()
+    [setattr(cmd, k, v) for k, v in kwargs.items()]
+    if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+        cmd.listall=True
+    return(apiclient.listVlanIpRanges(cmd))
+
+
+def list_usage_records(apiclient, **kwargs):
+    """Lists usage records for accounts"""
+
+    cmd = listUsageRecords.listUsageRecordsCmd()
+    [setattr(cmd, k, v) for k, v in kwargs.items()]
+    if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+        cmd.listall=True
+    return(apiclient.listUsageRecords(cmd))
+
+
+def list_nw_service_prividers(apiclient, **kwargs):
+    """Lists Network service providers"""
+
+    cmd = listNetworkServiceProviders.listNetworkServiceProvidersCmd()
+    [setattr(cmd, k, v) for k, v in kwargs.items()]
+    if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+        cmd.listall=True
+    return(apiclient.listNetworkServiceProviders(cmd))
+
+
+def list_virtual_router_elements(apiclient, **kwargs):
+    """Lists Virtual Router elements"""
+
+    cmd = listVirtualRouterElements.listVirtualRouterElementsCmd()
+    [setattr(cmd, k, v) for k, v in kwargs.items()]
+    if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+        cmd.listall=True
+    return(apiclient.listVirtualRouterElements(cmd))
+
+
+def list_network_offerings(apiclient, **kwargs):
+    """Lists network offerings"""
+
+    cmd = listNetworkOfferings.listNetworkOfferingsCmd()
+    [setattr(cmd, k, v) for k, v in kwargs.items()]
+    if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+        cmd.listall=True
+    return(apiclient.listNetworkOfferings(cmd))
+
+
+def list_resource_limits(apiclient, **kwargs):
+    """Lists resource limits"""
+
+    cmd = listResourceLimits.listResourceLimitsCmd()
+    [setattr(cmd, k, v) for k, v in kwargs.items()]
+    if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+        cmd.listall=True
+    return(apiclient.listResourceLimits(cmd))
+
+
+def list_vpc_offerings(apiclient, **kwargs):
+    """ Lists VPC offerings """
+
+    cmd = listVPCOfferings.listVPCOfferingsCmd()
+    [setattr(cmd, k, v) for k, v in kwargs.items()]
+    if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+        cmd.listall=True
+    return(apiclient.listVPCOfferings(cmd))
+
+
+def update_resource_count(apiclient, domainid, accountid=None,
+                          projectid=None, rtype=None):
+    """updates the resource count
+        0     - VM
+        1     - Public IP
+        2     - Volume
+        3     - Snapshot
+        4     - Template
+        5     - Projects
+        6     - Network
+        7     - VPC
+        8     - CPUs
+        9     - RAM
+        10    - Primary (shared) storage (Volumes)
+        11    - Secondary storage (Snapshots, Templates & ISOs)
+    """
+
+    Resources.updateCount(apiclient,
+                          domainid=domainid,
+                          account=accountid if accountid else None,
+                          projectid=projectid if projectid else None,
+                          resourcetype=rtype if rtype else None
+                          )
+    return
+
+def findSuitableHostForMigration(apiclient, vmid):
+    """Returns a suitable host for VM migration"""
+    suitableHost = None
+    try:
+        hosts = Host.listForMigration(apiclient, virtualmachineid=vmid,
+                )
+    except Exception as e:
+        raise Exception("Exception while getting hosts list suitable for 
migration: %s" % e)
+
+    suitablehosts = []
+    if isinstance(hosts, list) and len(hosts) > 0:
+        suitablehosts = [host for host in hosts if 
(str(host.resourcestate).lower() == "enabled"\
+                and str(host.state).lower() == "up")]
+        if len(suitablehosts)>0:
+            suitableHost = suitablehosts[0]
+
+    return suitableHost
+
+
+def get_resource_type(resource_id):
+    """Returns resource type"""
+
+    lookup = {0: "VM",
+              1: "Public IP",
+              2: "Volume",
+              3: "Snapshot",
+              4: "Template",
+              5: "Projects",
+              6: "Network",
+              7: "VPC",
+              8: "CPUs",
+              9: "RAM",
+              10: "Primary (shared) storage (Volumes)",
+              11: "Secondary storage (Snapshots, Templates & ISOs)"
+              }
+
+    return lookup[resource_id]
+
+
+
+def get_free_vlan(apiclient, zoneid):
+    """
+    Find an unallocated VLAN outside the range allocated to the physical 
network.
+
+    @note: This does not guarantee that the VLAN is available for use in
+    the deployment's network gear
+    @return: physical_network, shared_vlan_tag
+    """
+    list_physical_networks_response = PhysicalNetwork.list(
+        apiclient,
+        zoneid=zoneid
+    )
+    assert isinstance(list_physical_networks_response, list)
+    assert len(
+        list_physical_networks_response) > 0, "No physical networks found in 
zone %s" % zoneid
+
+    physical_network = list_physical_networks_response[0]
+
+    networks = list_networks(apiclient, zoneid=zoneid, type='Shared')
+    usedVlanIds = []
+
+    if isinstance(networks, list) and len(networks) > 0:
+        usedVlanIds = [int(nw.vlan)
+                       for nw in networks if nw.vlan != "untagged"]
+
+    if hasattr(physical_network, "vlan") is False:
+        while True:
+            shared_ntwk_vlan = random.randrange(1, 4095)
+            if shared_ntwk_vlan in usedVlanIds:
+                continue
+            else:
+                break
+    else:
+        vlans = xsplit(physical_network.vlan, ['-', ','])
+
+        assert len(vlans) > 0
+        assert int(vlans[0]) < int(
+            vlans[-1]), "VLAN range  %s was improperly split" % 
physical_network.vlan
+
+        # Assuming random function will give different integer each time
+        retriesCount = 20
+
+        shared_ntwk_vlan = None
+
+        while True:
+
+            if retriesCount == 0:
+                break
+
+            free_vlan = int(vlans[-1]) + random.randrange(1, 20)
+
+            if free_vlan > 4095:
+                free_vlan = int(vlans[0]) - random.randrange(1, 20)
+            if free_vlan < 0 or (free_vlan in usedVlanIds):
+                retriesCount -= 1
+                continue
+            else:
+                shared_ntwk_vlan = free_vlan
+                break
+
+    return physical_network, shared_ntwk_vlan
+
+
+def setNonContiguousVlanIds(apiclient, zoneid):
+    """
+    Form the non contiguous ranges based on currently assigned range in 
physical network
+    """
+
+    NonContigVlanIdsAcquired = False
+
+    list_physical_networks_response = PhysicalNetwork.list(
+        apiclient,
+        zoneid=zoneid
+    )
+    assert isinstance(list_physical_networks_response, list)
+    assert len(
+        list_physical_networks_response) > 0, "No physical networks found in 
zone %s" % zoneid
+
+    for physical_network in list_physical_networks_response:
+
+        vlans = xsplit(physical_network.vlan, ['-', ','])
+
+        assert len(vlans) > 0
+        assert int(vlans[0]) < int(
+            vlans[-1]), "VLAN range  %s was improperly split" % 
physical_network.vlan
+
+        # Keep some gap between existing vlan and the new vlans which we are 
going to add
+        # So that they are non contiguous
+
+        non_contig_end_vlan_id = int(vlans[-1]) + 6
+        non_contig_start_vlan_id = int(vlans[0]) - 6
+
+        # Form ranges which are consecutive to existing ranges but not 
immediately contiguous
+        # There should be gap in between existing range and new non contiguous
+        # ranage
+
+        # If you can't add range after existing range, because it's crossing 
4095, then
+        # select VLAN ids before the existing range such that they are greater 
than 0, and
+        # then add this non contiguoud range
+        vlan = {"partial_range": ["", ""], "full_range": ""}
+
+        if non_contig_end_vlan_id < 4095:
+            vlan["partial_range"][0] = str(
+                non_contig_end_vlan_id - 4) + '-' + str(non_contig_end_vlan_id 
- 3)
+            vlan["partial_range"][1] = str(
+                non_contig_end_vlan_id - 1) + '-' + str(non_contig_end_vlan_id)
+            vlan["full_range"] = str(
+                non_contig_end_vlan_id - 4) + '-' + str(non_contig_end_vlan_id)
+            NonContigVlanIdsAcquired = True
+
+        elif non_contig_start_vlan_id > 0:
+            vlan["partial_range"][0] = str(
+                non_contig_start_vlan_id) + '-' + str(non_contig_start_vlan_id 
+ 1)
+            vlan["partial_range"][1] = str(
+                non_contig_start_vlan_id + 3) + '-' + 
str(non_contig_start_vlan_id + 4)
+            vlan["full_range"] = str(
+                non_contig_start_vlan_id) + '-' + str(non_contig_start_vlan_id 
+ 4)
+            NonContigVlanIdsAcquired = True
+
+        else:
+            NonContigVlanIdsAcquired = False
+
+        # If failed to get relevant vlan ids, continue to next physical network
+        # else break from loop as we have hot the non contiguous vlan ids for
+        # the test purpose
+
+        if not NonContigVlanIdsAcquired:
+            continue
+        else:
+            break
+
+    # If even through looping from all existing physical networks, failed to 
get relevant non
+    # contiguous vlan ids, then fail the test case
+
+    if not NonContigVlanIdsAcquired:
+        return None, None
+
+    return physical_network, vlan
+
+def isIpInDesiredState(apiclient, ipaddressid, state):
+    """ Check if the given IP is in the correct state (given)
+    and return True/False accordingly"""
+    retriesCount = 10
+    ipInDesiredState = False
+    exceptionOccured = False
+    exceptionMessage = ""
+    try:
+        while retriesCount >= 0:
+            portableips = PublicIPAddress.list(apiclient, id=ipaddressid)
+            assert validateList(
+                portableips)[0] == PASS, "IPs list validation failed"
+            if str(portableips[0].state).lower() == state:
+                ipInDesiredState = True
+                break
+            retriesCount -= 1
+            time.sleep(60)
+    except Exception as e:
+        exceptionOccured = True
+        exceptionMessage = e
+        return [exceptionOccured, ipInDesiredState, e]
+    if not ipInDesiredState:
+        exceptionMessage = "Ip should be in %s state, it is in %s" %\
+                            (state, portableips[0].state)
+    return [False, ipInDesiredState, exceptionMessage]
+
+def setSharedNetworkParams(networkServices, range=20):
+    """Fill up the services dictionary for shared network using random 
subnet"""
+
+    # @range: range decides the endip. Pass the range as "x" if you want the 
difference between the startip
+    # and endip as "x"
+    # Set the subnet number of shared networks randomly prior to execution
+    # of each test case to avoid overlapping of ip addresses
+    shared_network_subnet_number = random.randrange(1,254)
+
+    networkServices["gateway"] = 
"172.16."+str(shared_network_subnet_number)+".1"
+    networkServices["startip"] = 
"172.16."+str(shared_network_subnet_number)+".2"
+    networkServices["endip"] = 
"172.16."+str(shared_network_subnet_number)+"."+str(range+1)
+    networkServices["netmask"] = "255.255.255.0"
+    return networkServices
+
+def createEnabledNetworkOffering(apiclient, networkServices):
+    """Create and enable network offering according to the type
+
+       @output: List, containing [ Result,Network Offering,Reason ]
+                 Ist Argument('Result') : FAIL : If exception or assertion 
error occurs
+                                          PASS : If network offering
+                                          is created and enabled successfully
+                 IInd Argument(Net Off) : Enabled network offering
+                                                In case of exception or
+                                                assertion error, it will be 
None
+                 IIIrd Argument(Reason) :  Reason for failure,
+                                              default to None
+    """
+    try:
+        resultSet = [FAIL, None, None]
+        # Create network offering
+        network_offering = NetworkOffering.create(apiclient, networkServices, 
conservemode=False)
+
+        # Update network offering state from disabled to enabled.
+        NetworkOffering.update(network_offering, apiclient, 
id=network_offering.id,
+                               state="enabled")
+    except Exception as e:
+        resultSet[2] = e
+        return resultSet
+    return [PASS, network_offering, None]
+
+def shouldTestBeSkipped(networkType, zoneType):
+    """Decide which test to skip, according to type of network and zone type"""
+
+    # If network type is isolated or vpc and zone type is basic, then test 
should be skipped
+    skipIt = False
+    if ((networkType.lower() == str(ISOLATED_NETWORK).lower() or 
networkType.lower() == str(VPC_NETWORK).lower())
+            and (zoneType.lower() == BASIC_ZONE)):
+        skipIt = True
+    return skipIt
+
+def verifyNetworkState(apiclient, networkid, state, listall=True):
+    """List networks and check if the network state matches the given state"""
+    retriesCount = 10
+    isNetworkInDesiredState = False
+    exceptionOccured = False
+    exceptionMessage = ""
+    try:
+        while retriesCount >= 0:
+            networks = Network.list(apiclient, id=networkid, listall=listall)
+            assert validateList(
+                networks)[0] == PASS, "Networks list validation failed"
+            if str(networks[0].state).lower() == state:
+                isNetworkInDesiredState = True
+                break
+            retriesCount -= 1
+            time.sleep(60)
+        if not isNetworkInDesiredState:
+            exceptionMessage = "Network state should be %s, it is %s" %\
+                                (state, networks[0].state)
+    except Exception as e:
+        exceptionOccured = True
+        exceptionMessage = e
+        return [exceptionOccured, isNetworkInDesiredState, exceptionMessage]
+    return [exceptionOccured, isNetworkInDesiredState, exceptionMessage]
+
+def verifyComputeOfferingCreation(apiclient, computeofferingid):
+    """List Compute offerings by ID and verify that the offering exists"""
+
+    cmd = listServiceOfferings.listServiceOfferingsCmd()
+    cmd.id = computeofferingid
+    serviceOfferings = None
+    try:
+        serviceOfferings = apiclient.listServiceOfferings(cmd)
+    except Exception:
+       return FAIL
+    if not (isinstance(serviceOfferings, list) and len(serviceOfferings) > 0):
+       return FAIL
+    return PASS
+
+def createNetworkRulesForVM(apiclient, virtualmachine, ruletype,
+                            account, networkruledata):
+    """Acquire IP, create Firewall and NAT/StaticNAT rule
+        (associating it with given vm) for that IP"""
+
+    try:
+        public_ip = PublicIPAddress.create(
+                apiclient,accountid=account.name,
+                zoneid=virtualmachine.zoneid,domainid=account.domainid,
+                networkid=virtualmachine.nic[0].networkid)
+
+        FireWallRule.create(
+            apiclient,ipaddressid=public_ip.ipaddress.id,
+            protocol='TCP', cidrlist=[networkruledata["fwrule"]["cidr"]],
+            startport=networkruledata["fwrule"]["startport"],
+            endport=networkruledata["fwrule"]["endport"]
+            )
+
+        if ruletype == NAT_RULE:
+            # Create NAT rule
+            NATRule.create(apiclient, virtualmachine,
+                                 
networkruledata["natrule"],ipaddressid=public_ip.ipaddress.id,
+                                 networkid=virtualmachine.nic[0].networkid)
+        elif ruletype == STATIC_NAT_RULE:
+            # Enable Static NAT for VM
+            StaticNATRule.enable(apiclient,public_ip.ipaddress.id,
+                                     virtualmachine.id, 
networkid=virtualmachine.nic[0].networkid)
+    except Exception as e:
+        [FAIL, e]
+    return [PASS, public_ip]
+
+def getPortableIpRangeServices(config):
+    """ Reads config values related to portable ip and fills up
+    services accordingly"""
+
+    services = {}
+    attributeError = False
+
+    if config.portableIpRange.startip:
+        services["startip"] = config.portableIpRange.startip
+    else:
+        attributeError = True
+
+    if config.portableIpRange.endip:
+        services["endip"] = config.portableIpRange.endip
+    else:
+        attributeError = True
+
+    if config.portableIpRange.netmask:
+        services["netmask"] = config.portableIpRange.netmask
+    else:
+        attributeError = True
+
+    if config.portableIpRange.gateway:
+        services["gateway"] = config.portableIpRange.gateway
+    else:
+        attributeError = True
+
+    if config.portableIpRange.vlan:
+        services["vlan"] = config.portableIpRange.vlan
+
+    if attributeError:
+        services = FAILED
+
+    return services
+
+
+def uploadVolume(apiclient, zoneid, account, services):
+    try:
+        # Upload the volume
+        volume = Volume.upload(apiclient, services["volume"],
+                                   zoneid=zoneid, account=account.name,
+                                   domainid=account.domainid, 
url=services["url"])
+
+        volume.wait_for_upload(apiclient)
+
+        # Check List Volume response for newly created volume
+        volumes = Volume.list(apiclient, id=volume.id,
+                                  zoneid=zoneid, listall=True)
+        validationresult = validateList(volumes)
+        assert validationresult[0] == PASS,\
+                            "volumes list validation failed: %s" % 
validationresult[2]
+        assert str(volumes[0].state).lower() == "uploaded",\
+                    "Volume state should be 'uploaded' but it is %s" % 
volumes[0].state
+    except Exception as e:
+        return [FAIL, e]
+    return [PASS, volume]
+
+def matchResourceCount(apiclient, expectedCount, resourceType,
+                              accountid=None, projectid=None):
+    """Match the resource count of account/project with the expected
+    resource count"""
+    try:
+        resourceholderlist = None
+        if accountid:
+            resourceholderlist = Account.list(apiclient, id=accountid)
+        elif projectid:
+            resourceholderlist = Project.list(apiclient, id=projectid, 
listall=True)
+        validationresult = validateList(resourceholderlist)
+        assert validationresult[0] == PASS,\
+               "accounts list validation failed"
+        if resourceType == RESOURCE_PRIMARY_STORAGE:
+            resourceCount = resourceholderlist[0].primarystoragetotal
+        elif resourceType == RESOURCE_SECONDARY_STORAGE:
+            resourceCount = resourceholderlist[0].secondarystoragetotal
+        elif resourceType == RESOURCE_CPU:
+            resourceCount = resourceholderlist[0].cputotal
+        elif resourceType == RESOURCE_MEMORY:
+            resourceCount = resourceholderlist[0].memorytotal
+        assert str(resourceCount) == str(expectedCount),\
+                "Resource count %s should match with the expected resource 
count %s" %\
+                (resourceCount, expectedCount)
+    except Exception as e:
+        return [FAIL, e]
+    return [PASS, None]
+
+def createSnapshotFromVirtualMachineVolume(apiclient, account, vmid):
+    """Create snapshot from volume"""
+
+    try:
+        volumes = Volume.list(apiclient, account=account.name,
+                              domainid=account.domainid, virtualmachineid=vmid)
+        validationresult = validateList(volumes)
+        assert validateList(volumes)[0] == PASS,\
+                            "List volumes should return a valid response"
+        snapshot = Snapshot.create(apiclient, volume_id=volumes[0].id,
+                                   account=account.name, 
domainid=account.domainid)
+        snapshots = Snapshot.list(apiclient, id=snapshot.id,
+                                      listall=True)
+        validationresult = validateList(snapshots)
+        assert validationresult[0] == PASS,\
+               "List snapshot should return a valid list"
+    except Exception as e:
+       return[FAIL, e]
+    return [PASS, snapshot]
+
+def isVmExpunged(apiclient, vmid, projectid=None, timeout=600):
+    """Verify if VM is expunged or not"""
+    vmExpunged= False
+    while timeout>=0:
+        try:
+            vms = VirtualMachine.list(apiclient, id=vmid, projectid=projectid)
+            if vms is None:
+                vmExpunged = True
+                break
+            timeout -= 60
+            time.sleep(60)
+        except Exception:
+            vmExpunged = True
+            break
+     #end while
+    return vmExpunged
+
+def isDomainResourceCountEqualToExpectedCount(apiclient, domainid, 
expectedcount,
+                                              resourcetype):
+    """Get the resource count of specific domain and match
+    it with the expected count
+    Return list [isExceptionOccured, reasonForException, 
isResourceCountEqual]"""
+    isResourceCountEqual = False
+    isExceptionOccured = False
+    reasonForException = None
+    try:
+        response = Resources.updateCount(apiclient, domainid=domainid,
+                                         resourcetype=resourcetype)
+    except Exception as e:
+        reasonForException = "Failed while updating resource count: %s" % e
+        isExceptionOccured = True
+        return [isExceptionOccured, reasonForException, isResourceCountEqual]
+
+    resourcecount = (response[0].resourcecount / (1024**3))
+    if resourcecount == expectedcount:
+        isResourceCountEqual = True
+    return [isExceptionOccured, reasonForException, isResourceCountEqual]
+
+def isNetworkDeleted(apiclient, networkid, timeout=600):
+    """ List the network and check that the list is empty or not"""
+    networkDeleted = False
+    while timeout >= 0:
+        networks = Network.list(apiclient, id=networkid)
+        if networks is None:
+            networkDeleted = True
+            break
+        timeout -= 60
+        time.sleep(60)
+    #end while
+    return networkDeleted

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d002c52a/tools/marvin/marvin/lib/cloudstack/diskoffering.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/lib/cloudstack/diskoffering.py 
b/tools/marvin/marvin/lib/cloudstack/diskoffering.py
new file mode 100644
index 0000000..f10fb6f
--- /dev/null
+++ b/tools/marvin/marvin/lib/cloudstack/diskoffering.py
@@ -0,0 +1,77 @@
+# 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.
+
+from marvin.cloudstackAPI import 
createDiskOffering,deleteDiskOffering,listDiskOfferings
+class DiskOffering:
+    """Manage disk offerings cycle"""
+
+    def __init__(self, items):
+        self.__dict__.update(items)
+
+    @classmethod
+    def create(cls, apiclient, services, custom=False, domainid=None):
+        """Create Disk offering"""
+        cmd = createDiskOffering.createDiskOfferingCmd()
+        cmd.displaytext = services["displaytext"]
+        cmd.name = services["name"]
+        if custom:
+            cmd.customized = True
+        else:
+            cmd.disksize = services["disksize"]
+
+        if domainid:
+            cmd.domainid = domainid
+
+        if "storagetype" in services:
+            cmd.storagetype = services["storagetype"]
+
+        if "customizediops" in services:
+            cmd.customizediops = services["customizediops"]
+
+        if "disksize" in services:
+            cmd.disksize = services["disksize"]
+
+        if "maxiops" in services:
+            cmd.maxiops = services["maxiops"]
+
+        if "miniops" in services:
+            cmd.miniops = services["miniops"]
+
+        if "tags" in services:
+            cmd.tags = services["tags"]
+
+        if "provisioningtype" in services:
+            cmd.provisioningtype = services["provisioningtype"]
+
+        return DiskOffering(apiclient.createDiskOffering(cmd).__dict__)
+
+    def delete(self, apiclient):
+        """Delete Disk offering"""
+        cmd = deleteDiskOffering.deleteDiskOfferingCmd()
+        cmd.id = self.id
+        apiclient.deleteDiskOffering(cmd)
+        return
+
+    @classmethod
+    def list(cls, apiclient, **kwargs):
+        """Lists all available disk offerings."""
+
+        cmd = listDiskOfferings.listDiskOfferingsCmd()
+        [setattr(cmd, k, v) for k, v in kwargs.items()]
+        if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+            cmd.listall = True
+        return(apiclient.listDiskOfferings(cmd))

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d002c52a/tools/marvin/marvin/lib/cloudstack/domain.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/lib/cloudstack/domain.py 
b/tools/marvin/marvin/lib/cloudstack/domain.py
new file mode 100644
index 0000000..492c321
--- /dev/null
+++ b/tools/marvin/marvin/lib/cloudstack/domain.py
@@ -0,0 +1,72 @@
+# 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.
+
+from marvin.cloudstackAPI import createDomain,deleteDomain,listDomains
+from marvin.lib.cloudstack.utils import random_gen
+class Domain:
+    """ Domain Life Cycle """
+    def __init__(self, items):
+        self.__dict__.update(items)
+
+    @classmethod
+    def create(cls, apiclient, services, name=None, networkdomain=None,
+               parentdomainid=None):
+        """Creates an domain"""
+
+        cmd = createDomain.createDomainCmd()
+
+        if "domainUUID" in services:
+            cmd.domainid = "-".join([services["domainUUID"], random_gen()])
+
+        if name:
+            cmd.name = "-".join([name, random_gen()])
+        elif "name" in services:
+            cmd.name = "-".join([services["name"], random_gen()])
+
+        if networkdomain:
+            cmd.networkdomain = networkdomain
+        elif "networkdomain" in services:
+            cmd.networkdomain = services["networkdomain"]
+
+        if parentdomainid:
+            cmd.parentdomainid = parentdomainid
+        elif "parentdomainid" in services:
+            cmd.parentdomainid = services["parentdomainid"]
+        try:
+            domain = apiclient.createDomain(cmd)
+            if domain is not None:
+                return Domain(domain.__dict__)
+        except Exception as e:
+            raise e
+
+    def delete(self, apiclient, cleanup=None):
+        """Delete an domain"""
+        cmd = deleteDomain.deleteDomainCmd()
+        cmd.id = self.id
+        if cleanup:
+            cmd.cleanup = cleanup
+        apiclient.deleteDomain(cmd)
+
+    @classmethod
+    def list(cls, apiclient, **kwargs):
+        """Lists domains"""
+        cmd = listDomains.listDomainsCmd()
+        [setattr(cmd, k, v) for k, v in kwargs.items()]
+        if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+            cmd.listall = True
+        return(apiclient.listDomains(cmd))
+

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d002c52a/tools/marvin/marvin/lib/cloudstack/host.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/lib/cloudstack/host.py 
b/tools/marvin/marvin/lib/cloudstack/host.py
new file mode 100644
index 0000000..d36907a
--- /dev/null
+++ b/tools/marvin/marvin/lib/cloudstack/host.py
@@ -0,0 +1,159 @@
+# 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 time
+
+from marvin.cloudstackAPI import 
addHost,prepareHostForMaintenance,deleteHost,cancelHostMaintenance,listHosts,findHostsForMigration,updateHost
+from marvin.lib.cloudstack.utils import validateList
+from marvin.codes import (FAILED, PASS)
+from marvin.cloudstackException import GetDetailExceptionInfo
+
+
+class Host:
+    """Manage Host life cycle"""
+
+    def __init__(self, items):
+        self.__dict__.update(items)
+
+    @classmethod
+    def create(cls, apiclient, cluster, services, zoneid=None, podid=None, 
hypervisor=None):
+        """
+        1. Creates the host based upon the information provided.
+        2. Verifies the output of the adding host and its state post addition
+           Returns FAILED in case of an issue, else an instance of Host
+        """
+        try:
+            cmd = addHost.addHostCmd()
+            cmd.hypervisor = hypervisor
+            cmd.url = services["url"]
+            cmd.clusterid = cluster.id
+
+            if zoneid:
+                cmd.zoneid = zoneid
+            else:
+                cmd.zoneid = services["zoneid"]
+
+            if podid:
+                cmd.podid = podid
+            else:
+                cmd.podid = services["podid"]
+
+            if "clustertype" in services:
+                cmd.clustertype = services["clustertype"]
+            if "username" in services:
+                cmd.username = services["username"]
+            if "password" in services:
+                cmd.password = services["password"]
+
+            '''
+            Adds a Host,
+            If response is valid and host is up return
+            an instance of Host.
+            If response is invalid, returns FAILED.
+            If host state is not up, verify through listHosts call
+            till host status is up and return accordingly. Max 3 retries
+            '''
+            host = apiclient.addHost(cmd)
+            ret = validateList(host)
+            if ret[0] == PASS:
+                if str(host[0].state).lower() == 'up':
+                    return Host(host[0].__dict__)
+                retries = 3
+                while retries:
+                    lh_resp = apiclient.listHosts(host[0].id)
+                    ret = validateList(lh_resp)
+                    if (ret[0] == PASS) and \
+                            (str(ret[1].state).lower() == 'up'):
+                        return Host(host[0].__dict__)
+                    retries += -1
+            return FAILED
+        except Exception as e:
+            print "Exception Occurred Under Host.create : %s" % \
+                  GetDetailExceptionInfo(e)
+            return FAILED
+
+    def delete(self, apiclient):
+        """Delete Host"""
+        # Host must be in maintenance mode before deletion
+        cmd = prepareHostForMaintenance.prepareHostForMaintenanceCmd()
+        cmd.id = self.id
+        apiclient.prepareHostForMaintenance(cmd)
+        time.sleep(30)
+
+        cmd = deleteHost.deleteHostCmd()
+        cmd.id = self.id
+        apiclient.deleteHost(cmd)
+        return
+
+    def enableMaintenance(self, apiclient):
+        """enables maintenance mode Host"""
+
+        cmd = prepareHostForMaintenance.prepareHostForMaintenanceCmd()
+        cmd.id = self.id
+        return apiclient.prepareHostForMaintenance(cmd)
+
+    @classmethod
+    def enableMaintenance(cls, apiclient, id):
+        """enables maintenance mode Host"""
+
+        cmd = prepareHostForMaintenance.prepareHostForMaintenanceCmd()
+        cmd.id = id
+        return apiclient.prepareHostForMaintenance(cmd)
+
+    def cancelMaintenance(self, apiclient):
+        """Cancels maintenance mode Host"""
+
+        cmd = cancelHostMaintenance.cancelHostMaintenanceCmd()
+        cmd.id = self.id
+        return apiclient.cancelHostMaintenance(cmd)
+
+    @classmethod
+    def cancelMaintenance(cls, apiclient, id):
+        """Cancels maintenance mode Host"""
+
+        cmd = cancelHostMaintenance.cancelHostMaintenanceCmd()
+        cmd.id = id
+        return apiclient.cancelHostMaintenance(cmd)
+
+    @classmethod
+    def list(cls, apiclient, **kwargs):
+        """List all Hosts matching criteria"""
+
+        cmd = listHosts.listHostsCmd()
+        [setattr(cmd, k, v) for k, v in kwargs.items()]
+        if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+            cmd.listall = True
+        return(apiclient.listHosts(cmd))
+
+    @classmethod
+    def listForMigration(cls, apiclient, **kwargs):
+        """List all Hosts for migration matching criteria"""
+
+        cmd = findHostsForMigration.findHostsForMigrationCmd()
+        [setattr(cmd, k, v) for k, v in kwargs.items()]
+        if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+            cmd.listall = True
+        return(apiclient.findHostsForMigration(cmd))
+
+    @classmethod
+    def update(cls, apiclient, **kwargs):
+        """Update host information"""
+
+        cmd = updateHost.updateHostCmd()
+        [setattr(cmd, k, v) for k, v in kwargs.items()]
+        return(apiclient.updateHost(cmd))
+

Reply via email to