Return-Path: X-Original-To: apmail-cloudstack-commits-archive@www.apache.org Delivered-To: apmail-cloudstack-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 6358510402 for ; Fri, 8 Nov 2013 18:09:06 +0000 (UTC) Received: (qmail 93471 invoked by uid 500); 8 Nov 2013 18:08:27 -0000 Delivered-To: apmail-cloudstack-commits-archive@cloudstack.apache.org Received: (qmail 93374 invoked by uid 500); 8 Nov 2013 18:08:26 -0000 Mailing-List: contact commits-help@cloudstack.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@cloudstack.apache.org Delivered-To: mailing list commits@cloudstack.apache.org Received: (qmail 92547 invoked by uid 99); 8 Nov 2013 18:08:18 -0000 Received: from tyr.zones.apache.org (HELO tyr.zones.apache.org) (140.211.11.114) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 08 Nov 2013 18:08:18 +0000 Received: by tyr.zones.apache.org (Postfix, from userid 65534) id C38E8815F06; Fri, 8 Nov 2013 18:08:17 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: bfederle@apache.org To: commits@cloudstack.apache.org Date: Fri, 08 Nov 2013 18:08:18 -0000 Message-Id: In-Reply-To: <26f77be02cd543c5a934c369c42431db@git.apache.org> References: <26f77be02cd543c5a934c369c42431db@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [02/76] [abbrv] CLOUSTACK-5099: Utils.py-has-wrong-reference, cleaned it. As well added Uniform naming convention Signed-off-by: SrikanteswaraRao Talluri http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ec00a6fb/tools/marvin/build/lib/marvin/integration/lib/common.py ---------------------------------------------------------------------- diff --git a/tools/marvin/build/lib/marvin/integration/lib/common.py b/tools/marvin/build/lib/marvin/integration/lib/common.py new file mode 100644 index 0000000..164ef20 --- /dev/null +++ b/tools/marvin/build/lib/marvin/integration/lib/common.py @@ -0,0 +1,739 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +"""Common functions +""" + +#Import Local Modules +from marvin.cloudstackAPI import * +from marvin.remoteSSHClient import remoteSSHClient +from utils import * +from base import * + +#Import System modules +import time + + +def is_config_suitable(apiclient, name, value): + """ + Ensure if the deployment has the expected `value` for the global setting `name' + @return: true if value is set, else false + """ + configs = Configurations.list(apiclient, name=name) + assert(configs is not None and isinstance(configs, list) and len(configs) > 0) + return configs[0].value == value + +def wait_for_cleanup(apiclient, configs=None): + """Sleeps till the cleanup configs passed""" + + # Configs list consists of the list of global configs + if not isinstance(configs, list): + return + for config in configs: + cmd = listConfigurations.listConfigurationsCmd() + cmd.name = config + cmd.listall = True + try: + config_descs = apiclient.listConfigurations(cmd) + except Exception as e: + raise Exception("Failed to fetch configurations: %s" % e) + + if not isinstance(config_descs, list): + raise Exception("List configs didn't returned a valid data") + + config_desc = config_descs[0] + # Sleep for the config_desc.value time + time.sleep(int(config_desc.value)) + return + +def add_netscaler(apiclient, zoneid, NSservice): + """ Adds Netscaler device and enables NS provider""" + + cmd = listPhysicalNetworks.listPhysicalNetworksCmd() + cmd.zoneid = zoneid + physical_networks = apiclient.listPhysicalNetworks(cmd) + if isinstance(physical_networks, list): + physical_network = physical_networks[0] + + cmd = listNetworkServiceProviders.listNetworkServiceProvidersCmd() + cmd.name = 'Netscaler' + cmd.physicalnetworkid=physical_network.id + nw_service_providers = apiclient.listNetworkServiceProviders(cmd) + + if isinstance(nw_service_providers, list): + netscaler_provider = nw_service_providers[0] + else: + cmd1 = addNetworkServiceProvider.addNetworkServiceProviderCmd() + cmd1.name = 'Netscaler' + cmd1.physicalnetworkid = physical_network.id + netscaler_provider = apiclient.addNetworkServiceProvider(cmd1) + + netscaler = NetScaler.add( + apiclient, + NSservice, + physicalnetworkid=physical_network.id + ) + if netscaler_provider.state != 'Enabled': + cmd = updateNetworkServiceProvider.updateNetworkServiceProviderCmd() + cmd.id = netscaler_provider.id + cmd.state = 'Enabled' + response = apiclient.updateNetworkServiceProvider(cmd) + + return netscaler + +def get_region(apiclient, services=None): + "Returns a default region" + + cmd = listRegions.listRegionsCmd() + if services: + if "regionid" in services: + cmd.id = services["regionid"] + + regions = apiclient.listRegions(cmd) + + if isinstance(regions, list): + assert len(regions) > 0 + return regions[0] + else: + raise Exception("Failed to find specified region.") + +def get_domain(apiclient, services=None): + "Returns a default domain" + + cmd = listDomains.listDomainsCmd() + if services: + if "domainid" in services: + cmd.id = services["domainid"] + + domains = apiclient.listDomains(cmd) + + if isinstance(domains, list): + assert len(domains) > 0 + return domains[0] + else: + raise Exception("Failed to find specified domain.") + + +def get_zone(apiclient, services=None): + "Returns a default zone" + + cmd = listZones.listZonesCmd() + if services: + if "zoneid" in services: + cmd.id = services["zoneid"] + + zones = apiclient.listZones(cmd) + + if isinstance(zones, list): + assert len(zones) > 0, "There are no available zones in the deployment" + return zones[0] + else: + raise Exception("Failed to find specified zone.") + + +def get_pod(apiclient, zoneid, services=None): + "Returns a default pod for specified zone" + + cmd = listPods.listPodsCmd() + cmd.zoneid = zoneid + + if services: + if "podid" in services: + cmd.id = services["podid"] + + pods = apiclient.listPods(cmd) + + if isinstance(pods, list): + assert len(pods) > 0, "No pods found for zone %s"%zoneid + return pods[0] + else: + raise Exception("Exception: Failed to find specified pod.") + + +def get_template(apiclient, zoneid, ostype, services=None): + "Returns a template" + + cmd = listOsTypes.listOsTypesCmd() + cmd.description = ostype + ostypes = apiclient.listOsTypes(cmd) + + if isinstance(ostypes, list): + ostypeid = ostypes[0].id + else: + raise Exception( + "Failed to find OS type with description: %s" % ostype) + + cmd = listTemplates.listTemplatesCmd() + cmd.templatefilter = 'featured' + cmd.zoneid = zoneid + + if services: + if "template" in services: + cmd.id = services["template"] + + list_templates = apiclient.listTemplates(cmd) + + if isinstance(list_templates, list): + assert len(list_templates) > 0, "received empty response on template of type %s"%ostype + for template in list_templates: + if template.ostypeid == ostypeid: + return template + elif template.isready: + return template + + raise Exception("Exception: Failed to find template with OSTypeID: %s" % + ostypeid) + return + + +def download_systemplates_sec_storage(server, services): + """Download System templates on sec storage""" + + try: + # Login to management server + ssh = remoteSSHClient( + server["ipaddress"], + server["port"], + server["username"], + server["password"] + ) + except Exception: + raise Exception("SSH access failted for server with IP address: %s" % + server["ipaddess"]) + # Mount Secondary Storage on Management Server + cmds = [ + "mkdir -p %s" % services["mnt_dir"], + "mount -t nfs %s:/%s %s" % ( + services["sec_storage"], + services["path"], + services["mnt_dir"] + ), + "%s -m %s -u %s -h %s -F" % ( + services["command"], + services["mnt_dir"], + services["download_url"], + services["hypervisor"] + ) + ] + for c in cmds: + result = ssh.execute(c) + + res = str(result) + + # Unmount the Secondary storage + ssh.execute("umount %s" % (services["mnt_dir"])) + + if res.count("Successfully installed system VM template") == 1: + return + else: + raise Exception("Failed to download System Templates on Sec Storage") + return + + +def wait_for_ssvms(apiclient, zoneid, podid, interval=60): + """After setup wait for SSVMs to come Up""" + + time.sleep(interval) + timeout = 40 + while True: + list_ssvm_response = list_ssvms( + apiclient, + systemvmtype='secondarystoragevm', + zoneid=zoneid, + podid=podid + ) + ssvm = list_ssvm_response[0] + if ssvm.state != 'Running': + # Sleep to ensure SSVMs are Up and Running + time.sleep(interval) + timeout = timeout - 1 + elif ssvm.state == 'Running': + break + elif timeout == 0: + raise Exception("SSVM failed to come up") + break + + timeout = 40 + while True: + list_ssvm_response = list_ssvms( + apiclient, + systemvmtype='consoleproxy', + zoneid=zoneid, + podid=podid + ) + cpvm = list_ssvm_response[0] + if cpvm.state != 'Running': + # Sleep to ensure SSVMs are Up and Running + time.sleep(interval) + timeout = timeout - 1 + elif cpvm.state == 'Running': + break + elif timeout == 0: + raise Exception("CPVM failed to come up") + break + return + +def get_builtin_template_info(apiclient, zoneid): + """Returns hypervisor specific infor for templates""" + + list_template_response = Template.list( + apiclient, + templatefilter='featured', + zoneid=zoneid, + ) + + for b_template in list_template_response: + if b_template.templatetype == 'BUILTIN': + break + + extract_response = Template.extract(apiclient, + b_template.id, + 'HTTP_DOWNLOAD', + zoneid) + + return extract_response.url, b_template.hypervisor, b_template.format + +def download_builtin_templates(apiclient, zoneid, hypervisor, host, + linklocalip, interval=60): + """After setup wait till builtin templates are downloaded""" + + # Change IPTABLES Rules + get_process_status( + host["ipaddress"], + host["port"], + host["username"], + host["password"], + linklocalip, + "iptables -P INPUT ACCEPT" + ) + time.sleep(interval) + # Find the BUILTIN Templates for given Zone, Hypervisor + list_template_response = list_templates( + apiclient, + hypervisor=hypervisor, + zoneid=zoneid, + templatefilter='self' + ) + + if not isinstance(list_template_response, list): + raise Exception("Failed to download BUILTIN templates") + + # Ensure all BUILTIN templates are downloaded + templateid = None + for template in list_template_response: + if template.templatetype == "BUILTIN": + templateid = template.id + + # Sleep to ensure that template is in downloading state after adding + # Sec storage + time.sleep(interval) + while True: + template_response = list_templates( + apiclient, + id=templateid, + zoneid=zoneid, + templatefilter='self' + ) + template = template_response[0] + # If template is ready, + # template.status = Download Complete + # Downloading - x% Downloaded + # Error - Any other string + if template.status == 'Download Complete': + break + + elif 'Downloaded' in template.status: + time.sleep(interval) + + elif 'Installing' not in template.status: + raise Exception("ErrorInDownload") + + return + + +def update_resource_limit(apiclient, resourcetype, account=None, + domainid=None, max=None, projectid=None): + """Updates the resource limit to 'max' for given account""" + + cmd = updateResourceLimit.updateResourceLimitCmd() + cmd.resourcetype = resourcetype + if account: + cmd.account = account + if domainid: + cmd.domainid = domainid + if max: + cmd.max = max + if projectid: + cmd.projectid = projectid + apiclient.updateResourceLimit(cmd) + return + + +def list_os_types(apiclient, **kwargs): + """List all os types matching criteria""" + + cmd = listOsTypes.listOsTypesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listOsTypes(cmd)) + + +def list_routers(apiclient, **kwargs): + """List all Routers matching criteria""" + + cmd = listRouters.listRoutersCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listRouters(cmd)) + + +def list_zones(apiclient, **kwargs): + """List all Zones matching criteria""" + + cmd = listZones.listZonesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listZones(cmd)) + + +def list_networks(apiclient, **kwargs): + """List all Networks matching criteria""" + + cmd = listNetworks.listNetworksCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listNetworks(cmd)) + + +def list_clusters(apiclient, **kwargs): + """List all Clusters matching criteria""" + + cmd = listClusters.listClustersCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listClusters(cmd)) + + +def list_ssvms(apiclient, **kwargs): + """List all SSVMs matching criteria""" + + cmd = listSystemVms.listSystemVmsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listSystemVms(cmd)) + + +def list_storage_pools(apiclient, **kwargs): + """List all storage pools matching criteria""" + + cmd = listStoragePools.listStoragePoolsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listStoragePools(cmd)) + + +def list_virtual_machines(apiclient, **kwargs): + """List all VMs matching criteria""" + + cmd = listVirtualMachines.listVirtualMachinesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listVirtualMachines(cmd)) + + +def list_hosts(apiclient, **kwargs): + """List all Hosts matching criteria""" + + cmd = listHosts.listHostsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listHosts(cmd)) + + +def list_configurations(apiclient, **kwargs): + """List configuration with specified name""" + + cmd = listConfigurations.listConfigurationsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listConfigurations(cmd)) + + +def list_publicIP(apiclient, **kwargs): + """List all Public IPs matching criteria""" + + cmd = listPublicIpAddresses.listPublicIpAddressesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listPublicIpAddresses(cmd)) + + +def list_nat_rules(apiclient, **kwargs): + """List all NAT rules matching criteria""" + + cmd = listPortForwardingRules.listPortForwardingRulesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listPortForwardingRules(cmd)) + + +def list_lb_rules(apiclient, **kwargs): + """List all Load balancing rules matching criteria""" + + cmd = listLoadBalancerRules.listLoadBalancerRulesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listLoadBalancerRules(cmd)) + + +def list_lb_instances(apiclient, **kwargs): + """List all Load balancing instances matching criteria""" + + cmd = listLoadBalancerRuleInstances.listLoadBalancerRuleInstancesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listLoadBalancerRuleInstances(cmd)) + + +def list_firewall_rules(apiclient, **kwargs): + """List all Firewall Rules matching criteria""" + + cmd = listFirewallRules.listFirewallRulesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listFirewallRules(cmd)) + + +def list_volumes(apiclient, **kwargs): + """List all volumes matching criteria""" + + cmd = listVolumes.listVolumesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listVolumes(cmd)) + + +def list_isos(apiclient, **kwargs): + """Lists all available ISO files.""" + + cmd = listIsos.listIsosCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listIsos(cmd)) + + +def list_snapshots(apiclient, **kwargs): + """List all snapshots matching criteria""" + + cmd = listSnapshots.listSnapshotsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listSnapshots(cmd)) + + +def list_templates(apiclient, **kwargs): + """List all templates matching criteria""" + + cmd = listTemplates.listTemplatesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listTemplates(cmd)) + + +def list_domains(apiclient, **kwargs): + """Lists domains""" + + cmd = listDomains.listDomainsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listDomains(cmd)) + + +def list_accounts(apiclient, **kwargs): + """Lists accounts and provides detailed account information for + listed accounts""" + + cmd = listAccounts.listAccountsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listAccounts(cmd)) + + +def list_users(apiclient, **kwargs): + """Lists users and provides detailed account information for + listed users""" + + cmd = listUsers.listUsersCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listUsers(cmd)) + + +def list_snapshot_policy(apiclient, **kwargs): + """Lists snapshot policies.""" + + cmd = listSnapshotPolicies.listSnapshotPoliciesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listSnapshotPolicies(cmd)) + + +def list_events(apiclient, **kwargs): + """Lists events""" + + cmd = listEvents.listEventsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listEvents(cmd)) + + +def list_disk_offering(apiclient, **kwargs): + """Lists all available disk offerings.""" + + cmd = listDiskOfferings.listDiskOfferingsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listDiskOfferings(cmd)) + + +def list_service_offering(apiclient, **kwargs): + """Lists all available service offerings.""" + + cmd = listServiceOfferings.listServiceOfferingsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listServiceOfferings(cmd)) + + +def list_vlan_ipranges(apiclient, **kwargs): + """Lists all VLAN IP ranges.""" + + cmd = listVlanIpRanges.listVlanIpRangesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listVlanIpRanges(cmd)) + + +def list_usage_records(apiclient, **kwargs): + """Lists usage records for accounts""" + + cmd = listUsageRecords.listUsageRecordsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listUsageRecords(cmd)) + + +def list_nw_service_prividers(apiclient, **kwargs): + """Lists Network service providers""" + + cmd = listNetworkServiceProviders.listNetworkServiceProvidersCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listNetworkServiceProviders(cmd)) + + +def list_virtual_router_elements(apiclient, **kwargs): + """Lists Virtual Router elements""" + + cmd = listVirtualRouterElements.listVirtualRouterElementsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listVirtualRouterElements(cmd)) + + +def list_network_offerings(apiclient, **kwargs): + """Lists network offerings""" + + cmd = listNetworkOfferings.listNetworkOfferingsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listNetworkOfferings(cmd)) + + +def list_resource_limits(apiclient, **kwargs): + """Lists resource limits""" + + cmd = listResourceLimits.listResourceLimitsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listResourceLimits(cmd)) + +def list_vpc_offerings(apiclient, **kwargs): + """ Lists VPC offerings """ + + cmd = listVPCOfferings.listVPCOfferingsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listVPCOfferings(cmd)) + +def update_resource_count(apiclient, domainid, accountid=None, + projectid=None, rtype=None): + """updates the resource count + 0 - VM + 1 - Public IP + 2 - Volume + 3 - Snapshot + 4 - Template + 5 - Projects + 6 - Network + 7 - VPC + 8 - CPUs + 9 - RAM + 10 - Primary (shared) storage (Volumes) + 11 - Secondary storage (Snapshots, Templates & ISOs) + """ + + Resources.updateCount(apiclient, + domainid=domainid, + account=accountid if accountid else None, + projectid=projectid if projectid else None, + resourcetype=rtype if rtype else None + ) + return + +def find_suitable_host(apiclient, vm): + """Returns a suitable host for VM migration""" + + hosts = Host.list(apiclient, + virtualmachineid=vm.id, + listall=True) + + if isinstance(hosts, list): + assert len(hosts) > 0, "List host should return valid response" + else: + raise Exception("Exception: List host should return valid response") + return hosts[0] + +def get_resource_type(resource_id): + """Returns resource type""" + + lookup = { 0: "VM", + 1: "Public IP", + 2: "Volume", + 3: "Snapshot", + 4: "Template", + 5: "Projects", + 6: "Network", + 7: "VPC", + 8: "CPUs", + 9: "RAM", + 10: "Primary (shared) storage (Volumes)", + 11: "Secondary storage (Snapshots, Templates & ISOs)" + } + + return lookup[resource_id] + +def get_portable_ip_range_services(config): + """ Reads config values related to portable ip and fills up + services accordingly""" + + services = {} + attributeError = False + + if config.portableIpRange.startip: + services["startip"] = config.portableIpRange.startip + else: + attributeError = True + + if config.portableIpRange.endip: + services["endip"] = config.portableIpRange.endip + else: + attributeError = True + + if config.portableIpRange.netmask: + services["netmask"] = config.portableIpRange.netmask + else: + attributeError = True + + if config.portableIpRange.gateway: + services["gateway"] = config.portableIpRange.gateway + else: + attributeError = True + + if config.portableIpRange.vlan: + services["vlan"] = config.portableIpRange.vlan + + if attributeError: + services = None + + return services http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ec00a6fb/tools/marvin/build/lib/marvin/integration/lib/utils.py ---------------------------------------------------------------------- diff --git a/tools/marvin/build/lib/marvin/integration/lib/utils.py b/tools/marvin/build/lib/marvin/integration/lib/utils.py new file mode 100644 index 0000000..d81e80d --- /dev/null +++ b/tools/marvin/build/lib/marvin/integration/lib/utils.py @@ -0,0 +1,320 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +"""Utilities functions +""" + +import marvin +import os +import time +import logging +import string +import random +import imaplib +import email +import socket +import urlparse +import datetime +from marvin.cloudstackAPI import * +from marvin.remoteSSHClient import remoteSSHClient + + +def restart_mgmt_server(server): + """Restarts the management server""" + + try: + # Get the SSH client + ssh = is_server_ssh_ready( + server["ipaddress"], + server["port"], + server["username"], + server["password"], + ) + result = ssh.execute("/etc/init.d/cloud-management restart") + res = str(result) + # Server Stop - OK + # Server Start - OK + if res.count("OK") != 2: + raise ("ErrorInReboot!") + except Exception as e: + raise e + return + + +def fetch_latest_mail(services, from_mail): + """Fetch mail""" + + # Login to mail server to verify email + mail = imaplib.IMAP4_SSL(services["server"]) + mail.login( + services["email"], + services["password"] + ) + mail.list() + mail.select(services["folder"]) + date = (datetime.date.today() - datetime.timedelta(1)).strftime("%d-%b-%Y") + + result, data = mail.uid( + 'search', + None, + '(SENTSINCE {date} HEADER FROM "{mail}")'.format( + date=date, + mail=from_mail + ) + ) + # Return False if email is not present + if data == []: + return False + + latest_email_uid = data[0].split()[-1] + result, data = mail.uid('fetch', latest_email_uid, '(RFC822)') + raw_email = data[0][1] + email_message = email.message_from_string(raw_email) + result = get_first_text_block(email_message) + return result + + +def get_first_text_block(email_message_instance): + """fetches first text block from the mail""" + maintype = email_message_instance.get_content_maintype() + if maintype == 'multipart': + for part in email_message_instance.get_payload(): + if part.get_content_maintype() == 'text': + return part.get_payload() + elif maintype == 'text': + return email_message_instance.get_payload() + + +def random_gen(id=None, size=6, chars=string.ascii_uppercase + string.digits): + """Generate Random Strings of variable length""" + randomstr = ''.join(random.choice(chars) for x in range(size)) + if id: + return ''.join([id, '-', randomstr]) + return randomstr + + +def cleanup_resources(api_client, resources): + """Delete resources""" + for obj in resources: + obj.delete(api_client) + + +def is_server_ssh_ready(ipaddress, port, username, password, retries=10, timeout=30, keyPairFileLocation=None): + """Return ssh handle else wait till sshd is running""" + try: + ssh = remoteSSHClient( + host=ipaddress, + port=port, + user=username, + passwd=password, + keyPairFileLocation=keyPairFileLocation, + retries=retries, + delay=timeout) + except Exception, e: + raise Exception("Failed to bring up ssh service in time. Waited %ss. Error is %s" % (retries * timeout, e)) + else: + return ssh + + +def format_volume_to_ext3(ssh_client, device="/dev/sda"): + """Format attached storage to ext3 fs""" + cmds = [ + "echo -e 'n\np\n1\n\n\nw' | fdisk %s" % device, + "mkfs.ext3 %s1" % device, + ] + for c in cmds: + ssh_client.execute(c) + + +def fetch_api_client(config_file='datacenterCfg'): + """Fetch the Cloudstack API Client""" + config = marvin.configGenerator.get_setup_config(config_file) + mgt = config.mgtSvr[0] + testClientLogger = logging.getLogger("testClient") + asyncTimeout = 3600 + return cloudstackAPIClient.CloudStackAPIClient( + marvin.cloudstackConnection.cloudConnection( + mgt.mgtSvrIp, + mgt.port, + mgt.apiKey, + mgt.securityKey, + asyncTimeout, + testClientLogger + ) + ) + +def get_host_credentials(config, hostip): + """Get login information for a host `hostip` (ipv4) from marvin's `config` + + @return the tuple username, password for the host else raise keyerror""" + for zone in config.zones: + for pod in zone.pods: + for cluster in pod.clusters: + for host in cluster.hosts: + if str(host.url).startswith('http'): + hostname = urlparse.urlsplit(str(host.url)).netloc + else: + hostname = str(host.url) + try: + if socket.getfqdn(hostip) == socket.getfqdn(hostname): + return host.username, host.password + except socket.error, e: + raise Exception("Unresolvable host %s error is %s" % (hostip, e)) + raise KeyError("Please provide the marvin configuration file with credentials to your hosts") + + +def get_process_status(hostip, port, username, password, linklocalip, process, hypervisor=None): + """Double hop and returns a process status""" + + #SSH to the machine + ssh = remoteSSHClient(hostip, port, username, password) + if str(hypervisor).lower() == 'vmware': + ssh_command = "ssh -i /var/cloudstack/management/.ssh/id_rsa -ostricthostkeychecking=no " + else: + ssh_command = "ssh -i ~/.ssh/id_rsa.cloud -ostricthostkeychecking=no " + + ssh_command = ssh_command +\ + "-oUserKnownHostsFile=/dev/null -p 3922 %s %s" % ( + linklocalip, + process) + + # Double hop into router + timeout = 5 + # Ensure the SSH login is successful + while True: + res = ssh.execute(ssh_command) + + if res[0] != "Host key verification failed.": + break + elif timeout == 0: + break + + time.sleep(5) + timeout = timeout - 1 + return res + + +def isAlmostEqual(first_digit, second_digit, range=0): + digits_equal_within_range = False + + try: + if ((first_digit - range) < second_digit < (first_digit + range)): + digits_equal_within_range = True + except Exception as e: + raise e + return digits_equal_within_range + + +def xsplit(txt, seps): + """ + Split a string in `txt` by list of delimiters in `seps` + @param txt: string to split + @param seps: list of separators + @return: list of split units + """ + default_sep = seps[0] + for sep in seps[1:]: # we skip seps[0] because that's the default separator + txt = txt.replace(sep, default_sep) + return [i.strip() for i in txt.split(default_sep)] + +def is_snapshot_on_nfs(apiclient, dbconn, config, zoneid, snapshotid): + """ + Checks whether a snapshot with id (not UUID) `snapshotid` is present on the nfs storage + + @param apiclient: api client connection + @param @dbconn: connection to the cloudstack db + @param config: marvin configuration file + @param zoneid: uuid of the zone on which the secondary nfs storage pool is mounted + @param snapshotid: uuid of the snapshot + @return: True if snapshot is found, False otherwise + """ + + from base import ImageStore, Snapshot + secondaryStores = ImageStore.list(apiclient, zoneid=zoneid) + + assert isinstance(secondaryStores, list), "Not a valid response for listImageStores" + assert len(secondaryStores) != 0, "No image stores found in zone %s" % zoneid + + secondaryStore = secondaryStores[0] + + if str(secondaryStore.providername).lower() != "nfs": + raise Exception( + "is_snapshot_on_nfs works only against nfs secondary storage. found %s" % str(secondaryStore.providername)) + + qresultset = dbconn.execute( + "select id from snapshots where uuid = '%s';" \ + % str(snapshotid) + ) + if len(qresultset) == 0: + raise Exception( + "No snapshot found in cloudstack with id %s" % snapshotid) + + + snapshotid = qresultset[0][0] + qresultset = dbconn.execute( + "select install_path from snapshot_store_ref where snapshot_id='%s' and store_role='Image';" % snapshotid + ) + + assert isinstance(qresultset, list), "Invalid db query response for snapshot %s" % snapshotid + + if len(qresultset) == 0: + #Snapshot does not exist + return False + + snapshotPath = qresultset[0][0] + + nfsurl = secondaryStore.url + from urllib2 import urlparse + parse_url = urlparse.urlsplit(nfsurl, scheme='nfs') + host, path = parse_url.netloc, parse_url.path + + if not config.mgtSvr: + raise Exception("Your marvin configuration does not contain mgmt server credentials") + mgtSvr, user, passwd = config.mgtSvr[0].mgtSvrIp, config.mgtSvr[0].user, config.mgtSvr[0].passwd + + try: + ssh_client = remoteSSHClient( + mgtSvr, + 22, + user, + passwd + ) + cmds = [ + "mkdir -p %s /mnt/tmp", + "mount -t %s %s%s /mnt/tmp" % ( + 'nfs', + host, + path, + ), + "test -f %s && echo 'snapshot exists'" % ( + os.path.join("/mnt/tmp", snapshotPath) + ), + ] + + for c in cmds: + result = ssh_client.execute(c) + + # Unmount the Sec Storage + cmds = [ + "cd", + "umount /mnt/tmp", + ] + for c in cmds: + ssh_client.execute(c) + except Exception as e: + raise Exception("SSH failed for management server: %s - %s" % + (config.mgtSvr[0].mgtSvrIp, e)) + return 'snapshot exists' in result http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ec00a6fb/tools/marvin/build/lib/marvin/jsonHelper.py ---------------------------------------------------------------------- diff --git a/tools/marvin/build/lib/marvin/jsonHelper.py b/tools/marvin/build/lib/marvin/jsonHelper.py new file mode 100644 index 0000000..ae40b8d --- /dev/null +++ b/tools/marvin/build/lib/marvin/jsonHelper.py @@ -0,0 +1,381 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +import cloudstackException +import json +import inspect +from cloudstackAPI import * + + +class jsonLoader(object): + '''The recursive class for building and representing objects with.''' + def __init__(self, obj): + for k in obj: + v = obj[k] + if isinstance(v, dict): + setattr(self, k, jsonLoader(v)) + elif isinstance(v, (list, tuple)): + if len(v) > 0 and isinstance(v[0], dict): + setattr(self, k, [jsonLoader(elem) for elem in v]) + else: + setattr(self, k, v) + else: + setattr(self, k, v) + + def __getattr__(self, val): + if val in self.__dict__: + return self.__dict__[val] + else: + return None + + def __repr__(self): + return '{%s}' % str(', '.join('%s : %s' % (k, repr(v)) for (k, v) + in self.__dict__.iteritems())) + + def __str__(self): + return '{%s}' % str(', '.join('%s : %s' % (k, repr(v)) for (k, v) + in self.__dict__.iteritems())) + + +class jsonDump(object): + @staticmethod + def __serialize(obj): + """Recursively walk object's hierarchy.""" + if isinstance(obj, (bool, int, long, float, basestring)): + return obj + elif isinstance(obj, dict): + obj = obj.copy() + newobj = {} + for key in obj: + if obj[key] is not None: + if (isinstance(obj[key], list) and len(obj[key]) == 0): + continue + newobj[key] = jsonDump.__serialize(obj[key]) + + return newobj + elif isinstance(obj, list): + return [jsonDump.__serialize(item) for item in obj] + elif isinstance(obj, tuple): + return tuple(jsonDump.__serialize([item for item in obj])) + elif hasattr(obj, '__dict__'): + return jsonDump.__serialize(obj.__dict__) + else: + return repr(obj) # Don't know how to handle, convert to string + + @staticmethod + def dump(obj): + return jsonDump.__serialize(obj) + + +def getclassFromName(cmd, name): + module = inspect.getmodule(cmd) + return getattr(module, name)() + + +def finalizeResultObj(result, responseName, responsecls): + responsclsLoadable = (responsecls is None + and responseName.endswith("response") + and responseName != "queryasyncjobresultresponse") + if responsclsLoadable: + '''infer the response class from the name''' + moduleName = responseName.replace("response", "") + try: + responsecls = getclassFromName(moduleName, responseName) + except: + pass + + responsNameValid = (responseName is not None + and responseName == "queryasyncjobresultresponse" + and responsecls is not None + and result.jobresult is not None) + if responsNameValid: + result.jobresult = finalizeResultObj(result.jobresult, None, + responsecls) + return result + elif responsecls is not None: + for k, v in result.__dict__.iteritems(): + if k in responsecls.__dict__: + return result + + attr = result.__dict__.keys()[0] + + value = getattr(result, attr) + if not isinstance(value, jsonLoader): + return result + + findObj = False + for k, v in value.__dict__.iteritems(): + if k in responsecls.__dict__: + findObj = True + break + if findObj: + return value + else: + return result + else: + return result + + +def getResultObj(returnObj, responsecls=None): + if len(returnObj) == 0: + return None + responseName = filter(lambda a: a != u'cloudstack-version', + returnObj.keys())[0] + + response = returnObj[responseName] + if len(response) == 0: + return None + + result = jsonLoader(response) + if result.errorcode is not None: + errMsg = "errorCode: %s, errorText:%s" % (result.errorcode, + result.errortext) + respname = responseName.replace("response", "") + raise cloudstackException.cloudstackAPIException(respname, errMsg) + + if result.count is not None: + for key in result.__dict__.iterkeys(): + if key == "count": + continue + else: + return getattr(result, key) + else: + return finalizeResultObj(result, responseName, responsecls) + +if __name__ == "__main__": + + result = '''{ "listnetworkserviceprovidersresponse" : { "count" : 1, + "networkserviceprovider" : [ { "destinationphysicalnetworkid" : "0", + "id" : "d827cae4-4998-4037-95a2-55b92b6318b1", + "name" : "VirtualRouter", + "physicalnetworkid" : "ad2948fc-1054-46c7-b1c7-61d990b86710", + "servicelist" : [ "Vpn", + "Dhcp", + "Dns", + "Gateway", + "Firewall", + "Lb", + "SourceNat", + "StaticNat", + "PortForwarding", + "UserData" + ], + "state" : "Disabled" + } ] + } }''' + nsp = getResultObj(result) + print nsp[0].id + + result = '''{ "listzonesresponse" : { + "count" : 1, + "zone" : [ { "allocationstate" : "Enabled", + "dhcpprovider" : "DhcpServer", + "dns1" : "8.8.8.8", + "dns2" : "8.8.4.4", + "id" : 1, + "internaldns1" : "192.168.110.254", + "internaldns2" : "192.168.110.253", + "name" : "test0", + "networktype" : "Basic", + "securitygroupsenabled" : true, + "zonetoken" : "5e818a11-6b00-3429-9a07-e27511d3169a" + } ] + } +}''' + zones = getResultObj(result) + print zones[0].id + res = authorizeSecurityGroupIngress.authorizeSecurityGroupIngressResponse() + result = '''{ + "queryasyncjobresultresponse" : { + "jobid" : 10, + "jobprocstatus" : 0, + "jobresult" : { + "securitygroup" : { + "account" : "admin", + "description" : "Default Security Group", + "domain" : "ROOT", + "domainid" : 1, + "id" : 1, + "ingressrule" : [ { "account" : "a", + "endport" : 22, + "protocol" : "tcp", + "ruleid" : 1, + "securitygroupname" : "default", + "startport" : 22 + }, + { "account" : "b", + "endport" : 22, + "protocol" : "tcp", + "ruleid" : 2, + "securitygroupname" : "default", + "startport" : 22 + } + ], + "name" : "default" + } + }, + "jobresultcode" : 0, + "jobresulttype" : "object", + "jobstatus" : 1 + } +}''' + asynJob = getResultObj(result, res) + print asynJob.jobid, repr(asynJob.jobresult) + print asynJob.jobresult.ingressrule[0].account + + result = '''{ + "queryasyncjobresultresponse" : { + "errorcode" : 431, + "errortext" : +"Unable to execute API command queryasyncjobresultresponse \ +due to missing parameter jobid" + } +}''' + try: + asynJob = getResultObj(result) + except cloudstackException.cloudstackAPIException, e: + print e + + result = '{ "queryasyncjobresultresponse" : {} }' + asynJob = getResultObj(result) + print asynJob + + result = '{}' + asynJob = getResultObj(result) + print asynJob + + result = '''{ + "createzoneresponse" : { + "zone" : { + "id":1,"name":"test0","dns1":"8.8.8.8","dns2":"8.8.4.4", + "internaldns1":"192.168.110.254","internaldns2":"192.168.110.253", + "networktype":"Basic","securitygroupsenabled":true, + "allocationstate":"Enabled", + "zonetoken":"3442f287-e932-3111-960b-514d1f9c4610", + "dhcpprovider":"DhcpServer" + } + } +}''' + res = createZone.createZoneResponse() + zone = getResultObj(result, res) + print zone.id + + result = '{ "attachvolumeresponse" : {"jobid":24} }' + res = attachVolume.attachVolumeResponse() + res = getResultObj(result, res) + print res + + result = '{ "listtemplatesresponse" : { } }' + print getResultObj(result, listTemplates.listTemplatesResponse()) + + result = '''{ + "queryasyncjobresultresponse" : { + "jobid":34,"jobstatus":2,"jobprocstatus":0,"jobresultcode":530, + "jobresulttype":"object","jobresult":{ + "errorcode":431, + "errortext": +"Please provide either a volume id, or a tuple(device id, instance id)" + } + } +}''' + print getResultObj(result, listTemplates.listTemplatesResponse()) + result = '''{ + "queryasyncjobresultresponse" : { + "jobid":41,"jobstatus":1,"jobprocstatus":0, + "jobresultcode":0,"jobresulttype":"object","jobresult":{ + "virtualmachine":{ + "id":37,"name":"i-2-37-TEST", + "displayname":"i-2-37-TEST","account":"admin", + "domainid":1,"domain":"ROOT", + "created":"2011-08-25T11:13:42-0700", + "state":"Running","haenable":false,"zoneid":1, + "zonename":"test0","hostid":5, + "hostname": + "SimulatedAgent.1e629060-f547-40dd-b792-57cdc4b7d611", + "templateid":10, + "templatename":"CentOS 5.3(64-bit) no GUI (Simulator)", + "templatedisplaytext": + "CentOS 5.3(64-bit) no GUI (Simulator)", + "passwordenabled":false,"serviceofferingid":7, + "serviceofferingname":"Small Instance","cpunumber":1, + "cpuspeed":500,"memory":512,"guestosid":11, + "rootdeviceid":0,"rootdevicetype":"NetworkFilesystem", + "securitygroup":[{"id":1,"name":"default", + "description":"Default Security Group"}], + "nic":[{"id":43,"networkid":204, + "netmask":"255.255.255.0","gateway":"192.168.1.1", + "ipaddress":"192.168.1.27", + "isolationuri":"ec2://untagged", + "broadcasturi":"vlan://untagged", + "traffictype":"Guest","type":"Direct", + "isdefault":true,"macaddress":"06:56:b8:00:00:53"}], + "hypervisor":"Simulator" + } + } + } +}''' + + result = '''{ + "queryasyncjobresultresponse" : { + "accountid":"30910093-22e4-4d3c-a464-8b36b60c8001", + "userid":"cb0aeca3-42ee-47c4-838a-2cd9053441f2", + "cmd":"com.cloud.api.commands.DeployVMCmd","jobstatus":1, + "jobprocstatus":0,"jobresultcode":0,"jobresulttype":"object", + "jobresult":{ + "virtualmachine":{ + "id":"d2e4d724-e089-4e59-be8e-647674059016", + "name":"i-2-14-TEST","displayname":"i-2-14-TEST", + "account":"admin", + "domainid":"8cfafe79-81eb-445e-8608-c5b7c31fc3a5", + "domain":"ROOT","created":"2012-01-15T18:30:11+0530", + "state":"Running","haenable":false, + "zoneid":"30a397e2-1c85-40c0-8463-70278952b046", + "zonename":"Sandbox-simulator", + "hostid":"cc0105aa-a2a9-427a-8ad7-4d835483b8a9", + "hostname": + "SimulatedAgent.9fee20cc-95ca-48b1-8268-5513d6e83a1b", + "templateid":"d92570fa-bf40-44db-9dff-45cc7042604d", + "templatename":"CentOS 5.3(64-bit) no GUI (Simulator)", + "templatedisplaytext":"CentOS 5.3(64-bit) no GUI (Simulator)", + "passwordenabled":false, + "serviceofferingid":"3734d632-797b-4f1d-ac62-33f9cf70d005", + "serviceofferingname":"Sample SO","cpunumber":1,"cpuspeed":100, + "memory":128, + "guestosid":"1e36f523-23e5-4e90-869b-a1b5e9ba674d", + "rootdeviceid":0,"rootdevicetype":"NetworkFilesystem", + "nic":[{"id":"4d3ab903-f511-4dab-8a6d-c2a3b51de7e0", + "networkid":"faeb7f24-a4b9-447d-bec6-c4956c4ab0f6", + "netmask":"255.255.240.0","gateway":"10.6.240.1",' + "ipaddress":"10.6.253.89","isolationuri":"vlan://211", + "broadcasturi":"vlan://211","traffictype":"Guest", + "type":"Isolated","isdefault":true, + "macaddress":"02:00:04:74:00:09"}], + "hypervisor":"Simulator" + } + }, + "created":"2012-01-15T18:30:11+0530", + "jobid":"f4a13f28-fcd6-4d7f-b9cd-ba7eb5a5701f" + } +}''' + vm = getResultObj(result, + deployVirtualMachine.deployVirtualMachineResponse()) + print vm.jobresult.id + + cmd = deployVirtualMachine.deployVirtualMachineCmd() + responsename = cmd.__class__.__name__.replace("Cmd", "Response") + response = getclassFromName(cmd, responsename) + print response.id http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ec00a6fb/tools/marvin/build/lib/marvin/marvinPlugin.py ---------------------------------------------------------------------- diff --git a/tools/marvin/build/lib/marvin/marvinPlugin.py b/tools/marvin/build/lib/marvin/marvinPlugin.py new file mode 100644 index 0000000..aded17c --- /dev/null +++ b/tools/marvin/build/lib/marvin/marvinPlugin.py @@ -0,0 +1,144 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +import marvin +import sys +import logging +import nose.core +from marvin.cloudstackTestCase import cloudstackTestCase +from marvin import deployDataCenter +from nose.plugins.base import Plugin + + +class MarvinPlugin(Plugin): + """ + Custom plugin for the cloudstackTestCases to be run using nose + """ + + name = "marvin" + + def configure(self, options, config): + if hasattr(options, self.enableOpt): + if not getattr(options, self.enableOpt): + self.enabled = False + return + else: + self.enabled = True + + self.logformat = logging.Formatter("%(asctime)s - %(levelname)s - " + + "%(name)s - %(message)s") + + if options.debug_log: + self.logger = logging.getLogger("NoseTestExecuteEngine") + self.debug_stream = logging.FileHandler(options.debug_log) + self.debug_stream.setFormatter(self.logformat) + self.logger.addHandler(self.debug_stream) + self.logger.setLevel(logging.DEBUG) + + if options.result_log: + ch = logging.StreamHandler() + ch.setLevel(logging.ERROR) + ch.setFormatter(self.logformat) + self.logger.addHandler(ch) + self.result_stream = open(options.result_log, "w") + else: + self.result_stream = sys.stdout + + deploy = deployDataCenter.deployDataCenters(options.config) + deploy.loadCfg() if options.load else deploy.deploy() + self.setClient(deploy.testClient) + self.setConfig(deploy.getCfg()) + + self.testrunner = nose.core.TextTestRunner(stream=self.result_stream, + descriptions=True, + verbosity=2, config=config) + + def options(self, parser, env): + """ + Register command line options + """ + parser.add_option("--marvin-config", action="store", + default=env.get('MARVIN_CONFIG', './datacenter.cfg'), + dest="config", + help="Marvin's configuration file where the " + + "datacenter information is specified " + + "[MARVIN_CONFIG]") + parser.add_option("--result-log", action="store", + default=env.get('RESULT_LOG', None), + dest="result_log", + help="The path to the results file where test " + + "summary will be written to [RESULT_LOG]") + parser.add_option("--client-log", action="store", + default=env.get('DEBUG_LOG', 'debug.log'), + dest="debug_log", + help="The path to the testcase debug logs " + + "[DEBUG_LOG]") + parser.add_option("--load", action="store_true", default=False, + dest="load", + help="Only load the deployment configuration given") + + Plugin.options(self, parser, env) + + def __init__(self): + self.identifier = None + Plugin.__init__(self) + + def prepareTestRunner(self, runner): + return self.testrunner + + def wantClass(self, cls): + if cls.__name__ == 'cloudstackTestCase': + return False + if issubclass(cls, cloudstackTestCase): + return True + return None + + def loadTestsFromTestCase(self, cls): + if cls.__name__ != 'cloudstackTestCase': + self.identifier = cls.__name__ + self._injectClients(cls) + + def setClient(self, client): + if client is not None: + self.testclient = client + + def setConfig(self, config): + if config is not None: + self.config = config + + def beforeTest(self, test): + testname = test.__str__().split()[0] + self.testclient.identifier = '-'.join([self.identifier, testname]) + self.logger.name = test.__str__() + + def _injectClients(self, test): + self.debug_stream. \ + setFormatter(logging. + Formatter("%(asctime)s - %(levelname)s - %(name)s" + + " - %(message)s")) + setattr(test, "debug", self.logger.debug) + setattr(test, "info", self.logger.info) + setattr(test, "warn", self.logger.warning) + setattr(test, "testClient", self.testclient) + setattr(test, "config", self.config) + if self.testclient.identifier is None: + self.testclient.identifier = self.identifier + setattr(test, "clstestclient", self.testclient) + if hasattr(test, "user"): + # when the class-level attr applied. all test runs as 'user' + self.testclient.createUserApiClient(test.UserName, test.DomainName, + test.AcctType) http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ec00a6fb/tools/marvin/build/lib/marvin/remoteSSHClient.py ---------------------------------------------------------------------- diff --git a/tools/marvin/build/lib/marvin/remoteSSHClient.py b/tools/marvin/build/lib/marvin/remoteSSHClient.py new file mode 100644 index 0000000..fea9b12 --- /dev/null +++ b/tools/marvin/build/lib/marvin/remoteSSHClient.py @@ -0,0 +1,108 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +import paramiko +import time +import cloudstackException +import contextlib +import logging +from contextlib import closing + + +class remoteSSHClient(object): + def __init__(self, host, port, user, passwd, retries=10, delay=30, + log_lvl=logging.INFO, keyPairFileLocation=None): + self.host = host + self.port = port + self.user = user + self.passwd = passwd + self.keyPairFile = keyPairFileLocation + self.ssh = paramiko.SSHClient() + self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + self.logger = logging.getLogger('sshClient') + ch = logging.StreamHandler() + ch.setLevel(log_lvl) + self.logger.addHandler(ch) + + retry_count = retries + while retry_count >= 0: + try: + if keyPairFileLocation is None: + self.ssh.connect(str(host), int(port), user, passwd) + self.logger.debug("SSH connect: %s@%s with passwd %s" % + (user, str(host), passwd)) + else: + self.ssh.connect(hostname=str(host), + port=int(port), + username=str(user), + key_filename=str(keyPairFileLocation), + look_for_keys=False + ) + self.logger.debug( + "connecting to server %s with user %s key %s" % + (str(host), user, keyPairFileLocation)) + self.logger.debug("SSH connect: %s@%s with passwd %s" % + (user, str(host), passwd)) + #except paramiko.AuthenticationException, authEx: + # raise cloudstackException. \ + # InvalidParameterException("Invalid credentials to " + # + "login to %s on port %s" % + # (str(host), port)) + except Exception as se: + if retry_count == 0: + raise cloudstackException. \ + InvalidParameterException(repr(se)) + else: + return + + retry_count = retry_count - 1 + time.sleep(delay) + + def execute(self, command): + stdin, stdout, stderr = self.ssh.exec_command(command) + output = stdout.readlines() + errors = stderr.readlines() + results = [] + if output is not None and len(output) == 0: + if errors is not None and len(errors) > 0: + for error in errors: + results.append(error.rstrip()) + + else: + for strOut in output: + results.append(strOut.rstrip()) + self.logger.debug("{Cmd: %s via Host: %s} {returns: %s}" % + (command, str(self.host), results)) + return results + + def scp(self, srcFile, destPath): + transport = paramiko.Transport((self.host, int(self.port))) + transport.connect(username=self.user, password=self.passwd) + sftp = paramiko.SFTPClient.from_transport(transport) + try: + sftp.put(srcFile, destPath) + except IOError, e: + raise e + + def close(self): + self.ssh.close() + + +if __name__ == "__main__": + with contextlib.closing(remoteSSHClient("10.223.75.10", 22, "root", + "password")) as ssh: + print ssh.execute("ls -l") http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ec00a6fb/tools/marvin/build/lib/marvin/sandbox/__init__.py ---------------------------------------------------------------------- diff --git a/tools/marvin/build/lib/marvin/sandbox/__init__.py b/tools/marvin/build/lib/marvin/sandbox/__init__.py new file mode 100644 index 0000000..57823fc --- /dev/null +++ b/tools/marvin/build/lib/marvin/sandbox/__init__.py @@ -0,0 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + + http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ec00a6fb/tools/marvin/build/lib/marvin/sandbox/advanced/__init__.py ---------------------------------------------------------------------- diff --git a/tools/marvin/build/lib/marvin/sandbox/advanced/__init__.py b/tools/marvin/build/lib/marvin/sandbox/advanced/__init__.py new file mode 100644 index 0000000..57823fc --- /dev/null +++ b/tools/marvin/build/lib/marvin/sandbox/advanced/__init__.py @@ -0,0 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + + http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ec00a6fb/tools/marvin/build/lib/marvin/sandbox/advanced/advanced_env.py ---------------------------------------------------------------------- diff --git a/tools/marvin/build/lib/marvin/sandbox/advanced/advanced_env.py b/tools/marvin/build/lib/marvin/sandbox/advanced/advanced_env.py new file mode 100644 index 0000000..1728e61 --- /dev/null +++ b/tools/marvin/build/lib/marvin/sandbox/advanced/advanced_env.py @@ -0,0 +1,167 @@ +#!/usr/bin/env python +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +''' +############################################################ +# Experimental state of scripts +# * Need to be reviewed +# * Only a sandbox +############################################################ +''' +import random +import marvin +from ConfigParser import SafeConfigParser +from optparse import OptionParser +from marvin.configGenerator import * + + +def getGlobalSettings(config): + for k, v in dict(config.items('globals')).iteritems(): + cfg = configuration() + cfg.name = k + cfg.value = v + yield cfg + + +def describeResources(config): + zs = cloudstackConfiguration() + + z = zone() + z.dns1 = config.get('environment', 'dns') + z.internaldns1 = config.get('environment', 'dns') + z.name = 'Sandbox-%s'%(config.get('cloudstack', 'hypervisor')) + z.networktype = 'Advanced' + z.guestcidraddress = '10.1.1.0/24' + z.securitygroupenabled = 'false' + + vpcprovider = provider() + vpcprovider.name = 'VpcVirtualRouter' + + lbprovider = provider() + lbprovider.name = 'InternalLbVm' + + pn = physical_network() + pn.name = "Sandbox-pnet" + pn.vlan = config.get('cloudstack', 'pnet.vlan') + pn.tags = ["cloud-simulator-public"] + pn.traffictypes = [traffictype("Guest"), + traffictype("Management", {"simulator" : "cloud-simulator-mgmt"}), + traffictype("Public", {"simulator":"cloud-simulator-public"})] + pn.isolationmethods = ["VLAN"] + pn.providers.append(vpcprovider) + pn.providers.append(lbprovider) + + pn2 = physical_network() + pn2.name = "Sandbox-pnet2" + pn2.vlan = config.get('cloudstack', 'pnet2.vlan') + pn2.tags = ["cloud-simulator-guest"] + pn2.traffictypes = [traffictype('Guest', {'simulator': 'cloud-simulator-guest'})] + pn2.isolationmethods = ["VLAN"] + pn2.providers.append(vpcprovider) + pn2.providers.append(lbprovider) + + z.physical_networks.append(pn) + z.physical_networks.append(pn2) + + p = pod() + p.name = 'POD0' + p.gateway = config.get('cloudstack', 'private.gateway') + p.startip = config.get('cloudstack', 'private.pod.startip') + p.endip = config.get('cloudstack', 'private.pod.endip') + p.netmask = config.get('cloudstack', 'private.netmask') + + v = iprange() + v.gateway = config.get('cloudstack', 'public.gateway') + v.startip = config.get('cloudstack', 'public.vlan.startip') + v.endip = config.get('cloudstack', 'public.vlan.endip') + v.netmask = config.get('cloudstack', 'public.netmask') + v.vlan = config.get('cloudstack', 'public.vlan') + z.ipranges.append(v) + + c = cluster() + c.clustername = 'C0' + c.hypervisor = config.get('cloudstack', 'hypervisor') + c.clustertype = 'CloudManaged' + + h = host() + h.username = 'root' + h.password = config.get('cloudstack', 'host.password') + h.url = 'http://%s'%(config.get('cloudstack', 'host')) + c.hosts.append(h) + + ps = primaryStorage() + ps.name = 'PS0' + ps.url = config.get('cloudstack', 'primary.pool') + c.primaryStorages.append(ps) + + p.clusters.append(c) + z.pods.append(p) + + secondary = secondaryStorage() + secondary.url = config.get('cloudstack', 'secondary.pool') + secondary.provider = "NFS" + z.secondaryStorages.append(secondary) + + '''Add zone''' + zs.zones.append(z) + + '''Add mgt server''' + mgt = managementServer() + mgt.mgtSvrIp = config.get('environment', 'mshost') + mgt.user = config.get('environment', 'mshost.user') + mgt.passwd = config.get('environment', 'mshost.passwd') + zs.mgtSvr.append(mgt) + + '''Add a database''' + db = dbServer() + db.dbSvr = config.get('environment', 'mysql.host') + db.user = config.get('environment', 'mysql.cloud.user') + db.passwd = config.get('environment', 'mysql.cloud.passwd') + zs.dbSvr = db + + '''Add some configuration''' + [zs.globalConfig.append(cfg) for cfg in getGlobalSettings(config)] + + ''''add loggers''' + testClientLogger = logger() + testClientLogger.name = 'TestClient' + testClientLogger.file = 'testclient.log' + + testCaseLogger = logger() + testCaseLogger.name = 'TestCase' + testCaseLogger.file = 'testcase.log' + + zs.logger.append(testClientLogger) + zs.logger.append(testCaseLogger) + return zs + + +if __name__ == '__main__': + parser = OptionParser() + parser.add_option('-i', '--input', action='store', default='setup.properties', \ + dest='input', help='file containing environment setup information') + parser.add_option('-o', '--output', action='store', default='./sandbox.cfg', \ + dest='output', help='path where environment json will be generated') + + + (opts, args) = parser.parse_args() + + cfg_parser = SafeConfigParser() + cfg_parser.read(opts.input) + + cfg = describeResources(cfg_parser) + generate_setup_config(cfg, opts.output) http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ec00a6fb/tools/marvin/build/lib/marvin/sandbox/advancedsg/__init__.py ---------------------------------------------------------------------- diff --git a/tools/marvin/build/lib/marvin/sandbox/advancedsg/__init__.py b/tools/marvin/build/lib/marvin/sandbox/advancedsg/__init__.py new file mode 100644 index 0000000..57823fc --- /dev/null +++ b/tools/marvin/build/lib/marvin/sandbox/advancedsg/__init__.py @@ -0,0 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + + http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ec00a6fb/tools/marvin/build/lib/marvin/sandbox/advancedsg/advancedsg_env.py ---------------------------------------------------------------------- diff --git a/tools/marvin/build/lib/marvin/sandbox/advancedsg/advancedsg_env.py b/tools/marvin/build/lib/marvin/sandbox/advancedsg/advancedsg_env.py new file mode 100644 index 0000000..9cf4a0a --- /dev/null +++ b/tools/marvin/build/lib/marvin/sandbox/advancedsg/advancedsg_env.py @@ -0,0 +1,151 @@ +#!/usr/bin/env python +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +''' +############################################################ +# Experimental state of scripts +# * Need to be reviewed +# * Only a sandbox +############################################################ +''' +import random +import marvin +from ConfigParser import SafeConfigParser +from optparse import OptionParser +from marvin.configGenerator import * + + +def getGlobalSettings(config): + for k, v in dict(config.items('globals')).iteritems(): + cfg = configuration() + cfg.name = k + cfg.value = v + yield cfg + + +def describeResources(config): + zs = cloudstackConfiguration() + + z = zone() + z.dns1 = config.get('environment', 'dns') + z.internaldns1 = config.get('environment', 'dns') + z.name = 'Sandbox-%s'%(config.get('cloudstack', 'hypervisor')) + z.networktype = 'Advanced' + z.securitygroupenabled = 'true' + + sgprovider = provider() + sgprovider.broadcastdomainrange = 'ZONE' + sgprovider.name = 'SecurityGroupProvider' + + pn = physical_network() + pn.name = "Sandbox-pnet" + pn.tags = ["cloud-simulator-pnet"] + pn.traffictypes = [traffictype("Guest"), + traffictype("Management", {"simulator" : "cloud-simulator-mgmt"})] + pn.isolationmethods = ["VLAN"] + pn.providers.append(sgprovider) + + z.physical_networks.append(pn) + + p = pod() + p.name = 'POD0' + p.gateway = config.get('cloudstack', 'private.gateway') + p.startip = config.get('cloudstack', 'private.pod.startip') + p.endip = config.get('cloudstack', 'private.pod.endip') + p.netmask = config.get('cloudstack', 'private.netmask') + + v = iprange() + v.gateway = config.get('cloudstack', 'guest.gateway') + v.startip = config.get('cloudstack', 'guest.vlan.startip') + v.endip = config.get('cloudstack', 'guest.vlan.endip') + v.netmask = config.get('cloudstack', 'guest.netmask') + v.vlan = config.get('cloudstack', 'guest.vlan') + z.ipranges.append(v) + + c = cluster() + c.clustername = 'C0' + c.hypervisor = config.get('cloudstack', 'hypervisor') + c.clustertype = 'CloudManaged' + + h = host() + h.username = 'root' + h.password = config.get('cloudstack', 'host.password') + h.url = 'http://%s'%(config.get('cloudstack', 'host')) + c.hosts.append(h) + + ps = primaryStorage() + ps.name = 'PS0' + ps.url = config.get('cloudstack', 'primary.pool') + c.primaryStorages.append(ps) + + p.clusters.append(c) + z.pods.append(p) + + secondary = secondaryStorage() + secondary.url = config.get('cloudstack', 'secondary.pool') + secondary.provider = "NFS" + z.secondaryStorages.append(secondary) + + '''Add zone''' + zs.zones.append(z) + + '''Add mgt server''' + mgt = managementServer() + mgt.mgtSvrIp = config.get('environment', 'mshost') + mgt.user = config.get('environment', 'mshost.user') + mgt.passwd = config.get('environment', 'mshost.passwd') + zs.mgtSvr.append(mgt) + + '''Add a database''' + db = dbServer() + db.dbSvr = config.get('environment', 'mysql.host') + db.user = config.get('environment', 'mysql.cloud.user') + db.passwd = config.get('environment', 'mysql.cloud.passwd') + zs.dbSvr = db + + '''Add some configuration''' + [zs.globalConfig.append(cfg) for cfg in getGlobalSettings(config)] + + ''''add loggers''' + testClientLogger = logger() + testClientLogger.name = 'TestClient' + testClientLogger.file = 'testclient.log' + + testCaseLogger = logger() + testCaseLogger.name = 'TestCase' + testCaseLogger.file = 'testcase.log' + + zs.logger.append(testClientLogger) + zs.logger.append(testCaseLogger) + return zs + + +if __name__ == '__main__': + parser = OptionParser() + parser.add_option('-i', '--input', action='store', default='setup.properties', \ + dest='input', help='file containing environment setup information') + parser.add_option('-o', '--output', action='store', default='./sandbox.cfg', \ + dest='output', help='path where environment json will be generated') + + + (opts, args) = parser.parse_args() + + cfg_parser = SafeConfigParser() + cfg_parser.read(opts.input) + + cfg = describeResources(cfg_parser) + generate_setup_config(cfg, opts.output) http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ec00a6fb/tools/marvin/build/lib/marvin/sandbox/basic/__init__.py ---------------------------------------------------------------------- diff --git a/tools/marvin/build/lib/marvin/sandbox/basic/__init__.py b/tools/marvin/build/lib/marvin/sandbox/basic/__init__.py new file mode 100644 index 0000000..57823fc --- /dev/null +++ b/tools/marvin/build/lib/marvin/sandbox/basic/__init__.py @@ -0,0 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + + http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ec00a6fb/tools/marvin/build/lib/marvin/sandbox/basic/basic_env.py ---------------------------------------------------------------------- diff --git a/tools/marvin/build/lib/marvin/sandbox/basic/basic_env.py b/tools/marvin/build/lib/marvin/sandbox/basic/basic_env.py new file mode 100644 index 0000000..bf106fc --- /dev/null +++ b/tools/marvin/build/lib/marvin/sandbox/basic/basic_env.py @@ -0,0 +1,149 @@ +#!/usr/bin/env python +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +''' +############################################################ +# Experimental state of scripts +# * Need to be reviewed +# * Only a sandbox +############################################################ +''' +import random +import marvin +from ConfigParser import SafeConfigParser +from optparse import OptionParser +from marvin.configGenerator import * + + +def getGlobalSettings(config): + for k, v in dict(config.items('globals')).iteritems(): + cfg = configuration() + cfg.name = k + cfg.value = v + yield cfg + + +def describeResources(config): + zs = cloudstackConfiguration() + + z = zone() + z.dns1 = config.get('environment', 'dns') + z.internaldns1 = config.get('environment', 'dns') + z.name = 'Sandbox-%s'%(config.get('cloudstack', 'hypervisor')) + z.networktype = 'Basic' + z.securitygroupenabled = 'true' + + sgprovider = provider() + sgprovider.broadcastdomainrange = 'Pod' + sgprovider.name = 'SecurityGroupProvider' + + pn = physical_network() + pn.name = "Sandbox-pnet" + pn.traffictypes = [traffictype("Guest"), traffictype("Management")] + pn.isolationmethods = ["L3"] + pn.providers.append(sgprovider) + + z.physical_networks.append(pn) + + p = pod() + p.name = 'POD0' + p.gateway = config.get('cloudstack', 'private.gateway') + p.startip = config.get('cloudstack', 'private.pod.startip') + p.endip = config.get('cloudstack', 'private.pod.endip') + p.netmask = config.get('cloudstack', 'private.netmask') + + v = iprange() + v.gateway = config.get('cloudstack', 'public.gateway') + v.startip = config.get('cloudstack', 'public.vlan.startip') + v.endip = config.get('cloudstack', 'public.vlan.endip') + v.netmask = config.get('cloudstack', 'public.netmask') + p.guestIpRanges.append(v) + + c = cluster() + c.clustername = 'C0' + c.hypervisor = config.get('cloudstack', 'hypervisor') + c.clustertype = 'CloudManaged' + + h = host() + h.username = 'root' + h.password = config.get('cloudstack', 'host.password') + h.url = 'http://%s'%(config.get('cloudstack', 'host')) + c.hosts.append(h) + + ps = primaryStorage() + ps.name = 'PS0' + ps.url = config.get('cloudstack', 'primary.pool') + c.primaryStorages.append(ps) + + p.clusters.append(c) + z.pods.append(p) + + secondary = secondaryStorage() + secondary.url = config.get('cloudstack', 'secondary.pool') + secondary.provider = "NFS" + z.secondaryStorages.append(secondary) + + '''Add zone''' + zs.zones.append(z) + + '''Add mgt server''' + mgt = managementServer() + mgt.mgtSvrIp = config.get('environment', 'mshost') + mgt.user = config.get('environment', 'mshost.user') + mgt.passwd = config.get('environment', 'mshost.passwd') + zs.mgtSvr.append(mgt) + + '''Add a database''' + db = dbServer() + db.dbSvr = config.get('environment', 'mysql.host') + db.user = config.get('environment', 'mysql.cloud.user') + db.passwd = config.get('environment', 'mysql.cloud.passwd') + zs.dbSvr = db + + '''Add some configuration''' + [zs.globalConfig.append(cfg) for cfg in getGlobalSettings(config)] + + ''''add loggers''' + testClientLogger = logger() + testClientLogger.name = 'TestClient' + testClientLogger.file = '/var/log/testclient.log' + + testCaseLogger = logger() + testCaseLogger.name = 'TestCase' + testCaseLogger.file = '/var/log/testcase.log' + + zs.logger.append(testClientLogger) + zs.logger.append(testCaseLogger) + return zs + + +if __name__ == '__main__': + parser = OptionParser() + parser.add_option('-i', '--input', action='store', default='setup.properties', \ + dest='input', help='file containing environment setup information') + parser.add_option('-o', '--output', action='store', default='./sandbox.cfg', \ + dest='output', help='path where environment json will be generated') + + + (opts, args) = parser.parse_args() + + cfg_parser = SafeConfigParser() + cfg_parser.read(opts.input) + + cfg = describeResources(cfg_parser) + generate_setup_config(cfg, opts.output) http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ec00a6fb/tools/marvin/build/lib/marvin/sandbox/testSetupSuccess.py ---------------------------------------------------------------------- diff --git a/tools/marvin/build/lib/marvin/sandbox/testSetupSuccess.py b/tools/marvin/build/lib/marvin/sandbox/testSetupSuccess.py new file mode 100644 index 0000000..8a0034c --- /dev/null +++ b/tools/marvin/build/lib/marvin/sandbox/testSetupSuccess.py @@ -0,0 +1,81 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +import marvin +import unittest +from marvin.cloudstackTestCase import * +from marvin.cloudstackAPI import * +from time import sleep as delay + +class TestSetupSuccess(cloudstackTestCase): + """ + Test to verify if the cloudstack is ready to launch tests upon + 1. Verify that system VMs are up and running in all zones + 2. Verify that built-in templates are Ready in all zones + """ + @classmethod + def setUpClass(cls): + cls.apiClient = super(TestSetupSuccess, cls).getClsTestClient().getApiClient() + + zones = listZones.listZonesCmd() + cls.zones_list = cls.apiClient.listZones(zones) + cls.retry = 50 + + def test_systemVmReady(self): + """ + system VMs need to be ready and Running for each zone in cloudstack + """ + for z in self.zones_list: + retry = self.retry + while retry != 0: + self.debug("looking for system VMs in zone: %s, %s"%(z.id, z.name)) + sysvms = listSystemVms.listSystemVmsCmd() + sysvms.zoneid = z.id + sysvms.state = 'Running' + sysvms_list = self.apiClient.listSystemVms(sysvms) + if sysvms_list is not None and len(sysvms_list) == 2: + assert len(sysvms_list) == 2 + self.debug("found %d system VMs running {%s}"%(len(sysvms_list), sysvms_list)) + break + retry = retry - 1 + delay(60) #wait a minute for retry + self.assertNotEqual(retry, 0, "system VMs not Running in zone %s"%z.name) + + def test_templateBuiltInReady(self): + """ + built-in templates CentOS to be ready + """ + for z in self.zones_list: + retry = self.retry + while retry != 0: + self.debug("Looking for at least one ready builtin template") + templates = listTemplates.listTemplatesCmd() + templates.templatefilter = 'featured' + templates.listall = 'true' + templates_list = self.apiClient.listTemplates(templates) + if templates_list is not None: + builtins = [tmpl for tmpl in templates_list if tmpl.templatetype == 'BUILTIN' and tmpl.isready == True] + if len(builtins) > 0: + self.debug("Found %d builtins ready for use %s"%(len(builtins), builtins)) + break + retry = retry - 1 + delay(60) #wait a minute for retry + self.assertNotEqual(retry, 0, "builtIn templates not ready in zone %s"%z.name) + + @classmethod + def tearDownClass(cls): + pass