Skip to content

Commit 1fb95a4

Browse files
slavkapdhslove
authored andcommitted
KVM: Option to deploy a VM with existing volume/snapshot (apache#10503)
* Option to deploy a VM with existing volume/snapshot * smoke test changes check if the hypervisor is KVM check if the primary storage's scope is ZONE wide * skip all tests if the storage isn't Zone-Wide and the hypervisor isn't KVM * 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 * Add StorPool tags on the new ROOT volume * Add the StorPool's tags when volume is created from a snapshot or a volume is attached as a ROOT to a VM * Addressed review
1 parent 975b10d commit 1fb95a4

File tree

29 files changed

+937
-196
lines changed

29 files changed

+937
-196
lines changed

api/src/main/java/com/cloud/vm/UserVmService.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
// under the License.
1717
package com.cloud.vm;
1818

19+
import com.cloud.storage.Snapshot;
20+
import com.cloud.storage.Volume;
1921
import java.util.LinkedHashMap;
2022
import java.util.List;
2123
import java.util.Map;
@@ -240,7 +242,7 @@ UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering s
240242
String userData, Long userDataId, String userDataDetails, List<String> sshKeyPairs, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIp, Boolean displayVm, String keyboard,
241243
List<Long> affinityGroupIdList, Map<String, String> customParameter, String customId, Map<String, Map<Integer, String>> dhcpOptionMap,
242244
Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap,
243-
Map<String, String> userVmOVFProperties, boolean dynamicScalingEnabled, Long overrideDiskOfferingId) throws InsufficientCapacityException,
245+
Map<String, String> userVmOVFProperties, boolean dynamicScalingEnabled, Long overrideDiskOfferingId, Volume volume, Snapshot snapshot) throws InsufficientCapacityException,
244246
ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException;
245247

