http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d002c52a/tools/marvin/marvin/lib/cloudstack/account.py ---------------------------------------------------------------------- diff --git a/tools/marvin/marvin/lib/cloudstack/account.py b/tools/marvin/marvin/lib/cloudstack/account.py new file mode 100644 index 0000000..f3eaf18 --- /dev/null +++ b/tools/marvin/marvin/lib/cloudstack/account.py @@ -0,0 +1,85 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + + +from marvin.cloudstackAPI import createAccount,deleteAccount,listAccounts,disableAccount + +from marvin.lib.cloudstack.utils import random_gen + +class Account: + """ Account Life Cycle """ + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, services, admin=False, domainid=None): + """Creates an account""" + cmd = createAccount.createAccountCmd() + + # 0 - User, 1 - Root Admin, 2 - Domain Admin + cmd.accounttype = 2 if (admin and domainid) else int(admin) + + cmd.email = services["email"] + cmd.firstname = services["firstname"] + cmd.lastname = services["lastname"] + + cmd.password = services["password"] + username = services["username"] + # Limit account username to 99 chars to avoid failure + # 6 chars start string + 85 chars apiclientid + 6 chars random string + 2 chars joining hyphen string = 99 + username = username[:6] + apiclientid = apiclient.id[-85:] if len(apiclient.id) > 85 else apiclient.id + cmd.username = "-".join([username, + random_gen(id=apiclientid, size=6)]) + + if "accountUUID" in services: + cmd.accountid = "-".join([services["accountUUID"], random_gen()]) + + if "userUUID" in services: + cmd.userid = "-".join([services["userUUID"], random_gen()]) + + + if domainid: + cmd.domainid = domainid + account = apiclient.createAccount(cmd) + + return Account(account.__dict__) + + def delete(self, apiclient): + """Delete an account""" + cmd = deleteAccount.deleteAccountCmd() + cmd.id = self.id + apiclient.deleteAccount(cmd) + + @classmethod + def list(cls, apiclient, **kwargs): + """Lists accounts and provides detailed account information for + listed accounts""" + + cmd = listAccounts.listAccountsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall = True + return(apiclient.listAccounts(cmd)) + + def disable(self, apiclient, lock=False): + """Disable an account""" + cmd = disableAccount.disableAccountCmd() + cmd.id = self.id + cmd.lock = lock + apiclient.disableAccount(cmd) +
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d002c52a/tools/marvin/marvin/lib/cloudstack/autoscale.py ---------------------------------------------------------------------- diff --git a/tools/marvin/marvin/lib/cloudstack/autoscale.py b/tools/marvin/marvin/lib/cloudstack/autoscale.py new file mode 100644 index 0000000..2d585ef --- /dev/null +++ b/tools/marvin/marvin/lib/cloudstack/autoscale.py @@ -0,0 +1,175 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +from marvin.cloudstackAPI import listCounters,createCondition,listConditions,listAutoScalePolicies,createAutoScalePolicy,updateAutoScalePolicy,listAutoScaleVmProfiles,createAutoScaleVmProfile,\ + updateAutoScaleVmProfile,createAutoScaleVmGroup,listAutoScaleVmGroups,enableAutoScaleVmGroup,disableAutoScaleVmGroup,updateAutoScaleVmGroup +class Autoscale: + + """Manage Auto scale""" + + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def listCounters(cls, apiclient, **kwargs): + """Lists all available Counters.""" + + cmd = listCounters.listCountersCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listCounters(cmd)) + + @classmethod + def createCondition(cls, apiclient, counterid, relationaloperator, threshold): + """creates condition.""" + + cmd = createCondition.createConditionCmd() + cmd.counterid = counterid + cmd.relationaloperator = relationaloperator + cmd.threshold = threshold + return(apiclient.createCondition(cmd)) + + @classmethod + def listConditions(cls, apiclient, **kwargs): + """Lists all available Conditions.""" + + cmd = listConditions.listConditionsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listConditions(cmd)) + + @classmethod + def listAutoscalePolicies(cls, apiclient, **kwargs): + """Lists all available Autoscale Policies.""" + + cmd = listAutoScalePolicies.listAutoScalePoliciesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listAutoScalePolicies(cmd)) + + @classmethod + def createAutoscalePolicy(cls, apiclient, action, conditionids, duration, quiettime=None): + """creates condition.""" + + cmd = createAutoScalePolicy.createAutoScalePolicyCmd() + cmd.action = action + cmd.conditionids = conditionids + cmd.duration = duration + if quiettime: + cmd.quiettime = quiettime + + return(apiclient.createAutoScalePolicy(cmd)) + + @classmethod + def updateAutoscalePolicy(cls, apiclient, id, **kwargs): + """Updates Autoscale Policy.""" + + cmd = updateAutoScalePolicy.updateAutoScalePolicyCmd() + cmd.id = id + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.updateAutoScalePolicy(cmd)) + + @classmethod + def listAutoscaleVmPofiles(cls, apiclient, **kwargs): + """Lists all available AutoscaleVM Profiles.""" + + cmd = listAutoScaleVmProfiles.listAutoScaleVmProfilesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listAutoScaleVmProfiles(cmd)) + + @classmethod + def createAutoscaleVmProfile(cls, apiclient, serviceofferingid, zoneid, templateid, + autoscaleuserid=None, destroyvmgraceperiod=None, counterparam=None): + """creates Autoscale VM Profile.""" + + cmd = createAutoScaleVmProfile.createAutoScaleVmProfileCmd() + cmd.serviceofferingid = serviceofferingid + cmd.zoneid = zoneid + cmd.templateid = templateid + if autoscaleuserid: + cmd.autoscaleuserid = autoscaleuserid + + if destroyvmgraceperiod: + cmd.destroyvmgraceperiod = destroyvmgraceperiod + + if counterparam: + for name, value in counterparam.items(): + cmd.counterparam.append({ + 'name': name, + 'value': value + }) + + return(apiclient.createAutoScaleVmProfile(cmd)) + + @classmethod + def updateAutoscaleVMProfile(cls, apiclient, id, **kwargs): + """Updates Autoscale Policy.""" + + cmd = updateAutoScaleVmProfile.updateAutoScaleVmProfileCmd() + cmd.id = id + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.updateAutoScaleVmProfile(cmd)) + + @classmethod + def createAutoscaleVmGroup(cls, apiclient, lbruleid, minmembers, maxmembers, + scaledownpolicyids, scaleuppolicyids, vmprofileid, interval=None): + """creates Autoscale VM Group.""" + + cmd = createAutoScaleVmGroup.createAutoScaleVmGroupCmd() + cmd.lbruleid = lbruleid + cmd.minmembers = minmembers + cmd.maxmembers = maxmembers + cmd.scaledownpolicyids = scaledownpolicyids + cmd.scaleuppolicyids = scaleuppolicyids + cmd.vmprofileid = vmprofileid + if interval: + cmd.interval = interval + + return(apiclient.createAutoScaleVmGroup(cmd)) + + @classmethod + def listAutoscaleVmGroup(cls, apiclient, **kwargs): + """Lists all available AutoscaleVM Group.""" + + cmd = listAutoScaleVmGroups.listAutoScaleVmGroupsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listAutoScaleVmGroups(cmd)) + + @classmethod + def enableAutoscaleVmGroup(cls, apiclient, id, **kwargs): + """Enables AutoscaleVM Group.""" + + cmd = enableAutoScaleVmGroup.enableAutoScaleVmGroupCmd() + cmd.id = id + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.enableAutoScaleVmGroup(cmd)) + + @classmethod + def disableAutoscaleVmGroup(cls, apiclient, id, **kwargs): + """Disables AutoscaleVM Group.""" + + cmd = disableAutoScaleVmGroup.disableAutoScaleVmGroupCmd() + cmd.id = id + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.disableAutoScaleVmGroup(cmd)) + + @classmethod + def updateAutoscaleVMGroup(cls, apiclient, id, **kwargs): + """Updates Autoscale VM Group.""" + + cmd = updateAutoScaleVmGroup.updateAutoScaleVmGroupCmd() + cmd.id = id + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.updateAutoScaleVmGroup(cmd)) + http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d002c52a/tools/marvin/marvin/lib/cloudstack/base.py ---------------------------------------------------------------------- diff --git a/tools/marvin/marvin/lib/cloudstack/base.py b/tools/marvin/marvin/lib/cloudstack/base.py new file mode 100755 index 0000000..3b48b24 --- /dev/null +++ b/tools/marvin/marvin/lib/cloudstack/base.py @@ -0,0 +1,336 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +""" Base class for all Cloudstack resources + -Virtual machine, Volume, Snapshot etc +""" + +from marvin.cloudstackAPI import * +# Import System modules + +class Hypervisor: + """Manage Hypervisor""" + + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def list(cls, apiclient, **kwargs): + """Lists hypervisors""" + + cmd = listHypervisors.listHypervisorsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall = True + return(apiclient.listHypervisors(cmd)) + + +class Configurations: + """Manage Configuration""" + + @classmethod + def update(cls, apiclient, name, value=None): + """Updates the specified configuration""" + + cmd = updateConfiguration.updateConfigurationCmd() + cmd.name = name + cmd.value = value + apiclient.updateConfiguration(cmd) + + @classmethod + def list(cls, apiclient, **kwargs): + """Lists configurations""" + + cmd = listConfigurations.listConfigurationsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall = True + return(apiclient.listConfigurations(cmd)) + + @classmethod + def listCapabilities(cls, apiclient, **kwargs): + """Lists capabilities""" + cmd = listCapabilities.listCapabilitiesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listCapabilities(cmd)) + + + +class Tag: + """Manage tags""" + + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, resourceIds, resourceType, tags): + """Create tags""" + + cmd = createTags.createTagsCmd() + cmd.resourceIds = resourceIds + cmd.resourcetype = resourceType + cmd.tags = [] + for key, value in tags.items(): + cmd.tags.append({ + 'key': key, + 'value': value + }) + return Tag(apiclient.createTags(cmd).__dict__) + + def delete(self, apiclient, resourceIds, resourceType, tags): + """Delete tags""" + + cmd = deleteTags.deleteTagsCmd() + cmd.resourceIds = resourceIds + cmd.resourcetype = resourceType + cmd.tags = [] + for key, value in tags.items(): + cmd.tags.append({ + 'key': key, + 'value': value + }) + apiclient.deleteTags(cmd) + + @classmethod + def list(cls, apiclient, **kwargs): + """List all tags matching the criteria""" + + cmd = listTags.listTagsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall = True + return(apiclient.listTags(cmd)) + + +class AffinityGroup: + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, aff_grp, account=None, domainid=None): + cmd = createAffinityGroup.createAffinityGroupCmd() + cmd.name = aff_grp['name'] + cmd.displayText = aff_grp['name'] + cmd.type = aff_grp['type'] + if account: + cmd.account = account + if domainid: + cmd.domainid = domainid + return AffinityGroup(apiclient.createAffinityGroup(cmd).__dict__) + + def update(self, apiclient): + pass + + def delete(self, apiclient): + cmd = deleteAffinityGroup.deleteAffinityGroupCmd() + cmd.id = self.id + return apiclient.deleteAffinityGroup(cmd) + + @classmethod + def list(cls, apiclient, **kwargs): + cmd = listAffinityGroups.listAffinityGroupsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall = True + return apiclient.listAffinityGroups(cmd) + + + + +class VNMC: + """Manage VNMC lifecycle""" + def __init__(self, items): + self.__dict__.update(items) + + def create(cls, apiclient, hostname, username, password, + physicalnetworkid): + """Registers VNMC appliance""" + + cmd = addCiscoVnmcResource.addCiscoVnmcResourceCmd() + cmd.hostname = hostname + cmd.username = username + cmd.password = password + cmd.physicalnetworkid = physicalnetworkid + return VNMC(apiclient.addCiscoVnmcResource(cmd)) + + def delete(self, apiclient): + """Removes VNMC appliance""" + + cmd = deleteCiscoVnmcResource.deleteCiscoVnmcResourceCmd() + cmd.resourceid = self.resourceid + return apiclient.deleteCiscoVnmcResource(cmd) + + @classmethod + def list(cls, apiclient, **kwargs): + """List VNMC appliances""" + + cmd = listCiscoVnmcResources.listCiscoVnmcResourcesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall = True + return(apiclient.listCiscoVnmcResources(cmd)) + + +class SSHKeyPair: + """Manage SSH Key pairs""" + + def __init__(self, items, services): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, name=None, account=None, + domainid=None, projectid=None): + """Creates SSH keypair""" + cmd = createSSHKeyPair.createSSHKeyPairCmd() + cmd.name = name + if account is not None: + cmd.account = account + if domainid is not None: + cmd.domainid = domainid + if projectid is not None: + cmd.projectid = projectid + return (apiclient.createSSHKeyPair(cmd)) + + @classmethod + def register(cls, apiclient, name, publickey): + """Registers SSH keypair""" + cmd = registerSSHKeyPair.registerSSHKeyPairCmd() + cmd.name = name + cmd.publickey = publickey + return (apiclient.registerSSHKeyPair(cmd)) + + def delete(self, apiclient): + """Delete SSH key pair""" + cmd = deleteSSHKeyPair.deleteSSHKeyPairCmd() + cmd.name = self.name + apiclient.deleteSSHKeyPair(cmd) + + @classmethod + def list(cls, apiclient, **kwargs): + """List all SSH key pairs""" + cmd = listSSHKeyPairs.listSSHKeyPairsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall = True + return(apiclient.listSSHKeyPairs(cmd)) + + +class Capacities: + """Manage Capacities""" + + @classmethod + def list(cls, apiclient, **kwargs): + """Lists capacities""" + + cmd = listCapacity.listCapacityCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall = True + return(apiclient.listCapacity(cmd)) + + +class Alert: + """Manage alerts""" + + @classmethod + def list(cls, apiclient, **kwargs): + """Lists alerts""" + + cmd = listAlerts.listAlertsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall = True + return(apiclient.listAlerts(cmd)) + + +class Resources: + """Manage resource limits""" + + def __init__(self, items, services): + self.__dict__.update(items) + + @classmethod + def list(cls, apiclient, **kwargs): + """Lists resource limits""" + + cmd = listResourceLimits.listResourceLimitsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall = True + return(apiclient.listResourceLimits(cmd)) + + @classmethod + def updateLimit(cls, apiclient, **kwargs): + """Updates resource limits""" + + cmd = updateResourceLimit.updateResourceLimitCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.updateResourceLimit(cmd)) + + @classmethod + def updateCount(cls, apiclient, **kwargs): + """Updates resource count""" + + cmd = updateResourceCount.updateResourceCountCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.updateResourceCount(cmd)) + + +class SimulatorMock: + """Manage simulator mock lifecycle""" + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, command, zoneid=None, podid=None, + clusterid=None, hostid=None, value="result:fail", + count=None, jsonresponse=None, method="GET"): + """Creates simulator mock""" + cmd = configureSimulator.configureSimulatorCmd() + cmd.zoneid = zoneid + cmd.podid = podid + cmd.clusterid = clusterid + cmd.hostid = hostid + cmd.name = command + cmd.value = value + cmd.count = count + cmd.jsonresponse = jsonresponse + try: + simulatormock = apiclient.configureSimulator(cmd, method=method) + if simulatormock is not None: + return SimulatorMock(simulatormock.__dict__) + except Exception as e: + raise e + + def delete(self, apiclient): + """Removes simulator mock""" + cmd = cleanupSimulatorMock.cleanupSimulatorMockCmd() + cmd.id = self.id + return apiclient.cleanupSimulatorMock(cmd) + + def query(self, apiclient): + """Queries simulator mock""" + cmd = querySimulatorMock.querySimulatorMockCmd() + cmd.id = self.id + try: + simulatormock = apiclient.querySimulatorMock(cmd) + if simulatormock is not None: + return SimulatorMock(simulatormock.__dict__) + except Exception as e: + raise e + + http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d002c52a/tools/marvin/marvin/lib/cloudstack/cluster.py ---------------------------------------------------------------------- diff --git a/tools/marvin/marvin/lib/cloudstack/cluster.py b/tools/marvin/marvin/lib/cloudstack/cluster.py new file mode 100644 index 0000000..8a58553 --- /dev/null +++ b/tools/marvin/marvin/lib/cloudstack/cluster.py @@ -0,0 +1,68 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +from marvin.cloudstackAPI import addCluster,deleteCluster,listClusters +class Cluster: + """Manage Cluster life cycle""" + + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, services, zoneid=None, podid=None, hypervisor=None): + """Create Cluster""" + cmd = addCluster.addClusterCmd() + cmd.clustertype = services["clustertype"] + cmd.hypervisor = hypervisor + + if zoneid: + cmd.zoneid = zoneid + else: + cmd.zoneid = services["zoneid"] + + if podid: + cmd.podid = podid + else: + cmd.podid = services["podid"] + + if "username" in services: + cmd.username = services["username"] + if "password" in services: + cmd.password = services["password"] + if "url" in services: + cmd.url = services["url"] + if "clustername" in services: + cmd.clustername = services["clustername"] + + return Cluster(apiclient.addCluster(cmd)[0].__dict__) + + def delete(self, apiclient): + """Delete Cluster""" + cmd = deleteCluster.deleteClusterCmd() + cmd.id = self.id + apiclient.deleteCluster(cmd) + return + + @classmethod + def list(cls, apiclient, **kwargs): + """List all Clusters matching criteria""" + + cmd = listClusters.listClustersCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall = True + return(apiclient.listClusters(cmd)) http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d002c52a/tools/marvin/marvin/lib/cloudstack/common.py ---------------------------------------------------------------------- diff --git a/tools/marvin/marvin/lib/cloudstack/common.py b/tools/marvin/marvin/lib/cloudstack/common.py new file mode 100644 index 0000000..22d17fd --- /dev/null +++ b/tools/marvin/marvin/lib/cloudstack/common.py @@ -0,0 +1,1374 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +"""Common functions +""" + +# Import Local Modules +import random + +from marvin.cloudstackAPI import (listConfigurations, + listPhysicalNetworks, + listRegions, + addNetworkServiceProvider, + updateNetworkServiceProvider, + listDomains, + listZones, + listPods, + listOsTypes, + listTemplates, + updateResourceLimit, + listRouters, + listNetworks, + listClusters, + listSystemVms, + listStoragePools, + listVirtualMachines, + listLoadBalancerRuleInstances, + listFirewallRules, + listVolumes, + listIsos, + listAccounts, + listSnapshotPolicies, + listDiskOfferings, + listVlanIpRanges, + listUsageRecords, + listNetworkServiceProviders, + listHosts, + listPublicIpAddresses, + listPortForwardingRules, + listLoadBalancerRules, + listSnapshots, + listUsers, + listEvents, + listServiceOfferings, + listVirtualRouterElements, + listNetworkOfferings, + listResourceLimits, + listVPCOfferings) +from marvin.sshClient import SshClient +from marvin.codes import (PASS, FAILED, ISOLATED_NETWORK, VPC_NETWORK, + BASIC_ZONE, FAIL, NAT_RULE, STATIC_NAT_RULE, + RESOURCE_PRIMARY_STORAGE, RESOURCE_SECONDARY_STORAGE, + RESOURCE_CPU, RESOURCE_MEMORY) +from marvin.lib.cloudstack.utils import (validateList, xsplit, get_process_status) +from marvin.lib.cloudstack.network import (PhysicalNetwork, + PublicIPAddress, + NATRule, + StaticNATRule, + NetScaler, + FireWallRule, + Network) +from marvin.lib.cloudstack.volume import Volume +from marvin.lib.cloudstack.account import Account +from marvin.lib.cloudstack.project import Project +from marvin.lib.cloudstack.snapshot import Snapshot +from marvin.lib.cloudstack.vm import VirtualMachine +from marvin.lib.cloudstack.template import Template +from marvin.lib.cloudstack.host import Host +from marvin.lib.cloudstack.base import Resources,Configurations +from marvin.lib.cloudstack.networkoffering import NetworkOffering + + +# Import System modules +import time + + +def is_config_suitable(apiclient, name, value): + """ + Ensure if the deployment has the expected `value` for the global setting `name' + @return: true if value is set, else false + """ + configs = Configurations.list(apiclient, name=name) + assert( + configs is not None and isinstance( + configs, + list) and len( + configs) > 0) + return configs[0].value == value + + +def wait_for_cleanup(apiclient, configs=None): + """Sleeps till the cleanup configs passed""" + + # Configs list consists of the list of global configs + if not isinstance(configs, list): + return + for config in configs: + cmd = listConfigurations.listConfigurationsCmd() + cmd.name = config + cmd.listall = True + try: + config_descs = apiclient.listConfigurations(cmd) + except Exception as e: + raise Exception("Failed to fetch configurations: %s" % e) + + if not isinstance(config_descs, list): + raise Exception("List configs didn't returned a valid data") + + config_desc = config_descs[0] + # Sleep for the config_desc.value time + time.sleep(int(config_desc.value)) + return + + +def add_netscaler(apiclient, zoneid, NSservice): + """ Adds Netscaler device and enables NS provider""" + + cmd = listPhysicalNetworks.listPhysicalNetworksCmd() + cmd.zoneid = zoneid + physical_networks = apiclient.listPhysicalNetworks(cmd) + if isinstance(physical_networks, list): + physical_network = physical_networks[0] + + cmd = listNetworkServiceProviders.listNetworkServiceProvidersCmd() + cmd.name = 'Netscaler' + cmd.physicalnetworkid = physical_network.id + nw_service_providers = apiclient.listNetworkServiceProviders(cmd) + + if isinstance(nw_service_providers, list): + netscaler_provider = nw_service_providers[0] + else: + cmd1 = addNetworkServiceProvider.addNetworkServiceProviderCmd() + cmd1.name = 'Netscaler' + cmd1.physicalnetworkid = physical_network.id + netscaler_provider = apiclient.addNetworkServiceProvider(cmd1) + + netscaler = NetScaler.add( + apiclient, + NSservice, + physicalnetworkid=physical_network.id + ) + if netscaler_provider.state != 'Enabled': + cmd = updateNetworkServiceProvider.updateNetworkServiceProviderCmd() + cmd.id = netscaler_provider.id + cmd.state = 'Enabled' + apiclient.updateNetworkServiceProvider(cmd) + + return netscaler + + +def get_region(apiclient, region_id=None, region_name=None): + ''' + @name : get_region + @Desc : Returns the Region Information for a given region id or region name + @Input : region_name: Name of the Region + region_id : Id of the region + @Output : 1. Region Information for the passed inputs else first Region + 2. FAILED In case the cmd failed + ''' + cmd = listRegions.listRegionsCmd() + if region_name is not None: + cmd.name = region_name + if region_id is not None: + cmd.id = region_id + cmd_out = apiclient.listRegions(cmd) + return FAILED if validateList(cmd_out)[0] != PASS else cmd_out[0] + + +def get_domain(apiclient, domain_id=None, domain_name=None): + ''' + @name : get_domain + @Desc : Returns the Domain Information for a given domain id or domain name + @Input : domain id : Id of the Domain + domain_name : Name of the Domain + @Output : 1. Domain Information for the passed inputs else first Domain + 2. FAILED In case the cmd failed + ''' + cmd = listDomains.listDomainsCmd() + + if domain_name is not None: + cmd.name = domain_name + if domain_id is not None: + cmd.id = domain_id + cmd_out = apiclient.listDomains(cmd) + if validateList(cmd_out)[0] != PASS: + return FAILED + return cmd_out[0] + + +def get_zone(apiclient, zone_name=None, zone_id=None): + ''' + @name : get_zone + @Desc :Returns the Zone Information for a given zone id or Zone Name + @Input : zone_name: Name of the Zone + zone_id : Id of the zone + @Output : 1. Zone Information for the passed inputs else first zone + 2. FAILED In case the cmd failed + ''' + cmd = listZones.listZonesCmd() + if zone_name is not None: + cmd.name = zone_name + if zone_id is not None: + cmd.id = zone_id + + cmd_out = apiclient.listZones(cmd) + + if validateList(cmd_out)[0] != PASS: + return FAILED + ''' + Check if input zone name and zone id is None, + then return first element of List Zones command + ''' + return cmd_out[0] + + +def get_pod(apiclient, zone_id=None, pod_id=None, pod_name=None): + ''' + @name : get_pod + @Desc : Returns the Pod Information for a given zone id or Zone Name + @Input : zone_id: Id of the Zone + pod_name : Name of the Pod + pod_id : Id of the Pod + @Output : 1. Pod Information for the pod + 2. FAILED In case the cmd failed + ''' + cmd = listPods.listPodsCmd() + + if pod_name is not None: + cmd.name = pod_name + if pod_id is not None: + cmd.id = pod_id + if zone_id is not None: + cmd.zoneid = zone_id + + cmd_out = apiclient.listPods(cmd) + + if validateList(cmd_out)[0] != PASS: + return FAILED + return cmd_out[0] +def get_template( + apiclient, zone_id=None, ostype_desc=None, template_filter="featured", template_type='BUILTIN', + template_id=None, template_name=None, account=None, domain_id=None, project_id=None, + hypervisor=None): + ''' + @Name : get_template + @Desc : Retrieves the template Information based upon inputs provided + Template is retrieved based upon either of the inputs matched + condition + @Input : returns a template" + @Output : FAILED in case of any failure + template Information matching the inputs + ''' + cmd = listTemplates.listTemplatesCmd() + cmd.templatefilter = template_filter + if domain_id is not None: + cmd.domainid = domain_id + if zone_id is not None: + cmd.zoneid = zone_id + if template_id is not None: + cmd.id = template_id + if template_name is not None: + cmd.name = template_name + if hypervisor is not None: + cmd.hypervisor = hypervisor + if project_id is not None: + cmd.projectid = project_id + if account is not None: + cmd.account = account + + ''' + Get the Templates pertaining to the inputs provided + ''' + list_templatesout = apiclient.listTemplates(cmd) + if validateList(list_templatesout)[0] != PASS: + return FAILED + + for template in list_templatesout: + if template.isready and template.templatetype == template_type: + return template + ''' + Return default first template, if no template matched + ''' + return list_templatesout[0] + + + +def get_windows_template( + apiclient, zone_id=None, ostype_desc=None, template_filter="featured", template_type='USER', + template_id=None, template_name=None, account=None, domain_id=None, project_id=None, + hypervisor=None): + ''' + @Name : get_template + @Desc : Retrieves the template Information based upon inputs provided + Template is retrieved based upon either of the inputs matched + condition + @Input : returns a template" + @Output : FAILED in case of any failure + template Information matching the inputs + ''' + cmd = listTemplates.listTemplatesCmd() + cmd.templatefilter = template_filter + if domain_id is not None: + cmd.domainid = domain_id + if zone_id is not None: + cmd.zoneid = zone_id + if template_id is not None: + cmd.id = template_id + if template_name is not None: + cmd.name = template_name + if hypervisor is not None: + cmd.hypervisor = hypervisor + if project_id is not None: + cmd.projectid = project_id + if account is not None: + cmd.account = account + + + ''' + Get the Templates pertaining to the inputs provided + ''' + list_templatesout = apiclient.listTemplates(cmd) + #print("template result is %s"%(list_templatesout)) + if list_templatesout is None: + return FAILED + if validateList(list_templatesout[0]) == FAIL : + return FAILED + + for template in list_templatesout: + if template.isready and template.templatetype == "USER" and template.ostypename == ostype_desc: + return template + ''' + Return default first template, if no template matched + ''' + + return FAILED + + + +def download_systemplates_sec_storage(server, services): + """Download System templates on sec storage""" + + try: + # Login to management server + ssh = SshClient( + server["ipaddress"], + server["port"], + server["username"], + server["password"] + ) + except Exception: + raise Exception("SSH access failed for server with IP address: %s" % + server["ipaddess"]) + # Mount Secondary Storage on Management Server + cmds = [ + "mkdir -p %s" % services["mnt_dir"], + "mount -t nfs %s:/%s %s" % ( + services["sec_storage"], + services["path"], + services["mnt_dir"] + ), + "%s -m %s -u %s -h %s -F" % ( + services["command"], + services["mnt_dir"], + services["download_url"], + services["hypervisor"] + ) + ] + for c in cmds: + result = ssh.execute(c) + + res = str(result) + + # Unmount the Secondary storage + ssh.execute("umount %s" % (services["mnt_dir"])) + + if res.count("Successfully installed system VM template") == 1: + return + else: + raise Exception("Failed to download System Templates on Sec Storage") + return + + +def wait_for_ssvms(apiclient, zoneid, podid, interval=60): + """After setup wait for SSVMs to come Up""" + + time.sleep(interval) + timeout = 40 + while True: + list_ssvm_response = list_ssvms( + apiclient, + systemvmtype='secondarystoragevm', + zoneid=zoneid, + podid=podid + ) + ssvm = list_ssvm_response[0] + if ssvm.state != 'Running': + # Sleep to ensure SSVMs are Up and Running + time.sleep(interval) + timeout = timeout - 1 + elif ssvm.state == 'Running': + break + elif timeout == 0: + raise Exception("SSVM failed to come up") + break + + timeout = 40 + while True: + list_ssvm_response = list_ssvms( + apiclient, + systemvmtype='consoleproxy', + zoneid=zoneid, + podid=podid + ) + cpvm = list_ssvm_response[0] + if cpvm.state != 'Running': + # Sleep to ensure SSVMs are Up and Running + time.sleep(interval) + timeout = timeout - 1 + elif cpvm.state == 'Running': + break + elif timeout == 0: + raise Exception("CPVM failed to come up") + break + return + + +def get_builtin_template_info(apiclient, zoneid): + """Returns hypervisor specific infor for templates""" + + list_template_response = Template.list( + apiclient, + templatefilter='featured', + zoneid=zoneid, + ) + + for b_template in list_template_response: + if b_template.templatetype == 'BUILTIN': + break + + extract_response = Template.extract(apiclient, + b_template.id, + 'HTTP_DOWNLOAD', + zoneid) + + return extract_response.url, b_template.hypervisor, b_template.format + + +def download_builtin_templates(apiclient, zoneid, hypervisor, host, + linklocalip, interval=60): + """After setup wait till builtin templates are downloaded""" + + # Change IPTABLES Rules + get_process_status( + host["ipaddress"], + host["port"], + host["username"], + host["password"], + linklocalip, + "iptables -P INPUT ACCEPT" + ) + time.sleep(interval) + # Find the BUILTIN Templates for given Zone, Hypervisor + list_template_response = list_templates( + apiclient, + hypervisor=hypervisor, + zoneid=zoneid, + templatefilter='self' + ) + + if not isinstance(list_template_response, list): + raise Exception("Failed to download BUILTIN templates") + + # Ensure all BUILTIN templates are downloaded + templateid = None + for template in list_template_response: + if template.templatetype == "BUILTIN": + templateid = template.id + + # Sleep to ensure that template is in downloading state after adding + # Sec storage + time.sleep(interval) + while True: + template_response = list_templates( + apiclient, + id=templateid, + zoneid=zoneid, + templatefilter='self' + ) + template = template_response[0] + # If template is ready, + # template.status = Download Complete + # Downloading - x% Downloaded + # Error - Any other string + if template.status == 'Download Complete': + break + + elif 'Downloaded' in template.status: + time.sleep(interval) + + elif 'Installing' not in template.status: + raise Exception("ErrorInDownload") + + return + + +def update_resource_limit(apiclient, resourcetype, account=None, + domainid=None, max=None, projectid=None): + """Updates the resource limit to 'max' for given account""" + + cmd = updateResourceLimit.updateResourceLimitCmd() + cmd.resourcetype = resourcetype + if account: + cmd.account = account + if domainid: + cmd.domainid = domainid + if max: + cmd.max = max + if projectid: + cmd.projectid = projectid + apiclient.updateResourceLimit(cmd) + return + + +def list_os_types(apiclient, **kwargs): + """List all os types matching criteria""" + + cmd = listOsTypes.listOsTypesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall=True + return(apiclient.listOsTypes(cmd)) + + +def list_routers(apiclient, **kwargs): + """List all Routers matching criteria""" + + cmd = listRouters.listRoutersCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall=True + return(apiclient.listRouters(cmd)) + + +def list_zones(apiclient, **kwargs): + """List all Zones matching criteria""" + + cmd = listZones.listZonesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall=True + return(apiclient.listZones(cmd)) + + +def list_networks(apiclient, **kwargs): + """List all Networks matching criteria""" + + cmd = listNetworks.listNetworksCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall=True + return(apiclient.listNetworks(cmd)) + + +def list_clusters(apiclient, **kwargs): + """List all Clusters matching criteria""" + + cmd = listClusters.listClustersCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall=True + return(apiclient.listClusters(cmd)) + + +def list_ssvms(apiclient, **kwargs): + """List all SSVMs matching criteria""" + + cmd = listSystemVms.listSystemVmsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall=True + return(apiclient.listSystemVms(cmd)) + + +def list_storage_pools(apiclient, **kwargs): + """List all storage pools matching criteria""" + + cmd = listStoragePools.listStoragePoolsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall=True + return(apiclient.listStoragePools(cmd)) + + +def list_virtual_machines(apiclient, **kwargs): + """List all VMs matching criteria""" + + cmd = listVirtualMachines.listVirtualMachinesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall=True + return(apiclient.listVirtualMachines(cmd)) + + +def list_hosts(apiclient, **kwargs): + """List all Hosts matching criteria""" + + cmd = listHosts.listHostsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall=True + return(apiclient.listHosts(cmd)) + + +def list_configurations(apiclient, **kwargs): + """List configuration with specified name""" + + cmd = listConfigurations.listConfigurationsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall=True + return(apiclient.listConfigurations(cmd)) + + +def list_publicIP(apiclient, **kwargs): + """List all Public IPs matching criteria""" + + cmd = listPublicIpAddresses.listPublicIpAddressesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall=True + return(apiclient.listPublicIpAddresses(cmd)) + + +def list_nat_rules(apiclient, **kwargs): + """List all NAT rules matching criteria""" + + cmd = listPortForwardingRules.listPortForwardingRulesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall=True + return(apiclient.listPortForwardingRules(cmd)) + + +def list_lb_rules(apiclient, **kwargs): + """List all Load balancing rules matching criteria""" + + cmd = listLoadBalancerRules.listLoadBalancerRulesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall=True + return(apiclient.listLoadBalancerRules(cmd)) + + +def list_lb_instances(apiclient, **kwargs): + """List all Load balancing instances matching criteria""" + + cmd = listLoadBalancerRuleInstances.listLoadBalancerRuleInstancesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall=True + return(apiclient.listLoadBalancerRuleInstances(cmd)) + + +def list_firewall_rules(apiclient, **kwargs): + """List all Firewall Rules matching criteria""" + + cmd = listFirewallRules.listFirewallRulesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall=True + return(apiclient.listFirewallRules(cmd)) + + +def list_volumes(apiclient, **kwargs): + """List all volumes matching criteria""" + + cmd = listVolumes.listVolumesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall=True + return(apiclient.listVolumes(cmd)) + + +def list_isos(apiclient, **kwargs): + """Lists all available ISO files.""" + + cmd = listIsos.listIsosCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall=True + return(apiclient.listIsos(cmd)) + + +def list_snapshots(apiclient, **kwargs): + """List all snapshots matching criteria""" + + cmd = listSnapshots.listSnapshotsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall=True + return(apiclient.listSnapshots(cmd)) + + +def list_templates(apiclient, **kwargs): + """List all templates matching criteria""" + + cmd = listTemplates.listTemplatesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall=True + return(apiclient.listTemplates(cmd)) + + +def list_domains(apiclient, **kwargs): + """Lists domains""" + + cmd = listDomains.listDomainsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall=True + return(apiclient.listDomains(cmd)) + + +def list_accounts(apiclient, **kwargs): + """Lists accounts and provides detailed account information for + listed accounts""" + + cmd = listAccounts.listAccountsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall=True + return(apiclient.listAccounts(cmd)) + + +def list_users(apiclient, **kwargs): + """Lists users and provides detailed account information for + listed users""" + + cmd = listUsers.listUsersCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall=True + return(apiclient.listUsers(cmd)) + + +def list_snapshot_policy(apiclient, **kwargs): + """Lists snapshot policies.""" + + cmd = listSnapshotPolicies.listSnapshotPoliciesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall=True + return(apiclient.listSnapshotPolicies(cmd)) + + +def list_events(apiclient, **kwargs): + """Lists events""" + + cmd = listEvents.listEventsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall=True + return(apiclient.listEvents(cmd)) + + +def list_disk_offering(apiclient, **kwargs): + """Lists all available disk offerings.""" + + cmd = listDiskOfferings.listDiskOfferingsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall=True + return(apiclient.listDiskOfferings(cmd)) + + +def list_service_offering(apiclient, **kwargs): + """Lists all available service offerings.""" + + cmd = listServiceOfferings.listServiceOfferingsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall=True + return(apiclient.listServiceOfferings(cmd)) + + +def list_vlan_ipranges(apiclient, **kwargs): + """Lists all VLAN IP ranges.""" + + cmd = listVlanIpRanges.listVlanIpRangesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall=True + return(apiclient.listVlanIpRanges(cmd)) + + +def list_usage_records(apiclient, **kwargs): + """Lists usage records for accounts""" + + cmd = listUsageRecords.listUsageRecordsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall=True + return(apiclient.listUsageRecords(cmd)) + + +def list_nw_service_prividers(apiclient, **kwargs): + """Lists Network service providers""" + + cmd = listNetworkServiceProviders.listNetworkServiceProvidersCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall=True + return(apiclient.listNetworkServiceProviders(cmd)) + + +def list_virtual_router_elements(apiclient, **kwargs): + """Lists Virtual Router elements""" + + cmd = listVirtualRouterElements.listVirtualRouterElementsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall=True + return(apiclient.listVirtualRouterElements(cmd)) + + +def list_network_offerings(apiclient, **kwargs): + """Lists network offerings""" + + cmd = listNetworkOfferings.listNetworkOfferingsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall=True + return(apiclient.listNetworkOfferings(cmd)) + + +def list_resource_limits(apiclient, **kwargs): + """Lists resource limits""" + + cmd = listResourceLimits.listResourceLimitsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall=True + return(apiclient.listResourceLimits(cmd)) + + +def list_vpc_offerings(apiclient, **kwargs): + """ Lists VPC offerings """ + + cmd = listVPCOfferings.listVPCOfferingsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall=True + return(apiclient.listVPCOfferings(cmd)) + + +def update_resource_count(apiclient, domainid, accountid=None, + projectid=None, rtype=None): + """updates the resource count + 0 - VM + 1 - Public IP + 2 - Volume + 3 - Snapshot + 4 - Template + 5 - Projects + 6 - Network + 7 - VPC + 8 - CPUs + 9 - RAM + 10 - Primary (shared) storage (Volumes) + 11 - Secondary storage (Snapshots, Templates & ISOs) + """ + + Resources.updateCount(apiclient, + domainid=domainid, + account=accountid if accountid else None, + projectid=projectid if projectid else None, + resourcetype=rtype if rtype else None + ) + return + +def findSuitableHostForMigration(apiclient, vmid): + """Returns a suitable host for VM migration""" + suitableHost = None + try: + hosts = Host.listForMigration(apiclient, virtualmachineid=vmid, + ) + except Exception as e: + raise Exception("Exception while getting hosts list suitable for migration: %s" % e) + + suitablehosts = [] + if isinstance(hosts, list) and len(hosts) > 0: + suitablehosts = [host for host in hosts if (str(host.resourcestate).lower() == "enabled"\ + and str(host.state).lower() == "up")] + if len(suitablehosts)>0: + suitableHost = suitablehosts[0] + + return suitableHost + + +def get_resource_type(resource_id): + """Returns resource type""" + + lookup = {0: "VM", + 1: "Public IP", + 2: "Volume", + 3: "Snapshot", + 4: "Template", + 5: "Projects", + 6: "Network", + 7: "VPC", + 8: "CPUs", + 9: "RAM", + 10: "Primary (shared) storage (Volumes)", + 11: "Secondary storage (Snapshots, Templates & ISOs)" + } + + return lookup[resource_id] + + + +def get_free_vlan(apiclient, zoneid): + """ + Find an unallocated VLAN outside the range allocated to the physical network. + + @note: This does not guarantee that the VLAN is available for use in + the deployment's network gear + @return: physical_network, shared_vlan_tag + """ + list_physical_networks_response = PhysicalNetwork.list( + apiclient, + zoneid=zoneid + ) + assert isinstance(list_physical_networks_response, list) + assert len( + list_physical_networks_response) > 0, "No physical networks found in zone %s" % zoneid + + physical_network = list_physical_networks_response[0] + + networks = list_networks(apiclient, zoneid=zoneid, type='Shared') + usedVlanIds = [] + + if isinstance(networks, list) and len(networks) > 0: + usedVlanIds = [int(nw.vlan) + for nw in networks if nw.vlan != "untagged"] + + if hasattr(physical_network, "vlan") is False: + while True: + shared_ntwk_vlan = random.randrange(1, 4095) + if shared_ntwk_vlan in usedVlanIds: + continue + else: + break + else: + vlans = xsplit(physical_network.vlan, ['-', ',']) + + assert len(vlans) > 0 + assert int(vlans[0]) < int( + vlans[-1]), "VLAN range %s was improperly split" % physical_network.vlan + + # Assuming random function will give different integer each time + retriesCount = 20 + + shared_ntwk_vlan = None + + while True: + + if retriesCount == 0: + break + + free_vlan = int(vlans[-1]) + random.randrange(1, 20) + + if free_vlan > 4095: + free_vlan = int(vlans[0]) - random.randrange(1, 20) + if free_vlan < 0 or (free_vlan in usedVlanIds): + retriesCount -= 1 + continue + else: + shared_ntwk_vlan = free_vlan + break + + return physical_network, shared_ntwk_vlan + + +def setNonContiguousVlanIds(apiclient, zoneid): + """ + Form the non contiguous ranges based on currently assigned range in physical network + """ + + NonContigVlanIdsAcquired = False + + list_physical_networks_response = PhysicalNetwork.list( + apiclient, + zoneid=zoneid + ) + assert isinstance(list_physical_networks_response, list) + assert len( + list_physical_networks_response) > 0, "No physical networks found in zone %s" % zoneid + + for physical_network in list_physical_networks_response: + + vlans = xsplit(physical_network.vlan, ['-', ',']) + + assert len(vlans) > 0 + assert int(vlans[0]) < int( + vlans[-1]), "VLAN range %s was improperly split" % physical_network.vlan + + # Keep some gap between existing vlan and the new vlans which we are going to add + # So that they are non contiguous + + non_contig_end_vlan_id = int(vlans[-1]) + 6 + non_contig_start_vlan_id = int(vlans[0]) - 6 + + # Form ranges which are consecutive to existing ranges but not immediately contiguous + # There should be gap in between existing range and new non contiguous + # ranage + + # If you can't add range after existing range, because it's crossing 4095, then + # select VLAN ids before the existing range such that they are greater than 0, and + # then add this non contiguoud range + vlan = {"partial_range": ["", ""], "full_range": ""} + + if non_contig_end_vlan_id < 4095: + vlan["partial_range"][0] = str( + non_contig_end_vlan_id - 4) + '-' + str(non_contig_end_vlan_id - 3) + vlan["partial_range"][1] = str( + non_contig_end_vlan_id - 1) + '-' + str(non_contig_end_vlan_id) + vlan["full_range"] = str( + non_contig_end_vlan_id - 4) + '-' + str(non_contig_end_vlan_id) + NonContigVlanIdsAcquired = True + + elif non_contig_start_vlan_id > 0: + vlan["partial_range"][0] = str( + non_contig_start_vlan_id) + '-' + str(non_contig_start_vlan_id + 1) + vlan["partial_range"][1] = str( + non_contig_start_vlan_id + 3) + '-' + str(non_contig_start_vlan_id + 4) + vlan["full_range"] = str( + non_contig_start_vlan_id) + '-' + str(non_contig_start_vlan_id + 4) + NonContigVlanIdsAcquired = True + + else: + NonContigVlanIdsAcquired = False + + # If failed to get relevant vlan ids, continue to next physical network + # else break from loop as we have hot the non contiguous vlan ids for + # the test purpose + + if not NonContigVlanIdsAcquired: + continue + else: + break + + # If even through looping from all existing physical networks, failed to get relevant non + # contiguous vlan ids, then fail the test case + + if not NonContigVlanIdsAcquired: + return None, None + + return physical_network, vlan + +def isIpInDesiredState(apiclient, ipaddressid, state): + """ Check if the given IP is in the correct state (given) + and return True/False accordingly""" + retriesCount = 10 + ipInDesiredState = False + exceptionOccured = False + exceptionMessage = "" + try: + while retriesCount >= 0: + portableips = PublicIPAddress.list(apiclient, id=ipaddressid) + assert validateList( + portableips)[0] == PASS, "IPs list validation failed" + if str(portableips[0].state).lower() == state: + ipInDesiredState = True + break + retriesCount -= 1 + time.sleep(60) + except Exception as e: + exceptionOccured = True + exceptionMessage = e + return [exceptionOccured, ipInDesiredState, e] + if not ipInDesiredState: + exceptionMessage = "Ip should be in %s state, it is in %s" %\ + (state, portableips[0].state) + return [False, ipInDesiredState, exceptionMessage] + +def setSharedNetworkParams(networkServices, range=20): + """Fill up the services dictionary for shared network using random subnet""" + + # @range: range decides the endip. Pass the range as "x" if you want the difference between the startip + # and endip as "x" + # Set the subnet number of shared networks randomly prior to execution + # of each test case to avoid overlapping of ip addresses + shared_network_subnet_number = random.randrange(1,254) + + networkServices["gateway"] = "172.16."+str(shared_network_subnet_number)+".1" + networkServices["startip"] = "172.16."+str(shared_network_subnet_number)+".2" + networkServices["endip"] = "172.16."+str(shared_network_subnet_number)+"."+str(range+1) + networkServices["netmask"] = "255.255.255.0" + return networkServices + +def createEnabledNetworkOffering(apiclient, networkServices): + """Create and enable network offering according to the type + + @output: List, containing [ Result,Network Offering,Reason ] + Ist Argument('Result') : FAIL : If exception or assertion error occurs + PASS : If network offering + is created and enabled successfully + IInd Argument(Net Off) : Enabled network offering + In case of exception or + assertion error, it will be None + IIIrd Argument(Reason) : Reason for failure, + default to None + """ + try: + resultSet = [FAIL, None, None] + # Create network offering + network_offering = NetworkOffering.create(apiclient, networkServices, conservemode=False) + + # Update network offering state from disabled to enabled. + NetworkOffering.update(network_offering, apiclient, id=network_offering.id, + state="enabled") + except Exception as e: + resultSet[2] = e + return resultSet + return [PASS, network_offering, None] + +def shouldTestBeSkipped(networkType, zoneType): + """Decide which test to skip, according to type of network and zone type""" + + # If network type is isolated or vpc and zone type is basic, then test should be skipped + skipIt = False + if ((networkType.lower() == str(ISOLATED_NETWORK).lower() or networkType.lower() == str(VPC_NETWORK).lower()) + and (zoneType.lower() == BASIC_ZONE)): + skipIt = True + return skipIt + +def verifyNetworkState(apiclient, networkid, state, listall=True): + """List networks and check if the network state matches the given state""" + retriesCount = 10 + isNetworkInDesiredState = False + exceptionOccured = False + exceptionMessage = "" + try: + while retriesCount >= 0: + networks = Network.list(apiclient, id=networkid, listall=listall) + assert validateList( + networks)[0] == PASS, "Networks list validation failed" + if str(networks[0].state).lower() == state: + isNetworkInDesiredState = True + break + retriesCount -= 1 + time.sleep(60) + if not isNetworkInDesiredState: + exceptionMessage = "Network state should be %s, it is %s" %\ + (state, networks[0].state) + except Exception as e: + exceptionOccured = True + exceptionMessage = e + return [exceptionOccured, isNetworkInDesiredState, exceptionMessage] + return [exceptionOccured, isNetworkInDesiredState, exceptionMessage] + +def verifyComputeOfferingCreation(apiclient, computeofferingid): + """List Compute offerings by ID and verify that the offering exists""" + + cmd = listServiceOfferings.listServiceOfferingsCmd() + cmd.id = computeofferingid + serviceOfferings = None + try: + serviceOfferings = apiclient.listServiceOfferings(cmd) + except Exception: + return FAIL + if not (isinstance(serviceOfferings, list) and len(serviceOfferings) > 0): + return FAIL + return PASS + +def createNetworkRulesForVM(apiclient, virtualmachine, ruletype, + account, networkruledata): + """Acquire IP, create Firewall and NAT/StaticNAT rule + (associating it with given vm) for that IP""" + + try: + public_ip = PublicIPAddress.create( + apiclient,accountid=account.name, + zoneid=virtualmachine.zoneid,domainid=account.domainid, + networkid=virtualmachine.nic[0].networkid) + + FireWallRule.create( + apiclient,ipaddressid=public_ip.ipaddress.id, + protocol='TCP', cidrlist=[networkruledata["fwrule"]["cidr"]], + startport=networkruledata["fwrule"]["startport"], + endport=networkruledata["fwrule"]["endport"] + ) + + if ruletype == NAT_RULE: + # Create NAT rule + NATRule.create(apiclient, virtualmachine, + networkruledata["natrule"],ipaddressid=public_ip.ipaddress.id, + networkid=virtualmachine.nic[0].networkid) + elif ruletype == STATIC_NAT_RULE: + # Enable Static NAT for VM + StaticNATRule.enable(apiclient,public_ip.ipaddress.id, + virtualmachine.id, networkid=virtualmachine.nic[0].networkid) + except Exception as e: + [FAIL, e] + return [PASS, public_ip] + +def getPortableIpRangeServices(config): + """ Reads config values related to portable ip and fills up + services accordingly""" + + services = {} + attributeError = False + + if config.portableIpRange.startip: + services["startip"] = config.portableIpRange.startip + else: + attributeError = True + + if config.portableIpRange.endip: + services["endip"] = config.portableIpRange.endip + else: + attributeError = True + + if config.portableIpRange.netmask: + services["netmask"] = config.portableIpRange.netmask + else: + attributeError = True + + if config.portableIpRange.gateway: + services["gateway"] = config.portableIpRange.gateway + else: + attributeError = True + + if config.portableIpRange.vlan: + services["vlan"] = config.portableIpRange.vlan + + if attributeError: + services = FAILED + + return services + + +def uploadVolume(apiclient, zoneid, account, services): + try: + # Upload the volume + volume = Volume.upload(apiclient, services["volume"], + zoneid=zoneid, account=account.name, + domainid=account.domainid, url=services["url"]) + + volume.wait_for_upload(apiclient) + + # Check List Volume response for newly created volume + volumes = Volume.list(apiclient, id=volume.id, + zoneid=zoneid, listall=True) + validationresult = validateList(volumes) + assert validationresult[0] == PASS,\ + "volumes list validation failed: %s" % validationresult[2] + assert str(volumes[0].state).lower() == "uploaded",\ + "Volume state should be 'uploaded' but it is %s" % volumes[0].state + except Exception as e: + return [FAIL, e] + return [PASS, volume] + +def matchResourceCount(apiclient, expectedCount, resourceType, + accountid=None, projectid=None): + """Match the resource count of account/project with the expected + resource count""" + try: + resourceholderlist = None + if accountid: + resourceholderlist = Account.list(apiclient, id=accountid) + elif projectid: + resourceholderlist = Project.list(apiclient, id=projectid, listall=True) + validationresult = validateList(resourceholderlist) + assert validationresult[0] == PASS,\ + "accounts list validation failed" + if resourceType == RESOURCE_PRIMARY_STORAGE: + resourceCount = resourceholderlist[0].primarystoragetotal + elif resourceType == RESOURCE_SECONDARY_STORAGE: + resourceCount = resourceholderlist[0].secondarystoragetotal + elif resourceType == RESOURCE_CPU: + resourceCount = resourceholderlist[0].cputotal + elif resourceType == RESOURCE_MEMORY: + resourceCount = resourceholderlist[0].memorytotal + assert str(resourceCount) == str(expectedCount),\ + "Resource count %s should match with the expected resource count %s" %\ + (resourceCount, expectedCount) + except Exception as e: + return [FAIL, e] + return [PASS, None] + +def createSnapshotFromVirtualMachineVolume(apiclient, account, vmid): + """Create snapshot from volume""" + + try: + volumes = Volume.list(apiclient, account=account.name, + domainid=account.domainid, virtualmachineid=vmid) + validationresult = validateList(volumes) + assert validateList(volumes)[0] == PASS,\ + "List volumes should return a valid response" + snapshot = Snapshot.create(apiclient, volume_id=volumes[0].id, + account=account.name, domainid=account.domainid) + snapshots = Snapshot.list(apiclient, id=snapshot.id, + listall=True) + validationresult = validateList(snapshots) + assert validationresult[0] == PASS,\ + "List snapshot should return a valid list" + except Exception as e: + return[FAIL, e] + return [PASS, snapshot] + +def isVmExpunged(apiclient, vmid, projectid=None, timeout=600): + """Verify if VM is expunged or not""" + vmExpunged= False + while timeout>=0: + try: + vms = VirtualMachine.list(apiclient, id=vmid, projectid=projectid) + if vms is None: + vmExpunged = True + break + timeout -= 60 + time.sleep(60) + except Exception: + vmExpunged = True + break + #end while + return vmExpunged + +def isDomainResourceCountEqualToExpectedCount(apiclient, domainid, expectedcount, + resourcetype): + """Get the resource count of specific domain and match + it with the expected count + Return list [isExceptionOccured, reasonForException, isResourceCountEqual]""" + isResourceCountEqual = False + isExceptionOccured = False + reasonForException = None + try: + response = Resources.updateCount(apiclient, domainid=domainid, + resourcetype=resourcetype) + except Exception as e: + reasonForException = "Failed while updating resource count: %s" % e + isExceptionOccured = True + return [isExceptionOccured, reasonForException, isResourceCountEqual] + + resourcecount = (response[0].resourcecount / (1024**3)) + if resourcecount == expectedcount: + isResourceCountEqual = True + return [isExceptionOccured, reasonForException, isResourceCountEqual] + +def isNetworkDeleted(apiclient, networkid, timeout=600): + """ List the network and check that the list is empty or not""" + networkDeleted = False + while timeout >= 0: + networks = Network.list(apiclient, id=networkid) + if networks is None: + networkDeleted = True + break + timeout -= 60 + time.sleep(60) + #end while + return networkDeleted http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d002c52a/tools/marvin/marvin/lib/cloudstack/diskoffering.py ---------------------------------------------------------------------- diff --git a/tools/marvin/marvin/lib/cloudstack/diskoffering.py b/tools/marvin/marvin/lib/cloudstack/diskoffering.py new file mode 100644 index 0000000..f10fb6f --- /dev/null +++ b/tools/marvin/marvin/lib/cloudstack/diskoffering.py @@ -0,0 +1,77 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +from marvin.cloudstackAPI import createDiskOffering,deleteDiskOffering,listDiskOfferings +class DiskOffering: + """Manage disk offerings cycle""" + + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, services, custom=False, domainid=None): + """Create Disk offering""" + cmd = createDiskOffering.createDiskOfferingCmd() + cmd.displaytext = services["displaytext"] + cmd.name = services["name"] + if custom: + cmd.customized = True + else: + cmd.disksize = services["disksize"] + + if domainid: + cmd.domainid = domainid + + if "storagetype" in services: + cmd.storagetype = services["storagetype"] + + if "customizediops" in services: + cmd.customizediops = services["customizediops"] + + if "disksize" in services: + cmd.disksize = services["disksize"] + + if "maxiops" in services: + cmd.maxiops = services["maxiops"] + + if "miniops" in services: + cmd.miniops = services["miniops"] + + if "tags" in services: + cmd.tags = services["tags"] + + if "provisioningtype" in services: + cmd.provisioningtype = services["provisioningtype"] + + return DiskOffering(apiclient.createDiskOffering(cmd).__dict__) + + def delete(self, apiclient): + """Delete Disk offering""" + cmd = deleteDiskOffering.deleteDiskOfferingCmd() + cmd.id = self.id + apiclient.deleteDiskOffering(cmd) + return + + @classmethod + def list(cls, apiclient, **kwargs): + """Lists all available disk offerings.""" + + cmd = listDiskOfferings.listDiskOfferingsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall = True + return(apiclient.listDiskOfferings(cmd)) http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d002c52a/tools/marvin/marvin/lib/cloudstack/domain.py ---------------------------------------------------------------------- diff --git a/tools/marvin/marvin/lib/cloudstack/domain.py b/tools/marvin/marvin/lib/cloudstack/domain.py new file mode 100644 index 0000000..492c321 --- /dev/null +++ b/tools/marvin/marvin/lib/cloudstack/domain.py @@ -0,0 +1,72 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +from marvin.cloudstackAPI import createDomain,deleteDomain,listDomains +from marvin.lib.cloudstack.utils import random_gen +class Domain: + """ Domain Life Cycle """ + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, services, name=None, networkdomain=None, + parentdomainid=None): + """Creates an domain""" + + cmd = createDomain.createDomainCmd() + + if "domainUUID" in services: + cmd.domainid = "-".join([services["domainUUID"], random_gen()]) + + if name: + cmd.name = "-".join([name, random_gen()]) + elif "name" in services: + cmd.name = "-".join([services["name"], random_gen()]) + + if networkdomain: + cmd.networkdomain = networkdomain + elif "networkdomain" in services: + cmd.networkdomain = services["networkdomain"] + + if parentdomainid: + cmd.parentdomainid = parentdomainid + elif "parentdomainid" in services: + cmd.parentdomainid = services["parentdomainid"] + try: + domain = apiclient.createDomain(cmd) + if domain is not None: + return Domain(domain.__dict__) + except Exception as e: + raise e + + def delete(self, apiclient, cleanup=None): + """Delete an domain""" + cmd = deleteDomain.deleteDomainCmd() + cmd.id = self.id + if cleanup: + cmd.cleanup = cleanup + apiclient.deleteDomain(cmd) + + @classmethod + def list(cls, apiclient, **kwargs): + """Lists domains""" + cmd = listDomains.listDomainsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall = True + return(apiclient.listDomains(cmd)) + http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d002c52a/tools/marvin/marvin/lib/cloudstack/host.py ---------------------------------------------------------------------- diff --git a/tools/marvin/marvin/lib/cloudstack/host.py b/tools/marvin/marvin/lib/cloudstack/host.py new file mode 100644 index 0000000..d36907a --- /dev/null +++ b/tools/marvin/marvin/lib/cloudstack/host.py @@ -0,0 +1,159 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +import time + +from marvin.cloudstackAPI import addHost,prepareHostForMaintenance,deleteHost,cancelHostMaintenance,listHosts,findHostsForMigration,updateHost +from marvin.lib.cloudstack.utils import validateList +from marvin.codes import (FAILED, PASS) +from marvin.cloudstackException import GetDetailExceptionInfo + + +class Host: + """Manage Host life cycle""" + + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, cluster, services, zoneid=None, podid=None, hypervisor=None): + """ + 1. Creates the host based upon the information provided. + 2. Verifies the output of the adding host and its state post addition + Returns FAILED in case of an issue, else an instance of Host + """ + try: + cmd = addHost.addHostCmd() + cmd.hypervisor = hypervisor + cmd.url = services["url"] + cmd.clusterid = cluster.id + + if zoneid: + cmd.zoneid = zoneid + else: + cmd.zoneid = services["zoneid"] + + if podid: + cmd.podid = podid + else: + cmd.podid = services["podid"] + + if "clustertype" in services: + cmd.clustertype = services["clustertype"] + if "username" in services: + cmd.username = services["username"] + if "password" in services: + cmd.password = services["password"] + + ''' + Adds a Host, + If response is valid and host is up return + an instance of Host. + If response is invalid, returns FAILED. + If host state is not up, verify through listHosts call + till host status is up and return accordingly. Max 3 retries + ''' + host = apiclient.addHost(cmd) + ret = validateList(host) + if ret[0] == PASS: + if str(host[0].state).lower() == 'up': + return Host(host[0].__dict__) + retries = 3 + while retries: + lh_resp = apiclient.listHosts(host[0].id) + ret = validateList(lh_resp) + if (ret[0] == PASS) and \ + (str(ret[1].state).lower() == 'up'): + return Host(host[0].__dict__) + retries += -1 + return FAILED + except Exception as e: + print "Exception Occurred Under Host.create : %s" % \ + GetDetailExceptionInfo(e) + return FAILED + + def delete(self, apiclient): + """Delete Host""" + # Host must be in maintenance mode before deletion + cmd = prepareHostForMaintenance.prepareHostForMaintenanceCmd() + cmd.id = self.id + apiclient.prepareHostForMaintenance(cmd) + time.sleep(30) + + cmd = deleteHost.deleteHostCmd() + cmd.id = self.id + apiclient.deleteHost(cmd) + return + + def enableMaintenance(self, apiclient): + """enables maintenance mode Host""" + + cmd = prepareHostForMaintenance.prepareHostForMaintenanceCmd() + cmd.id = self.id + return apiclient.prepareHostForMaintenance(cmd) + + @classmethod + def enableMaintenance(cls, apiclient, id): + """enables maintenance mode Host""" + + cmd = prepareHostForMaintenance.prepareHostForMaintenanceCmd() + cmd.id = id + return apiclient.prepareHostForMaintenance(cmd) + + def cancelMaintenance(self, apiclient): + """Cancels maintenance mode Host""" + + cmd = cancelHostMaintenance.cancelHostMaintenanceCmd() + cmd.id = self.id + return apiclient.cancelHostMaintenance(cmd) + + @classmethod + def cancelMaintenance(cls, apiclient, id): + """Cancels maintenance mode Host""" + + cmd = cancelHostMaintenance.cancelHostMaintenanceCmd() + cmd.id = id + return apiclient.cancelHostMaintenance(cmd) + + @classmethod + def list(cls, apiclient, **kwargs): + """List all Hosts matching criteria""" + + cmd = listHosts.listHostsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall = True + return(apiclient.listHosts(cmd)) + + @classmethod + def listForMigration(cls, apiclient, **kwargs): + """List all Hosts for migration matching criteria""" + + cmd = findHostsForMigration.findHostsForMigrationCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + if 'account' in kwargs.keys() and 'domainid' in kwargs.keys(): + cmd.listall = True + return(apiclient.findHostsForMigration(cmd)) + + @classmethod + def update(cls, apiclient, **kwargs): + """Update host information""" + + cmd = updateHost.updateHostCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.updateHost(cmd)) +
