diff --git a/cmd/api/api/api_test.go b/cmd/api/api/api_test.go index a6abfb4..8371f99 100644 --- a/cmd/api/api/api_test.go +++ b/cmd/api/api/api_test.go @@ -25,7 +25,10 @@ import ( // newTestService creates an ApiService for testing with automatic cleanup func newTestService(t *testing.T) *ApiService { cfg := &config.Config{ - DataDir: t.TempDir(), + DataDir: t.TempDir(), + BridgeName: "vmbr0", + SubnetCIDR: "10.100.0.0/16", + DNSServer: "1.1.1.1", } p := paths.New(cfg.DataDir) @@ -44,6 +47,11 @@ func newTestService(t *testing.T) *ApiService { } instanceMgr := instances.NewManager(p, imageMgr, systemMgr, networkMgr, deviceMgr, volumeMgr, limits, "", nil, nil) + // Initialize network manager (creates bridge for network-enabled tests) + if err := networkMgr.Initialize(ctx(), nil); err != nil { + t.Logf("Warning: failed to initialize network manager: %v (network tests may fail)", err) + } + // Register cleanup for orphaned Cloud Hypervisor processes t.Cleanup(func() { cleanupOrphanedProcesses(t, cfg.DataDir) @@ -54,6 +62,7 @@ func newTestService(t *testing.T) *ApiService { ImageManager: imageMgr, InstanceManager: instanceMgr, VolumeManager: volumeMgr, + NetworkManager: networkMgr, DeviceManager: deviceMgr, ResourceManager: resourceMgr, } diff --git a/cmd/api/api/instances_test.go b/cmd/api/api/instances_test.go index 90116bf..005241a 100644 --- a/cmd/api/api/instances_test.go +++ b/cmd/api/api/instances_test.go @@ -148,7 +148,7 @@ func TestInstanceLifecycle_StopStart(t *testing.T) { // 1. Create instance t.Log("Creating instance...") - networkEnabled := false + networkEnabled := true createResp, err := svc.CreateInstance(ctx(), oapi.CreateInstanceRequestObject{ Body: &oapi.CreateInstanceRequest{ Name: "test-lifecycle", diff --git a/lib/network/allocate.go b/lib/network/allocate.go index b3906f9..b622ace 100644 --- a/lib/network/allocate.go +++ b/lib/network/allocate.go @@ -27,8 +27,8 @@ func (m *manager) CreateAllocation(ctx context.Context, req AllocateRequest) (*N return nil, fmt.Errorf("get default network: %w", err) } - // 2. Check name uniqueness - exists, err := m.NameExists(ctx, req.InstanceName) + // 2. Check name uniqueness (exclude current instance to allow restarts) + exists, err := m.NameExists(ctx, req.InstanceName, req.InstanceID) if err != nil { return nil, fmt.Errorf("check name exists: %w", err) } diff --git a/lib/network/derive.go b/lib/network/derive.go index fc352bb..591bab3 100644 --- a/lib/network/derive.go +++ b/lib/network/derive.go @@ -113,14 +113,20 @@ func (m *manager) ListAllocations(ctx context.Context) ([]Allocation, error) { return allocations, nil } -// NameExists checks if instance name is already used in the default network -func (m *manager) NameExists(ctx context.Context, name string) (bool, error) { +// NameExists checks if instance name is already used in the default network. +// excludeInstanceID allows excluding a specific instance from the check (used when +// starting an existing instance to avoid it conflicting with itself). +func (m *manager) NameExists(ctx context.Context, name string, excludeInstanceID string) (bool, error) { allocations, err := m.ListAllocations(ctx) if err != nil { return false, err } for _, alloc := range allocations { + // Skip the excluded instance (e.g., when restarting an instance) + if excludeInstanceID != "" && alloc.InstanceID == excludeInstanceID { + continue + } if alloc.InstanceName == name { return true, nil } diff --git a/lib/network/manager.go b/lib/network/manager.go index 9102a59..5fed5d1 100644 --- a/lib/network/manager.go +++ b/lib/network/manager.go @@ -29,7 +29,7 @@ type Manager interface { // Queries (derive from CH/snapshots) GetAllocation(ctx context.Context, instanceID string) (*Allocation, error) ListAllocations(ctx context.Context) ([]Allocation, error) - NameExists(ctx context.Context, name string) (bool, error) + NameExists(ctx context.Context, name string, excludeInstanceID string) (bool, error) // GetUploadBurstMultiplier returns the configured multiplier for upload burst ceiling. GetUploadBurstMultiplier() int