mirror of
https://github.com/netbirdio/management-refactor.git
synced 2026-05-22 17:12:59 -07:00
extend with additional packages
This commit is contained in:
@@ -6,22 +6,88 @@ toolchain go1.23.8
|
||||
|
||||
require (
|
||||
github.com/caarlos0/env/v11 v11.3.1
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||
github.com/golang/mock v1.6.0
|
||||
github.com/golang/protobuf v1.5.4
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/gorilla/mux v1.8.1
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.2-0.20240212192251-757544f21357
|
||||
github.com/hashicorp/go-secure-stdlib/base62 v0.1.2
|
||||
github.com/mattn/go-sqlite3 v1.14.22
|
||||
github.com/netbirdio/management-integrations/integrations v0.0.0-20250330143713-7901e0a82203
|
||||
github.com/netbirdio/netbird v0.41.0
|
||||
github.com/petermattis/goid v0.0.0-20250319124200-ccd6737f222a
|
||||
github.com/rs/xid v1.3.0
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/spf13/cobra v1.9.1
|
||||
github.com/spf13/viper v1.20.1
|
||||
github.com/stretchr/testify v1.10.0
|
||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6
|
||||
google.golang.org/grpc v1.67.3
|
||||
gorm.io/driver/postgres v1.5.11
|
||||
gorm.io/driver/sqlite v1.5.7
|
||||
gorm.io/gorm v1.25.12
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go/auth v0.13.0 // indirect
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.6 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.6.0 // indirect
|
||||
dario.cat/mergo v1.0.0 // indirect
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
|
||||
github.com/BurntSushi/toml v1.4.0 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/Microsoft/hcsshim v0.12.3 // indirect
|
||||
github.com/TheJumpCloud/jcapi-go v3.0.0+incompatible // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.30.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.27.27 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.27 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/route53 v1.42.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.22.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 // indirect
|
||||
github.com/aws/smithy-go v1.20.3 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/c-robinson/iplib v1.0.3 // indirect
|
||||
github.com/caddyserver/certmagic v0.21.3 // indirect
|
||||
github.com/caddyserver/zerossl v0.1.3 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/containerd/containerd v1.7.26 // indirect
|
||||
github.com/containerd/log v0.1.0 // indirect
|
||||
github.com/containerd/platforms v0.2.1 // indirect
|
||||
github.com/cpuguy83/dockercfg v0.3.2 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/distribution/reference v0.6.0 // indirect
|
||||
github.com/docker/docker v26.1.5+incompatible // indirect
|
||||
github.com/docker/go-connections v0.5.0 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/eko/gocache/lib/v4 v4.2.0 // indirect
|
||||
github.com/eko/gocache/store/go_cache/v4 v4.2.2 // indirect
|
||||
github.com/eko/gocache/store/redis/v4 v4.2.2 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fsnotify/fsnotify v1.8.0 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/go-sql-driver/mysql v1.8.1 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/google/s2a-go v0.1.8 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.14.1 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/go-uuid v1.0.3 // indirect
|
||||
github.com/hashicorp/go-version v1.6.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
|
||||
@@ -29,19 +95,79 @@ require (
|
||||
github.com/jackc/puddle/v2 v2.2.1 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.22 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/kelseyhightower/envconfig v1.4.0 // indirect
|
||||
github.com/klauspost/compress v1.17.8 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
||||
github.com/libdns/libdns v0.2.2 // indirect
|
||||
github.com/libdns/route53 v1.5.0 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20240513124658-fba389f38bae // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/mholt/acmez/v2 v2.0.1 // indirect
|
||||
github.com/miekg/dns v1.1.59 // indirect
|
||||
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||
github.com/moby/patternmatcher v0.6.0 // indirect
|
||||
github.com/moby/sys/sequential v0.5.0 // indirect
|
||||
github.com/moby/sys/user v0.3.0 // indirect
|
||||
github.com/moby/sys/userns v0.1.0 // indirect
|
||||
github.com/moby/term v0.5.0 // indirect
|
||||
github.com/morikuni/aec v1.0.0 // indirect
|
||||
github.com/okta/okta-sdk-golang/v2 v2.18.0 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.0 // indirect
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
|
||||
github.com/prometheus/client_golang v1.19.1 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.53.0 // indirect
|
||||
github.com/prometheus/procfs v0.15.0 // indirect
|
||||
github.com/redis/go-redis/v9 v9.7.1 // indirect
|
||||
github.com/sagikazarmark/locafero v0.7.0 // indirect
|
||||
github.com/shirou/gopsutil/v3 v3.24.4 // indirect
|
||||
github.com/shoenig/go-m1cpu v0.1.6 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spf13/afero v1.12.0 // indirect
|
||||
github.com/spf13/cast v1.7.1 // indirect
|
||||
github.com/spf13/pflag v1.0.6 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/testcontainers/testcontainers-go v0.31.0 // indirect
|
||||
github.com/testcontainers/testcontainers-go/modules/mysql v0.31.0 // indirect
|
||||
github.com/testcontainers/testcontainers-go/modules/postgres v0.31.0 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.14 // indirect
|
||||
github.com/tklauser/numcpus v0.8.0 // indirect
|
||||
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
|
||||
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||
github.com/zeebo/blake3 v0.2.3 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect
|
||||
go.opentelemetry.io/otel v1.29.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/prometheus v0.48.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.29.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.29.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/metric v1.29.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.29.0 // indirect
|
||||
go.uber.org/mock v0.4.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
goauthentik.io/api/v3 v3.2023051.3 // indirect
|
||||
golang.org/x/crypto v0.36.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect
|
||||
golang.org/x/mod v0.17.0 // indirect
|
||||
golang.org/x/net v0.36.0 // indirect
|
||||
golang.org/x/oauth2 v0.25.0 // indirect
|
||||
golang.org/x/sync v0.12.0 // indirect
|
||||
golang.org/x/sys v0.31.0 // indirect
|
||||
golang.org/x/text v0.23.0 // indirect
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
|
||||
golang.zx2c4.com/wireguard/windows v0.5.3 // indirect
|
||||
google.golang.org/api v0.215.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8 // indirect
|
||||
google.golang.org/protobuf v1.36.1 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
|
||||
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
gorm.io/driver/mysql v1.5.7 // indirect
|
||||
)
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
package server
|
||||
@@ -0,0 +1,4 @@
|
||||
package network_map
|
||||
|
||||
type Controller struct {
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/netbirdio/netbird/management/proto"
|
||||
"github.com/netbirdio/netbird/management/server/telemetry"
|
||||
"github.com/netbirdio/netbird/management/server/types"
|
||||
)
|
||||
|
||||
const channelBufferSize = 100
|
||||
|
||||
type UpdateMessage struct {
|
||||
Update *proto.SyncResponse
|
||||
NetworkMap *types.NetworkMap
|
||||
}
|
||||
|
||||
type UpdateChannel struct {
|
||||
// peerChannels is an update channel indexed by Peer.ID
|
||||
peerChannels map[string]chan *UpdateMessage
|
||||
// channelsMux keeps the mutex to access peerChannels
|
||||
channelsMux *sync.RWMutex
|
||||
// metrics provides method to collect application metrics
|
||||
metrics telemetry.AppMetrics
|
||||
}
|
||||
|
||||
// NewUpdateChannel returns a new instance of UpdateChannel
|
||||
func NewUpdateChannel(metrics telemetry.AppMetrics) *UpdateChannel {
|
||||
return &UpdateChannel{
|
||||
peerChannels: make(map[string]chan *UpdateMessage),
|
||||
channelsMux: &sync.RWMutex{},
|
||||
metrics: metrics,
|
||||
}
|
||||
}
|
||||
|
||||
// SendUpdate sends update message to the peer's channel
|
||||
func (p *UpdateChannel) SendUpdate(ctx context.Context, peerID string, update *UpdateMessage) {
|
||||
start := time.Now()
|
||||
var found, dropped bool
|
||||
|
||||
p.channelsMux.RLock()
|
||||
|
||||
defer func() {
|
||||
p.channelsMux.RUnlock()
|
||||
if p.metrics != nil {
|
||||
p.metrics.UpdateChannelMetrics().CountSendUpdateDuration(time.Since(start), found, dropped)
|
||||
}
|
||||
}()
|
||||
|
||||
if channel, ok := p.peerChannels[peerID]; ok {
|
||||
found = true
|
||||
select {
|
||||
case channel <- update:
|
||||
log.WithContext(ctx).Debugf("update was sent to channel for peer %s", peerID)
|
||||
default:
|
||||
dropped = true
|
||||
log.WithContext(ctx).Warnf("channel for peer %s is %d full or closed", peerID, len(channel))
|
||||
}
|
||||
} else {
|
||||
log.WithContext(ctx).Debugf("peer %s has no channel", peerID)
|
||||
}
|
||||
}
|
||||
|
||||
// CreateChannel creates a go channel for a given peer used to deliver updates relevant to the peer.
|
||||
func (p *UpdateChannel) CreateChannel(ctx context.Context, peerID string) chan *UpdateMessage {
|
||||
start := time.Now()
|
||||
|
||||
closed := false
|
||||
|
||||
p.channelsMux.Lock()
|
||||
defer func() {
|
||||
p.channelsMux.Unlock()
|
||||
if p.metrics != nil {
|
||||
p.metrics.UpdateChannelMetrics().CountCreateChannelDuration(time.Since(start), closed)
|
||||
}
|
||||
}()
|
||||
|
||||
if channel, ok := p.peerChannels[peerID]; ok {
|
||||
closed = true
|
||||
delete(p.peerChannels, peerID)
|
||||
close(channel)
|
||||
}
|
||||
// mbragin: todo shouldn't it be more? or configurable?
|
||||
channel := make(chan *UpdateMessage, channelBufferSize)
|
||||
p.peerChannels[peerID] = channel
|
||||
|
||||
log.WithContext(ctx).Debugf("opened updates channel for a peer %s", peerID)
|
||||
|
||||
return channel
|
||||
}
|
||||
|
||||
func (p *UpdateChannel) closeChannel(ctx context.Context, peerID string) {
|
||||
if channel, ok := p.peerChannels[peerID]; ok {
|
||||
delete(p.peerChannels, peerID)
|
||||
close(channel)
|
||||
|
||||
log.WithContext(ctx).Debugf("closed updates channel of a peer %s", peerID)
|
||||
return
|
||||
}
|
||||
|
||||
log.WithContext(ctx).Debugf("closing updates channel: peer %s has no channel", peerID)
|
||||
}
|
||||
|
||||
// CloseChannels closes updates channel for each given peer
|
||||
func (p *UpdateChannel) CloseChannels(ctx context.Context, peerIDs []string) {
|
||||
start := time.Now()
|
||||
|
||||
p.channelsMux.Lock()
|
||||
defer func() {
|
||||
p.channelsMux.Unlock()
|
||||
if p.metrics != nil {
|
||||
p.metrics.UpdateChannelMetrics().CountCloseChannelsDuration(time.Since(start), len(peerIDs))
|
||||
}
|
||||
}()
|
||||
|
||||
for _, id := range peerIDs {
|
||||
p.closeChannel(ctx, id)
|
||||
}
|
||||
}
|
||||
|
||||
// CloseChannel closes updates channel of a given peer
|
||||
func (p *UpdateChannel) CloseChannel(ctx context.Context, peerID string) {
|
||||
start := time.Now()
|
||||
|
||||
p.channelsMux.Lock()
|
||||
defer func() {
|
||||
p.channelsMux.Unlock()
|
||||
if p.metrics != nil {
|
||||
p.metrics.UpdateChannelMetrics().CountCloseChannelDuration(time.Since(start))
|
||||
}
|
||||
}()
|
||||
|
||||
p.closeChannel(ctx, peerID)
|
||||
}
|
||||
|
||||
// GetAllConnectedPeers returns a copy of the connected peers map
|
||||
func (p *UpdateChannel) GetAllConnectedPeers() map[string]struct{} {
|
||||
start := time.Now()
|
||||
|
||||
p.channelsMux.RLock()
|
||||
|
||||
m := make(map[string]struct{})
|
||||
|
||||
defer func() {
|
||||
p.channelsMux.RUnlock()
|
||||
if p.metrics != nil {
|
||||
p.metrics.UpdateChannelMetrics().CountGetAllConnectedPeersDuration(time.Since(start), len(m))
|
||||
}
|
||||
}()
|
||||
|
||||
for ID := range p.peerChannels {
|
||||
m[ID] = struct{}{}
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
// HasChannel returns true if peers has channel in update manager, otherwise false
|
||||
func (p *UpdateChannel) HasChannel(peerID string) bool {
|
||||
start := time.Now()
|
||||
|
||||
p.channelsMux.RLock()
|
||||
|
||||
defer func() {
|
||||
p.channelsMux.RUnlock()
|
||||
if p.metrics != nil {
|
||||
p.metrics.UpdateChannelMetrics().CountHasChannelDuration(time.Since(start))
|
||||
}
|
||||
}()
|
||||
|
||||
_, ok := p.peerChannels[peerID]
|
||||
|
||||
return ok
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/netbirdio/netbird/management/proto"
|
||||
)
|
||||
|
||||
// var peersUpdater *UpdateChannel
|
||||
|
||||
func TestCreateChannel(t *testing.T) {
|
||||
peer := "test-create"
|
||||
peersUpdater := NewUpdateChannel(nil)
|
||||
defer peersUpdater.CloseChannel(context.Background(), peer)
|
||||
|
||||
_ = peersUpdater.CreateChannel(context.Background(), peer)
|
||||
if _, ok := peersUpdater.peerChannels[peer]; !ok {
|
||||
t.Error("Error creating the channel")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendUpdate(t *testing.T) {
|
||||
peer := "test-sendupdate"
|
||||
peersUpdater := NewUpdateChannel(nil)
|
||||
update1 := &UpdateMessage{Update: &proto.SyncResponse{
|
||||
NetworkMap: &proto.NetworkMap{
|
||||
Serial: 0,
|
||||
},
|
||||
}}
|
||||
_ = peersUpdater.CreateChannel(context.Background(), peer)
|
||||
if _, ok := peersUpdater.peerChannels[peer]; !ok {
|
||||
t.Error("Error creating the channel")
|
||||
}
|
||||
peersUpdater.SendUpdate(context.Background(), peer, update1)
|
||||
select {
|
||||
case <-peersUpdater.peerChannels[peer]:
|
||||
default:
|
||||
t.Error("Update wasn't send")
|
||||
}
|
||||
|
||||
for range [channelBufferSize]int{} {
|
||||
peersUpdater.SendUpdate(context.Background(), peer, update1)
|
||||
}
|
||||
|
||||
update2 := &UpdateMessage{Update: &proto.SyncResponse{
|
||||
NetworkMap: &proto.NetworkMap{
|
||||
Serial: 10,
|
||||
},
|
||||
}}
|
||||
|
||||
peersUpdater.SendUpdate(context.Background(), peer, update2)
|
||||
timeout := time.After(5 * time.Second)
|
||||
for range [channelBufferSize]int{} {
|
||||
select {
|
||||
case <-timeout:
|
||||
t.Error("timed out reading previously sent updates")
|
||||
case updateReader := <-peersUpdater.peerChannels[peer]:
|
||||
if updateReader.Update.NetworkMap.Serial == update2.Update.NetworkMap.Serial {
|
||||
t.Error("got the update that shouldn't have been sent")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestCloseChannel(t *testing.T) {
|
||||
peer := "test-close"
|
||||
peersUpdater := NewUpdateChannel(nil)
|
||||
_ = peersUpdater.CreateChannel(context.Background(), peer)
|
||||
if _, ok := peersUpdater.peerChannels[peer]; !ok {
|
||||
t.Error("Error creating the channel")
|
||||
}
|
||||
peersUpdater.CloseChannel(context.Background(), peer)
|
||||
if _, ok := peersUpdater.peerChannels[peer]; ok {
|
||||
t.Error("Error closing the channel")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package peer_expiration
|
||||
@@ -0,0 +1,112 @@
|
||||
package accounts
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
nbcontext "github.com/netbirdio/netbird/management/server/context"
|
||||
"github.com/netbirdio/netbird/management/server/http/util"
|
||||
|
||||
"management/internal/shared/db"
|
||||
"management/internal/shared/errors"
|
||||
"management/internal/shared/permissions"
|
||||
"management/internal/shared/permissions/modules"
|
||||
"management/internal/shared/permissions/operations"
|
||||
)
|
||||
|
||||
type handler struct {
|
||||
manager *Manager
|
||||
permissionsManager permissions.Manager
|
||||
}
|
||||
|
||||
func newHandler(manager *Manager, permissionsManager permissions.Manager) *handler {
|
||||
return &handler{
|
||||
manager: manager,
|
||||
permissionsManager: permissionsManager,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *handler) RegisterAPI(router *mux.Router) {
|
||||
router.HandleFunc("/accounts/{accountId}", h.updateAccount).Methods("PUT", "OPTIONS")
|
||||
router.HandleFunc("/accounts/{accountId}", h.deleteAccount).Methods("DELETE", "OPTIONS")
|
||||
router.HandleFunc("/accounts", h.getAllAccounts).Methods("GET", "OPTIONS")
|
||||
}
|
||||
|
||||
func (h *handler) updateAccount(w http.ResponseWriter, r *http.Request) {
|
||||
userAuth, err := nbcontext.GetUserAuthFromContext(r.Context())
|
||||
if err != nil {
|
||||
util.WriteError(r.Context(), err, w)
|
||||
return
|
||||
}
|
||||
|
||||
allowed, err := h.permissionsManager.ValidateUserPermissions(r.Context(), userAuth.AccountId, userAuth.UserId, modules.Accounts, operations.Write)
|
||||
if err != nil {
|
||||
util.WriteError(r.Context(), errors.NewPermissionValidationError(err), w)
|
||||
return
|
||||
}
|
||||
if !allowed {
|
||||
util.WriteError(r.Context(), errors.NewPermissionDeniedError(), w)
|
||||
}
|
||||
|
||||
vars := mux.Vars(r)
|
||||
accountId := vars["accountId"]
|
||||
|
||||
users, err := h.manager.UpdateAccount(r.Context(), nil, accountId)
|
||||
if err != nil {
|
||||
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
_ = json.NewEncoder(w).Encode(users)
|
||||
}
|
||||
|
||||
func (h *handler) deleteAccount(w http.ResponseWriter, r *http.Request) {
|
||||
userAuth, err := nbcontext.GetUserAuthFromContext(r.Context())
|
||||
if err != nil {
|
||||
util.WriteError(r.Context(), err, w)
|
||||
return
|
||||
}
|
||||
|
||||
allowed, err := h.permissionsManager.ValidateUserPermissions(r.Context(), userAuth.AccountId, userAuth.UserId, modules.Accounts, operations.Write)
|
||||
if err != nil {
|
||||
util.WriteError(r.Context(), errors.NewPermissionValidationError(err), w)
|
||||
return
|
||||
}
|
||||
if !allowed {
|
||||
util.WriteError(r.Context(), errors.NewPermissionDeniedError(), w)
|
||||
}
|
||||
|
||||
vars := mux.Vars(r)
|
||||
accountId := vars["accountId"]
|
||||
|
||||
user, err := h.manager.DeleteAccount(r.Context(), nil, db.LockingStrengthShare, accountId)
|
||||
if err != nil {
|
||||
http.Error(w, "Not Found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
_ = json.NewEncoder(w).Encode(user)
|
||||
}
|
||||
|
||||
func (h *handler) getAllAccounts(w http.ResponseWriter, r *http.Request) {
|
||||
userAuth, err := nbcontext.GetUserAuthFromContext(r.Context())
|
||||
if err != nil {
|
||||
util.WriteError(r.Context(), err, w)
|
||||
return
|
||||
}
|
||||
|
||||
allowed, err := h.permissionsManager.ValidateUserPermissions(r.Context(), userAuth.AccountId, userAuth.UserId, modules.Accounts, operations.Read)
|
||||
if err != nil {
|
||||
util.WriteError(r.Context(), errors.NewPermissionValidationError(err), w)
|
||||
return
|
||||
}
|
||||
if !allowed {
|
||||
util.WriteError(r.Context(), errors.NewPermissionDeniedError(), w)
|
||||
}
|
||||
|
||||
accounts, err := h.manager.GetAllAccounts(r.Context(), nil, db.LockingStrengthShare)
|
||||
if err != nil {
|
||||
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
_ = json.NewEncoder(w).Encode(accounts)
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package accounts
|
||||
|
||||
import "management/pkg/logging"
|
||||
|
||||
var log = logging.LoggerForThisPackage()
|
||||
|
||||
type Manager struct {
|
||||
repo Repository
|
||||
handler *handler
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package accounts
|
||||
|
||||
import "management/internal/shared/db"
|
||||
|
||||
type Repository interface {
|
||||
RunInTx(fn func(tx db.Transaction) error) error
|
||||
}
|
||||
|
||||
type repository struct {
|
||||
store *db.Store
|
||||
}
|
||||
|
||||
func newRepository(s *db.Store) Repository {
|
||||
return &repository{store: s}
|
||||
}
|
||||
|
||||
func (r *repository) RunInTx(fn func(tx db.Transaction) error) error {
|
||||
return r.store.RunInTx(fn)
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package settings
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
nbcontext "github.com/netbirdio/netbird/management/server/context"
|
||||
"github.com/netbirdio/netbird/management/server/http/util"
|
||||
|
||||
"management/internal/shared/db"
|
||||
"management/internal/shared/errors"
|
||||
"management/internal/shared/permissions"
|
||||
)
|
||||
|
||||
type handler struct {
|
||||
manager *Manager
|
||||
permissionsManager permissions.Manager
|
||||
}
|
||||
|
||||
func newHandler(manager *Manager, permissionsManager permissions.Manager) *handler {
|
||||
return &handler{
|
||||
manager: manager,
|
||||
permissionsManager: permissionsManager,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *handler) RegisterAPI(router *mux.Router) {
|
||||
router.HandleFunc("/account/{accountID}/settings", h.GetAllUsers).Methods("GET", "OPTIONS")
|
||||
router.HandleFunc("/account/{accountID}/settings", h.GetUser).Methods("PUT", "OPTIONS")
|
||||
}
|
||||
|
||||
func (h *handler) GetAllUsers(w http.ResponseWriter, r *http.Request) {
|
||||
userAuth, err := nbcontext.GetUserAuthFromContext(r.Context())
|
||||
if err != nil {
|
||||
util.WriteError(r.Context(), err, w)
|
||||
return
|
||||
}
|
||||
|
||||
allowed, err := h.permissionsManager.ValidateUserPermissions(r.Context(), userAuth.AccountId, userAuth.UserId, modules.Users, operations.Read)
|
||||
if err != nil {
|
||||
util.WriteError(r.Context(), errors.NewPermissionValidationError(err), w)
|
||||
return
|
||||
}
|
||||
if !allowed {
|
||||
util.WriteError(r.Context(), errors.NewPermissionDeniedError(), w)
|
||||
}
|
||||
|
||||
users, err := h.manager.GetAllUsers(r.Context(), nil, db.LockingStrengthShare, userAuth.AccountId)
|
||||
if err != nil {
|
||||
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
_ = json.NewEncoder(w).Encode(users)
|
||||
}
|
||||
|
||||
func (h *handler) GetUser(w http.ResponseWriter, r *http.Request) {
|
||||
userAuth, err := nbcontext.GetUserAuthFromContext(r.Context())
|
||||
if err != nil {
|
||||
util.WriteError(r.Context(), err, w)
|
||||
return
|
||||
}
|
||||
|
||||
allowed, err := h.permissionsManager.ValidateUserPermissions(r.Context(), userAuth.AccountId, userAuth.UserId, modules.Users, operations.Read)
|
||||
if err != nil {
|
||||
util.WriteError(r.Context(), errors.NewPermissionValidationError(err), w)
|
||||
return
|
||||
}
|
||||
if !allowed {
|
||||
util.WriteError(r.Context(), errors.NewPermissionDeniedError(), w)
|
||||
}
|
||||
|
||||
vars := mux.Vars(r)
|
||||
userId := vars["userId"]
|
||||
|
||||
user, err := h.manager.GetUserByID(r.Context(), nil, db.LockingStrengthShare, userId)
|
||||
if err != nil {
|
||||
http.Error(w, "Not Found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
_ = json.NewEncoder(w).Encode(user)
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package settings
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server/integrations/extra_settings"
|
||||
|
||||
"management/internal/modules/accounts/settings/types"
|
||||
"management/internal/modules/users"
|
||||
"management/internal/shared/db"
|
||||
"management/pkg/logging"
|
||||
)
|
||||
|
||||
var log = logging.LoggerForThisPackage()
|
||||
|
||||
type Manager struct {
|
||||
repository Repository
|
||||
extraSettingsManager extra_settings.Manager
|
||||
userManager *users.Manager
|
||||
}
|
||||
|
||||
func NewManager(store *db.Store, userManager *users.Manager, extraSettingsManager extra_settings.Manager) *Manager {
|
||||
return &Manager{
|
||||
repository: newRepository(store),
|
||||
extraSettingsManager: extraSettingsManager,
|
||||
userManager: userManager,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Manager) GetExtraSettingsManager() extra_settings.Manager {
|
||||
return m.extraSettingsManager
|
||||
}
|
||||
|
||||
func (m *Manager) GetSettings(ctx context.Context, tx db.Transaction, strength db.LockingStrength, accountID string) (*types.Settings, error) {
|
||||
extraSettings, err := m.extraSettingsManager.GetExtraSettings(ctx, accountID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get extra settings: %w", err)
|
||||
}
|
||||
|
||||
settings, err := m.repository.GetAccountSettings(tx, strength, accountID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get account settings: %w", err)
|
||||
}
|
||||
|
||||
// Once we migrate the peer approval to settings manager this merging is obsolete
|
||||
if settings.Extra != nil {
|
||||
settings.Extra.FlowEnabled = extraSettings.FlowEnabled
|
||||
settings.Extra.FlowPacketCounterEnabled = extraSettings.FlowPacketCounterEnabled
|
||||
settings.Extra.FlowENCollectionEnabled = extraSettings.FlowENCollectionEnabled
|
||||
settings.Extra.FlowDnsCollectionEnabled = extraSettings.FlowDnsCollectionEnabled
|
||||
}
|
||||
|
||||
return settings, nil
|
||||
}
|
||||
|
||||
func (m *Manager) GetExtraSettings(ctx context.Context, tx db.Transaction, accountID string) (*types.ExtraSettings, error) {
|
||||
extraSettings, err := m.extraSettingsManager.GetExtraSettings(ctx, accountID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get extra settings: %w", err)
|
||||
}
|
||||
|
||||
settings, err := m.repository.GetAccountSettings(tx, db.LockingStrengthShare, accountID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get account settings: %w", err)
|
||||
}
|
||||
|
||||
// Once we migrate the peer approval to settings manager this merging is obsolete
|
||||
if settings.Extra == nil {
|
||||
settings.Extra = &types.ExtraSettings{}
|
||||
}
|
||||
|
||||
settings.Extra.FlowEnabled = extraSettings.FlowEnabled
|
||||
|
||||
return settings.Extra, nil
|
||||
}
|
||||
|
||||
func (m *Manager) UpdateExtraSettings(ctx context.Context, accountID, userID string, extraSettings *types.ExtraSettings) (bool, error) {
|
||||
return m.extraSettingsManager.UpdateExtraSettings(ctx, accountID, userID, extraSettings)
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package settings
|
||||
|
||||
import (
|
||||
"management/internal/modules/accounts/settings/types"
|
||||
"management/internal/shared/db"
|
||||
)
|
||||
|
||||
type Repository interface {
|
||||
RunInTx(fn func(tx db.Transaction) error) error
|
||||
GetAccountSettings(tx db.Transaction, strength db.LockingStrength, accountID string) (*types.Settings, error)
|
||||
}
|
||||
|
||||
type repository struct {
|
||||
store *db.Store
|
||||
}
|
||||
|
||||
func newRepository(s *db.Store) Repository {
|
||||
return &repository{store: s}
|
||||
}
|
||||
|
||||
func (r *repository) RunInTx(fn func(tx db.Transaction) error) error {
|
||||
return r.store.RunInTx(fn)
|
||||
}
|
||||
|
||||
func (r *repository) GetAccountSettings(tx db.Transaction, strength db.LockingStrength, accountID string) (*types.Settings, error) {
|
||||
var settings types.Settings
|
||||
err := r.store.GetOne(tx, strength, &settings, "account_id = ?", accountID)
|
||||
return &settings, err
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Settings represents Account settings structure that can be modified via API and Dashboard
|
||||
type Settings struct {
|
||||
// PeerLoginExpirationEnabled globally enables or disables peer login expiration
|
||||
PeerLoginExpirationEnabled bool
|
||||
|
||||
// PeerLoginExpiration is a setting that indicates when peer login expires.
|
||||
// Applies to all peers that have Peer.LoginExpirationEnabled set to true.
|
||||
PeerLoginExpiration time.Duration
|
||||
|
||||
// PeerInactivityExpirationEnabled globally enables or disables peer inactivity expiration
|
||||
PeerInactivityExpirationEnabled bool
|
||||
|
||||
// PeerInactivityExpiration is a setting that indicates when peer inactivity expires.
|
||||
// Applies to all peers that have Peer.PeerInactivityExpirationEnabled set to true.
|
||||
PeerInactivityExpiration time.Duration
|
||||
|
||||
// RegularUsersViewBlocked allows to block regular users from viewing even their own peers and some UI elements
|
||||
RegularUsersViewBlocked bool
|
||||
|
||||
// GroupsPropagationEnabled allows to propagate auto groups from the user to the peer
|
||||
GroupsPropagationEnabled bool
|
||||
|
||||
// JWTGroupsEnabled allows extract groups from JWT claim, which name defined in the JWTGroupsClaimName
|
||||
// and add it to account groups.
|
||||
JWTGroupsEnabled bool
|
||||
|
||||
// JWTGroupsClaimName from which we extract groups name to add it to account groups
|
||||
JWTGroupsClaimName string
|
||||
|
||||
// JWTAllowGroups list of groups to which users are allowed access
|
||||
JWTAllowGroups []string `gorm:"serializer:json"`
|
||||
|
||||
// RoutingPeerDNSResolutionEnabled enabled the DNS resolution on the routing peers
|
||||
RoutingPeerDNSResolutionEnabled bool
|
||||
|
||||
// Extra is a dictionary of Account settings
|
||||
Extra *ExtraSettings `gorm:"embedded;embeddedPrefix:extra_"`
|
||||
}
|
||||
|
||||
// Copy copies the Settings struct
|
||||
func (s *Settings) Copy() *Settings {
|
||||
settings := &Settings{
|
||||
PeerLoginExpirationEnabled: s.PeerLoginExpirationEnabled,
|
||||
PeerLoginExpiration: s.PeerLoginExpiration,
|
||||
JWTGroupsEnabled: s.JWTGroupsEnabled,
|
||||
JWTGroupsClaimName: s.JWTGroupsClaimName,
|
||||
GroupsPropagationEnabled: s.GroupsPropagationEnabled,
|
||||
JWTAllowGroups: s.JWTAllowGroups,
|
||||
RegularUsersViewBlocked: s.RegularUsersViewBlocked,
|
||||
|
||||
PeerInactivityExpirationEnabled: s.PeerInactivityExpirationEnabled,
|
||||
PeerInactivityExpiration: s.PeerInactivityExpiration,
|
||||
|
||||
RoutingPeerDNSResolutionEnabled: s.RoutingPeerDNSResolutionEnabled,
|
||||
}
|
||||
if s.Extra != nil {
|
||||
settings.Extra = s.Extra.Copy()
|
||||
}
|
||||
return settings
|
||||
}
|
||||
|
||||
type ExtraSettings struct {
|
||||
// PeerApprovalEnabled enables or disables the need for peers bo be approved by an administrator
|
||||
PeerApprovalEnabled bool
|
||||
|
||||
// IntegratedValidatorGroups list of group IDs to be used with integrated approval configurations
|
||||
IntegratedValidatorGroups []string `gorm:"serializer:json"`
|
||||
|
||||
FlowEnabled bool `gorm:"-"`
|
||||
FlowPacketCounterEnabled bool `gorm:"-"`
|
||||
FlowENCollectionEnabled bool `gorm:"-"`
|
||||
FlowDnsCollectionEnabled bool `gorm:"-"`
|
||||
}
|
||||
|
||||
// Copy copies the ExtraSettings struct
|
||||
func (e *ExtraSettings) Copy() *ExtraSettings {
|
||||
var cpGroup []string
|
||||
|
||||
return &ExtraSettings{
|
||||
PeerApprovalEnabled: e.PeerApprovalEnabled,
|
||||
IntegratedValidatorGroups: append(cpGroup, e.IntegratedValidatorGroups...),
|
||||
}
|
||||
}
|
||||
@@ -28,11 +28,11 @@ func newHandler(manager *Manager, permissionsManager permissions.Manager) *handl
|
||||
}
|
||||
|
||||
func (h *handler) RegisterAPI(router *mux.Router) {
|
||||
router.HandleFunc("/users", h.GetAllUsers).Methods("GET", "OPTIONS")
|
||||
router.HandleFunc("/users/{userId}", h.GetUser).Methods("GET", "OPTIONS")
|
||||
router.HandleFunc("/users", h.getAllUsers).Methods("GET", "OPTIONS")
|
||||
router.HandleFunc("/users/{userId}", h.getUser).Methods("GET", "OPTIONS")
|
||||
}
|
||||
|
||||
func (h *handler) GetAllUsers(w http.ResponseWriter, r *http.Request) {
|
||||
func (h *handler) getAllUsers(w http.ResponseWriter, r *http.Request) {
|
||||
userAuth, err := nbcontext.GetUserAuthFromContext(r.Context())
|
||||
if err != nil {
|
||||
util.WriteError(r.Context(), err, w)
|
||||
@@ -56,7 +56,7 @@ func (h *handler) GetAllUsers(w http.ResponseWriter, r *http.Request) {
|
||||
_ = json.NewEncoder(w).Encode(users)
|
||||
}
|
||||
|
||||
func (h *handler) GetUser(w http.ResponseWriter, r *http.Request) {
|
||||
func (h *handler) getUser(w http.ResponseWriter, r *http.Request) {
|
||||
userAuth, err := nbcontext.GetUserAuthFromContext(r.Context())
|
||||
if err != nil {
|
||||
util.WriteError(r.Context(), err, w)
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
package users
|
||||
@@ -5,8 +5,12 @@ import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/netbirdio/management-integrations/integrations"
|
||||
|
||||
"management/internal/modules/settings"
|
||||
"management/internal/modules/users"
|
||||
"management/internal/shared/api"
|
||||
"management/internal/shared/api/rest"
|
||||
"management/internal/shared/db"
|
||||
"management/internal/shared/permissions"
|
||||
"management/pkg/logging"
|
||||
@@ -31,10 +35,12 @@ func NewServer() *Server {
|
||||
|
||||
store := db.NewStore(ctx, dbConn)
|
||||
|
||||
router := api.NewRouter()
|
||||
router := rest.NewRouter()
|
||||
|
||||
extraSettingsManager := integrations.NewManager()
|
||||
permissionsManager := permissions.NewManager(store)
|
||||
userManager := users.NewManager(store, permissions.NewManager(store))
|
||||
settingsManager := settings.NewManager(store, userManager, extraSettingsManager)
|
||||
|
||||
return &Server{
|
||||
httpServer: &http.Server{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user