harikrishna-patnala commented on code in PR #13101:
URL: https://github.com/apache/cloudstack/pull/13101#discussion_r3186056265
##########
server/src/main/java/com/cloud/template/TemplateManagerImpl.java:
##########
@@ -1402,20 +1445,114 @@ private boolean attachISOToVM(long vmId, long isoId,
boolean attach, boolean for
return (a != null && a.getResult());
}
- private boolean attachISOToVM(long vmId, long userId, long isoId, boolean
attach, boolean forced, boolean isVirtualRouter) {
+ boolean attachISOToVM(long vmId, long userId, long isoId, boolean attach,
boolean forced, boolean isVirtualRouter) {
UserVmVO vm = _userVmDao.findById(vmId);
VMTemplateVO iso = _tmpltDao.findById(isoId);
- boolean success = attachISOToVM(vmId, isoId, attach, forced,
isVirtualRouter);
- if (success && attach && !isVirtualRouter) {
+ int targetSlot = attach ? chooseAttachSlot(vmId, vm) :
findAttachedSlot(vmId, vm, isoId);
+ boolean success = attachISOToVM(vmId, isoId, targetSlot, attach,
forced, isVirtualRouter);
+ if (!success || isVirtualRouter) {
+ return success;
+ }
+ if (attach) {
+ persistIsoAttachment(vmId, vm, iso, targetSlot);
+ } else {
+ persistIsoDetachment(vmId, vm, isoId, targetSlot);
+ }
+ return success;
+ }
+
+ private int chooseAttachSlot(long vmId, UserVmVO vm) {
+ if (vm.getIsoId() == null) {
+ return CDROM_PRIMARY_DEVICE_SEQ;
+ }
+ VmIsoMapVO highest = highestCdromMapEntry(vmId);
+ return highest == null ? CDROM_PRIMARY_DEVICE_SEQ + 1 :
highest.getDeviceSeq() + 1;
+ }
+
+ private int findAttachedSlot(long vmId, UserVmVO vm, long isoId) {
+ if (vm.getIsoId() != null && vm.getIsoId() == isoId) {
+ return CDROM_PRIMARY_DEVICE_SEQ;
+ }
+ VmIsoMapVO entry = _vmIsoMapDao.findByVmIdIsoId(vmId, isoId);
+ return entry != null ? entry.getDeviceSeq() : CDROM_PRIMARY_DEVICE_SEQ;
+ }
+
+ private void persistIsoAttachment(long vmId, UserVmVO vm, VMTemplateVO
iso, int slot) {
+ if (slot == CDROM_PRIMARY_DEVICE_SEQ) {
vm.setIsoId(iso.getId());
_userVmDao.update(vmId, vm);
+ } else {
+ _vmIsoMapDao.persist(new VmIsoMapVO(vmId, iso.getId(), slot));
}
- if (success && !attach && !isVirtualRouter) {
+ }
+
+ private void persistIsoDetachment(long vmId, UserVmVO vm, long isoId, int
slot) {
+ if (slot == CDROM_PRIMARY_DEVICE_SEQ) {
vm.setIsoId(null);
_userVmDao.update(vmId, vm);
+ return;
}
- return success;
+ VmIsoMapVO entry = _vmIsoMapDao.findByVmIdIsoId(vmId, isoId);
+ if (entry != null) {
+ _vmIsoMapDao.remove(entry.getId());
+ }
+ }
+
+ VmIsoMapVO highestCdromMapEntry(long vmId) {
+ VmIsoMapVO highest = null;
+ for (VmIsoMapVO row : _vmIsoMapDao.listByVmId(vmId)) {
+ if (highest == null || row.getDeviceSeq() >
highest.getDeviceSeq()) {
+ highest = row;
+ }
+ }
+ return highest;
+ }
+
+ Long resolveIsoIdForDetach(Long primaryIsoId, List<VmIsoMapVO> extras,
Long isoParamId) {
+ if (isoParamId != null) {
+ boolean attached = (primaryIsoId != null &&
primaryIsoId.equals(isoParamId))
+ || extras.stream().anyMatch(r -> r.getIsoId() ==
isoParamId);
+ if (!attached) {
+ throw new InvalidParameterValueException("The specified ISO is
not attached to this Instance.");
+ }
+ return isoParamId;
+ }
+ int totalAttached = (primaryIsoId != null ? 1 : 0) + extras.size();
+ if (totalAttached == 0) {
+ throw new InvalidParameterValueException("The specified instance
has no ISO attached to it.");
+ }
+ if (totalAttached > 1) {
+ throw new InvalidParameterValueException("Instance has more than
one ISO attached; specify the 'id' parameter to choose which to detach.");
+ }
+ return primaryIsoId != null ? primaryIsoId : extras.get(0).getIsoId();
+ }
+
+ boolean isIsoAlreadyAttached(long vmId, Long primaryIsoId, long isoId) {
+ if (primaryIsoId != null && primaryIsoId.equals(isoId)) {
+ return true;
+ }
+ return _vmIsoMapDao.findByVmIdIsoId(vmId, isoId) != null;
+ }
+
+ private void enforceCdromAttachLimits(long vmId, UserVm vm, long isoId) {
+ Long primaryIsoId = vm.getIsoId();
+ if (isIsoAlreadyAttached(vmId, primaryIsoId, isoId)) {
+ throw new InvalidParameterValueException("The specified ISO is
already attached to this Instance.");
+ }
+ int effectiveMax = effectiveMaxCdroms(vm);
+ int attached = (primaryIsoId != null ? 1 : 0) +
_vmIsoMapDao.listByVmId(vmId).size();
+ if (attached >= effectiveMax) {
+ throw new InvalidParameterValueException(String.format(
+ "Instance has reached the maximum of %d attached
CD-ROM(s); detach one before attaching another.", effectiveMax));
+ }
+ }
+
+ private int effectiveMaxCdroms(VirtualMachine vm) {
+ int globalCap = VmCdromMaxCount.value();
+ // hda is root on i440fx/IDE, leaving hdc/hdd available for cdroms.
+ int hypervisorCap = (vm.getHypervisorType() == HypervisorType.KVM) ? 2
: 1;
Review Comment:
Instead of hardcoding these numbers, is there a way to fetch from the
hypervisor ?
and I feel even if there is no way to fetch from hypervisor, we can still do
a check if the config value is more than expected value (2 for KVM and 1 for
others) and log an error message and let the operation fail.
I'm just thinking if in future if hypervisor increases the supported value
we dont have do any code changes.
##########
engine/components-api/src/main/java/com/cloud/template/TemplateManager.java:
##########
@@ -64,6 +64,17 @@ public interface TemplateManager {
true,
ConfigKey.Scope.Global);
+ ConfigKey<Integer> VmCdromMaxCount = new ConfigKey<Integer>("Advanced",
+ Integer.class,
+ "vm.cdrom.max.count", "1",
+ "Maximum number of CD-ROM drives per VM.",
+ true,
+ ConfigKey.Scope.Global);
Review Comment:
as this is the hypervisor dependent, is it better to keep the scope as
Cluster ?
If you are making this change, please update the getters of this config to
read from clusterId
##########
api/src/main/java/org/apache/cloudstack/api/command/user/iso/DetachIsoCmd.java:
##########
@@ -51,6 +52,10 @@ public class DetachIsoCmd extends BaseAsyncCmd implements
UserCmd {
description = "If true, ejects the ISO before detaching on VMware.
Default: false", since = "4.15.1")
protected Boolean forced;
+ @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType =
TemplateResponse.class,
+ description = "The ID of the ISO to detach. Required when the
Instance has more than one ISO attached.")
Review Comment:
```suggestion
description = "The ID of the ISO to detach. Required when the
Instance has more than one ISO attached.", since = "4.23.0")
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]