You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by da...@apache.org on 2014/07/28 17:41:19 UTC
[02/18] Marvin + test changes from master Signed-off-by:
SrikanteswaraRao Talluri
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/798a6aa2/tools/marvin/marvin/lib/common.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/lib/common.py b/tools/marvin/marvin/lib/common.py
new file mode 100644
index 0000000..8868d2d
--- /dev/null
+++ b/tools/marvin/marvin/lib/common.py
@@ -0,0 +1,1062 @@
+# 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 (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, ISOLATED_NETWORK, VPC_NETWORK,
+ BASIC_ZONE, FAIL, NAT_RULE, STATIC_NAT_RULE)
+import random
+from marvin.lib.utils import *
+from marvin.lib.base import *
+from marvin.codes import PASS
+
+
+# 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 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()]
+ 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 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 is_public_ip_in_correct_state(apiclient, ipaddressid, state):
+ """ Check if the given IP is in the correct state (given)
+ and return True/False accordingly"""
+ retriesCount = 10
+ while True:
+ portableips = PublicIPAddress.list(apiclient, id=ipaddressid)
+ assert validateList(portableips)[0] == PASS, "IPs list validation failed"
+ if str(portableips[0].state).lower() == state:
+ break
+ elif retriesCount == 0:
+ return False
+ else:
+ retriesCount -= 1
+ time.sleep(60)
+ continue
+ return True
+
+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):
+ """List networks and check if the network state matches the given state"""
+ try:
+ networks = Network.list(apiclient, id=networkid)
+ except Exception as e:
+ raise Exception("Failed while fetching network list with error: %s" % e)
+ assert validateList(networks)[0] == PASS, "Networks list validation failed, list is %s" % networks
+ assert str(networks[0].state).lower() == state, "network state should be %s, it is %s" % (state, networks[0].state)
+ return
+
+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]
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/798a6aa2/tools/marvin/marvin/lib/utils.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/lib/utils.py b/tools/marvin/marvin/lib/utils.py
new file mode 100644
index 0000000..cb5dcfb
--- /dev/null
+++ b/tools/marvin/marvin/lib/utils.py
@@ -0,0 +1,498 @@
+# 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 cloudstackAPIClient, listHosts, listRouters
+from platform import system
+from marvin.cloudstackException import GetDetailExceptionInfo
+from marvin.sshClient import SshClient
+from marvin.codes import (
+ SUCCESS,
+ FAIL,
+ PASS,
+ MATCH_NOT_FOUND,
+ INVALID_INPUT,
+ EMPTY_LIST,
+ FAILED)
+
+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=20, retryinterv=30, timeout=10.0, keyPairFileLocation=None):
+ '''
+ @Name: is_server_ssh_ready
+ @Input: timeout: tcp connection timeout flag,
+ others information need to be added
+ @Output:object for SshClient
+ Name of the function is little misnomer and is not
+ verifying anything as such mentioned
+ '''
+
+ try:
+ ssh = SshClient(
+ host=ipaddress,
+ port=port,
+ user=username,
+ passwd=password,
+ keyPairFiles=keyPairFileLocation,
+ retries=retries,
+ delay=retryinterv,
+ timeout=timeout)
+ except Exception, e:
+ raise Exception("SSH connection has Failed. Waited %ss. Error is %s" % (retries * retryinterv, str(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,
+ 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 = SshClient(hostip, port, username, password)
+ if (str(hypervisor).lower() == 'vmware'
+ or str(hypervisor).lower() == 'hyperv'):
+ 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 get_hypervisor_type(apiclient):
+
+ """Return the hypervisor type of the hosts in setup"""
+
+ cmd = listHosts.listHostsCmd()
+ cmd.type = 'Routing'
+ cmd.listall = True
+ hosts = apiclient.listHosts(cmd)
+ hosts_list_validation_result = validateList(hosts)
+ assert hosts_list_validation_result[0] == PASS, "host list validation failed"
+ return hosts_list_validation_result[1].hypervisor
+
+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
+ """
+ # snapshot extension to be appended to the snapshot path obtained from db
+ snapshot_extensions = {"vmware": ".ovf",
+ "kvm": "",
+ "xenserver": ".vhd",
+ "simulator":""}
+
+ 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,store_id 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
+
+ from base import ImageStore
+ #pass store_id to get the exact storage pool where snapshot is stored
+ secondaryStores = ImageStore.list(apiclient, zoneid=zoneid, id=int(qresultset[0][1]))
+
+ 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))
+
+ hypervisor = get_hypervisor_type(apiclient)
+ # append snapshot extension based on hypervisor, to the snapshot path
+ snapshotPath = str(qresultset[0][0]) + snapshot_extensions[str(hypervisor).lower()]
+
+ 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 = SshClient(
+ 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
+
+def validateList(inp):
+ """
+ @name: validateList
+ @Description: 1. A utility function to validate
+ whether the input passed is a list
+ 2. The list is empty or not
+ 3. If it is list and not empty, return PASS and first element
+ 4. If not reason for FAIL
+ @Input: Input to be validated
+ @output: List, containing [ Result,FirstElement,Reason ]
+ Ist Argument('Result') : FAIL : If it is not a list
+ If it is list but empty
+ PASS : If it is list and not empty
+ IInd Argument('FirstElement'): If it is list and not empty,
+ then first element
+ in it, default to None
+ IIIrd Argument( 'Reason' ): Reason for failure ( FAIL ),
+ default to None.
+ INVALID_INPUT
+ EMPTY_LIST
+ """
+ ret = [FAIL, None, None]
+ if inp is None:
+ ret[2] = INVALID_INPUT
+ return ret
+ if not isinstance(inp, list):
+ ret[2] = INVALID_INPUT
+ return ret
+ if len(inp) == 0:
+ ret[2] = EMPTY_LIST
+ return ret
+ return [PASS, inp[0], None]
+
+def verifyElementInList(inp, toverify, responsevar=None, pos=0):
+ '''
+ @name: verifyElementInList
+ @Description:
+ 1. A utility function to validate
+ whether the input passed is a list.
+ The list is empty or not.
+ If it is list and not empty, verify
+ whether a given element is there in that list or not
+ at a given pos
+ @Input:
+ I : Input to be verified whether its a list or not
+ II : Element to verify whether it exists in the list
+ III : variable name in response object to verify
+ default to None, if None, we will verify for the complete
+ first element EX: state of response object object
+ IV : Position in the list at which the input element to verify
+ default to 0
+ @output: List, containing [ Result,Reason ]
+ Ist Argument('Result') : FAIL : If it is not a list
+ If it is list but empty
+ PASS : If it is list and not empty
+ and matching element was found
+ IIrd Argument( 'Reason' ): Reason for failure ( FAIL ),
+ default to None.
+ INVALID_INPUT
+ EMPTY_LIST
+ MATCH_NOT_FOUND
+ '''
+ if toverify is None or toverify == '' \
+ or pos is None or pos < -1 or pos == '':
+ return [FAIL, INVALID_INPUT]
+ out = validateList(inp)
+ if out[0] == FAIL:
+ return [FAIL, out[2]]
+ if len(inp) > pos:
+ if responsevar is None:
+ if inp[pos] == toverify:
+ return [PASS, None]
+ else:
+ if responsevar in inp[pos].__dict__ and getattr(inp[pos], responsevar) == toverify:
+ return [PASS, None]
+ else:
+ return [FAIL, MATCH_NOT_FOUND]
+ else:
+ return [FAIL, MATCH_NOT_FOUND]
+
+def checkVolumeSize(ssh_handle=None,
+ volume_name="/dev/sda",
+ cmd_inp="/sbin/fdisk -l | grep Disk",
+ size_to_verify=0):
+ '''
+ @Name : getDiskUsage
+ @Desc : provides facility to verify the volume size against the size to verify
+ @Input: 1. ssh_handle : machine against which to execute the disk size cmd
+ 2. volume_name : The name of the volume against which to verify the size
+ 3. cmd_inp : Input command used to veify the size
+ 4. size_to_verify: size against which to compare.
+ @Output: Returns FAILED in case of an issue, else SUCCESS
+ '''
+ try:
+ if ssh_handle is None or cmd_inp is None or volume_name is None:
+ return INVALID_INPUT
+
+ cmd = cmd_inp
+ '''
+ Retrieve the cmd output
+ '''
+ if system().lower() != "windows":
+ fdisk_output = ssh_handle.runCommand(cmd_inp)
+ if fdisk_output["status"] != SUCCESS:
+ return FAILED
+ temp_out = fdisk_output["stdout"]
+ for line in temp_out.split("\n"):
+ if volume_name in line:
+ parts = line.split()
+ if str(parts[-2]) == str(size_to_verify):
+ return [SUCCESS,str(parts[-2])]
+ return [FAILED,"Volume Not Found"]
+ except Exception, e:
+ print "\n Exception Occurred under getDiskUsage: " \
+ "%s" %GetDetailExceptionInfo(e)
+ return [FAILED,GetDetailExceptionInfo(e)]
+
+
+def verifyRouterState(apiclient, routerid, allowedstates):
+ """List the router and verify that its state is in allowed states
+ @output: List, containing [Result, Reason]
+ Ist Argument ('Result'): FAIL: If router state is not
+ in allowed states
+ PASS: If router state is in
+ allowed states"""
+
+ try:
+ cmd = listRouters.listRoutersCmd()
+ cmd.id = routerid
+ cmd.listall = True
+ routers = apiclient.listRouters(cmd)
+ except Exception as e:
+ return [FAIL, e]
+ listvalidationresult = validateList(routers)
+ if listvalidationresult[0] == FAIL:
+ return [FAIL, listvalidationresult[2]]
+ if routers[0].redundantstate not in allowedstates:
+ return [FAIL, "Redundant state of the router should be in %s but is %s" %
+ (allowedstates, routers[0].redundantstate)]
+ return [PASS, None]
+
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/798a6aa2/tools/marvin/marvin/marvinInit.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/marvinInit.py b/tools/marvin/marvin/marvinInit.py
index f722058..c35fec6 100644
--- a/tools/marvin/marvin/marvinInit.py
+++ b/tools/marvin/marvin/marvinInit.py
@@ -15,56 +15,67 @@
# specific language governing permissions and limitations
# under the License.
'''
-@Desc: Initializes the marvin and does required prerequisites
+Initializes the marvin and does required prerequisites
for starting it.
-1. Parses the configuration file passed to marvin and creates a
- parsed config
+ 1. Parses the configuration file passed to marvin and creates a
+ parsed config.
2. Initializes the logging required for marvin.All logs are
now made available under a single timestamped folder.
- 3. Deploys the Data Center based upon input
+ 3. Deploys the Data Center based upon input.
'''
-
-from marvin import configGenerator
-from marvin import cloudstackException
+from marvin.configGenerator import getSetupConfig
from marvin.marvinLog import MarvinLog
-from marvin.deployDataCenter import deployDataCenters
+from marvin.deployDataCenter import DeployDataCenters
+from marvin.cloudstackTestClient import CSTestClient
+from marvin.cloudstackException import GetDetailExceptionInfo
from marvin.codes import(
- YES,
- NO,
+ XEN_SERVER,
SUCCESS,
FAILED
- )
-import sys
-import time
+)
import os
-import logging
-import string
-import random
class MarvinInit:
- def __init__(self, config_file, load_flag, log_folder_path=None):
+
+ def __init__(self, config_file,
+ deploy_dc_flag=None,
+ test_mod_name="deploydc",
+ zone=None,
+ hypervisor_type=None,
+ user_logfolder_path=None):
self.__configFile = config_file
- self.__loadFlag = load_flag
- self.__parsedConfig = None
- self.__logFolderPath = log_folder_path
+ self.__deployFlag = deploy_dc_flag
+ self.__logFolderPath = None
self.__tcRunLogger = None
+ self.__testModName = test_mod_name
self.__testClient = None
- self.__tcRunDebugFile = None
+ self.__tcResultFile = None
+ self.__testDataFilePath = None
+ self.__zoneForTests = zone
+ self.__parsedConfig = None
+ self.__hypervisorType = hypervisor_type
+ self.__userLogFolderPath = user_logfolder_path
def __parseConfig(self):
'''
+ @Name: __parseConfig
@Desc : Parses the configuration file passed and assigns
the parsed configuration
+ @Output : SUCCESS or FAILED
'''
try:
- self.__parsedConfig = configGenerator.\
- getSetupConfig(self.__configFile)
+ if not os.path.isfile(self.__configFile):
+ print "\n=== Marvin Parse Config Init Failed ==="
+ return FAILED
+ self.__parsedConfig = getSetupConfig(self.__configFile)
+ print "\n=== Marvin Parse Config Successful ==="
return SUCCESS
- except Exception, e:
- print "\n Exception Occurred Under __parseConfig : %s" % str(e)
- return None
+ except Exception as e:
+ print "\nException Occurred Under __parseConfig : " \
+ "%s" % GetDetailExceptionInfo(e)
+ return FAILED
def getParsedConfig(self):
return self.__parsedConfig
@@ -78,33 +89,67 @@ class MarvinInit:
def getLogger(self):
return self.__tcRunLogger
- def getDebugFile(self):
- return self.__tcRunDebugFile
+ def getResultFile(self):
+ '''
+ @Name : getDebugFile
+ @Desc : Creates the result file at a given path.
+ @Output : Returns the Result file to be used for writing
+ test outputs
+ '''
+ if self.__logFolderPath is not None:
+ self.__tcResultFile = open(self.__logFolderPath +
+ "/results.txt", "w")
+ return self.__tcResultFile
+
+ def __setHypervisorAndZoneInfo(self):
+ '''
+ @Name : __setHypervisorAndZoneInfo
+ @Desc: Set the HyperVisor and Zone details;
+ default to XenServer
+ '''
+ try:
+ if not self.__hypervisorType:
+ self.__hypervisorType = XEN_SERVER
+ if not self.__zoneForTests:
+ if self.__parsedConfig:
+ for zone in self.__parsedConfig.zones:
+ self.__zoneForTests = zone.name
+ break
+ return SUCCESS
+ except Exception as e:
+ print "\n Exception Occurred Under init " \
+ "%s" % GetDetailExceptionInfo(e)
+ return FAILED
def init(self):
'''
+ @Name : init
@Desc :Initializes the marvin by
1. Parsing the configuration and creating a parsed config
structure
2. Creates a timestamped log folder and provides all logs
to be dumped there
3. Creates the DataCenter based upon configuration provided
+ @Output : SUCCESS or FAILED
'''
try:
- if ((self.__parseConfig() is not None) and
- (self.__initLogging() is not None) and
- (self.__deployDC() is not None)):
+ if ((self.__parseConfig() != FAILED) and
+ (self.__setHypervisorAndZoneInfo())and
+ (self.__setTestDataPath() != FAILED) and
+ (self.__initLogging() != FAILED) and
+ (self.__createTestClient() != FAILED) and
+ (self.__deployDC() != FAILED)):
return SUCCESS
- else:
- return FAILED
- except Exception, e:
- print "\n Exception Occurred Under init %s" % str(e)
+ return FAILED
+ except Exception as e:
+ print "\n Exception Occurred Under init " \
+ "%s" % GetDetailExceptionInfo(e)
return FAILED
def __initLogging(self):
- try:
- '''
- @Desc : 1. Initializes the logging for marvin and so provides
+ '''
+ @Name : __initLogging
+ @Desc : 1. Initializes the logging for marvin and so provides
various log features for automation run.
2. Initializes all logs to be available under
given Folder Path,where all test run logs
@@ -112,58 +157,87 @@ class MarvinInit:
3. All logging like exception log,results, run info etc
for a given test run are available under a given
timestamped folder
- '''
- temp_path = "".join(str(time.time()).split("."))
- if self.__logFolderPath is None:
- log_config = self.__parsedConfig.logger
- if log_config is not None:
- if log_config.LogFolderPath is not None:
- self.logFolderPath = log_config.LogFolderPath + '/' \
- + temp_path
- else:
- self.logFolderPath = temp_path
- else:
- self.logFolderPath = temp_path
- else:
- self.logFolderPath = self.__logFolderPath + '/' + temp_path
- if os.path.exists(self.logFolderPath):
- self.logFolderPath += ''.join(random.choice(
- string.ascii_uppercase +
- string.digits for x in range(3)))
- os.makedirs(self.logFolderPath)
- '''
- Log File Paths
- '''
- tc_failed_exceptionlog = self.logFolderPath + "/failed_" \
- "plus_" \
- "exceptions.txt"
- tc_run_log = self.logFolderPath + "/runinfo.txt"
- self.__tcRunDebugFile = open(self.logFolderPath +
- "/results.txt", "w")
-
+ @Output : SUCCESS or FAILED
+ '''
+ try:
log_obj = MarvinLog("CSLog")
- self.__tcRunLogger = log_obj.setLogHandler(tc_run_log)
- log_obj.setLogHandler(tc_failed_exceptionlog,
- log_level=logging.FATAL)
+ if log_obj:
+ ret = log_obj.\
+ createLogs(self.__testModName,
+ self.__parsedConfig.logger,
+ self.__userLogFolderPath)
+ if ret != FAILED:
+ self.__logFolderPath = log_obj.getLogFolderPath()
+ self.__tcRunLogger = log_obj.getLogger()
+ print "\n=== Marvin Init Logging Successful==="
+ return SUCCESS
+ return FAILED
+ except Exception as e:
+ print "\n Exception Occurred Under __initLogging " \
+ ":%s" % GetDetailExceptionInfo(e)
+ return FAILED
+
+ def __createTestClient(self):
+ '''
+ @Name : __createTestClient
+ @Desc : Creates the TestClient during init
+ based upon the parameters provided
+ @Output: Returns SUCCESS or FAILED
+ '''
+ try:
+ mgt_details = self.__parsedConfig.mgtSvr[0]
+ dbsvr_details = self.__parsedConfig.dbSvr
+ self.__testClient = CSTestClient(mgt_details, dbsvr_details,
+ logger=self.__tcRunLogger,
+ test_data_filepath=
+ self.__testDataFilePath,
+ zone=self.__zoneForTests,
+ hypervisor_type=
+ self.__hypervisorType)
+ if self.__testClient:
+ return self.__testClient.createTestClient()
+ return FAILED
+ except Exception as e:
+ print "\n Exception Occurred Under __createTestClient : %s" % \
+ GetDetailExceptionInfo(e)
+ return FAILED
+
+ def __setTestDataPath(self):
+ '''
+ @Name : __setTestDataPath
+ @Desc : Sets the TestData Path for tests to run
+ @Output:Returns SUCCESS or FAILED
+ '''
+ try:
+ if ((self.__parsedConfig.TestData is not None) and
+ (self.__parsedConfig.TestData.Path is not None)):
+ self.__testDataFilePath = self.__parsedConfig.TestData.Path
+ print "\n=== Marvin Setting TestData Successful==="
return SUCCESS
- except Exception, e:
- print "\n Exception Occurred Under __initLogging :%s" % str(e)
- return None
+ except Exception as e:
+ print "\nException Occurred Under __setTestDataPath : %s" % \
+ GetDetailExceptionInfo(e)
+ return FAILED
def __deployDC(self):
+ '''
+ @Name : __deployDC
+ @Desc : Deploy the DataCenter and returns accordingly.
+ @Output: SUCCESS or FAILED
+ '''
try:
- '''
- Deploy the DataCenter and retrieves test client.
- '''
- deploy_obj = deployDataCenters(self.__parsedConfig,
- self.__tcRunLogger)
- if self.__loadFlag:
- deploy_obj.loadCfg()
- else:
- deploy_obj.deploy()
-
- self.__testClient = deploy_obj.testClient
- return SUCCESS
- except Exception, e:
- print "\n Exception Occurred Under __deployDC : %s" % str(e)
- return None
+ ret = SUCCESS
+ if self.__deployFlag:
+ deploy_obj = DeployDataCenters(self.__testClient,
+ self.__parsedConfig,
+ self.__tcRunLogger)
+ ret = deploy_obj.deploy()
+ if ret == SUCCESS:
+ print "Deploy DC Successful"
+ else:
+ print "Deploy DC Failed"
+ return ret
+ except Exception as e:
+ print "\n Exception Occurred Under __deployDC : %s" % \
+ GetDetailExceptionInfo(e)
+ return FAILED
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/798a6aa2/tools/marvin/marvin/marvinLog.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/marvinLog.py b/tools/marvin/marvin/marvinLog.py
index 76de185..65687aa 100644
--- a/tools/marvin/marvin/marvinLog.py
+++ b/tools/marvin/marvin/marvinLog.py
@@ -20,17 +20,22 @@
import logging
import sys
import time
-from marvin.codes import (NO,
- YES
+import os
+from marvin.codes import (SUCCESS,
+ FAILED
)
+from marvin.cloudstackException import GetDetailExceptionInfo
+from marvin.lib.utils import random_gen
class MarvinLog:
+
'''
+ @Name : MarvinLog
@Desc : provides interface for logging to marvin
@Input : logger_name : name for logger
'''
- logFormat = logging.Formatter("%(asctime)s - %(levelname)s - %(name)s - %(message)s")
+ logFormat = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
_instance = None
def __new__(cls, logger_name):
@@ -39,21 +44,39 @@ class MarvinLog:
return cls._instance
def __init__(self, logger_name):
- self.loggerName = logger_name
- self.logger = None
+ '''
+ @Name: __init__
+ @Input: logger_name for logger
+ '''
+ self.__loggerName = logger_name
+ '''
+ Logger for Logging Info
+ '''
+ self.__logger = None
+ '''
+ Log Folder Directory
+ '''
+ self.__logFolderDir = None
self.__setLogger()
def __setLogger(self):
- self.logger = logging.getLogger(self.loggerName)
- self.logger.setLevel(logging.DEBUG)
+ '''
+ @Name : __setLogger
+ @Desc : Sets the Logger and Level
+ '''
+ self.__logger = logging.getLogger(self.__loggerName)
+ self.__logger.setLevel(logging.DEBUG)
- def setLogHandler(self, log_file_path, log_format=None,
- log_level=logging.DEBUG):
+ def __setLogHandler(self, log_file_path,
+ log_format=None,
+ log_level=logging.DEBUG):
'''
+ @Name : __setLogHandler
@Desc: Adds the given Log handler to the current logger
@Input: log_file_path: Log File Path as where to store the logs
log_format : Format of log messages to be dumped
log_level : Determines the level of logging for this logger
+ @Output: SUCCESS if no issues else FAILED
'''
try:
if log_file_path is not None:
@@ -66,8 +89,98 @@ class MarvinLog:
else:
stream.setFormatter(self.__class__.logFormat)
stream.setLevel(log_level)
- self.logger.addHandler(stream)
- except Exception, e:
- print "\n Exception Occurred Under setLogHandler %s" % str(e)
- finally:
- return self.logger
+ self.__logger.addHandler(stream)
+ return SUCCESS
+ except Exception as e:
+ print "\nException Occurred Under " \
+ "__setLogHandler %s" % GetDetailExceptionInfo(e)
+ return FAILED
+
+ def __cleanPreviousLogs(self, logfolder_to_remove):
+ '''
+ @Name : __cleanPreviousLogs
+ @Desc : Removes the Previous Logs
+ @Return: N\A
+ @Input: logfolder_to_remove: Path of Log to remove
+ '''
+ try:
+ if os.path.isdir(logfolder_to_remove):
+ os.rmdir(logfolder_to_remove)
+ except Exception as e:
+ print "\n Exception Occurred Under __cleanPreviousLogs :%s" % \
+ GetDetailExceptionInfo(e)
+ return FAILED
+
+ def getLogger(self):
+ '''
+ @Name:getLogger
+ @Desc : Returns the Logger
+ '''
+ return self.__logger
+
+ def getLogFolderPath(self):
+ '''
+ @Name : getLogFolderPath
+ @Desc : Returns the final log directory path for marvin run
+ '''
+ return self.__logFolderDir
+
+ def createLogs(self,
+ test_module_name=None,
+ log_cfg=None,
+ user_provided_logpath=None):
+ '''
+ @Name : createLogs
+ @Desc : Gets the Logger with file paths initialized and created
+ @Inputs :test_module_name: Test Module Name to use for logs while
+ creating log folder path
+ log_cfg: Log Configuration provided inside of
+ Configuration
+ user_provided_logpath:LogPath provided by user
+ If user provided log path
+ is available, then one in cfg
+ will not be picked up.
+ @Output : SUCCESS\FAILED
+ '''
+ try:
+ temp_ts = time.strftime("%b_%d_%Y_%H_%M_%S",
+ time.localtime())
+ if test_module_name is None:
+ temp_path = temp_ts + "_" + random_gen()
+ else:
+ temp_path = str(test_module_name) + \
+ "__" + str(temp_ts) + "_" + random_gen()
+
+ if user_provided_logpath:
+ temp_dir = user_provided_logpath
+ elif ((log_cfg is not None) and
+ ('LogFolderPath' in log_cfg.__dict__.keys()) and
+ (log_cfg.__dict__.get('LogFolderPath') is not None)):
+ temp_dir = \
+ log_cfg.__dict__.get('LogFolderPath') + "/MarvinLogs"
+
+ self.__logFolderDir = temp_dir + "//" + temp_path
+ print "\n==== Log Folder Path: %s. " \
+ "All logs will be available here ====" \
+ % str(self.__logFolderDir)
+ os.makedirs(self.__logFolderDir)
+
+ '''
+ Log File Paths
+ 1. FailedExceptionLog
+ 2. RunLog contains the complete Run Information for Test Run
+ 3. ResultFile contains the TC result information for Test Run
+ '''
+ tc_failed_exception_log = \
+ self.__logFolderDir + "/failed_plus_exceptions.txt"
+ tc_run_log = self.__logFolderDir + "/runinfo.txt"
+ if self.__setLogHandler(tc_run_log,
+ log_level=logging.DEBUG) != FAILED:
+ self.__setLogHandler(tc_failed_exception_log,
+ log_level=logging.FATAL)
+ return SUCCESS
+ return FAILED
+ except Exception as e:
+ print "\n Exception Occurred Under createLogs :%s" % \
+ GetDetailExceptionInfo(e)
+ return FAILED