[management] Add support for filtering peers by name and IP (#3279)

* add peers ip and name filters

Signed-off-by: bcmmbaga <bethuelmbaga12@gmail.com>

* add get peers filter

Signed-off-by: bcmmbaga <bethuelmbaga12@gmail.com>

* fix get account peers

Signed-off-by: bcmmbaga <bethuelmbaga12@gmail.com>

* Extend GetAccountPeers store to support filtering by name and IP

Signed-off-by: bcmmbaga <bethuelmbaga12@gmail.com>

* Fix get peers references

Signed-off-by: bcmmbaga <bethuelmbaga12@gmail.com>

---------

Signed-off-by: bcmmbaga <bethuelmbaga12@gmail.com>
This commit is contained in:
Bethuel Mmbaga 2025-02-05 00:33:15 +03:00 committed by GitHub
parent 1b011a2d85
commit 9ec61206c2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 73 additions and 22 deletions

View File

@ -86,7 +86,7 @@ type AccountManager interface {
GetUserByID(ctx context.Context, id string) (*types.User, error) GetUserByID(ctx context.Context, id string) (*types.User, error)
GetUser(ctx context.Context, claims jwtclaims.AuthorizationClaims) (*types.User, error) GetUser(ctx context.Context, claims jwtclaims.AuthorizationClaims) (*types.User, error)
ListUsers(ctx context.Context, accountID string) ([]*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 MarkPeerConnected(ctx context.Context, peerKey string, connected bool, realIP net.IP, accountID string) error
DeletePeer(ctx context.Context, accountID, peerID, userID string) error DeletePeer(ctx context.Context, accountID, peerID, userID string) error
UpdatePeer(ctx context.Context, accountID, userID string, peer *nbpeer.Peer) (*nbpeer.Peer, error) UpdatePeer(ctx context.Context, accountID, userID string, peer *nbpeer.Peer) (*nbpeer.Peer, error)

View File

@ -2183,6 +2183,17 @@ paths:
summary: List all Peers summary: List all Peers
description: Returns a list of all peers description: Returns a list of all peers
tags: [ 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: security:
- BearerAuth: [ ] - BearerAuth: [ ]
- TokenAuth: [ ] - TokenAuth: [ ]

View File

@ -1580,6 +1580,15 @@ type UserRequest struct {
Role string `json:"role"` 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. // GetApiPeersPeerIdIngressPortsParams defines parameters for GetApiPeersPeerIdIngressPorts.
type GetApiPeersPeerIdIngressPortsParams struct { type GetApiPeersPeerIdIngressPortsParams struct {
// Name Filters ingress port allocations by name // Name Filters ingress port allocations by name

View File

@ -60,7 +60,7 @@ func (h *handler) getAllGroups(w http.ResponseWriter, r *http.Request) {
return return
} }
accountPeers, err := h.accountManager.GetPeers(r.Context(), accountID, userID) accountPeers, err := h.accountManager.GetPeers(r.Context(), accountID, userID, "", "")
if err != nil { if err != nil {
util.WriteError(r.Context(), err, w) util.WriteError(r.Context(), err, w)
return return
@ -154,7 +154,7 @@ func (h *handler) updateGroup(w http.ResponseWriter, r *http.Request) {
return return
} }
accountPeers, err := h.accountManager.GetPeers(r.Context(), accountID, userID) accountPeers, err := h.accountManager.GetPeers(r.Context(), accountID, userID, "", "")
if err != nil { if err != nil {
util.WriteError(r.Context(), err, w) util.WriteError(r.Context(), err, w)
return return
@ -213,7 +213,7 @@ func (h *handler) createGroup(w http.ResponseWriter, r *http.Request) {
return return
} }
accountPeers, err := h.accountManager.GetPeers(r.Context(), accountID, userID) accountPeers, err := h.accountManager.GetPeers(r.Context(), accountID, userID, "", "")
if err != nil { if err != nil {
util.WriteError(r.Context(), err, w) util.WriteError(r.Context(), err, w)
return return
@ -272,7 +272,7 @@ func (h *handler) getGroup(w http.ResponseWriter, r *http.Request) {
return return
} }
accountPeers, err := h.accountManager.GetPeers(r.Context(), accountID, userID) accountPeers, err := h.accountManager.GetPeers(r.Context(), accountID, userID, "", "")
if err != nil { if err != nil {
util.WriteError(r.Context(), err, w) util.WriteError(r.Context(), err, w)
return return

View File

@ -69,7 +69,7 @@ func initGroupTestData(initGroups ...*types.Group) *handler {
return nil, fmt.Errorf("unknown group name") 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 return maps.Values(TestPeers), nil
}, },
DeleteGroupFunc: func(_ context.Context, accountID, userId, groupID string) error { DeleteGroupFunc: func(_ context.Context, accountID, userId, groupID string) error {

View File

@ -186,7 +186,10 @@ func (h *Handler) GetAllPeers(w http.ResponseWriter, r *http.Request) {
return 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 { if err != nil {
util.WriteError(r.Context(), err, w) util.WriteError(r.Context(), err, w)
return return

View File

@ -125,7 +125,7 @@ func initTestMetaData(peers ...*nbpeer.Peer) *Handler {
} }
return p, nil 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 return peers, nil
}, },
GetPeerGroupsFunc: func(ctx context.Context, accountID, peerID string) ([]*types.Group, error) { GetPeerGroupsFunc: func(ctx context.Context, accountID, peerID string) ([]*types.Group, error) {

View File

@ -88,7 +88,7 @@ func (am *DefaultAccountManager) GetValidatedPeers(ctx context.Context, accountI
return err return err
} }
peers, err = transaction.GetAccountPeers(ctx, store.LockingStrengthShare, accountID) peers, err = transaction.GetAccountPeers(ctx, store.LockingStrengthShare, accountID, "", "")
return err return err
}) })
if err != nil { if err != nil {

View File

@ -31,7 +31,7 @@ type MockAccountManager struct {
GetAccountIDByUserIdFunc func(ctx context.Context, userId, domain string) (string, error) GetAccountIDByUserIdFunc func(ctx context.Context, userId, domain string) (string, error)
GetUserFunc func(ctx context.Context, claims jwtclaims.AuthorizationClaims) (*types.User, error) GetUserFunc func(ctx context.Context, claims jwtclaims.AuthorizationClaims) (*types.User, error)
ListUsersFunc func(ctx context.Context, accountID string) ([]*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 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) 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 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 // 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 { 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") return nil, status.Errorf(codes.Unimplemented, "method GetPeers is not implemented")
} }

View File

@ -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 // 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. // 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) user, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthShare, userID)
if err != nil { if err != nil {
return nil, err return nil, err
@ -76,7 +76,7 @@ func (am *DefaultAccountManager) GetPeers(ctx context.Context, accountID, userID
return []*nbpeer.Peer{}, nil 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 { if err != nil {
return nil, err return nil, err
} }

View File

@ -708,7 +708,7 @@ func TestDefaultAccountManager_GetPeers(t *testing.T) {
return return
} }
peers, err := manager.GetPeers(context.Background(), accountID, someUser) peers, err := manager.GetPeers(context.Background(), accountID, someUser, "", "")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
return return
@ -914,7 +914,7 @@ func BenchmarkGetPeers(b *testing.B) {
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
_, err := manager.GetPeers(context.Background(), accountID, userID) _, err := manager.GetPeers(context.Background(), accountID, userID, "", "")
if err != nil { if err != nil {
b.Fatalf("GetPeers failed: %v", err) b.Fatalf("GetPeers failed: %v", err)
} }

View File

@ -50,5 +50,5 @@ func (m *managerImpl) GetAllPeers(ctx context.Context, accountID, userID string)
return nil, status.NewPermissionDeniedError() return nil, status.NewPermissionDeniedError()
} }
return m.store.GetAccountPeers(ctx, store.LockingStrengthShare, accountID) return m.store.GetAccountPeers(ctx, store.LockingStrengthShare, accountID, "", "")
} }

View File

@ -1236,10 +1236,18 @@ func (s *SqlStore) GetPeerGroups(ctx context.Context, lockStrength LockingStreng
} }
// GetAccountPeers retrieves peers for an account. // 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 var peers []*nbpeer.Peer
result := s.db.Clauses(clause.Locking{Strength: string(lockStrength)}).Find(&peers, accountIDCondition, accountID) query := s.db.Clauses(clause.Locking{Strength: string(lockStrength)}).Where(accountIDCondition, accountID)
if err := result.Error; err != nil {
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) 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") return nil, status.Errorf(status.Internal, "failed to get peers from store")
} }

View File

@ -2666,6 +2666,8 @@ func TestSqlStore_GetAccountPeers(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
accountID string accountID string
nameFilter string
ipFilter string
expectedCount int expectedCount int
}{ }{
{ {
@ -2683,11 +2685,29 @@ func TestSqlStore_GetAccountPeers(t *testing.T) {
accountID: "", accountID: "",
expectedCount: 0, 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 { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { 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.NoError(t, err)
require.Len(t, peers, tt.expectedCount) require.Len(t, peers, tt.expectedCount)
}) })

View File

@ -105,7 +105,7 @@ type Store interface {
RemoveResourceFromGroup(ctx context.Context, accountId string, groupID string, resourceID string) error RemoveResourceFromGroup(ctx context.Context, accountId string, groupID string, resourceID string) error
AddPeerToAccount(ctx context.Context, lockStrength LockingStrength, peer *nbpeer.Peer) error AddPeerToAccount(ctx context.Context, lockStrength LockingStrength, peer *nbpeer.Peer) error
GetPeerByPeerPubKey(ctx context.Context, lockStrength LockingStrength, peerKey string) (*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) 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) 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) GetPeersByIDs(ctx context.Context, lockStrength LockingStrength, accountID string, peerIDs []string) (map[string]*nbpeer.Peer, error)