Skip to content
Next Next commit
ScaleIO/PowerFlex smoke tests improvements, and some fixes
  • Loading branch information
sureshanaparti committed Sep 9, 2025
commit 8c2c89001533c9f3c1aff2767daa6a1f5230f440
Original file line number Diff line number Diff line change
Expand Up @@ -3087,7 +3087,7 @@ public int compare(final DiskTO arg0, final DiskTO arg1) {
}

if (vmSpec.getOs().toLowerCase().contains("window")) {
isWindowsTemplate =true;
isWindowsTemplate = true;
}
for (final DiskTO volume : disks) {
KVMPhysicalDisk physicalDisk = null;
Expand Down Expand Up @@ -3206,6 +3206,9 @@ public int compare(final DiskTO arg0, final DiskTO arg1) {
disk.defNetworkBasedDisk(physicalDisk.getPath().replace("rbd:", ""), pool.getSourceHost(), pool.getSourcePort(), pool.getAuthUserName(),
pool.getUuid(), devId, diskBusType, DiskProtocol.RBD, DiskDef.DiskFmtType.RAW);
} else if (pool.getType() == StoragePoolType.PowerFlex) {
if (isWindowsTemplate && isUefiEnabled) {
diskBusTypeData = DiskDef.DiskBus.SATA;
}
disk.defBlockBasedDisk(physicalDisk.getPath(), devId, diskBusTypeData);
if (physicalDisk.getFormat().equals(PhysicalDiskFormat.QCOW2)) {
disk.setDiskFormatType(DiskDef.DiskFmtType.QCOW2);
Expand Down Expand Up @@ -3236,7 +3239,6 @@ public int compare(final DiskTO arg0, final DiskTO arg1) {
disk.defFileBasedDisk(physicalDisk.getPath(), devId, diskBusType, DiskDef.DiskFmtType.QCOW2);
}
}

}
pool.customizeLibvirtDiskDef(disk);
}
Expand Down Expand Up @@ -4513,6 +4515,14 @@ protected String getDiskPathFromDiskDef(DiskDef disk) {
return token[1];
}
} else if (token.length > 3) {
// for powerflex/scaleio, path = /dev/disk/by-id/emc-vol-2202eefc4692120f-540fd8fa00000003
if (token.length > 4 && StringUtils.isNotBlank(token[4]) && token[4].startsWith("emc-vol-")) {
final String[] emcVolToken = token[4].split("-");
if (emcVolToken.length == 4) {
return emcVolToken[3];
}
}

// for example, path = /mnt/pool_uuid/disk_path/
return token[3];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ public ListResponse<VmMetricsStatsResponse> searchForSystemVmMetricsStats(ListSy
@Override
public ListResponse<VolumeMetricsStatsResponse> searchForVolumeMetricsStats(ListVolumesUsageHistoryCmd cmd) {
Pair<List<VolumeVO>, Integer> volumeList = searchForVolumesInternal(cmd);
Map<Long,List<VolumeStatsVO>> volumeStatsList = searchForVolumeMetricsStatsInternal(cmd, volumeList.first());
Map<Long, List<VolumeStatsVO>> volumeStatsList = searchForVolumeMetricsStatsInternal(cmd, volumeList.first());
return createVolumeMetricsStatsResponse(volumeList, volumeStatsList);
}

Expand Down
2 changes: 1 addition & 1 deletion server/src/main/java/com/cloud/server/StatsCollector.java
Original file line number Diff line number Diff line change
Expand Up @@ -1459,7 +1459,7 @@ public void doInTransactionWithoutResult(TransactionStatus status) {
for (VmDiskStats vmDiskStat : vmDiskStats) {
VmDiskStatsEntry vmDiskStatEntry = (VmDiskStatsEntry)vmDiskStat;
SearchCriteria<VolumeVO> sc_volume = _volsDao.createSearchCriteria();
sc_volume.addAnd("path", SearchCriteria.Op.EQ, vmDiskStatEntry.getPath());
sc_volume.addAnd("path", SearchCriteria.Op.LIKE, vmDiskStatEntry.getPath() + "%");
Comment thread
weizhouapache marked this conversation as resolved.
List<VolumeVO> volumes = _volsDao.search(sc_volume, null);

if (CollectionUtils.isEmpty(volumes))
Expand Down
2 changes: 1 addition & 1 deletion server/src/main/java/com/cloud/vm/UserVmManagerImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -5860,7 +5860,7 @@ public void doInTransactionWithoutResult(TransactionStatus status) {

for (VmDiskStatsEntry vmDiskStat : vmDiskStats) {
SearchCriteria<VolumeVO> sc_volume = _volsDao.createSearchCriteria();
sc_volume.addAnd("path", SearchCriteria.Op.EQ, vmDiskStat.getPath());
sc_volume.addAnd("path", SearchCriteria.Op.LIKE, vmDiskStat.getPath() + "%");
List<VolumeVO> volumes = _volsDao.search(sc_volume, null);
if ((volumes == null) || (volumes.size() == 0)) {
break;
Expand Down
9 changes: 9 additions & 0 deletions test/integration/smoke/test_deploy_vm_root_resize.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
RESOURCE_PRIMARY_STORAGE
from nose.plugins.attrib import attr
from marvin.sshClient import SshClient
import math
import time
import re
from marvin.cloudstackAPI import updateTemplate,registerTemplate
Expand Down Expand Up @@ -276,6 +277,14 @@ def test_00_deploy_vm_root_resize(self):
self.assertNotEqual(res[2], INVALID_INPUT, "Invalid list VM "
"response")
rootvolume = list_volume_response[0]
list_volume_pool_response = list_storage_pools(
self.apiclient,
id=rootvolume.storageid
)
rootvolume_pool = list_volume_pool_response[0]
if rootvolume_pool.type.lower() == "powerflex":
newrootsize = (int(math.ceil(newrootsize / 8) * 8))

success = False
if rootvolume is not None and rootvolume.size == (newrootsize << 30):
success = True
Expand Down
40 changes: 34 additions & 6 deletions test/integration/smoke/test_restore_vm.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,13 @@
# under the License.
""" P1 tests for Scaling up Vm
"""

import math

# Import Local Modules
from marvin.cloudstackTestCase import cloudstackTestCase
from marvin.lib.base import (VirtualMachine, Volume, DiskOffering, ServiceOffering, Template)
from marvin.lib.common import (get_zone, get_domain)
from marvin.lib.common import (get_zone, get_domain, list_storage_pools)
from nose.plugins.attrib import attr

_multiprocess_shared_ = True
Expand Down Expand Up @@ -78,8 +81,13 @@ def test_01_restore_vm(self):
self._cleanup.append(virtual_machine)

old_root_vol = Volume.list(self.apiclient, virtualmachineid=virtual_machine.id)[0]
old_root_vol_pool_res = list_storage_pools(self.apiclient, id=old_root_vol.storageid)
old_root_vol_pool = old_root_vol_pool_res[0]
expected_old_root_vol_size = self.template_t1.size
if old_root_vol_pool.type.lower() == "powerflex":
expected_old_root_vol_size = (int(math.ceil((expected_old_root_vol_size / (1024 ** 3)) / 8) * 8)) * (1024 ** 3)
self.assertEqual(old_root_vol.state, 'Ready', "Volume should be in Ready state")
self.assertEqual(old_root_vol.size, self.template_t1.size, "Size of volume and template should match")
self.assertEqual(old_root_vol.size, expected_old_root_vol_size, "Size of volume and template should match")

virtual_machine.restore(self.apiclient, self.template_t2.id, expunge=True)

Expand All @@ -88,8 +96,13 @@ def test_01_restore_vm(self):
self.assertEqual(restored_vm.templateid, self.template_t2.id, "VM's template after restore is incorrect")

root_vol = Volume.list(self.apiclient, virtualmachineid=restored_vm.id)[0]
root_vol_pool_res = list_storage_pools(self.apiclient, id=root_vol.storageid)
root_vol_pool = root_vol_pool_res[0]
expected_root_vol_size = self.template_t2.size
if root_vol_pool.type.lower() == "powerflex":
expected_root_vol_size = (int(math.ceil((expected_root_vol_size / (1024 ** 3)) / 8) * 8)) * (1024 ** 3)
self.assertEqual(root_vol.state, 'Ready', "Volume should be in Ready state")
self.assertEqual(root_vol.size, self.template_t2.size, "Size of volume and template should match")
self.assertEqual(root_vol.size, expected_root_vol_size, "Size of volume and template should match")

old_root_vol = Volume.list(self.apiclient, id=old_root_vol.id)
self.assertEqual(old_root_vol, None, "Old volume should be deleted")
Expand All @@ -105,8 +118,13 @@ def test_02_restore_vm_with_disk_offering(self):
self._cleanup.append(virtual_machine)

old_root_vol = Volume.list(self.apiclient, virtualmachineid=virtual_machine.id)[0]
old_root_vol_pool_res = list_storage_pools(self.apiclient, id=old_root_vol.storageid)
old_root_vol_pool = old_root_vol_pool_res[0]
expected_old_root_vol_size = self.template_t1.size
if old_root_vol_pool.type.lower() == "powerflex":
expected_old_root_vol_size = (int(math.ceil((expected_old_root_vol_size / (1024 ** 3)) / 8) * 8)) * (1024 ** 3)
self.assertEqual(old_root_vol.state, 'Ready', "Volume should be in Ready state")
self.assertEqual(old_root_vol.size, self.template_t1.size, "Size of volume and template should match")
self.assertEqual(old_root_vol.size, expected_old_root_vol_size, "Size of volume and template should match")

virtual_machine.restore(self.apiclient, self.template_t2.id, self.disk_offering.id, expunge=True)

Expand All @@ -115,9 +133,14 @@ def test_02_restore_vm_with_disk_offering(self):
self.assertEqual(restored_vm.templateid, self.template_t2.id, "VM's template after restore is incorrect")

root_vol = Volume.list(self.apiclient, virtualmachineid=restored_vm.id)[0]
root_vol_pool_res = list_storage_pools(self.apiclient, id=root_vol.storageid)
root_vol_pool = root_vol_pool_res[0]
expected_root_vol_size = self.disk_offering.disksize
if root_vol_pool.type.lower() == "powerflex":
expected_root_vol_size = (int(math.ceil(expected_root_vol_size / 8) * 8))
self.assertEqual(root_vol.diskofferingid, self.disk_offering.id, "Disk offering id should match")
self.assertEqual(root_vol.state, 'Ready', "Volume should be in Ready state")
self.assertEqual(root_vol.size, self.disk_offering.disksize * 1024 * 1024 * 1024,
self.assertEqual(root_vol.size, expected_root_vol_size * 1024 * 1024 * 1024,
"Size of volume and disk offering should match")

old_root_vol = Volume.list(self.apiclient, id=old_root_vol.id)
Expand All @@ -134,8 +157,13 @@ def test_03_restore_vm_with_disk_offering_custom_size(self):
self._cleanup.append(virtual_machine)

old_root_vol = Volume.list(self.apiclient, virtualmachineid=virtual_machine.id)[0]
old_root_vol_pool_res = list_storage_pools(self.apiclient, id=old_root_vol.storageid)
old_root_vol_pool = old_root_vol_pool_res[0]
expected_old_root_vol_size = self.template_t1.size
if old_root_vol_pool.type.lower() == "powerflex":
expected_old_root_vol_size = (int(math.ceil((expected_old_root_vol_size / (1024 ** 3)) / 8) * 8)) * (1024 ** 3)
self.assertEqual(old_root_vol.state, 'Ready', "Volume should be in Ready state")
self.assertEqual(old_root_vol.size, self.template_t1.size, "Size of volume and template should match")
self.assertEqual(old_root_vol.size, expected_old_root_vol_size, "Size of volume and template should match")

virtual_machine.restore(self.apiclient, self.template_t2.id, self.disk_offering.id, rootdisksize=16)

Expand Down
52 changes: 43 additions & 9 deletions test/integration/smoke/test_snapshots.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@
from marvin.codes import FAILED
from nose.plugins.attrib import attr
from marvin.cloudstackTestCase import cloudstackTestCase
from marvin.cloudstackException import CloudstackAPIException
from marvin.lib.utils import (cleanup_resources,
is_snapshot_on_nfs,
is_snapshot_on_powerflex,
validateList)
from marvin.lib.base import (VirtualMachine,
Account,
Expand Down Expand Up @@ -146,10 +148,16 @@ def test_01_snapshot_root_disk(self):
type='ROOT',
listall=True
)
volume = volumes[0]
volume_pool_response = list_storage_pools(
self.apiclient,
id=volume.storageid
)
volume_pool = volume_pool_response[0]

snapshot = Snapshot.create(
self.apiclient,
volumes[0].id,
volume.id,
account=self.account.name,
domainid=self.account.domainid
)
Expand Down Expand Up @@ -209,6 +217,11 @@ def test_01_snapshot_root_disk(self):
"Check if backup_snap_id is not null"
)

if volume_pool.type.lower() == "powerflex":
self.assertTrue(is_snapshot_on_powerflex(
self.apiclient, self.dbclient, self.config, self.zone.id, snapshot.id))
return

self.assertTrue(is_snapshot_on_nfs(
self.apiclient, self.dbclient, self.config, self.zone.id, snapshot.id))
return
Expand Down Expand Up @@ -246,6 +259,11 @@ def test_02_list_snapshots_with_removed_data_store(self):
PASS,
"Invalid response returned for list volumes")
vol_uuid = vol_res[0].id
volume_pool_response = list_storage_pools(self.apiclient,
id=vol_res[0].storageid)
volume_pool = volume_pool_response[0]
if volume_pool.type.lower() != 'networkfilesystem':
self.skipTest("This test is not supported for volume created on storage pool type %s" % volume_pool.type)
clusters = list_clusters(
self.apiclient,
zoneid=self.zone.id
Expand Down Expand Up @@ -437,15 +455,16 @@ def setUpClass(cls):
)
cls._cleanup.append(cls.virtual_machine)

volumes =Volume.list(
volumes = Volume.list(
cls.userapiclient,
virtualmachineid=cls.virtual_machine.id,
type='ROOT',
listall=True
)
cls.volume = volumes[0]
cls.snapshot = Snapshot.create(
cls.userapiclient,
volumes[0].id,
cls.volume.id,
account=cls.account.name,
domainid=cls.account.domainid
)
Expand Down Expand Up @@ -475,13 +494,28 @@ def test_01_snapshot_to_volume(self):
"""Test creating volume from snapshot
"""
self.services['volume_from_snapshot']['zoneid'] = self.zone.id
self.volume_from_snap = Volume.create_from_snapshot(
self.userapiclient,
snapshot_id=self.snapshot.id,
services=self.services["volume_from_snapshot"],
account=self.account.name,
domainid=self.account.domainid
snapshot_volume_pool_response = list_storage_pools(
self.apiclient,
id=self.volume.storageid
)
snapshot_volume_pool = snapshot_volume_pool_response[0]
try:
self.volume_from_snap = Volume.create_from_snapshot(
self.userapiclient,
snapshot_id=self.snapshot.id,
services=self.services["volume_from_snapshot"],
account=self.account.name,
domainid=self.account.domainid
)
except CloudstackAPIException as cs:
self.debug(cs.errorMsg)
if snapshot_volume_pool.type.lower() == "powerflex":
self.assertTrue(
cs.errorMsg.find("Create volume from snapshot is not supported for PowerFlex volume snapshots") > 0,
msg="Other than unsupported error while creating volume from snapshot for volume on PowerFlex pool")
return
self.fail("Failed to create volume from snapshot: %s" % cs)

self.cleanup.append(self.volume_from_snap)

self.assertEqual(
Expand Down
27 changes: 23 additions & 4 deletions test/integration/smoke/test_usage.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
from marvin.lib.common import (get_zone,
get_domain,
get_suitable_test_template,
list_storage_pools,
find_storage_pool_type)


Expand Down Expand Up @@ -611,17 +612,17 @@ def test_01_volume_usage(self):
except Exception as e:
self.fail("Failed to stop instance: %s" % e)

volume_response = Volume.list(
data_volume_response = Volume.list(
self.apiclient,
virtualmachineid=self.virtual_machine.id,
type='DATADISK',
listall=True)
self.assertEqual(
isinstance(volume_response, list),
isinstance(data_volume_response, list),
True,
"Check for valid list volumes response"
)
data_volume = volume_response[0]
data_volume = data_volume_response[0]

# Detach data Disk
self.debug("Detaching volume ID: %s VM with ID: %s" % (
Expand Down Expand Up @@ -769,7 +770,25 @@ def test_01_volume_usage(self):
"Running",
"VM state should be running after deployment"
)
self.virtual_machine.attach_volume(self.apiclient,volume_uploaded)
root_volume_response = Volume.list(
self.apiclient,
virtualmachineid=self.virtual_machine.id,
type='ROOT',
listall=True)
root_volume = root_volume_response[0]
rool_volume_pool_response = list_storage_pools(
self.apiclient,
id=root_volume.storageid
)
rool_volume_pool = rool_volume_pool_response[0]
try:
self.virtual_machine.attach_volume(self.apiclient,volume_uploaded)
except Exception as e:
self.debug("Exception %s: " % e)
if rool_volume_pool.type.lower() == "powerflex" and "this operation is unsupported on storage pool type PowerFlex" in str(e):
return
self.fail(e)

self.debug("select type from usage_event where offering_id = 6 and volume_id = '%s';"
% volume_id)

Expand Down
Loading