bhouse-nexthop commented on PR #14233:
URL: https://github.com/apache/cloudstack/pull/14233#issuecomment-6740870727
### Test report: destroy and router replacement with the host unreachable,
hung, Down, or the instance stalled (S1-S7, retest on the current head)
This follows the earlier report on system VM destroy (S8, the
`test_11_destroy_ssvm` error). It covers the PR's own scenarios.
The first run of these scenarios was on the PR before 095ad969e6. S5 failed
there:
- `restartNetwork cleanup=true` succeeded with the router's host
Disconnected.
- The rolling restart stopped the old router with an explicit forced stop,
so it was released without the host confirming. Its domain kept running next to
the new router.
095ad969e6 changes that. I upgraded the lab to a build with it and reran S5,
S5 for a VPC, an all-hosts-Up control, S7b, and S1, S4, S7a and S8 as
regression checks. S2, S3 and S6 come from the first run. 095ad969e6 does not
touch their paths: the destroy stop, an explicit forced stop of an instance,
and account cleanup.
**Environment**
- A CloudStack 24.0 (main) build with this PR, including 095ad969e6, applied
alongside some of my other open PRs, including #14207. All three hosts and the
management server were upgraded in place to the same build.
- 4.22 (the PR's target): not run on a 4.22 build. The code paths match in
both branches:
- `VirtualMachineManagerImpl` and `AccountManagerImpl` don't differ
between 4.22 and main in the stop, expunge and account-cleanup paths.
- `VpcManagerImpl`'s rolling restart is identical.
- In `NetworkOrchestrator.rollingRestartRouters()`, only the opening "is
rolling restart enabled" check differs. The part this PR changes, the stop and
destroy of the old routers, is the same in both.
- Three KVM hosts on Ubuntu 24.04 (libvirt 10.0.0, QEMU 8.2.2), nested
virtualisation, one cluster; Ceph RBD primary storage; one management server.
- `vm.destroy.forcestop=true` for these runs (except where noted), set back
to `false` afterwards. `ping.interval=60`, `ping.timeout=2.5`,
`network.rolling.restart=true` (default).
- All test VMs (CirrOS) and the routers under test were on one host, host 1.
- **About host states in this lab:** with only RBD primary storage,
`KVMInvestigator` has no HA storage to check, so a host with its agent stopped
stays `Disconnected`. In the first run it stayed that way for 10+ minutes and
never went Alert or Down. A truly Down host could not be produced without
killing other workloads on the hypervisor, so S4 and S5-Down set `Down` in the
DB.
**Results**
| Scenario | Run on | Result |
|---|---|---|
| S1: destroy with the host Disconnected | first run, and again on the
current head | pass |
| S2: hung agent (`kill -STOP`) on an Up host | first run | pass |
| S3: explicit `stopVirtualMachine forced=true` still releases | first run
(and the forced router stops in S5 below) | pass |
| S4: destroy with the host Down (DB-forced) | first run, and again on the
current head | pass |
| S5: `restartNetwork cleanup=true`, router on a Disconnected host |
**failed on the first run**; current head | pass |
| S5-VPC: `restartVPC cleanup=true`, VPC router on a Disconnected host |
current head | pass |
| S5-Up: rolling restart with every host Up (network and VPC) | current head
| pass |
| S5-Down: rolling restart with the router's host Down (DB-forced),
`vm.destroy.forcestop=false` | current head | pass |
| S6: account cleanup with an instance on a Disconnected host | first run |
pass |
| S7a: stalled Migrating (DB-forced) | first run, and again on the current
head | pass |
| S7b: stalled Starting (DB-forced), destroy with
`vm.destroy.forcestop=true` | **stock error on the first run**; current head |
pass |
| S8: SSVM destroy (quick recheck) | current head | pass |
**S5: `restartNetwork cleanup=true` with the router on the Disconnected
host**
- **Setup:** isolated network with source NAT, its router on host 1. I
stopped host 1's agent; the host was `Disconnected` within seconds. After 30 s,
I ran the restart.
- **The restart failed** in about 2 s:
```
Resource [Host:1] is unreachable: Unable to replace router r-373-VM: its
host <host 1> is Disconnected and may still be running it. Retry once the host
is Up, or stop the router with forced=true first.
```
- The check runs before the new router is deployed:
- No new `vm_instance` row was created, and the network still had one
router.
- `r-373-VM` was still `Running` on host 1 in CloudStack, and its domain
was still running there.
- `stopRouter forced=true` (the explicit decision) returned `Stopped`.
- The same restart then succeeded. A new router, `r-375-VM`, came up on host
2, and `r-373-VM` was destroyed and expunged.
- On the first run, without 095ad969e6, the same restart succeeded on the
first try. The old router was released with `Unable to actually stop ... but
continue with release because it's a force stop`, and its domain kept running.
**S5-VPC: `restartVPC cleanup=true` with the VPC router on the Disconnected
host**
- **Setup:** a VPC (default VPC offering) with one tier and a CirrOS VM in
it. The VPC router was on host 1, and host 1's agent was stopped.
- The restart failed the same way, with no new router deployed. The old
router stayed `Running` in CloudStack and on host 1:
```
Resource [Host:1] is unreachable: Unable to replace router r-374-VM: its
host <host 1> is Disconnected and may still be running it. Retry once the host
is Up, or stop the router with forced=true first.
```
- After `stopRouter forced=true`, the restart succeeded. The new router
`r-376-VM` came up on host 2, and the old one was expunged.
**S5-Up: the rolling restart with every host Up still replaces the router**
- `restartNetwork cleanup=true`: a new router was deployed and the old one
destroyed. The old router's domain was gone from its host, so the host
confirmed the stop.
- `restartVPC cleanup=true`: the same, and the tier VM stayed Running.
**S5-Down: rolling restart with the router's host Down (DB-forced while the
agent was stopped)**
- I set `vm.destroy.forcestop=false` for this step, to check that the stop
of the old router stays forced whatever that setting says.
- The restart succeeded. A new router came up on host 3, and the old one was
released:
```
WARN Unable to actually stop VM instance
{"id":370,"instanceName":"r-370-VM","state":"Stopping","type":"DomainRouter",...}
DEBUG Expunged VM instance {"id":370,"instanceName":"r-370-VM",...}
```
This is the "host is gone" case.
- The host status was then put back to `Disconnected`.
- As expected, the domain kept running on the real host, which never got the
stop.
**After host 1 reconnected (old router domains)**
- The agent was started and host 1 was `Up` again 21 s later.
- Three old router domains were still running on host 1: `r-373-VM` and
`r-374-VM` (from the explicit forced stops) and `r-370-VM` (released as Down).
Their DB rows were expunged.
- #14207 is in this build. The first power report flagged the three domains
and raised the "Instances running on a host that CloudStack has no record of"
alert:
```
WARN Host reports 3 instance(s) that do not exist in CloudStack DB, they
are running unmanaged. host: ..., instances: [r-370-VM, r-373-VM, r-374-VM]
```
- They were not stopped automatically, and were still running after 200 s. I
destroyed them by hand.
- This is the expected cost of `forced=true`, or of a host wrongly marked
Down. Without #14207 they would not be reported at all.
- The S4 VM (destroyed while the host was DB-forced Down) still had a row in
`Destroyed` state. On reconnect, #14207 stopped it automatically: `Stopped
unmanaged instance ... on host 1`.
**S1: agent stopped (host Disconnected)**
- `destroyVirtualMachine` failed with `Unable to stop VM instance ... Host
with specified id is not in the right state: Disconnected`, after:
```
WARN Not releasing the resources of VM instance
{...,"state":"Stopping",...}: its host Host {"id":1,"name":"<host 1>",...} is
Disconnected and did not confirm the instance is stopped. Retry the destroy, or
stop the instance with forced=true if it is known to be gone.
```
- The VM stayed `Running`. Its domain was still in `virsh list` on host 1,
and its NIC row (IP, MAC, state `Reserved`) was unchanged.
- Once the agent was started and the host was Up, the same destroy
succeeded, and the domain was gone.
- Same result in the first run and on the current head.
**S2: hung agent on an Up host (`kill -STOP` of the agent JVM), destroy at
once (first run)**
- The destroy **failed after 234 s**, by which time the host had gone Alert:
```
WARN Unable to stop VM instance {...,"state":"Stopping",...}
WARN Not releasing the resources of VM instance {...}: its host <host 1>
is Alert and did not confirm the instance is stopped. Retry the destroy, or
stop the instance with forced=true if it is known to be gone.
```
- After `kill -CONT`, the host was Up again 31 s later. The VM was still
Running, and its domain was still on host 1.
- The retried destroy succeeded, and the domain was gone.
**S3: an explicit `stopVirtualMachine forced=true` still releases (first
run)**
- With host 1 Disconnected, the forced stop returned `Stopped`, and the NIC
went to `Allocated`, as before.
- The domain was still running on host 1, which is expected: the host never
got the stop. I destroyed it by hand.
- The forced `stopRouter` calls in S5 and S5-VPC on the current head behaved
the same way.
**S4: host Down (DB-forced)**
- With the agent stopped, I set the host's status to `Down` in the DB,
destroyed a VM, then set the status back.
- The destroy succeeded and released the NIC (`Allocated`). This is the
"host is gone" case, where the forced release is still taken.
- The domain kept running on the real host, as it would on a host that was
only marked Down.
- First run: I destroyed it by hand.
- Current head: #14207 stopped it when the host reconnected (see above).
**S6: account cleanup with an instance on a Disconnected host (first run)**
- `deleteAccount` returned success and logged:
```
WARN Not releasing the resources of VM instance {"id":218,...}: ...
WARN Not expunging instance VM instance {"id":218,...}, it may still be
running on its host.
WARN Deferring the rest of the cleanup of account Account
[{"accountName":"acct-x",...}]: it has instances that may still be running.
```
- The VM stayed Running with its NIC, and the account's network stayed
`Implemented`.
- The next cleanup run (`account.cleanup.interval=300` for the test), with
the host still away, deferred again.
- After the agent was started, the cleanup finished within 223 s: the VM was
expunged, the domain gone from host 1, the network destroyed, and the account
removed.
**S7a: stalled Migrating**
- **Setup (DB-forced):** `state=Migrating`, `host_id` set to host 2, and
`last_host_id` set to host 1, where the VM really runs.
- The destroy was refused:
```
Unable to stop VM instance {...,"state":"Migrating",...} in state
Migrating: the host it is migrating from may still be running it
```
- The domain stayed on host 1, and the NIC stayed `Reserved`.
- After the DB state was put back to Running, the destroy succeeded.
- Same result in the first run and on the current head.
**S7b: stalled Starting (DB-forced on a running VM), one destroy with
`vm.destroy.forcestop=true`**
- **First run:** the release happened, then the API call failed with `We
cannot proceed with stop VM ... since it is not in 'Stopping' state, current
state: Stopped`, and a second destroy was needed.
- That error is stock. The forced-cleanup branch of `advanceStop()` fell
through to the Stopping check after a successful cleanup.
- 095ad969e6 adds the missing `return`.
- **Current head: the destroy succeeded in one call**, and the VM is
`Destroyed`.
- The ordinary stop went first: `StopCommand` with `forceStop=false`.
- The forced cleanup followed (`Unable to transition the state but we're
moving on because it's forced stop ... from Starting via StopRequested`). Host
1 confirmed, and the release followed (`Starting -> Stopped
[AgentReportStopped]`).
- The domain was gone and the NIC `Allocated`.
- The work job ended `SUCCEEDED`, and the destroy went on to `Destroying
vm ... expunge flag off`.
- **Timing:** the call took about 2 minutes this time (4 s in the first
run). The CirrOS guest did not answer the graceful shutdown, so the agent
waited for its timeout (`Timed out waiting for domain ... to shutdown
gracefully`) and then destroyed the domain. That is how any ordinary stop
behaves; it is not a hang.
**S8: system VM destroy (quick recheck on the current head)**
- With all hosts Up and `vm.destroy.forcestop=true`, `destroySystemVm` on
the SSVM completed in 5 s, and the old domain was gone.
- The replacement was Running with its agent Up 57 s after the destroy call.
**Other observations (not from this PR)**
- The failed `restartNetwork` is logged at ERROR, as `Unexpected exception
while executing ... RestartNetworkCmd`, with error code 530. The failed
`restartVPC` is logged at WARN with 534.
- `RestartNetworkCmd.execute()` lets `ResourceUnavailableException` reach
the dispatcher, while `RestartVPCCmd` catches it. That is existing behaviour
for any `ResourceUnavailableException` from a network restart.
**Result:** **pass.**
- A destroy no longer releases an instance in these cases:
- its host is Disconnected, Alert or hung (S1, S2);
- its migration source may still be running it (S7a).
- A destroy still releases when the host is Down (S4), or when the caller
forces the stop (S3).
- A rolling `restartNetwork`/`restartVPC` with `cleanup=true` refuses while
an old router's host is Disconnected, before deploying anything (S5, S5-VPC).
It succeeds after an explicit `stopRouter forced=true`, and it succeeds when
every host is Up (S5-Up) or the router's host is Down (S5-Down).
- Account cleanup defers and then completes once the host is back (S6).
- A destroy of an instance stalled in Starting now completes in one call
(S7b).
**Not covered**
- A real host Down: S4 and S5-Down used the DB.
- The window in the "Known limitations": a host that becomes unreachable
while the new router is being deployed.
- Network GC with the router on an unreachable host.
- Redundant routers.
- More than one management server.
- A 4.22 build.
--
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]