From cf0190dc5d111e3a0af013fa94d464aa799a5026 Mon Sep 17 00:00:00 2001 From: Stefan Majer Date: Fri, 16 Aug 2024 10:38:44 +0200 Subject: [PATCH] Only fetch required ips per switch describe instead of all --- cmd/metal-api/internal/datastore/ip.go | 16 ++++++++++++++++ .../internal/service/switch-service.go | 19 +++++++++++++------ cmd/metal-api/internal/testdata/testdata.go | 4 ++++ 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/cmd/metal-api/internal/datastore/ip.go b/cmd/metal-api/internal/datastore/ip.go index 5c54649a3..758dd68dc 100644 --- a/cmd/metal-api/internal/datastore/ip.go +++ b/cmd/metal-api/internal/datastore/ip.go @@ -97,6 +97,22 @@ func (rs *RethinkStore) SearchIPs(q *IPSearchQuery, ips *metal.IPs) error { return rs.searchEntities(q.generateTerm(rs), ips) } +// FindIPsByProjects returns all ips of given projects. +// FIXME no test present to check if the query actually works +// according to https://stackoverflow.com/questions/44424377/rethinkdb-query-filter-against-multiple-values-for-single-key it should :-) +func (rs *RethinkStore) FindIPsByProjects(projects []string) (metal.IPs, error) { + q := *rs.ipTable() + q = q.Filter(func(row r.Term) r.Term { + return row.Field("projectid").Contains(func(nw r.Term) r.Term { + return nw.Field("projectid").Contains(r.Expr(projects)) + }) + }) + + ips := make([]metal.IP, 0) + err := rs.searchEntities(&q, ips) + return ips, err +} + // ListIPs returns all ips. func (rs *RethinkStore) ListIPs() (metal.IPs, error) { ips := make([]metal.IP, 0) diff --git a/cmd/metal-api/internal/service/switch-service.go b/cmd/metal-api/internal/service/switch-service.go index 8fea0f965..8c7ba6fef 100644 --- a/cmd/metal-api/internal/service/switch-service.go +++ b/cmd/metal-api/internal/service/switch-service.go @@ -997,9 +997,12 @@ func makeSwitchCons(s *metal.Switch) []v1.SwitchConnection { } func findSwitchReferencedEntities(s *metal.Switch, ds *datastore.RethinkStore) (*metal.Partition, metal.IPsMap, metal.Machines, *metal.SwitchStatus, error) { - var err error - var p *metal.Partition - var m metal.Machines + var ( + err error + p *metal.Partition + ms metal.Machines + projects []string + ) if s.PartitionID != "" { p, err = ds.FindPartition(s.PartitionID) @@ -1007,13 +1010,17 @@ func findSwitchReferencedEntities(s *metal.Switch, ds *datastore.RethinkStore) ( return nil, nil, nil, nil, fmt.Errorf("switch %q references partition, but partition %q cannot be found in database: %w", s.ID, s.PartitionID, err) } - err = ds.SearchMachines(&datastore.MachineSearchQuery{PartitionID: &s.PartitionID}, &m) + err = ds.SearchMachines(&datastore.MachineSearchQuery{PartitionID: &s.PartitionID}, &ms) if err != nil { return nil, nil, nil, nil, fmt.Errorf("could not search machines of partition %q for switch %q: %w", s.PartitionID, s.ID, err) } } - ips, err := ds.ListIPs() + for project := range ms.ByProjectID() { + projects = append(projects, project) + } + + ips, err := ds.FindIPsByProjects(projects) if err != nil { return nil, nil, nil, nil, fmt.Errorf("ips could not be listed: %w", err) } @@ -1023,7 +1030,7 @@ func findSwitchReferencedEntities(s *metal.Switch, ds *datastore.RethinkStore) ( return nil, nil, nil, nil, fmt.Errorf("switchStatus could not be listed: %w", err) } - return p, ips.ByProjectID(), m, ss, nil + return p, ips.ByProjectID(), ms, ss, nil } func makeSwitchResponseList(ss metal.Switches, ds *datastore.RethinkStore) ([]*v1.SwitchResponse, error) { diff --git a/cmd/metal-api/internal/testdata/testdata.go b/cmd/metal-api/internal/testdata/testdata.go index 273f5bfb0..9896f3e4d 100644 --- a/cmd/metal-api/internal/testdata/testdata.go +++ b/cmd/metal-api/internal/testdata/testdata.go @@ -891,6 +891,10 @@ func InitMockDBData(mock *r.Mock) { mock.On(r.DB("mockdb").Table("image")).Return(TestImages, nil) mock.On(r.DB("mockdb").Table("network")).Return(TestNetworks, nil) mock.On(r.DB("mockdb").Table("ip")).Return(TestIPs, nil) + + // FIXME i hate these mocks + // mock.On(r.DB("mockdb").Table("ip").Filter(func(var_5 r.Term) r.Term { return var_5.Field("projectid").Contains(func(var_6 r.Term) r.Term { return var_6.Field("projectid").Contains(["p1", "p2"]) }) })).Return(TestIPs, nil) + mock.On(r.DB("mockdb").Table("machine")).Return(TestMachines, nil) mock.On(r.DB("mockdb").Table("switch")).Return(TestSwitches, nil) mock.On(r.DB("mockdb").Table("switchstatus")).Return(TestSwitchStates, nil)