Skip to content

Commit f46fad8

Browse files
committed
Create multiple data volumes for createVMFromBackup api and ui
1 parent 7e3f083 commit f46fad8

File tree

13 files changed

+150
-323
lines changed

13 files changed

+150
-323
lines changed

api/src/main/java/com/cloud/storage/VolumeApiService.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import java.util.List;
2323
import java.util.Map;
2424

25-
import com.cloud.offering.DiskOfferingInfo;
2625
import com.cloud.utils.Pair;
2726
import org.apache.cloudstack.api.command.user.volume.AssignVolumeCmd;
2827
import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd;
@@ -107,8 +106,6 @@ public interface VolumeApiService {
107106

108107
Volume attachVolumeToVM(AttachVolumeCmd command);
109108

110-
boolean createAndAttachVolumes(Long vmId, List<DiskOfferingInfo> diskOfferings, Long totalSize, Long zoneId, Long ownerId) throws ResourceAllocationException;
111-
112109
Volume attachVolumeToVM(Long vmId, Long volumeId, Long deviceId, Boolean allowAttachForSharedFS);
113110

114111
Volume detachVolumeViaDestroyVM(long vmId, long volumeId);

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

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

19-
import java.util.List;
20-
2119
import javax.inject.Inject;
2220

2321
import org.apache.cloudstack.acl.RoleType;
@@ -29,10 +27,14 @@
2927
import org.apache.cloudstack.api.ServerApiException;
3028
import org.apache.cloudstack.api.command.user.UserCmd;
3129
import org.apache.cloudstack.api.response.BackupResponse;
32-
import org.apache.cloudstack.api.response.DiskOfferingResponse;
3330
import org.apache.cloudstack.api.response.UserVmResponse;
3431
import org.apache.cloudstack.backup.BackupManager;
3532

33+
import com.cloud.exception.ConcurrentOperationException;
34+
import com.cloud.exception.InsufficientCapacityException;
35+
import com.cloud.exception.InsufficientServerCapacityException;
36+
import com.cloud.exception.ResourceAllocationException;
37+
import com.cloud.exception.ResourceUnavailableException;
3638
import com.cloud.uservm.UserVm;
3739
import com.cloud.vm.VirtualMachine;
3840

@@ -57,51 +59,10 @@ public class CreateVMFromBackupCmd extends DeployVMCmd implements UserCmd {
5759
description = "backup ID to create the VM from")
5860
private Long backupId;
5961

60-
@Parameter(name = ApiConstants.DISK_OFFERING_IDS,
61-
type = CommandType.LIST,
62-
collectionType = CommandType.UUID,
63-
entityType = DiskOfferingResponse.class,
64-
description = "list of disk offering ids to be used by the data volumes of the vm.")
65-
private List<Long> diskOfferingIds;
66-
67-
@Parameter(name = ApiConstants.DISK_SIZES,
68-
type = CommandType.LIST,
69-
collectionType = CommandType.LONG,
70-
description = "list of volume sizes to be used by the data volumes of the vm for custom disk offering.")
71-
private List<Long> diskSizes;
72-
73-
@Parameter(name = ApiConstants.MIN_IOPS,
74-
type = CommandType.LIST,
75-
collectionType = CommandType.LONG,
76-
description = "list of minIops to be used by the data volumes of the vm for custom disk offering.")
77-
private List<Long> minIops;
78-
79-
@Parameter(name = ApiConstants.MAX_IOPS,
80-
type = CommandType.LIST,
81-
collectionType = CommandType.LONG,
82-
description = "list of maxIops to be used by the data volumes of the vm for custom disk offering.")
83-
private List<Long> maxIops;
84-
8562
public Long getBackupId() {
8663
return backupId;
8764
}
8865

89-
public List<Long> getDiskOfferingIds() {
90-
return diskOfferingIds;
91-
}
92-
93-
public List<Long> getDiskSizes() {
94-
return diskSizes;
95-
}
96-
97-
public List<Long> getMinIops() {
98-
return minIops;
99-
}
100-
101-
public List<Long> getMaxIops() {
102-
return maxIops;
103-
}
104-
10566
@Override
10667
public void create() {
10768
UserVm vm;
@@ -110,9 +71,22 @@ public void create() {
11071
if (vm != null) {
11172
setEntityId(vm.getId());
11273
setEntityUuid(vm.getUuid());
74+
} else {
75+
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to deploy vm");
11376
}
114-
} catch (Exception e) {
115-
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create vm due to exception: " + e.getMessage());
77+
} catch (InsufficientCapacityException ex) {
78+
logger.info(ex);
79+
logger.trace(ex.getMessage(), ex);
80+
throw new ServerApiException(ApiErrorCode.INSUFFICIENT_CAPACITY_ERROR, ex.getMessage());
81+
} catch (ResourceUnavailableException ex) {
82+
logger.warn("Exception: ", ex);
83+
throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, ex.getMessage());
84+
} catch (ConcurrentOperationException ex) {
85+
logger.warn("Exception: ", ex);
86+
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage());
87+
} catch (ResourceAllocationException ex) {
88+
logger.warn("Exception: ", ex);
89+
throw new ServerApiException(ApiErrorCode.RESOURCE_ALLOCATION_ERROR, ex.getMessage());
11690
}
11791
}
11892

