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