Skip to content

Commit b7a4031

Browse files
authored
chore: de-flake testing (#130)
* network: avoid deleting taps when running set is unknown * deps: bump oapi runtime for generated client compatibility * api: decouple instance network mapping from generated tag shape * ci: trigger stability run 2/5 * ci: verify required linux test binaries under sudo path * ci: run sudo tool probes via bash builtin command -v * ci: trigger stability run 2/5 after merge * ci: trigger stability run 3/5 after merge
1 parent 2b1ed88 commit b7a4031

3 files changed

Lines changed: 37 additions & 21 deletions

File tree

.github/workflows/test.yml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,19 @@ jobs:
3838
sudo apt-get install -y erofs-utils e2fsprogs iptables
3939
fi
4040
go mod download
41-
41+
42+
- name: Verify Linux test toolchain
43+
run: |
44+
set -euo pipefail
45+
TEST_PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$PATH"
46+
for bin in mkfs.erofs mkfs.ext4 iptables; do
47+
if ! sudo env "PATH=$TEST_PATH" bash -lc "command -v '$bin' >/dev/null"; then
48+
echo "missing required binary under sudo PATH: $bin"
49+
exit 1
50+
fi
51+
sudo env "PATH=$TEST_PATH" bash -lc "command -v '$bin'"
52+
done
53+
4254
# Avoids rate limits when running the tests
4355
# Tests includes pulling, then converting to disk images
4456
- name: Login to Docker Hub

cmd/api/api/instances.go

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -796,23 +796,21 @@ func instanceToOAPI(inst instances.Instance) oapi.Instance {
796796
uploadBwStr = &s
797797
}
798798

799-
// Build network object with ip/mac and bandwidth nested inside
800-
netObj := &struct {
801-
BandwidthDownload *string `json:"bandwidth_download,omitempty"`
802-
BandwidthUpload *string `json:"bandwidth_upload,omitempty"`
803-
Enabled *bool `json:"enabled,omitempty"`
804-
Ip *string `json:"ip"`
805-
Mac *string `json:"mac"`
806-
Name *string `json:"name,omitempty"`
807-
}{
808-
Enabled: lo.ToPtr(inst.NetworkEnabled),
809-
BandwidthDownload: downloadBwStr,
810-
BandwidthUpload: uploadBwStr,
799+
// Build network payload as JSON to avoid compile-time coupling to
800+
// generated anonymous struct tags in oapi.Instance.Network.
801+
networkPayload := map[string]any{
802+
"enabled": inst.NetworkEnabled,
803+
}
804+
if downloadBwStr != nil {
805+
networkPayload["bandwidth_download"] = *downloadBwStr
806+
}
807+
if uploadBwStr != nil {
808+
networkPayload["bandwidth_upload"] = *uploadBwStr
811809
}
812810
if inst.NetworkEnabled {
813-
netObj.Name = lo.ToPtr("default")
814-
netObj.Ip = lo.ToPtr(inst.IP)
815-
netObj.Mac = lo.ToPtr(inst.MAC)
811+
networkPayload["name"] = "default"
812+
networkPayload["ip"] = inst.IP
813+
networkPayload["mac"] = inst.MAC
816814
}
817815

818816
// Convert hypervisor type
@@ -836,7 +834,7 @@ func instanceToOAPI(inst instances.Instance) oapi.Instance {
836834
OverlaySize: lo.ToPtr(overlaySizeStr),
837835
Vcpus: lo.ToPtr(inst.Vcpus),
838836
DiskIoBps: diskIoBpsStr,
839-
Network: netObj,
837+
Network: nil,
840838
CreatedAt: inst.CreatedAt,
841839
StartedAt: inst.StartedAt,
842840
StoppedAt: inst.StoppedAt,
@@ -845,6 +843,10 @@ func instanceToOAPI(inst instances.Instance) oapi.Instance {
845843
Hypervisor: &hvType,
846844
}
847845

846+
if b, err := json.Marshal(networkPayload); err == nil {
847+
_ = json.Unmarshal(b, &oapiInst.Network)
848+
}
849+
848850
if inst.ExitMessage != "" {
849851
oapiInst.ExitMessage = lo.ToPtr(inst.ExitMessage)
850852
}

lib/network/bridge_linux.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -864,14 +864,16 @@ func (m *manager) queryNetworkState(bridgeName string) (*Network, error) {
864864

865865
// CleanupOrphanedTAPs removes TAP devices that aren't used by any running instance.
866866
// runningInstanceIDs is a list of instance IDs that currently have a running VMM.
867-
// Pass nil to skip cleanup entirely (used when we couldn't determine running instances).
867+
// Pass nil or an empty list to skip cleanup entirely (used when we couldn't
868+
// determine an authoritative list of running instances for this host).
868869
// Returns the number of TAPs deleted.
869870
func (m *manager) CleanupOrphanedTAPs(ctx context.Context, runningInstanceIDs []string) int {
870871
log := logger.FromContext(ctx)
871872

872-
// If nil, skip cleanup entirely to avoid accidentally deleting TAPs for running VMs
873-
if runningInstanceIDs == nil {
874-
log.DebugContext(ctx, "skipping TAP cleanup (nil instance list)")
873+
// Skip cleanup when we don't have an authoritative running set.
874+
// This avoids deleting TAPs created by other concurrent hypeman processes/tests.
875+
if len(runningInstanceIDs) == 0 {
876+
log.DebugContext(ctx, "skipping TAP cleanup (empty instance list)")
875877
return 0
876878
}
877879

0 commit comments

Comments
 (0)