mirror of
https://github.com/netbirdio/netbird.git
synced 2025-04-29 22:05:23 +02:00
[management] Add accessible peers endpoint (#2579)
* move accessible peer to separate endpoint in api doc Signed-off-by: bcmmbaga <bethuelmbaga12@gmail.com> * add endpoint to get accessible peers Signed-off-by: bcmmbaga <bethuelmbaga12@gmail.com> * Update management/server/http/api/openapi.yml Co-authored-by: pascal-fischer <32096965+pascal-fischer@users.noreply.github.com> * Update management/server/http/api/openapi.yml Co-authored-by: pascal-fischer <32096965+pascal-fischer@users.noreply.github.com> * Update management/server/http/peers_handler.go Co-authored-by: pascal-fischer <32096965+pascal-fischer@users.noreply.github.com> --------- Signed-off-by: bcmmbaga <bethuelmbaga12@gmail.com> Co-authored-by: pascal-fischer <32096965+pascal-fischer@users.noreply.github.com>
This commit is contained in:
parent
4c130a0291
commit
170e842422
@ -251,7 +251,7 @@ components:
|
|||||||
- name
|
- name
|
||||||
- ssh_enabled
|
- ssh_enabled
|
||||||
- login_expiration_enabled
|
- login_expiration_enabled
|
||||||
PeerBase:
|
Peer:
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: '#/components/schemas/PeerMinimum'
|
- $ref: '#/components/schemas/PeerMinimum'
|
||||||
- type: object
|
- type: object
|
||||||
@ -378,25 +378,40 @@ components:
|
|||||||
description: User ID of the user that enrolled this peer
|
description: User ID of the user that enrolled this peer
|
||||||
type: string
|
type: string
|
||||||
example: google-oauth2|277474792786460067937
|
example: google-oauth2|277474792786460067937
|
||||||
|
os:
|
||||||
|
description: Peer's operating system and version
|
||||||
|
type: string
|
||||||
|
example: linux
|
||||||
|
country_code:
|
||||||
|
$ref: '#/components/schemas/CountryCode'
|
||||||
|
city_name:
|
||||||
|
$ref: '#/components/schemas/CityName'
|
||||||
|
geoname_id:
|
||||||
|
description: Unique identifier from the GeoNames database for a specific geographical location.
|
||||||
|
type: integer
|
||||||
|
example: 2643743
|
||||||
|
connected:
|
||||||
|
description: Peer to Management connection status
|
||||||
|
type: boolean
|
||||||
|
example: true
|
||||||
|
last_seen:
|
||||||
|
description: Last time peer connected to Netbird's management service
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
|
example: "2023-05-05T10:05:26.420578Z"
|
||||||
required:
|
required:
|
||||||
- ip
|
- ip
|
||||||
- dns_label
|
- dns_label
|
||||||
- user_id
|
- user_id
|
||||||
Peer:
|
- os
|
||||||
allOf:
|
- country_code
|
||||||
- $ref: '#/components/schemas/PeerBase'
|
- city_name
|
||||||
- type: object
|
- geoname_id
|
||||||
properties:
|
- connected
|
||||||
accessible_peers:
|
- last_seen
|
||||||
description: List of accessible peers
|
|
||||||
type: array
|
|
||||||
items:
|
|
||||||
$ref: '#/components/schemas/AccessiblePeer'
|
|
||||||
required:
|
|
||||||
- accessible_peers
|
|
||||||
PeerBatch:
|
PeerBatch:
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: '#/components/schemas/PeerBase'
|
- $ref: '#/components/schemas/Peer'
|
||||||
- type: object
|
- type: object
|
||||||
properties:
|
properties:
|
||||||
accessible_peers_count:
|
accessible_peers_count:
|
||||||
@ -1806,6 +1821,38 @@ paths:
|
|||||||
"$ref": "#/components/responses/forbidden"
|
"$ref": "#/components/responses/forbidden"
|
||||||
'500':
|
'500':
|
||||||
"$ref": "#/components/responses/internal_error"
|
"$ref": "#/components/responses/internal_error"
|
||||||
|
/api/peers/{peerId}/accessible-peers:
|
||||||
|
get:
|
||||||
|
summary: List accessible Peers
|
||||||
|
description: Returns a list of peers that the specified peer can connect to within the network.
|
||||||
|
tags: [ Peers ]
|
||||||
|
security:
|
||||||
|
- BearerAuth: [ ]
|
||||||
|
- TokenAuth: [ ]
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: peerId
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
description: The unique identifier of a peer
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: A JSON Array of Accessible Peers
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/AccessiblePeer'
|
||||||
|
'400':
|
||||||
|
"$ref": "#/components/responses/bad_request"
|
||||||
|
'401':
|
||||||
|
"$ref": "#/components/responses/requires_authentication"
|
||||||
|
'403':
|
||||||
|
"$ref": "#/components/responses/forbidden"
|
||||||
|
'500':
|
||||||
|
"$ref": "#/components/responses/internal_error"
|
||||||
/api/setup-keys:
|
/api/setup-keys:
|
||||||
get:
|
get:
|
||||||
summary: List all Setup Keys
|
summary: List all Setup Keys
|
||||||
|
@ -152,18 +152,36 @@ const (
|
|||||||
|
|
||||||
// AccessiblePeer defines model for AccessiblePeer.
|
// AccessiblePeer defines model for AccessiblePeer.
|
||||||
type AccessiblePeer struct {
|
type AccessiblePeer struct {
|
||||||
|
// CityName Commonly used English name of the city
|
||||||
|
CityName CityName `json:"city_name"`
|
||||||
|
|
||||||
|
// Connected Peer to Management connection status
|
||||||
|
Connected bool `json:"connected"`
|
||||||
|
|
||||||
|
// CountryCode 2-letter ISO 3166-1 alpha-2 code that represents the country
|
||||||
|
CountryCode CountryCode `json:"country_code"`
|
||||||
|
|
||||||
// DnsLabel Peer's DNS label is the parsed peer name for domain resolution. It is used to form an FQDN by appending the account's domain to the peer label. e.g. peer-dns-label.netbird.cloud
|
// DnsLabel Peer's DNS label is the parsed peer name for domain resolution. It is used to form an FQDN by appending the account's domain to the peer label. e.g. peer-dns-label.netbird.cloud
|
||||||
DnsLabel string `json:"dns_label"`
|
DnsLabel string `json:"dns_label"`
|
||||||
|
|
||||||
|
// GeonameId Unique identifier from the GeoNames database for a specific geographical location.
|
||||||
|
GeonameId int `json:"geoname_id"`
|
||||||
|
|
||||||
// Id Peer ID
|
// Id Peer ID
|
||||||
Id string `json:"id"`
|
Id string `json:"id"`
|
||||||
|
|
||||||
// Ip Peer's IP address
|
// Ip Peer's IP address
|
||||||
Ip string `json:"ip"`
|
Ip string `json:"ip"`
|
||||||
|
|
||||||
|
// LastSeen Last time peer connected to Netbird's management service
|
||||||
|
LastSeen time.Time `json:"last_seen"`
|
||||||
|
|
||||||
// Name Peer's hostname
|
// Name Peer's hostname
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
|
||||||
|
// Os Peer's operating system and version
|
||||||
|
Os string `json:"os"`
|
||||||
|
|
||||||
// UserId User ID of the user that enrolled this peer
|
// UserId User ID of the user that enrolled this peer
|
||||||
UserId string `json:"user_id"`
|
UserId string `json:"user_id"`
|
||||||
}
|
}
|
||||||
@ -490,81 +508,6 @@ type OSVersionCheck struct {
|
|||||||
|
|
||||||
// Peer defines model for Peer.
|
// Peer defines model for Peer.
|
||||||
type Peer struct {
|
type Peer struct {
|
||||||
// AccessiblePeers List of accessible peers
|
|
||||||
AccessiblePeers []AccessiblePeer `json:"accessible_peers"`
|
|
||||||
|
|
||||||
// ApprovalRequired (Cloud only) Indicates whether peer needs approval
|
|
||||||
ApprovalRequired bool `json:"approval_required"`
|
|
||||||
|
|
||||||
// CityName Commonly used English name of the city
|
|
||||||
CityName CityName `json:"city_name"`
|
|
||||||
|
|
||||||
// Connected Peer to Management connection status
|
|
||||||
Connected bool `json:"connected"`
|
|
||||||
|
|
||||||
// ConnectionIp Peer's public connection IP address
|
|
||||||
ConnectionIp string `json:"connection_ip"`
|
|
||||||
|
|
||||||
// CountryCode 2-letter ISO 3166-1 alpha-2 code that represents the country
|
|
||||||
CountryCode CountryCode `json:"country_code"`
|
|
||||||
|
|
||||||
// DnsLabel Peer's DNS label is the parsed peer name for domain resolution. It is used to form an FQDN by appending the account's domain to the peer label. e.g. peer-dns-label.netbird.cloud
|
|
||||||
DnsLabel string `json:"dns_label"`
|
|
||||||
|
|
||||||
// GeonameId Unique identifier from the GeoNames database for a specific geographical location.
|
|
||||||
GeonameId int `json:"geoname_id"`
|
|
||||||
|
|
||||||
// Groups Groups that the peer belongs to
|
|
||||||
Groups []GroupMinimum `json:"groups"`
|
|
||||||
|
|
||||||
// Hostname Hostname of the machine
|
|
||||||
Hostname string `json:"hostname"`
|
|
||||||
|
|
||||||
// Id Peer ID
|
|
||||||
Id string `json:"id"`
|
|
||||||
|
|
||||||
// Ip Peer's IP address
|
|
||||||
Ip string `json:"ip"`
|
|
||||||
|
|
||||||
// KernelVersion Peer's operating system kernel version
|
|
||||||
KernelVersion string `json:"kernel_version"`
|
|
||||||
|
|
||||||
// LastLogin Last time this peer performed log in (authentication). E.g., user authenticated.
|
|
||||||
LastLogin time.Time `json:"last_login"`
|
|
||||||
|
|
||||||
// LastSeen Last time peer connected to Netbird's management service
|
|
||||||
LastSeen time.Time `json:"last_seen"`
|
|
||||||
|
|
||||||
// LoginExpirationEnabled Indicates whether peer login expiration has been enabled or not
|
|
||||||
LoginExpirationEnabled bool `json:"login_expiration_enabled"`
|
|
||||||
|
|
||||||
// LoginExpired Indicates whether peer's login expired or not
|
|
||||||
LoginExpired bool `json:"login_expired"`
|
|
||||||
|
|
||||||
// Name Peer's hostname
|
|
||||||
Name string `json:"name"`
|
|
||||||
|
|
||||||
// Os Peer's operating system and version
|
|
||||||
Os string `json:"os"`
|
|
||||||
|
|
||||||
// SerialNumber System serial number
|
|
||||||
SerialNumber string `json:"serial_number"`
|
|
||||||
|
|
||||||
// SshEnabled Indicates whether SSH server is enabled on this peer
|
|
||||||
SshEnabled bool `json:"ssh_enabled"`
|
|
||||||
|
|
||||||
// UiVersion Peer's desktop UI version
|
|
||||||
UiVersion string `json:"ui_version"`
|
|
||||||
|
|
||||||
// UserId User ID of the user that enrolled this peer
|
|
||||||
UserId string `json:"user_id"`
|
|
||||||
|
|
||||||
// Version Peer's daemon or cli version
|
|
||||||
Version string `json:"version"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// PeerBase defines model for PeerBase.
|
|
||||||
type PeerBase struct {
|
|
||||||
// ApprovalRequired (Cloud only) Indicates whether peer needs approval
|
// ApprovalRequired (Cloud only) Indicates whether peer needs approval
|
||||||
ApprovalRequired bool `json:"approval_required"`
|
ApprovalRequired bool `json:"approval_required"`
|
||||||
|
|
||||||
|
@ -115,6 +115,7 @@ func (apiHandler *apiHandler) addPeersEndpoint() {
|
|||||||
apiHandler.Router.HandleFunc("/peers", peersHandler.GetAllPeers).Methods("GET", "OPTIONS")
|
apiHandler.Router.HandleFunc("/peers", peersHandler.GetAllPeers).Methods("GET", "OPTIONS")
|
||||||
apiHandler.Router.HandleFunc("/peers/{peerId}", peersHandler.HandlePeer).
|
apiHandler.Router.HandleFunc("/peers/{peerId}", peersHandler.HandlePeer).
|
||||||
Methods("GET", "PUT", "DELETE", "OPTIONS")
|
Methods("GET", "PUT", "DELETE", "OPTIONS")
|
||||||
|
apiHandler.Router.HandleFunc("/peers/{peerId}/accessible-peers", peersHandler.GetAccessiblePeers).Methods("GET", "OPTIONS")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (apiHandler *apiHandler) addUsersEndpoint() {
|
func (apiHandler *apiHandler) addUsersEndpoint() {
|
||||||
|
@ -71,12 +71,8 @@ func (h *PeersHandler) getPeer(ctx context.Context, account *server.Account, pee
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
customZone := account.GetPeersCustomZone(ctx, h.accountManager.GetDNSDomain())
|
|
||||||
netMap := account.GetPeerNetworkMap(ctx, peerID, customZone, validPeers, nil)
|
|
||||||
accessiblePeers := toAccessiblePeers(netMap, dnsDomain)
|
|
||||||
|
|
||||||
_, valid := validPeers[peer.ID]
|
_, valid := validPeers[peer.ID]
|
||||||
util.WriteJSONObject(ctx, w, toSinglePeerResponse(peerToReturn, groupsInfo, dnsDomain, accessiblePeers, valid))
|
util.WriteJSONObject(ctx, w, toSinglePeerResponse(peerToReturn, groupsInfo, dnsDomain, valid))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *PeersHandler) updatePeer(ctx context.Context, account *server.Account, user *server.User, peerID string, w http.ResponseWriter, r *http.Request) {
|
func (h *PeersHandler) updatePeer(ctx context.Context, account *server.Account, user *server.User, peerID string, w http.ResponseWriter, r *http.Request) {
|
||||||
@ -117,13 +113,9 @@ func (h *PeersHandler) updatePeer(ctx context.Context, account *server.Account,
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
customZone := account.GetPeersCustomZone(ctx, h.accountManager.GetDNSDomain())
|
|
||||||
netMap := account.GetPeerNetworkMap(ctx, peerID, customZone, validPeers, nil)
|
|
||||||
accessiblePeers := toAccessiblePeers(netMap, dnsDomain)
|
|
||||||
|
|
||||||
_, valid := validPeers[peer.ID]
|
_, valid := validPeers[peer.ID]
|
||||||
|
|
||||||
util.WriteJSONObject(r.Context(), w, toSinglePeerResponse(peer, groupMinimumInfo, dnsDomain, accessiblePeers, valid))
|
util.WriteJSONObject(r.Context(), w, toSinglePeerResponse(peer, groupMinimumInfo, dnsDomain, valid))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *PeersHandler) deletePeer(ctx context.Context, accountID, userID string, peerID string, w http.ResponseWriter) {
|
func (h *PeersHandler) deletePeer(ctx context.Context, accountID, userID string, peerID string, w http.ResponseWriter) {
|
||||||
@ -220,32 +212,66 @@ func (h *PeersHandler) setApprovalRequiredFlag(respBody []*api.PeerBatch, approv
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetAccessiblePeers returns a list of all peers that the specified peer can connect to within the network.
|
||||||
|
func (h *PeersHandler) GetAccessiblePeers(w http.ResponseWriter, r *http.Request) {
|
||||||
|
claims := h.claimsExtractor.FromRequestContext(r)
|
||||||
|
account, _, err := h.accountManager.GetAccountFromToken(r.Context(), claims)
|
||||||
|
if err != nil {
|
||||||
|
util.WriteError(r.Context(), err, w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
peerID := vars["peerId"]
|
||||||
|
if len(peerID) == 0 {
|
||||||
|
util.WriteError(r.Context(), status.Errorf(status.InvalidArgument, "invalid peer ID"), w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
dnsDomain := h.accountManager.GetDNSDomain()
|
||||||
|
|
||||||
|
validPeers, err := h.accountManager.GetValidatedPeers(account)
|
||||||
|
if err != nil {
|
||||||
|
log.WithContext(r.Context()).Errorf("failed to list approved peers: %v", err)
|
||||||
|
util.WriteError(r.Context(), fmt.Errorf("internal error"), w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
customZone := account.GetPeersCustomZone(r.Context(), h.accountManager.GetDNSDomain())
|
||||||
|
netMap := account.GetPeerNetworkMap(r.Context(), peerID, customZone, validPeers, nil)
|
||||||
|
|
||||||
|
util.WriteJSONObject(r.Context(), w, toAccessiblePeers(netMap, dnsDomain))
|
||||||
|
}
|
||||||
|
|
||||||
func toAccessiblePeers(netMap *server.NetworkMap, dnsDomain string) []api.AccessiblePeer {
|
func toAccessiblePeers(netMap *server.NetworkMap, dnsDomain string) []api.AccessiblePeer {
|
||||||
accessiblePeers := make([]api.AccessiblePeer, 0, len(netMap.Peers)+len(netMap.OfflinePeers))
|
accessiblePeers := make([]api.AccessiblePeer, 0, len(netMap.Peers)+len(netMap.OfflinePeers))
|
||||||
for _, p := range netMap.Peers {
|
for _, p := range netMap.Peers {
|
||||||
ap := api.AccessiblePeer{
|
accessiblePeers = append(accessiblePeers, peerToAccessiblePeer(p, dnsDomain))
|
||||||
Id: p.ID,
|
|
||||||
Name: p.Name,
|
|
||||||
Ip: p.IP.String(),
|
|
||||||
DnsLabel: fqdn(p, dnsDomain),
|
|
||||||
UserId: p.UserID,
|
|
||||||
}
|
|
||||||
accessiblePeers = append(accessiblePeers, ap)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, p := range netMap.OfflinePeers {
|
for _, p := range netMap.OfflinePeers {
|
||||||
ap := api.AccessiblePeer{
|
accessiblePeers = append(accessiblePeers, peerToAccessiblePeer(p, dnsDomain))
|
||||||
Id: p.ID,
|
|
||||||
Name: p.Name,
|
|
||||||
Ip: p.IP.String(),
|
|
||||||
DnsLabel: fqdn(p, dnsDomain),
|
|
||||||
UserId: p.UserID,
|
|
||||||
}
|
|
||||||
accessiblePeers = append(accessiblePeers, ap)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return accessiblePeers
|
return accessiblePeers
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func peerToAccessiblePeer(peer *nbpeer.Peer, dnsDomain string) api.AccessiblePeer {
|
||||||
|
return api.AccessiblePeer{
|
||||||
|
CityName: peer.Location.CityName,
|
||||||
|
Connected: peer.Status.Connected,
|
||||||
|
CountryCode: peer.Location.CountryCode,
|
||||||
|
DnsLabel: fqdn(peer, dnsDomain),
|
||||||
|
GeonameId: int(peer.Location.GeoNameID),
|
||||||
|
Id: peer.ID,
|
||||||
|
Ip: peer.IP.String(),
|
||||||
|
LastSeen: peer.Status.LastSeen,
|
||||||
|
Name: peer.Name,
|
||||||
|
Os: peer.Meta.OS,
|
||||||
|
UserId: peer.UserID,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func toGroupsInfo(groups map[string]*nbgroup.Group, peerID string) []api.GroupMinimum {
|
func toGroupsInfo(groups map[string]*nbgroup.Group, peerID string) []api.GroupMinimum {
|
||||||
var groupsInfo []api.GroupMinimum
|
var groupsInfo []api.GroupMinimum
|
||||||
groupsChecked := make(map[string]struct{})
|
groupsChecked := make(map[string]struct{})
|
||||||
@ -270,7 +296,7 @@ func toGroupsInfo(groups map[string]*nbgroup.Group, peerID string) []api.GroupMi
|
|||||||
return groupsInfo
|
return groupsInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
func toSinglePeerResponse(peer *nbpeer.Peer, groupsInfo []api.GroupMinimum, dnsDomain string, accessiblePeer []api.AccessiblePeer, approved bool) *api.Peer {
|
func toSinglePeerResponse(peer *nbpeer.Peer, groupsInfo []api.GroupMinimum, dnsDomain string, approved bool) *api.Peer {
|
||||||
osVersion := peer.Meta.OSVersion
|
osVersion := peer.Meta.OSVersion
|
||||||
if osVersion == "" {
|
if osVersion == "" {
|
||||||
osVersion = peer.Meta.Core
|
osVersion = peer.Meta.Core
|
||||||
@ -296,7 +322,6 @@ func toSinglePeerResponse(peer *nbpeer.Peer, groupsInfo []api.GroupMinimum, dnsD
|
|||||||
LoginExpirationEnabled: peer.LoginExpirationEnabled,
|
LoginExpirationEnabled: peer.LoginExpirationEnabled,
|
||||||
LastLogin: peer.LastLogin,
|
LastLogin: peer.LastLogin,
|
||||||
LoginExpired: peer.Status.LoginExpired,
|
LoginExpired: peer.Status.LoginExpired,
|
||||||
AccessiblePeers: accessiblePeer,
|
|
||||||
ApprovalRequired: !approved,
|
ApprovalRequired: !approved,
|
||||||
CountryCode: peer.Location.CountryCode,
|
CountryCode: peer.Location.CountryCode,
|
||||||
CityName: peer.Location.CityName,
|
CityName: peer.Location.CityName,
|
||||||
|
Loading…
Reference in New Issue
Block a user