Skip to content

Commit 4617be4

Browse files
vmware: Fix template upload from local (#4555)
Update the guest OS from the OVF file after upload is completed This PR fixes the template upload from local on VMware Co-authored-by: dahn <daan.hoogland@gmail.com> Co-authored-by: dahn <daan.hoogland@gmail.com>
1 parent 874c7be commit 4617be4

File tree

8 files changed

+111
-55
lines changed

8 files changed

+111
-55
lines changed

api/src/main/java/org/apache/cloudstack/api/command/user/template/GetUploadParamsForTemplateCmd.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import java.util.Collection;
2323
import java.util.Map;
2424

25+
import com.cloud.hypervisor.Hypervisor;
2526
import org.apache.cloudstack.acl.RoleType;
2627
import org.apache.cloudstack.api.APICommand;
2728
import org.apache.cloudstack.api.AbstractGetUploadParamsCmd;
@@ -51,7 +52,8 @@ public class GetUploadParamsForTemplateCmd extends AbstractGetUploadParamsCmd {
5152
@Parameter(name = ApiConstants.HYPERVISOR, type = CommandType.STRING, required = true, description = "the target hypervisor for the template")
5253
private String hypervisor;
5354

54-
@Parameter(name = ApiConstants.OS_TYPE_ID, type = CommandType.UUID, entityType = GuestOSResponse.class, required = true, description = "the ID of the OS Type that best represents the OS of this template.")
55+
@Parameter(name = ApiConstants.OS_TYPE_ID, type = CommandType.UUID, entityType = GuestOSResponse.class, required = false,
56+
description = "the ID of the OS Type that best represents the OS of this template. Not required for VMware as the guest OS is obtained from the OVF file.")
5557
private Long osTypeId;
5658

5759
@Parameter(name = ApiConstants.BITS, type = CommandType.INTEGER, description = "32 or 64 bits support. 64 by default")
@@ -168,6 +170,12 @@ private void validateRequest() {
168170
if (getZoneId() <= 0) {
169171
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "invalid zoneid");
170172
}
173+
if (!hypervisor.equalsIgnoreCase(Hypervisor.HypervisorType.VMware.toString()) && osTypeId == null) {
174+
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Missing parameter ostypeid");
175+
}
176+
if (hypervisor.equalsIgnoreCase(Hypervisor.HypervisorType.VMware.toString()) && osTypeId != null) {
177+
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Invalid parameter ostypeid, not applicable for VMware");
178+
}
171179
}
172180

173181
@Override

core/src/main/java/org/apache/cloudstack/storage/command/UploadStatusAnswer.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
package org.apache.cloudstack.storage.command;
2121

2222
import com.cloud.agent.api.Answer;
23+
import com.cloud.utils.Pair;
2324

2425
public class UploadStatusAnswer extends Answer {
2526
public static enum UploadStatus {
@@ -31,6 +32,8 @@ public static enum UploadStatus {
3132
private long physicalSize = 0;
3233
private String installPath = null;
3334
private int downloadPercent = 0;
35+
private Pair<String, String> guestOsInfo;
36+
private String minimumHardwareVersion;
3437

3538
protected UploadStatusAnswer() {
3639
}
@@ -85,4 +88,20 @@ public int getDownloadPercent() {
8588
public void setDownloadPercent(int downloadPercent) {
8689
this.downloadPercent = downloadPercent;
8790
}
91+
92+
public Pair<String, String> getGuestOsInfo() {
93+
return guestOsInfo;
94+
}
95+
96+
public void setGuestOsInfo(Pair<String, String> guestOsInfo) {
97+
this.guestOsInfo = guestOsInfo;
98+
}
99+
100+
public void setMinimumHardwareVersion(String minimumHardwareVersion) {
101+
this.minimumHardwareVersion = minimumHardwareVersion;
102+
}
103+
104+
public String getMinimumHardwareVersion() {
105+
return minimumHardwareVersion;
106+
}
88107
}

engine/storage/src/main/java/org/apache/cloudstack/storage/image/deployasis/DeployAsIsHelperImpl.java

Lines changed: 21 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,6 @@
1919
package org.apache.cloudstack.storage.image.deployasis;
2020

2121
import com.cloud.agent.api.storage.DownloadAnswer;
22-
import com.cloud.agent.api.to.DataStoreTO;
23-
import com.cloud.agent.api.to.DataTO;
24-
import com.cloud.agent.api.to.DiskTO;
2522
import com.cloud.agent.api.to.NicTO;
2623
import com.cloud.agent.api.to.OVFInformationTO;
2724
import com.cloud.agent.api.to.deployasis.OVFConfigurationTO;
@@ -39,10 +36,8 @@
3936
import com.cloud.storage.GuestOSCategoryVO;
4037
import com.cloud.storage.GuestOSHypervisorVO;
4138
import com.cloud.storage.GuestOSVO;
42-
import com.cloud.storage.VMTemplateStoragePoolVO;
4339
import com.cloud.storage.VMTemplateStorageResourceAssoc;
4440
import com.cloud.storage.VMTemplateVO;
45-
import com.cloud.storage.Volume;
4641
import com.cloud.storage.dao.GuestOSCategoryDao;
4742
import com.cloud.storage.dao.GuestOSDao;
4843
import com.cloud.storage.dao.GuestOSHypervisorDao;
@@ -57,7 +52,6 @@
5752
import com.google.gson.GsonBuilder;
5853
import com.cloud.agent.api.to.deployasis.OVFNetworkTO;
5954
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
60-
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
6155
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
6256
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
6357
import org.apache.commons.collections.CollectionUtils;
@@ -155,17 +149,16 @@ public boolean persistTemplateDeployAsIsDetails(long templateId, DownloadAnswer
155149
}
156150

157151
/**
158-
* Handle the guest OS read from the OVF and try to match it to an existing guest OS in DB.
159-
* If the guest OS cannot be mapped to an existing guest OS in DB, then create it and create support for hypervisor versions.
160-
* Roll back actions in case of unexpected erros
152+
* Returns the mapped guest OS from the OVF file of the template to the CloudStack database OS ID
161153
*/
162-
private void handleGuestOsFromOVFDescriptor(long templateId, String guestOsType, String guestOsDescription,
163-
String minimumHardwareVersion) {
154+
public Long retrieveTemplateGuestOsIdFromGuestOsInfo(long templateId, String guestOsType, String guestOsDescription,
155+
String minimumHardwareVersion) {
164156
VMTemplateVO template = templateDao.findById(templateId);
165157
Hypervisor.HypervisorType hypervisor = template.getHypervisorType();
166158
if (hypervisor != Hypervisor.HypervisorType.VMware) {
167-
return;
159+
return null;
168160
}
161+
169162
String minimumHypervisorVersion = getMinimumSupportedHypervisorVersionForHardwareVersion(minimumHardwareVersion);
170163
LOGGER.info("Minimum hardware version " + minimumHardwareVersion + " matched to hypervisor version " + minimumHypervisorVersion + ". " +
171164
"Checking guest OS supporting this version");
@@ -175,14 +168,27 @@ private void handleGuestOsFromOVFDescriptor(long templateId, String guestOsType,
175168

176169
if (CollectionUtils.isNotEmpty(guestOsMappings)) {
177170
GuestOSHypervisorVO mapping = guestOsMappings.get(0);
178-
long guestOsId = mapping.getGuestOsId();
179-
LOGGER.info("Updating deploy-as-is template guest OS to " + guestOsType);
180-
updateTemplateGuestOsId(template, guestOsId);
171+
return mapping.getGuestOsId();
181172
} else {
182173
throw new CloudRuntimeException("Did not find a guest OS with type " + guestOsType);
183174
}
184175
}
185176

177+
/**
178+
* Handle the guest OS read from the OVF and try to match it to an existing guest OS in DB.
179+
* If the guest OS cannot be mapped to an existing guest OS in DB, then create it and create support for hypervisor versions.
180+
* Roll back actions in case of unexpected errors
181+
*/
182+
private void handleGuestOsFromOVFDescriptor(long templateId, String guestOsType, String guestOsDescription,
183+
String minimumHardwareVersion) {
184+
Long guestOsId = retrieveTemplateGuestOsIdFromGuestOsInfo(templateId, guestOsType, guestOsDescription, minimumHardwareVersion);
185+
if (guestOsId != null) {
186+
LOGGER.info("Updating deploy-as-is template guest OS to " + guestOsType);
187+
VMTemplateVO template = templateDao.findById(templateId);
188+
updateTemplateGuestOsId(template, guestOsId);
189+
}
190+
}
191+
186192
/**
187193
* Updates the deploy-as-is template guest OS doing:
188194
* - Create a new guest OS with the guest OS description parsed from the OVF
@@ -268,38 +274,6 @@ public Map<String, String> getVirtualMachineDeployAsIsProperties(VirtualMachineP
268274
return map;
269275
}
270276

271-
@Override
272-
public String getAllocatedVirtualMachineTemplatePath(VirtualMachineProfile vm, String configuration, String destStoragePool) {
273-
StoragePoolVO storagePoolVO = storagePoolDao.findByUuid(destStoragePool);
274-
VMTemplateStoragePoolVO tmplRef = templateStoragePoolDao.findByPoolTemplate(storagePoolVO.getId(),
275-
vm.getTemplate().getId(), configuration);
276-
if (tmplRef != null) {
277-
return tmplRef.getInstallPath();
278-
}
279-
return null;
280-
}
281-
282-
@Override
283-
public String getAllocatedVirtualMachineDestinationStoragePool(VirtualMachineProfile vm) {
284-
if (vm != null) {
285-
if (CollectionUtils.isNotEmpty(vm.getDisks())) {
286-
for (DiskTO disk : vm.getDisks()) {
287-
if (disk.getType() == Volume.Type.ISO) {
288-
continue;
289-
}
290-
DataTO data = disk.getData();
291-
if (data != null) {
292-
DataStoreTO dataStore = data.getDataStore();
293-
if (dataStore != null) {
294-
return dataStore.getUuid();
295-
}
296-
}
297-
}
298-
}
299-
}
300-
return null;
301-
}
302-
303277
@Override
304278
public Map<Integer, String> getAllocatedVirtualMachineNicsAdapterMapping(VirtualMachineProfile vm, NicTO[] nics) {
305279
Map<Integer, String> map = new HashMap<>();

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
import javax.inject.Inject;
2626
import javax.naming.ConfigurationException;
2727

28+
import com.cloud.hypervisor.Hypervisor;
29+
import com.cloud.utils.Pair;
2830
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
2931
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
3032
import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint;
@@ -44,6 +46,7 @@
4446
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
4547
import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreDao;
4648
import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreVO;
49+
import org.apache.cloudstack.storage.image.deployasis.DeployAsIsHelper;
4750
import org.apache.cloudstack.utils.identity.ManagementServerNode;
4851
import org.apache.log4j.Logger;
4952
import org.springframework.stereotype.Component;
@@ -115,6 +118,8 @@ public class ImageStoreUploadMonitorImpl extends ManagerBase implements ImageSto
115118
private TemplateService templateService;
116119
@Inject
117120
private TemplateJoinDao templateJoinDao;
121+
@Inject
122+
private DeployAsIsHelper deployAsIsHelper;
118123

119124
private long _nodeId;
120125
private ScheduledExecutorService _executor = null;
@@ -407,6 +412,20 @@ public void doInTransactionWithoutResult(TransactionStatus status) {
407412

408413
VMTemplateVO templateUpdate = _templateDao.createForUpdate();
409414
templateUpdate.setSize(answer.getVirtualSize());
415+
if (template.getHypervisorType() == Hypervisor.HypervisorType.VMware) {
416+
Pair<String, String> guestOsInfo = answer.getGuestOsInfo();
417+
String minimumHardwareVersion = answer.getMinimumHardwareVersion();
418+
String osType = guestOsInfo.first();
419+
String osDescription = guestOsInfo.second();
420+
s_logger.info("Guest OS information retrieved from the template: " + osType + " - " + osDescription);
421+
try {
422+
Long guestOsId = deployAsIsHelper.retrieveTemplateGuestOsIdFromGuestOsInfo(template.getId(),
423+
osType, osDescription, minimumHardwareVersion);
424+
templateUpdate.setGuestOSId(guestOsId);
425+
} catch (CloudRuntimeException e) {
426+
s_logger.error("Could not map the guest OS to a CloudStack guest OS", e);
427+
}
428+
}
410429
_templateDao.update(tmpTemplate.getId(), templateUpdate);
411430
// For multi-disk OVA, check and create data disk templates or root disks as details
412431
if (tmpTemplate.getFormat().equals(Storage.ImageFormat.OVA)) {

server/src/main/java/com/cloud/template/TemplateAdapterBase.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -171,9 +171,8 @@ public TemplateProfile prepare(boolean isIso, long userId, String name, String d
171171
requiresHVM = true;
172172
}
173173
if (deployAsIs) {
174-
GuestOS deployAsIsGuestOs = ApiDBUtils.findGuestOSByDisplayName(DeployAsIsConstants.DEFAULT_GUEST_OS_DEPLOY_AS_IS);
175174
s_logger.info("Setting default guest OS for deploy-as-is template while the template registration is not completed");
176-
guestOSId = deployAsIsGuestOs.getId();
175+
guestOSId = getDefaultDeployAsIsGuestOsId();
177176
}
178177
}
179178

@@ -341,12 +340,22 @@ private TemplateProfile prepareUploadParamsInternal(UploadParams params) throws
341340
params.isDynamicallyScalable(), params.isRoutingType() ? TemplateType.ROUTING : TemplateType.USER, params.isDirectDownload(), false);
342341
}
343342

343+
private Long getDefaultDeployAsIsGuestOsId() {
344+
GuestOS deployAsIsGuestOs = ApiDBUtils.findGuestOSByDisplayName(DeployAsIsConstants.DEFAULT_GUEST_OS_DEPLOY_AS_IS);
345+
return deployAsIsGuestOs.getId();
346+
}
347+
344348
@Override
345349
public TemplateProfile prepare(GetUploadParamsForTemplateCmd cmd) throws ResourceAllocationException {
350+
Long osTypeId = cmd.getOsTypeId();
351+
if (osTypeId == null) {
352+
s_logger.info("Setting the default guest OS for deploy-as-is templates while the template upload is not completed");
353+
osTypeId = getDefaultDeployAsIsGuestOsId();
354+
}
346355
UploadParams params = new TemplateUploadParams(CallContext.current().getCallingUserId(), cmd.getName(),
347356
cmd.getDisplayText(), cmd.getBits(), BooleanUtils.toBoolean(cmd.isPasswordEnabled()),
348357
BooleanUtils.toBoolean(cmd.getRequiresHvm()), BooleanUtils.toBoolean(cmd.isPublic()),
349-
BooleanUtils.toBoolean(cmd.isFeatured()), BooleanUtils.toBoolean(cmd.isExtractable()), cmd.getFormat(), cmd.getOsTypeId(),
358+
BooleanUtils.toBoolean(cmd.isFeatured()), BooleanUtils.toBoolean(cmd.isExtractable()), cmd.getFormat(), osTypeId,
350359
cmd.getZoneId(), HypervisorType.getType(cmd.getHypervisor()), cmd.getChecksum(),
351360
cmd.getTemplateTag(), cmd.getEntityOwnerId(), cmd.getDetails(), BooleanUtils.toBoolean(cmd.isSshKeyEnabled()),
352361
BooleanUtils.toBoolean(cmd.isDynamicallyScalable()), BooleanUtils.toBoolean(cmd.isRoutingType()));

engine/storage/src/main/java/org/apache/cloudstack/storage/image/deployasis/DeployAsIsHelper.java renamed to server/src/main/java/org/apache/cloudstack/storage/image/deployasis/DeployAsIsHelper.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,7 @@ public interface DeployAsIsHelper {
2727

2828
boolean persistTemplateDeployAsIsDetails(long templateId, DownloadAnswer answer, TemplateDataStoreVO tmpltStoreVO);
2929
Map<String, String> getVirtualMachineDeployAsIsProperties(VirtualMachineProfile vmId);
30-
31-
String getAllocatedVirtualMachineTemplatePath(VirtualMachineProfile vm, String configuration, String destStoragePool);
32-
String getAllocatedVirtualMachineDestinationStoragePool(VirtualMachineProfile vm);
33-
3430
Map<Integer, String> getAllocatedVirtualMachineNicsAdapterMapping(VirtualMachineProfile vm, NicTO[] nics);
31+
Long retrieveTemplateGuestOsIdFromGuestOsInfo(long templateId, String guestOsType, String guestOsDescription,
32+
String minimumHardwareVersion);
3533
}

services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2278,6 +2278,8 @@ private UploadStatusAnswer execute(UploadStatusCommand cmd) {
22782278
answer.setInstallPath(uploadEntity.getTmpltPath());
22792279
answer.setPhysicalSize(uploadEntity.getPhysicalSize());
22802280
answer.setDownloadPercent(100);
2281+
answer.setGuestOsInfo(uploadEntity.getGuestOsInfo());
2282+
answer.setMinimumHardwareVersion(uploadEntity.getMinimumHardwareVersion());
22812283
uploadEntityStateMap.remove(entityUuid);
22822284
return answer;
22832285
} else if (uploadEntity.getUploadState() == UploadEntity.Status.IN_PROGRESS) {
@@ -3413,6 +3415,14 @@ public String postUpload(String uuid, String filename, long processTimeout) {
34133415
loc.addFormat(info);
34143416
uploadEntity.setVirtualSize(info.virtualSize);
34153417
uploadEntity.setPhysicalSize(info.size);
3418+
if (info.ovfInformationTO != null) {
3419+
if (info.ovfInformationTO.getGuestOsInfo() != null) {
3420+
uploadEntity.setGuestOsInfo(info.ovfInformationTO.getGuestOsInfo());
3421+
}
3422+
if (info.ovfInformationTO.getHardwareSection() != null) {
3423+
uploadEntity.setMinimumHardwareVersion(info.ovfInformationTO.getHardwareSection().getMinimiumHardwareVersion());
3424+
}
3425+
}
34163426
break;
34173427
}
34183428
}

services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/template/UploadEntity.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020

2121
import com.cloud.storage.Storage;
22+
import com.cloud.utils.Pair;
2223

2324
public class UploadEntity {
2425
private long downloadedsize;
@@ -35,6 +36,8 @@ public class UploadEntity {
3536
private String description;
3637
private long contentLength;
3738
private long processTimeout;
39+
private Pair<String, String> guestOsInfo;
40+
private String minimumHardwareVersion;
3841

3942
public static enum ResourceType {
4043
VOLUME, TEMPLATE
@@ -207,4 +210,20 @@ public long getContentLength() {
207210
public void setContentLength(long contentLength) {
208211
this.contentLength = contentLength;
209212
}
213+
214+
public Pair<String, String> getGuestOsInfo() {
215+
return guestOsInfo;
216+
}
217+
218+
public void setGuestOsInfo(Pair<String, String> guestOsInfo) {
219+
this.guestOsInfo = guestOsInfo;
220+
}
221+
222+
public void setMinimumHardwareVersion(String minimumHardwareVersion) {
223+
this.minimumHardwareVersion = minimumHardwareVersion;
224+
}
225+
226+
public String getMinimumHardwareVersion() {
227+
return minimumHardwareVersion;
228+
}
210229
}

0 commit comments

Comments
 (0)