Skip to content

Commit e92c825

Browse files
committed
support StorPool tags
add StorPool tags to a volume created from snapshot or to a volume which will be attached as a ROOT to a new VM
1 parent bbcc073 commit e92c825

File tree

6 files changed

+130
-6
lines changed

6 files changed

+130
-6
lines changed

engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@
5757
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
5858
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreDriver;
5959
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
60+
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider;
61+
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProviderManager;
6062
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStore;
6163
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver;
6264
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory;
@@ -272,6 +274,9 @@ public enum UserVmCloneType {
272274
@Inject
273275
protected SnapshotHelper snapshotHelper;
274276

277+
@Inject
278+
private DataStoreProviderManager dataStoreProviderMgr;
279+
275280
private final StateMachine2<Volume.State, Volume.Event, Volume> _volStateMachine;
276281
protected List<StoragePoolAllocator> _storagePoolAllocators;
277282

@@ -903,6 +908,7 @@ private DiskProfile allocateTemplatedVolume(Type type, String name, DiskOffering
903908

904909
if (volume != null) {
905910
volume = attachExistingVolumeToVm(vm, deviceId, volume, type);
911+
provideVmInfoToTheStorageVolume(vm, volume);
906912
return toDiskProfile(volume, offering);
907913
}
908914
Long size;
@@ -982,6 +988,19 @@ private DiskProfile allocateTemplatedVolume(Type type, String name, DiskOffering
982988
return toDiskProfile(vol, offering);
983989
}
984990

991+
private void provideVmInfoToTheStorageVolume(VirtualMachine vm, Volume volume) {
992+
993+
StoragePoolVO pool = _storagePoolDao.findById(volume.getPoolId());
994+
if (pool != null) {
995+
DataStoreProvider storeProvider = dataStoreProviderMgr
996+
.getDataStoreProvider(pool.getStorageProviderName());
997+
DataStoreDriver storeDriver = storeProvider.getDataStoreDriver();
998+
if (storeDriver != null && storeDriver instanceof PrimaryDataStoreDriver && ((PrimaryDataStoreDriver) storeDriver).isVmInfoNeeded()) {
999+
((PrimaryDataStoreDriver) storeDriver).provideVmInfo(vm.getId(), volume.getId());
1000+
}
1001+
}
1002+
}
1003+
9851004
private Volume attachExistingVolumeToVm(VirtualMachine vm, long deviceId, Volume volume, Type type) {
9861005
VolumeVO volumeVO = _volumeDao.findById(volume.getId());
9871006
if (volumeVO == null) {

plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/datastore/driver/StorPoolPrimaryDataStoreDriver.java

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -632,8 +632,11 @@ public void copyAsync(DataObject srcData, DataObject dstData, AsyncCompletionCal
632632
VolumeInfo vinfo = (VolumeInfo)dstData;
633633
final String volumeName = vinfo.getUuid();
634634
final Long size = vinfo.getSize();
635+
635636
SpConnectionDesc conn = StorPoolUtil.getSpConnection(vinfo.getDataStore().getUuid(), vinfo.getDataStore().getId(), storagePoolDetailsDao, primaryStoreDao);
636-
SpApiResponse resp = StorPoolUtil.volumeCreate(volumeName, snapshotName, size, null, null, "volume", sinfo.getBaseVolume().getMaxIops(), conn);
637+
638+
StorPoolVolumeDef spVolume = createVolumeWithTags(sinfo, snapshotName, vinfo, volumeName, size, conn);
639+
SpApiResponse resp = StorPoolUtil.volumeCreate(spVolume, conn);
637640
if (resp.getError() == null) {
638641
updateStoragePool(dstData.getDataStore().getId(), size);
639642

@@ -649,9 +652,10 @@ public void copyAsync(DataObject srcData, DataObject dstData, AsyncCompletionCal
649652
SnapshotDataStoreVO snap = getSnapshotImageStoreRef(sinfo.getId(), vinfo.getDataCenterId());
650653
SnapshotDetailsVO snapshotDetail = snapshotDetailsDao.findDetail(sinfo.getId(), StorPoolUtil.SP_DELAY_DELETE);
651654
if (snapshotDetail != null) {
652-
err = String.format("Could not create volume from snapshot due to: %s. The snapshot was created with the delayDelete option.", resp.getError());
655+
answer = new Answer(cmd, false, String.format("Could not create volume from snapshot due to: %s. The snapshot was created with the delayDelete option.", resp.getError()));
653656
} else if (snap != null && StorPoolStorageAdaptor.getVolumeNameFromPath(snap.getInstallPath(), false) == null) {
654-
SpApiResponse emptyVolumeCreateResp = StorPoolUtil.volumeCreate(volumeName, null, size, null, null, "volume", null, conn);
657+
spVolume.setParent(null);
658+
SpApiResponse emptyVolumeCreateResp = StorPoolUtil.volumeCreate(spVolume, conn);
655659
if (emptyVolumeCreateResp.getError() == null) {
656660
answer = createVolumeFromSnapshot(srcData, dstData, size, emptyVolumeCreateResp);
657661
} else {
@@ -661,7 +665,7 @@ public void copyAsync(DataObject srcData, DataObject dstData, AsyncCompletionCal
661665
answer = new Answer(cmd, false, String.format("The snapshot %s does not exists neither on primary, neither on secondary storage. Cannot create volume from snapshot", snapshotName));
662666
}
663667
} else {
664-
err = String.format("Could not create Storpool volume %s from snapshot %s. Error: %s", volumeName, snapshotName, resp.getError());
668+
answer = new Answer(cmd, false, String.format("Could not create Storpool volume %s from snapshot %s. Error: %s", volumeName, snapshotName, resp.getError()));
665669
}
666670
} else if (srcType == DataObjectType.SNAPSHOT && dstType == DataObjectType.SNAPSHOT) {
667671
SnapshotInfo sinfo = (SnapshotInfo)srcData;
@@ -984,6 +988,23 @@ public void copyAsync(DataObject srcData, DataObject dstData, AsyncCompletionCal
984988
callback.complete(res);
985989
}
986990

991+
private StorPoolVolumeDef createVolumeWithTags(SnapshotInfo sinfo, String snapshotName, VolumeInfo vinfo, String volumeName, Long size, SpConnectionDesc conn) {
992+
String tier = null;
993+
String template = null;
994+
if (vinfo.getDiskOfferingId() != null) {
995+
tier = getTierFromOfferingDetail(vinfo.getDiskOfferingId());
996+
if (tier == null) {
997+
template = getTemplateFromOfferingDetail(vinfo.getDiskOfferingId());
998+
}
999+
}
1000+
1001+
if (template == null) {
1002+
template = conn.getTemplateName();
1003+
}
1004+
Map<String, String> tags = StorPoolHelper.addStorPoolTags(volumeName, getVMInstanceUUID(vinfo.getInstanceId()), "volume", getVcPolicyTag(vinfo.getInstanceId()), tier);
1005+
return new StorPoolVolumeDef(null, size, tags, snapshotName, sinfo.getBaseVolume().getMaxIops(), template, null, null, null);
1006+
}
1007+
9871008
private Answer createVolumeSnapshot(StorageSubSystemCommand cmd, Long size, SpConnectionDesc conn,
9881009
String volName, TemplateObjectTO dstTO) {
9891010
Answer answer;

plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/datastore/util/StorPoolUtil.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,10 @@ public static SpApiResponse volumeCreate(Long size, String parentName, String te
520520
return POST("MultiCluster/VolumeCreate", json, conn);
521521
}
522522

523+
public static SpApiResponse volumeCreate(StorPoolVolumeDef volume, SpConnectionDesc conn) {
524+
return POST("MultiCluster/VolumeCreate", volume, conn);
525+
}
526+
523527
public static SpApiResponse volumeCreate(SpConnectionDesc conn) {
524528
Map<String, Object> json = new LinkedHashMap<>();
525529
json.put("name", "");

test/integration/plugins/storpool/test_storpool_tiers.py

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@
2626
StoragePool,
2727
VirtualMachine,
2828
SecurityGroup,
29-
ResourceDetails
29+
ResourceDetails,
30+
Snapshot,
31+
Volume,
3032
)
3133
from marvin.lib.common import (get_domain,
3234
get_template,
@@ -167,6 +169,26 @@ def setUpCloudStack(cls):
167169
cls.random_data_0 = random_gen(size=100)
168170
cls.test_dir = "/tmp"
169171
cls.random_data = "random.data"
172+
cls.virtual_machine = VirtualMachine.create(
173+
cls.apiclient,
174+
cls.services["small"],
175+
accountid=cls.account.name,
176+
domainid=cls.account.domainid,
177+
templateid=cls.template.id,
178+
serviceofferingid=cls.service_offering.id,
179+
overridediskofferingid=cls.disk_offerings_tier1_tags.id,
180+
)
181+
182+
volume = list_volumes(
183+
cls.apiclient,
184+
virtualmachineid=cls.virtual_machine.id,
185+
type='ROOT',
186+
listall=True
187+
)[0]
188+
cls.snapshot = Snapshot.create(
189+
cls.apiclient,
190+
volume.id,
191+
)
170192
return
171193

172194
@classmethod
@@ -437,6 +459,22 @@ def test_12_shrink_data_volume(self):
437459
disk_offering_id=self.disk_offerings_tier2_tags.id, attached=True)
438460
virtual_machine_tier1_tag.stop(self.apiclient, forced=True)
439461

462+
@attr(tags=["advanced", "advancedns", "smoke"], required_hardware="true")
463+
def test_13_deploy_vm_from_volume_check_tags(self):
464+
vm = self.deploy_vm_from_snapshot_or_template(snapshotid=self.snapshot.id, is_snapshot=False)
465+
root_volume = list_volumes(self.apiclient, virtualmachineid=vm.id, type="ROOT",
466+
listall=True)
467+
self.vc_policy_tags(volumes=root_volume, vm=vm, qos_or_template=self.qos,
468+
disk_offering_id=self.disk_offerings_tier1_tags.id, attached=True)
469+
470+
@attr(tags=["advanced", "advancedns", "smoke"], required_hardware="true")
471+
def test_14_deploy_vm_from_snapshot_check_tags(self):
472+
vm = self.deploy_vm_from_snapshot_or_template(snapshotid=self.snapshot.id, is_snapshot=True)
473+
root_volume = list_volumes(self.apiclient, virtualmachineid=vm.id, type="ROOT",
474+
listall=True)
475+
self.vc_policy_tags(volumes=root_volume, vm=vm, qos_or_template=self.qos,
476+
disk_offering_id=self.disk_offerings_tier1_tags.id, attached=True)
477+
440478
def deploy_vm_and_check_tier_tag(self):
441479
virtual_machine_tier1_tag = VirtualMachine.create(
442480
self.apiclient,
@@ -542,3 +580,41 @@ def changeOfferingForVolume(self, volume_id, disk_offering_id, size, shrinkok=No
542580
change_offering_for_volume_cmd.shrinkok = shrinkok
543581

544582
return self.apiclient.changeOfferingForVolume(change_offering_for_volume_cmd)
583+
584+
def deploy_vm_from_snapshot_or_template(self, snapshotid, is_snapshot=False):
585+
if is_snapshot:
586+
virtual_machine = VirtualMachine.create(self.apiclient,
587+
{"name": "StorPool-%s" % uuid.uuid4()},
588+
zoneid=self.zone.id,
589+
accountid=self.account.name,
590+
domainid=self.account.domainid,
591+
serviceofferingid=self.service_offering.id,
592+
snapshotid=snapshotid,
593+
)
594+
try:
595+
ssh_client = virtual_machine.get_ssh_client()
596+
except Exception as e:
597+
self.fail("SSH failed for virtual machine: %s - %s" %
598+
(virtual_machine.ipaddress, e))
599+
600+
return virtual_machine
601+
volume = Volume.create_from_snapshot(
602+
self.apiclient,
603+
snapshot_id=snapshotid,
604+
services=self.services,
605+
disk_offering=self.disk_offering.id,
606+
zoneid=self.zone.id,
607+
)
608+
virtual_machine = VirtualMachine.create(self.apiclient,
609+
{"name": "StorPool-%s" % uuid.uuid4()},
610+
zoneid=self.zone.id,
611+
accountid=self.account.name,
612+
domainid=self.account.domainid,
613+
serviceofferingid=self.service_offering.id,
614+
volumeid=volume.id,
615+
)
616+
try:
617+
ssh_client = virtual_machine.get_ssh_client()
618+
except Exception as e:
619+
self.fail("SSH failed for virtual machine: %s - %s" %
620+
(virtual_machine.ipaddress, e))

test/integration/smoke/test_vm_lifecycle_with_snapshot_or_volume.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,7 @@ def create_volume_from_snapshot_deploy_vm(self, snapshotid):
296296
volume = Volume.create_from_snapshot(
297297
self.apiclient,
298298
snapshot_id=snapshotid,
299+
services=self.services,
299300
disk_offering=self.disk_offering.id,
300301
zoneid=self.zone.id,
301302
)

tools/marvin/marvin/lib/base.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1222,7 +1222,7 @@ def create_custom_disk(cls, apiclient, services, account=None,
12221222

12231223
@classmethod
12241224
def create_from_snapshot(cls, apiclient, snapshot_id, services,
1225-
account=None, domainid=None, projectid=None, zoneid=None):
1225+
account=None, domainid=None, projectid=None, zoneid=None, disk_offering=None):
12261226
"""Create Volume from snapshot"""
12271227
cmd = createVolume.createVolumeCmd()
12281228
cmd.name = "-".join([services["diskname"], random_gen()])
@@ -1249,6 +1249,9 @@ def create_from_snapshot(cls, apiclient, snapshot_id, services,
12491249
if projectid:
12501250
cmd.projectid = projectid
12511251

1252+
if disk_offering:
1253+
cmd.diskofferingid = disk_offering
1254+
12521255
return Volume(apiclient.createVolume(cmd).__dict__)
12531256

12541257
@classmethod

0 commit comments

Comments
 (0)