cloudstack-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bfede...@apache.org
Subject [02/76] [abbrv] CLOUSTACK-5099: Utils.py-has-wrong-reference, cleaned it. As well added Uniform naming convention Signed-off-by: SrikanteswaraRao Talluri <talluri@apache.org>
Date Fri, 08 Nov 2013 18:08:18 GMT
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ec00a6fb/tools/marvin/build/lib/marvin/integration/lib/common.py
----------------------------------------------------------------------
diff --git a/tools/marvin/build/lib/marvin/integration/lib/common.py b/tools/marvin/build/lib/marvin/integration/lib/common.py
new file mode 100644
index 0000000..164ef20
--- /dev/null
+++ b/tools/marvin/build/lib/marvin/integration/lib/common.py
@@ -0,0 +1,739 @@
+# 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
+from marvin.cloudstackAPI import *
+from marvin.remoteSSHClient import remoteSSHClient
+from utils import *
+from base import *
+
+#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'
+      response = apiclient.updateNetworkServiceProvider(cmd)
+
+    return netscaler
+
+def get_region(apiclient, services=None):
+    "Returns a default region"
+
+    cmd = listRegions.listRegionsCmd()
+    if services:
+        if "regionid" in services:
+            cmd.id = services["regionid"]
+
+    regions = apiclient.listRegions(cmd)
+
+    if isinstance(regions, list):
+        assert len(regions) > 0
+        return regions[0]
+    else:
+        raise Exception("Failed to find specified region.")
+
+def get_domain(apiclient, services=None):
+    "Returns a default domain"
+
+    cmd = listDomains.listDomainsCmd()
+    if services:
+        if "domainid" in services:
+            cmd.id = services["domainid"]
+
+    domains = apiclient.listDomains(cmd)
+
+    if isinstance(domains, list):
+        assert len(domains) > 0
+        return domains[0]
+    else:
+        raise Exception("Failed to find specified domain.")
+
+
+def get_zone(apiclient, services=None):
+    "Returns a default zone"
+
+    cmd = listZones.listZonesCmd()
+    if services:
+        if "zoneid" in services:
+            cmd.id = services["zoneid"]
+
+    zones = apiclient.listZones(cmd)
+
+    if isinstance(zones, list):
+        assert len(zones) > 0, "There are no available zones in the deployment"
+        return zones[0]
+    else:
+        raise Exception("Failed to find specified zone.")
+
+
+def get_pod(apiclient, zoneid, services=None):
+    "Returns a default pod for specified zone"
+
+    cmd = listPods.listPodsCmd()
+    cmd.zoneid = zoneid
+
+    if services:
+        if "podid" in services:
+            cmd.id = services["podid"]
+
+    pods = apiclient.listPods(cmd)
+
+    if isinstance(pods, list):
+        assert len(pods) > 0, "No pods found for zone %s"%zoneid
+        return pods[0]
+    else:
+        raise Exception("Exception: Failed to find specified pod.")
+
+
+def get_template(apiclient, zoneid, ostype, services=None):
+    "Returns a template"
+
+    cmd = listOsTypes.listOsTypesCmd()
+    cmd.description = ostype
+    ostypes = apiclient.listOsTypes(cmd)
+
+    if isinstance(ostypes, list):
+        ostypeid = ostypes[0].id
+    else:
+        raise Exception(
+            "Failed to find OS type with description: %s" % ostype)
+
+    cmd = listTemplates.listTemplatesCmd()
+    cmd.templatefilter = 'featured'
+    cmd.zoneid = zoneid
+
+    if services:
+        if "template" in services:
+            cmd.id = services["template"]
+
+    list_templates = apiclient.listTemplates(cmd)
+
+    if isinstance(list_templates, list):
+        assert len(list_templates) > 0, "received empty response on template of type %s"%ostype
+        for template in list_templates:
+            if template.ostypeid == ostypeid:
+                return template
+            elif template.isready:
+                return template
+
+    raise Exception("Exception: Failed to find template with OSTypeID: %s" %
+                                                                    ostypeid)
+    return
+
+
+def download_systemplates_sec_storage(server, services):
+    """Download System templates on sec storage"""
+
+    try:
+        # Login to management server
+        ssh = remoteSSHClient(
+                                          server["ipaddress"],
+                                          server["port"],
+                                          server["username"],
+                                          server["password"]
+                             )
+    except Exception:
+        raise Exception("SSH access failted 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()]
+    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()]
+    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()]
+    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()]
+    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()]
+    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()]
+    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()]
+    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()]
+    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()]
+    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()]
+    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()]
+    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()]
+    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()]
+    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()]
+    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()]
+    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()]
+    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()]
+    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()]
+    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()]
+    return(apiclient.listTemplates(cmd))
+
+
+def list_domains(apiclient, **kwargs):
+    """Lists domains"""
+
+    cmd = listDomains.listDomainsCmd()
+    [setattr(cmd, k, v) for k, v in kwargs.items()]
+    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()]
+    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()]
+    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()]
+    return(apiclient.listSnapshotPolicies(cmd))
+
+
+def list_events(apiclient, **kwargs):
+    """Lists events"""
+
+    cmd = listEvents.listEventsCmd()
+    [setattr(cmd, k, v) for k, v in kwargs.items()]
+    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()]
+    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()]
+    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()]
+    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()]
+    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()]
+    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()]
+    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()]
+    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()]
+    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()]
+    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 find_suitable_host(apiclient, vm):
+        """Returns a suitable host for VM migration"""
+
+        hosts = Host.list(apiclient,
+                          virtualmachineid=vm.id,
+                          listall=True)
+
+        if isinstance(hosts, list):
+            assert len(hosts) > 0, "List host should return valid response"
+        else:
+            raise Exception("Exception: List host should return valid response")
+        return hosts[0]
+
+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_portable_ip_range_services(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 = None
+
+    return services

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ec00a6fb/tools/marvin/build/lib/marvin/integration/lib/utils.py
----------------------------------------------------------------------
diff --git a/tools/marvin/build/lib/marvin/integration/lib/utils.py b/tools/marvin/build/lib/marvin/integration/lib/utils.py
new file mode 100644
index 0000000..d81e80d
--- /dev/null
+++ b/tools/marvin/build/lib/marvin/integration/lib/utils.py
@@ -0,0 +1,320 @@
+# 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.
+"""Utilities functions
+"""
+
+import marvin
+import os
+import time
+import logging
+import string
+import random
+import imaplib
+import email
+import socket
+import urlparse
+import datetime
+from marvin.cloudstackAPI import *
+from marvin.remoteSSHClient import remoteSSHClient
+
+
+def restart_mgmt_server(server):
+    """Restarts the management server"""
+
+    try:
+        # Get the SSH client
+        ssh = is_server_ssh_ready(
+            server["ipaddress"],
+            server["port"],
+            server["username"],
+            server["password"],
+        )
+        result = ssh.execute("/etc/init.d/cloud-management restart")
+        res = str(result)
+        # Server Stop - OK
+        # Server Start - OK
+        if res.count("OK") != 2:
+            raise ("ErrorInReboot!")
+    except Exception as e:
+        raise e
+    return
+
+
+def fetch_latest_mail(services, from_mail):
+    """Fetch mail"""
+
+    # Login to mail server to verify email
+    mail = imaplib.IMAP4_SSL(services["server"])
+    mail.login(
+        services["email"],
+        services["password"]
+    )
+    mail.list()
+    mail.select(services["folder"])
+    date = (datetime.date.today() - datetime.timedelta(1)).strftime("%d-%b-%Y")
+
+    result, data = mail.uid(
+        'search',
+        None,
+        '(SENTSINCE {date} HEADER FROM "{mail}")'.format(
+            date=date,
+            mail=from_mail
+        )
+    )
+    # Return False if email is not present
+    if data == []:
+        return False
+
+    latest_email_uid = data[0].split()[-1]
+    result, data = mail.uid('fetch', latest_email_uid, '(RFC822)')
+    raw_email = data[0][1]
+    email_message = email.message_from_string(raw_email)
+    result = get_first_text_block(email_message)
+    return result
+
+
+def get_first_text_block(email_message_instance):
+    """fetches first text block from the mail"""
+    maintype = email_message_instance.get_content_maintype()
+    if maintype == 'multipart':
+        for part in email_message_instance.get_payload():
+            if part.get_content_maintype() == 'text':
+                return part.get_payload()
+    elif maintype == 'text':
+        return email_message_instance.get_payload()
+
+
+def random_gen(id=None, 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 id:
+        return ''.join([id, '-', randomstr])
+    return randomstr
+
+
+def cleanup_resources(api_client, resources):
+    """Delete resources"""
+    for obj in resources:
+        obj.delete(api_client)
+
+
+def is_server_ssh_ready(ipaddress, port, username, password, retries=10, timeout=30, keyPairFileLocation=None):
+    """Return ssh handle else wait till sshd is running"""
+    try:
+        ssh = remoteSSHClient(
+            host=ipaddress,
+            port=port,
+            user=username,
+            passwd=password,
+            keyPairFileLocation=keyPairFileLocation,
+            retries=retries,
+            delay=timeout)
+    except Exception, e:
+        raise Exception("Failed to bring up ssh service in time. Waited %ss. Error is %s" % (retries * timeout, e))
+    else:
+        return ssh
+
+
+def format_volume_to_ext3(ssh_client, device="/dev/sda"):
+    """Format attached storage to ext3 fs"""
+    cmds = [
+        "echo -e 'n\np\n1\n\n\nw' | fdisk %s" % device,
+        "mkfs.ext3 %s1" % device,
+    ]
+    for c in cmds:
+        ssh_client.execute(c)
+
+
+def fetch_api_client(config_file='datacenterCfg'):
+    """Fetch the Cloudstack API Client"""
+    config = marvin.configGenerator.get_setup_config(config_file)
+    mgt = config.mgtSvr[0]
+    testClientLogger = logging.getLogger("testClient")
+    asyncTimeout = 3600
+    return cloudstackAPIClient.CloudStackAPIClient(
+        marvin.cloudstackConnection.cloudConnection(
+            mgt.mgtSvrIp,
+            mgt.port,
+            mgt.apiKey,
+            mgt.securityKey,
+            asyncTimeout,
+            testClientLogger
+        )
+    )
+
+def get_host_credentials(config, hostip):
+    """Get login information for a host `hostip` (ipv4) from marvin's `config`
+
+    @return the tuple username, password for the host else raise keyerror"""
+    for zone in config.zones:
+        for pod in zone.pods:
+            for cluster in pod.clusters:
+                for host in cluster.hosts:
+                    if str(host.url).startswith('http'):
+                        hostname = urlparse.urlsplit(str(host.url)).netloc
+                    else:
+                        hostname = str(host.url)
+                    try:
+                        if socket.getfqdn(hostip) == socket.getfqdn(hostname):
+                            return host.username, host.password
+                    except socket.error, e:
+                        raise Exception("Unresolvable host %s error is %s" % (hostip, e))
+    raise KeyError("Please provide the marvin configuration file with credentials to your hosts")
+
+
+def get_process_status(hostip, port, username, password, linklocalip, process, hypervisor=None):
+    """Double hop and returns a process status"""
+
+    #SSH to the machine
+    ssh = remoteSSHClient(hostip, port, username, password)
+    if str(hypervisor).lower() == 'vmware':
+        ssh_command = "ssh -i /var/cloudstack/management/.ssh/id_rsa -ostricthostkeychecking=no "
+    else:
+        ssh_command = "ssh -i ~/.ssh/id_rsa.cloud -ostricthostkeychecking=no "
+
+    ssh_command = ssh_command +\
+                  "-oUserKnownHostsFile=/dev/null -p 3922 %s %s" % (
+                      linklocalip,
+                      process)
+
+    # Double hop into router
+    timeout = 5
+    # Ensure the SSH login is successful
+    while True:
+        res = ssh.execute(ssh_command)
+
+        if res[0] != "Host key verification failed.":
+            break
+        elif timeout == 0:
+            break
+
+        time.sleep(5)
+        timeout = timeout - 1
+    return res
+
+
+def isAlmostEqual(first_digit, second_digit, range=0):
+    digits_equal_within_range = False
+
+    try:
+        if ((first_digit - range) < second_digit < (first_digit + range)):
+            digits_equal_within_range = True
+    except Exception as e:
+        raise e
+    return digits_equal_within_range
+
+
+def xsplit(txt, seps):
+    """
+    Split a string in `txt` by list of delimiters in `seps`
+    @param txt: string to split
+    @param seps: list of separators
+    @return: list of split units
+    """
+    default_sep = seps[0]
+    for sep in seps[1:]: # we skip seps[0] because that's the default separator
+        txt = txt.replace(sep, default_sep)
+    return [i.strip() for i in txt.split(default_sep)]
+
+def is_snapshot_on_nfs(apiclient, dbconn, config, zoneid, snapshotid):
+    """
+    Checks whether a snapshot with id (not UUID) `snapshotid` is present on the nfs storage
+
+    @param apiclient: api client connection
+    @param @dbconn:  connection to the cloudstack db
+    @param config: marvin configuration file
+    @param zoneid: uuid of the zone on which the secondary nfs storage pool is mounted
+    @param snapshotid: uuid of the snapshot
+    @return: True if snapshot is found, False otherwise
+    """
+
+    from base import ImageStore, Snapshot
+    secondaryStores = ImageStore.list(apiclient, zoneid=zoneid)
+
+    assert isinstance(secondaryStores, list), "Not a valid response for listImageStores"
+    assert len(secondaryStores) != 0, "No image stores found in zone %s" % zoneid
+
+    secondaryStore = secondaryStores[0]
+
+    if str(secondaryStore.providername).lower() != "nfs":
+        raise Exception(
+            "is_snapshot_on_nfs works only against nfs secondary storage. found %s" % str(secondaryStore.providername))
+
+    qresultset = dbconn.execute(
+                        "select id from snapshots where uuid = '%s';" \
+                        % str(snapshotid)
+                        )
+    if len(qresultset) == 0:
+        raise Exception(
+            "No snapshot found in cloudstack with id %s" % snapshotid)
+
+
+    snapshotid = qresultset[0][0]
+    qresultset = dbconn.execute(
+        "select install_path from snapshot_store_ref where snapshot_id='%s' and store_role='Image';" % snapshotid
+    )
+
+    assert isinstance(qresultset, list), "Invalid db query response for snapshot %s" % snapshotid
+
+    if len(qresultset) == 0:
+        #Snapshot does not exist
+        return False
+
+    snapshotPath = qresultset[0][0]
+
+    nfsurl = secondaryStore.url
+    from urllib2 import urlparse
+    parse_url = urlparse.urlsplit(nfsurl, scheme='nfs')
+    host, path = parse_url.netloc, parse_url.path
+
+    if not config.mgtSvr:
+        raise Exception("Your marvin configuration does not contain mgmt server credentials")
+    mgtSvr, user, passwd = config.mgtSvr[0].mgtSvrIp, config.mgtSvr[0].user, config.mgtSvr[0].passwd
+
+    try:
+        ssh_client = remoteSSHClient(
+            mgtSvr,
+            22,
+            user,
+            passwd
+        )
+        cmds = [
+                "mkdir -p %s /mnt/tmp",
+                "mount -t %s %s%s /mnt/tmp" % (
+                    'nfs',
+                    host,
+                    path,
+                    ),
+                "test -f %s && echo 'snapshot exists'" % (
+                    os.path.join("/mnt/tmp", snapshotPath)
+                    ),
+            ]
+
+        for c in cmds:
+            result = ssh_client.execute(c)
+
+        # Unmount the Sec Storage
+        cmds = [
+                "cd",
+                "umount /mnt/tmp",
+            ]
+        for c in cmds:
+            ssh_client.execute(c)
+    except Exception as e:
+        raise Exception("SSH failed for management server: %s - %s" %
+                      (config.mgtSvr[0].mgtSvrIp, e))
+    return 'snapshot exists' in result

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

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ec00a6fb/tools/marvin/build/lib/marvin/marvinPlugin.py
----------------------------------------------------------------------
diff --git a/tools/marvin/build/lib/marvin/marvinPlugin.py b/tools/marvin/build/lib/marvin/marvinPlugin.py
new file mode 100644
index 0000000..aded17c
--- /dev/null
+++ b/tools/marvin/build/lib/marvin/marvinPlugin.py
@@ -0,0 +1,144 @@
+# 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 marvin
+import sys
+import logging
+import nose.core
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin import deployDataCenter
+from nose.plugins.base import Plugin
+
+
+class MarvinPlugin(Plugin):
+    """
+    Custom plugin for the cloudstackTestCases to be run using nose
+    """
+
+    name = "marvin"
+
+    def configure(self, options, config):
+        if hasattr(options, self.enableOpt):
+            if not getattr(options, self.enableOpt):
+                self.enabled = False
+                return
+            else:
+                self.enabled = True
+
+        self.logformat = logging.Formatter("%(asctime)s - %(levelname)s - " +
+                                           "%(name)s - %(message)s")
+
+        if options.debug_log:
+            self.logger = logging.getLogger("NoseTestExecuteEngine")
+            self.debug_stream = logging.FileHandler(options.debug_log)
+            self.debug_stream.setFormatter(self.logformat)
+            self.logger.addHandler(self.debug_stream)
+            self.logger.setLevel(logging.DEBUG)
+
+        if options.result_log:
+            ch = logging.StreamHandler()
+            ch.setLevel(logging.ERROR)
+            ch.setFormatter(self.logformat)
+            self.logger.addHandler(ch)
+            self.result_stream = open(options.result_log, "w")
+        else:
+            self.result_stream = sys.stdout
+
+        deploy = deployDataCenter.deployDataCenters(options.config)
+        deploy.loadCfg() if options.load else deploy.deploy()
+        self.setClient(deploy.testClient)
+        self.setConfig(deploy.getCfg())
+
+        self.testrunner = nose.core.TextTestRunner(stream=self.result_stream,
+                                                   descriptions=True,
+                                                   verbosity=2, config=config)
+
+    def options(self, parser, env):
+        """
+        Register command line options
+        """
+        parser.add_option("--marvin-config", action="store",
+                          default=env.get('MARVIN_CONFIG', './datacenter.cfg'),
+                          dest="config",
+                          help="Marvin's configuration file where the " +
+                               "datacenter information is specified " +
+                               "[MARVIN_CONFIG]")
+        parser.add_option("--result-log", action="store",
+                          default=env.get('RESULT_LOG', None),
+                          dest="result_log",
+                          help="The path to the results file where test " +
+                               "summary will be written to [RESULT_LOG]")
+        parser.add_option("--client-log", action="store",
+                          default=env.get('DEBUG_LOG', 'debug.log'),
+                          dest="debug_log",
+                          help="The path to the testcase debug logs " +
+                          "[DEBUG_LOG]")
+        parser.add_option("--load", action="store_true", default=False,
+                          dest="load",
+                          help="Only load the deployment configuration given")
+
+        Plugin.options(self, parser, env)
+
+    def __init__(self):
+        self.identifier = None
+        Plugin.__init__(self)
+
+    def prepareTestRunner(self, runner):
+        return self.testrunner
+
+    def wantClass(self, cls):
+        if cls.__name__ == 'cloudstackTestCase':
+            return False
+        if issubclass(cls, cloudstackTestCase):
+            return True
+        return None
+
+    def loadTestsFromTestCase(self, cls):
+        if cls.__name__ != 'cloudstackTestCase':
+            self.identifier = cls.__name__
+            self._injectClients(cls)
+
+    def setClient(self, client):
+        if client is not None:
+            self.testclient = client
+
+    def setConfig(self, config):
+        if config is not None:
+            self.config = config
+
+    def beforeTest(self, test):
+        testname = test.__str__().split()[0]
+        self.testclient.identifier = '-'.join([self.identifier, testname])
+        self.logger.name = test.__str__()
+
+    def _injectClients(self, test):
+        self.debug_stream. \
+            setFormatter(logging.
+                         Formatter("%(asctime)s - %(levelname)s - %(name)s" +
+                                   " - %(message)s"))
+        setattr(test, "debug", self.logger.debug)
+        setattr(test, "info", self.logger.info)
+        setattr(test, "warn", self.logger.warning)
+        setattr(test, "testClient", self.testclient)
+        setattr(test, "config", self.config)
+        if self.testclient.identifier is None:
+            self.testclient.identifier = self.identifier
+        setattr(test, "clstestclient", self.testclient)
+        if hasattr(test, "user"):
+            # when the class-level attr applied. all test runs as 'user'
+            self.testclient.createUserApiClient(test.UserName, test.DomainName,
+                                                test.AcctType)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ec00a6fb/tools/marvin/build/lib/marvin/remoteSSHClient.py
----------------------------------------------------------------------
diff --git a/tools/marvin/build/lib/marvin/remoteSSHClient.py b/tools/marvin/build/lib/marvin/remoteSSHClient.py
new file mode 100644
index 0000000..fea9b12
--- /dev/null
+++ b/tools/marvin/build/lib/marvin/remoteSSHClient.py
@@ -0,0 +1,108 @@
+# 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 paramiko
+import time
+import cloudstackException
+import contextlib
+import logging
+from contextlib import closing
+
+
+class remoteSSHClient(object):
+    def __init__(self, host, port, user, passwd, retries=10, delay=30,
+                 log_lvl=logging.INFO, keyPairFileLocation=None):
+        self.host = host
+        self.port = port
+        self.user = user
+        self.passwd = passwd
+        self.keyPairFile = keyPairFileLocation
+        self.ssh = paramiko.SSHClient()
+        self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
+        self.logger = logging.getLogger('sshClient')
+        ch = logging.StreamHandler()
+        ch.setLevel(log_lvl)
+        self.logger.addHandler(ch)
+
+        retry_count = retries
+        while retry_count >= 0:
+            try:
+                if keyPairFileLocation is None:
+                    self.ssh.connect(str(host), int(port), user, passwd)
+                    self.logger.debug("SSH connect: %s@%s with passwd %s" %
+                                      (user, str(host), passwd))
+                else:
+                    self.ssh.connect(hostname=str(host),
+                                     port=int(port),
+                                     username=str(user),
+                                     key_filename=str(keyPairFileLocation),
+                                     look_for_keys=False
+                                     )
+                    self.logger.debug(
+                        "connecting to server %s with user %s key %s" %
+                        (str(host), user, keyPairFileLocation))
+                    self.logger.debug("SSH connect: %s@%s with passwd %s" %
+                                      (user, str(host), passwd))
+            #except paramiko.AuthenticationException, authEx:
+            #    raise cloudstackException. \
+            #        InvalidParameterException("Invalid credentials to "
+            #                                  + "login to %s on port %s" %
+            #                                  (str(host), port))
+            except Exception as se:
+                if retry_count == 0:
+                    raise cloudstackException. \
+                        InvalidParameterException(repr(se))
+            else:
+                return
+
+            retry_count = retry_count - 1
+            time.sleep(delay)
+
+    def execute(self, command):
+        stdin, stdout, stderr = self.ssh.exec_command(command)
+        output = stdout.readlines()
+        errors = stderr.readlines()
+        results = []
+        if output is not None and len(output) == 0:
+            if errors is not None and len(errors) > 0:
+                for error in errors:
+                    results.append(error.rstrip())
+
+        else:
+            for strOut in output:
+                results.append(strOut.rstrip())
+        self.logger.debug("{Cmd: %s via Host: %s} {returns: %s}" %
+                          (command, str(self.host), results))
+        return results
+
+    def scp(self, srcFile, destPath):
+        transport = paramiko.Transport((self.host, int(self.port)))
+        transport.connect(username=self.user, password=self.passwd)
+        sftp = paramiko.SFTPClient.from_transport(transport)
+        try:
+            sftp.put(srcFile, destPath)
+        except IOError, e:
+            raise e
+
+    def close(self):
+        self.ssh.close()
+
+
+if __name__ == "__main__":
+    with contextlib.closing(remoteSSHClient("10.223.75.10", 22, "root",
+                                            "password")) as ssh:
+        print ssh.execute("ls -l")

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ec00a6fb/tools/marvin/build/lib/marvin/sandbox/__init__.py
----------------------------------------------------------------------
diff --git a/tools/marvin/build/lib/marvin/sandbox/__init__.py b/tools/marvin/build/lib/marvin/sandbox/__init__.py
new file mode 100644
index 0000000..57823fc
--- /dev/null
+++ b/tools/marvin/build/lib/marvin/sandbox/__init__.py
@@ -0,0 +1,18 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+# 
+#   http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ec00a6fb/tools/marvin/build/lib/marvin/sandbox/advanced/__init__.py
----------------------------------------------------------------------
diff --git a/tools/marvin/build/lib/marvin/sandbox/advanced/__init__.py b/tools/marvin/build/lib/marvin/sandbox/advanced/__init__.py
new file mode 100644
index 0000000..57823fc
--- /dev/null
+++ b/tools/marvin/build/lib/marvin/sandbox/advanced/__init__.py
@@ -0,0 +1,18 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+# 
+#   http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ec00a6fb/tools/marvin/build/lib/marvin/sandbox/advanced/advanced_env.py
----------------------------------------------------------------------
diff --git a/tools/marvin/build/lib/marvin/sandbox/advanced/advanced_env.py b/tools/marvin/build/lib/marvin/sandbox/advanced/advanced_env.py
new file mode 100644
index 0000000..1728e61
--- /dev/null
+++ b/tools/marvin/build/lib/marvin/sandbox/advanced/advanced_env.py
@@ -0,0 +1,167 @@
+#!/usr/bin/env python
+# 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.
+'''
+############################################################
+# Experimental state of scripts 
+#    * Need to be reviewed
+#    * Only a sandbox
+############################################################
+'''
+import random
+import marvin
+from ConfigParser import SafeConfigParser
+from optparse import OptionParser
+from marvin.configGenerator import *
+
+
+def getGlobalSettings(config):
+   for k, v in dict(config.items('globals')).iteritems():
+        cfg = configuration()
+        cfg.name = k
+        cfg.value = v
+        yield cfg
+
+
+def describeResources(config):
+    zs = cloudstackConfiguration()
+
+    z = zone()
+    z.dns1 = config.get('environment', 'dns')
+    z.internaldns1 = config.get('environment', 'dns')
+    z.name = 'Sandbox-%s'%(config.get('cloudstack', 'hypervisor'))
+    z.networktype = 'Advanced'
+    z.guestcidraddress = '10.1.1.0/24'
+    z.securitygroupenabled = 'false'
+    
+    vpcprovider = provider()
+    vpcprovider.name = 'VpcVirtualRouter'
+
+    lbprovider = provider()
+    lbprovider.name = 'InternalLbVm'
+    
+    pn = physical_network()
+    pn.name = "Sandbox-pnet"
+    pn.vlan = config.get('cloudstack', 'pnet.vlan')
+    pn.tags = ["cloud-simulator-public"]
+    pn.traffictypes = [traffictype("Guest"),
+            traffictype("Management", {"simulator" : "cloud-simulator-mgmt"}),
+            traffictype("Public", {"simulator":"cloud-simulator-public"})]
+    pn.isolationmethods = ["VLAN"]
+    pn.providers.append(vpcprovider)
+    pn.providers.append(lbprovider)
+
+    pn2 = physical_network()
+    pn2.name = "Sandbox-pnet2"
+    pn2.vlan = config.get('cloudstack', 'pnet2.vlan')
+    pn2.tags = ["cloud-simulator-guest"]
+    pn2.traffictypes = [traffictype('Guest', {'simulator': 'cloud-simulator-guest'})]
+    pn2.isolationmethods = ["VLAN"]
+    pn2.providers.append(vpcprovider)
+    pn2.providers.append(lbprovider)
+    
+    z.physical_networks.append(pn)
+    z.physical_networks.append(pn2)
+
+    p = pod()
+    p.name = 'POD0'
+    p.gateway = config.get('cloudstack', 'private.gateway')
+    p.startip =  config.get('cloudstack', 'private.pod.startip')
+    p.endip =  config.get('cloudstack', 'private.pod.endip')
+    p.netmask = config.get('cloudstack', 'private.netmask')
+
+    v = iprange()
+    v.gateway = config.get('cloudstack', 'public.gateway')
+    v.startip = config.get('cloudstack', 'public.vlan.startip')
+    v.endip = config.get('cloudstack', 'public.vlan.endip') 
+    v.netmask = config.get('cloudstack', 'public.netmask')
+    v.vlan = config.get('cloudstack', 'public.vlan')
+    z.ipranges.append(v)
+
+    c = cluster()
+    c.clustername = 'C0'
+    c.hypervisor = config.get('cloudstack', 'hypervisor')
+    c.clustertype = 'CloudManaged'
+
+    h = host()
+    h.username = 'root'
+    h.password = config.get('cloudstack', 'host.password')
+    h.url = 'http://%s'%(config.get('cloudstack', 'host'))
+    c.hosts.append(h)
+
+    ps = primaryStorage()
+    ps.name = 'PS0'
+    ps.url = config.get('cloudstack', 'primary.pool')
+    c.primaryStorages.append(ps)
+
+    p.clusters.append(c)
+    z.pods.append(p)
+
+    secondary = secondaryStorage()
+    secondary.url = config.get('cloudstack', 'secondary.pool')
+    secondary.provider = "NFS"
+    z.secondaryStorages.append(secondary)
+
+    '''Add zone'''
+    zs.zones.append(z)
+
+    '''Add mgt server'''
+    mgt = managementServer()
+    mgt.mgtSvrIp = config.get('environment', 'mshost')
+    mgt.user = config.get('environment', 'mshost.user')
+    mgt.passwd = config.get('environment', 'mshost.passwd')
+    zs.mgtSvr.append(mgt)
+
+    '''Add a database'''
+    db = dbServer()
+    db.dbSvr = config.get('environment', 'mysql.host')
+    db.user = config.get('environment', 'mysql.cloud.user')
+    db.passwd = config.get('environment', 'mysql.cloud.passwd')
+    zs.dbSvr = db
+
+    '''Add some configuration'''
+    [zs.globalConfig.append(cfg) for cfg in getGlobalSettings(config)]
+
+    ''''add loggers'''
+    testClientLogger = logger()
+    testClientLogger.name = 'TestClient'
+    testClientLogger.file = 'testclient.log'
+
+    testCaseLogger = logger()
+    testCaseLogger.name = 'TestCase'
+    testCaseLogger.file = 'testcase.log'
+
+    zs.logger.append(testClientLogger)
+    zs.logger.append(testCaseLogger)
+    return zs
+
+
+if __name__ == '__main__':
+    parser = OptionParser()
+    parser.add_option('-i', '--input', action='store', default='setup.properties', \
+                      dest='input', help='file containing environment setup information')
+    parser.add_option('-o', '--output', action='store', default='./sandbox.cfg', \
+                      dest='output', help='path where environment json will be generated')
+
+
+    (opts, args) = parser.parse_args()
+
+    cfg_parser = SafeConfigParser()
+    cfg_parser.read(opts.input)
+
+    cfg = describeResources(cfg_parser)
+    generate_setup_config(cfg, opts.output)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ec00a6fb/tools/marvin/build/lib/marvin/sandbox/advancedsg/__init__.py
----------------------------------------------------------------------
diff --git a/tools/marvin/build/lib/marvin/sandbox/advancedsg/__init__.py b/tools/marvin/build/lib/marvin/sandbox/advancedsg/__init__.py
new file mode 100644
index 0000000..57823fc
--- /dev/null
+++ b/tools/marvin/build/lib/marvin/sandbox/advancedsg/__init__.py
@@ -0,0 +1,18 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+# 
+#   http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ec00a6fb/tools/marvin/build/lib/marvin/sandbox/advancedsg/advancedsg_env.py
----------------------------------------------------------------------
diff --git a/tools/marvin/build/lib/marvin/sandbox/advancedsg/advancedsg_env.py b/tools/marvin/build/lib/marvin/sandbox/advancedsg/advancedsg_env.py
new file mode 100644
index 0000000..9cf4a0a
--- /dev/null
+++ b/tools/marvin/build/lib/marvin/sandbox/advancedsg/advancedsg_env.py
@@ -0,0 +1,151 @@
+#!/usr/bin/env python
+# 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.
+'''
+############################################################
+# Experimental state of scripts 
+#    * Need to be reviewed
+#    * Only a sandbox
+############################################################
+'''
+import random
+import marvin
+from ConfigParser import SafeConfigParser
+from optparse import OptionParser
+from marvin.configGenerator import *
+
+
+def getGlobalSettings(config):
+   for k, v in dict(config.items('globals')).iteritems():
+        cfg = configuration()
+        cfg.name = k
+        cfg.value = v
+        yield cfg
+
+
+def describeResources(config):
+    zs = cloudstackConfiguration()
+
+    z = zone()
+    z.dns1 = config.get('environment', 'dns')
+    z.internaldns1 = config.get('environment', 'dns')
+    z.name = 'Sandbox-%s'%(config.get('cloudstack', 'hypervisor'))
+    z.networktype = 'Advanced'
+    z.securitygroupenabled = 'true'
+    
+    sgprovider = provider()
+    sgprovider.broadcastdomainrange = 'ZONE'
+    sgprovider.name = 'SecurityGroupProvider'
+    
+    pn = physical_network()
+    pn.name = "Sandbox-pnet"
+    pn.tags = ["cloud-simulator-pnet"]
+    pn.traffictypes = [traffictype("Guest"),
+                       traffictype("Management", {"simulator" : "cloud-simulator-mgmt"})]
+    pn.isolationmethods = ["VLAN"]
+    pn.providers.append(sgprovider)
+
+    z.physical_networks.append(pn)
+
+    p = pod()
+    p.name = 'POD0'
+    p.gateway = config.get('cloudstack', 'private.gateway')
+    p.startip =  config.get('cloudstack', 'private.pod.startip')
+    p.endip =  config.get('cloudstack', 'private.pod.endip')
+    p.netmask = config.get('cloudstack', 'private.netmask')
+
+    v = iprange()
+    v.gateway = config.get('cloudstack', 'guest.gateway')
+    v.startip = config.get('cloudstack', 'guest.vlan.startip')
+    v.endip = config.get('cloudstack', 'guest.vlan.endip') 
+    v.netmask = config.get('cloudstack', 'guest.netmask')
+    v.vlan = config.get('cloudstack', 'guest.vlan')
+    z.ipranges.append(v)
+
+    c = cluster()
+    c.clustername = 'C0'
+    c.hypervisor = config.get('cloudstack', 'hypervisor')
+    c.clustertype = 'CloudManaged'
+
+    h = host()
+    h.username = 'root'
+    h.password = config.get('cloudstack', 'host.password')
+    h.url = 'http://%s'%(config.get('cloudstack', 'host'))
+    c.hosts.append(h)
+
+    ps = primaryStorage()
+    ps.name = 'PS0'
+    ps.url = config.get('cloudstack', 'primary.pool')
+    c.primaryStorages.append(ps)
+
+    p.clusters.append(c)
+    z.pods.append(p)
+
+    secondary = secondaryStorage()
+    secondary.url = config.get('cloudstack', 'secondary.pool')
+    secondary.provider = "NFS"
+    z.secondaryStorages.append(secondary)
+
+    '''Add zone'''
+    zs.zones.append(z)
+
+    '''Add mgt server'''
+    mgt = managementServer()
+    mgt.mgtSvrIp = config.get('environment', 'mshost')
+    mgt.user = config.get('environment', 'mshost.user')
+    mgt.passwd = config.get('environment', 'mshost.passwd')
+    zs.mgtSvr.append(mgt)
+
+    '''Add a database'''
+    db = dbServer()
+    db.dbSvr = config.get('environment', 'mysql.host')
+    db.user = config.get('environment', 'mysql.cloud.user')
+    db.passwd = config.get('environment', 'mysql.cloud.passwd')
+    zs.dbSvr = db
+
+    '''Add some configuration'''
+    [zs.globalConfig.append(cfg) for cfg in getGlobalSettings(config)]
+
+    ''''add loggers'''
+    testClientLogger = logger()
+    testClientLogger.name = 'TestClient'
+    testClientLogger.file = 'testclient.log'
+
+    testCaseLogger = logger()
+    testCaseLogger.name = 'TestCase'
+    testCaseLogger.file = 'testcase.log'
+
+    zs.logger.append(testClientLogger)
+    zs.logger.append(testCaseLogger)
+    return zs
+
+
+if __name__ == '__main__':
+    parser = OptionParser()
+    parser.add_option('-i', '--input', action='store', default='setup.properties', \
+                      dest='input', help='file containing environment setup information')
+    parser.add_option('-o', '--output', action='store', default='./sandbox.cfg', \
+                      dest='output', help='path where environment json will be generated')
+
+
+    (opts, args) = parser.parse_args()
+
+    cfg_parser = SafeConfigParser()
+    cfg_parser.read(opts.input)
+
+    cfg = describeResources(cfg_parser)
+    generate_setup_config(cfg, opts.output)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ec00a6fb/tools/marvin/build/lib/marvin/sandbox/basic/__init__.py
----------------------------------------------------------------------
diff --git a/tools/marvin/build/lib/marvin/sandbox/basic/__init__.py b/tools/marvin/build/lib/marvin/sandbox/basic/__init__.py
new file mode 100644
index 0000000..57823fc
--- /dev/null
+++ b/tools/marvin/build/lib/marvin/sandbox/basic/__init__.py
@@ -0,0 +1,18 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+# 
+#   http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ec00a6fb/tools/marvin/build/lib/marvin/sandbox/basic/basic_env.py
----------------------------------------------------------------------
diff --git a/tools/marvin/build/lib/marvin/sandbox/basic/basic_env.py b/tools/marvin/build/lib/marvin/sandbox/basic/basic_env.py
new file mode 100644
index 0000000..bf106fc
--- /dev/null
+++ b/tools/marvin/build/lib/marvin/sandbox/basic/basic_env.py
@@ -0,0 +1,149 @@
+#!/usr/bin/env python
+# 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.
+
+'''
+############################################################
+# Experimental state of scripts 
+#    * Need to be reviewed
+#    * Only a sandbox
+############################################################
+'''
+import random
+import marvin
+from ConfigParser import SafeConfigParser
+from optparse import OptionParser
+from marvin.configGenerator import *
+
+
+def getGlobalSettings(config):
+   for k, v in dict(config.items('globals')).iteritems():
+        cfg = configuration()
+        cfg.name = k
+        cfg.value = v
+        yield cfg
+
+
+def describeResources(config):
+    zs = cloudstackConfiguration()
+
+    z = zone()
+    z.dns1 = config.get('environment', 'dns')
+    z.internaldns1 = config.get('environment', 'dns')
+    z.name = 'Sandbox-%s'%(config.get('cloudstack', 'hypervisor'))
+    z.networktype = 'Basic'
+    z.securitygroupenabled = 'true'
+    
+    sgprovider = provider()
+    sgprovider.broadcastdomainrange = 'Pod'
+    sgprovider.name = 'SecurityGroupProvider'
+    
+    pn = physical_network()
+    pn.name = "Sandbox-pnet"
+    pn.traffictypes = [traffictype("Guest"), traffictype("Management")]
+    pn.isolationmethods = ["L3"]
+    pn.providers.append(sgprovider)
+    
+    z.physical_networks.append(pn)
+
+    p = pod()
+    p.name = 'POD0'
+    p.gateway = config.get('cloudstack', 'private.gateway')
+    p.startip =  config.get('cloudstack', 'private.pod.startip')
+    p.endip =  config.get('cloudstack', 'private.pod.endip')
+    p.netmask = config.get('cloudstack', 'private.netmask')
+
+    v = iprange()
+    v.gateway = config.get('cloudstack', 'public.gateway')
+    v.startip = config.get('cloudstack', 'public.vlan.startip')
+    v.endip = config.get('cloudstack', 'public.vlan.endip') 
+    v.netmask = config.get('cloudstack', 'public.netmask')
+    p.guestIpRanges.append(v)
+
+    c = cluster()
+    c.clustername = 'C0'
+    c.hypervisor = config.get('cloudstack', 'hypervisor')
+    c.clustertype = 'CloudManaged'
+
+    h = host()
+    h.username = 'root'
+    h.password = config.get('cloudstack', 'host.password')
+    h.url = 'http://%s'%(config.get('cloudstack', 'host'))
+    c.hosts.append(h)
+
+    ps = primaryStorage()
+    ps.name = 'PS0'
+    ps.url = config.get('cloudstack', 'primary.pool')
+    c.primaryStorages.append(ps)
+
+    p.clusters.append(c)
+    z.pods.append(p)
+
+    secondary = secondaryStorage()
+    secondary.url = config.get('cloudstack', 'secondary.pool')
+    secondary.provider = "NFS"
+    z.secondaryStorages.append(secondary)
+
+    '''Add zone'''
+    zs.zones.append(z)
+
+    '''Add mgt server'''
+    mgt = managementServer()
+    mgt.mgtSvrIp = config.get('environment', 'mshost')
+    mgt.user = config.get('environment', 'mshost.user')
+    mgt.passwd = config.get('environment', 'mshost.passwd')
+    zs.mgtSvr.append(mgt)
+
+    '''Add a database'''
+    db = dbServer()
+    db.dbSvr = config.get('environment', 'mysql.host')
+    db.user = config.get('environment', 'mysql.cloud.user')
+    db.passwd = config.get('environment', 'mysql.cloud.passwd')
+    zs.dbSvr = db
+
+    '''Add some configuration'''
+    [zs.globalConfig.append(cfg) for cfg in getGlobalSettings(config)]
+
+    ''''add loggers'''
+    testClientLogger = logger()
+    testClientLogger.name = 'TestClient'
+    testClientLogger.file = '/var/log/testclient.log'
+
+    testCaseLogger = logger()
+    testCaseLogger.name = 'TestCase'
+    testCaseLogger.file = '/var/log/testcase.log'
+
+    zs.logger.append(testClientLogger)
+    zs.logger.append(testCaseLogger)
+    return zs
+
+
+if __name__ == '__main__':
+    parser = OptionParser()
+    parser.add_option('-i', '--input', action='store', default='setup.properties', \
+                      dest='input', help='file containing environment setup information')
+    parser.add_option('-o', '--output', action='store', default='./sandbox.cfg', \
+                      dest='output', help='path where environment json will be generated')
+
+
+    (opts, args) = parser.parse_args()
+
+    cfg_parser = SafeConfigParser()
+    cfg_parser.read(opts.input)
+
+    cfg = describeResources(cfg_parser)
+    generate_setup_config(cfg, opts.output)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ec00a6fb/tools/marvin/build/lib/marvin/sandbox/testSetupSuccess.py
----------------------------------------------------------------------
diff --git a/tools/marvin/build/lib/marvin/sandbox/testSetupSuccess.py b/tools/marvin/build/lib/marvin/sandbox/testSetupSuccess.py
new file mode 100644
index 0000000..8a0034c
--- /dev/null
+++ b/tools/marvin/build/lib/marvin/sandbox/testSetupSuccess.py
@@ -0,0 +1,81 @@
+# 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 marvin
+import unittest
+from marvin.cloudstackTestCase import *
+from marvin.cloudstackAPI import *
+from time import sleep as delay
+
+class TestSetupSuccess(cloudstackTestCase):
+    """
+    Test to verify if the cloudstack is ready to launch tests upon
+    1. Verify that system VMs are up and running in all zones
+    2. Verify that built-in templates are Ready in all zones
+    """
+    @classmethod
+    def setUpClass(cls):
+        cls.apiClient = super(TestSetupSuccess, cls).getClsTestClient().getApiClient()
+        
+        zones = listZones.listZonesCmd()
+        cls.zones_list = cls.apiClient.listZones(zones)
+        cls.retry = 50
+        
+    def test_systemVmReady(self):
+        """
+        system VMs need to be ready and Running for each zone in cloudstack
+        """
+        for z in self.zones_list:
+            retry = self.retry
+            while retry != 0:
+                self.debug("looking for system VMs in zone: %s, %s"%(z.id, z.name))
+                sysvms = listSystemVms.listSystemVmsCmd()
+                sysvms.zoneid = z.id
+                sysvms.state = 'Running'
+                sysvms_list = self.apiClient.listSystemVms(sysvms)
+                if sysvms_list is not None and len(sysvms_list) == 2:
+                    assert len(sysvms_list) == 2
+                    self.debug("found %d system VMs running {%s}"%(len(sysvms_list), sysvms_list))
+                    break
+                retry = retry - 1
+                delay(60) #wait a minute for retry
+            self.assertNotEqual(retry, 0, "system VMs not Running in zone %s"%z.name)
+    
+    def test_templateBuiltInReady(self):
+        """
+        built-in templates CentOS to be ready
+        """
+        for z in self.zones_list:
+            retry = self.retry
+            while retry != 0:
+                self.debug("Looking for at least one ready builtin template")
+                templates = listTemplates.listTemplatesCmd()
+                templates.templatefilter = 'featured'
+                templates.listall = 'true'
+                templates_list = self.apiClient.listTemplates(templates)
+                if templates_list is not None:
+                    builtins = [tmpl for tmpl in templates_list if tmpl.templatetype == 'BUILTIN' and tmpl.isready == True]
+                    if len(builtins) > 0:
+                        self.debug("Found %d builtins ready for use %s"%(len(builtins), builtins))
+                        break
+                retry = retry - 1
+                delay(60) #wait a minute for retry
+            self.assertNotEqual(retry, 0, "builtIn templates not ready in zone %s"%z.name)
+            
+    @classmethod
+    def tearDownClass(cls):
+        pass


Mime
View raw message