Merge remote-tracking branch 'origin/4.17'

Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com>
This commit is contained in:
Rohit Yadav 2022-11-30 21:02:17 +05:30
commit 3d8ea4f3b3
14 changed files with 539 additions and 72 deletions

View File

@ -436,7 +436,7 @@ public interface ManagementService {
*/ */
Pair<List<? extends StoragePool>, List<? extends StoragePool>> listStoragePoolsForMigrationOfVolume(Long volumeId); Pair<List<? extends StoragePool>, List<? extends StoragePool>> listStoragePoolsForMigrationOfVolume(Long volumeId);
Pair<List<? extends StoragePool>, List<? extends StoragePool>> listStoragePoolsForMigrationOfVolumeInternal(Long volumeId, Long newDiskOfferingId, Long newSize, Long newMinIops, Long newMaxIops, boolean keepSourceStoragePool, boolean bypassStorageTypeCheck); Pair<List<? extends StoragePool>, List<? extends StoragePool>> listStoragePoolsForSystemMigrationOfVolume(Long volumeId, Long newDiskOfferingId, Long newSize, Long newMinIops, Long newMaxIops, boolean keepSourceStoragePool, boolean bypassStorageTypeCheck);
String[] listEventTypes(); String[] listEventTypes();

View File

@ -524,7 +524,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
@Override @Override
public void allocate(final String vmInstanceName, final VirtualMachineTemplate template, final ServiceOffering serviceOffering, public void allocate(final String vmInstanceName, final VirtualMachineTemplate template, final ServiceOffering serviceOffering,
final LinkedHashMap<? extends Network, List<? extends NicProfile>> networks, final DeploymentPlan plan, final HypervisorType hyperType) throws InsufficientCapacityException { final LinkedHashMap<? extends Network, List<? extends NicProfile>> networks, final DeploymentPlan plan, final HypervisorType hyperType) throws InsufficientCapacityException {
DiskOffering diskOffering = _diskOfferingDao.findById(serviceOffering.getId()); DiskOffering diskOffering = _diskOfferingDao.findById(serviceOffering.getDiskOfferingId());
allocate(vmInstanceName, template, serviceOffering, new DiskOfferingInfo(diskOffering), new ArrayList<>(), networks, plan, hyperType, null, null); allocate(vmInstanceName, template, serviceOffering, new DiskOfferingInfo(diskOffering), new ArrayList<>(), networks, plan, hyperType, null, null);
} }

View File

@ -3526,7 +3526,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S
} else if (param.matches("vbd_.*_write")) { } else if (param.matches("vbd_.*_write")) {
vmStatsAnswer.setDiskWriteKBs(vmStatsAnswer.getDiskWriteKBs() + getDataAverage(dataNode, col, numRows) / BASE_TO_CONVERT_BYTES_INTO_KILOBYTES); vmStatsAnswer.setDiskWriteKBs(vmStatsAnswer.getDiskWriteKBs() + getDataAverage(dataNode, col, numRows) / BASE_TO_CONVERT_BYTES_INTO_KILOBYTES);
} else if (param.contains("memory_internal_free")) { } else if (param.contains("memory_internal_free")) {
vmStatsAnswer.setIntFreeMemoryKBs(vmStatsAnswer.getIntFreeMemoryKBs() + getDataAverage(dataNode, col, numRows) / BASE_TO_CONVERT_BYTES_INTO_KILOBYTES); vmStatsAnswer.setIntFreeMemoryKBs(vmStatsAnswer.getIntFreeMemoryKBs() + getDataAverage(dataNode, col, numRows));
} else if (param.contains("memory_target")) { } else if (param.contains("memory_target")) {
vmStatsAnswer.setTargetMemoryKBs(vmStatsAnswer.getTargetMemoryKBs() + getDataAverage(dataNode, col, numRows) / BASE_TO_CONVERT_BYTES_INTO_KILOBYTES); vmStatsAnswer.setTargetMemoryKBs(vmStatsAnswer.getTargetMemoryKBs() + getDataAverage(dataNode, col, numRows) / BASE_TO_CONVERT_BYTES_INTO_KILOBYTES);
} else if (param.contains("memory")) { } else if (param.contains("memory")) {

View File

@ -120,7 +120,7 @@ public class DomainChecker extends AdapterBase implements SecurityChecker {
*/ */
private void checkPublicTemplateAccess(VirtualMachineTemplate template, Account owner, Account caller){ private void checkPublicTemplateAccess(VirtualMachineTemplate template, Account owner, Account caller){
if (!QueryService.SharePublicTemplatesWithOtherDomains.valueIn(owner.getDomainId()) || if (QueryService.SharePublicTemplatesWithOtherDomains.valueIn(owner.getDomainId()) ||
caller.getDomainId() == owner.getDomainId() || caller.getDomainId() == owner.getDomainId() ||
_domainDao.isChildDomain(owner.getDomainId(), caller.getDomainId())) { _domainDao.isChildDomain(owner.getDomainId(), caller.getDomainId())) {
return; return;

View File

@ -1552,7 +1552,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
@Override @Override
public Pair<List<? extends StoragePool>, List<? extends StoragePool>> listStoragePoolsForMigrationOfVolume(final Long volumeId) { public Pair<List<? extends StoragePool>, List<? extends StoragePool>> listStoragePoolsForMigrationOfVolume(final Long volumeId) {
Pair<List<? extends StoragePool>, List<? extends StoragePool>> allPoolsAndSuitablePoolsPair = listStoragePoolsForMigrationOfVolumeInternal(volumeId, null, null, null, null, false, true); Pair<List<? extends StoragePool>, List<? extends StoragePool>> allPoolsAndSuitablePoolsPair = listStoragePoolsForMigrationOfVolumeInternal(volumeId, null, null, null, null, false, true, false);
List<? extends StoragePool> allPools = allPoolsAndSuitablePoolsPair.first(); List<? extends StoragePool> allPools = allPoolsAndSuitablePoolsPair.first();
List<? extends StoragePool> suitablePools = allPoolsAndSuitablePoolsPair.second(); List<? extends StoragePool> suitablePools = allPoolsAndSuitablePoolsPair.second();
List<StoragePool> avoidPools = new ArrayList<>(); List<StoragePool> avoidPools = new ArrayList<>();
@ -1568,7 +1568,13 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
return new Pair<List<? extends StoragePool>, List<? extends StoragePool>>(allPools, suitablePools); return new Pair<List<? extends StoragePool>, List<? extends StoragePool>>(allPools, suitablePools);
} }
public Pair<List<? extends StoragePool>, List<? extends StoragePool>> listStoragePoolsForMigrationOfVolumeInternal(final Long volumeId, Long newDiskOfferingId, Long newSize, Long newMinIops, Long newMaxIops, boolean keepSourceStoragePool, boolean bypassStorageTypeCheck) { @Override
public Pair<List<? extends StoragePool>, List<? extends StoragePool>> listStoragePoolsForSystemMigrationOfVolume(final Long volumeId, Long newDiskOfferingId, Long newSize, Long newMinIops, Long newMaxIops, boolean keepSourceStoragePool, boolean bypassStorageTypeCheck) {
return listStoragePoolsForMigrationOfVolumeInternal(volumeId, newDiskOfferingId, newSize, newMinIops, newMaxIops, keepSourceStoragePool, bypassStorageTypeCheck, true);
}
public Pair<List<? extends StoragePool>, List<? extends StoragePool>> listStoragePoolsForMigrationOfVolumeInternal(final Long volumeId, Long newDiskOfferingId, Long newSize, Long newMinIops, Long newMaxIops, boolean keepSourceStoragePool, boolean bypassStorageTypeCheck, boolean bypassAccountCheck) {
if (!bypassAccountCheck) {
final Account caller = getCaller(); final Account caller = getCaller();
if (!_accountMgr.isRootAdmin(caller.getId())) { if (!_accountMgr.isRootAdmin(caller.getId())) {
if (s_logger.isDebugEnabled()) { if (s_logger.isDebugEnabled()) {
@ -1576,6 +1582,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
} }
throw new PermissionDeniedException("No permission to migrate volume, only root admin can migrate a volume"); throw new PermissionDeniedException("No permission to migrate volume, only root admin can migrate a volume");
} }
}
final VolumeVO volume = _volumeDao.findById(volumeId); final VolumeVO volume = _volumeDao.findById(volumeId);
if (volume == null) { if (volume == null) {

View File

@ -96,6 +96,7 @@ import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToSt
import org.apache.cloudstack.utils.volume.VirtualMachineDiskInfo; import org.apache.cloudstack.utils.volume.VirtualMachineDiskInfo;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils; import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.commons.lang3.builder.ToStringStyle;
@ -1803,14 +1804,14 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
return volume; return volume;
} }
if (currentSize != newSize || newMaxIops != volume.getMaxIops() || newMinIops != volume.getMinIops()) { if (currentSize != newSize || !compareEqualsIncludingNullOrZero(newMaxIops, volume.getMaxIops()) || !compareEqualsIncludingNullOrZero(newMinIops, volume.getMinIops())) {
volumeResizeRequired = true; volumeResizeRequired = true;
validateVolumeReadyStateAndHypervisorChecks(volume, currentSize, newSize); validateVolumeReadyStateAndHypervisorChecks(volume, currentSize, newSize);
} }
StoragePoolVO existingStoragePool = _storagePoolDao.findById(volume.getPoolId()); StoragePoolVO existingStoragePool = _storagePoolDao.findById(volume.getPoolId());
Pair<List<? extends StoragePool>, List<? extends StoragePool>> poolsPair = managementService.listStoragePoolsForMigrationOfVolumeInternal(volume.getId(), newDiskOffering.getId(), newSize, newMinIops, newMaxIops, true, false); Pair<List<? extends StoragePool>, List<? extends StoragePool>> poolsPair = managementService.listStoragePoolsForSystemMigrationOfVolume(volume.getId(), newDiskOffering.getId(), newSize, newMinIops, newMaxIops, true, false);
List<? extends StoragePool> suitableStoragePools = poolsPair.second(); List<? extends StoragePool> suitableStoragePools = poolsPair.second();
if (!suitableStoragePools.stream().anyMatch(p -> (p.getId() == existingStoragePool.getId()))) { if (!suitableStoragePools.stream().anyMatch(p -> (p.getId() == existingStoragePool.getId()))) {
@ -1859,6 +1860,21 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
return volume; return volume;
} }
/**
* This method is to compare long values, in miniops and maxiops a or b can be null or 0.
* Use this method to treat 0 and null as same
*
* @param a
* @param b
* @return true if a and b are equal excluding 0 and null values.
*/
private boolean compareEqualsIncludingNullOrZero(Long a, Long b) {
a = ObjectUtils.defaultIfNull(a, 0L);
b = ObjectUtils.defaultIfNull(b, 0L);
return a.equals(b);
}
/** /**
* Returns true if the new disk offering is the same than current offering, and the respective Service offering is a custom (constraint or unconstraint) offering. * Returns true if the new disk offering is the same than current offering, and the respective Service offering is a custom (constraint or unconstraint) offering.
*/ */

View File

@ -318,8 +318,10 @@ public class TaggedResourceManagerImpl extends ManagerBase implements TaggedReso
private void informStoragePoolForVmTags(long vmId, String key, String value) { private void informStoragePoolForVmTags(long vmId, String key, String value) {
List<VolumeVO> volumeVos = volumeDao.findByInstance(vmId); List<VolumeVO> volumeVos = volumeDao.findByInstance(vmId);
for (VolumeVO volume : volumeVos) { for (VolumeVO volume : volumeVos) {
DataStore dataStore = dataStoreMgr.getDataStore(volume.getPoolId(), DataStoreRole.Primary); Long poolId = volume.getPoolId();
DataStore dataStore = retrieveDatastore(poolId);
if (dataStore == null || !(dataStore.getDriver() instanceof PrimaryDataStoreDriver)) { if (dataStore == null || !(dataStore.getDriver() instanceof PrimaryDataStoreDriver)) {
s_logger.info(String.format("No data store found for VM %d with pool ID %d.", vmId, poolId));
continue; continue;
} }
PrimaryDataStoreDriver dataStoreDriver = (PrimaryDataStoreDriver) dataStore.getDriver(); PrimaryDataStoreDriver dataStoreDriver = (PrimaryDataStoreDriver) dataStore.getDriver();
@ -328,4 +330,11 @@ public class TaggedResourceManagerImpl extends ManagerBase implements TaggedReso
} }
} }
} }
protected DataStore retrieveDatastore(Long poolId) {
if (poolId == null) {
return null;
}
return dataStoreMgr.getDataStore(poolId, DataStoreRole.Primary);
}
} }

View File

@ -47,9 +47,12 @@ import com.cloud.utils.Pair;
*/ */
public interface UserVmManager extends UserVmService { public interface UserVmManager extends UserVmService {
String EnableDynamicallyScaleVmCK = "enable.dynamic.scale.vm"; String EnableDynamicallyScaleVmCK = "enable.dynamic.scale.vm";
String AllowDiskOfferingChangeDuringScaleVmCK = "allow.diskoffering.change.during.scale.vm";
String AllowUserExpungeRecoverVmCK ="allow.user.expunge.recover.vm"; String AllowUserExpungeRecoverVmCK ="allow.user.expunge.recover.vm";
ConfigKey<Boolean> EnableDynamicallyScaleVm = new ConfigKey<Boolean>("Advanced", Boolean.class, EnableDynamicallyScaleVmCK, "false", ConfigKey<Boolean> EnableDynamicallyScaleVm = new ConfigKey<Boolean>("Advanced", Boolean.class, EnableDynamicallyScaleVmCK, "false",
"Enables/Disables dynamically scaling a vm", true, ConfigKey.Scope.Zone); "Enables/Disables dynamically scaling a vm", true, ConfigKey.Scope.Zone);
ConfigKey<Boolean> AllowDiskOfferingChangeDuringScaleVm = new ConfigKey<Boolean>("Advanced", Boolean.class, AllowDiskOfferingChangeDuringScaleVmCK, "false",
"Determines whether to allow or disallow disk offering change for root volume during scaling of a stopped or running vm", true, ConfigKey.Scope.Zone);
ConfigKey<Boolean> AllowUserExpungeRecoverVm = new ConfigKey<Boolean>("Advanced", Boolean.class, AllowUserExpungeRecoverVmCK, "false", ConfigKey<Boolean> AllowUserExpungeRecoverVm = new ConfigKey<Boolean>("Advanced", Boolean.class, AllowUserExpungeRecoverVmCK, "false",
"Determines whether users can expunge or recover their vm", true, ConfigKey.Scope.Account); "Determines whether users can expunge or recover their vm", true, ConfigKey.Scope.Account);
ConfigKey<Boolean> DisplayVMOVFProperties = new ConfigKey<Boolean>("Advanced", Boolean.class, "vm.display.ovf.properties", "false", ConfigKey<Boolean> DisplayVMOVFProperties = new ConfigKey<Boolean>("Advanced", Boolean.class, "vm.display.ovf.properties", "false",

View File

@ -1296,7 +1296,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
// resize and migrate the root volume if required // resize and migrate the root volume if required
DiskOfferingVO newDiskOffering = _diskOfferingDao.findById(newServiceOffering.getDiskOfferingId()); DiskOfferingVO newDiskOffering = _diskOfferingDao.findById(newServiceOffering.getDiskOfferingId());
changeDiskOfferingForRootVolume(vmId, newDiskOffering, customParameters); changeDiskOfferingForRootVolume(vmId, newDiskOffering, customParameters, vmInstance.getDataCenterId());
_itMgr.upgradeVmDb(vmId, newServiceOffering, currentServiceOffering); _itMgr.upgradeVmDb(vmId, newServiceOffering, currentServiceOffering);
@ -2066,7 +2066,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
// #3 resize or migrate the root volume if required // #3 resize or migrate the root volume if required
DiskOfferingVO newDiskOffering = _diskOfferingDao.findById(newServiceOffering.getDiskOfferingId()); DiskOfferingVO newDiskOffering = _diskOfferingDao.findById(newServiceOffering.getDiskOfferingId());
changeDiskOfferingForRootVolume(vmId, newDiskOffering, customParameters); changeDiskOfferingForRootVolume(vmId, newDiskOffering, customParameters, vmInstance.getDataCenterId());
// #4 scale the vm now // #4 scale the vm now
vmInstance = _vmInstanceDao.findById(vmId); vmInstance = _vmInstanceDao.findById(vmId);
@ -2109,7 +2109,14 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
} }
} }
private void changeDiskOfferingForRootVolume(Long vmId, DiskOfferingVO newDiskOffering, Map<String, String> customParameters) throws ResourceAllocationException { private void changeDiskOfferingForRootVolume(Long vmId, DiskOfferingVO newDiskOffering, Map<String, String> customParameters, Long zoneId) throws ResourceAllocationException {
if (!AllowDiskOfferingChangeDuringScaleVm.valueIn(zoneId)) {
if (s_logger.isDebugEnabled()) {
s_logger.debug(String.format("Changing the disk offering of the root volume during the compute offering change operation is disabled. Please check the setting [%s].", AllowDiskOfferingChangeDuringScaleVm.key()));
}
return;
}
List<VolumeVO> vols = _volsDao.findReadyAndAllocatedRootVolumesByInstance(vmId); List<VolumeVO> vols = _volsDao.findReadyAndAllocatedRootVolumesByInstance(vmId);
@ -7985,7 +7992,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
@Override @Override
public ConfigKey<?>[] getConfigKeys() { public ConfigKey<?>[] getConfigKeys() {
return new ConfigKey<?>[] {EnableDynamicallyScaleVm, AllowUserExpungeRecoverVm, VmIpFetchWaitInterval, VmIpFetchTrialMax, return new ConfigKey<?>[] {EnableDynamicallyScaleVm, AllowDiskOfferingChangeDuringScaleVm, AllowUserExpungeRecoverVm, VmIpFetchWaitInterval, VmIpFetchTrialMax,
VmIpFetchThreadPoolMax, VmIpFetchTaskWorkers, AllowDeployVmIfGivenHostFails, EnableAdditionalVmConfig, DisplayVMOVFProperties, VmIpFetchThreadPoolMax, VmIpFetchTaskWorkers, AllowDeployVmIfGivenHostFails, EnableAdditionalVmConfig, DisplayVMOVFProperties,
KvmAdditionalConfigAllowList, XenServerAdditionalConfigAllowList, VmwareAdditionalConfigAllowList}; KvmAdditionalConfigAllowList, XenServerAdditionalConfigAllowList, VmwareAdditionalConfigAllowList};
} }

View File

@ -794,7 +794,7 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
continue; continue;
} }
LOGGER.debug(String.format("Volume %s needs to be migrated", volumeVO.getUuid())); LOGGER.debug(String.format("Volume %s needs to be migrated", volumeVO.getUuid()));
Pair<List<? extends StoragePool>, List<? extends StoragePool>> poolsPair = managementService.listStoragePoolsForMigrationOfVolumeInternal(profile.getVolumeId(), null, null, null, null, false, true); Pair<List<? extends StoragePool>, List<? extends StoragePool>> poolsPair = managementService.listStoragePoolsForSystemMigrationOfVolume(profile.getVolumeId(), null, null, null, null, false, true);
if (CollectionUtils.isEmpty(poolsPair.first()) && CollectionUtils.isEmpty(poolsPair.second())) { if (CollectionUtils.isEmpty(poolsPair.first()) && CollectionUtils.isEmpty(poolsPair.second())) {
cleanupFailedImportVM(vm); cleanupFailedImportVM(vm);
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("VM import failed for unmanaged vm: %s during volume ID: %s migration as no suitable pool(s) found", userVm.getInstanceName(), volumeVO.getUuid())); throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("VM import failed for unmanaged vm: %s during volume ID: %s migration as no suitable pool(s) found", userVm.getInstanceName(), volumeVO.getUuid()));

View File

@ -25,6 +25,7 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@ -123,4 +124,10 @@ public class TaggedResourceManagerImplTest extends TestCase {
Mockito.doThrow(PermissionDeniedException.class).when(accountManager).checkAccess(caller, null, false, owner); Mockito.doThrow(PermissionDeniedException.class).when(accountManager).checkAccess(caller, null, false, owner);
taggedResourceManagerImplSpy.checkTagsDeletePermission(List.of(resourceTag1, resourceTag2), caller); taggedResourceManagerImplSpy.checkTagsDeletePermission(List.of(resourceTag1, resourceTag2), caller);
} }
@Test
public void testRetrieveDataStoreNullPoolId() {
DataStore dataStore = taggedResourceManagerImplSpy.retrieveDatastore(null);
Assert.assertNull(dataStore);
}
} }

View File

@ -1002,7 +1002,7 @@ class CsRemoteAccessVpn(CsDataBag):
secret = CsFile(vpnsecretfilte) secret = CsFile(vpnsecretfilte)
secret.empty() secret.empty()
secret.addeq("%s : PSK \"%s\"" % (left, psk)) secret.addeq(": PSK \"%s\"" % (psk))
secret.commit() secret.commit()
xl2tpdconf = CsFile(xl2tpdconffile) xl2tpdconf = CsFile(xl2tpdconffile)

View File

@ -25,10 +25,13 @@ from marvin.lib.base import (Account,
Host, Host,
VirtualMachine, VirtualMachine,
ServiceOffering, ServiceOffering,
DiskOffering,
Template, Template,
Configurations) Configurations,
Volume)
from marvin.lib.common import (get_zone, from marvin.lib.common import (get_zone,
get_template, get_template,
get_test_template,
get_domain) get_domain)
from nose.plugins.attrib import attr from nose.plugins.attrib import attr
from marvin.sshClient import SshClient from marvin.sshClient import SshClient
@ -54,7 +57,7 @@ class TestScaleVm(cloudstackTestCase):
return return
# Get Zone, Domain and templates # Get Zone, Domain and templates
domain = get_domain(cls.apiclient) cls.domain = get_domain(cls.apiclient)
cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests()) cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
cls.services['mode'] = cls.zone.networktype cls.services['mode'] = cls.zone.networktype
@ -73,14 +76,19 @@ class TestScaleVm(cloudstackTestCase):
isdynamicallyscalable='true' isdynamicallyscalable='true'
) )
else: else:
cls.template = Template.register( cls.template = get_test_template(
cls.apiclient, cls.apiclient,
cls.services["CentOS7template"], cls.zone.id,
zoneid=cls.zone.id cls.hypervisor
)
if cls.template == FAILED:
assert False, "get_test_template() failed to return template\
with hypervisor %s" % cls.hypervisor
cls.template = Template.update(
cls.template,
cls.apiclient,
isdynamicallyscalable='true'
) )
cls._cleanup.append(cls.template)
cls.template.download(cls.apiclient)
time.sleep(60)
# Set Zones and disk offerings # Set Zones and disk offerings
cls.services["small"]["zoneid"] = cls.zone.id cls.services["small"]["zoneid"] = cls.zone.id
@ -90,7 +98,7 @@ class TestScaleVm(cloudstackTestCase):
cls.account = Account.create( cls.account = Account.create(
cls.apiclient, cls.apiclient,
cls.services["account"], cls.services["account"],
domainid=domain.id domainid=cls.domain.id
) )
cls._cleanup.append(cls.account) cls._cleanup.append(cls.account)
@ -124,37 +132,6 @@ class TestScaleVm(cloudstackTestCase):
dynamicscalingenabled=False dynamicscalingenabled=False
) )
# create a virtual machine
cls.virtual_machine = VirtualMachine.create(
cls.apiclient,
cls.services["small"],
accountid=cls.account.name,
domainid=cls.account.domainid,
serviceofferingid=cls.small_offering.id,
mode=cls.services["mode"]
)
# create a virtual machine which cannot be dynamically scalable
cls.virtual_machine_with_service_offering_dynamic_scaling_disabled = VirtualMachine.create(
cls.apiclient,
cls.services["small"],
accountid=cls.account.name,
domainid=cls.account.domainid,
serviceofferingid=cls.small_offering_dynamic_scaling_disabled.id,
mode=cls.services["mode"]
)
# create a virtual machine which cannot be dynamically scalable
cls.virtual_machine_not_dynamically_scalable = VirtualMachine.create(
cls.apiclient,
cls.services["small"],
accountid=cls.account.name,
domainid=cls.account.domainid,
serviceofferingid=cls.small_offering.id,
mode=cls.services["mode"],
dynamicscalingenabled=False
)
cls._cleanup = [ cls._cleanup = [
cls.small_offering, cls.small_offering,
cls.big_offering, cls.big_offering,
@ -170,6 +147,11 @@ class TestScaleVm(cloudstackTestCase):
name="enable.dynamic.scale.vm", name="enable.dynamic.scale.vm",
value="false" value="false"
) )
Configurations.update(
cls.apiclient,
name="allow.diskOffering.change.during.scale.vm",
value="false"
)
super(TestScaleVm,cls).tearDownClass() super(TestScaleVm,cls).tearDownClass()
return return
@ -177,6 +159,7 @@ class TestScaleVm(cloudstackTestCase):
self.apiclient = self.testClient.getApiClient() self.apiclient = self.testClient.getApiClient()
self.dbclient = self.testClient.getDbConnection() self.dbclient = self.testClient.getDbConnection()
self.cleanup = [] self.cleanup = []
self.services["disk_offering"]["disksize"] = 2
if self.unsupportedHypervisor: if self.unsupportedHypervisor:
self.skipTest("Skipping test because unsupported hypervisor\ self.skipTest("Skipping test because unsupported hypervisor\
@ -199,6 +182,9 @@ class TestScaleVm(cloudstackTestCase):
return ssh_client return ssh_client
def is_host_xcpng8(self, hostname):
return type(hostname) == list and len(hostname) > 0 and 'XCP-ng 8' in hostname[0]
@attr(hypervisor="xenserver") @attr(hypervisor="xenserver")
@attr(tags=["advanced", "basic"], required_hardware="false") @attr(tags=["advanced", "basic"], required_hardware="false")
def test_01_scale_vm(self): def test_01_scale_vm(self):
@ -216,6 +202,17 @@ class TestScaleVm(cloudstackTestCase):
# scaling is not # scaling is not
# guaranteed until tools are installed, vm rebooted # guaranteed until tools are installed, vm rebooted
# create a virtual machine
self.virtual_machine = VirtualMachine.create(
self.apiclient,
self.services["small"],
accountid=self.account.name,
domainid=self.account.domainid,
serviceofferingid=self.small_offering.id,
mode=self.services["mode"]
)
self.cleanup.append(self.virtual_machine)
# If hypervisor is Vmware, then check if # If hypervisor is Vmware, then check if
# the vmware tools are installed and the process is running # the vmware tools are installed and the process is running
# Vmware tools are necessary for scale VM operation # Vmware tools are necessary for scale VM operation
@ -227,6 +224,7 @@ class TestScaleVm(cloudstackTestCase):
if not "running" in result: if not "running" in result:
self.skipTest("Skipping scale VM operation because\ self.skipTest("Skipping scale VM operation because\
VMware tools are not installed on the VM") VMware tools are not installed on the VM")
res = None
if self.hypervisor.lower() != 'simulator': if self.hypervisor.lower() != 'simulator':
hostid = self.virtual_machine.hostid hostid = self.virtual_machine.hostid
host = Host.list( host = Host.list(
@ -251,14 +249,27 @@ class TestScaleVm(cloudstackTestCase):
self.apiclient, self.apiclient,
isdynamicallyscalable='true') isdynamicallyscalable='true')
if self.is_host_xcpng8(res):
self.debug("Only scaling for CPU for XCP-ng 8")
offering_data = self.services["service_offerings"]["big"]
offering_data["cpunumber"] = 2
offering_data["memory"] = self.virtual_machine.memory
self.bigger_offering = ServiceOffering.create(
self.apiclient,
offering_data
)
self.cleanup.append(self.bigger_offering)
else:
self.bigger_offering = self.big_offering
self.debug("Scaling VM-ID: %s to service offering: %s and state %s" % ( self.debug("Scaling VM-ID: %s to service offering: %s and state %s" % (
self.virtual_machine.id, self.virtual_machine.id,
self.big_offering.id, self.bigger_offering.id,
self.virtual_machine.state self.virtual_machine.state
)) ))
cmd = scaleVirtualMachine.scaleVirtualMachineCmd() cmd = scaleVirtualMachine.scaleVirtualMachineCmd()
cmd.serviceofferingid = self.big_offering.id cmd.serviceofferingid = self.bigger_offering.id
cmd.id = self.virtual_machine.id cmd.id = self.virtual_machine.id
try: try:
@ -297,11 +308,11 @@ class TestScaleVm(cloudstackTestCase):
offering %s and the response says %s" % offering %s and the response says %s" %
(self.virtual_machine.id, (self.virtual_machine.id,
self.virtual_machine.serviceofferingid, self.virtual_machine.serviceofferingid,
self.big_offering.id, self.bigger_offering.id,
vm_response.serviceofferingid)) vm_response.serviceofferingid))
self.assertEqual( self.assertEqual(
vm_response.serviceofferingid, vm_response.serviceofferingid,
self.big_offering.id, self.bigger_offering.id,
"Check service offering of the VM" "Check service offering of the VM"
) )
@ -313,7 +324,7 @@ class TestScaleVm(cloudstackTestCase):
return return
@attr(tags=["advanced", "basic"], required_hardware="false") @attr(tags=["advanced", "basic"], required_hardware="false")
def test_02_scale_vm(self): def test_02_scale_vm_negative_offering_disable_scaling(self):
"""Test scale virtual machine which is created from a service offering for which dynamicscalingenabled is false. Scaling operation should fail. """Test scale virtual machine which is created from a service offering for which dynamicscalingenabled is false. Scaling operation should fail.
""" """
@ -325,6 +336,17 @@ class TestScaleVm(cloudstackTestCase):
# scaling is not # scaling is not
# guaranteed until tools are installed, vm rebooted # guaranteed until tools are installed, vm rebooted
# create a virtual machine which cannot be dynamically scalable
self.virtual_machine_with_service_offering_dynamic_scaling_disabled = VirtualMachine.create(
self.apiclient,
self.services["small"],
accountid=self.account.name,
domainid=self.account.domainid,
serviceofferingid=self.small_offering_dynamic_scaling_disabled.id,
mode=self.services["mode"]
)
self.cleanup.append(self.virtual_machine_with_service_offering_dynamic_scaling_disabled)
# If hypervisor is Vmware, then check if # If hypervisor is Vmware, then check if
# the vmware tools are installed and the process is running # the vmware tools are installed and the process is running
# Vmware tools are necessary for scale VM operation # Vmware tools are necessary for scale VM operation
@ -368,7 +390,7 @@ class TestScaleVm(cloudstackTestCase):
self.debug("Scaling VM-ID: %s to service offering: %s for which dynamic scaling is disabled and VM state %s" % ( self.debug("Scaling VM-ID: %s to service offering: %s for which dynamic scaling is disabled and VM state %s" % (
self.virtual_machine_with_service_offering_dynamic_scaling_disabled.id, self.virtual_machine_with_service_offering_dynamic_scaling_disabled.id,
self.big_offering_dynamic_scaling_disabled.id, self.big_offering_dynamic_scaling_disabled.id,
self.virtual_machine.state self.virtual_machine_with_service_offering_dynamic_scaling_disabled.state
)) ))
cmd = scaleVirtualMachine.scaleVirtualMachineCmd() cmd = scaleVirtualMachine.scaleVirtualMachineCmd()
@ -388,7 +410,7 @@ class TestScaleVm(cloudstackTestCase):
self.debug("Scaling VM-ID: %s to service offering: %s for which dynamic scaling is enabled and VM state %s" % ( self.debug("Scaling VM-ID: %s to service offering: %s for which dynamic scaling is enabled and VM state %s" % (
self.virtual_machine_with_service_offering_dynamic_scaling_disabled.id, self.virtual_machine_with_service_offering_dynamic_scaling_disabled.id,
self.big_offering.id, self.big_offering.id,
self.virtual_machine.state self.virtual_machine_with_service_offering_dynamic_scaling_disabled.state
)) ))
cmd = scaleVirtualMachine.scaleVirtualMachineCmd() cmd = scaleVirtualMachine.scaleVirtualMachineCmd()
@ -408,7 +430,7 @@ class TestScaleVm(cloudstackTestCase):
return return
@attr(tags=["advanced", "basic"], required_hardware="false") @attr(tags=["advanced", "basic"], required_hardware="false")
def test_03_scale_vm(self): def test_03_scale_vm_negative_vm_disable_scaling(self):
"""Test scale virtual machine which is not dynamically scalable to a service offering. Scaling operation should fail. """Test scale virtual machine which is not dynamically scalable to a service offering. Scaling operation should fail.
""" """
# Validate the following # Validate the following
@ -422,6 +444,18 @@ class TestScaleVm(cloudstackTestCase):
# scaling is not # scaling is not
# guaranteed until tools are installed, vm rebooted # guaranteed until tools are installed, vm rebooted
# create a virtual machine which cannot be dynamically scalable
self.virtual_machine_not_dynamically_scalable = VirtualMachine.create(
self.apiclient,
self.services["small"],
accountid=self.account.name,
domainid=self.account.domainid,
serviceofferingid=self.small_offering.id,
mode=self.services["mode"],
dynamicscalingenabled=False
)
self.cleanup.append(self.virtual_machine_not_dynamically_scalable)
# If hypervisor is Vmware, then check if # If hypervisor is Vmware, then check if
# the vmware tools are installed and the process is running # the vmware tools are installed and the process is running
# Vmware tools are necessary for scale VM operation # Vmware tools are necessary for scale VM operation
@ -463,7 +497,7 @@ class TestScaleVm(cloudstackTestCase):
self.debug("Scaling VM-ID: %s to service offering: %s for which dynamic scaling is enabled and VM state %s" % ( self.debug("Scaling VM-ID: %s to service offering: %s for which dynamic scaling is enabled and VM state %s" % (
self.virtual_machine_not_dynamically_scalable.id, self.virtual_machine_not_dynamically_scalable.id,
self.big_offering.id, self.big_offering.id,
self.virtual_machine.state self.virtual_machine_not_dynamically_scalable.state
)) ))
cmd = scaleVirtualMachine.scaleVirtualMachineCmd() cmd = scaleVirtualMachine.scaleVirtualMachineCmd()
@ -481,3 +515,386 @@ class TestScaleVm(cloudstackTestCase):
self.fail("Expected an exception to be thrown, failing") self.fail("Expected an exception to be thrown, failing")
return return
@attr(hypervisor="xenserver")
@attr(tags=["advanced", "basic"], required_hardware="false")
def test_04_scale_vm_with_user_account(self):
"""Test scale virtual machine under useraccount
"""
# Validate the following
# Create a user Account and create a VM in it.
# Scale up the vm and see if it scales to the new svc offering
# Create an user account
self.userAccount = Account.create(
self.apiclient,
self.services["account"],
admin=False,
domainid=self.domain.id
)
self.cleanup.append(self.userAccount)
# Create user api client of the user account
self.userapiclient = self.testClient.getUserApiClient(
UserName=self.userAccount.name,
DomainName=self.userAccount.domain
)
# create a virtual machine
self.virtual_machine_in_user_account = VirtualMachine.create(
self.userapiclient,
self.services["small"],
accountid=self.userAccount.name,
domainid=self.userAccount.domainid,
serviceofferingid=self.small_offering.id,
mode=self.services["mode"]
)
if self.hypervisor.lower() == "vmware":
sshClient = self.virtual_machine_in_user_account.get_ssh_client()
result = str(
sshClient.execute("service vmware-tools status")).lower()
self.debug("and result is: %s" % result)
if not "running" in result:
self.skipTest("Skipping scale VM operation because\
VMware tools are not installed on the VM")
res = None
if self.hypervisor.lower() != 'simulator':
list_vm_response = VirtualMachine.list(
self.apiclient,
id=self.virtual_machine_in_user_account.id
)[0]
hostid = list_vm_response.hostid
host = Host.list(
self.apiclient,
zoneid=self.zone.id,
hostid=hostid,
type='Routing'
)[0]
try:
username = self.hostConfig["username"]
password = self.hostConfig["password"]
ssh_client = self.get_ssh_client(host.ipaddress, username, password)
res = ssh_client.execute("hostnamectl | grep 'Operating System' | cut -d':' -f2")
except Exception as e:
pass
if 'XenServer' in res[0]:
self.skipTest("Skipping test for XenServer as it's License does not allow scaling")
self.virtual_machine_in_user_account.update(
self.userapiclient,
isdynamicallyscalable='true')
if self.is_host_xcpng8(res):
self.debug("Only scaling for CPU for XCP-ng 8")
offering_data = self.services["service_offerings"]["big"]
offering_data["cpunumber"] = 2
offering_data["memory"] = self.virtual_machine_in_user_account.memory
self.bigger_offering = ServiceOffering.create(
self.apiclient,
offering_data
)
self.cleanup.append(self.bigger_offering)
else:
self.bigger_offering = self.big_offering
self.debug("Scaling VM-ID: %s to service offering: %s and state %s" % (
self.virtual_machine_in_user_account.id,
self.bigger_offering.id,
self.virtual_machine_in_user_account.state
))
cmd = scaleVirtualMachine.scaleVirtualMachineCmd()
cmd.serviceofferingid = self.bigger_offering.id
cmd.id = self.virtual_machine_in_user_account.id
try:
self.userapiclient.scaleVirtualMachine(cmd)
except Exception as e:
if "LicenceRestriction" in str(e):
self.skipTest("Your XenServer License does not allow scaling")
else:
self.fail("Scaling failed with the following exception: " + str(e))
list_vm_response = VirtualMachine.list(
self.userapiclient,
id=self.virtual_machine_in_user_account.id
)
vm_response = list_vm_response[0]
self.debug(
"Scaling VM-ID: %s from service offering: %s to new service\
offering %s and the response says %s" %
(self.virtual_machine_in_user_account.id,
self.virtual_machine_in_user_account.serviceofferingid,
self.bigger_offering.id,
vm_response.serviceofferingid))
self.assertEqual(
vm_response.serviceofferingid,
self.bigger_offering.id,
"Check service offering of the VM"
)
self.assertEqual(
vm_response.state,
'Running',
"Check the state of VM"
)
return
@attr(hypervisor="xenserver")
@attr(tags=["advanced", "basic"], required_hardware="false")
def test_05_scale_vm_dont_allow_disk_offering_change(self):
"""Test scale virtual machine with disk offering changes
"""
# Validate the following two cases
# 1
# create serviceoffering1 with diskoffering1
# create serviceoffering2 with diskoffering2
# create a VM with serviceoffering1
# Scale up the vm to serviceoffering2
# Check disk offering of root volume to be diskoffering1 since setting allow.diskOffering.change.during.scale.vm is false
# 2
# create serviceoffering3 with diskoffering3
# update setting allow.diskOffering.change.during.scale.vm to true
# scale up the VM to serviceoffering3
# Check disk offering of root volume to be diskoffering3 since setting allow.diskOffering.change.during.scale.vm is true
self.disk_offering1 = DiskOffering.create(
self.apiclient,
self.services["disk_offering"],
)
self._cleanup.append(self.disk_offering1)
offering_data = {
'displaytext': 'ServiceOffering1WithDiskOffering1',
'cpuspeed': 500,
'cpunumber': 1,
'name': 'ServiceOffering1WithDiskOffering1',
'memory': 512,
'diskofferingid': self.disk_offering1.id
}
self.ServiceOffering1WithDiskOffering1 = ServiceOffering.create(
self.apiclient,
offering_data,
)
self._cleanup.append(self.ServiceOffering1WithDiskOffering1)
# create a virtual machine
self.virtual_machine_test = VirtualMachine.create(
self.apiclient,
self.services["small"],
accountid=self.account.name,
domainid=self.account.domainid,
serviceofferingid=self.ServiceOffering1WithDiskOffering1.id,
mode=self.services["mode"]
)
if self.hypervisor.lower() == "vmware":
sshClient = self.virtual_machine_test.get_ssh_client()
result = str(
sshClient.execute("service vmware-tools status")).lower()
self.debug("and result is: %s" % result)
if not "running" in result:
self.skipTest("Skipping scale VM operation because\
VMware tools are not installed on the VM")
res = None
if self.hypervisor.lower() != 'simulator':
hostid = self.virtual_machine_test.hostid
host = Host.list(
self.apiclient,
zoneid=self.zone.id,
hostid=hostid,
type='Routing'
)[0]
try:
username = self.hostConfig["username"]
password = self.hostConfig["password"]
ssh_client = self.get_ssh_client(host.ipaddress, username, password)
res = ssh_client.execute("hostnamectl | grep 'Operating System' | cut -d':' -f2")
except Exception as e:
pass
if 'XenServer' in res[0]:
self.skipTest("Skipping test for XenServer as it's License does not allow scaling")
self.virtual_machine_test.update(
self.apiclient,
isdynamicallyscalable='true')
self.disk_offering2 = DiskOffering.create(
self.apiclient,
self.services["disk_offering"],
)
self._cleanup.append(self.disk_offering2)
offering_data = {
'displaytext': 'ServiceOffering2WithDiskOffering2',
'cpuspeed': 1000,
'cpunumber': 2,
'name': 'ServiceOffering2WithDiskOffering2',
'memory': 1024,
'diskofferingid': self.disk_offering2.id
}
if self.is_host_xcpng8(res):
self.debug("Only scaling for CPU for XCP-ng 8")
offering_data["memory"] = self.virtual_machine_test.memory
self.ServiceOffering2WithDiskOffering2 = ServiceOffering.create(
self.apiclient,
offering_data,
)
self._cleanup.append(self.ServiceOffering2WithDiskOffering2)
self.debug("Scaling VM-ID: %s to service offering: %s and state %s" % (
self.virtual_machine_test.id,
self.ServiceOffering2WithDiskOffering2.id,
self.virtual_machine_test.state
))
cmd = scaleVirtualMachine.scaleVirtualMachineCmd()
cmd.serviceofferingid = self.ServiceOffering2WithDiskOffering2.id
cmd.id = self.virtual_machine_test.id
try:
self.apiclient.scaleVirtualMachine(cmd)
except Exception as e:
if "LicenceRestriction" in str(e):
self.skipTest("Your XenServer License does not allow scaling")
else:
self.fail("Scaling failed with the following exception: " + str(e))
list_vm_response = VirtualMachine.list(
self.apiclient,
id=self.virtual_machine_test.id
)
vm_response = list_vm_response[0]
self.debug(
"Scaling VM-ID: %s from service offering: %s to new service\
offering %s and the response says %s" %
(self.virtual_machine_test.id,
self.virtual_machine_test.serviceofferingid,
self.ServiceOffering2WithDiskOffering2.id,
vm_response.serviceofferingid))
vm_response = list_vm_response[0]
self.assertEqual(
vm_response.serviceofferingid,
self.ServiceOffering2WithDiskOffering2.id,
"Check service offering of the VM"
)
volume_response = Volume.list(
self.apiclient,
virtualmachineid=self.virtual_machine_test.id,
listall=True
)[0]
self.assertEqual(
volume_response.diskofferingid,
self.disk_offering1.id,
"Check disk offering of the VM, this should not change since allow.diskOffering.change.during.scale.vm is false"
)
# Do same scale vm operation with allow.diskOffering.change.during.scale.vm value to true
if self.hypervisor.lower() in ['simulator']:
self.debug("Simulator doesn't support changing disk offering, volume resize")
return
disk_offering_data = self.services["disk_offering"]
if self.hypervisor.lower() in ['xenserver']:
self.debug("For hypervisor %s, do not resize volume and just change try to change the disk offering")
volume_response = Volume.list(
self.apiclient,
virtualmachineid=self.virtual_machine_test.id,
listall=True
)[0]
disk_offering_data["disksize"] = int(volume_response.size / (1024 ** 3))
self.disk_offering3 = DiskOffering.create(
self.apiclient,
disk_offering_data,
)
self._cleanup.append(self.disk_offering3)
offering_data = {
'displaytext': 'ServiceOffering3WithDiskOffering3',
'cpuspeed': 1500,
'cpunumber': 2,
'name': 'ServiceOffering3WithDiskOffering3',
'memory': 1024,
'diskofferingid': self.disk_offering3.id
}
if self.is_host_xcpng8(res):
self.debug("Only scaling for CPU for XCP-ng 8")
offering_data["memory"] = vm_response.memory
self.ServiceOffering3WithDiskOffering3 = ServiceOffering.create(
self.apiclient,
offering_data,
)
self._cleanup.append(self.ServiceOffering3WithDiskOffering3)
Configurations.update(
self.apiclient,
name="allow.diskOffering.change.during.scale.vm",
value="true"
)
self.debug("Scaling VM-ID: %s to service offering: %s and state %s" % (
self.virtual_machine_test.id,
self.ServiceOffering3WithDiskOffering3.id,
self.virtual_machine_test.state
))
cmd = scaleVirtualMachine.scaleVirtualMachineCmd()
cmd.serviceofferingid = self.ServiceOffering3WithDiskOffering3.id
cmd.id = self.virtual_machine_test.id
try:
self.apiclient.scaleVirtualMachine(cmd)
except Exception as e:
if "LicenceRestriction" in str(e):
self.skipTest("Your XenServer License does not allow scaling")
else:
self.fail("Scaling failed with the following exception: " + str(e))
list_vm_response = VirtualMachine.list(
self.apiclient,
id=self.virtual_machine_test.id
)
vm_response = list_vm_response[0]
self.debug(
"Scaling VM-ID: %s from service offering: %s to new service\
offering %s and the response says %s" %
(self.virtual_machine_test.id,
self.virtual_machine_test.serviceofferingid,
self.ServiceOffering3WithDiskOffering3.id,
vm_response.serviceofferingid))
self.assertEqual(
vm_response.serviceofferingid,
self.ServiceOffering3WithDiskOffering3.id,
"Check service offering of the VM"
)
volume_response = Volume.list(
self.apiclient,
virtualmachineid=self.virtual_machine_test.id,
listall=True
)[0]
self.assertEqual(
volume_response.diskofferingid,
self.disk_offering3.id,
"Check disk offering of the VM, this should change since allow.diskOffering.change.during.scale.vm is true"
)
return

View File

@ -103,7 +103,8 @@ export default {
wrapperCol: { span: 12 } wrapperCol: { span: 12 }
}, },
validStatus: '', validStatus: '',
validMessage: '' validMessage: '',
formModel: {}
} }
}, },
watch: { watch: {