bhouse-nexthop commented on PR #14199:
URL: https://github.com/apache/cloudstack/pull/14199#issuecomment-6737449618

   ### Test report: Ceph outages on a KVM host, with the agent's Ceph traffic 
blocked
   
   **Environment**
   - A CloudStack 24.0 (main) build with this PR applied, alongside some of my 
other open PRs. That includes #14188 (merged), which looks RBD volumes up 
through librbd.
   - **4.22 caveat:** I ran this on 24.0, not 4.22. The KVM storage code this 
PR touches (`LibvirtStorageAdaptor`, `KVMStorageProcessor`, 
`KVMStoragePoolManager` and the snapshot wrappers) is the same on 4.22 and 
main, so I expect the same behaviour there. I have not run it on a 4.22 build.
   - Three KVM hosts on Ubuntu 24.04 (libvirt 10.0.0, QEMU 8.2.2), nested 
virtualisation. Ceph squid 19.2.3, RBD primary storage, NFS secondary storage.
   - The agent's defaults: `rados.osd.op.timeout=60`, `rados.mon.op.timeout=30`.
   
   **How the fault was injected**
   - An nftables rule on the KVM host drops only the traffic from the 
`cloudstack-agent.service` cgroup to Ceph:
     ```
     nft add rule inet cephblk out socket cgroupv2 level 2 
'"system.slice/cloudstack-agent.service"' ip daddr <ceph> tcp dport '{ 
6800-7568 }' counter drop
     ```
     Steps 1, 2 and 5 drop the OSD ports only, so `rados_connect` succeeds and 
the image open waits on the OSDs. Step 4 also drops the mon ports.
   - qemu runs in `machine.slice` and is not matched, so running guests keep 
their disk I/O. I checked this before the run, and again after every block by 
watching the guests' I/O request counters grow.
   - Processes the agent starts, such as `qemu-img`, inherit its cgroup and are 
blocked too.
   - Ceph was `HEALTH_OK` after every step, and all hosts stayed Up throughout.
   
   **History**
   - The first lab run of this PR found that each Ceph operation was bounded, 
but `KVMStoragePoolManager.getPhysicalDisk()` retried any failure 100 times, 3 
s apart. A deploy with the OSDs blocked failed one open every ~63 s and would 
have held the command for about 105 minutes. A snapshot behaved the same way.
   - The PR now treats a Ceph error other than librbd's `-ENOENT` as final 
("not retrying a Ceph error"). Everything below is on that version.
   
   **1. OSD ports blocked, deploy a VM to the host**
   - The deploy **failed after 67 s**, with `Unable to orchestrate the start of 
VM instance ...`.
   - The agent log shows one bounded open, and no retry:
     ```
     07:12:24 Trying to fetch storage pool <pool> from libvirt
     07:13:24 ERROR A Ceph RBD operation failed (-110). The error was: Failed 
to open image <template> - Connection timed out
     07:13:24 WARN  [KVMStoragePoolManager] Failed to find volume:<template> 
due to ...RbdException: Failed to open image <template>, not retrying a Ceph 
error
     ```
   - At 45 s, `jstack` showed the deploy's handler thread in 
`rbd_open_read_only`, as expected while the open waits. A second handler was 
there too, running a `GetVolumeStatsCommand` from the stats collector. That one 
also came back after its single bounded open (answered at 56 s). Neither 
command held the other up, and the host stayed Up.
   - After I removed the block, a fresh deploy to the same host succeeded.
   
   **2. "Without": the timeouts set to 0, which is the stock behaviour**
   - I set `rados.osd.op.timeout=0` and `rados.mon.op.timeout=0` in 
`agent.properties`, restarted the agent, and repeated step 1.
   - The deploy's handler thread was parked in `rbd_open_read_only` at 70 s and 
