From c80e786ba460d8ca8d76f809db75dd46c8174298 Mon Sep 17 00:00:00 2001 From: Gerrit Date: Thu, 7 Nov 2024 13:54:32 +0100 Subject: [PATCH] Add request param to calculate partition capacity for specific project This helps in cases where you have machine reservations for a project and want to display the proper free counts in case this project. --- .../internal/service/partition-service.go | 5 ++ .../service/partition-service_test.go | 52 ++++++++++++++++++- .../internal/service/v1/partition.go | 5 +- spec/metal-api.json | 9 +++- 4 files changed, 67 insertions(+), 4 deletions(-) diff --git a/cmd/metal-api/internal/service/partition-service.go b/cmd/metal-api/internal/service/partition-service.go index 58d77e6a..5ad902d2 100644 --- a/cmd/metal-api/internal/service/partition-service.go +++ b/cmd/metal-api/internal/service/partition-service.go @@ -545,6 +545,11 @@ func (r *partitionResource) calcPartitionCapacity(pcr *v1.PartitionCapacityReque cap.Reservations += reservation.Amount cap.UsedReservations += usedReservations + + if pcr.Project != nil && *pcr.Project == reservation.ProjectID { + continue + } + cap.Free -= reservation.Amount - usedReservations cap.Free = max(cap.Free, 0) } diff --git a/cmd/metal-api/internal/service/partition-service_test.go b/cmd/metal-api/internal/service/partition-service_test.go index 1d57dab2..bac50f5b 100644 --- a/cmd/metal-api/internal/service/partition-service_test.go +++ b/cmd/metal-api/internal/service/partition-service_test.go @@ -337,6 +337,7 @@ func TestPartitionCapacity(t *testing.T) { tests := []struct { name string + pcr *v1.PartitionCapacityRequest mockFn func(mock *r.Mock) want []*v1.PartitionCapacity }{ @@ -742,15 +743,64 @@ func TestPartitionCapacity(t *testing.T) { }, }, }, + { + name: "evaluate capacity for specific project", + pcr: &v1.PartitionCapacityRequest{ + Project: pointer.Pointer("project-123"), + }, + mockFn: func(mock *r.Mock) { + m1 := machineTpl("1", "partition-a", "size-a", "project-123") + m2 := machineTpl("2", "partition-a", "size-a", "") + m3 := machineTpl("3", "partition-a", "size-a", "") + m2.Waiting = true + m3.Waiting = true + + reservations := []metal.SizeReservation{ + { + SizeID: "size-a", + Amount: 3, + ProjectID: "project-123", + PartitionIDs: []string{"partition-a"}, + }, + } + + mockMachines(mock, metal.MachineLivelinessAlive, reservations, m1, m2, m3) + }, + want: []*v1.PartitionCapacity{ + { + Common: v1.Common{ + Identifiable: v1.Identifiable{ID: "partition-a"}, Describable: v1.Describable{Name: pointer.Pointer(""), Description: pointer.Pointer("")}, + }, + ServerCapacities: v1.ServerCapacities{ + { + Size: "size-a", + Total: 3, + Allocated: 1, + Waiting: 2, + Free: 2, + Allocatable: 2, + Reservations: 3, + UsedReservations: 1, + PhonedHome: 1, + RemainingReservations: 2, + }, + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { var ( ds, mock = datastore.InitMockDB(t) - body = &v1.PartitionCapacityRequest{} + body = tt.pcr ws = NewPartition(slog.Default(), ds, nil) ) + if body == nil { + body = &v1.PartitionCapacityRequest{} + } + if tt.mockFn != nil { tt.mockFn(mock) } diff --git a/cmd/metal-api/internal/service/v1/partition.go b/cmd/metal-api/internal/service/v1/partition.go index fc0c7e96..b6037242 100644 --- a/cmd/metal-api/internal/service/v1/partition.go +++ b/cmd/metal-api/internal/service/v1/partition.go @@ -42,8 +42,9 @@ type PartitionResponse struct { } type PartitionCapacityRequest struct { - ID *string `json:"id" description:"the id of the partition" optional:"true"` - Size *string `json:"sizeid" description:"the size to filter for" optional:"true"` + ID *string `json:"id" description:"the id of the partition" optional:"true"` + Size *string `json:"sizeid" description:"the size to filter for" optional:"true"` + Project *string `json:"projectid" description:"if provided the machine reservations of this project will be respected in the free counts"` } type ServerCapacities []*ServerCapacity diff --git a/spec/metal-api.json b/spec/metal-api.json index 721eea9f..627f942c 100644 --- a/spec/metal-api.json +++ b/spec/metal-api.json @@ -4171,11 +4171,18 @@ "description": "the id of the partition", "type": "string" }, + "projectid": { + "description": "if provided the machine reservations of this project will be respected in the free counts", + "type": "string" + }, "sizeid": { "description": "the size to filter for", "type": "string" } - } + }, + "required": [ + "projectid" + ] }, "v1.PartitionCreateRequest": { "properties": {