mirror of
https://github.com/cozystack/cozystack.git
synced 2026-11-09 14:02:56 +09:00
Two timing bugs unmasked by Flux v2.8 kstatus, with the same root shape:
the bats steps assumed a side-effect ordering ("by the time X is true,
the parent HR's helm install is done") that held under v2.7's faster
dispatch but breaks under v2.8 where helm-controller walks kstatus on
every applied resource before flipping the HR Ready.
run-kubernetes.sh:
After every addon HR (cilium, coredns, csi, vsnap-crd, ingress-nginx)
reaches Ready, the remediation guard reads `.status.history` on the
parent kubernetes-${test_name} HR. The parent's helm install can still
be Reconciling at that point because kstatus is finishing its full
sweep; `.status.history` is empty until install completes, so the
guard exits 1 with "empty .status.history on a Ready HR". kubernetes-
latest masked this because the ouroboros assertions add ~10m of
buffer; kubernetes-previous (no ouroboros) hit the guard with the
parent still installing. Add an explicit
kubectl wait hr/kubernetes-${test_name} --for=condition=ready
before the guard.
vminstance.bats:
The test waited 120s for `kubectl get vmi vm-instance-$name` to
return a VMI with an assigned IP, then waited for the parent HR Ready
separately afterwards. Under v2.7 the parent HR's helm install
applied the VirtualMachine CR fast enough that kubevirt had created
the VMI before the 120s budget expired. Under v2.8 the dispatch is
slower and the VMI poll returned NotFound for its entire budget.
Reorder: wait for HR Ready first (which implies the VirtualMachine
CR is applied + kstatus-ready), then poll for the VMI with IP.
Loosen the VMI poll budget from 120s to 5m for nested-virt slow paths.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
(cherry picked from commit c664b868bc)
118 lines
5.3 KiB
Bash
118 lines
5.3 KiB
Bash
#!/usr/bin/env bats
|
|
|
|
@test "Create a VM Disk" {
|
|
name='test'
|
|
# Delete any leftover from a previous run and BLOCK until removal completes.
|
|
# `kubectl apply` on a resource still in finalizer-drain silently no-ops
|
|
# ("Detected changes to resource ... which is currently being deleted"),
|
|
# which then races a NotFound on the downstream HR wait. The previous
|
|
# `|| true` swallowed timeout errors here and let the test continue with
|
|
# the old VMDisk still draining. Bumped timeout to 3m and removed `|| true`
|
|
# so a true delete failure surfaces immediately.
|
|
kubectl -n tenant-test delete vminstances.apps.cozystack.io $name --ignore-not-found --timeout=3m
|
|
kubectl -n tenant-test delete vmdisks.apps.cozystack.io $name --ignore-not-found --timeout=3m
|
|
kubectl apply -f - <<EOF
|
|
apiVersion: apps.cozystack.io/v1alpha1
|
|
kind: VMDisk
|
|
metadata:
|
|
name: $name
|
|
namespace: tenant-test
|
|
spec:
|
|
source:
|
|
http:
|
|
url: https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img
|
|
optical: false
|
|
storage: 5Gi
|
|
storageClass: replicated
|
|
EOF
|
|
# Wait for the operator to materialise the HelmRelease before kubectl wait
|
|
# kicks in (kubectl wait errors immediately if the object does not exist yet).
|
|
timeout 60 sh -ec "until kubectl -n tenant-test get hr vm-disk-$name >/dev/null 2>&1; do sleep 2; done"
|
|
kubectl -n tenant-test wait hr vm-disk-$name --timeout=5m --for=condition=ready
|
|
kubectl -n tenant-test wait dv vm-disk-$name --timeout=250s --for=condition=ready
|
|
kubectl -n tenant-test wait pvc vm-disk-$name --timeout=200s --for=jsonpath='{.status.phase}'=Bound
|
|
# Drop the VMDisk so the next test starts from a clean slate. Each test
|
|
# owns its own resources; "Create a VM Instance" creates its own VMDisk
|
|
# inline rather than depending on this one.
|
|
kubectl -n tenant-test delete vmdisks.apps.cozystack.io $name --ignore-not-found --timeout=3m
|
|
}
|
|
|
|
@test "Create a VM Instance" {
|
|
# Use a distinct disk name from "Create a VM Disk" so a flaky finalizer
|
|
# drain on the prior disk's PV/PVC cannot collide with this test's apply.
|
|
diskName='vmi-test'
|
|
name='test'
|
|
# Pre-clean any leftover VMInstance from a prior run. The VMDisk is
|
|
# created by this test (decoupled from "Create a VM Disk" above), so no
|
|
# predelete here — the prior test already cleaned up its own VMDisk.
|
|
kubectl -n tenant-test delete vminstances.apps.cozystack.io $name --ignore-not-found --timeout=3m
|
|
# Create the VMDisk this test depends on. Same wait-for-HR pattern as the
|
|
# first test, so this block is self-contained.
|
|
kubectl apply -f - <<EOF
|
|
apiVersion: apps.cozystack.io/v1alpha1
|
|
kind: VMDisk
|
|
metadata:
|
|
name: $diskName
|
|
namespace: tenant-test
|
|
spec:
|
|
source:
|
|
http:
|
|
url: https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img
|
|
optical: false
|
|
storage: 5Gi
|
|
storageClass: replicated
|
|
EOF
|
|
timeout 60 sh -ec "until kubectl -n tenant-test get hr vm-disk-$diskName >/dev/null 2>&1; do sleep 2; done"
|
|
kubectl -n tenant-test wait hr vm-disk-$diskName --timeout=5m --for=condition=ready
|
|
kubectl -n tenant-test wait dv vm-disk-$diskName --timeout=250s --for=condition=ready
|
|
kubectl -n tenant-test wait pvc vm-disk-$diskName --timeout=200s --for=jsonpath='{.status.phase}'=Bound
|
|
kubectl apply -f - <<EOF
|
|
apiVersion: apps.cozystack.io/v1alpha1
|
|
kind: VMInstance
|
|
metadata:
|
|
name: $name
|
|
namespace: tenant-test
|
|
spec:
|
|
external: false
|
|
externalMethod: PortList
|
|
externalPorts:
|
|
- 22
|
|
running: true
|
|
instanceType: "u1.medium"
|
|
instanceProfile: ubuntu
|
|
disks:
|
|
- name: $diskName
|
|
gpus: []
|
|
sshKeys:
|
|
- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPht0dPk5qQ+54g1hSX7A6AUxXJW5T6n/3d7Ga2F8gTF
|
|
test@test
|
|
cloudInit: |
|
|
#cloud-config
|
|
users:
|
|
- name: test
|
|
shell: /bin/bash
|
|
sudo: ['ALL=(ALL) NOPASSWD: ALL']
|
|
groups: sudo
|
|
ssh_authorized_keys:
|
|
- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPht0dPk5qQ+54g1hSX7A6AUxXJW5T6n/3d7Ga2F8gTF test@test
|
|
cloudInitSeed: ""
|
|
EOF
|
|
# Wait for the operator to materialise the HelmRelease before downstream
|
|
# waits proceed (kubectl wait errors immediately if the HR does not exist).
|
|
timeout 60 sh -ec "until kubectl -n tenant-test get hr vm-instance-$name >/dev/null 2>&1; do sleep 2; done"
|
|
# Wait for the parent HR Ready before polling for the VMI. Under Flux v2.8
|
|
# kstatus the helm install can be still dispatching when the previous
|
|
# ordering assumed it had already applied the VirtualMachine CR — without
|
|
# this the next poll for `vmi vm-instance-$name` returned NotFound for
|
|
# its entire 120s budget because kubevirt hadn't seen the VM yet.
|
|
kubectl -n tenant-test wait hr vm-instance-$name --timeout=5m --for=condition=ready
|
|
# Nested KubeVirt VM startup (virt-launcher + libvirt + cloud-init DHCP)
|
|
# routinely takes 30-60s under runner load. 5m is a comfortable upper
|
|
# bound for nested virt + slow runner I/O after the HR-Ready gate.
|
|
timeout 5m sh -ec "until kubectl -n tenant-test get vmi vm-instance-$name -o jsonpath='{.status.interfaces[0].ipAddress}' | grep -q '[0-9]'; do sleep 2; done"
|
|
# VM ready follows IP assignment closely; 60s gives buffer for the qemu-guest-agent.
|
|
kubectl -n tenant-test wait vm vm-instance-$name --timeout=5m --for=condition=ready
|
|
kubectl -n tenant-test delete vminstances.apps.cozystack.io $name --ignore-not-found --timeout=3m
|
|
kubectl -n tenant-test delete vmdisks.apps.cozystack.io $diskName --ignore-not-found --timeout=3m
|
|
}
|