Skip to content

Commit 3bc8eeb

Browse files
committed
Option to deploy a VM with existing volume/snapshot
1 parent eab37ec commit 3bc8eeb

File tree

26 files changed

+772
-246
lines changed

26 files changed

+772
-246
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;
@@ -221,7 +223,7 @@ UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering s
221223
String userData, Long userDataId, String userDataDetails, List<String> sshKeyPairs, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIp, Boolean displayVm, String keyboard,
222224
List<Long> affinityGroupIdList, Map<String, String> customParameter, String customId, Map<String, Map<Integer, String>> dhcpOptionMap,
223225
Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap,
224-
Map<String, String> userVmOVFProperties, boolean dynamicScalingEnabled, Long overrideDiskOfferingId) throws InsufficientCapacityException,
226+
Map<String, String> userVmOVFProperties, boolean dynamicScalingEnabled, Long overrideDiskOfferingId, Volume volume, Snapshot snapshot) throws InsufficientCapacityException,
225227
ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException;
226228

227229
/**
@@ -297,7 +299,7 @@ UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, ServiceOfferin
297299
List<Long> securityGroupIdList, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor,
298300
HTTPMethod httpmethod, String userData, Long userDataId, String userDataDetails, List<String> sshKeyPairs, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard,
299301
List<Long> affinityGroupIdList, Map<String, String> customParameters, String customId, Map<String, Map<Integer, String>> dhcpOptionMap,
300-
Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap, Map<String, String> userVmOVFProperties, boolean dynamicScalingEnabled, Long overrideDiskOfferingId, String vmType) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException;
302+
Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap, Map<String, String> userVmOVFProperties, boolean dynamicScalingEnabled, Long overrideDiskOfferingId, String vmType, Volume volume, Snapshot snapshot) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException;
301303

302304
/**
303305
* Creates a User VM in Advanced Zone (Security Group feature is disabled)
@@ -369,7 +371,7 @@ UserVm createAdvancedVirtualMachine(DataCenter zone, ServiceOffering serviceOffe
369371
String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod, String userData,
370372
Long userDataId, String userDataDetails, List<String> sshKeyPairs, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard, List<Long> affinityGroupIdList,
371373
Map<String, String> customParameters, String customId, Map<String, Map<Integer, String>> dhcpOptionMap, Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap,
372-
Map<String, String> templateOvfPropertiesMap, boolean dynamicScalingEnabled, String vmType, Long overrideDiskOfferingId)
374+
Map<String, String> templateOvfPropertiesMap, boolean dynamicScalingEnabled, String vmType, Long overrideDiskOfferingId, Volume volume, Snapshot snapshot)
373375

374376
throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException;
375377

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

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
// under the License.
1717
package org.apache.cloudstack.api.command.user.vm;
1818

19+
import com.cloud.utils.exception.CloudRuntimeException;
1920
import java.util.ArrayList;
2021
import java.util.Arrays;
2122
import java.util.Collection;
@@ -48,9 +49,11 @@
4849
import org.apache.cloudstack.api.response.ProjectResponse;
4950
import org.apache.cloudstack.api.response.SecurityGroupResponse;
5051
import org.apache.cloudstack.api.response.ServiceOfferingResponse;
52+
import org.apache.cloudstack.api.response.SnapshotResponse;
5153
import org.apache.cloudstack.api.response.TemplateResponse;
5254
import org.apache.cloudstack.api.response.UserDataResponse;
5355
import org.apache.cloudstack.api.response.UserVmResponse;
56+
import org.apache.cloudstack.api.response.VolumeResponse;
5457
import org.apache.cloudstack.api.response.ZoneResponse;
5558
import org.apache.cloudstack.context.CallContext;
5659
import org.apache.commons.collections.CollectionUtils;
@@ -95,7 +98,7 @@ public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd implements SecurityG
9598
private Long serviceOfferingId;
9699

97100
@ACL
98-
@Parameter(name = ApiConstants.TEMPLATE_ID, type = CommandType.UUID, entityType = TemplateResponse.class, required = true, description = "the ID of the template for the virtual machine")
101+
@Parameter(name = ApiConstants.TEMPLATE_ID, type = CommandType.UUID, entityType = TemplateResponse.class, description = "the ID of the template for the virtual machine")
99102
private Long templateId;
100103

101104
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "host name for the virtual machine", validations = {ApiArgValidator.RFCComplianceDomainName})
@@ -278,6 +281,11 @@ public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd implements SecurityG
278281
description = "Enable packed virtqueues or not.")
279282
private Boolean nicPackedVirtQueues;
280283

284+
@Parameter(name = ApiConstants.VOLUME_ID, type = CommandType.UUID, entityType = VolumeResponse.class, since = "4.21")
285+
private Long volumeId;
286+
287+
@Parameter(name = ApiConstants.SNAPSHOT_ID, type = CommandType.UUID, entityType = SnapshotResponse.class, since = "4.21")
288+
private Long snapshotId;
281289
/////////////////////////////////////////////////////
282290
/////////////////// Accessors ///////////////////////
283291
/////////////////////////////////////////////////////
@@ -720,6 +728,18 @@ public ApiConstants.IoDriverPolicy getIoDriverPolicy() {
720728
}
721729
return null;
722730
}
731+
732+
public Long getVolumeId() {
733+
return volumeId;
734+
}
735+
736+
public Long getSnapshotId() {
737+
return snapshotId;
738+
}
739+
740+
public boolean isVolumeOrSnapshotProvided() {
741+
return volumeId != null || snapshotId != null;
742+
}
723743
/////////////////////////////////////////////////////
724744
/////////////// API Implementation///////////////////
725745
/////////////////////////////////////////////////////
@@ -816,6 +836,9 @@ public void execute() {
816836

817837
@Override
818838
public void create() throws ResourceAllocationException {
839+
if (!isVolumeOrSnapshotProvided() && templateId == null) {
840+
throw new CloudRuntimeException("There isn't a ROOT volume, snapshot of ROOT volume or template provided to deploy a Virtual machine");
841+
}
819842
try {
820843
UserVm vm = _userVmService.createVirtualMachine(this);
821844

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) 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, 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
@@ -137,7 +137,7 @@ DiskProfile allocateRawVolume(Type type, String name, DiskOffering offering, Lon
137137
* Allocate a volume or multiple volumes in case of template is registered with the 'deploy-as-is' option, allowing multiple disks
138138
*/
139139
List<DiskProfile> allocateTemplatedVolumes(Type type, String name, DiskOffering offering, Long rootDisksize, Long minIops, Long maxIops, VirtualMachineTemplate template, VirtualMachine vm,
140-
Account owner);
140+
Account owner, Volume volume, Snapshot snapshot);
141141

