mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
api,server: add params for updatehypervisorcapabilities API (#5473)
* api,server: add params for updatehypervisorcapabilities API Allows updating following capabilities for a hypervisor, version: - Max DATA volumes limit - Storage motion supported - Max hosts per cluster - VM snapshot enabled * added test * changes Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com> * Update test/integration/smoke/test_hypervisor_capabilities.py Co-authored-by: dahn <daan.hoogland@gmail.com>
This commit is contained in:
parent
8adb8df2fe
commit
62b806ac13
@ -52,4 +52,6 @@ public interface HypervisorCapabilities extends Identity, InternalIdentity {
|
||||
|
||||
boolean isStorageMotionSupported();
|
||||
|
||||
Boolean isVmSnapshotEnabled();
|
||||
|
||||
}
|
||||
|
||||
@ -22,6 +22,7 @@ import java.util.Map;
|
||||
|
||||
import org.apache.cloudstack.api.command.admin.cluster.ListClustersCmd;
|
||||
import org.apache.cloudstack.api.command.admin.config.ListCfgsByCmd;
|
||||
import org.apache.cloudstack.api.command.admin.config.UpdateHypervisorCapabilitiesCmd;
|
||||
import org.apache.cloudstack.api.command.admin.guest.AddGuestOsCmd;
|
||||
import org.apache.cloudstack.api.command.admin.guest.AddGuestOsMappingCmd;
|
||||
import org.apache.cloudstack.api.command.admin.guest.ListGuestOsMappingCmd;
|
||||
@ -407,7 +408,7 @@ public interface ManagementService {
|
||||
Pair<List<? extends HypervisorCapabilities>, Integer> listHypervisorCapabilities(Long id, HypervisorType hypervisorType, String keyword, Long startIndex,
|
||||
Long pageSizeVal);
|
||||
|
||||
HypervisorCapabilities updateHypervisorCapabilities(Long id, Long maxGuestsLimit, Boolean securityGroupEnabled);
|
||||
HypervisorCapabilities updateHypervisorCapabilities(UpdateHypervisorCapabilitiesCmd cmd);
|
||||
|
||||
/**
|
||||
* list all the top consumed resources across different capacity types
|
||||
|
||||
@ -590,6 +590,7 @@ public class ApiConstants {
|
||||
public static final String MIGRATE_ALLOWED = "migrateallowed";
|
||||
public static final String MIGRATE_TO = "migrateto";
|
||||
public static final String GUID = "guid";
|
||||
public static final String VM_SNAPSHOT_ENABELD = "vmsnapshotenabled";
|
||||
public static final String VSWITCH_TYPE_GUEST_TRAFFIC = "guestvswitchtype";
|
||||
public static final String VSWITCH_TYPE_PUBLIC_TRAFFIC = "publicvswitchtype";
|
||||
public static final String VSWITCH_NAME_GUEST_TRAFFIC = "guestvswitchname";
|
||||
|
||||
@ -52,6 +52,18 @@ public class UpdateHypervisorCapabilitiesCmd extends BaseCmd {
|
||||
@Parameter(name = ApiConstants.MAX_GUESTS_LIMIT, type = CommandType.LONG, description = "the max number of Guest VMs per host for this hypervisor.")
|
||||
private Long maxGuestsLimit;
|
||||
|
||||
@Parameter(name = ApiConstants.MAX_DATA_VOLUMES_LIMIT, type = CommandType.INTEGER, description = "the maximum number of Data Volumes that can be attached to a VM for this hypervisor.", since = "4.16.0")
|
||||
private Integer maxDataVolumesLimit;
|
||||
|
||||
@Parameter(name = ApiConstants.STORAGE_MOTION_ENABLED, type = CommandType.BOOLEAN, description = "set true to enable storage motion support for this hypervisor", since = "4.16.0")
|
||||
private Boolean storageMotionSupported;
|
||||
|
||||
@Parameter(name = ApiConstants.MAX_HOSTS_PER_CLUSTER, type = CommandType.INTEGER, description = "the maximum number of the hypervisor hosts per cluster ", since = "4.16.0")
|
||||
private Integer maxHostsPerClusterLimit;
|
||||
|
||||
@Parameter(name = ApiConstants.VM_SNAPSHOT_ENABELD, type = CommandType.BOOLEAN, description = "set true to enable VM snapshots for this hypervisor", since = "4.16.0")
|
||||
private Boolean vmSnapshotEnabled;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////////// Accessors ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
@ -68,6 +80,22 @@ public class UpdateHypervisorCapabilitiesCmd extends BaseCmd {
|
||||
return maxGuestsLimit;
|
||||
}
|
||||
|
||||
public Integer getMaxDataVolumesLimit() {
|
||||
return maxDataVolumesLimit;
|
||||
}
|
||||
|
||||
public Boolean getStorageMotionSupported() {
|
||||
return storageMotionSupported;
|
||||
}
|
||||
|
||||
public Integer getMaxHostsPerClusterLimit() {
|
||||
return maxHostsPerClusterLimit;
|
||||
}
|
||||
|
||||
public Boolean getVmSnapshotEnabled() {
|
||||
return vmSnapshotEnabled;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
@ -84,7 +112,7 @@ public class UpdateHypervisorCapabilitiesCmd extends BaseCmd {
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
HypervisorCapabilities result = _mgr.updateHypervisorCapabilities(getId(), getMaxGuestsLimit(), getSecurityGroupEnabled());
|
||||
HypervisorCapabilities result = _mgr.updateHypervisorCapabilities(this);
|
||||
if (result != null) {
|
||||
HypervisorCapabilitiesResponse response = _responseGenerator.createHypervisorCapabilitiesResponse(result);
|
||||
response.setResponseName(getCommandName());
|
||||
|
||||
@ -16,8 +16,6 @@
|
||||
// under the License.
|
||||
package org.apache.cloudstack.api.response;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.BaseResponse;
|
||||
import org.apache.cloudstack.api.EntityReference;
|
||||
@ -25,6 +23,7 @@ import org.apache.cloudstack.api.EntityReference;
|
||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||
import com.cloud.hypervisor.HypervisorCapabilities;
|
||||
import com.cloud.serializer.Param;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
@EntityReference(value = HypervisorCapabilities.class)
|
||||
public class HypervisorCapabilitiesResponse extends BaseResponse {
|
||||
@ -60,6 +59,10 @@ public class HypervisorCapabilitiesResponse extends BaseResponse {
|
||||
@Param(description = "true if storage motion is supported")
|
||||
private boolean isStorageMotionSupported;
|
||||
|
||||
@SerializedName(ApiConstants.VM_SNAPSHOT_ENABELD)
|
||||
@Param(description = "true if VM snapshots are enabled for this hypervisor")
|
||||
private boolean isVmSnapshotEnabled;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
@ -123,4 +126,12 @@ public class HypervisorCapabilitiesResponse extends BaseResponse {
|
||||
public void setMaxHostsPerCluster(Integer maxHostsPerCluster) {
|
||||
this.maxHostsPerCluster = maxHostsPerCluster;
|
||||
}
|
||||
|
||||
public boolean isVmSnapshotEnabled() {
|
||||
return isVmSnapshotEnabled;
|
||||
}
|
||||
|
||||
public void setVmSnapshotEnabled(boolean vmSnapshotEnabled) {
|
||||
isVmSnapshotEnabled = vmSnapshotEnabled;
|
||||
}
|
||||
}
|
||||
|
||||
@ -189,7 +189,8 @@ public class HypervisorCapabilitiesVO implements HypervisorCapabilities {
|
||||
this.maxHostsPerCluster = maxHostsPerCluster;
|
||||
}
|
||||
|
||||
public Boolean getVmSnapshotEnabled() {
|
||||
@Override
|
||||
public Boolean isVmSnapshotEnabled() {
|
||||
return vmSnapshotEnabled;
|
||||
}
|
||||
|
||||
|
||||
@ -105,7 +105,7 @@ public class HypervisorCapabilitiesDaoImpl extends GenericDaoBase<HypervisorCapa
|
||||
@Override
|
||||
public Boolean isVmSnapshotEnabled(HypervisorType hypervisorType, String hypervisorVersion) {
|
||||
HypervisorCapabilitiesVO result = getCapabilities(hypervisorType, hypervisorVersion);
|
||||
return result.getVmSnapshotEnabled();
|
||||
return result.isVmSnapshotEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -34,7 +34,6 @@ import java.util.stream.Collectors;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import com.cloud.server.ResourceIcon;
|
||||
import org.apache.cloudstack.acl.ControlledEntity;
|
||||
import org.apache.cloudstack.acl.ControlledEntity.ACLType;
|
||||
import org.apache.cloudstack.affinity.AffinityGroup;
|
||||
@ -304,6 +303,7 @@ import com.cloud.projects.ProjectAccount;
|
||||
import com.cloud.projects.ProjectInvitation;
|
||||
import com.cloud.region.ha.GlobalLoadBalancerRule;
|
||||
import com.cloud.resource.RollingMaintenanceManager;
|
||||
import com.cloud.server.ResourceIcon;
|
||||
import com.cloud.server.ResourceTag;
|
||||
import com.cloud.server.ResourceTag.ResourceObjectType;
|
||||
import com.cloud.service.ServiceOfferingVO;
|
||||
@ -2614,6 +2614,7 @@ public class ApiResponseHelper implements ResponseGenerator {
|
||||
hpvCapabilitiesResponse.setMaxDataVolumesLimit(hpvCapabilities.getMaxDataVolumesLimit());
|
||||
hpvCapabilitiesResponse.setMaxHostsPerCluster(hpvCapabilities.getMaxHostsPerCluster());
|
||||
hpvCapabilitiesResponse.setIsStorageMotionSupported(hpvCapabilities.isStorageMotionSupported());
|
||||
hpvCapabilitiesResponse.setVmSnapshotEnabled(hpvCapabilities.isVmSnapshotEnabled());
|
||||
return hpvCapabilitiesResponse;
|
||||
}
|
||||
|
||||
|
||||
@ -35,8 +35,6 @@ import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
@ -44,8 +42,6 @@ import javax.crypto.spec.SecretKeySpec;
|
||||
import javax.inject.Inject;
|
||||
import javax.naming.ConfigurationException;
|
||||
|
||||
import com.cloud.dc.DomainVlanMapVO;
|
||||
import com.cloud.dc.dao.DomainVlanMapDao;
|
||||
import org.apache.cloudstack.acl.ControlledEntity;
|
||||
import org.apache.cloudstack.affinity.AffinityGroupProcessor;
|
||||
import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao;
|
||||
@ -605,6 +601,7 @@ import com.cloud.consoleproxy.ConsoleProxyManager;
|
||||
import com.cloud.dc.AccountVlanMapVO;
|
||||
import com.cloud.dc.ClusterVO;
|
||||
import com.cloud.dc.DataCenterVO;
|
||||
import com.cloud.dc.DomainVlanMapVO;
|
||||
import com.cloud.dc.HostPodVO;
|
||||
import com.cloud.dc.Pod;
|
||||
import com.cloud.dc.PodVlanMapVO;
|
||||
@ -614,6 +611,7 @@ import com.cloud.dc.VlanVO;
|
||||
import com.cloud.dc.dao.AccountVlanMapDao;
|
||||
import com.cloud.dc.dao.ClusterDao;
|
||||
import com.cloud.dc.dao.DataCenterDao;
|
||||
import com.cloud.dc.dao.DomainVlanMapDao;
|
||||
import com.cloud.dc.dao.HostPodDao;
|
||||
import com.cloud.dc.dao.PodVlanMapDao;
|
||||
import com.cloud.dc.dao.VlanDao;
|
||||
@ -663,9 +661,9 @@ import com.cloud.network.dao.LoadBalancerDao;
|
||||
import com.cloud.network.dao.LoadBalancerVO;
|
||||
import com.cloud.network.dao.NetworkAccountDao;
|
||||
import com.cloud.network.dao.NetworkAccountVO;
|
||||
import com.cloud.network.dao.NetworkDao;
|
||||
import com.cloud.network.dao.NetworkDomainDao;
|
||||
import com.cloud.network.dao.NetworkDomainVO;
|
||||
import com.cloud.network.dao.NetworkDao;
|
||||
import com.cloud.network.dao.NetworkVO;
|
||||
import com.cloud.network.vpc.dao.VpcDao;
|
||||
import com.cloud.org.Cluster;
|
||||
@ -4459,7 +4457,14 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
||||
}
|
||||
|
||||
@Override
|
||||
public HypervisorCapabilities updateHypervisorCapabilities(final Long id, final Long maxGuestsLimit, final Boolean securityGroupEnabled) {
|
||||
public HypervisorCapabilities updateHypervisorCapabilities(UpdateHypervisorCapabilitiesCmd cmd) {
|
||||
final Long id = cmd.getId();
|
||||
final Boolean securityGroupEnabled = cmd.getSecurityGroupEnabled();
|
||||
final Long maxGuestsLimit = cmd.getMaxGuestsLimit();
|
||||
final Integer maxDataVolumesLimit = cmd.getMaxDataVolumesLimit();
|
||||
final Boolean storageMotionSupported = cmd.getStorageMotionSupported();
|
||||
final Integer maxHostsPerClusterLimit = cmd.getMaxHostsPerClusterLimit();
|
||||
final Boolean vmSnapshotEnabled = cmd.getVmSnapshotEnabled();
|
||||
HypervisorCapabilitiesVO hpvCapabilities = _hypervisorCapabilitiesDao.findById(id, true);
|
||||
|
||||
if (hpvCapabilities == null) {
|
||||
@ -4468,19 +4473,37 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
||||
throw ex;
|
||||
}
|
||||
|
||||
final boolean updateNeeded = maxGuestsLimit != null || securityGroupEnabled != null;
|
||||
final boolean updateNeeded = securityGroupEnabled != null || maxGuestsLimit != null ||
|
||||
maxDataVolumesLimit != null || storageMotionSupported != null || maxHostsPerClusterLimit != null ||
|
||||
vmSnapshotEnabled != null;
|
||||
if (!updateNeeded) {
|
||||
return hpvCapabilities;
|
||||
}
|
||||
|
||||
hpvCapabilities = _hypervisorCapabilitiesDao.createForUpdate(id);
|
||||
|
||||
if (securityGroupEnabled != null) {
|
||||
hpvCapabilities.setSecurityGroupEnabled(securityGroupEnabled);
|
||||
}
|
||||
|
||||
if (maxGuestsLimit != null) {
|
||||
hpvCapabilities.setMaxGuestsLimit(maxGuestsLimit);
|
||||
}
|
||||
|
||||
if (securityGroupEnabled != null) {
|
||||
hpvCapabilities.setSecurityGroupEnabled(securityGroupEnabled);
|
||||
if (maxDataVolumesLimit != null) {
|
||||
hpvCapabilities.setMaxDataVolumesLimit(maxDataVolumesLimit);
|
||||
}
|
||||
|
||||
if (storageMotionSupported != null) {
|
||||
hpvCapabilities.setStorageMotionSupported(storageMotionSupported);
|
||||
}
|
||||
|
||||
if (maxHostsPerClusterLimit != null) {
|
||||
hpvCapabilities.setMaxHostsPerCluster(maxHostsPerClusterLimit);
|
||||
}
|
||||
|
||||
if (vmSnapshotEnabled != null) {
|
||||
hpvCapabilities.setVmSnapshotEnabled(vmSnapshotEnabled);
|
||||
}
|
||||
|
||||
if (_hypervisorCapabilitiesDao.update(id, hpvCapabilities)) {
|
||||
|
||||
289
test/integration/component/test_hypervisor_capabilities.py
Normal file
289
test/integration/component/test_hypervisor_capabilities.py
Normal file
@ -0,0 +1,289 @@
|
||||
# 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.
|
||||
""" Test cases for Testing Hypervisor Capabilities
|
||||
"""
|
||||
from nose.plugins.attrib import attr
|
||||
from marvin.cloudstackTestCase import cloudstackTestCase
|
||||
from marvin.lib.utils import (cleanup_resources,
|
||||
validateList)
|
||||
from marvin.lib.base import (Account,
|
||||
ServiceOffering,
|
||||
DiskOffering,
|
||||
VirtualMachine,
|
||||
Volume,
|
||||
Host,
|
||||
VmSnapshot)
|
||||
from marvin.lib.common import (get_domain,
|
||||
get_zone,
|
||||
get_template,
|
||||
list_virtual_machines,
|
||||
list_ssvms,
|
||||
list_routers)
|
||||
from marvin.lib.decoratorGenerators import skipTestIf
|
||||
|
||||
|
||||
from marvin.cloudstackAPI import (updateHypervisorCapabilities,
|
||||
listHypervisorCapabilities)
|
||||
|
||||
from marvin.codes import PASS
|
||||
|
||||
|
||||
class TestHypervisorCapabilities(cloudstackTestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
testClient = super(TestHypervisorCapabilities, cls).getClsTestClient()
|
||||
cls.apiclient = testClient.getApiClient()
|
||||
cls.services = testClient.getParsedTestDataConfig()
|
||||
cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
|
||||
cls.domain = get_domain(cls.apiclient)
|
||||
|
||||
cls.hypervisor = cls.testClient.getHypervisorInfo()
|
||||
# Get Zone, Domain and templates
|
||||
|
||||
cls.notSupported = True
|
||||
cls._cleanup = []
|
||||
cls.hosts = Host.list(cls.apiclient, zoneid=cls.zone.id, type='Routing')
|
||||
if isinstance(cls.hosts, list) and len(cls.hosts) > 0:
|
||||
cls.host = cls.hosts[0]
|
||||
cls.notSupported = False
|
||||
|
||||
cls.hypervisorversion = "default"
|
||||
if hasattr(cls.host, 'hypervisorversion'):
|
||||
cls.hypervisorversion = cls.host.hypervisorversion
|
||||
|
||||
if cls.notSupported == False:
|
||||
cls.notSupported = True
|
||||
cmdList = listHypervisorCapabilities.listHypervisorCapabilitiesCmd()
|
||||
cmdList.hypervisor = cls.hypervisor
|
||||
capabilities = cls.apiclient.listHypervisorCapabilities(cmdList)
|
||||
for capability in capabilities:
|
||||
if capability.hypervisorversion == cls.hypervisorversion:
|
||||
cls.hostCapability = capability
|
||||
cls.notSupported = False
|
||||
break
|
||||
|
||||
if cls.notSupported == True:
|
||||
cls.hypervisorversion = "default"
|
||||
for capability in capabilities:
|
||||
if capability.hypervisorversion == cls.hypervisorversion:
|
||||
cls.hostCapability = capability
|
||||
cls.notSupported = False
|
||||
break
|
||||
|
||||
if cls.notSupported == False:
|
||||
cls.template = get_template(
|
||||
cls.apiclient,
|
||||
cls.zone.id,
|
||||
cls.services["ostype"])
|
||||
|
||||
# Create an account
|
||||
cls.account = Account.create(
|
||||
cls.apiclient,
|
||||
cls.services["account"],
|
||||
domainid=cls.domain.id
|
||||
)
|
||||
cls._cleanup.append(cls.account)
|
||||
|
||||
# Create user api client of the account
|
||||
cls.userapiclient = testClient.getUserApiClient(
|
||||
UserName=cls.account.name,
|
||||
DomainName=cls.account.domain
|
||||
)
|
||||
# Create Service offering
|
||||
cls.service_offering = ServiceOffering.create(
|
||||
cls.apiclient,
|
||||
cls.services["service_offering"],
|
||||
hosttags="host1"
|
||||
)
|
||||
cls._cleanup.append(cls.service_offering)
|
||||
|
||||
cls.disk_offering = DiskOffering.create(
|
||||
cls.apiclient,
|
||||
cls.services["disk_offering"]
|
||||
)
|
||||
cls._cleanup.append(cls.disk_offering)
|
||||
|
||||
return
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
super(TestHypervisorCapabilities, cls).tearDownClass()
|
||||
|
||||
def setUp(self):
|
||||
self.cleanup = []
|
||||
|
||||
self.apiclient = self.testClient.getApiClient()
|
||||
self.dbclient = self.testClient.getDbConnection()
|
||||
|
||||
def tearDown(self):
|
||||
try:
|
||||
if self.notSupported == False:
|
||||
Host.update(self.apiclient, id=self.host.id, hosttags="")
|
||||
self.updateHostHypervisorCapability(self.hostCapability.id,
|
||||
self.hostCapability.maxdatavolumeslimit,
|
||||
self.hostCapability.vmsnapshotenabled)
|
||||
|
||||
super(TestHypervisorCapabilities, self).tearDown()
|
||||
except Exception as e:
|
||||
raise Exception("Warning: Exception during cleanup : %s" % e)
|
||||
return
|
||||
|
||||
@skipTestIf("notSupported")
|
||||
@attr(tags=["advanced", "basic"], required_hardware="false")
|
||||
def test_01_check_hypervisor_max_data_volume_limit(self):
|
||||
""" Test hypervisor maxdatavolumeslimit effect
|
||||
|
||||
# 1. Set maxdatavolumeslimit to 1 for hypervisor
|
||||
# 2. List capabilities and verify value
|
||||
# 3. Deploy a VM and attach a volume to it
|
||||
# 4. Try attach another volume, it should fail
|
||||
# 5. Set maxdatavolumeslimit to 32 for hypervisor
|
||||
# 6. Try attach second volume, it should succeed
|
||||
"""
|
||||
self.updateHostHypervisorCapability(self.hostCapability.id, 1)
|
||||
capabilities = self.listHostHypervisorCapabilities(self.hostCapability.id)
|
||||
self.assertTrue(isinstance(capabilities, list), "listHypervisorCapabilities response not a valid list")
|
||||
self.assertEqual(len(capabilities), 1, "listHypervisorCapabilities response not valid")
|
||||
self.assertEqual(capabilities[0].maxdatavolumeslimit,
|
||||
1,
|
||||
"listHypervisorCapabilities response maxdatavolumeslimit value not 1")
|
||||
|
||||
Host.update(self.apiclient, id=self.host.id, hosttags="host1")
|
||||
volume_created1 = Volume.create(
|
||||
self.userapiclient,
|
||||
self.services["volume"],
|
||||
zoneid=self.zone.id,
|
||||
diskofferingid=self.disk_offering.id
|
||||
)
|
||||
self.cleanup.append(volume_created1)
|
||||
volume_created2 = Volume.create(
|
||||
self.userapiclient,
|
||||
self.services["volume"],
|
||||
zoneid=self.zone.id,
|
||||
diskofferingid=self.disk_offering.id
|
||||
)
|
||||
self.cleanup.append(volume_created2)
|
||||
vm = VirtualMachine.create(
|
||||
self.userapiclient,
|
||||
self.services["small"],
|
||||
templateid=self.template.id,
|
||||
accountid=self.account.name,
|
||||
domainid=self.account.domainid,
|
||||
serviceofferingid=self.service_offering.id,
|
||||
zoneid=self.zone.id
|
||||
)
|
||||
self.cleanup.append(vm)
|
||||
|
||||
vm.attach_volume(
|
||||
self.userapiclient,
|
||||
volume_created1
|
||||
)
|
||||
|
||||
try:
|
||||
vm.attach_volume(
|
||||
self.userapiclient,
|
||||
volume_created2
|
||||
)
|
||||
vm.detach_volume(self.userapiclient, volume_created1)
|
||||
vm.detach_volume(self.userapiclient, volume_created2)
|
||||
self.fail("Successful to attach 2 DATA disks when max DATA disk limit was set to 1")
|
||||
except Exception as e:
|
||||
self.debug("Failed to attach 2nd DATA disk when max DATA disk limit was set to 1: %s" % e)
|
||||
|
||||
self.updateHostHypervisorCapability(self.hostCapability.id, 32)
|
||||
|
||||
vm.attach_volume(
|
||||
self.userapiclient,
|
||||
volume_created2
|
||||
)
|
||||
vm.stop(self.userapiclient, forced=True)
|
||||
vm.detach_volume(self.userapiclient, volume_created1)
|
||||
vm.detach_volume(self.userapiclient, volume_created2)
|
||||
|
||||
@skipTestIf("notSupported")
|
||||
@attr(tags=["advanced", "basic"], required_hardware="false")
|
||||
def test_02_check_hypervisor_vm_snapshot(self):
|
||||
""" Test hypervisor vmsnapshotenabled effect
|
||||
|
||||
# 1. Set vmsnapshotenabled to false for hypervisor
|
||||
# 2. List capabilities and verify value
|
||||
# 3. Deploy a VM
|
||||
# 4. Try VM snapshot, it should fail
|
||||
# 5. Set vmsnapshotenabled to true for hypervisor
|
||||
# 6. Try VM snapshot again, it should succeed
|
||||
"""
|
||||
if self.hypervisor == "KVM":
|
||||
self.skipTest("Skipping test: Reason - VM Snapshot of running VM is not supported for KVM")
|
||||
self.updateHostHypervisorCapability(self.hostCapability.id, None, False)
|
||||
capabilities = self.listHostHypervisorCapabilities(self.hostCapability.id)
|
||||
self.assertTrue(isinstance(capabilities, list), "listHypervisorCapabilities response not a valid list")
|
||||
self.assertEqual(len(capabilities), 1, "listHypervisorCapabilities response not valid")
|
||||
self.assertEqual(capabilities[0].vmsnapshotenabled,
|
||||
False,
|
||||
"listHypervisorCapabilities response vmsnapshotenabled value not False")
|
||||
|
||||
Host.update(self.apiclient, id=self.host.id, hosttags="host1")
|
||||
vm = VirtualMachine.create(
|
||||
self.userapiclient,
|
||||
self.services["small"],
|
||||
templateid=self.template.id,
|
||||
accountid=self.account.name,
|
||||
domainid=self.account.domainid,
|
||||
serviceofferingid=self.service_offering.id,
|
||||
zoneid=self.zone.id
|
||||
)
|
||||
self.cleanup.append(vm)
|
||||
|
||||
try:
|
||||
fail_snapshot = VmSnapshot.create(
|
||||
self.userapiclient,
|
||||
vmid=vm.id,
|
||||
snapshotmemory="false",
|
||||
name="Test Snapshot",
|
||||
description="Test Snapshot Desc"
|
||||
)
|
||||
self.cleanup.append(fail_snapshot)
|
||||
self.fail("Successful to take VM snapshot even when vmsnapshotenabled was set to False")
|
||||
except Exception as e:
|
||||
self.debug("Failed to take VM snapshot even vmsnapshotenabled was set to False: %s" % e)
|
||||
|
||||
self.updateHostHypervisorCapability(self.hostCapability.id, None, True)
|
||||
|
||||
vm_snapshot = VmSnapshot.create(
|
||||
self.userapiclient,
|
||||
vmid=vm.id,
|
||||
snapshotmemory="false",
|
||||
name="Test Snapshot",
|
||||
description="Test Snapshot Desc"
|
||||
)
|
||||
self.cleanup.append(vm_snapshot)
|
||||
|
||||
def updateHostHypervisorCapability(self, id, maxDataVolumes, vmSnapshotEnabled=None):
|
||||
cmd = updateHypervisorCapabilities.updateHypervisorCapabilitiesCmd()
|
||||
cmd.id = id
|
||||
if maxDataVolumes != None:
|
||||
cmd.maxdatavolumeslimit = maxDataVolumes
|
||||
if vmSnapshotEnabled != None:
|
||||
cmd.vmsnapshotenabled = vmSnapshotEnabled
|
||||
self.apiclient.updateHypervisorCapabilities(cmd)
|
||||
|
||||
def listHostHypervisorCapabilities(self, id, hypervisor=None):
|
||||
cmd = listHypervisorCapabilities.listHypervisorCapabilitiesCmd()
|
||||
cmd.id = id
|
||||
return self.apiclient.listHypervisorCapabilities(cmd)
|
||||
|
||||
@ -5097,6 +5097,11 @@ class VmSnapshot:
|
||||
cmd.vmsnapshotid = vmsnapshotid
|
||||
return apiclient.deleteVMSnapshot(cmd)
|
||||
|
||||
def delete(self, apiclient):
|
||||
cmd = deleteVMSnapshot.deleteVMSnapshotCmd()
|
||||
cmd.vmsnapshotid = self.id
|
||||
return apiclient.deleteVMSnapshot(cmd)
|
||||
|
||||
|
||||
class Region:
|
||||
""" Regions related Api """
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user