diff --git a/cmd/metal-api/internal/service/partition-service.go b/cmd/metal-api/internal/service/partition-service.go index 61f77486..9eee4531 100644 --- a/cmd/metal-api/internal/service/partition-service.go +++ b/cmd/metal-api/internal/service/partition-service.go @@ -380,12 +380,14 @@ func (r *partitionResource) partitionCapacity(request *restful.Request, response func (r *partitionResource) calcPartitionCapacity(pcr *v1.PartitionCapacityRequest) ([]v1.PartitionCapacity, error) { var ( - ps metal.Partitions - ms metal.Machines + ps metal.Partitions + ms metal.Machines + allMs metal.Machines pcs = map[string]*v1.PartitionCapacity{} - machineQuery = datastore.MachineSearchQuery{} + machineQuery = datastore.MachineSearchQuery{} + allMachineQuery = datastore.MachineSearchQuery{} ) if pcr != nil && pcr.ID != nil { @@ -396,6 +398,7 @@ func (r *partitionResource) calcPartitionCapacity(pcr *v1.PartitionCapacityReque ps = metal.Partitions{*p} machineQuery.PartitionID = pcr.ID + allMachineQuery.PartitionID = pcr.ID } else { var err error ps, err = r.ds.ListPartitions() @@ -413,6 +416,12 @@ func (r *partitionResource) calcPartitionCapacity(pcr *v1.PartitionCapacityReque return nil, err } + // if filtered on partition get all without more filters for issues evaluation + err = r.ds.SearchMachines(&allMachineQuery, &allMs) + if err != nil { + return nil, err + } + ecs, err := r.ds.ListProvisioningEventContainers() if err != nil { return nil, fmt.Errorf("unable to fetch provisioning event containers: %w", err) @@ -429,7 +438,7 @@ func (r *partitionResource) calcPartitionCapacity(pcr *v1.PartitionCapacityReque } machinesWithIssues, err := issues.Find(&issues.Config{ - Machines: ms, + Machines: allMs, EventContainers: ecs, Omit: []issues.Type{issues.TypeLastEventError}, }) diff --git a/cmd/metal-api/internal/service/partition-service_test.go b/cmd/metal-api/internal/service/partition-service_test.go index bac50f5b..cbd2e510 100644 --- a/cmd/metal-api/internal/service/partition-service_test.go +++ b/cmd/metal-api/internal/service/partition-service_test.go @@ -310,6 +310,27 @@ func TestPartitionCapacity(t *testing.T) { mock.On(r.DB("mockdb").Table("event")).Return(events, nil) mock.On(r.DB("mockdb").Table("partition")).Return(partitions, nil) mock.On(r.DB("mockdb").Table("size")).Return(sizes, nil) + + //Filtered mocks + var filteredPartition []metal.Partition + for _, partition := range partitions { + if partition.ID == "partition-a" { + filteredPartition = append(filteredPartition, partition) + } + } + var filteredMachinesByPartition []metal.Machine + var filteredMachinesByPartitionBySize []metal.Machine + for _, machine := range ms { + if machine.PartitionID == "partition-a" { + filteredMachinesByPartition = append(filteredMachinesByPartition, machine) + if machine.SizeID == "size-a" { + filteredMachinesByPartitionBySize = append(filteredMachinesByPartitionBySize, machine) + } + } + } + mock.On(r.DB("mockdb").Table("partition").Get("partition-a")).Return(filteredPartition, nil) + mock.On(r.DB("mockdb").Table("machine").Filter(func(var_1 r.Term) r.Term { return var_1.Field("partitionid").Eq("partition-a") })).Return(filteredMachinesByPartition, nil) + mock.On(r.DB("mockdb").Table("machine").Filter(func(var_1 r.Term) r.Term { return var_1.Field("partitionid").Eq("partition-a") }).Filter(func(var_1 r.Term) r.Term { return var_1.Field("sizeid").Eq("size-a") })).Return(filteredMachinesByPartitionBySize, nil) } machineTpl = func(id, partition, size, project string) metal.Machine { @@ -411,6 +432,92 @@ func TestPartitionCapacity(t *testing.T) { }, }, }, + { + name: "filter considers all machines", + pcr: &v1.PartitionCapacityRequest{ + ID: pointer.Pointer("partition-a"), + Size: pointer.Pointer("size-a"), + }, + mockFn: func(mock *r.Mock) { + m1 := machineTpl("1", "partition-a", "size-a", "project-123") + m2 := machineTpl("2", "partition-a", "size-a", "project-123") + m3 := machineTpl("3", "partition-a", "size-a", "project-123") + m4 := machineTpl("4", "partition-a", "size-b", "project-123") + m4.IPMI.Address = "1.2.3.1" + m5 := machineTpl("5", "partition-b", "size-a", "project-123") + mockMachines(mock, metal.MachineLivelinessAlive, nil, m1, m2, m3, m4, m5) + }, + + 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, + PhonedHome: 3, + Faulty: 1, + Allocated: 3, + FaultyMachines: []string{"1"}, + }, + }, + }, + }, + }, + { + name: "non filter considers all machines", + pcr: &v1.PartitionCapacityRequest{}, + mockFn: func(mock *r.Mock) { + m1 := machineTpl("1", "partition-a", "size-a", "project-123") + m2 := machineTpl("2", "partition-a", "size-a", "project-123") + m3 := machineTpl("3", "partition-a", "size-a", "project-123") + m4 := machineTpl("4", "partition-a", "size-b", "project-123") + m4.IPMI.Address = "1.2.3.1" + m5 := machineTpl("5", "partition-b", "size-a", "project-123") + mockMachines(mock, metal.MachineLivelinessAlive, nil, m1, m2, m3, m4, m5) + }, + 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, + PhonedHome: 3, + Faulty: 1, + Allocated: 3, + FaultyMachines: []string{"1"}, + }, + { + Size: "size-b", + Total: 1, + PhonedHome: 1, + Faulty: 1, + Allocated: 1, + FaultyMachines: []string{"4"}, + }, + }, + }, + { + Common: v1.Common{ + Identifiable: v1.Identifiable{ID: "partition-b"}, Describable: v1.Describable{Name: pointer.Pointer(""), Description: pointer.Pointer("")}, + }, + ServerCapacities: v1.ServerCapacities{ + { + Size: "size-a", + Total: 1, + PhonedHome: 1, + Faulty: 0, + Allocated: 1, + }, + }, + }, + }, + }, { name: "one waiting machine", mockFn: func(mock *r.Mock) {