246248
/**
@@ -316,7 +318,7 @@ UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, ServiceOfferin
316318
List<Long> securityGroupIdList, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor,
317319
HTTPMethod httpmethod, String userData, Long userDataId, String userDataDetails, List<String> sshKeyPairs, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard,
318320
List<Long> affinityGroupIdList, Map<String, String> customParameters, String customId, Map<String, Map<Integer, String>> dhcpOptionMap,
319-
Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap, Map<String, String> userVmOVFProperties, boolean dynamicScalingEnabled, Long overrideDiskOfferingId, String vmType) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException;
321+
Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap, Map<String, String> userVmOVFProperties, boolean dynamicScalingEnabled, Long overrideDiskOfferingId, String vmType, Volume volume, Snapshot snapshot) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException;
320322

321323
/**
322324
* Creates a User VM in Advanced Zone (Security Group feature is disabled)
@@ -388,7 +390,7 @@ UserVm createAdvancedVirtualMachine(DataCenter zone, ServiceOffering serviceOffe
388390
String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod, String userData,
389391
Long userDataId, String userDataDetails, List<String> sshKeyPairs, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard, List<Long> affinityGroupIdList,
390392
Map<String, String> customParameters, String customId, Map<String, Map<Integer, String>> dhcpOptionMap, Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap,
391-
Map<String, String> templateOvfPropertiesMap, boolean dynamicScalingEnabled, String vmType, Long overrideDiskOfferingId)
393+
Map<String, String> templateOvfPropertiesMap, boolean dynamicScalingEnabled, String vmType, Long overrideDiskOfferingId, Volume volume, Snapshot snapshot)
392394

393395
throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException;
394396

api/src/main/java/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,14 @@
3030
import com.cloud.offering.DiskOffering;
3131
import com.cloud.template.VirtualMachineTemplate;
3232
import com.cloud.uservm.UserVm;
33+
import com.cloud.utils.exception.CloudRuntimeException;
3334
import com.cloud.utils.net.Dhcp;
3435
import com.cloud.utils.net.NetUtils;
3536
import com.cloud.vm.VirtualMachine;
3637
import com.cloud.vm.VmDetailConstants;
38+
39+
import java.util.Objects;
40+
import java.util.stream.Stream;
3741
import org.apache.cloudstack.acl.RoleType;
3842
import org.apache.cloudstack.affinity.AffinityGroupResponse;
3943
import org.apache.cloudstack.api.ACL;
@@ -55,9 +59,11 @@
5559
import org.apache.cloudstack.api.response.ProjectResponse;
5660
import org.apache.cloudstack.api.response.SecurityGroupResponse;
5761
import org.apache.cloudstack.api.response.ServiceOfferingResponse;
62+
import org.apache.cloudstack.api.response.SnapshotResponse;
5863
import org.apache.cloudstack.api.response.TemplateResponse;
5964
import org.apache.cloudstack.api.response.UserDataResponse;
6065
import org.apache.cloudstack.api.response.UserVmResponse;
66+
import org.apache.cloudstack.api.response.VolumeResponse;
6167
import org.apache.cloudstack.api.response.ZoneResponse;
6268
import org.apache.cloudstack.context.CallContext;
6369
import org.apache.cloudstack.vm.lease.VMLeaseManager;
@@ -93,7 +99,7 @@ public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd implements SecurityG
9399
private Long serviceOfferingId;
94100

95101
@ACL
96-
@Parameter(name = ApiConstants.TEMPLATE_ID, type = CommandType.UUID, entityType = TemplateResponse.class, required = true, description = "the ID of the template for the virtual machine")
102+
@Parameter(name = ApiConstants.TEMPLATE_ID, type = CommandType.UUID, entityType = TemplateResponse.class, description = "the ID of the template for the virtual machine")
97103
private Long templateId;
98104

99105
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "host name for the virtual machine", validations = {ApiArgValidator.RFCComplianceDomainName})
@@ -288,6 +294,11 @@ public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd implements SecurityG
288294
description = "Lease expiry action, valid values are STOP and DESTROY")
289295
private String leaseExpiryAction;
290296

297+
@Parameter(name = ApiConstants.VOLUME_ID, type = CommandType.UUID, entityType = VolumeResponse.class, since = "4.21")
298+
private Long volumeId;
299+
300+
@Parameter(name = ApiConstants.SNAPSHOT_ID, type = CommandType.UUID, entityType = SnapshotResponse.class, since = "4.21")
301+
private Long snapshotId;
291302
/////////////////////////////////////////////////////
292303
/////////////////// Accessors ///////////////////////
293304
/////////////////////////////////////////////////////
@@ -780,6 +791,18 @@ public ApiConstants.IoDriverPolicy getIoDriverPolicy() {
780791
}
781792
return null;
782793
}
794+
795+
public Long getVolumeId() {
796+
return volumeId;
797+
}
798+
799+
public Long getSnapshotId() {
800+
return snapshotId;
801+
}
802+
803+
public boolean isVolumeOrSnapshotProvided() {
804+
return volumeId != null || snapshotId != null;
805+
}
783806
/////////////////////////////////////////////////////
784807
/////////////// API Implementation///////////////////
785808
/////////////////////////////////////////////////////
@@ -871,6 +894,10 @@ public void execute() {
871894

872895
@Override
873896
public void create() throws ResourceAllocationException {
897+
if (Stream.of(templateId, snapshotId, volumeId).filter(Objects::nonNull).count() != 1) {
898+
throw new CloudRuntimeException("Please provide only one of the following parameters - template ID, volume ID or snapshot ID");
899+
}
900+
874901
try {
875902
UserVm vm = _userVmService.createVirtualMachine(this);
876903

engine/api/src/main/java/com/cloud/vm/VirtualMachineManager.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
// under the License.
1717
package com.cloud.vm;
1818

19+
import com.cloud.storage.Snapshot;
20+
import com.cloud.storage.Volume;
1921
import java.net.URI;
2022
import java.util.HashMap;
2123
import java.util.LinkedHashMap;
@@ -129,11 +131,11 @@ interface Topics {
129131
* @throws InsufficientCapacityException If there are insufficient capacity to deploy this vm.
130132
*/
131133
void allocate(String vmInstanceName, VirtualMachineTemplate template, ServiceOffering serviceOffering, DiskOfferingInfo rootDiskOfferingInfo,
132-
List<DiskOfferingInfo> dataDiskOfferings, LinkedHashMap<? extends Network, List<? extends NicProfile>> auxiliaryNetworks, DeploymentPlan plan,
133-
HypervisorType hyperType, Map<String, Map<Integer, String>> extraDhcpOptions, Map<Long, DiskOffering> datadiskTemplateToDiskOfferingMap, Map<String, String> customParameters) throws InsufficientCapacityException;
134+
List<DiskOfferingInfo> dataDiskOfferings, LinkedHashMap<? extends Network, List<? extends NicProfile>> auxiliaryNetworks, DeploymentPlan plan,
135+
HypervisorType hyperType, Map<String, Map<Integer, String>> extraDhcpOptions, Map<Long, DiskOffering> datadiskTemplateToDiskOfferingMap, Map<String, String> customParameters, Volume volume, Snapshot snapshot) throws InsufficientCapacityException;
134136