again at 370 s: the same thread, with its CPU time unchanged 
(`AgentRequest-Handler-5 #56 ... cpu=58.26ms elapsed=96s`, then 
`elapsed=397s`). At 430 s, a second handler (a later command) was parked the 
same way.
   - The agent process was the same throughout; nothing restarted it.
   - When I removed the block after ~450 s, the parked open completed and the 
VM came up Running. That is the stock "wait for as long as Ceph is away".
   - I put the defaults back and restarted the agent afterwards.
   
   **3. Snapshot of a running VM's ROOT with the OSD ports blocked**
   - `createSnapshot` **failed after 62 s**. The agent logged the same single 
`-110` open and the "not retrying a Ceph error" line, then `Failed take 
snapshot for volume ...`.
   - `listSnapshots` shows the snapshot in `Error`, not BackedUp, and `rbd snap 
ls` on the image is empty, so there is no stray RBD snapshot.
   - Once unblocked, a new snapshot of the same ROOT reached BackedUp in 4 s.
   
   **4. Snapshot backup interrupted mid-copy**
   - A 20 GB data disk, filled from `/dev/urandom`. I used 20 GB rather than 40 
GB to stay clear of the pool's nearfull ratio.
   - `snapshot.backup.to.secondary=true`. I started `createSnapshot`, and found 
the copy by watching for its process on the hosts:
     ```
     qemu-img convert -O qcow2 -U 
rbd:cloudstack/<image>@<snap>:mon_host=...:client_mount_timeout=30 
/mnt/<secondary>/snapshots/...
     cgroup 0::/system.slice/cloudstack-agent.service
     ```
   - With 7.0 GB copied (and growing at ~240 MB/s), I blocked all of the agent 
cgroup's Ceph ports on that host for 180 s.
     - The copy stalled at 7045709824 bytes for the whole window, and 
`qemu-img` stayed alive.
     - After the block was removed, `qemu-img` resumed and finished 85 s later.
   - The snapshot ended BackedUp with a full-size file: 21478375424 bytes, 
`qemu-img info` virtual size 20 GiB, matching `physical_size` in 
`snapshot_store_ref`. No short file was recorded.
   - **Note on scope:** this backup path is 
`KVMStorageProcessor.backupSnapshot()`, which copies with `qemu-img convert`. 
This PR doesn't change that code, and `qemu-img` gets no op timeout, so a 
longer outage would hold the copy until `backup.snapshot.wait`.
   - The PR's read-loop fix (a negative `rbd_read` is now an error instead of 
end-of-image) is in `LibvirtBackupSnapshotCommandWrapper`. I found no current 
management-server path that sends `BackupSnapshotCommand`, so that change is 
covered by the unit tests only.
   
   **5. Watchers on the template image (from the first run, same code for this 
part)**
   - I sampled `rbd status` on the template image every ~0.2 s while 6 VMs were 
deployed from it at once, 3 to each of two hosts.
   - No watcher appeared, and all 6 VMs were Running. The clone parent is 
opened read-only.
   
   **6. Cluster handles released (from the first run, same code for this part)**
   - `ceph tell mon.* sessions` entries from the host: 22 before and 22 after 
10 deploy/destroy cycles on it.
   
   **Result:** pass.
   - With the OSDs unreachable, a deploy and a snapshot now fail in about one 
`rados.osd.op.timeout` (67 s and 62 s), instead of waiting for as long as Ceph 
is away.
   - Other commands on the host keep running, and the host stays Up.
   - With the timeouts set to 0, the agent goes back to the stock behaviour, 
with a handler parked in `rbd_open` for the whole outage.
   - A failed snapshot leaves no RBD snapshot behind and is not recorded as 
created. An interrupted backup did not record a short file.
   - Clone opens hold no watchers, and the cluster handles are released.
   
   **Not covered**
   - A mon-only outage during a long copy, the internal librbd completion hang, 
a cross-cluster copy, and a pool without cephx.
   - `BackupSnapshotCommand` (see step 4).
   


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