Repository navigation
Unreleased regression (4.20, 4.22, main): the orphaned-network cleanup from #12409 shuts down networks while a VM start is implementing them, so the start fails with "Network is not yet fully implemented" #14522
Description
problem
While testing instance boot groups (#13907) on a main nightly build, boot group starts failed with "Network is not yet fully implemented". The cause turned out to be unrelated to boot groups. It is the orphaned-network cleanup added by #12409.
#12409 solves a real problem: a network left in Implementing after a crash or a lost job could not be used again, and cleaning those up is valuable. The problem is only in how a "stuck" network is detected. The cleanup also catches networks that a VM start is implementing at that moment.
#12409 is in no release yet:
- It was merged into 4.20 on 2026-09-09 (milestone 4.20.4) and merged forward into 4.22 and main on 2026-09-10.
- None of 4.20.3.x, 4.22.1.x or 4.23.0.0 contains it.
- Unless it is fixed, it ships with 4.20.4 and with the next releases cut from 4.22 and main. The next release from main would ship it together with boot groups.
What the code does (AsyncJobManagerImpl.cleanupOrphanedNetworks(), framework/jobs):
- It runs in the async-job GC task every 10 seconds (
GC_INTERVAL). - It lists networks in state Implementing. It skips a network whose creation time is within
job.expire.minutes(default 1440, one day). Once a network is more than a day old, this check always passes, however briefly the network has been Implementing. - It treats a network as busy only if a pending async job has instance type
Networkand that network's id. When a VM start or deployment implements a network, the work runs inside the VM's own job (VmWorkStart, instance type VirtualMachine), so the cleanup never sees it. - It fires
Network.Event.OperationFailed(Implementing to Shutdown). If the state machine refuses, it sets Shutdown directly in the database. It does this without the network lock, which the implementing thread holds (NetworkOrchestrator.implementNetwork,acquireInLockTable). - Implementing an isolated network includes booting its virtual router. That took about 36 s here, so a 10-second tick lands inside the implementation almost every time. When the start then prepares the NICs, the network is in Shutdown, and the start fails:
ResourceUnavailableException: Resource [Network:209] is unreachable: Network is not yet fully implemented
Trace (management-server.log, network id 209):
- 01:19:46-50: the network GC shut the network down (router stopped).
- 01:20:23.709: a VM start took the network's lock and asked the guru and VirtualRouter to implement it. The router's StartCommand went out at 01:20:24.217.
- 01:20:31.650:
Found orphaned network 209 in Implementing state without async job. Network created: 2026-10-27T14:32:37, age: 2087 minutes, expiration threshold: 1440 minutes. Transitioning to Shutdown state., followed bySuccessfully transitioned orphaned network 209 to Shutdown state using state machine. - 01:21:00.246: the router start finished, and the lock was released at 01:21:02.030.
- 01:21:02.048: NIC prepare failed with "Network is not yet fully implemented", and the start failed.
Why we are confident about the cause: the test networks were created on 2026-10-27 at 14:32 UTC.
- For the first 24 hours, the same check found networks in Implementing and skipped them as too young. Nothing failed.
- From 2026-10-28 14:32 on, every cleanup run that found a network in Implementing marked it as orphaned, and the start implementing it failed. That was 7 cleanup runs and 17 failed boot group starts.
- One plain startVirtualMachine call also failed its first attempt this way, and the API's retry passed.
Impact:
- Which networks: any network older than
job.expire.minutes(one day by default, so practically every production network) whenever it has to be implemented again. Typical cases:- the first VM start after the network GC shut an idle network down (with the default
network.gc.*settings, about 10-20 minutes after its last VM stopped); - the first deployment into a network created more than a day ago.
- the first VM start after the network GC shut an idle network down (with the default
- Network types: the cleanup does not filter by type. Any network that passes through Implementing is exposed; we saw it with isolated networks.
- Plain start and deploy API:
VMEntityManagerImpl.deployVirtualMachineretries once, which usually passes because the router is up by then. So the problem is partly hidden: the first attempt fails, a WARN is logged, and the start takes longer. The retry can be hit too; we saw that once. - Paths without a retry fail outright:
- Instance boot groups (feature: instance boot group and readiness rules #13907, on main) start VMs through
advanceStartonce (InstanceBootGroupManagerImplline 201 on main), so the whole group halts. - HA restarts (
startVirtualMachineForHA) also calladvanceStartonce. The HA worker may try again later on its own schedule. HA was not tested here.
- Instance boot groups (feature: instance boot group and readiness rules #13907, on main) start VMs through
- State consistency: the cleanup changes the state of a network that another thread is implementing under the lock, and falls back to writing Shutdown directly to the database.
versions
- Observed on: the main nightly
cloudstack-management-24.0.0-SNAPSHOT.20261027, which includes the merged feature: instance boot group and readiness rules #13907 (f03cffc; it does not touch this code). - Code:
AsyncJobManagerImpl.cleanupOrphanedNetworks(), added by Allow cleaning up of networks stuck in Implementing state #12409 (215ef98). It is present on the 4.20 and 4.22 branches and on main. - Environment:
- KVM, a single host, EL9, MySQL 8.0.
- Isolated networks on DefaultIsolatedNetworkOfferingWithSourceNatService (not persistent).
- Default
network.gc.intervalandnetwork.gc.wait(600/600) andjob.expire.minutes(1440).
The steps to reproduce the bug
As observed:
- Take an isolated network on a non-persistent offering, created more than
job.expire.minutesago (default one day). - Stop all its VMs and wait until the network GC shuts it down (network in Shutdown, router stopped). With the defaults this takes about 10-20 minutes.
- Start a VM on it.
- With a boot group (or any path that calls
advanceStartonce), the start fails with "Network is not yet fully implemented". - With the plain startVirtualMachine API, the first attempt fails and the API's retry usually passes.
- With a boot group (or any path that calls
- management-server.log shows
Found orphaned network <id> in Implementing state without async joba few seconds after the implementation started.
Quicker variant (not yet run in this exact form):
- Set
job.expire.minutesto 5. It is dynamic, but note that it also shortens job retention on the test system. - Create a new isolated network, which stays Allocated until it is first used.
- Wait more than 5 minutes, then deploy a VM into it. The cleanup should cut the first implementation the same way.
Control: a network younger than job.expire.minutes is not affected. A controlled A/B confirmation (a young network against an old one, each case twice) is running, and its results will follow as a comment.
What to do about it?
Possible fixes (any of these would do):
- Measure the time stuck in Implementing, not the age since creation. Treat a network as stuck only if it has had no implement activity for X minutes since it entered Implementing, for example from a timestamp set on that transition. Use an X tied to how long an implementation can take, not
job.expire.minutes. - Recognise the implementer. Count VmWork jobs (and any other job that implements networks) as active. Or, before the transition, try the network's lock without waiting: skip the network if the lock is held, and otherwise re-read its state under the lock and transition only if it is still Implementing. Avoid the direct database write to Shutdown while another thread may own the network.
- Tests:
- Start a VM through
advanceStart(no retry) on a network older than the threshold, with the cleanup running. It must succeed, and no orphan may be logged. - A network that is truly stuck (lock free, idle for X minutes) is still cleaned up.
- Start a VM through
If a fix cannot make 4.20.4, it may be safer to disable this cleanup on the release branches for now, so that the regression does not ship.
Workarounds until fixed:
- Use a persistent network offering. The network GC never collects those networks, so they stay Implemented.
- Or make sure networks are Implemented before starts that do not retry, for example by first starting one VM per network with the plain start API.
cc @Pearl1594: thank you for #12409. We are raising this now only because it has not shipped yet and there is still time to adjust it before 4.20.4.
Activity
[-][SHORT PROBLEM DESCRIPTION][/-][+]Unreleased regression (4.20, 4.22, main): the orphaned-network cleanup from #12409 shuts down networks while a VM start is implementing them, so the start fails with "Network is not yet fully implemented"[/+]andrijapanicsb commentedon Oct 29, 2026
A/B confirmation, as promised in the issue. Same build (main nightly
cloudstack-management-24.0.0-SNAPSHOT.20261027), KVM, a single host, isolated networks on DefaultIsolatedNetworkOfferingWithSourceNatService (not persistent). The global settings were unchanged:network.gc.interval/network.gc.wait600/600 andjob.expire.minutes1440, read back after the test.Method. Each case starts one VM on one network that needs implementing. The cases ran one at a time, about 30 s apart, with young and old interleaved. Before the test, the network GC had shut every network in A, B and P down (state Allocated, router stopped).
advanceStart, no retry).startVirtualMachine(the API path, which retries once).networks.createdon these two test networks only, while they were Allocated:UPDATE networks SET created = created - INTERVAL 2 DAY WHERE id IN (213, 214);deployVirtualMachineinto network 213.Results:
Log lines (management-server.log, 2026-10-29 UTC; times exact, lines shortened, network ids only):
Conclusion. The network's age since creation alone decides the outcome.
job.expire.minuteshad its network moved to Shutdown mid-implementation: 6 of 6, including 2 that were only backdated.The retry is not a safe net either. Shortly after the A/B, a plain
deployVirtualMachineinto old network 209 (shut down by the GC) failed outright. The cleanup caught both attempts:The retry's implementation took about 2 s, and a 10-second cleanup run landed inside it. A new deploy about two minutes later passed.
For maintainers reproducing it: backdating a test network's
created, as above, reproduces it immediately. Loweringjob.expire.minutesalso reproduces it, but it deletes completed job history; backdating a test network'screatedhas no side effects.Updated counts from the soak described in the issue: the issue was written at 7 cleanup runs and 17 failed boot group starts. By the end of the soak (95 cycles, ending 2026-10-29 04:49 UTC), it was 10 cleanup runs and 26 failed boot group starts. Leaving aside readiness-rule timing (a separate boot-group topic), all but one of the soak's failed group starts came from this cleanup.