[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)
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)

View File

@ -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: [ ]

View File

@ -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

View File

@ -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

View File

@ -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 {

View File

@ -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

View File

@ -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) {

View File

@ -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 {

View File

@ -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")
}

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
// 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
}

View File

@ -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)
}

View File

@ -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, "", "")
}

View File

@ -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")
}

View File

@ -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)
})

View File

@ -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)