142142
String getVmNameFromVolumeId(long volumeId);
143143

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

Lines changed: 9 additions & 7 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,20 +64,20 @@ 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("disk-size") Long diskSize,
67-
@QueryParam("compute-tags") List<String> computeTags, @QueryParam("root-disk-tags") List<String> rootDiskTags,
68-
@QueryParam("network-nic-map") Map<String, List<NicProfile>> networkNicMap, @QueryParam("deploymentplan") DeploymentPlan plan,
69-
@QueryParam("root-disk-size") Long rootDiskSize, @QueryParam("extra-dhcp-option-map") Map<String, Map<Integer, String>> extraDhcpOptionMap,
70-
@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("disk-size") Long diskSize,
69+
@QueryParam("compute-tags") List<String> computeTags, @QueryParam("root-disk-tags") List<String> rootDiskTags,
70+
@QueryParam("network-nic-map") Map<String, List<NicProfile>> networkNicMap, @QueryParam("deploymentplan") DeploymentPlan plan,
71+
@QueryParam("root-disk-size") Long rootDiskSize, @QueryParam("extra-dhcp-option-map") Map<String, Map<Integer, String>> extraDhcpOptionMap,
72+
@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;
7173

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

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

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

Lines changed: 10 additions & 7 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;
@@ -223,6 +224,7 @@
223224
import com.cloud.service.dao.ServiceOfferingDao;
224225
import com.cloud.storage.DiskOfferingVO;
225226
import com.cloud.storage.ScopeType;
227+
import com.cloud.storage.Snapshot;
226228
import com.cloud.storage.Storage;
227229
import com.cloud.storage.Storage.ImageFormat;
228230
import com.cloud.storage.StorageManager;
@@ -283,6 +285,7 @@
283285
import com.cloud.vm.snapshot.dao.VMSnapshotDao;
284286
import com.google.gson.Gson;
285287