135137
void allocate(String vmInstanceName, VirtualMachineTemplate template, ServiceOffering serviceOffering,
136-
LinkedHashMap<? extends Network, List<? extends NicProfile>> networkProfiles, DeploymentPlan plan, HypervisorType hyperType) throws InsufficientCapacityException;
138+
LinkedHashMap<? extends Network, List<? extends NicProfile>> networkProfiles, DeploymentPlan plan, HypervisorType hyperType, Volume volume, Snapshot snapshot) throws InsufficientCapacityException;
137139

138140
void start(String vmUuid, Map<VirtualMachineProfile.Param, Object> params);
139141

engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ DiskProfile allocateRawVolumes(Type type, String name, DiskOffering offering, Lo
154154
* Allocate a volume or multiple volumes in case of template is registered with the 'deploy-as-is' option, allowing multiple disks
155155
*/
156156
List<DiskProfile> allocateTemplatedVolumes(Type type, String name, DiskOffering offering, Long rootDisksize, Long minIops, Long maxIops, VirtualMachineTemplate template, VirtualMachine vm,
157-
Account owner);
157+
Account owner, Volume volume, Snapshot snapshot);
158158

159159
String getVmNameFromVolumeId(long volumeId);
160160

engine/api/src/main/java/org/apache/cloudstack/engine/service/api/OrchestrationService.java

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
*/
1919
package org.apache.cloudstack.engine.service.api;
2020

21+
import com.cloud.storage.Snapshot;
22+
import com.cloud.storage.Volume;
2123
import java.net.URL;
2224
import java.util.List;
2325
import java.util.Map;
@@ -62,21 +64,21 @@ public interface OrchestrationService {
6264
@POST
6365
@Path("/createvm")
6466
VirtualMachineEntity createVirtualMachine(@QueryParam("id") String id, @QueryParam("owner") String owner, @QueryParam("template-id") String templateId,
65-
@QueryParam("host-name") String hostName, @QueryParam("display-name") String displayName, @QueryParam("hypervisor") String hypervisor,
66-
@QueryParam("cpu") int cpu, @QueryParam("speed") int speed, @QueryParam("ram") long memory, @QueryParam("customParameters") Map<String, String> customParameters,
67-
@QueryParam("disk-size") Long diskSize,
68-
@QueryParam("compute-tags") List<String> computeTags, @QueryParam("root-disk-tags") List<String> rootDiskTags,
69-
@QueryParam("network-nic-map") Map<String, List<NicProfile>> networkNicMap, @QueryParam("deploymentplan") DeploymentPlan plan,
70-
@QueryParam("root-disk-size") Long rootDiskSize, @QueryParam("extra-dhcp-option-map") Map<String, Map<Integer, String>> extraDhcpOptionMap,
71-
@QueryParam("datadisktemplate-diskoffering-map") Map<Long, DiskOffering> datadiskTemplateToDiskOfferingMap, @QueryParam("disk-offering-id") Long diskOfferingId, @QueryParam("root-disk-offering-id") Long rootDiskOfferingId) throws InsufficientCapacityException;
67+
@QueryParam("host-name") String hostName, @QueryParam("display-name") String displayName, @QueryParam("hypervisor") String hypervisor,
68+
@QueryParam("cpu") int cpu, @QueryParam("speed") int speed, @QueryParam("ram") long memory, @QueryParam("customParameters") Map<String, String> customParameters,
69+
@QueryParam("disk-size") Long diskSize,
70+
@QueryParam("compute-tags") List<String> computeTags, @QueryParam("root-disk-tags") List<String> rootDiskTags,
71+
@QueryParam("network-nic-map") Map<String, List<NicProfile>> networkNicMap, @QueryParam("deploymentplan") DeploymentPlan plan,
72+
@QueryParam("root-disk-size") Long rootDiskSize, @QueryParam("extra-dhcp-option-map") Map<String, Map<Integer, String>> extraDhcpOptionMap,
73+
@QueryParam("datadisktemplate-diskoffering-map") Map<Long, DiskOffering> datadiskTemplateToDiskOfferingMap, @QueryParam("disk-offering-id") Long diskOfferingId, @QueryParam("root-disk-offering-id") Long rootDiskOfferingId, Volume volume, Snapshot snapshot) throws InsufficientCapacityException;
7274