@@ -121,9 +95,27 @@ public void execute () {
12195
UserVm vm = null;
12296
try {
12397
vm = _userVmService.restoreVMFromBackup(this);
124-
} catch (Exception e) {
125-
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create vm due to exception: " + e.getMessage());
98+
} catch (ResourceUnavailableException ex) {
99+
logger.warn("Exception: ", ex);
100+
throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, ex.getMessage());
101+
} catch (ResourceAllocationException ex) {
102+
logger.warn("Exception: ", ex);
103+
throw new ServerApiException(ApiErrorCode.RESOURCE_ALLOCATION_ERROR, ex.getMessage());
104+
} catch (ConcurrentOperationException ex) {
105+
logger.warn("Exception: ", ex);
106+
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage());
107+
} catch (InsufficientCapacityException ex) {
108+
StringBuilder message = new StringBuilder(ex.getMessage());
109+
if (ex instanceof InsufficientServerCapacityException) {
110+
if (((InsufficientServerCapacityException)ex).isAffinityApplied()) {
111+
message.append(", Please check the affinity groups provided, there may not be sufficient capacity to follow them");
112+
}
113+
}
114+
logger.info(String.format("%s: %s", message.toString(), ex.getLocalizedMessage()));
115+
logger.debug(message.toString(), ex);
116+
throw new ServerApiException(ApiErrorCode.INSUFFICIENT_CAPACITY_ERROR, message.toString());
126117
}
118+
127119
if (vm != null) {
128120
UserVmResponse response = _responseGenerator.createUserVmResponse(getResponseView(), "virtualmachine", vm).get(0);
129121
response.setResponseName(getCommandName());

api/src/main/java/org/apache/cloudstack/backup/Backup.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,4 +146,5 @@ public String toString() {
146146
List<VolumeInfo> getBackedUpVolumes();
147147
long getZoneId();
148148
Map<String, String> getDetails();
149+
String getDetail(String name);
149150
}

api/src/main/java/org/apache/cloudstack/backup/BackupManager.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@
2828
import org.apache.cloudstack.framework.config.ConfigKey;
2929
import org.apache.cloudstack.framework.config.Configurable;
3030

31-
import com.cloud.exception.ResourceAllocationException;
3231
import com.cloud.exception.ResourceUnavailableException;
32+
import com.cloud.offering.DiskOfferingInfo;
3333
import com.cloud.utils.Pair;
3434
import com.cloud.utils.component.Manager;
3535
import com.cloud.utils.component.PluggableService;
@@ -159,7 +159,7 @@ public interface BackupManager extends BackupService, Configurable, PluggableSer
159159

160160
BackupOffering updateBackupOffering(UpdateBackupOfferingCmd updateBackupOfferingCmd);
161161

162-
boolean createDataVolumesForRestore(Long backupId, Long vmId, List<Long> diskOfferingIds, List<Long> diskSizes, List<Long> minIops, List<Long> maxIops) throws ResourceAllocationException;
162+
List<DiskOfferingInfo> getDataDiskOfferingListFromBackup(Backup backup);
163163

164164
Map<String, String> getBackupVmDetails(VirtualMachine vm);
165165

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -520,16 +520,15 @@ public void allocate(final String vmInstanceName, final VirtualMachineTemplate t
520520
// Create new Volume context and inject event resource type, id and details to generate VOLUME.CREATE event for the ROOT disk.
521521
CallContext volumeContext = CallContext.register(CallContext.current(), ApiCommandResourceType.Volume);
522522
try {
523+
int diskNumber = 1;
523524
if (dataDiskOfferings != null) {
524-
int diskNumber = 1;
525525
for (final DiskOfferingInfo dataDiskOfferingInfo : dataDiskOfferings) {
526526
volumeMgr.allocateRawVolume(Type.DATADISK, "DATA-" + persistedVm.getId() + "-" + String.valueOf(diskNumber), dataDiskOfferingInfo.getDiskOffering(), dataDiskOfferingInfo.getSize(),
527527
dataDiskOfferingInfo.getMinIops(), dataDiskOfferingInfo.getMaxIops(), persistedVm, template, owner, Long.valueOf(diskNumber));
528528
diskNumber++;
529529
}
530530
}
531531
if (datadiskTemplateToDiskOfferingMap != null && !datadiskTemplateToDiskOfferingMap.isEmpty()) {
532-
int diskNumber = 1;
533532
for (Entry<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap : datadiskTemplateToDiskOfferingMap.entrySet()) {
534533
DiskOffering diskOffering = dataDiskTemplateToDiskOfferingMap.getValue();
535534
long diskOfferingSize = diskOffering.getDiskSize() / (1024 * 1024 * 1024);

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ public VirtualMachineEntity createVirtualMachine(String id, String owner, String
242242

243243
dataDiskOfferings.add(dataDiskOfferingInfo);
244244
}
245-
} else {
245+
} else if (dataDiskOfferingsInfo != null){
246246
dataDiskOfferings.addAll(dataDiskOfferingsInfo);
247247
}
248248

engine/schema/src/main/java/org/apache/cloudstack/backup/BackupVO.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ public void setDetail(String name, String value) {
239239
this.details.put(name, value);
240240
}
241241

242+
@Override
242243
public String getDetail(String name) {
243244
return this.details.get(name);
244245
}

server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,6 @@
128128
import com.cloud.api.ApiDBUtils;
129129
import com.cloud.configuration.Config;
130130
import com.cloud.configuration.ConfigurationManager;
131-
import com.cloud.configuration.Resource;
132131
import com.cloud.configuration.Resource.ResourceType;
133132
import com.cloud.dc.ClusterDetailsDao;
134133
import com.cloud.dc.DataCenter;
@@ -154,7 +153,6 @@
154153
import com.cloud.hypervisor.HypervisorCapabilitiesVO;
155154
import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao;
156155
import com.cloud.offering.DiskOffering;
157-
import com.cloud.offering.DiskOfferingInfo;
158156
import com.cloud.org.Grouping;
159157
import com.cloud.projects.Project;
160158
import com.cloud.projects.ProjectManager;
@@ -2543,36 +2541,6 @@ private Volume orchestrateAttachVolumeToVM(Long vmId, Long volumeId, Long device
25432541
return newVol;
25442542
}
25452543

2546-
@Override
2547-
public boolean createAndAttachVolumes(Long vmId, List<DiskOfferingInfo> diskOfferings, Long totalSize, Long zoneId, Long ownerId) throws ResourceAllocationException {
2548-
Account caller = CallContext.current().getCallingAccount();
2549-
Account owner = _accountMgr.getAccount(ownerId);
2550-
List<Long> volumesId = new ArrayList<>();
2551-
boolean error = false;
2552-
2553-
_resourceLimitMgr.checkResourceLimit(owner, Resource.ResourceType.volume, diskOfferings.size());
2554-
_resourceLimitMgr.checkResourceLimit(owner, Resource.ResourceType.primary_storage, totalSize);
2555-
2556-
for (DiskOfferingInfo diskOfferingInfo : diskOfferings) {
2557-
DiskOffering diskOffering = diskOfferingInfo.getDiskOffering();
2558-
VolumeVO volume = commitVolume(null, caller, owner, true, zoneId, diskOffering.getId(),
2559-
diskOffering.getProvisioningType(), diskOfferingInfo.getSize(), diskOfferingInfo.getMinIops(),
2560-
diskOfferingInfo.getMaxIops(), null, getRandomVolumeName(), _uuidMgr.generateUuid(Volume.class, null), new HashMap<>());
2561-
if (volume == null) {
2562-
error = true;
2563-
break;
2564-
}
2565-
volumesId.add(volume.getId());
2566-
attachVolumeToVM(vmId, volume.getId(), null, false);
2567-
}
2568-
if (error) {
2569-
for (Long volumeId : volumesId) {
2570-
destroyVolume(volumeId, caller, true, true);
2571-
}
2572-
}
2573-
return !error;
2574-
}
2575-
25762544
public Volume attachVolumeToVM(Long vmId, Long volumeId, Long deviceId, Boolean allowAttachForSharedFS) {
25772545
Account caller = CallContext.current().getCallingAccount();
25782546

server/src/main/java/com/cloud/vm/UserVmManagerImpl.java

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8862,6 +8862,14 @@ public UserVm allocateVMFromBackup(CreateVMFromBackupCmd cmd) throws Insufficien
88628862
}
88638863
}
88648864

8865+
List<DiskOfferingInfo> dataDiskOfferingsInfo = cmd.getDataDiskOfferingsInfo();
8866+
if (dataDiskOfferingsInfo != null && diskOfferingId != null) {
8867+
new InvalidParameterValueException("Cannot specify both disk offering id and data disk offering details");
8868+
}
8869+
if (dataDiskOfferingsInfo == null && diskOfferingId == null) {
8870+
dataDiskOfferingsInfo = backupManager.getDataDiskOfferingListFromBackup(backup);
8871+
}
8872+
88658873
DiskOffering diskOfferingMappedInServiceOffering = _entityMgr.findById(DiskOffering.class, serviceOffering.getDiskOfferingId());
88668874
if (diskOfferingMappedInServiceOffering.isUseLocalStorage()) {
88678875
throw new InvalidParameterValueException("Local storage disk offering not supported for instance created from backup");
@@ -8913,23 +8921,23 @@ public UserVm allocateVMFromBackup(CreateVMFromBackupCmd cmd) throws Insufficien
89138921
throw new InvalidParameterValueException("Can't specify network Ids in Basic zone");
89148922
} else {
89158923
vm = createBasicSecurityGroupVirtualMachine(zone, serviceOffering, template, getSecurityGroupIdList(cmd, zone, template, owner), owner, name, displayName, diskOfferingId,
8916-
size , null, null , cmd.getHypervisor(), cmd.getHttpMethod(), null, null, null, sshKeyPairs, ipToNetworkMap, addrs, null , null , cmd.getAffinityGroupIdList(),
8924+
size , dataDiskOfferingsInfo, null , cmd.getHypervisor(), cmd.getHttpMethod(), null, null, null, sshKeyPairs, ipToNetworkMap, addrs, null , null , cmd.getAffinityGroupIdList(),
89178925
cmd.getDetails(), cmd.getCustomId(), cmd.getDhcpOptionsMap(),
89188926
dataDiskTemplateToDiskOfferingMap, userVmOVFProperties, false, overrideDiskOfferingId);
89198927
}
89208928
} else {
89218929
if (_networkModel.checkSecurityGroupSupportForNetwork(owner, zone, networkIds,
89228930
cmd.getSecurityGroupIdList())) {
89238931
vm = createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, template, networkIds, getSecurityGroupIdList(cmd, zone, template, owner), owner, name,
8924-
displayName, diskOfferingId, size, null, null, cmd.getHypervisor(), cmd.getHttpMethod(), null, null, null, sshKeyPairs, ipToNetworkMap, addrs, null, null,
8932+
displayName, diskOfferingId, size, dataDiskOfferingsInfo, null, cmd.getHypervisor(), cmd.getHttpMethod(), null, null, null, sshKeyPairs, ipToNetworkMap, addrs, null, null,
89258933
cmd.getAffinityGroupIdList(), cmd.getDetails(), cmd.getCustomId(), cmd.getDhcpOptionsMap(),
89268934
dataDiskTemplateToDiskOfferingMap, userVmOVFProperties, false, overrideDiskOfferingId, null);
89278935

89288936
} else {
89298937
if (cmd.getSecurityGroupIdList() != null && !cmd.getSecurityGroupIdList().isEmpty()) {
89308938
throw new InvalidParameterValueException("Can't create vm with security groups; security group feature is not enabled per zone");
89318939
}
8932-
vm = createAdvancedVirtualMachine(zone, serviceOffering, template, networkIds, owner, name, displayName, diskOfferingId, size, null, null,
8940+
vm = createAdvancedVirtualMachine(zone, serviceOffering, template, networkIds, owner, name, displayName, diskOfferingId, size, dataDiskOfferingsInfo, null,
89338941
cmd.getHypervisor(), cmd.getHttpMethod(), null, null, null, sshKeyPairs, ipToNetworkMap, addrs, null, null, cmd.getAffinityGroupIdList(), cmd.getDetails(),
89348942
cmd.getCustomId(), cmd.getDhcpOptionsMap(), dataDiskTemplateToDiskOfferingMap, userVmOVFProperties, false, null, overrideDiskOfferingId);
89358943
}
@@ -8943,18 +8951,7 @@ public UserVm restoreVMFromBackup(CreateVMFromBackupCmd cmd) throws ResourceUnav
89438951
long vmId = cmd.getEntityId();
89448952
Map<Long, DiskOffering> diskOfferingMap = cmd.getDataDiskTemplateToDiskOfferingMap();
89458953
Map<VirtualMachineProfile.Param, Object> additonalParams = new HashMap<>();
8946-
UserVm vm;
8947-
try {
8948-
vm = startVirtualMachine(vmId, null, null, null, diskOfferingMap, additonalParams, null);
8949-
} catch (ResourceUnavailableException e) {
8950-
throw new CloudRuntimeException("Unable to start the instance " + e);
8951-
}
8952-
8953-
try {
8954-
backupManager.createDataVolumesForRestore(cmd.getBackupId(), vmId, cmd.getDataDiskOfferingsInfo());
8955-
} catch (Exception e) {
8956-
throw new CloudRuntimeException("Unable to create data volumes " + e);
8957-
}
8954+
UserVm vm = startVirtualMachine(vmId, null, null, null, diskOfferingMap, additonalParams, null);
89588955

89598956
boolean status = false;
89608957
try {
@@ -8974,11 +8971,7 @@ public UserVm restoreVMFromBackup(CreateVMFromBackupCmd cmd) throws ResourceUnav
89748971
backupManager.restoreBackupToVM(cmd.getBackupId(), vmId);
89758972

89768973
if (cmd.getStartVm()) {
8977-
try {
8978-
vm = startVirtualMachine(vmId, null, null, null, diskOfferingMap, additonalParams, null);
8979-
} catch (ResourceUnavailableException e) {
8980-
throw new CloudRuntimeException("Unable to start the instance " + e);
8981-
}
8974+
vm = startVirtualMachine(vmId, null, null, null, diskOfferingMap, additonalParams, null);
89828975
}
89838976
return vm;
89848977
}

0 commit comments

Comments
 (0)