288+
286289
public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMachineManager, VmWorkJobHandler, Listener, Configurable {
287290

288291
public static final String VM_WORK_JOB_HANDLER = VirtualMachineManagerImpl.class.getSimpleName();
@@ -483,8 +486,8 @@ public void registerGuru(final VirtualMachine.Type type, final VirtualMachineGur
483486
@Override
484487
@DB
485488
public void allocate(final String vmInstanceName, final VirtualMachineTemplate template, final ServiceOffering serviceOffering,
486-
final DiskOfferingInfo rootDiskOfferingInfo, final List<DiskOfferingInfo> dataDiskOfferings,
487-
final LinkedHashMap<? extends Network, List<? extends NicProfile>> auxiliaryNetworks, final DeploymentPlan plan, final HypervisorType hyperType, final Map<String, Map<Integer, String>> extraDhcpOptions, final Map<Long, DiskOffering> datadiskTemplateToDiskOfferingMap)
489+
final DiskOfferingInfo rootDiskOfferingInfo, final List<DiskOfferingInfo> dataDiskOfferings,
490+
final LinkedHashMap<? extends Network, List<? extends NicProfile>> auxiliaryNetworks, final DeploymentPlan plan, final HypervisorType hyperType, final Map<String, Map<Integer, String>> extraDhcpOptions, final Map<Long, DiskOffering> datadiskTemplateToDiskOfferingMap, Volume volume, Snapshot snapshot)
488491
throws InsufficientCapacityException {
489492

490493
logger.info("allocating virtual machine from template: {} with hostname: {} and {} networks", template, vmInstanceName, auxiliaryNetworks.size());
@@ -522,7 +525,7 @@ public void allocate(final String vmInstanceName, final VirtualMachineTemplate t
522525

523526
logger.debug("Allocating disks for {}", persistedVm);
524527

525-
allocateRootVolume(persistedVm, template, rootDiskOfferingInfo, owner, rootDiskSizeFinal);
528+
allocateRootVolume(persistedVm, template, rootDiskOfferingInfo, owner, rootDiskSizeFinal, volume, snapshot);
526529

527530
// Create new Volume context and inject event resource type, id and details to generate VOLUME.CREATE event for the ROOT disk.
528531
CallContext volumeContext = CallContext.register(CallContext.current(), ApiCommandResourceType.Volume);
@@ -563,7 +566,7 @@ public void allocate(final String vmInstanceName, final VirtualMachineTemplate t
563566
}
564567
}
565568

566-
private void allocateRootVolume(VMInstanceVO vm, VirtualMachineTemplate template, DiskOfferingInfo rootDiskOfferingInfo, Account owner, Long rootDiskSizeFinal) {
569+
private void allocateRootVolume(VMInstanceVO vm, VirtualMachineTemplate template, DiskOfferingInfo rootDiskOfferingInfo, Account owner, Long rootDiskSizeFinal, Volume volume, Snapshot snapshot) {
567570
// Create new Volume context and inject event resource type, id and details to generate VOLUME.CREATE event for the ROOT disk.
568571
CallContext volumeContext = CallContext.register(CallContext.current(), ApiCommandResourceType.Volume);
569572
try {
@@ -575,7 +578,7 @@ private void allocateRootVolume(VMInstanceVO vm, VirtualMachineTemplate template
575578
logger.debug("%s has format [{}]. Skipping ROOT volume [{}] allocation.", template.toString(), ImageFormat.BAREMETAL, rootVolumeName);
576579
} else {
577580
volumeMgr.allocateTemplatedVolumes(Type.ROOT, rootVolumeName, rootDiskOfferingInfo.getDiskOffering(), rootDiskSizeFinal,
578-
rootDiskOfferingInfo.getMinIops(), rootDiskOfferingInfo.getMaxIops(), template, vm, owner);
581+
rootDiskOfferingInfo.getMinIops(), rootDiskOfferingInfo.getMaxIops(), template, vm, owner, volume, snapshot);
579582
}
580583
} finally {
581584
// Remove volumeContext and pop vmContext back
@@ -585,9 +588,9 @@ private void allocateRootVolume(VMInstanceVO vm, VirtualMachineTemplate template
585588

586589
@Override
587590
public void allocate(final String vmInstanceName, final VirtualMachineTemplate template, final ServiceOffering serviceOffering,
588-
final LinkedHashMap<? extends Network, List<? extends NicProfile>> networks, final DeploymentPlan plan, final HypervisorType hyperType) throws InsufficientCapacityException {
591+
final LinkedHashMap<? extends Network, List<? extends NicProfile>> networks, final DeploymentPlan plan, final HypervisorType hyperType, Volume volume, Snapshot snapshot) throws InsufficientCapacityException {
589592
DiskOffering diskOffering = _diskOfferingDao.findById(serviceOffering.getDiskOfferingId());
590-
allocate(vmInstanceName, template, serviceOffering, new DiskOfferingInfo(diskOffering), new ArrayList<>(), networks, plan, hyperType, null, null);
593+
allocate(vmInstanceName, template, serviceOffering, new DiskOfferingInfo(diskOffering), new ArrayList<>(), networks, plan, hyperType, null, null, volume, snapshot);
591594
}
592595

593596
VirtualMachineGuru getVmGuru(final VirtualMachine vm) {

0 commit comments

Comments
 (0)