Damans227 commented on code in PR #13101:
URL: https://github.com/apache/cloudstack/pull/13101#discussion_r3189721043


##########
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:
   Runtime fetch isn't possible. **libvirt** don't expose "max CDROMs" as a 
capability; the number falls out of CloudStack's machine-type + bus choices 
_(i440fx + IDE + root takes hda → 2 free slots on KVM)._
   
   So, addressed the second half: flipped `effectiveMaxCdroms` to 
validate-and-throw an error. Misconfigs now fail attach/deploy with the 
recommended max in the message.
   



-- 
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]

Reply via email to