This is an automated email from the ASF dual-hosted git repository.

Pearl1594 pushed a commit to branch ghi14177-nic-reconcile-4.22
in repository https://gitbox.apache.org/repos/asf/cloudstack.git

commit 99d9c27f529333d85f9ef02cfc02acd9e5f48431
Author: Pearl1594 <[email protected]>
AuthorDate: Wed Oct 21 16:28:21 2026 -0400

    Re-reserve released NICs when a VM resyncs to Running to restore nics_count
---
 .../service/NetworkOrchestrationService.java         |  6 ++++++
 .../java/com/cloud/vm/VirtualMachineManagerImpl.java | 15 +++++++++++++++
 .../engine/orchestration/NetworkOrchestrator.java    | 20 ++++++++++++++++++++
 .../java/com/cloud/vpc/MockNetworkManagerImpl.java   |  4 ++++
 4 files changed, 45 insertions(+)

diff --git 
a/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java
 
b/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java
index d851867ef13..022679dc392 100644
--- 
a/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java
+++ 
b/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java
@@ -265,6 +265,12 @@ public interface NetworkOrchestrationService {
         throws InsufficientVirtualNetworkCapacityException, 
InsufficientAddressCapacityException, ConcurrentOperationException, 
InsufficientCapacityException,
         ResourceUnavailableException;
 
+    /**
+     * Re-reserves the Allocated nics of a VM that is Running, e.g. after its 
nics were released on a power report
+     * that was later reverted, and restores the active nics count of their 
networks.
+     */
+    void reconcileNicsForRunningVm(VirtualMachineProfile vmProfile, 
DeployDestination dest, ReservationContext context);
+
     /**
      * Removes the provided nic from the given vm
      * @param vm
diff --git 
a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java
 
b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java
index c98391a654d..996e71dd060 100755
--- 
a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java
+++ 
b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java
@@ -5432,6 +5432,7 @@ public class VirtualMachineManagerImpl extends 
ManagerBase implements VirtualMac
             ActionEventUtils.onActionEvent(User.UID_SYSTEM, 
Account.ACCOUNT_ID_SYSTEM, vm.getDomainId(),
                 EventTypes.EVENT_VM_START, "Out of band VM power on", 
vm.getId(), getApiCommandResourceTypeForVm(vm).toString());
             logger.info("VM {} is sync-ed to at Running state according to 
power-on report from hypervisor.", vm.getInstanceName());
+            reconcileNicsForRunningVm(vm);
             break;
 
         case Destroyed:
@@ -5456,6 +5457,20 @@ public class VirtualMachineManagerImpl extends 
ManagerBase implements VirtualMac
         }
     }
 
+    private void reconcileNicsForRunningVm(final VMInstanceVO vm) {
+        final VMInstanceVO runningVm = _vmDao.findById(vm.getId());
+        if (runningVm == null || runningVm.getType() != 
VirtualMachine.Type.User || runningVm.getState() != State.Running || 
runningVm.getHostId() == null
+                || 
_nicsDao.listByVmId(runningVm.getId()).stream().noneMatch(nic -> nic.getState() 
== Nic.State.Allocated)) {
+            return;
+        }
+        final Host host = _hostDao.findById(runningVm.getHostId());
+        final DataCenter dc = _entityMgr.findById(DataCenter.class, 
runningVm.getDataCenterId());
+        final User user = _entityMgr.findById(User.class, User.UID_SYSTEM);
+        final Account account = _entityMgr.findById(Account.class, 
Account.ACCOUNT_ID_SYSTEM);
+        final ReservationContext context = new ReservationContextImpl(null, 
null, user, account);
+        _networkMgr.reconcileNicsForRunningVm(new 
VirtualMachineProfileImpl(runningVm), new DeployDestination(dc, null, null, 
host), context);
+    }
+
     private void handlePowerOffReportWithNoPendingJobsOnVM(final VMInstanceVO 
vm) {
         switch (vm.getState()) {
         case Starting:
diff --git 
a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
 
b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
index 9b1609c669a..219fb5525f6 100644
--- 
a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
+++ 
b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
@@ -2187,6 +2187,26 @@ public class NetworkOrchestrator extends ManagerBase 
implements NetworkOrchestra
         }
     }
 
+    @Override
+    public void reconcileNicsForRunningVm(final VirtualMachineProfile 
vmProfile, final DeployDestination dest, final ReservationContext context) {
+        for (final NicVO nic : _nicDao.listByVmId(vmProfile.getId())) {
+            if (nic.getState() != Nic.State.Allocated) {
+                continue;
+            }
+            try {
+                final Pair<NetworkGuru, NetworkVO> implemented = 
implementNetwork(nic.getNetworkId(), dest, context);
+                if (implemented == null || implemented.first() == null) {
+                    logger.warn("Unable to implement Network ID={} to 
reconcile NIC {} of Running Instance {}", nic.getNetworkId(), nic, vmProfile);
+                    continue;
+                }
+                prepareNic(vmProfile, dest, context, nic.getId(), 
implemented.second());
+                logger.info("Re-reserved NIC {} of Running Instance {}", nic, 
vmProfile);
+            } catch (final Exception e) {
+                logger.warn("Failed to reconcile NIC {} of Running Instance 
{}", nic, vmProfile, e);
+            }
+        }
+    }
+
     @Override
     public NicProfile prepareNic(final VirtualMachineProfile vmProfile, final 
DeployDestination dest, final ReservationContext context, final long nicId, 
final Network network)
             throws InsufficientVirtualNetworkCapacityException, 
InsufficientAddressCapacityException, ConcurrentOperationException, 
InsufficientCapacityException,
diff --git a/server/src/test/java/com/cloud/vpc/MockNetworkManagerImpl.java 
b/server/src/test/java/com/cloud/vpc/MockNetworkManagerImpl.java
index aa27b24e60f..76db7173d87 100644
--- a/server/src/test/java/com/cloud/vpc/MockNetworkManagerImpl.java
+++ b/server/src/test/java/com/cloud/vpc/MockNetworkManagerImpl.java
@@ -758,6 +758,10 @@ public class MockNetworkManagerImpl extends ManagerBase 
implements NetworkOrches
         return null;
     }
 
+    @Override
+    public void reconcileNicsForRunningVm(VirtualMachineProfile vmProfile, 
DeployDestination dest, ReservationContext context) {
+    }
+
     @Override
     public NicProfile prepareNic(VirtualMachineProfile vmProfile, 
DeployDestination dest, ReservationContext context, long nicId, Network network)
         throws InsufficientVirtualNetworkCapacityException, 
InsufficientAddressCapacityException, ConcurrentOperationException, 
InsufficientCapacityException,

Reply via email to