diff --git a/management/server/account.go b/management/server/account.go index f123b50ed..d87b90244 100644 --- a/management/server/account.go +++ b/management/server/account.go @@ -86,7 +86,7 @@ type AccountManager interface { GetUserByID(ctx context.Context, id string) (*types.User, error) GetUser(ctx context.Context, claims jwtclaims.AuthorizationClaims) (*types.User, error) ListUsers(ctx context.Context, accountID string) ([]*types.User, error) - GetPeers(ctx context.Context, accountID, userID string) ([]*nbpeer.Peer, error) + GetPeers(ctx context.Context, accountID, userID, nameFilter, ipFilter string) ([]*nbpeer.Peer, error) MarkPeerConnected(ctx context.Context, peerKey string, connected bool, realIP net.IP, accountID string) error DeletePeer(ctx context.Context, accountID, peerID, userID string) error UpdatePeer(ctx context.Context, accountID, userID string, peer *nbpeer.Peer) (*nbpeer.Peer, error) diff --git a/management/server/http/api/openapi.yml b/management/server/http/api/openapi.yml index 6c640f219..1ef0c7a1e 100644 --- a/management/server/http/api/openapi.yml +++ b/management/server/http/api/openapi.yml @@ -2183,6 +2183,17 @@ paths: summary: List all Peers description: Returns a list of all peers tags: [ Peers ] + parameters: + - in: query + name: name + schema: + type: string + description: Filter peers by name + - in: query + name: ip + schema: + type: string + description: Filter peers by IP address security: - BearerAuth: [ ] - TokenAuth: [ ] diff --git a/management/server/http/api/types.gen.go b/management/server/http/api/types.gen.go index 11765068e..90bf989e2 100644 --- a/management/server/http/api/types.gen.go +++ b/management/server/http/api/types.gen.go @@ -1580,6 +1580,15 @@ type UserRequest struct { Role string `json:"role"` } +// GetApiPeersParams defines parameters for GetApiPeers. +type GetApiPeersParams struct { + // Name Filter peers by name + Name *string `form:"name,omitempty" json:"name,omitempty"` + + // Ip Filter peers by IP address + Ip *string `form:"ip,omitempty" json:"ip,omitempty"` +} + // GetApiPeersPeerIdIngressPortsParams defines parameters for GetApiPeersPeerIdIngressPorts. type GetApiPeersPeerIdIngressPortsParams struct { // Name Filters ingress port allocations by name diff --git a/management/server/http/handlers/groups/groups_handler.go b/management/server/http/handlers/groups/groups_handler.go index b7121c234..b86d19e28 100644 --- a/management/server/http/handlers/groups/groups_handler.go +++ b/management/server/http/handlers/groups/groups_handler.go @@ -60,7 +60,7 @@ func (h *handler) getAllGroups(w http.ResponseWriter, r *http.Request) { return } - accountPeers, err := h.accountManager.GetPeers(r.Context(), accountID, userID) + accountPeers, err := h.accountManager.GetPeers(r.Context(), accountID, userID, "", "") if err != nil { util.WriteError(r.Context(), err, w) return @@ -154,7 +154,7 @@ func (h *handler) updateGroup(w http.ResponseWriter, r *http.Request) { return } - accountPeers, err := h.accountManager.GetPeers(r.Context(), accountID, userID) + accountPeers, err := h.accountManager.GetPeers(r.Context(), accountID, userID, "", "") if err != nil { util.WriteError(r.Context(), err, w) return @@ -213,7 +213,7 @@ func (h *handler) createGroup(w http.ResponseWriter, r *http.Request) { return } - accountPeers, err := h.accountManager.GetPeers(r.Context(), accountID, userID) + accountPeers, err := h.accountManager.GetPeers(r.Context(), accountID, userID, "", "") if err != nil { util.WriteError(r.Context(), err, w) return @@ -272,7 +272,7 @@ func (h *handler) getGroup(w http.ResponseWriter, r *http.Request) { return } - accountPeers, err := h.accountManager.GetPeers(r.Context(), accountID, userID) + accountPeers, err := h.accountManager.GetPeers(r.Context(), accountID, userID, "", "") if err != nil { util.WriteError(r.Context(), err, w) return diff --git a/management/server/http/handlers/groups/groups_handler_test.go b/management/server/http/handlers/groups/groups_handler_test.go index 96e381da1..05e45f848 100644 --- a/management/server/http/handlers/groups/groups_handler_test.go +++ b/management/server/http/handlers/groups/groups_handler_test.go @@ -69,7 +69,7 @@ func initGroupTestData(initGroups ...*types.Group) *handler { return nil, fmt.Errorf("unknown group name") }, - GetPeersFunc: func(ctx context.Context, accountID, userID string) ([]*nbpeer.Peer, error) { + GetPeersFunc: func(ctx context.Context, accountID, userID, nameFilter, ipFilter string) ([]*nbpeer.Peer, error) { return maps.Values(TestPeers), nil }, DeleteGroupFunc: func(_ context.Context, accountID, userId, groupID string) error { diff --git a/management/server/http/handlers/peers/peers_handler.go b/management/server/http/handlers/peers/peers_handler.go index cdd8026f2..262300c9e 100644 --- a/management/server/http/handlers/peers/peers_handler.go +++ b/management/server/http/handlers/peers/peers_handler.go @@ -186,7 +186,10 @@ func (h *Handler) GetAllPeers(w http.ResponseWriter, r *http.Request) { return } - peers, err := h.accountManager.GetPeers(r.Context(), accountID, userID) + nameFilter := r.URL.Query().Get("name") + ipFilter := r.URL.Query().Get("ip") + + peers, err := h.accountManager.GetPeers(r.Context(), accountID, userID, nameFilter, ipFilter) if err != nil { util.WriteError(r.Context(), err, w) return diff --git a/management/server/http/handlers/peers/peers_handler_test.go b/management/server/http/handlers/peers/peers_handler_test.go index 16065a677..248611bd2 100644 --- a/management/server/http/handlers/peers/peers_handler_test.go +++ b/management/server/http/handlers/peers/peers_handler_test.go @@ -125,7 +125,7 @@ func initTestMetaData(peers ...*nbpeer.Peer) *Handler { } return p, nil }, - GetPeersFunc: func(_ context.Context, accountID, userID string) ([]*nbpeer.Peer, error) { + GetPeersFunc: func(_ context.Context, accountID, userID, nameFilter, ipFilter string) ([]*nbpeer.Peer, error) { return peers, nil }, GetPeerGroupsFunc: func(ctx context.Context, accountID, peerID string) ([]*types.Group, error) { diff --git a/management/server/integrated_validator.go b/management/server/integrated_validator.go index b9827f457..b95ea1699 100644 --- a/management/server/integrated_validator.go +++ b/management/server/integrated_validator.go @@ -88,7 +88,7 @@ func (am *DefaultAccountManager) GetValidatedPeers(ctx context.Context, accountI return err } - peers, err = transaction.GetAccountPeers(ctx, store.LockingStrengthShare, accountID) + peers, err = transaction.GetAccountPeers(ctx, store.LockingStrengthShare, accountID, "", "") return err }) if err != nil { diff --git a/management/server/mock_server/account_mock.go b/management/server/mock_server/account_mock.go index c8e42d20a..e7f2a3c13 100644 --- a/management/server/mock_server/account_mock.go +++ b/management/server/mock_server/account_mock.go @@ -31,7 +31,7 @@ type MockAccountManager struct { GetAccountIDByUserIdFunc func(ctx context.Context, userId, domain string) (string, error) GetUserFunc func(ctx context.Context, claims jwtclaims.AuthorizationClaims) (*types.User, error) ListUsersFunc func(ctx context.Context, accountID string) ([]*types.User, error) - GetPeersFunc func(ctx context.Context, accountID, userID string) ([]*nbpeer.Peer, error) + GetPeersFunc func(ctx context.Context, accountID, userID, nameFilter, ipFilter string) ([]*nbpeer.Peer, error) MarkPeerConnectedFunc func(ctx context.Context, peerKey string, connected bool, realIP net.IP) error SyncAndMarkPeerFunc func(ctx context.Context, accountID string, peerPubKey string, meta nbpeer.PeerSystemMeta, realIP net.IP) (*nbpeer.Peer, *types.NetworkMap, []*posture.Checks, error) DeletePeerFunc func(ctx context.Context, accountID, peerKey, userID string) error @@ -628,9 +628,9 @@ func (am *MockAccountManager) CheckUserAccessByJWTGroups(ctx context.Context, cl } // GetPeers mocks GetPeers of the AccountManager interface -func (am *MockAccountManager) GetPeers(ctx context.Context, accountID, userID string) ([]*nbpeer.Peer, error) { +func (am *MockAccountManager) GetPeers(ctx context.Context, accountID, userID, nameFilter, ipFilter string) ([]*nbpeer.Peer, error) { if am.GetPeersFunc != nil { - return am.GetPeersFunc(ctx, accountID, userID) + return am.GetPeersFunc(ctx, accountID, userID, nameFilter, ipFilter) } return nil, status.Errorf(codes.Unimplemented, "method GetPeers is not implemented") } diff --git a/management/server/peer.go b/management/server/peer.go index ef40baa27..39a883a2c 100644 --- a/management/server/peer.go +++ b/management/server/peer.go @@ -57,7 +57,7 @@ type PeerLogin struct { // GetPeers returns a list of peers under the given account filtering out peers that do not belong to a user if // the current user is not an admin. -func (am *DefaultAccountManager) GetPeers(ctx context.Context, accountID, userID string) ([]*nbpeer.Peer, error) { +func (am *DefaultAccountManager) GetPeers(ctx context.Context, accountID, userID, nameFilter, ipFilter string) ([]*nbpeer.Peer, error) { user, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthShare, userID) if err != nil { return nil, err @@ -76,7 +76,7 @@ func (am *DefaultAccountManager) GetPeers(ctx context.Context, accountID, userID return []*nbpeer.Peer{}, nil } - accountPeers, err := am.Store.GetAccountPeers(ctx, store.LockingStrengthShare, accountID) + accountPeers, err := am.Store.GetAccountPeers(ctx, store.LockingStrengthShare, accountID, nameFilter, ipFilter) if err != nil { return nil, err } diff --git a/management/server/peer_test.go b/management/server/peer_test.go index 49bd043de..c9f74c760 100644 --- a/management/server/peer_test.go +++ b/management/server/peer_test.go @@ -708,7 +708,7 @@ func TestDefaultAccountManager_GetPeers(t *testing.T) { return } - peers, err := manager.GetPeers(context.Background(), accountID, someUser) + peers, err := manager.GetPeers(context.Background(), accountID, someUser, "", "") if err != nil { t.Fatal(err) return @@ -914,7 +914,7 @@ func BenchmarkGetPeers(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { - _, err := manager.GetPeers(context.Background(), accountID, userID) + _, err := manager.GetPeers(context.Background(), accountID, userID, "", "") if err != nil { b.Fatalf("GetPeers failed: %v", err) } diff --git a/management/server/peers/manager.go b/management/server/peers/manager.go index 6a188e8b7..1e067cef5 100644 --- a/management/server/peers/manager.go +++ b/management/server/peers/manager.go @@ -50,5 +50,5 @@ func (m *managerImpl) GetAllPeers(ctx context.Context, accountID, userID string) return nil, status.NewPermissionDeniedError() } - return m.store.GetAccountPeers(ctx, store.LockingStrengthShare, accountID) + return m.store.GetAccountPeers(ctx, store.LockingStrengthShare, accountID, "", "") } diff --git a/management/server/store/sql_store.go b/management/server/store/sql_store.go index 2179f0754..b05b17755 100644 --- a/management/server/store/sql_store.go +++ b/management/server/store/sql_store.go @@ -1236,10 +1236,18 @@ func (s *SqlStore) GetPeerGroups(ctx context.Context, lockStrength LockingStreng } // GetAccountPeers retrieves peers for an account. -func (s *SqlStore) GetAccountPeers(ctx context.Context, lockStrength LockingStrength, accountID string) ([]*nbpeer.Peer, error) { +func (s *SqlStore) GetAccountPeers(ctx context.Context, lockStrength LockingStrength, accountID, nameFilter, ipFilter string) ([]*nbpeer.Peer, error) { var peers []*nbpeer.Peer - result := s.db.Clauses(clause.Locking{Strength: string(lockStrength)}).Find(&peers, accountIDCondition, accountID) - if err := result.Error; err != nil { + query := s.db.Clauses(clause.Locking{Strength: string(lockStrength)}).Where(accountIDCondition, accountID) + + if nameFilter != "" { + query = query.Where("name LIKE ?", "%"+nameFilter+"%") + } + if ipFilter != "" { + query = query.Where("ip LIKE ?", "%"+ipFilter+"%") + } + + if err := query.Find(&peers).Error; err != nil { log.WithContext(ctx).Errorf("failed to get peers from the store: %s", err) return nil, status.Errorf(status.Internal, "failed to get peers from store") } diff --git a/management/server/store/sql_store_test.go b/management/server/store/sql_store_test.go index 9350da1c8..cf22d5be5 100644 --- a/management/server/store/sql_store_test.go +++ b/management/server/store/sql_store_test.go @@ -2666,6 +2666,8 @@ func TestSqlStore_GetAccountPeers(t *testing.T) { tests := []struct { name string accountID string + nameFilter string + ipFilter string expectedCount int }{ { @@ -2683,11 +2685,29 @@ func TestSqlStore_GetAccountPeers(t *testing.T) { accountID: "", expectedCount: 0, }, + { + name: "should filter peers by name", + accountID: "bf1c8084-ba50-4ce7-9439-34653001fc3b", + nameFilter: "expiredhost", + expectedCount: 1, + }, + { + name: "should filter peers by partial name", + accountID: "bf1c8084-ba50-4ce7-9439-34653001fc3b", + nameFilter: "host", + expectedCount: 3, + }, + { + name: "should filter peers by ip", + accountID: "bf1c8084-ba50-4ce7-9439-34653001fc3b", + ipFilter: "100.64.39.54", + expectedCount: 1, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - peers, err := store.GetAccountPeers(context.Background(), LockingStrengthShare, tt.accountID) + peers, err := store.GetAccountPeers(context.Background(), LockingStrengthShare, tt.accountID, tt.nameFilter, tt.ipFilter) require.NoError(t, err) require.Len(t, peers, tt.expectedCount) }) diff --git a/management/server/store/store.go b/management/server/store/store.go index 4b4dcfb4f..b58fc68ec 100644 --- a/management/server/store/store.go +++ b/management/server/store/store.go @@ -105,7 +105,7 @@ type Store interface { RemoveResourceFromGroup(ctx context.Context, accountId string, groupID string, resourceID string) error AddPeerToAccount(ctx context.Context, lockStrength LockingStrength, peer *nbpeer.Peer) error GetPeerByPeerPubKey(ctx context.Context, lockStrength LockingStrength, peerKey string) (*nbpeer.Peer, error) - GetAccountPeers(ctx context.Context, lockStrength LockingStrength, accountID string) ([]*nbpeer.Peer, error) + GetAccountPeers(ctx context.Context, lockStrength LockingStrength, accountID, nameFilter, ipFilter string) ([]*nbpeer.Peer, error) GetUserPeers(ctx context.Context, lockStrength LockingStrength, accountID, userID string) ([]*nbpeer.Peer, error) GetPeerByID(ctx context.Context, lockStrength LockingStrength, accountID string, peerID string) (*nbpeer.Peer, error) GetPeersByIDs(ctx context.Context, lockStrength LockingStrength, accountID string, peerIDs []string) (map[string]*nbpeer.Peer, error)