7375
@POST
7476
VirtualMachineEntity createVirtualMachineFromScratch(@QueryParam("id") String id, @QueryParam("owner") String owner, @QueryParam("iso-id") String isoId,
7577
@QueryParam("host-name") String hostName, @QueryParam("display-name") String displayName, @QueryParam("hypervisor") String hypervisor,
7678
@QueryParam("os") String os, @QueryParam("cpu") int cpu, @QueryParam("speed") int speed, @QueryParam("ram") long memory, @QueryParam("customParameters") Map<String, String> customParameters, @QueryParam("disk-size") Long diskSize,
7779
@QueryParam("compute-tags") List<String> computeTags, @QueryParam("root-disk-tags") List<String> rootDiskTags,
7880
@QueryParam("network-nic-map") Map<String, List<NicProfile>> networkNicMap, @QueryParam("deploymentplan") DeploymentPlan plan,
79-
@QueryParam("extra-dhcp-option-map") Map<String, Map<Integer, String>> extraDhcpOptionMap, @QueryParam("disk-offering-id") Long diskOfferingId) throws InsufficientCapacityException;
81+
@QueryParam("extra-dhcp-option-map") Map<String, Map<Integer, String>> extraDhcpOptionMap, @QueryParam("disk-offering-id") Long diskOfferingId, Volume volume, Snapshot snapshot) throws InsufficientCapacityException;
8082

8183
@POST
8284
NetworkEntity createNetwork(String id, String name, String domainName, String cidr, String gateway);

engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
import javax.naming.ConfigurationException;
5050
import javax.persistence.EntityExistsException;
5151

52+
5253
import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao;
5354
import org.apache.cloudstack.annotation.AnnotationService;
5455
import org.apache.cloudstack.annotation.dao.AnnotationDao;
@@ -231,6 +232,7 @@
231232
import com.cloud.service.dao.ServiceOfferingDao;
232233
import com.cloud.storage.DiskOfferingVO;
233234
import com.cloud.storage.ScopeType;
235+
import com.cloud.storage.Snapshot;
234236
import com.cloud.storage.Storage;
235237
import com.cloud.storage.Storage.ImageFormat;
236238
import com.cloud.storage.StorageManager;
@@ -292,6 +294,7 @@
292294
import com.cloud.vm.snapshot.dao.VMSnapshotDao;
293295
import com.google.gson.Gson;
294296

