| # 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.codes import FAILED, KVM, PASS, XEN_SERVER, RUNNING |
| from nose.plugins.attrib import attr |
| from marvin.cloudstackTestCase import cloudstackTestCase |
| from marvin.lib.utils import random_gen, cleanup_resources, validateList, is_snapshot_on_nfs, isAlmostEqual |
| from marvin.lib.base import (Account, |
| Cluster, |
| Configurations, |
| ServiceOffering, |
| Snapshot, |
| StoragePool, |
| Template, |
| VirtualMachine, |
| VmSnapshot, |
| Volume) |
| from marvin.lib.common import (get_zone, |
| get_domain, |
| get_template, |
| list_disk_offering, |
| list_hosts, |
| list_snapshots, |
| list_storage_pools, |
| list_volumes, |
| list_virtual_machines, |
| list_configurations, |
| list_service_offering, |
| list_clusters, |
| list_zones) |
| from marvin.cloudstackAPI import (listOsTypes, |
| listTemplates, |
| listHosts, |
| listClusters, |
| createTemplate, |
| createVolume, |
| getVolumeSnapshotDetails, |
| resizeVolume, |
| authorizeSecurityGroupIngress, |
| migrateVirtualMachineWithVolume, |
| destroyVirtualMachine, |
| deployVirtualMachine, |
| createAccount, |
| startVirtualMachine, |
| ) |
| import time |
| import pprint |
| import random |
| from marvin.configGenerator import configuration |
| import uuid |
| import logging |
| import subprocess |
| import json |
| from storpool import spapi |
| from storpool import sptypes |
| |
| class TestData(): |
| account = "account" |
| capacityBytes = "capacitybytes" |
| capacityIops = "capacityiops" |
| clusterId = "clusterId" |
| diskName = "diskname" |
| diskOffering = "diskoffering" |
| diskOffering2 = "diskoffering2" |
| diskOfferingEncrypted = "diskOfferingEncrypted" |
| diskOfferingEncrypted2 = "diskOfferingEncrypted2" |
| cephDiskOffering = "cephDiskOffering" |
| nfsDiskOffering = "nfsDiskOffering" |
| diskOfferingTier1Tag = "diskOfferingTier1Tag" |
| diskOfferingTier2Tag = "diskOfferingTier2Tag" |
| diskOfferingTier1Template = "diskOfferingTier1Template" |
| diskOfferingTier2Template = "diskOfferingTier2Template" |
| diskOfferingWithTagsAndTempl = "diskOfferingWithTagsAndTempl" |
| domainId = "domainId" |
| hypervisor = "hypervisor" |
| login = "login" |
| mvip = "mvip" |
| password = "password" |
| port = "port" |
| primaryStorage = "primarystorage" |
| primaryStorage2 = "primarystorage2" |
| primaryStorage3 = "primarystorage3" |
| primaryStorage4 = "primaryStorage4" |
| provider = "provider" |
| serviceOffering = "serviceOffering" |
| serviceOfferingssd2 = "serviceOffering-ssd2" |
| serviceOfferingsPrimary = "serviceOfferingsPrimary" |
| serviceOfferingsIops = "serviceOfferingsIops" |
| serviceOfferingsCeph = "serviceOfferingsCeph" |
| scope = "scope" |
| StorPool = "StorPool" |
| storageTag = ["ssd", "ssd2"] |
| tags = "tags" |
| virtualMachine = "virtualmachine" |
| virtualMachine2 = "virtualmachine2" |
| volume_1 = "volume_1" |
| volume_2 = "volume_2" |
| volume_3 = "volume_3" |
| volume_4 = "volume_4" |
| volume_5 = "volume_5" |
| volume_6 = "volume_6" |
| volume_7 = "volume_7" |
| zoneId = "zoneId" |
| |
| def __init__(self): |
| sp_template_1 = 'ssd' |
| sp_template_2 = 'ssd2' |
| sp_template_3 = 'test-primary' |
| self.testdata = { |
| TestData.primaryStorage: { |
| "name": sp_template_1, |
| TestData.scope: "ZONE", |
| "url": sp_template_1, |
| TestData.provider: "StorPool", |
| "path": "/dev/storpool", |
| TestData.capacityBytes: 2251799813685248, |
| TestData.hypervisor: "KVM" |
| }, |
| TestData.primaryStorage2: { |
| "name": sp_template_2, |
| TestData.scope: "ZONE", |
| "url": sp_template_2, |
| TestData.provider: "StorPool", |
| "path": "/dev/storpool", |
| TestData.capacityBytes: 2251799813685248, |
| TestData.hypervisor: "KVM" |
| }, |
| TestData.primaryStorage3: { |
| "name": sp_template_3, |
| TestData.scope: "ZONE", |
| "url": sp_template_3, |
| TestData.provider: "StorPool", |
| "path": "/dev/storpool", |
| TestData.capacityBytes: 2251799813685248, |
| TestData.hypervisor: "KVM" |
| }, |
| TestData.primaryStorage4: { |
| "name": "ceph", |
| TestData.scope: "ZONE", |
| TestData.provider: "RBD", |
| TestData.hypervisor: "KVM" |
| }, |
| TestData.virtualMachine: { |
| "name": "TestVM", |
| "displayname": "TestVM", |
| "privateport": 22, |
| "publicport": 22, |
| "protocol": "tcp" |
| }, |
| TestData.virtualMachine2: { |
| "name": "TestVM2", |
| "displayname": "TestVM2", |
| "privateport": 22, |
| "publicport": 22, |
| "protocol": "tcp" |
| }, |
| TestData.serviceOffering:{ |
| "name": sp_template_1, |
| "displaytext": "SP_CO_2 (Min IOPS = 10,000; Max IOPS = 15,000)", |
| "cpunumber": 1, |
| "cpuspeed": 500, |
| "memory": 512, |
| "storagetype": "shared", |
| "customizediops": False, |
| "hypervisorsnapshotreserve": 200, |
| "tags": sp_template_1 |
| }, |
| TestData.serviceOfferingssd2:{ |
| "name": sp_template_2, |
| "displaytext": "SP_CO_2 (Min IOPS = 10,000; Max IOPS = 15,000)", |
| "cpunumber": 1, |
| "cpuspeed": 500, |
| "memory": 512, |
| "storagetype": "shared", |
| "customizediops": False, |
| "hypervisorsnapshotreserve": 200, |
| "tags": sp_template_2 |
| }, |
| TestData.serviceOfferingsPrimary:{ |
| "name": "nfs", |
| "displaytext": "SP_CO_2 (Min IOPS = 10,000; Max IOPS = 15,000)", |
| "cpunumber": 1, |
| "cpuspeed": 500, |
| "memory": 512, |
| "storagetype": "shared", |
| "customizediops": False, |
| "hypervisorsnapshotreserve": 200, |
| "tags": "nfs" |
| }, |
| TestData.serviceOfferingsCeph:{ |
| "name": "ceph", |
| "displaytext": "Ceph Service offerings", |
| "cpunumber": 1, |
| "cpuspeed": 500, |
| "memory": 512, |
| "storagetype": "shared", |
| "customizediops": False, |
| "hypervisorsnapshotreserve": 200, |
| "tags": "ceph" |
| }, |
| TestData.serviceOfferingsIops:{ |
| "name": "iops", |
| "displaytext": "Testing IOPS on StorPool", |
| "cpunumber": 1, |
| "cpuspeed": 500, |
| "memory": 512, |
| "storagetype": "shared", |
| "customizediops": True, |
| "tags": sp_template_1, |
| }, |
| TestData.diskOffering: { |
| "name": "SP_DO_1", |
| "displaytext": "SP_DO_1 (5GB Min IOPS = 300; Max IOPS = 500)", |
| "disksize": 5, |
| "customizediops": False, |
| "miniops": 300, |
| "maxiops": 500, |
| "hypervisorsnapshotreserve": 200, |
| TestData.tags: sp_template_1, |
| "storagetype": "shared" |
| }, |
| TestData.diskOffering2: { |
| "name": "SP_DO_1", |
| "displaytext": "SP_DO_1 (5GB Min IOPS = 300; Max IOPS = 500)", |
| "disksize": 5, |
| "customizediops": False, |
| "miniops": 300, |
| "maxiops": 500, |
| "hypervisorsnapshotreserve": 200, |
| TestData.tags: sp_template_2, |
| "storagetype": "shared" |
| }, |
| TestData.diskOfferingEncrypted: { |
| "name": "ssd-encrypted", |
| "displaytext": "ssd-encrypted", |
| "disksize": 5, |
| "hypervisorsnapshotreserve": 200, |
| "encrypt": True, |
| TestData.tags: sp_template_1, |
| "storagetype": "shared" |
| }, |
| TestData.diskOfferingEncrypted2: { |
| "name": "ssd2-encrypted", |
| "displaytext": "ssd2-encrypted", |
| "disksize": 5, |
| "hypervisorsnapshotreserve": 200, |
| "encrypt": True, |
| TestData.tags: sp_template_2, |
| "storagetype": "shared" |
| }, |
| TestData.cephDiskOffering: { |
| "name": "ceph", |
| "displaytext": "Ceph fixed disk offering", |
| "disksize": 5, |
| "customizediops": False, |
| "miniops": 300, |
| "maxiops": 500, |
| "hypervisorsnapshotreserve": 200, |
| TestData.tags: "ceph", |
| "storagetype": "shared" |
| }, |
| TestData.nfsDiskOffering: { |
| "name": "nfs", |
| "displaytext": "NFS fixed disk offering", |
| "disksize": 5, |
| "customizediops": False, |
| "miniops": 300, |
| "maxiops": 500, |
| "hypervisorsnapshotreserve": 200, |
| TestData.tags: "nfs", |
| "storagetype": "shared" |
| }, |
| TestData.diskOfferingTier1Template: { |
| "name": "tier1-template", |
| "displaytext": "Tier1 using different StorPool template", |
| "custom": True, |
| "hypervisorsnapshotreserve": 200, |
| TestData.tags: sp_template_1, |
| "storagetype": "shared" |
| }, |
| TestData.diskOfferingTier2Template: { |
| "name": "tier2-template", |
| "displaytext": "Tier2 using different StorPool template", |
| "custom": True, |
| "hypervisorsnapshotreserve": 200, |
| TestData.tags: sp_template_1, |
| "storagetype": "shared" |
| }, |
| TestData.diskOfferingTier1Tag: { |
| "name": "tier1-tag", |
| "displaytext": "Tier1 using QOS tags", |
| "custom": True, |
| "hypervisorsnapshotreserve": 200, |
| TestData.tags: sp_template_1, |
| "storagetype": "shared" |
| }, |
| TestData.diskOfferingTier2Tag: { |
| "name": "tier2-tag", |
| "displaytext": "Tier2 using QOS tags", |
| "custom": True, |
| "hypervisorsnapshotreserve": 200, |
| TestData.tags: sp_template_1, |
| "storagetype": "shared" |
| }, |
| TestData.diskOfferingWithTagsAndTempl: { |
| "name": "tier2-tag-template", |
| "displaytext": "Tier2 using QOS tags and template", |
| "custom": True, |
| "hypervisorsnapshotreserve": 200, |
| TestData.tags: sp_template_1, |
| "storagetype": "shared" |
| }, |
| TestData.volume_1: { |
| TestData.diskName: "test-volume-1", |
| }, |
| TestData.volume_2: { |
| TestData.diskName: "test-volume-2", |
| }, |
| TestData.volume_3: { |
| TestData.diskName: "test-volume-3", |
| }, |
| TestData.volume_4: { |
| TestData.diskName: "test-volume-4", |
| }, |
| TestData.volume_5: { |
| TestData.diskName: "test-volume-5", |
| }, |
| TestData.volume_6: { |
| TestData.diskName: "test-volume-6", |
| }, |
| TestData.volume_7: { |
| TestData.diskName: "test-volume-7", |
| }, |
| } |
| class StorPoolHelper(): |
| def setUpClass(cls): |
| cls.logger = None |
| |
| @classmethod |
| def logging(cls): |
| return cls.logger |
| |
| @classmethod |
| def create_template_from_snapshot(self, apiclient, services, snapshotid=None, volumeid=None): |
| """Create template from Volume""" |
| # Create template from Virtual machine and Volume ID |
| cmd = createTemplate.createTemplateCmd() |
| cmd.displaytext = "StorPool_Template" |
| cmd.name = "-".join(["StorPool-", random_gen()]) |
| if "ostypeid" in services: |
| cmd.ostypeid = services["ostypeid"] |
| elif "ostype" in services: |
| # Find OSTypeId from Os type |
| sub_cmd = listOsTypes.listOsTypesCmd() |
| sub_cmd.description = services["ostype"] |
| ostypes = apiclient.listOsTypes(sub_cmd) |
| |
| if not isinstance(ostypes, list): |
| raise Exception( |
| "Unable to find Ostype id with desc: %s" % |
| services["ostype"]) |
| cmd.ostypeid = ostypes[0].id |
| else: |
| raise Exception( |
| "Unable to find Ostype is required for creating template") |
| |
| cmd.isfeatured = True |
| cmd.ispublic = True |
| cmd.isextractable = False |
| |
| if snapshotid: |
| cmd.snapshotid = snapshotid |
| if volumeid: |
| cmd.volumeid = volumeid |
| return Template(apiclient.createTemplate(cmd).__dict__) |
| |
| @classmethod |
| def getCfgFromUrl(self, url): |
| cfg = dict([ |
| option.split('=') |
| for option in url.split(';') |
| ]) |
| host, port = cfg['SP_API_HTTP'].split(':') |
| auth = cfg['SP_AUTH_TOKEN'] |
| return host, int(port), auth |
| |
| @classmethod |
| def get_remote_storpool_cluster(cls): |
| logging.debug("######################## get_remote_storpool_cluster") |
| |
| storpool_clusterid = subprocess.check_output(['storpool_confshow', 'CLUSTER_ID']).strip() |
| clusterid = storpool_clusterid.split("=")[1].split(".")[1] |
| logging.debug("######################## %s" % storpool_clusterid) |
| cmd = ["storpool", "-j", "cluster", "list"] |
| proc = subprocess.Popen(cmd,stdout=subprocess.PIPE).stdout.read() |
| csl = json.loads(proc) |
| logging.debug("######################## %s" % csl) |
| |
| clusters = csl.get("data").get("clusters") |
| logging.debug("######################## %s" % clusters) |
| |
| for c in clusters: |
| c_id = c.get("id") |
| if c_id != clusterid: |
| return c.get("name") |
| |
| @classmethod |
| def get_local_cluster(cls, apiclient, zoneid): |
| storpool_clusterid = subprocess.check_output(['storpool_confshow', 'CLUSTER_ID']) |
| clusterid = storpool_clusterid.split("=") |
| logging.debug(storpool_clusterid) |
| clusters = list_clusters(apiclient, zoneid = zoneid) |
| for c in clusters: |
| configuration = list_configurations( |
| apiclient, |
| clusterid = c.id |
| ) |
| for conf in configuration: |
| if conf.name == 'sp.cluster.id' and (conf.value in clusterid[1]): |
| return c |
| |
| @classmethod |
| def get_remote_cluster(cls, apiclient, zoneid): |
| storpool_clusterid = subprocess.check_output(['storpool_confshow', 'CLUSTER_ID']) |
| clusterid = storpool_clusterid.split("=") |
| logging.debug(storpool_clusterid) |
| clusters = list_clusters(apiclient, zoneid = zoneid) |
| for c in clusters: |
| configuration = list_configurations( |
| apiclient, |
| clusterid = c.id |
| ) |
| for conf in configuration: |
| if conf.name == 'sp.cluster.id' and (conf.value not in clusterid[1]): |
| return c |
| |
| @classmethod |
| def get_snapshot_template_id(self, apiclient, snapshot, storage_pool_id): |
| try: |
| cmd = getVolumeSnapshotDetails.getVolumeSnapshotDetailsCmd() |
| cmd.snapshotid = snapshot.id |
| snapshot_details = apiclient.getVolumeSnapshotDetails(cmd) |
| logging.debug("Snapshot details %s" % snapshot_details) |
| logging.debug("Snapshot with uuid %s" % snapshot.id) |
| for s in snapshot_details: |
| if s["snapshotDetailsName"] == storage_pool_id: |
| return s["snapshotDetailsValue"] |
| except Exception as err: |
| raise Exception(err) |
| |
| return None |
| |
| @classmethod |
| def getDestinationHost(self, hostsToavoid, hosts): |
| destinationHost = None |
| for host in hosts: |
| if host.id not in hostsToavoid: |
| destinationHost = host |
| break |
| return destinationHost |
| |
| |
| @classmethod |
| def getDestinationPool(self, |
| poolsToavoid, |
| migrateto, |
| pools |
| ): |
| """ Get destination pool which has scope same as migrateto |
| and which is not in avoid set |
| """ |
| |
| destinationPool = None |
| |
| # Get Storage Pool Id to migrate to |
| for storagePool in pools: |
| if storagePool.scope == migrateto: |
| if storagePool.name not in poolsToavoid: |
| destinationPool = storagePool |
| break |
| |
| return destinationPool |
| |
| @classmethod |
| def get_destination_pools_hosts(self, apiclient, vm, hosts): |
| vol_list = list_volumes( |
| apiclient, |
| virtualmachineid=vm.id, |
| listall=True) |
| # Get destination host |
| destinationHost = self.getDestinationHost(vm.hostid, hosts) |
| return destinationHost, vol_list |
| |
| @classmethod |
| def list_hosts_by_cluster_id(cls, apiclient, clusterid): |
| """List all Hosts matching criteria""" |
| cmd = listHosts.listHostsCmd() |
| cmd.clusterid = clusterid |
| return(apiclient.listHosts(cmd)) |
| |
| @classmethod |
| def set_securityGroups(cls, apiclient, account, domainid, id): |
| cmd = authorizeSecurityGroupIngress.authorizeSecurityGroupIngressCmd() |
| cmd.protocol = 'TCP' |
| cmd.startport = 22 |
| cmd.endport = 22 |
| cmd.cidrlist = '0.0.0.0/0' |
| cmd.securitygroupid = id |
| cmd.account = account |
| cmd.domainid = domainid |
| |
| apiclient.authorizeSecurityGroupIngress(cmd) |
| |
| cmd.protocol = 'ICMP' |
| cmd.icmptype = "-1" |
| cmd.icmpcode = "-1" |
| # Authorize to only account not CIDR |
| cmd.securitygroupid = id |
| cmd.account = account |
| cmd.domainid = domainid |
| apiclient.authorizeSecurityGroupIngress(cmd) |
| |
| @classmethod |
| def migrateVm(self, apiclient, vm, destinationHost): |
| """ |
| This method is to migrate a VM using migrate virtual machine API |
| """ |
| |
| vm.migrate( |
| apiclient, |
| hostid=destinationHost.id, |
| ) |
| vm.getState( |
| apiclient, |
| "Running" |
| ) |
| # check for the VM's host and volume's storage post migration |
| migrated_vm_response = list_virtual_machines(apiclient, id=vm.id) |
| assert isinstance(migrated_vm_response, list), "Check list virtual machines response for valid list" |
| |
| assert migrated_vm_response[0].hostid == destinationHost.id, "VM did not migrate to a specified host" |
| return migrated_vm_response[0] |
| |
| @classmethod |
| def migrateVmWithVolumes(self, apiclient, vm, destinationHost, volumes, pool): |
| """ |
| This method is used to migrate a vm and its volumes using migrate virtual machine with volume API |
| INPUTS: |
| 1. vm -> virtual machine object |
| 2. destinationHost -> the host to which VM will be migrated |
| 3. volumes -> list of volumes which are to be migrated |
| 4. pools -> list of destination pools |
| """ |
| vol_pool_map = {vol.id: pool.id for vol in volumes} |
| |
| cmd = migrateVirtualMachineWithVolume.migrateVirtualMachineWithVolumeCmd() |
| cmd.hostid = destinationHost.id |
| cmd.migrateto = [] |
| cmd.virtualmachineid = self.virtual_machine.id |
| for volume, pool1 in vol_pool_map.items(): |
| cmd.migrateto.append({ |
| 'volume': volume, |
| 'pool': pool1 |
| }) |
| apiclient.migrateVirtualMachineWithVolume(cmd) |
| |
| vm.getState( |
| apiclient, |
| "Running" |
| ) |
| # check for the VM's host and volume's storage post migration |
| migrated_vm_response = list_virtual_machines(apiclient, id=vm.id) |
| assert isinstance(migrated_vm_response, list), "Check list virtual machines response for valid list" |
| |
| assert migrated_vm_response[0].hostid == destinationHost.id, "VM did not migrate to a specified host" |
| |
| for vol in volumes: |
| migrated_volume_response = list_volumes( |
| apiclient, |
| virtualmachineid=migrated_vm_response[0].id, |
| name=vol.name, |
| listall=True) |
| assert isinstance(migrated_volume_response, list), "Check list virtual machines response for valid list" |
| assert migrated_volume_response[0].storageid == pool.id, "Volume did not migrate to a specified pool" |
| |
| assert str(migrated_volume_response[0].state).lower().eq('ready'), "Check migrated volume is in Ready state" |
| |
| return migrated_vm_response[0] |
| |
| @classmethod |
| def create_sp_template_and_storage_pool(self, apiclient, template_name, primary_storage, zoneid): |
| spapiRemote = spapi.Api.fromConfig() |
| logging.debug("================ %s" % spapiRemote) |
| |
| sp_api = spapi.Api.fromConfig(multiCluster= True) |
| logging.debug("================ %s" % sp_api) |
| |
| remote_cluster = self.get_remote_storpool_cluster() |
| logging.debug("================ %s" % remote_cluster) |
| |
| newTemplate = sptypes.VolumeTemplateCreateDesc(name = template_name, placeAll = "ssd", placeTail = "ssd", placeHead = "ssd", replication=1) |
| template_on_remote = spapiRemote.volumeTemplateCreate(newTemplate, clusterName = remote_cluster) |
| template_on_local = spapiRemote.volumeTemplateCreate(newTemplate) |
| storage_pool = StoragePool.create(apiclient, primary_storage, zoneid = zoneid,) |
| return storage_pool, spapiRemote, sp_api |
| |
| @classmethod |
| def destroy_vm(self, apiclient, virtualmachineid): |
| cmd = destroyVirtualMachine.destroyVirtualMachineCmd() |
| cmd.id = virtualmachineid |
| cmd.expunge = True |
| apiclient.destroyVirtualMachine(cmd) |
| |
| @classmethod |
| def check_storpool_volume_size(cls, volume, spapi): |
| name = volume.path.split("/")[3] |
| try: |
| spvolume = spapi.volumeList(volumeName = "~" + name) |
| if spvolume[0].size != volume.size: |
| raise Exception("Storpool volume size is not the same as CloudStack db size") |
| except spapi.ApiError as err: |
| raise Exception(err) |
| |
| @classmethod |
| def check_storpool_volume_iops(cls, spapi, volume,): |
| name = volume.path.split("/")[3] |
| try: |
| spvolume = spapi.volumeList(volumeName = "~" + name) |
| logging.debug(spvolume[0].iops) |
| logging.debug(volume.maxiops) |
| if spvolume[0].iops != volume.maxiops: |
| raise Exception("Storpool volume size is not the same as CloudStack db size") |
| except spapi.ApiError as err: |
| raise Exception(err) |
| |
| @classmethod |
| def create_custom_disk(cls, apiclient, services, size = None, miniops = None, maxiops =None, diskofferingid=None, zoneid=None, account=None, domainid=None, snapshotid=None): |
| """Create Volume from Custom disk offering""" |
| cmd = createVolume.createVolumeCmd() |
| cmd.name = services["diskname"] |
| |
| if diskofferingid: |
| cmd.diskofferingid = diskofferingid |
| |
| if size: |
| cmd.size = size |
| |
| if miniops: |
| cmd.miniops = miniops |
| |
| if maxiops: |
| cmd.maxiops = maxiops |
| |
| if account: |
| cmd.account = account |
| |
| if domainid: |
| cmd.domainid = domainid |
| |
| if snapshotid: |
| cmd.snapshotid = snapshotid |
| |
| cmd.zoneid = zoneid |
| |
| return Volume(apiclient.createVolume(cmd).__dict__) |
| |
| @classmethod |
| def create_vm_custom(cls, apiclient, services, templateid=None, zoneid=None, |
| serviceofferingid=None, method='GET', hypervisor=None, |
| cpuNumber=None, cpuSpeed=None, memory=None, minIops=None, |
| maxIops=None, hostid=None, rootdisksize=None, account=None, domainid=None |
| ): |
| """Create the instance""" |
| |
| cmd = deployVirtualMachine.deployVirtualMachineCmd() |
| |
| if serviceofferingid: |
| cmd.serviceofferingid = serviceofferingid |
| elif "serviceoffering" in services: |
| cmd.serviceofferingid = services["serviceoffering"] |
| |
| if zoneid: |
| cmd.zoneid = zoneid |
| elif "zoneid" in services: |
| cmd.zoneid = services["zoneid"] |
| |
| if hypervisor: |
| cmd.hypervisor = hypervisor |
| |
| if hostid: |
| cmd.hostid = hostid |
| |
| if "displayname" in services: |
| cmd.displayname = services["displayname"] |
| |
| if "name" in services: |
| cmd.name = services["name"] |
| |
| if templateid: |
| cmd.templateid = templateid |
| elif "template" in services: |
| cmd.templateid = services["template"] |
| |
| cmd.details = [{}] |
| |
| if cpuNumber: |
| cmd.details[0]["cpuNumber"] = cpuNumber |
| |
| if cpuSpeed: |
| cmd.details[0]["cpuSpeed"] = cpuSpeed |
| |
| if memory: |
| cmd.details[0]["memory"] = memory |
| |
| if minIops: |
| cmd.details[0]["minIops"] = minIops |
| |
| if maxIops: |
| cmd.details[0]["maxIops"] = maxIops |
| |
| if rootdisksize >= 0: |
| cmd.details[0]["rootdisksize"] = rootdisksize |
| |
| if account: |
| cmd.account = account |
| |
| if domainid: |
| cmd.domainid = domainid |
| |
| virtual_machine = apiclient.deployVirtualMachine(cmd, method=method) |
| |
| return VirtualMachine(virtual_machine.__dict__, services) |
| |
| |
| @classmethod |
| def resize_volume(cls, apiclient, volume, shrinkOk=None, disk_offering =None, size=None, maxiops=None, miniops=None): |
| |
| cmd = resizeVolume.resizeVolumeCmd() |
| cmd.id = volume.id |
| |
| if disk_offering: |
| cmd.diskofferingid = disk_offering.id |
| if size: |
| cmd.size = size |
| |
| if maxiops: |
| cmd.maxiops = maxiops |
| if miniops: |
| cmd.miniops |
| |
| cmd.shrinkok = shrinkOk |
| apiclient.resizeVolume(cmd) |
| |
| new_size = Volume.list( |
| apiclient, |
| id=volume.id |
| ) |
| volume_size = new_size[0].size |
| return new_size[0] |
| |
| @classmethod |
| def create_account(cls, apiclient, services, accounttype=None, domainid=None, roleid=None): |
| """Creates an account""" |
| cmd = createAccount.createAccountCmd() |
| |
| # 0 - User, 1 - Root Admin, 2 - Domain Admin |
| if accounttype: |
| cmd.accounttype = accounttype |
| else: |
| cmd.accounttype = 1 |
| |
| 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 |
| |
| if roleid: |
| cmd.roleid = roleid |
| |
| account = apiclient.createAccount(cmd) |
| |
| return Account(account.__dict__) |
| |
| def start(cls, apiclient, vmid, hostid): |
| """Start the instance""" |
| cmd = startVirtualMachine.startVirtualMachineCmd() |
| cmd.id = vmid |
| cmd.hostid = hostid |
| return (apiclient.startVirtualMachine(cmd)) |
| |
| @classmethod |
| def getClustersWithStorPool(cls, apiclient, zoneId,): |
| cmd = listClusters.listClustersCmd() |
| cmd.zoneid = zoneId |
| cmd.allocationstate = "Enabled" |
| clusters = apiclient.listClusters(cmd) |
| clustersToDeploy = [] |
| for cluster in clusters: |
| if cluster.resourcedetails['sp.cluster.id']: |
| clustersToDeploy.append(cluster.id) |
| |
| return clustersToDeploy |
| |
| @classmethod |
| def getHostToDeployOrMigrate(cls, apiclient, hostsToavoid, clustersToDeploy): |
| hostsOnCluster = [] |
| for c in clustersToDeploy: |
| hostsOnCluster.append(cls.list_hosts_by_cluster_id(apiclient, c)) |
| |
| destinationHost = None |
| for host in hostsOnCluster: |
| |
| if hostsToavoid is None: |
| return host[0] |
| if host[0].id not in hostsToavoid: |
| destinationHost = host[0] |
| break |
| |
| return destinationHost |