diff --git a/internal/incusplacement/starlarkexec/execute.go b/internal/incusplacement/starlarkexec/execute.go index 4980a59b..2ddff4c5 100644 --- a/internal/incusplacement/starlarkexec/execute.go +++ b/internal/incusplacement/starlarkexec/execute.go @@ -53,7 +53,11 @@ type MemberSnapshot struct { } type InstanceSnapshot struct { - Name string + Name string + // Project is the Incus project that owns the instance. Empty means the + // project passed to get_instances / get_instances_count, so existing + // fleet-worker fixtures stay in the queried project. + Project string MemoryLimitMiB int } @@ -162,8 +166,9 @@ func Execute(script string, request PlacementRequest, cluster ClusterSnapshot) ( if err != nil { return nil, err } - instances := make([]api.Instance, 0, len(member.Instances)) - for _, instance := range member.Instances { + filtered := instancesForProject(member, project) + instances := make([]api.Instance, 0, len(filtered)) + for _, instance := range filtered { instances = append(instances, api.Instance{ Name: instance.Name, Project: project, Location: location, ExpandedConfig: api.ConfigMap{ @@ -185,7 +190,7 @@ func Execute(script string, request PlacementRequest, cluster ClusterSnapshot) ( if err != nil { return nil, err } - count := len(member.Instances) + count := len(instancesForProject(member, project)) if includePending { count = member.PendingCount } @@ -269,3 +274,20 @@ func lookupMember(members map[string]MemberSnapshot, name string) (MemberSnapsho } return member, nil } + +func instancesForProject(member MemberSnapshot, project string) []InstanceSnapshot { + if project == "" { + return append([]InstanceSnapshot(nil), member.Instances...) + } + matched := make([]InstanceSnapshot, 0, len(member.Instances)) + for _, instance := range member.Instances { + instanceProject := instance.Project + if instanceProject == "" { + instanceProject = project + } + if instanceProject == project { + matched = append(matched, instance) + } + } + return matched +} diff --git a/internal/incusplacement/starlarkexec/execute_test.go b/internal/incusplacement/starlarkexec/execute_test.go index fae5e060..4e0054b4 100644 --- a/internal/incusplacement/starlarkexec/execute_test.go +++ b/internal/incusplacement/starlarkexec/execute_test.go @@ -121,6 +121,23 @@ func TestWrongProjectIsANoOp(t *testing.T) { } } +func TestForeignProjectInstancesDoNotConsumeFleetRAM(t *testing.T) { + script := renderExample(t) + cluster := fourEmptyMembers() + cluster.Members[0].Instances = []InstanceSnapshot{ + {Name: "other-1", Project: "not-fleet", MemoryLimitMiB: 8192}, + {Name: "other-2", Project: "not-fleet", MemoryLimitMiB: 8192}, + } + cluster.Members[0].PendingCount = 0 + outcome, err := Execute(script, eightGiBRequest(), cluster) + if err != nil { + t.Fatal(err) + } + if outcome.Failed || outcome.Target != "gha-runner-1" { + t.Fatalf("other-project occupancy filled gha-fleet RAM: %#v", outcome) + } +} + func renderExample(t *testing.T) string { t.Helper() _, current, _, ok := runtime.Caller(0)