mirror of
https://github.com/netbirdio/netbird.git
synced 2024-12-04 22:10:56 +01:00
extend example
This commit is contained in:
parent
27c3a4c5d6
commit
0c6c5fdc70
122
management/refactor/api/http/handler.go
Normal file
122
management/refactor/api/http/handler.go
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
"github.com/rs/cors"
|
||||||
|
|
||||||
|
"github.com/netbirdio/management-integrations/integrations"
|
||||||
|
"github.com/netbirdio/netbird/management/refactor/resources/peers"
|
||||||
|
s "github.com/netbirdio/netbird/management/server"
|
||||||
|
"github.com/netbirdio/netbird/management/server/geolocation"
|
||||||
|
|
||||||
|
"github.com/netbirdio/netbird/management/server/http/middleware"
|
||||||
|
"github.com/netbirdio/netbird/management/server/jwtclaims"
|
||||||
|
"github.com/netbirdio/netbird/management/server/telemetry"
|
||||||
|
)
|
||||||
|
|
||||||
|
const apiPrefix = "/api"
|
||||||
|
|
||||||
|
// AuthCfg contains parameters for authentication middleware
|
||||||
|
type AuthCfg struct {
|
||||||
|
Issuer string
|
||||||
|
Audience string
|
||||||
|
UserIDClaim string
|
||||||
|
KeysLocation string
|
||||||
|
}
|
||||||
|
|
||||||
|
type DefaultAPIHandler struct {
|
||||||
|
Router *mux.Router
|
||||||
|
AccountManager s.AccountManager
|
||||||
|
geolocationManager *geolocation.Geolocation
|
||||||
|
AuthCfg AuthCfg
|
||||||
|
}
|
||||||
|
|
||||||
|
// EmptyObject is an empty struct used to return empty JSON object
|
||||||
|
type EmptyObject struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDefaultAPIHandler creates the Management service HTTP API handler registering all the available endpoints.
|
||||||
|
func NewDefaultAPIHandler(ctx context.Context, jwtValidator jwtclaims.JWTValidator, appMetrics telemetry.AppMetrics, authCfg AuthCfg) (http.Handler, error) {
|
||||||
|
claimsExtractor := jwtclaims.NewClaimsExtractor(
|
||||||
|
jwtclaims.WithAudience(authCfg.Audience),
|
||||||
|
jwtclaims.WithUserIDClaim(authCfg.UserIDClaim),
|
||||||
|
)
|
||||||
|
|
||||||
|
authMiddleware := middleware.NewAuthMiddleware(
|
||||||
|
accountManager.GetAccountFromPAT,
|
||||||
|
jwtValidator.ValidateAndParse,
|
||||||
|
accountManager.MarkPATUsed,
|
||||||
|
accountManager.CheckUserAccessByJWTGroups,
|
||||||
|
claimsExtractor,
|
||||||
|
authCfg.Audience,
|
||||||
|
authCfg.UserIDClaim,
|
||||||
|
)
|
||||||
|
|
||||||
|
corsMiddleware := cors.AllowAll()
|
||||||
|
|
||||||
|
acMiddleware := middleware.NewAccessControl(
|
||||||
|
authCfg.Audience,
|
||||||
|
authCfg.UserIDClaim,
|
||||||
|
accountManager.GetUser)
|
||||||
|
|
||||||
|
rootRouter := mux.NewRouter()
|
||||||
|
metricsMiddleware := appMetrics.HTTPMiddleware()
|
||||||
|
|
||||||
|
prefix := apiPrefix
|
||||||
|
router := rootRouter.PathPrefix(prefix).Subrouter()
|
||||||
|
router.Use(metricsMiddleware.Handler, corsMiddleware.Handler, authMiddleware.Handler, acMiddleware.Handler)
|
||||||
|
|
||||||
|
api := DefaultAPIHandler{
|
||||||
|
Router: router,
|
||||||
|
AccountManager: accountManager,
|
||||||
|
geolocationManager: LocationManager,
|
||||||
|
AuthCfg: authCfg,
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := integrations.RegisterHandlers(ctx, prefix, api.Router, accountManager, claimsExtractor); err != nil {
|
||||||
|
return nil, fmt.Errorf("register integrations endpoints: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
peers.RegisterPeersEndpoints(api.Router)
|
||||||
|
// api.addAccountsEndpoint()
|
||||||
|
// api.addPeersEndpoint()
|
||||||
|
// api.addUsersEndpoint()
|
||||||
|
// api.addUsersTokensEndpoint()
|
||||||
|
// api.addSetupKeysEndpoint()
|
||||||
|
// api.addRulesEndpoint()
|
||||||
|
// api.addPoliciesEndpoint()
|
||||||
|
// api.addGroupsEndpoint()
|
||||||
|
// api.addRoutesEndpoint()
|
||||||
|
// api.addDNSNameserversEndpoint()
|
||||||
|
// api.addDNSSettingEndpoint()
|
||||||
|
// api.addEventsEndpoint()
|
||||||
|
// api.addPostureCheckEndpoint()
|
||||||
|
// api.addLocationsEndpoint()
|
||||||
|
|
||||||
|
err := api.Router.Walk(func(route *mux.Route, _ *mux.Router, _ []*mux.Route) error {
|
||||||
|
methods, err := route.GetMethods()
|
||||||
|
if err != nil { // we may have wildcard routes from integrations without methods, skip them for now
|
||||||
|
methods = []string{}
|
||||||
|
}
|
||||||
|
for _, method := range methods {
|
||||||
|
template, err := route.GetPathTemplate()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = metricsMiddleware.AddHTTPRequestResponseCounter(template, method)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rootRouter, nil
|
||||||
|
}
|
7
management/refactor/api/http/specs/cfg.yaml
Normal file
7
management/refactor/api/http/specs/cfg.yaml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package: api
|
||||||
|
generate:
|
||||||
|
models: true
|
||||||
|
embedded-spec: false
|
||||||
|
output: types.gen.go
|
||||||
|
compatibility:
|
||||||
|
always-prefix-enum-values: true
|
16
management/refactor/api/http/specs/generate.sh
Executable file
16
management/refactor/api/http/specs/generate.sh
Executable file
@ -0,0 +1,16 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if ! which realpath > /dev/null 2>&1
|
||||||
|
then
|
||||||
|
echo realpath is not installed
|
||||||
|
echo run: brew install coreutils
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
old_pwd=$(pwd)
|
||||||
|
script_path=$(dirname $(realpath "$0"))
|
||||||
|
cd "$script_path"
|
||||||
|
go install github.com/deepmap/oapi-codegen/cmd/oapi-codegen@4a1477f6a8ba6ca8115cc23bb2fb67f0b9fca18e
|
||||||
|
oapi-codegen --config cfg.yaml openapi.yml
|
||||||
|
cd "$old_pwd"
|
2870
management/refactor/api/http/specs/openapi.yaml
Normal file
2870
management/refactor/api/http/specs/openapi.yaml
Normal file
File diff suppressed because it is too large
Load Diff
1
management/refactor/api/http/specs/types.gen.go
Normal file
1
management/refactor/api/http/specs/types.gen.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package specs
|
@ -3,11 +3,16 @@ package mesh
|
|||||||
import (
|
import (
|
||||||
"github.com/netbirdio/management-integrations/integrations"
|
"github.com/netbirdio/management-integrations/integrations"
|
||||||
nbdns "github.com/netbirdio/netbird/dns"
|
nbdns "github.com/netbirdio/netbird/dns"
|
||||||
"github.com/netbirdio/netbird/management/refactor/peers"
|
"github.com/netbirdio/netbird/management/refactor/api/http"
|
||||||
"github.com/netbirdio/netbird/management/refactor/policies"
|
"github.com/netbirdio/netbird/management/refactor/resources/network"
|
||||||
"github.com/netbirdio/netbird/management/refactor/settings"
|
networkTypes "github.com/netbirdio/netbird/management/refactor/resources/network/types"
|
||||||
|
"github.com/netbirdio/netbird/management/refactor/resources/peers"
|
||||||
|
peerTypes "github.com/netbirdio/netbird/management/refactor/resources/peers/types"
|
||||||
|
"github.com/netbirdio/netbird/management/refactor/resources/policies"
|
||||||
|
"github.com/netbirdio/netbird/management/refactor/resources/routes"
|
||||||
|
"github.com/netbirdio/netbird/management/refactor/resources/settings"
|
||||||
|
"github.com/netbirdio/netbird/management/refactor/resources/users"
|
||||||
"github.com/netbirdio/netbird/management/refactor/store"
|
"github.com/netbirdio/netbird/management/refactor/store"
|
||||||
"github.com/netbirdio/netbird/management/refactor/users"
|
|
||||||
"github.com/netbirdio/netbird/management/server/activity"
|
"github.com/netbirdio/netbird/management/server/activity"
|
||||||
"github.com/netbirdio/netbird/management/server/status"
|
"github.com/netbirdio/netbird/management/server/status"
|
||||||
)
|
)
|
||||||
@ -23,16 +28,22 @@ type DefaultController struct {
|
|||||||
userManager users.Manager
|
userManager users.Manager
|
||||||
policiesManager policies.Manager
|
policiesManager policies.Manager
|
||||||
settingsManager settings.Manager
|
settingsManager settings.Manager
|
||||||
|
networkManager network.Manager
|
||||||
|
routesManager routes.Manager
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDefaultController() *DefaultController {
|
func NewDefaultController() *DefaultController {
|
||||||
storeStore, _ := store.NewDefaultStore(store.SqliteStoreEngine, "", nil)
|
storeStore, _ := store.NewDefaultStore(store.SqliteStoreEngine, "", nil)
|
||||||
settingsManager := settings.NewDefaultManager(storeStore)
|
settingsManager := settings.NewDefaultManager(storeStore)
|
||||||
|
networkManager := network.NewDefaultManager()
|
||||||
peersManager := peers.NewDefaultManager(storeStore, settingsManager)
|
peersManager := peers.NewDefaultManager(storeStore, settingsManager)
|
||||||
|
routesManager := routes.NewDefaultManager(storeStore, peersManager)
|
||||||
usersManager := users.NewDefaultManager(storeStore, peersManager)
|
usersManager := users.NewDefaultManager(storeStore, peersManager)
|
||||||
policiesManager := policies.NewDefaultManager(storeStore, peersManager)
|
policiesManager := policies.NewDefaultManager(storeStore, peersManager)
|
||||||
|
|
||||||
peersManager, settingsManager, usersManager, policiesManager, storeStore = integrations.InjectCloud(peersManager, policiesManager, settingsManager, usersManager, storeStore)
|
apiHandler, _ := http.NewDefaultAPIHandler()
|
||||||
|
|
||||||
|
peersManager, settingsManager, usersManager, policiesManager, storeStore, apiHandler = integrations.InjectCloud(peersManager, policiesManager, settingsManager, usersManager, storeStore)
|
||||||
|
|
||||||
return &DefaultController{
|
return &DefaultController{
|
||||||
store: storeStore,
|
store: storeStore,
|
||||||
@ -40,10 +51,12 @@ func NewDefaultController() *DefaultController {
|
|||||||
userManager: usersManager,
|
userManager: usersManager,
|
||||||
policiesManager: policiesManager,
|
policiesManager: policiesManager,
|
||||||
settingsManager: settingsManager,
|
settingsManager: settingsManager,
|
||||||
|
networkManager: networkManager,
|
||||||
|
routesManager: routesManager,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *DefaultController) LoginPeer(login peers.PeerLogin) {
|
func (c *DefaultController) LoginPeer(login peerTypes.PeerLogin) (*peerTypes.Peer, *networkTypes.NetworkMap, error) {
|
||||||
|
|
||||||
peer, err := c.peersManager.GetPeerByPubKey(login.WireGuardPubKey)
|
peer, err := c.peersManager.GetPeerByPubKey(login.WireGuardPubKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -60,7 +73,7 @@ func (c *DefaultController) LoginPeer(login peers.PeerLogin) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
account, err := pm.accountManager.GetAccount(peer.GetAccountID())
|
settings, err := c.settingsManager.GetSettings(peer.GetAccountID())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@ -68,7 +81,7 @@ func (c *DefaultController) LoginPeer(login peers.PeerLogin) {
|
|||||||
// this flag prevents unnecessary calls to the persistent store.
|
// this flag prevents unnecessary calls to the persistent store.
|
||||||
shouldStorePeer := false
|
shouldStorePeer := false
|
||||||
updateRemotePeers := false
|
updateRemotePeers := false
|
||||||
if peerLoginExpired(peer, account) {
|
if peerLoginExpired(peer, settings) {
|
||||||
err = checkAuth(login.UserID, peer)
|
err = checkAuth(login.UserID, peer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
@ -79,7 +92,7 @@ func (c *DefaultController) LoginPeer(login peers.PeerLogin) {
|
|||||||
updateRemotePeers = true
|
updateRemotePeers = true
|
||||||
shouldStorePeer = true
|
shouldStorePeer = true
|
||||||
|
|
||||||
pm.eventsManager.StoreEvent(login.UserID, peer.ID, account.Id, activity.UserLoggedInPeer, peer.EventMeta(pm.accountManager.GetDNSDomain()))
|
pm.eventsManager.StoreEvent(login.UserID, peer.GetID(), peer.GetAccountID(), activity.UserLoggedInPeer, peer.EventMeta(pm.accountManager.GetDNSDomain()))
|
||||||
}
|
}
|
||||||
|
|
||||||
if peer.UpdateMetaIfNew(login.Meta) {
|
if peer.UpdateMetaIfNew(login.Meta) {
|
||||||
@ -107,29 +120,37 @@ func (c *DefaultController) SyncPeer() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *DefaultController) GetPeerNetworkMap(peerID, dnsDomain string) *NetworkMap {
|
func (c *DefaultController) GetPeerNetworkMap(accountID, peerID, dnsDomain string) (*networkTypes.NetworkMap, error) {
|
||||||
|
unlock := c.store.AcquireAccountLock(accountID)
|
||||||
|
defer unlock()
|
||||||
|
|
||||||
|
network, err := c.networkManager.GetNetwork(accountID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
peer, err := c.peersManager.GetNetworkPeerByID(peerID)
|
peer, err := c.peersManager.GetNetworkPeerByID(peerID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &NetworkMap{
|
return &networkTypes.NetworkMap{
|
||||||
Network: a.Network.Copy(),
|
Network: network.Copy(),
|
||||||
}
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
aclPeers, firewallRules := c.policiesManager.GetAccessiblePeersAndFirewallRules(peerID)
|
aclPeers, firewallRules := c.policiesManager.GetAccessiblePeersAndFirewallRules(peerID)
|
||||||
// exclude expired peers
|
// exclude expired peers
|
||||||
var peersToConnect []peers.Peer
|
var peersToConnect []*peerTypes.Peer
|
||||||
var expiredPeers []peers.Peer
|
var expiredPeers []*peerTypes.Peer
|
||||||
accSettings, _ := c.settingsManager.GetSettings(peer.GetAccountID())
|
accSettings, _ := c.settingsManager.GetSettings(peer.GetAccountID())
|
||||||
for _, p := range aclPeers {
|
for _, p := range aclPeers {
|
||||||
expired, _ := p.LoginExpired(accSettings.GetPeerLoginExpiration())
|
expired, _ := p.LoginExpired(accSettings.GetPeerLoginExpiration())
|
||||||
if accSettings.GetPeerLoginExpirationEnabled() && expired {
|
if accSettings.GetPeerLoginExpirationEnabled() && expired {
|
||||||
expiredPeers = append(expiredPeers, p)
|
expiredPeers = append(expiredPeers, &p)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
peersToConnect = append(peersToConnect, p)
|
peersToConnect = append(peersToConnect, &p)
|
||||||
}
|
}
|
||||||
|
|
||||||
routesUpdate := a.getRoutesToSync(peerID, peersToConnect)
|
routesUpdate := c.routesManager.GetRoutesToSync(peerID, peersToConnect, accountID)
|
||||||
|
|
||||||
dnsManagementStatus := a.getPeerDNSManagementStatus(peerID)
|
dnsManagementStatus := a.getPeerDNSManagementStatus(peerID)
|
||||||
dnsUpdate := nbdns.Config{
|
dnsUpdate := nbdns.Config{
|
||||||
@ -146,12 +167,12 @@ func (c *DefaultController) GetPeerNetworkMap(peerID, dnsDomain string) *Network
|
|||||||
dnsUpdate.NameServerGroups = getPeerNSGroups(a, peerID)
|
dnsUpdate.NameServerGroups = getPeerNSGroups(a, peerID)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &NetworkMap{
|
return &networkTypes.NetworkMap{
|
||||||
Peers: peersToConnect,
|
Peers: peersToConnect,
|
||||||
Network: a.Network.Copy(),
|
Network: network.Copy(),
|
||||||
Routes: routesUpdate,
|
Routes: routesUpdate,
|
||||||
DNSConfig: dnsUpdate,
|
DNSConfig: dnsUpdate,
|
||||||
OfflinePeers: expiredPeers,
|
OfflinePeers: expiredPeers,
|
||||||
FirewallRules: firewallRules,
|
FirewallRules: firewallRules,
|
||||||
}
|
}, nil
|
||||||
}
|
}
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
package mesh
|
|
||||||
|
|
||||||
import (
|
|
||||||
nbdns "github.com/netbirdio/netbird/dns"
|
|
||||||
nbpeer "github.com/netbirdio/netbird/management/server/peer"
|
|
||||||
)
|
|
||||||
|
|
||||||
type NetworkMap struct {
|
|
||||||
Peers []*nbpeer.Peer
|
|
||||||
Network *Network
|
|
||||||
Routes []*route.Route
|
|
||||||
DNSConfig nbdns.Config
|
|
||||||
OfflinePeers []*nbpeer.Peer
|
|
||||||
FirewallRules []*FirewallRule
|
|
||||||
}
|
|
@ -1,50 +0,0 @@
|
|||||||
package peers
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/netbirdio/netbird/management/refactor/settings"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Manager interface {
|
|
||||||
GetPeerByPubKey(pubKey string) (Peer, error)
|
|
||||||
GetPeerByID(id string) (Peer, error)
|
|
||||||
GetNetworkPeerByID(id string) (Peer, error)
|
|
||||||
GetNetworkPeersInAccount(id string) ([]Peer, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type DefaultManager struct {
|
|
||||||
repository Repository
|
|
||||||
settingsManager settings.Manager
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDefaultManager(repository Repository, settingsManager settings.Manager) *DefaultManager {
|
|
||||||
return &DefaultManager{
|
|
||||||
repository: repository,
|
|
||||||
settingsManager: settingsManager,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (dm *DefaultManager) GetNetworkPeerByID(id string) (Peer, error) {
|
|
||||||
return dm.repository.FindPeerByID(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (dm *DefaultManager) GetNetworkPeersInAccount(id string) ([]Peer, error) {
|
|
||||||
defaultPeers, err := dm.repository.FindAllPeersInAccount(id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
peers := make([]Peer, len(defaultPeers))
|
|
||||||
for _, dp := range defaultPeers {
|
|
||||||
peers = append(peers, dp)
|
|
||||||
}
|
|
||||||
|
|
||||||
return peers, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (dm *DefaultManager) GetPeerByPubKey(pubKey string) (Peer, error) {
|
|
||||||
return dm.repository.FindPeerByPubKey(pubKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (dm *DefaultManager) GetPeerByID(id string) (Peer, error) {
|
|
||||||
return dm.repository.FindPeerByID(id)
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
package peers
|
|
||||||
|
|
||||||
type Repository interface {
|
|
||||||
FindPeerByPubKey(pubKey string) (Peer, error)
|
|
||||||
FindPeerByID(id string) (Peer, error)
|
|
||||||
FindAllPeersInAccount(id string) ([]Peer, error)
|
|
||||||
UpdatePeer(peer Peer) error
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
package policies
|
|
||||||
|
|
||||||
type Policy interface {
|
|
||||||
}
|
|
||||||
|
|
||||||
type DefaultPolicy struct {
|
|
||||||
}
|
|
1
management/refactor/resources/dns/api.go
Normal file
1
management/refactor/resources/dns/api.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package dns
|
1
management/refactor/resources/dns/manager.go
Normal file
1
management/refactor/resources/dns/manager.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package dns
|
1
management/refactor/resources/dns/repository.go
Normal file
1
management/refactor/resources/dns/repository.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package dns
|
11
management/refactor/resources/dns/types/config.go
Normal file
11
management/refactor/resources/dns/types/config.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
// Config represents a dns configuration that is exchanged between management and peers
|
||||||
|
type Config struct {
|
||||||
|
// ServiceEnable indicates if the service should be enabled
|
||||||
|
ServiceEnable bool
|
||||||
|
// NameServerGroups contains a list of nameserver group
|
||||||
|
NameServerGroups []*NameServerGroup
|
||||||
|
// CustomZones contains a list of custom zone
|
||||||
|
CustomZones []CustomZone
|
||||||
|
}
|
9
management/refactor/resources/dns/types/custom_zone.go
Normal file
9
management/refactor/resources/dns/types/custom_zone.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
// CustomZone represents a custom zone to be resolved by the dns server
|
||||||
|
type CustomZone struct {
|
||||||
|
// Domain is the zone's domain
|
||||||
|
Domain string
|
||||||
|
// Records custom zone records
|
||||||
|
Records []SimpleRecord
|
||||||
|
}
|
75
management/refactor/resources/dns/types/name_server.go
Normal file
75
management/refactor/resources/dns/types/name_server.go
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import "net/netip"
|
||||||
|
|
||||||
|
// NameServerType nameserver type
|
||||||
|
type NameServerType int
|
||||||
|
|
||||||
|
// NameServer represents a DNS nameserver
|
||||||
|
type NameServer struct {
|
||||||
|
// IP address of nameserver
|
||||||
|
IP netip.Addr
|
||||||
|
// NSType nameserver type
|
||||||
|
NSType NameServerType
|
||||||
|
// Port nameserver listening port
|
||||||
|
Port int
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy copies a nameserver object
|
||||||
|
func (n *NameServer) Copy() *NameServer {
|
||||||
|
return &NameServer{
|
||||||
|
IP: n.IP,
|
||||||
|
NSType: n.NSType,
|
||||||
|
Port: n.Port,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEqual compares one nameserver with the other
|
||||||
|
func (n *NameServer) IsEqual(other *NameServer) bool {
|
||||||
|
return other.IP == n.IP &&
|
||||||
|
other.NSType == n.NSType &&
|
||||||
|
other.Port == n.Port
|
||||||
|
}
|
||||||
|
|
||||||
|
func compareNameServerList(list, other []NameServer) bool {
|
||||||
|
if len(list) != len(other) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ns := range list {
|
||||||
|
if !containsNameServer(ns, other) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func containsNameServer(element NameServer, list []NameServer) bool {
|
||||||
|
for _, ns := range list {
|
||||||
|
if ns.IsEqual(&element) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func compareGroupsList(list, other []string) bool {
|
||||||
|
if len(list) != len(other) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, id := range list {
|
||||||
|
match := false
|
||||||
|
for _, otherID := range other {
|
||||||
|
if id == otherID {
|
||||||
|
match = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !match {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
65
management/refactor/resources/dns/types/name_server_group.go
Normal file
65
management/refactor/resources/dns/types/name_server_group.go
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
type NameServerGroup interface {
|
||||||
|
}
|
||||||
|
|
||||||
|
type DefaultNameServerGroup struct {
|
||||||
|
// ID identifier of group
|
||||||
|
ID string `gorm:"primaryKey"`
|
||||||
|
// AccountID is a reference to Account that this object belongs
|
||||||
|
AccountID string `gorm:"index"`
|
||||||
|
// Name group name
|
||||||
|
Name string
|
||||||
|
// Description group description
|
||||||
|
Description string
|
||||||
|
// NameServers list of nameservers
|
||||||
|
NameServers []NameServer `gorm:"serializer:json"`
|
||||||
|
// Groups list of peer group IDs to distribute the nameservers information
|
||||||
|
Groups []string `gorm:"serializer:json"`
|
||||||
|
// Primary indicates that the nameserver group is the primary resolver for any dns query
|
||||||
|
Primary bool
|
||||||
|
// Domains indicate the dns query domains to use with this nameserver group
|
||||||
|
Domains []string `gorm:"serializer:json"`
|
||||||
|
// Enabled group status
|
||||||
|
Enabled bool
|
||||||
|
// SearchDomainsEnabled indicates whether to add match domains to search domains list or not
|
||||||
|
SearchDomainsEnabled bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// EventMeta returns activity event meta related to the nameserver group
|
||||||
|
func (g *DefaultNameServerGroup) EventMeta() map[string]any {
|
||||||
|
return map[string]any{"name": g.Name}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy copies a nameserver group object
|
||||||
|
func (g *DefaultNameServerGroup) Copy() *DefaultNameServerGroup {
|
||||||
|
nsGroup := &DefaultNameServerGroup{
|
||||||
|
ID: g.ID,
|
||||||
|
Name: g.Name,
|
||||||
|
Description: g.Description,
|
||||||
|
NameServers: make([]NameServer, len(g.NameServers)),
|
||||||
|
Groups: make([]string, len(g.Groups)),
|
||||||
|
Enabled: g.Enabled,
|
||||||
|
Primary: g.Primary,
|
||||||
|
Domains: make([]string, len(g.Domains)),
|
||||||
|
SearchDomainsEnabled: g.SearchDomainsEnabled,
|
||||||
|
}
|
||||||
|
|
||||||
|
copy(nsGroup.NameServers, g.NameServers)
|
||||||
|
copy(nsGroup.Groups, g.Groups)
|
||||||
|
copy(nsGroup.Domains, g.Domains)
|
||||||
|
|
||||||
|
return nsGroup
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEqual compares one nameserver group with the other
|
||||||
|
func (g *DefaultNameServerGroup) IsEqual(other *DefaultNameServerGroup) bool {
|
||||||
|
return other.ID == g.ID &&
|
||||||
|
other.Name == g.Name &&
|
||||||
|
other.Description == g.Description &&
|
||||||
|
other.Primary == g.Primary &&
|
||||||
|
other.SearchDomainsEnabled == g.SearchDomainsEnabled &&
|
||||||
|
compareNameServerList(g.NameServers, other.NameServers) &&
|
||||||
|
compareGroupsList(g.Groups, other.Groups) &&
|
||||||
|
compareGroupsList(g.Domains, other.Domains)
|
||||||
|
}
|
7
management/refactor/resources/dns/types/settings.go
Normal file
7
management/refactor/resources/dns/types/settings.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
type Settings interface {
|
||||||
|
}
|
||||||
|
|
||||||
|
type DefaultSettings struct {
|
||||||
|
}
|
53
management/refactor/resources/dns/types/simpe_record.go
Normal file
53
management/refactor/resources/dns/types/simpe_record.go
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SimpleRecord provides a simple DNS record specification for CNAME, A and AAAA records
|
||||||
|
type SimpleRecord struct {
|
||||||
|
// Name domain name
|
||||||
|
Name string
|
||||||
|
// Type of record, 1 for A, 5 for CNAME, 28 for AAAA. see https://pkg.go.dev/github.com/miekg/dns@v1.1.41#pkg-constants
|
||||||
|
Type int
|
||||||
|
// Class dns class, currently use the DefaultClass for all records
|
||||||
|
Class string
|
||||||
|
// TTL time-to-live for the record
|
||||||
|
TTL int
|
||||||
|
// RData is the actual value resolved in a dns query
|
||||||
|
RData string
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns a string of the simple record formatted as:
|
||||||
|
// <Name> <TTL> <Class> <Type> <RDATA>
|
||||||
|
func (s SimpleRecord) String() string {
|
||||||
|
fqdn := dns.Fqdn(s.Name)
|
||||||
|
return fmt.Sprintf("%s %d %s %s %s", fqdn, s.TTL, s.Class, dns.Type(s.Type).String(), s.RData)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Len returns the length of the RData field, based on its type
|
||||||
|
func (s SimpleRecord) Len() uint16 {
|
||||||
|
emptyString := s.RData == ""
|
||||||
|
switch s.Type {
|
||||||
|
case 1:
|
||||||
|
if emptyString {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return net.IPv4len
|
||||||
|
case 5:
|
||||||
|
if emptyString || s.RData == "." {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return uint16(len(s.RData) + 1)
|
||||||
|
case 28:
|
||||||
|
if emptyString {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return net.IPv6len
|
||||||
|
default:
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
1
management/refactor/resources/groups/api.go
Normal file
1
management/refactor/resources/groups/api.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package groups
|
1
management/refactor/resources/groups/manager.go
Normal file
1
management/refactor/resources/groups/manager.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package groups
|
1
management/refactor/resources/groups/repository.go
Normal file
1
management/refactor/resources/groups/repository.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package groups
|
23
management/refactor/resources/groups/types/group.go
Normal file
23
management/refactor/resources/groups/types/group.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
type Group interface {
|
||||||
|
}
|
||||||
|
|
||||||
|
type DefaultGroup struct {
|
||||||
|
// ID of the group
|
||||||
|
ID string
|
||||||
|
|
||||||
|
// AccountID is a reference to Account that this object belongs
|
||||||
|
AccountID string `json:"-" gorm:"index"`
|
||||||
|
|
||||||
|
// Name visible in the UI
|
||||||
|
Name string
|
||||||
|
|
||||||
|
// Issued of the group
|
||||||
|
Issued string
|
||||||
|
|
||||||
|
// Peers list of the group
|
||||||
|
Peers []string `gorm:"serializer:json"`
|
||||||
|
|
||||||
|
IntegrationReference IntegrationReference `gorm:"embedded;embeddedPrefix:integration_ref_"`
|
||||||
|
}
|
1
management/refactor/resources/network/api.go
Normal file
1
management/refactor/resources/network/api.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package network
|
19
management/refactor/resources/network/manager.go
Normal file
19
management/refactor/resources/network/manager.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package network
|
||||||
|
|
||||||
|
import "github.com/netbirdio/netbird/management/refactor/resources/network/types"
|
||||||
|
|
||||||
|
type Manager interface {
|
||||||
|
GetNetwork(accountID string) (types.Network, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type DefaultManager struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDefaultManager() *DefaultManager {
|
||||||
|
return &DefaultManager{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d DefaultManager) GetNetwork(accountID string) (types.Network, error) {
|
||||||
|
// TODO implement me
|
||||||
|
panic("implement me")
|
||||||
|
}
|
1
management/refactor/resources/network/repository.go
Normal file
1
management/refactor/resources/network/repository.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package network
|
70
management/refactor/resources/network/types/network.go
Normal file
70
management/refactor/resources/network/types/network.go
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/rand"
|
||||||
|
"net"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/c-robinson/iplib"
|
||||||
|
"github.com/rs/xid"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// SubnetSize is a size of the subnet of the global network, e.g. 100.77.0.0/16
|
||||||
|
SubnetSize = 16
|
||||||
|
// NetSize is a global network size 100.64.0.0/10
|
||||||
|
NetSize = 10
|
||||||
|
)
|
||||||
|
|
||||||
|
type Network struct {
|
||||||
|
Identifier string `json:"id"`
|
||||||
|
Net net.IPNet `gorm:"serializer:gob"`
|
||||||
|
Dns string
|
||||||
|
// Serial is an ID that increments by 1 when any change to the network happened (e.g. new peer has been added).
|
||||||
|
// Used to synchronize state to the client apps.
|
||||||
|
Serial uint64
|
||||||
|
|
||||||
|
mu sync.Mutex `json:"-" gorm:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewNetwork creates a new Network initializing it with a Serial=0
|
||||||
|
// It takes a random /16 subnet from 100.64.0.0/10 (64 different subnets)
|
||||||
|
func NewNetwork() *Network {
|
||||||
|
|
||||||
|
n := iplib.NewNet4(net.ParseIP("100.64.0.0"), NetSize)
|
||||||
|
sub, _ := n.Subnet(SubnetSize)
|
||||||
|
|
||||||
|
s := rand.NewSource(time.Now().Unix())
|
||||||
|
r := rand.New(s)
|
||||||
|
intn := r.Intn(len(sub))
|
||||||
|
|
||||||
|
return &Network{
|
||||||
|
Identifier: xid.New().String(),
|
||||||
|
Net: sub[intn].IPNet,
|
||||||
|
Dns: "",
|
||||||
|
Serial: 0}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IncSerial increments Serial by 1 reflecting that the network state has been changed
|
||||||
|
func (n *Network) IncSerial() {
|
||||||
|
n.mu.Lock()
|
||||||
|
defer n.mu.Unlock()
|
||||||
|
n.Serial++
|
||||||
|
}
|
||||||
|
|
||||||
|
// CurrentSerial returns the Network.Serial of the network (latest state id)
|
||||||
|
func (n *Network) CurrentSerial() uint64 {
|
||||||
|
n.mu.Lock()
|
||||||
|
defer n.mu.Unlock()
|
||||||
|
return n.Serial
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Network) Copy() *Network {
|
||||||
|
return &Network{
|
||||||
|
Identifier: n.Identifier,
|
||||||
|
Net: n.Net,
|
||||||
|
Dns: n.Dns,
|
||||||
|
Serial: n.Serial,
|
||||||
|
}
|
||||||
|
}
|
18
management/refactor/resources/network/types/network_map.go
Normal file
18
management/refactor/resources/network/types/network_map.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
peerTypes "github.com/netbirdio/netbird/management/refactor/resources/peers/types"
|
||||||
|
policyTypes "github.com/netbirdio/netbird/management/refactor/resources/policies/types"
|
||||||
|
routeTypes "github.com/netbirdio/netbird/management/refactor/resources/routes/types"
|
||||||
|
|
||||||
|
nbdns "github.com/netbirdio/netbird/dns"
|
||||||
|
)
|
||||||
|
|
||||||
|
type NetworkMap struct {
|
||||||
|
Peers []*peerTypes.Peer
|
||||||
|
Network *Network
|
||||||
|
Routes []*routeTypes.Route
|
||||||
|
DNSConfig nbdns.Config
|
||||||
|
OfflinePeers []*peerTypes.Peer
|
||||||
|
FirewallRules []*policyTypes.FirewallRule
|
||||||
|
}
|
317
management/refactor/resources/peers/api.go
Normal file
317
management/refactor/resources/peers/api.go
Normal file
@ -0,0 +1,317 @@
|
|||||||
|
package peers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
|
||||||
|
http2 "github.com/netbirdio/netbird/management/refactor/api/http"
|
||||||
|
peerTypes "github.com/netbirdio/netbird/management/refactor/resources/peers/types"
|
||||||
|
"github.com/netbirdio/netbird/management/refactor/store"
|
||||||
|
"github.com/netbirdio/netbird/management/server"
|
||||||
|
"github.com/netbirdio/netbird/management/server/http/api"
|
||||||
|
"github.com/netbirdio/netbird/management/server/http/util"
|
||||||
|
"github.com/netbirdio/netbird/management/server/jwtclaims"
|
||||||
|
nbpeer "github.com/netbirdio/netbird/management/server/peer"
|
||||||
|
"github.com/netbirdio/netbird/management/server/status"
|
||||||
|
)
|
||||||
|
|
||||||
|
func RegisterPeersEndpoints(manager Manager, router *mux.Router) {
|
||||||
|
peersHandler := NewDefaultPeersHandler(manager, apiHandler.AuthCfg)
|
||||||
|
router.HandleFunc("/peers", peersHandler.GetAllPeers).Methods("GET", "OPTIONS")
|
||||||
|
router.HandleFunc("/peers/{peerId}", peersHandler.HandlePeer).
|
||||||
|
Methods("GET", "PUT", "DELETE", "OPTIONS")
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultPeersHandler is a handler that returns peers of the account
|
||||||
|
type DefaultPeersHandler struct {
|
||||||
|
peersManager Manager
|
||||||
|
store store.Store
|
||||||
|
claimsExtractor *jwtclaims.ClaimsExtractor
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDefaultPeersHandler creates a new PeersHandler HTTP handler
|
||||||
|
func NewDefaultPeersHandler(manager Manager, authCfg AuthCfg) *DefaultPeersHandler {
|
||||||
|
return &DefaultPeersHandler{
|
||||||
|
peersManager: manager,
|
||||||
|
claimsExtractor: jwtclaims.NewClaimsExtractor(
|
||||||
|
jwtclaims.WithAudience(authCfg.Audience),
|
||||||
|
jwtclaims.WithUserIDClaim(authCfg.UserIDClaim),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *DefaultPeersHandler) checkPeerStatus(peer *peerTypes.Peer) (*peerTypes.Peer, error) {
|
||||||
|
peerToReturn := peer.Copy()
|
||||||
|
if peer.Status.Connected {
|
||||||
|
// Although we have online status in store we do not yet have an updated channel so have to show it as disconnected
|
||||||
|
// This may happen after server restart when not all peers are yet connected
|
||||||
|
if !h.accountManager.HasConnectedChannel(peer.ID) {
|
||||||
|
peerToReturn.Status.Connected = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return peerToReturn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *DefaultPeersHandler) getPeer(account *server.Account, peerID, userID string, w http.ResponseWriter) {
|
||||||
|
peer, err := h.peersManager.GetPeerByID(account.Id, peerID, userID)
|
||||||
|
if err != nil {
|
||||||
|
util.WriteError(err, w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
peerToReturn, err := h.checkPeerStatus(peer)
|
||||||
|
if err != nil {
|
||||||
|
util.WriteError(err, w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dnsDomain := h.accountManager.GetDNSDomain()
|
||||||
|
|
||||||
|
groupsInfo := toGroupsInfo(account.Groups, peer.ID)
|
||||||
|
|
||||||
|
netMap := account.GetPeerNetworkMap(peerID, h.accountManager.GetDNSDomain())
|
||||||
|
accessiblePeers := toAccessiblePeers(netMap, dnsDomain)
|
||||||
|
|
||||||
|
util.WriteJSONObject(w, toSinglePeerResponse(peerToReturn, groupsInfo, dnsDomain, accessiblePeers))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *DefaultPeersHandler) updatePeer(account *server.Account, user *server.User, peerID string, w http.ResponseWriter, r *http.Request) {
|
||||||
|
req := &api.PeerRequest{}
|
||||||
|
err := json.NewDecoder(r.Body).Decode(&req)
|
||||||
|
if err != nil {
|
||||||
|
util.WriteErrorResponse("couldn't parse JSON request", http.StatusBadRequest, w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
update := &nbpeer.Peer{ID: peerID, SSHEnabled: req.SshEnabled, Name: req.Name,
|
||||||
|
LoginExpirationEnabled: req.LoginExpirationEnabled}
|
||||||
|
|
||||||
|
if req.ApprovalRequired != nil {
|
||||||
|
update.Status = &nbpeer.PeerStatus{RequiresApproval: *req.ApprovalRequired}
|
||||||
|
}
|
||||||
|
|
||||||
|
peer, err := h.accountManager.UpdatePeer(account.Id, user.Id, update)
|
||||||
|
if err != nil {
|
||||||
|
util.WriteError(err, w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dnsDomain := h.accountManager.GetDNSDomain()
|
||||||
|
|
||||||
|
groupMinimumInfo := toGroupsInfo(account.Groups, peer.ID)
|
||||||
|
|
||||||
|
netMap := account.GetPeerNetworkMap(peerID, h.accountManager.GetDNSDomain())
|
||||||
|
accessiblePeers := toAccessiblePeers(netMap, dnsDomain)
|
||||||
|
|
||||||
|
util.WriteJSONObject(w, toSinglePeerResponse(peer, groupMinimumInfo, dnsDomain, accessiblePeers))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *DefaultPeersHandler) deletePeer(accountID, userID string, peerID string, w http.ResponseWriter) {
|
||||||
|
err := h.accountManager.DeletePeer(accountID, peerID, userID)
|
||||||
|
if err != nil {
|
||||||
|
util.WriteError(err, w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.WriteJSONObject(w, http2.EmptyObject{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandlePeer handles all peer requests for GET, PUT and DELETE operations
|
||||||
|
func (h *DefaultPeersHandler) HandlePeer(w http.ResponseWriter, r *http.Request) {
|
||||||
|
claims := h.claimsExtractor.FromRequestContext(r)
|
||||||
|
account, user, err := h.accountManager.GetAccountFromToken(claims)
|
||||||
|
if err != nil {
|
||||||
|
util.WriteError(err, w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
peerID := vars["peerId"]
|
||||||
|
if len(peerID) == 0 {
|
||||||
|
util.WriteError(status.Errorf(status.InvalidArgument, "invalid peer ID"), w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch r.Method {
|
||||||
|
case http.MethodDelete:
|
||||||
|
h.deletePeer(account.Id, user.Id, peerID, w)
|
||||||
|
return
|
||||||
|
case http.MethodPut:
|
||||||
|
h.updatePeer(account, user, peerID, w, r)
|
||||||
|
return
|
||||||
|
case http.MethodGet:
|
||||||
|
h.getPeer(account, peerID, user.Id, w)
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
util.WriteError(status.Errorf(status.NotFound, "unknown METHOD"), w)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllPeers returns a list of all peers associated with a provided account
|
||||||
|
func (h *DefaultPeersHandler) GetAllPeers(w http.ResponseWriter, r *http.Request) {
|
||||||
|
switch r.Method {
|
||||||
|
case http.MethodGet:
|
||||||
|
claims := h.claimsExtractor.FromRequestContext(r)
|
||||||
|
account, user, err := h.accountManager.GetAccountFromToken(claims)
|
||||||
|
if err != nil {
|
||||||
|
util.WriteError(err, w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
peers, err := h.accountManager.GetPeers(account.Id, user.Id)
|
||||||
|
if err != nil {
|
||||||
|
util.WriteError(err, w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
dnsDomain := h.accountManager.GetDNSDomain()
|
||||||
|
|
||||||
|
respBody := make([]*api.PeerBatch, 0, len(peers))
|
||||||
|
for _, peer := range peers {
|
||||||
|
peerToReturn, err := h.checkPeerStatus(peer)
|
||||||
|
if err != nil {
|
||||||
|
util.WriteError(err, w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
groupMinimumInfo := toGroupsInfo(account.Groups, peer.ID)
|
||||||
|
|
||||||
|
accessiblePeerNumbers := h.accessiblePeersNumber(account, peer.ID)
|
||||||
|
|
||||||
|
respBody = append(respBody, toPeerListItemResponse(peerToReturn, groupMinimumInfo, dnsDomain, accessiblePeerNumbers))
|
||||||
|
}
|
||||||
|
util.WriteJSONObject(w, respBody)
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
util.WriteError(status.Errorf(status.NotFound, "unknown METHOD"), w)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *DefaultPeersHandler) accessiblePeersNumber(account *server.Account, peerID string) int {
|
||||||
|
netMap := account.GetPeerNetworkMap(peerID, h.accountManager.GetDNSDomain())
|
||||||
|
return len(netMap.Peers) + len(netMap.OfflinePeers)
|
||||||
|
}
|
||||||
|
|
||||||
|
func toAccessiblePeers(netMap *server.NetworkMap, dnsDomain string) []api.AccessiblePeer {
|
||||||
|
accessiblePeers := make([]api.AccessiblePeer, 0, len(netMap.Peers)+len(netMap.OfflinePeers))
|
||||||
|
for _, p := range netMap.Peers {
|
||||||
|
ap := api.AccessiblePeer{
|
||||||
|
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 {
|
||||||
|
ap := api.AccessiblePeer{
|
||||||
|
Id: p.ID,
|
||||||
|
Name: p.Name,
|
||||||
|
Ip: p.IP.String(),
|
||||||
|
DnsLabel: fqdn(p, dnsDomain),
|
||||||
|
UserId: p.UserID,
|
||||||
|
}
|
||||||
|
accessiblePeers = append(accessiblePeers, ap)
|
||||||
|
}
|
||||||
|
return accessiblePeers
|
||||||
|
}
|
||||||
|
|
||||||
|
func toGroupsInfo(groups map[string]*server.Group, peerID string) []api.GroupMinimum {
|
||||||
|
var groupsInfo []api.GroupMinimum
|
||||||
|
groupsChecked := make(map[string]struct{})
|
||||||
|
for _, group := range groups {
|
||||||
|
_, ok := groupsChecked[group.ID]
|
||||||
|
if ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
groupsChecked[group.ID] = struct{}{}
|
||||||
|
for _, pk := range group.Peers {
|
||||||
|
if pk == peerID {
|
||||||
|
info := api.GroupMinimum{
|
||||||
|
Id: group.ID,
|
||||||
|
Name: group.Name,
|
||||||
|
PeersCount: len(group.Peers),
|
||||||
|
}
|
||||||
|
groupsInfo = append(groupsInfo, info)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return groupsInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
func toSinglePeerResponse(peer *nbpeer.Peer, groupsInfo []api.GroupMinimum, dnsDomain string, accessiblePeer []api.AccessiblePeer) *api.Peer {
|
||||||
|
osVersion := peer.Meta.OSVersion
|
||||||
|
if osVersion == "" {
|
||||||
|
osVersion = peer.Meta.Core
|
||||||
|
}
|
||||||
|
|
||||||
|
return &api.Peer{
|
||||||
|
Id: peer.ID,
|
||||||
|
Name: peer.Name,
|
||||||
|
Ip: peer.IP.String(),
|
||||||
|
ConnectionIp: peer.Location.ConnectionIP.String(),
|
||||||
|
Connected: peer.Status.Connected,
|
||||||
|
LastSeen: peer.Status.LastSeen,
|
||||||
|
Os: fmt.Sprintf("%s %s", peer.Meta.OS, osVersion),
|
||||||
|
KernelVersion: peer.Meta.KernelVersion,
|
||||||
|
GeonameId: int(peer.Location.GeoNameID),
|
||||||
|
Version: peer.Meta.WtVersion,
|
||||||
|
Groups: groupsInfo,
|
||||||
|
SshEnabled: peer.SSHEnabled,
|
||||||
|
Hostname: peer.Meta.Hostname,
|
||||||
|
UserId: peer.UserID,
|
||||||
|
UiVersion: peer.Meta.UIVersion,
|
||||||
|
DnsLabel: fqdn(peer, dnsDomain),
|
||||||
|
LoginExpirationEnabled: peer.LoginExpirationEnabled,
|
||||||
|
LastLogin: peer.LastLogin,
|
||||||
|
LoginExpired: peer.Status.LoginExpired,
|
||||||
|
AccessiblePeers: accessiblePeer,
|
||||||
|
ApprovalRequired: &peer.Status.RequiresApproval,
|
||||||
|
CountryCode: peer.Location.CountryCode,
|
||||||
|
CityName: peer.Location.CityName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func toPeerListItemResponse(peer *nbpeer.Peer, groupsInfo []api.GroupMinimum, dnsDomain string, accessiblePeersCount int) *api.PeerBatch {
|
||||||
|
osVersion := peer.Meta.OSVersion
|
||||||
|
if osVersion == "" {
|
||||||
|
osVersion = peer.Meta.Core
|
||||||
|
}
|
||||||
|
|
||||||
|
return &api.PeerBatch{
|
||||||
|
Id: peer.ID,
|
||||||
|
Name: peer.Name,
|
||||||
|
Ip: peer.IP.String(),
|
||||||
|
ConnectionIp: peer.Location.ConnectionIP.String(),
|
||||||
|
Connected: peer.Status.Connected,
|
||||||
|
LastSeen: peer.Status.LastSeen,
|
||||||
|
Os: fmt.Sprintf("%s %s", peer.Meta.OS, osVersion),
|
||||||
|
KernelVersion: peer.Meta.KernelVersion,
|
||||||
|
GeonameId: int(peer.Location.GeoNameID),
|
||||||
|
Version: peer.Meta.WtVersion,
|
||||||
|
Groups: groupsInfo,
|
||||||
|
SshEnabled: peer.SSHEnabled,
|
||||||
|
Hostname: peer.Meta.Hostname,
|
||||||
|
UserId: peer.UserID,
|
||||||
|
UiVersion: peer.Meta.UIVersion,
|
||||||
|
DnsLabel: fqdn(peer, dnsDomain),
|
||||||
|
LoginExpirationEnabled: peer.LoginExpirationEnabled,
|
||||||
|
LastLogin: peer.LastLogin,
|
||||||
|
LoginExpired: peer.Status.LoginExpired,
|
||||||
|
AccessiblePeersCount: accessiblePeersCount,
|
||||||
|
ApprovalRequired: &peer.Status.RequiresApproval,
|
||||||
|
CountryCode: peer.Location.CountryCode,
|
||||||
|
CityName: peer.Location.CityName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func fqdn(peer *nbpeer.Peer, dnsDomain string) string {
|
||||||
|
fqdn := peer.FQDN(dnsDomain)
|
||||||
|
if fqdn == "" {
|
||||||
|
return peer.DNSLabel
|
||||||
|
} else {
|
||||||
|
return fqdn
|
||||||
|
}
|
||||||
|
}
|
51
management/refactor/resources/peers/manager.go
Normal file
51
management/refactor/resources/peers/manager.go
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
package peers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/netbirdio/netbird/management/refactor/resources/peers/types"
|
||||||
|
"github.com/netbirdio/netbird/management/refactor/resources/settings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Manager interface {
|
||||||
|
GetPeerByPubKey(pubKey string) (types.Peer, error)
|
||||||
|
GetPeerByID(id string) (types.Peer, error)
|
||||||
|
GetNetworkPeerByID(id string) (types.Peer, error)
|
||||||
|
GetNetworkPeersInAccount(id string) ([]types.Peer, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type DefaultManager struct {
|
||||||
|
repository Repository
|
||||||
|
settingsManager settings.Manager
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDefaultManager(repository Repository, settingsManager settings.Manager) *DefaultManager {
|
||||||
|
return &DefaultManager{
|
||||||
|
repository: repository,
|
||||||
|
settingsManager: settingsManager,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dm *DefaultManager) GetNetworkPeerByID(id string) (types.Peer, error) {
|
||||||
|
return dm.repository.FindPeerByID(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dm *DefaultManager) GetNetworkPeersInAccount(accountId string) ([]types.Peer, error) {
|
||||||
|
defaultPeers, err := dm.repository.FindAllPeersInAccount(accountId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
peers := make([]types.Peer, len(defaultPeers))
|
||||||
|
for _, dp := range defaultPeers {
|
||||||
|
peers = append(peers, dp)
|
||||||
|
}
|
||||||
|
|
||||||
|
return peers, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dm *DefaultManager) GetPeerByPubKey(pubKey string) (types.Peer, error) {
|
||||||
|
return dm.repository.FindPeerByPubKey(pubKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dm *DefaultManager) GetPeerByID(id string) (types.Peer, error) {
|
||||||
|
return dm.repository.FindPeerByID(id)
|
||||||
|
}
|
10
management/refactor/resources/peers/repository.go
Normal file
10
management/refactor/resources/peers/repository.go
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package peers
|
||||||
|
|
||||||
|
import "github.com/netbirdio/netbird/management/refactor/resources/peers/types"
|
||||||
|
|
||||||
|
type Repository interface {
|
||||||
|
FindPeerByPubKey(pubKey string) (types.Peer, error)
|
||||||
|
FindPeerByID(id string) (types.Peer, error)
|
||||||
|
FindAllPeersInAccount(id string) ([]types.Peer, error)
|
||||||
|
UpdatePeer(peer types.Peer) error
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package peers
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -33,6 +33,7 @@ type Peer interface {
|
|||||||
FQDN(dnsDomain string) string
|
FQDN(dnsDomain string) string
|
||||||
EventMeta(dnsDomain string) map[string]any
|
EventMeta(dnsDomain string) map[string]any
|
||||||
LoginExpired(expiresIn time.Duration) (bool, time.Duration)
|
LoginExpired(expiresIn time.Duration) (bool, time.Duration)
|
||||||
|
Copy() Peer
|
||||||
}
|
}
|
||||||
|
|
||||||
// Peer represents a machine connected to the network.
|
// Peer represents a machine connected to the network.
|
||||||
@ -48,11 +49,15 @@ type DefaultPeer struct {
|
|||||||
SetupKey string
|
SetupKey string
|
||||||
// IP address of the Peer
|
// IP address of the Peer
|
||||||
IP net.IP `gorm:"uniqueIndex:idx_peers_account_id_ip"`
|
IP net.IP `gorm:"uniqueIndex:idx_peers_account_id_ip"`
|
||||||
|
// Meta is a Peer system meta data
|
||||||
|
Meta PeerSystemMeta `gorm:"embedded;embeddedPrefix:meta_"`
|
||||||
// Name is peer's name (machine name)
|
// Name is peer's name (machine name)
|
||||||
Name string
|
Name string
|
||||||
// DNSLabel is the parsed peer name for domain resolution. It is used to form an FQDN by appending the account's
|
// DNSLabel 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
|
// domain to the peer label. e.g. peer-dns-label.netbird.cloud
|
||||||
DNSLabel string
|
DNSLabel string
|
||||||
|
// Status peer's management connection status
|
||||||
|
Status *PeerStatus `gorm:"embedded;embeddedPrefix:peer_status_"`
|
||||||
// The user ID that registered the peer
|
// The user ID that registered the peer
|
||||||
UserID string
|
UserID string
|
||||||
// SSHKey is a public SSH key of the peer
|
// SSHKey is a public SSH key of the peer
|
||||||
@ -64,8 +69,20 @@ type DefaultPeer struct {
|
|||||||
LoginExpirationEnabled bool
|
LoginExpirationEnabled bool
|
||||||
// LastLogin the time when peer performed last login operation
|
// LastLogin the time when peer performed last login operation
|
||||||
LastLogin time.Time
|
LastLogin time.Time
|
||||||
|
// CreatedAt records the time the peer was created
|
||||||
|
CreatedAt time.Time
|
||||||
// Indicate ephemeral peer attribute
|
// Indicate ephemeral peer attribute
|
||||||
Ephemeral bool
|
Ephemeral bool
|
||||||
|
// Geo location based on connection IP
|
||||||
|
Location Location `gorm:"embedded;embeddedPrefix:location_"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Location is a geo location information of a Peer based on public connection IP
|
||||||
|
type Location struct {
|
||||||
|
ConnectionIP net.IP // from grpc peer or reverse proxy headers depends on setup
|
||||||
|
CountryCode string
|
||||||
|
CityName string
|
||||||
|
GeoNameID uint // city level geoname id
|
||||||
}
|
}
|
||||||
|
|
||||||
// PeerLogin used as a data object between the gRPC API and AccountManager on Login request.
|
// PeerLogin used as a data object between the gRPC API and AccountManager on Login request.
|
24
management/refactor/resources/peers/types/peer_status.go
Normal file
24
management/refactor/resources/peers/types/peer_status.go
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
// Copy PeerStatus
|
||||||
|
func (p *PeerStatus) Copy() *PeerStatus {
|
||||||
|
return &PeerStatus{
|
||||||
|
LastSeen: p.LastSeen,
|
||||||
|
Connected: p.Connected,
|
||||||
|
LoginExpired: p.LoginExpired,
|
||||||
|
RequiresApproval: p.RequiresApproval,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type PeerStatus struct { //nolint:revive
|
||||||
|
// LastSeen is the last time peer was connected to the management service
|
||||||
|
LastSeen time.Time
|
||||||
|
// Connected indicates whether peer is connected to the management service or not
|
||||||
|
Connected bool
|
||||||
|
// LoginExpired
|
||||||
|
LoginExpired bool
|
||||||
|
// RequiresApproval indicates whether peer requires approval or not
|
||||||
|
RequiresApproval bool
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import "net/netip"
|
||||||
|
|
||||||
|
// NetworkAddress is the IP address with network and MAC address of a network interface
|
||||||
|
type NetworkAddress struct {
|
||||||
|
NetIP netip.Prefix `gorm:"serializer:json"`
|
||||||
|
Mac string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Environment is a system environment information
|
||||||
|
type Environment struct {
|
||||||
|
Cloud string
|
||||||
|
Platform string
|
||||||
|
}
|
||||||
|
|
||||||
|
// PeerSystemMeta is a metadata of a Peer machine system
|
||||||
|
type PeerSystemMeta struct { //nolint:revive
|
||||||
|
Hostname string
|
||||||
|
GoOS string
|
||||||
|
Kernel string
|
||||||
|
Core string
|
||||||
|
Platform string
|
||||||
|
OS string
|
||||||
|
OSVersion string
|
||||||
|
WtVersion string
|
||||||
|
UIVersion string
|
||||||
|
KernelVersion string
|
||||||
|
NetworkAddresses []NetworkAddress `gorm:"serializer:json"`
|
||||||
|
SystemSerialNumber string
|
||||||
|
SystemProductName string
|
||||||
|
SystemManufacturer string
|
||||||
|
Environment Environment `gorm:"serializer:json"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p PeerSystemMeta) isEqual(other PeerSystemMeta) bool {
|
||||||
|
if len(p.NetworkAddresses) != len(other.NetworkAddresses) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, addr := range p.NetworkAddresses {
|
||||||
|
var found bool
|
||||||
|
for _, oAddr := range other.NetworkAddresses {
|
||||||
|
if addr.Mac == oAddr.Mac && addr.NetIP == oAddr.NetIP {
|
||||||
|
found = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return p.Hostname == other.Hostname &&
|
||||||
|
p.GoOS == other.GoOS &&
|
||||||
|
p.Kernel == other.Kernel &&
|
||||||
|
p.KernelVersion == other.KernelVersion &&
|
||||||
|
p.Core == other.Core &&
|
||||||
|
p.Platform == other.Platform &&
|
||||||
|
p.OS == other.OS &&
|
||||||
|
p.OSVersion == other.OSVersion &&
|
||||||
|
p.WtVersion == other.WtVersion &&
|
||||||
|
p.UIVersion == other.UIVersion &&
|
||||||
|
p.SystemSerialNumber == other.SystemSerialNumber &&
|
||||||
|
p.SystemProductName == other.SystemProductName &&
|
||||||
|
p.SystemManufacturer == other.SystemManufacturer &&
|
||||||
|
p.Environment.Cloud == other.Environment.Cloud &&
|
||||||
|
p.Environment.Platform == other.Environment.Platform
|
||||||
|
}
|
1
management/refactor/resources/policies/api.go
Normal file
1
management/refactor/resources/policies/api.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package policies
|
@ -1,24 +1,27 @@
|
|||||||
package policies
|
package policies
|
||||||
|
|
||||||
import "github.com/netbirdio/netbird/management/refactor/peers"
|
import (
|
||||||
|
"github.com/netbirdio/netbird/management/refactor/resources/peers"
|
||||||
|
"github.com/netbirdio/netbird/management/refactor/resources/peers/types"
|
||||||
|
)
|
||||||
|
|
||||||
type Manager interface {
|
type Manager interface {
|
||||||
GetAccessiblePeersAndFirewallRules(peerID string) (peers []peers.Peer, firewallRules []*FirewallRule)
|
GetAccessiblePeersAndFirewallRules(peerID string) (peers []types.Peer, firewallRules []*FirewallRule)
|
||||||
}
|
}
|
||||||
|
|
||||||
type DefaultManager struct {
|
type DefaultManager struct {
|
||||||
repository repository
|
repository Repository
|
||||||
peerManager peers.Manager
|
peerManager peers.Manager
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDefaultManager(repository repository, peerManager peers.Manager) *DefaultManager {
|
func NewDefaultManager(repository Repository, peerManager peers.Manager) *DefaultManager {
|
||||||
return &DefaultManager{
|
return &DefaultManager{
|
||||||
repository: repository,
|
repository: repository,
|
||||||
peerManager: peerManager,
|
peerManager: peerManager,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dm *DefaultManager) GetAccessiblePeersAndFirewallRules(peerID string) (peers []peers.Peer, firewallRules []*FirewallRule) {
|
func (dm *DefaultManager) GetAccessiblePeersAndFirewallRules(peerID string) (peers []types.Peer, firewallRules []*FirewallRule) {
|
||||||
peer, err := dm.peerManager.GetPeerByID(peerID)
|
peer, err := dm.peerManager.GetPeerByID(peerID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil
|
return nil, nil
|
1
management/refactor/resources/policies/posture/api.go
Normal file
1
management/refactor/resources/policies/posture/api.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package posture
|
@ -0,0 +1 @@
|
|||||||
|
package posture
|
@ -0,0 +1 @@
|
|||||||
|
package posture
|
@ -0,0 +1,19 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
// FirewallRule is a rule of the firewall.
|
||||||
|
type FirewallRule struct {
|
||||||
|
// PeerIP of the peer
|
||||||
|
PeerIP string
|
||||||
|
|
||||||
|
// Direction of the traffic
|
||||||
|
Direction int
|
||||||
|
|
||||||
|
// Action of the traffic
|
||||||
|
Action string
|
||||||
|
|
||||||
|
// Protocol of the traffic
|
||||||
|
Protocol string
|
||||||
|
|
||||||
|
// Port of the traffic
|
||||||
|
Port string
|
||||||
|
}
|
13
management/refactor/resources/policies/types/policy.go
Normal file
13
management/refactor/resources/policies/types/policy.go
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
type Policy interface {
|
||||||
|
GetID() string
|
||||||
|
}
|
||||||
|
|
||||||
|
type DefaultPolicy struct {
|
||||||
|
ID string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dp *DefaultPolicy) GetID() string {
|
||||||
|
return dp.ID
|
||||||
|
}
|
13
management/refactor/resources/policies/types/policy_rule.go
Normal file
13
management/refactor/resources/policies/types/policy_rule.go
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
type PolicyRule interface {
|
||||||
|
GetID() string
|
||||||
|
}
|
||||||
|
|
||||||
|
type DefaultPolicyRule struct {
|
||||||
|
ID string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dpr *DefaultPolicyRule) GetID() string {
|
||||||
|
return dpr.ID
|
||||||
|
}
|
1
management/refactor/resources/routes/api.go
Normal file
1
management/refactor/resources/routes/api.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package routes
|
100
management/refactor/resources/routes/manager.go
Normal file
100
management/refactor/resources/routes/manager.go
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
package routes
|
||||||
|
|
||||||
|
import (
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/netbirdio/netbird/management/refactor/resources/peers"
|
||||||
|
"github.com/netbirdio/netbird/management/refactor/resources/peers/types"
|
||||||
|
routeTypes "github.com/netbirdio/netbird/management/refactor/resources/routes/types"
|
||||||
|
"github.com/netbirdio/netbird/route"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Manager interface {
|
||||||
|
GetRoutesToSync(peerID string, peersToConnect []*types.Peer, accountID string) []*routeTypes.Route
|
||||||
|
}
|
||||||
|
|
||||||
|
type DefaultManager struct {
|
||||||
|
repository Repository
|
||||||
|
peersManager peers.Manager
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDefaultManager(repository Repository, peersManager peers.Manager) *DefaultManager {
|
||||||
|
return &DefaultManager{
|
||||||
|
repository: repository,
|
||||||
|
peersManager: peersManager,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d DefaultManager) GetRoutesToSync(peerID string, peersToConnect []*types.Peer) []*routeTypes.Route {
|
||||||
|
routes, peerDisabledRoutes := d.getRoutingPeerRoutes(peerID)
|
||||||
|
peerRoutesMembership := make(lookupMap)
|
||||||
|
for _, r := range append(routes, peerDisabledRoutes...) {
|
||||||
|
peerRoutesMembership[route.GetHAUniqueID(r)] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
groupListMap := a.getPeerGroups(peerID)
|
||||||
|
for _, peer := range aclPeers {
|
||||||
|
activeRoutes, _ := a.getRoutingPeerRoutes(peer.ID)
|
||||||
|
groupFilteredRoutes := a.filterRoutesByGroups(activeRoutes, groupListMap)
|
||||||
|
filteredRoutes := a.filterRoutesFromPeersOfSameHAGroup(groupFilteredRoutes, peerRoutesMembership)
|
||||||
|
routes = append(routes, filteredRoutes...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return routes
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d DefaultManager) getRoutingPeerRoutes(accountID, peerID string) (enabledRoutes []routeTypes.Route, disabledRoutes []routeTypes.Route) {
|
||||||
|
peer, err := d.peersManager.GetPeerByID(peerID)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("peer %s that doesn't exist under account %s", peerID, accountID)
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// currently we support only linux routing peers
|
||||||
|
if peer.Meta.GoOS != "linux" {
|
||||||
|
return enabledRoutes, disabledRoutes
|
||||||
|
}
|
||||||
|
|
||||||
|
seenRoute := make(map[string]struct{})
|
||||||
|
|
||||||
|
takeRoute := func(r routeTypes.Route, id string) {
|
||||||
|
if _, ok := seenRoute[r.GetID()]; ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
seenRoute[r.GetID()] = struct{}{}
|
||||||
|
|
||||||
|
if r.IsEnabled() {
|
||||||
|
r.SetPeer(peer.GetKey())
|
||||||
|
enabledRoutes = append(enabledRoutes, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
disabledRoutes = append(disabledRoutes, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, r := range a.Routes {
|
||||||
|
for _, groupID := range r.PeerGroups {
|
||||||
|
group := a.GetGroup(groupID)
|
||||||
|
if group == nil {
|
||||||
|
log.Errorf("route %s has peers group %s that doesn't exist under account %s", r.ID, groupID, a.Id)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, id := range group.Peers {
|
||||||
|
if id != peerID {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
newPeerRoute := r.Copy()
|
||||||
|
newPeerRoute.Peer = id
|
||||||
|
newPeerRoute.PeerGroups = nil
|
||||||
|
newPeerRoute.ID = r.ID + ":" + id // we have to provide unique route id when distribute network map
|
||||||
|
takeRoute(newPeerRoute, id)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if r.Peer == peerID {
|
||||||
|
takeRoute(r.Copy(), peerID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return enabledRoutes, disabledRoutes
|
||||||
|
}
|
4
management/refactor/resources/routes/repository.go
Normal file
4
management/refactor/resources/routes/repository.go
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
package routes
|
||||||
|
|
||||||
|
type Repository interface {
|
||||||
|
}
|
54
management/refactor/resources/routes/types/route.go
Normal file
54
management/refactor/resources/routes/types/route.go
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import "net/netip"
|
||||||
|
|
||||||
|
const (
|
||||||
|
// InvalidNetwork invalid network type
|
||||||
|
InvalidNetwork NetworkType = iota
|
||||||
|
// IPv4Network IPv4 network type
|
||||||
|
IPv4Network
|
||||||
|
// IPv6Network IPv6 network type
|
||||||
|
IPv6Network
|
||||||
|
)
|
||||||
|
|
||||||
|
// NetworkType route network type
|
||||||
|
type NetworkType int
|
||||||
|
|
||||||
|
type Route interface {
|
||||||
|
GetID() string
|
||||||
|
IsEnabled() bool
|
||||||
|
GetPeer() string
|
||||||
|
SetPeer(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
type DefaultRoute struct {
|
||||||
|
ID string `gorm:"primaryKey"`
|
||||||
|
// AccountID is a reference to Account that this object belongs
|
||||||
|
AccountID string `gorm:"index"`
|
||||||
|
Network netip.Prefix `gorm:"serializer:gob"`
|
||||||
|
NetID string
|
||||||
|
Description string
|
||||||
|
Peer string
|
||||||
|
PeerGroups []string `gorm:"serializer:gob"`
|
||||||
|
NetworkType NetworkType
|
||||||
|
Masquerade bool
|
||||||
|
Metric int
|
||||||
|
Enabled bool
|
||||||
|
Groups []string `gorm:"serializer:json"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *DefaultRoute) GetID() string {
|
||||||
|
return r.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *DefaultRoute) IsEnabled() bool {
|
||||||
|
return r.Enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *DefaultRoute) GetPeer() string {
|
||||||
|
return r.Peer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *DefaultRoute) SetPeer(peer string) {
|
||||||
|
r.Peer = peer
|
||||||
|
}
|
1
management/refactor/resources/settings/api.go
Normal file
1
management/refactor/resources/settings/api.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package settings
|
21
management/refactor/resources/settings/manager.go
Normal file
21
management/refactor/resources/settings/manager.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package settings
|
||||||
|
|
||||||
|
import "github.com/netbirdio/netbird/management/refactor/resources/settings/types"
|
||||||
|
|
||||||
|
type Manager interface {
|
||||||
|
GetSettings(accountID string) (types.Settings, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type DefaultManager struct {
|
||||||
|
repository Repository
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDefaultManager(repository Repository) *DefaultManager {
|
||||||
|
return &DefaultManager{
|
||||||
|
repository: repository,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dm *DefaultManager) GetSettings(accountID string) (types.Settings, error) {
|
||||||
|
return dm.repository.FindSettings(accountID)
|
||||||
|
}
|
7
management/refactor/resources/settings/repository.go
Normal file
7
management/refactor/resources/settings/repository.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package settings
|
||||||
|
|
||||||
|
import "github.com/netbirdio/netbird/management/refactor/resources/settings/types"
|
||||||
|
|
||||||
|
type Repository interface {
|
||||||
|
FindSettings(accountID string) (types.Settings, error)
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package settings
|
package types
|
||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
1
management/refactor/resources/setup_keys/api.go
Normal file
1
management/refactor/resources/setup_keys/api.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package setup_keys
|
1
management/refactor/resources/setup_keys/manager.go
Normal file
1
management/refactor/resources/setup_keys/manager.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package setup_keys
|
1
management/refactor/resources/setup_keys/repository.go
Normal file
1
management/refactor/resources/setup_keys/repository.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package setup_keys
|
@ -0,0 +1,7 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
type SetupKey interface {
|
||||||
|
}
|
||||||
|
|
||||||
|
type DefaultSetupKey struct {
|
||||||
|
}
|
1
management/refactor/resources/users/api.go
Normal file
1
management/refactor/resources/users/api.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package users
|
27
management/refactor/resources/users/manager.go
Normal file
27
management/refactor/resources/users/manager.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package users
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/netbirdio/netbird/management/refactor/resources/peers"
|
||||||
|
"github.com/netbirdio/netbird/management/refactor/resources/users/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Manager interface {
|
||||||
|
GetUser(id string) (types.User, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type DefaultManager struct {
|
||||||
|
repository Repository
|
||||||
|
peerManager peers.Manager
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDefaultManager(repository Repository, peerManager peers.Manager) *DefaultManager {
|
||||||
|
return &DefaultManager{
|
||||||
|
repository: repository,
|
||||||
|
peerManager: peerManager,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d DefaultManager) GetUser(id string) (types.User, error) {
|
||||||
|
// TODO implement me
|
||||||
|
panic("implement me")
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
package personal_access_tokens
|
@ -0,0 +1 @@
|
|||||||
|
package personal_access_tokens
|
@ -0,0 +1 @@
|
|||||||
|
package personal_access_tokens
|
@ -0,0 +1 @@
|
|||||||
|
package types
|
@ -1,4 +1,4 @@
|
|||||||
package users
|
package types
|
||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
@ -1,19 +0,0 @@
|
|||||||
package settings
|
|
||||||
|
|
||||||
type Manager interface {
|
|
||||||
GetSettings(accountID string) (Settings, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type DefaultManager struct {
|
|
||||||
repository repository
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDefaultManager(repository repository) *DefaultManager {
|
|
||||||
return &DefaultManager{
|
|
||||||
repository: repository,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (dm *DefaultManager) GetSettings(accountID string) (Settings, error) {
|
|
||||||
return dm.repository.FindSettings(accountID)
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
package settings
|
|
||||||
|
|
||||||
type Repository interface {
|
|
||||||
FindSettings(accountID string) (Settings, error)
|
|
||||||
}
|
|
50
management/refactor/store/account.go
Normal file
50
management/refactor/store/account.go
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package store
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
dnsTypes "github.com/netbirdio/netbird/management/refactor/resources/dns/types"
|
||||||
|
groupTypes "github.com/netbirdio/netbird/management/refactor/resources/groups/types"
|
||||||
|
networkTypes "github.com/netbirdio/netbird/management/refactor/resources/network/types"
|
||||||
|
peerTypes "github.com/netbirdio/netbird/management/refactor/resources/peers/types"
|
||||||
|
policyTypes "github.com/netbirdio/netbird/management/refactor/resources/policies/types"
|
||||||
|
routeTypes "github.com/netbirdio/netbird/management/refactor/resources/routes/types"
|
||||||
|
settingsTypes "github.com/netbirdio/netbird/management/refactor/resources/settings/types"
|
||||||
|
setupKeyTypes "github.com/netbirdio/netbird/management/refactor/resources/setup_keys/types"
|
||||||
|
userTypes "github.com/netbirdio/netbird/management/refactor/resources/users/types"
|
||||||
|
"github.com/netbirdio/netbird/management/server/posture"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Account represents a unique account of the system
|
||||||
|
type DefaultAccount struct {
|
||||||
|
// we have to name column to aid as it collides with Network.Id when work with associations
|
||||||
|
Id string `gorm:"primaryKey"`
|
||||||
|
|
||||||
|
// User.Id it was created by
|
||||||
|
CreatedBy string
|
||||||
|
CreatedAt time.Time
|
||||||
|
Domain string `gorm:"index"`
|
||||||
|
DomainCategory string
|
||||||
|
IsDomainPrimaryAccount bool
|
||||||
|
SetupKeys map[string]*setupKeyTypes.DefaultSetupKey `gorm:"-"`
|
||||||
|
SetupKeysG []setupKeyTypes.DefaultSetupKey `json:"-" gorm:"foreignKey:AccountID;references:id"`
|
||||||
|
Network *networkTypes.Network `gorm:"embedded;embeddedPrefix:network_"`
|
||||||
|
Peers map[string]*peerTypes.DefaultPeer `gorm:"-"`
|
||||||
|
PeersG []peerTypes.DefaultPeer `json:"-" gorm:"foreignKey:AccountID;references:id"`
|
||||||
|
Users map[string]*userTypes.DefaultUser `gorm:"-"`
|
||||||
|
UsersG []userTypes.DefaultUser `json:"-" gorm:"foreignKey:AccountID;references:id"`
|
||||||
|
Groups map[string]*groupTypes.DefaultGroup `gorm:"-"`
|
||||||
|
GroupsG []groupTypes.DefaultGroup `json:"-" gorm:"foreignKey:AccountID;references:id"`
|
||||||
|
Policies []*policyTypes.DefaultPolicy `gorm:"foreignKey:AccountID;references:id"`
|
||||||
|
Routes map[string]*routeTypes.DefaultRoute `gorm:"-"`
|
||||||
|
RoutesG []routeTypes.DefaultRoute `json:"-" gorm:"foreignKey:AccountID;references:id"`
|
||||||
|
NameServerGroups map[string]*dnsTypes.DefaultNameServerGroup `gorm:"-"`
|
||||||
|
NameServerGroupsG []dnsTypes.DefaultNameServerGroup `json:"-" gorm:"foreignKey:AccountID;references:id"`
|
||||||
|
DNSSettings dnsTypes.DefaultSettings `gorm:"embedded;embeddedPrefix:dns_settings_"`
|
||||||
|
PostureChecks []*posture.Checks `gorm:"foreignKey:AccountID;references:id"`
|
||||||
|
// Settings is a dictionary of Account settings
|
||||||
|
Settings *settingsTypes.DefaultSettings `gorm:"embedded;embeddedPrefix:settings_"`
|
||||||
|
// deprecated on store and api level
|
||||||
|
Rules map[string]*Rule `json:"-" gorm:"-"`
|
||||||
|
RulesG []Rule `json:"-" gorm:"-"`
|
||||||
|
}
|
@ -1,8 +1,8 @@
|
|||||||
package store
|
package store
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/netbirdio/netbird/management/refactor/peers"
|
peerTypes "github.com/netbirdio/netbird/management/refactor/resources/peers/types"
|
||||||
"github.com/netbirdio/netbird/management/refactor/settings"
|
settingsTypes "github.com/netbirdio/netbird/management/refactor/resources/settings/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -12,27 +12,27 @@ const (
|
|||||||
type DefaultPostgresStore struct {
|
type DefaultPostgresStore struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DefaultPostgresStore) FindSettings(accountID string) (settings.Settings, error) {
|
func (s *DefaultPostgresStore) FindSettings(accountID string) (settingsTypes.Settings, error) {
|
||||||
// TODO implement me
|
// TODO implement me
|
||||||
panic("implement me")
|
panic("implement me")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DefaultPostgresStore) FindPeerByPubKey(pubKey string) (peers.Peer, error) {
|
func (s *DefaultPostgresStore) FindPeerByPubKey(pubKey string) (peerTypes.Peer, error) {
|
||||||
// TODO implement me
|
// TODO implement me
|
||||||
panic("implement me")
|
panic("implement me")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DefaultPostgresStore) FindPeerByID(id string) (peers.Peer, error) {
|
func (s *DefaultPostgresStore) FindPeerByID(id string) (peerTypes.Peer, error) {
|
||||||
// TODO implement me
|
// TODO implement me
|
||||||
panic("implement me")
|
panic("implement me")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DefaultPostgresStore) FindAllPeersInAccount(id string) ([]peers.Peer, error) {
|
func (s *DefaultPostgresStore) FindAllPeersInAccount(id string) ([]peerTypes.Peer, error) {
|
||||||
// TODO implement me
|
// TODO implement me
|
||||||
panic("implement me")
|
panic("implement me")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DefaultPostgresStore) UpdatePeer(peer peers.Peer) error {
|
func (s *DefaultPostgresStore) UpdatePeer(peer peerTypes.Peer) error {
|
||||||
// TODO implement me
|
// TODO implement me
|
||||||
panic("implement me")
|
panic("implement me")
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package store
|
package store
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
@ -12,8 +13,17 @@ import (
|
|||||||
"gorm.io/gorm/clause"
|
"gorm.io/gorm/clause"
|
||||||
"gorm.io/gorm/logger"
|
"gorm.io/gorm/logger"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/management/refactor/peers"
|
dnsTypes "github.com/netbirdio/netbird/management/refactor/resources/dns/types"
|
||||||
"github.com/netbirdio/netbird/management/refactor/settings"
|
groupTypes "github.com/netbirdio/netbird/management/refactor/resources/groups/types"
|
||||||
|
"github.com/netbirdio/netbird/management/refactor/resources/peers"
|
||||||
|
policyTypes "github.com/netbirdio/netbird/management/refactor/resources/policies/types"
|
||||||
|
routeTypes "github.com/netbirdio/netbird/management/refactor/resources/routes/types"
|
||||||
|
"github.com/netbirdio/netbird/management/refactor/resources/settings"
|
||||||
|
setupKeyTypes "github.com/netbirdio/netbird/management/refactor/resources/setup_keys/types"
|
||||||
|
userTypes "github.com/netbirdio/netbird/management/refactor/resources/users/types"
|
||||||
|
|
||||||
|
nbpeer "github.com/netbirdio/netbird/management/server/peer"
|
||||||
|
"github.com/netbirdio/netbird/management/server/status"
|
||||||
"github.com/netbirdio/netbird/management/server/telemetry"
|
"github.com/netbirdio/netbird/management/server/telemetry"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -23,37 +33,13 @@ const (
|
|||||||
|
|
||||||
// SqliteStore represents an account storage backed by a Sqlite DB persisted to disk
|
// SqliteStore represents an account storage backed by a Sqlite DB persisted to disk
|
||||||
type DefaultSqliteStore struct {
|
type DefaultSqliteStore struct {
|
||||||
db *gorm.DB
|
DB *gorm.DB
|
||||||
storeFile string
|
storeFile string
|
||||||
accountLocks sync.Map
|
accountLocks sync.Map
|
||||||
globalAccountLock sync.Mutex
|
globalAccountLock sync.Mutex
|
||||||
metrics telemetry.AppMetrics
|
metrics telemetry.AppMetrics
|
||||||
installationPK int
|
installationPK int
|
||||||
}
|
accounts map[string]*DefaultAccount
|
||||||
|
|
||||||
func (s *DefaultSqliteStore) FindSettings(accountID string) (settings.Settings, error) {
|
|
||||||
// TODO implement me
|
|
||||||
panic("implement me")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *DefaultSqliteStore) FindPeerByPubKey(pubKey string) (peers.Peer, error) {
|
|
||||||
// TODO implement me
|
|
||||||
panic("implement me")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *DefaultSqliteStore) FindPeerByID(id string) (peers.Peer, error) {
|
|
||||||
// TODO implement me
|
|
||||||
panic("implement me")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *DefaultSqliteStore) FindAllPeersInAccount(id string) ([]peers.Peer, error) {
|
|
||||||
// TODO implement me
|
|
||||||
panic("implement me")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *DefaultSqliteStore) UpdatePeer(peer peers.Peer) error {
|
|
||||||
// TODO implement me
|
|
||||||
panic("implement me")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type installation struct {
|
type installation struct {
|
||||||
@ -63,10 +49,10 @@ type installation struct {
|
|||||||
|
|
||||||
// NewSqliteStore restores a store from the file located in the datadir
|
// NewSqliteStore restores a store from the file located in the datadir
|
||||||
func NewDefaultSqliteStore(dataDir string, metrics telemetry.AppMetrics) (*DefaultSqliteStore, error) {
|
func NewDefaultSqliteStore(dataDir string, metrics telemetry.AppMetrics) (*DefaultSqliteStore, error) {
|
||||||
storeStr := "store.db?cache=shared"
|
storeStr := "store.DB?cache=shared"
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
// Vo avoid `The process cannot access the file because it is being used by another process` on Windows
|
// Vo avoid `The process cannot access the file because it is being used by another process` on Windows
|
||||||
storeStr = "store.db"
|
storeStr = "store.DB"
|
||||||
}
|
}
|
||||||
|
|
||||||
file := filepath.Join(dataDir, storeStr)
|
file := filepath.Join(dataDir, storeStr)
|
||||||
@ -85,7 +71,7 @@ func NewDefaultSqliteStore(dataDir string, metrics telemetry.AppMetrics) (*Defau
|
|||||||
conns := runtime.NumCPU()
|
conns := runtime.NumCPU()
|
||||||
sql.SetMaxOpenConns(conns) // TODO: make it configurable
|
sql.SetMaxOpenConns(conns) // TODO: make it configurable
|
||||||
|
|
||||||
// err = db.AutoMigrate(
|
// err = DB.AutoMigrate(
|
||||||
// &SetupKey{}, &Peer{}, &User{}, &PersonalAccessToken{}, &Group{}, &Rule{},
|
// &SetupKey{}, &Peer{}, &User{}, &PersonalAccessToken{}, &Group{}, &Rule{},
|
||||||
// &Account{}, &Policy{}, &PolicyRule{}, &route.Route{}, &nbdns.NameServerGroup{},
|
// &Account{}, &Policy{}, &PolicyRule{}, &route.Route{}, &nbdns.NameServerGroup{},
|
||||||
// &installation{},
|
// &installation{},
|
||||||
@ -94,12 +80,7 @@ func NewDefaultSqliteStore(dataDir string, metrics telemetry.AppMetrics) (*Defau
|
|||||||
// return nil, err
|
// return nil, err
|
||||||
// }
|
// }
|
||||||
|
|
||||||
return &DefaultSqliteStore{db: db, storeFile: file, metrics: metrics, installationPK: 1}, nil
|
return &DefaultSqliteStore{DB: db, storeFile: file, metrics: metrics, installationPK: 1}, nil
|
||||||
}
|
|
||||||
|
|
||||||
func (s *DefaultSqliteStore) GetLicense() string {
|
|
||||||
// TODO implement me
|
|
||||||
panic("implement me")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AcquireGlobalLock acquires global lock across all the accounts and returns a function that releases the lock
|
// AcquireGlobalLock acquires global lock across all the accounts and returns a function that releases the lock
|
||||||
@ -138,17 +119,161 @@ func (s *DefaultSqliteStore) AcquireAccountLock(accountID string) (unlock func()
|
|||||||
return unlock
|
return unlock
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *DefaultSqliteStore) LoadAccount(accountID string) error {
|
||||||
|
var account DefaultAccount
|
||||||
|
result := s.DB.Model(&account).
|
||||||
|
Preload("UsersG.PATsG"). // have to be specifies as this is nester reference
|
||||||
|
Preload(clause.Associations).
|
||||||
|
First(&account, "id = ?", accountID)
|
||||||
|
if result.Error != nil {
|
||||||
|
log.Errorf("error when getting account from the store: %s", result.Error)
|
||||||
|
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||||
|
return status.Errorf(status.NotFound, "account not found")
|
||||||
|
}
|
||||||
|
return status.Errorf(status.Internal, "issue getting account from store")
|
||||||
|
}
|
||||||
|
|
||||||
|
// we have to manually preload policy rules as it seems that gorm preloading doesn't do it for us
|
||||||
|
for i, policy := range account.Policies {
|
||||||
|
var rules []*policyTypes.DefaultPolicyRule
|
||||||
|
err := s.DB.Model(&policyTypes.DefaultPolicyRule{}).Find(&rules, "policy_id = ?", policy.ID).Error
|
||||||
|
if err != nil {
|
||||||
|
return status.Errorf(status.NotFound, "rule not found")
|
||||||
|
}
|
||||||
|
account.Policies[i].Rules = rules
|
||||||
|
}
|
||||||
|
|
||||||
|
account.SetupKeys = make(map[string]*setupKeyTypes.DefaultSetupKey, len(account.SetupKeysG))
|
||||||
|
for _, key := range account.SetupKeysG {
|
||||||
|
account.SetupKeys[key.Key] = key.Copy()
|
||||||
|
}
|
||||||
|
account.SetupKeysG = nil
|
||||||
|
|
||||||
|
account.Peers = make(map[string]*nbpeer.Peer, len(account.PeersG))
|
||||||
|
for _, peer := range account.PeersG {
|
||||||
|
account.Peers[peer.ID] = peer.Copy()
|
||||||
|
}
|
||||||
|
account.PeersG = nil
|
||||||
|
|
||||||
|
account.Users = make(map[string]*userTypes.DefaultUser, len(account.UsersG))
|
||||||
|
for _, user := range account.UsersG {
|
||||||
|
user.PATs = make(map[string]*PersonalAccessToken, len(user.PATs))
|
||||||
|
for _, pat := range user.PATsG {
|
||||||
|
user.PATs[pat.ID] = pat.Copy()
|
||||||
|
}
|
||||||
|
account.Users[user.Id] = user.Copy()
|
||||||
|
}
|
||||||
|
account.UsersG = nil
|
||||||
|
|
||||||
|
account.Groups = make(map[string]*groupTypes.DefaultGroup, len(account.GroupsG))
|
||||||
|
for _, group := range account.GroupsG {
|
||||||
|
account.Groups[group.ID] = group.Copy()
|
||||||
|
}
|
||||||
|
account.GroupsG = nil
|
||||||
|
|
||||||
|
account.Routes = make(map[string]*routeTypes.DefaultRoute, len(account.RoutesG))
|
||||||
|
for _, route := range account.RoutesG {
|
||||||
|
account.Routes[route.ID] = route.Copy()
|
||||||
|
}
|
||||||
|
account.RoutesG = nil
|
||||||
|
|
||||||
|
account.NameServerGroups = make(map[string]*dnsTypes.DefaultNameServerGroup, len(account.NameServerGroupsG))
|
||||||
|
for _, ns := range account.NameServerGroupsG {
|
||||||
|
account.NameServerGroups[ns.ID] = ns.Copy()
|
||||||
|
}
|
||||||
|
account.NameServerGroupsG = nil
|
||||||
|
|
||||||
|
s.accounts[account.Id] = &account
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DefaultSqliteStore) WriteAccount(accountID string) error {
|
||||||
|
start := time.Now()
|
||||||
|
|
||||||
|
account, ok := s.accounts[accountID]
|
||||||
|
if !ok {
|
||||||
|
return status.Errorf(status.NotFound, "account not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, key := range account.SetupKeys {
|
||||||
|
account.SetupKeysG = append(account.SetupKeysG, *key)
|
||||||
|
}
|
||||||
|
|
||||||
|
for id, peer := range account.Peers {
|
||||||
|
peer.ID = id
|
||||||
|
account.PeersG = append(account.PeersG, *peer)
|
||||||
|
}
|
||||||
|
|
||||||
|
for id, user := range account.Users {
|
||||||
|
user.Id = id
|
||||||
|
for id, pat := range user.PATs {
|
||||||
|
pat.ID = id
|
||||||
|
user.PATsG = append(user.PATsG, *pat)
|
||||||
|
}
|
||||||
|
account.UsersG = append(account.UsersG, *user)
|
||||||
|
}
|
||||||
|
|
||||||
|
for id, group := range account.Groups {
|
||||||
|
group.ID = id
|
||||||
|
account.GroupsG = append(account.GroupsG, *group)
|
||||||
|
}
|
||||||
|
|
||||||
|
for id, route := range account.Routes {
|
||||||
|
route.ID = id
|
||||||
|
account.RoutesG = append(account.RoutesG, *route)
|
||||||
|
}
|
||||||
|
|
||||||
|
for id, ns := range account.NameServerGroups {
|
||||||
|
ns.ID = id
|
||||||
|
account.NameServerGroupsG = append(account.NameServerGroupsG, *ns)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := s.DB.Transaction(func(tx *gorm.DB) error {
|
||||||
|
result := tx.Select(clause.Associations).Delete(account.Policies, "account_id = ?", account.Id)
|
||||||
|
if result.Error != nil {
|
||||||
|
return result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
result = tx.Select(clause.Associations).Delete(account.UsersG, "account_id = ?", account.Id)
|
||||||
|
if result.Error != nil {
|
||||||
|
return result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
result = tx.Select(clause.Associations).Delete(account)
|
||||||
|
if result.Error != nil {
|
||||||
|
return result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
result = tx.
|
||||||
|
Session(&gorm.Session{FullSaveAssociations: true}).
|
||||||
|
Clauses(clause.OnConflict{UpdateAll: true}).Create(account)
|
||||||
|
if result.Error != nil {
|
||||||
|
return result.Error
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
took := time.Since(start)
|
||||||
|
if s.metrics != nil {
|
||||||
|
s.metrics.StoreMetrics().CountPersistenceDuration(took)
|
||||||
|
}
|
||||||
|
log.Debugf("took %d ms to persist an account to the SQLite", took.Milliseconds())
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func (s *DefaultSqliteStore) SaveInstallationID(ID string) error {
|
func (s *DefaultSqliteStore) SaveInstallationID(ID string) error {
|
||||||
installation := installation{InstallationIDValue: ID}
|
installation := installation{InstallationIDValue: ID}
|
||||||
installation.ID = uint(s.installationPK)
|
installation.ID = uint(s.installationPK)
|
||||||
|
|
||||||
return s.db.Clauses(clause.OnConflict{UpdateAll: true}).Create(&installation).Error
|
return s.DB.Clauses(clause.OnConflict{UpdateAll: true}).Create(&installation).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DefaultSqliteStore) GetInstallationID() string {
|
func (s *DefaultSqliteStore) GetInstallationID() string {
|
||||||
var installation installation
|
var installation installation
|
||||||
|
|
||||||
if result := s.db.First(&installation, "id = ?", s.installationPK); result.Error != nil {
|
if result := s.DB.First(&installation, "id = ?", s.installationPK); result.Error != nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,3 +289,57 @@ func (s *DefaultSqliteStore) Close() error {
|
|||||||
func (s *DefaultSqliteStore) GetStoreEngine() StoreEngine {
|
func (s *DefaultSqliteStore) GetStoreEngine() StoreEngine {
|
||||||
return SqliteStoreEngine
|
return SqliteStoreEngine
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *DefaultSqliteStore) GetLicense() string {
|
||||||
|
// TODO implement me
|
||||||
|
panic("implement me")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DefaultSqliteStore) FindSettings(accountID string) (settings.Settings, error) {
|
||||||
|
account, ok := s.accounts[accountID]
|
||||||
|
if !ok {
|
||||||
|
return nil, status.Errorf(status.NotFound, "account not found")
|
||||||
|
}
|
||||||
|
return account.Settings, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DefaultSqliteStore) FindPeerByPubKey(accountID string, pubKey string) (peers.Peer, error) {
|
||||||
|
a, ok := s.accounts[accountID]
|
||||||
|
if !ok {
|
||||||
|
return nil, status.Errorf(status.NotFound, "account not found")
|
||||||
|
}
|
||||||
|
for _, peer := range a.Peers {
|
||||||
|
if peer.Key == pubKey {
|
||||||
|
return peer.Copy(), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, status.Errorf(status.NotFound, "peer with the public key %s not found", pubKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DefaultSqliteStore) FindPeerByID(accountID string, id string) (peers.Peer, error) {
|
||||||
|
a, ok := s.accounts[accountID]
|
||||||
|
if !ok {
|
||||||
|
return nil, status.Errorf(status.NotFound, "account not found")
|
||||||
|
}
|
||||||
|
for _, peer := range a.Peers {
|
||||||
|
if peer.ID == id {
|
||||||
|
return peer.Copy(), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, status.Errorf(status.NotFound, "peer with the ID %s not found", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DefaultSqliteStore) FindAllPeersInAccount(accountId string) ([]peers.Peer, error) {
|
||||||
|
a, ok := s.accounts[accountID]
|
||||||
|
if !ok {
|
||||||
|
return nil, status.Errorf(status.NotFound, "account not found")
|
||||||
|
}
|
||||||
|
return a.Peers, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DefaultSqliteStore) UpdatePeer(peer peers.Peer) error {
|
||||||
|
// TODO implement me
|
||||||
|
panic("implement me")
|
||||||
|
}
|
||||||
|
@ -7,27 +7,26 @@ import (
|
|||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/management/refactor/peers"
|
peerTypes "github.com/netbirdio/netbird/management/refactor/resources/peers/types"
|
||||||
"github.com/netbirdio/netbird/management/refactor/settings"
|
settingsTypes "github.com/netbirdio/netbird/management/refactor/resources/settings/types"
|
||||||
"github.com/netbirdio/netbird/management/server/telemetry"
|
"github.com/netbirdio/netbird/management/server/telemetry"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Store interface {
|
type Store interface {
|
||||||
|
AcquireAccountLock(id string) func()
|
||||||
|
AcquireGlobalLock() func()
|
||||||
|
LoadAccount(id string) error
|
||||||
|
WriteAccount(id string) error
|
||||||
GetLicense() string
|
GetLicense() string
|
||||||
FindPeerByPubKey(pubKey string) (peers.Peer, error)
|
FindPeerByPubKey(pubKey string) (peerTypes.Peer, error)
|
||||||
FindPeerByID(id string) (peers.Peer, error)
|
FindPeerByID(id string) (peerTypes.Peer, error)
|
||||||
FindAllPeersInAccount(id string) ([]peers.Peer, error)
|
FindAllPeersInAccount(id string) ([]peerTypes.Peer, error)
|
||||||
UpdatePeer(peer peers.Peer) error
|
UpdatePeer(peer peerTypes.Peer) error
|
||||||
FindSettings(accountID string) (settings.Settings, error)
|
FindSettings(accountID string) (settingsTypes.Settings, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type DefaultStore interface {
|
type DefaultStore interface {
|
||||||
GetLicense() string
|
Store
|
||||||
FindPeerByPubKey(pubKey string) (peers.Peer, error)
|
|
||||||
FindPeerByID(id string) (peers.Peer, error)
|
|
||||||
FindAllPeersInAccount(id string) ([]peers.Peer, error)
|
|
||||||
UpdatePeer(peer peers.Peer) error
|
|
||||||
FindSettings(accountID string) (settings.Settings, error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type StoreEngine string
|
type StoreEngine string
|
||||||
|
@ -1,24 +0,0 @@
|
|||||||
package users
|
|
||||||
|
|
||||||
import "github.com/netbirdio/netbird/management/refactor/peers"
|
|
||||||
|
|
||||||
type Manager interface {
|
|
||||||
GetUser(id string) (User, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type DefaultManager struct {
|
|
||||||
repository repository
|
|
||||||
peerManager peers.Manager
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDefaultManager(repository repository, peerManager peers.Manager) *DefaultManager {
|
|
||||||
return &DefaultManager{
|
|
||||||
repository: repository,
|
|
||||||
peerManager: peerManager,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d DefaultManager) GetUser(id string) (User, error) {
|
|
||||||
// TODO implement me
|
|
||||||
panic("implement me")
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user