297+
295298
public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMachineManager, VmWorkJobHandler, Listener, Configurable {
296299

297300
public static final String VM_WORK_JOB_HANDLER = VirtualMachineManagerImpl.class.getSimpleName();
@@ -504,9 +507,9 @@ public void registerGuru(final VirtualMachine.Type type, final VirtualMachineGur
504507
@Override
505508
@DB
506509
public void allocate(final String vmInstanceName, final VirtualMachineTemplate template, final ServiceOffering serviceOffering,
507-
final DiskOfferingInfo rootDiskOfferingInfo, final List<DiskOfferingInfo> dataDiskOfferings,
508-
final LinkedHashMap<? extends Network, List<? extends NicProfile>> auxiliaryNetworks, final DeploymentPlan plan, final HypervisorType hyperType, final Map<String, Map<Integer, String>> extraDhcpOptions,
509-
final Map<Long, DiskOffering> datadiskTemplateToDiskOfferingMap, final Map<String, String> customParameters)
510+
final DiskOfferingInfo rootDiskOfferingInfo, final List<DiskOfferingInfo> dataDiskOfferings,
511+
final LinkedHashMap<? extends Network, List<? extends NicProfile>> auxiliaryNetworks, final DeploymentPlan plan, final HypervisorType hyperType, final Map<String, Map<Integer, String>> extraDhcpOptions,
512+
final Map<Long, DiskOffering> datadiskTemplateToDiskOfferingMap, final Map<String, String> customParameters, Volume volume, Snapshot snapshot)
510513
throws InsufficientCapacityException {
511514

512515
logger.info("allocating virtual machine from template: {} with hostname: {} and {} networks", template, vmInstanceName, auxiliaryNetworks.size());
@@ -549,7 +552,7 @@ public void allocate(final String vmInstanceName, final VirtualMachineTemplate t
549552
volVO.setInstanceId(vm.getId());
550553
_volsDao.update(volVO.getId(), volVO);
551554
} else {
552-
allocateRootVolume(persistedVm, template, rootDiskOfferingInfo, owner, rootDiskSizeFinal);
555+
allocateRootVolume(persistedVm, template, rootDiskOfferingInfo, owner, rootDiskSizeFinal, volume, snapshot);
553556
}
554557

555558
// Create new Volume context and inject event resource type, id and details to generate VOLUME.CREATE event for the ROOT disk.
@@ -591,7 +594,7 @@ public void allocate(final String vmInstanceName, final VirtualMachineTemplate t
591594
}
592595
}
593596

594-
private void allocateRootVolume(VMInstanceVO vm, VirtualMachineTemplate template, DiskOfferingInfo rootDiskOfferingInfo, Account owner, Long rootDiskSizeFinal) {
597+
private void allocateRootVolume(VMInstanceVO vm, VirtualMachineTemplate template, DiskOfferingInfo rootDiskOfferingInfo, Account owner, Long rootDiskSizeFinal, Volume volume, Snapshot snapshot) {
595598
// Create new Volume context and inject event resource type, id and details to generate VOLUME.CREATE event for the ROOT disk.
596599
CallContext volumeContext = CallContext.register(CallContext.current(), ApiCommandResourceType.Volume);
597600
try {
@@ -603,7 +606,7 @@ private void allocateRootVolume(VMInstanceVO vm, VirtualMachineTemplate template
603606
logger.debug("%s has format [{}]. Skipping ROOT volume [{}] allocation.", template.toString(), ImageFormat.BAREMETAL, rootVolumeName);
604607
} else {
605608
volumeMgr.allocateTemplatedVolumes(Type.ROOT, rootVolumeName, rootDiskOfferingInfo.getDiskOffering(), rootDiskSizeFinal,
606-
rootDiskOfferingInfo.getMinIops(), rootDiskOfferingInfo.getMaxIops(), template, vm, owner);
609+
rootDiskOfferingInfo.getMinIops(), rootDiskOfferingInfo.getMaxIops(), template, vm, owner, volume, snapshot);
607610
}
608611
} finally {
609612
// Remove volumeContext and pop vmContext back
@@ -613,9 +616,9 @@ private void allocateRootVolume(VMInstanceVO vm, VirtualMachineTemplate template
613616

614617
@Override
615618
public void allocate(final String vmInstanceName, final VirtualMachineTemplate template, final ServiceOffering serviceOffering,
616-
final LinkedHashMap<? extends Network, List<? extends NicProfile>> networks, final DeploymentPlan plan, final HypervisorType hyperType) throws InsufficientCapacityException {
619+
final LinkedHashMap<? extends Network, List<? extends NicProfile>> networks, final DeploymentPlan plan, final HypervisorType hyperType, Volume volume, Snapshot snapshot) throws InsufficientCapacityException {
617620
DiskOffering diskOffering = _diskOfferingDao.findById(serviceOffering.getDiskOfferingId());
618-
allocate(vmInstanceName, template, serviceOffering, new DiskOfferingInfo(diskOffering), new ArrayList<>(), networks, plan, hyperType, null, null, null );
621+
allocate(vmInstanceName, template, serviceOffering, new DiskOfferingInfo(diskOffering), new ArrayList<>(), networks, plan, hyperType, null, null, null, volume, snapshot);
619622
}
620623

621624
VirtualMachineGuru getVmGuru(final VirtualMachine vm) {

0 commit comments

Comments
 (0)