mirror of
https://github.com/netbirdio/netbird.git
synced 2026-05-02 15:16:38 +00:00
move to reverse proxy and update api
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
|
||||||
nbcontext "github.com/netbirdio/netbird/management/server/context"
|
nbcontext "github.com/netbirdio/netbird/management/server/context"
|
||||||
"github.com/netbirdio/netbird/shared/management/http/api"
|
"github.com/netbirdio/netbird/shared/management/http/api"
|
||||||
"github.com/netbirdio/netbird/shared/management/http/util"
|
"github.com/netbirdio/netbird/shared/management/http/util"
|
||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/management/internals/modules/services/domains"
|
"github.com/netbirdio/netbird/management/internals/modules/reverseproxy/domains"
|
||||||
)
|
)
|
||||||
|
|
||||||
type resolver struct {
|
type resolver struct {
|
||||||
13
management/internals/modules/reverseproxy/interface.go
Normal file
13
management/internals/modules/reverseproxy/interface.go
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package reverseproxy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Manager interface {
|
||||||
|
GetAllReverseProxies(ctx context.Context, accountID, userID string) ([]*ReverseProxy, error)
|
||||||
|
GetReverseProxy(ctx context.Context, accountID, userID, reverseProxyID string) (*ReverseProxy, error)
|
||||||
|
CreateReverseProxy(ctx context.Context, accountID, userID string, reverseProxy *ReverseProxy) (*ReverseProxy, error)
|
||||||
|
UpdateReverseProxy(ctx context.Context, accountID, userID string, reverseProxy *ReverseProxy) (*ReverseProxy, error)
|
||||||
|
DeleteReverseProxy(ctx context.Context, accountID, userID, reverseProxyID string) error
|
||||||
|
}
|
||||||
161
management/internals/modules/reverseproxy/manager/api.go
Normal file
161
management/internals/modules/reverseproxy/manager/api.go
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
package manager
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
|
||||||
|
"github.com/netbirdio/netbird/management/internals/modules/reverseproxy"
|
||||||
|
nbcontext "github.com/netbirdio/netbird/management/server/context"
|
||||||
|
"github.com/netbirdio/netbird/shared/management/http/api"
|
||||||
|
"github.com/netbirdio/netbird/shared/management/http/util"
|
||||||
|
"github.com/netbirdio/netbird/shared/management/status"
|
||||||
|
)
|
||||||
|
|
||||||
|
type handler struct {
|
||||||
|
manager reverseproxy.Manager
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterEndpoints(router *mux.Router, manager reverseproxy.Manager) {
|
||||||
|
h := &handler{
|
||||||
|
manager: manager,
|
||||||
|
}
|
||||||
|
|
||||||
|
router.HandleFunc("/reverse-proxies", h.getAllReverseProxies).Methods("GET", "OPTIONS")
|
||||||
|
router.HandleFunc("/reverse-proxies", h.createReverseProxy).Methods("POST", "OPTIONS")
|
||||||
|
router.HandleFunc("/reverse-proxies/{reverseProxyId}", h.getReverseProxy).Methods("GET", "OPTIONS")
|
||||||
|
router.HandleFunc("/reverse-proxies/{reverseProxyId}", h.updateReverseProxy).Methods("PUT", "OPTIONS")
|
||||||
|
router.HandleFunc("/reverse-proxies/{reverseProxyId}", h.deleteReverseProxy).Methods("DELETE", "OPTIONS")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *handler) getAllReverseProxies(w http.ResponseWriter, r *http.Request) {
|
||||||
|
userAuth, err := nbcontext.GetUserAuthFromContext(r.Context())
|
||||||
|
if err != nil {
|
||||||
|
util.WriteError(r.Context(), err, w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
allReverseProxies, err := h.manager.GetAllReverseProxies(r.Context(), userAuth.AccountId, userAuth.UserId)
|
||||||
|
if err != nil {
|
||||||
|
util.WriteError(r.Context(), err, w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
apiReverseProxies := make([]*api.ReverseProxy, 0, len(allReverseProxies))
|
||||||
|
for _, reverseProxy := range allReverseProxies {
|
||||||
|
apiReverseProxies = append(apiReverseProxies, reverseProxy.ToAPIResponse())
|
||||||
|
}
|
||||||
|
|
||||||
|
util.WriteJSONObject(r.Context(), w, apiReverseProxies)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *handler) createReverseProxy(w http.ResponseWriter, r *http.Request) {
|
||||||
|
userAuth, err := nbcontext.GetUserAuthFromContext(r.Context())
|
||||||
|
if err != nil {
|
||||||
|
util.WriteError(r.Context(), err, w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var req api.PostApiReverseProxyJSONRequestBody
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||||
|
util.WriteErrorResponse("couldn't parse JSON request", http.StatusBadRequest, w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
reverseProxy := new(reverseproxy.ReverseProxy)
|
||||||
|
reverseProxy.FromAPIRequest(&req)
|
||||||
|
|
||||||
|
if err = reverseProxy.Validate(); err != nil {
|
||||||
|
util.WriteError(r.Context(), status.Errorf(status.InvalidArgument, "%s", err.Error()), w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
createdReverseProxy, err := h.manager.CreateReverseProxy(r.Context(), userAuth.AccountId, userAuth.UserId, reverseProxy)
|
||||||
|
if err != nil {
|
||||||
|
util.WriteError(r.Context(), err, w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
util.WriteJSONObject(r.Context(), w, createdReverseProxy.ToAPIResponse())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *handler) getReverseProxy(w http.ResponseWriter, r *http.Request) {
|
||||||
|
userAuth, err := nbcontext.GetUserAuthFromContext(r.Context())
|
||||||
|
if err != nil {
|
||||||
|
util.WriteError(r.Context(), err, w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
reverseProxyID := mux.Vars(r)["proxyId"]
|
||||||
|
if reverseProxyID == "" {
|
||||||
|
util.WriteError(r.Context(), status.Errorf(status.InvalidArgument, "reverse proxy ID is required"), w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
reverseProxy, err := h.manager.GetReverseProxy(r.Context(), userAuth.AccountId, userAuth.UserId, reverseProxyID)
|
||||||
|
if err != nil {
|
||||||
|
util.WriteError(r.Context(), err, w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
util.WriteJSONObject(r.Context(), w, reverseProxy.ToAPIResponse())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *handler) updateReverseProxy(w http.ResponseWriter, r *http.Request) {
|
||||||
|
userAuth, err := nbcontext.GetUserAuthFromContext(r.Context())
|
||||||
|
if err != nil {
|
||||||
|
util.WriteError(r.Context(), err, w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
reverseProxyID := mux.Vars(r)["proxyId"]
|
||||||
|
if reverseProxyID == "" {
|
||||||
|
util.WriteError(r.Context(), status.Errorf(status.InvalidArgument, "reverse proxy ID is required"), w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var req api.PutApiReverseProxyProxyIdJSONRequestBody
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||||
|
util.WriteErrorResponse("couldn't parse JSON request", http.StatusBadRequest, w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
reverseProxy := new(reverseproxy.ReverseProxy)
|
||||||
|
reverseProxy.ID = reverseProxyID
|
||||||
|
reverseProxy.FromAPIRequest(&req)
|
||||||
|
|
||||||
|
if err = reverseProxy.Validate(); err != nil {
|
||||||
|
util.WriteError(r.Context(), status.Errorf(status.InvalidArgument, "%s", err.Error()), w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
updatedReverseProxy, err := h.manager.UpdateReverseProxy(r.Context(), userAuth.AccountId, userAuth.UserId, reverseProxy)
|
||||||
|
if err != nil {
|
||||||
|
util.WriteError(r.Context(), err, w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
util.WriteJSONObject(r.Context(), w, updatedReverseProxy.ToAPIResponse())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *handler) deleteReverseProxy(w http.ResponseWriter, r *http.Request) {
|
||||||
|
userAuth, err := nbcontext.GetUserAuthFromContext(r.Context())
|
||||||
|
if err != nil {
|
||||||
|
util.WriteError(r.Context(), err, w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
reverseProxyID := mux.Vars(r)["proxyId"]
|
||||||
|
if reverseProxyID == "" {
|
||||||
|
util.WriteError(r.Context(), status.Errorf(status.InvalidArgument, "reverse proxy ID is required"), w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := h.manager.DeleteReverseProxy(r.Context(), userAuth.AccountId, userAuth.UserId, reverseProxyID); err != nil {
|
||||||
|
util.WriteError(r.Context(), err, w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
util.WriteJSONObject(r.Context(), w, util.EmptyObject{})
|
||||||
|
}
|
||||||
171
management/internals/modules/reverseproxy/manager/manager.go
Normal file
171
management/internals/modules/reverseproxy/manager/manager.go
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
package manager
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/netbirdio/netbird/management/internals/modules/reverseproxy"
|
||||||
|
"github.com/netbirdio/netbird/management/server/account"
|
||||||
|
"github.com/netbirdio/netbird/management/server/activity"
|
||||||
|
"github.com/netbirdio/netbird/management/server/permissions"
|
||||||
|
"github.com/netbirdio/netbird/management/server/permissions/modules"
|
||||||
|
"github.com/netbirdio/netbird/management/server/permissions/operations"
|
||||||
|
"github.com/netbirdio/netbird/management/server/store"
|
||||||
|
"github.com/netbirdio/netbird/shared/management/status"
|
||||||
|
)
|
||||||
|
|
||||||
|
type managerImpl struct {
|
||||||
|
store store.Store
|
||||||
|
accountManager account.Manager
|
||||||
|
permissionsManager permissions.Manager
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewManager(store store.Store, accountManager account.Manager, permissionsManager permissions.Manager) reverseproxy.Manager {
|
||||||
|
return &managerImpl{
|
||||||
|
store: store,
|
||||||
|
accountManager: accountManager,
|
||||||
|
permissionsManager: permissionsManager,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *managerImpl) GetAllReverseProxies(ctx context.Context, accountID, userID string) ([]*reverseproxy.ReverseProxy, error) {
|
||||||
|
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Services, operations.Read)
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.NewPermissionValidationError(err)
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
return nil, status.NewPermissionDeniedError()
|
||||||
|
}
|
||||||
|
|
||||||
|
return m.store.GetAccountReverseProxies(ctx, store.LockingStrengthNone, accountID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *managerImpl) GetReverseProxy(ctx context.Context, accountID, userID, reverseProxyID string) (*reverseproxy.ReverseProxy, error) {
|
||||||
|
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Services, operations.Read)
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.NewPermissionValidationError(err)
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
return nil, status.NewPermissionDeniedError()
|
||||||
|
}
|
||||||
|
|
||||||
|
return m.store.GetReverseProxyByID(ctx, store.LockingStrengthNone, accountID, reverseProxyID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *managerImpl) CreateReverseProxy(ctx context.Context, accountID, userID string, reverseProxy *reverseproxy.ReverseProxy) (*reverseproxy.ReverseProxy, error) {
|
||||||
|
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Services, operations.Create)
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.NewPermissionValidationError(err)
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
return nil, status.NewPermissionDeniedError()
|
||||||
|
}
|
||||||
|
|
||||||
|
authConfig := reverseProxy.Auth
|
||||||
|
|
||||||
|
reverseProxy = reverseproxy.NewReverseProxy(accountID, reverseProxy.Name, reverseProxy.Domain, reverseProxy.Targets, reverseProxy.Enabled)
|
||||||
|
|
||||||
|
reverseProxy.Auth = authConfig
|
||||||
|
|
||||||
|
err = m.store.ExecuteInTransaction(ctx, func(transaction store.Store) error {
|
||||||
|
// Check for duplicate domain
|
||||||
|
existingReverseProxy, err := transaction.GetReverseProxyByDomain(ctx, accountID, reverseProxy.Domain)
|
||||||
|
if err != nil {
|
||||||
|
if sErr, ok := status.FromError(err); !ok || sErr.Type() != status.NotFound {
|
||||||
|
return fmt.Errorf("failed to check existing reverse proxy: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if existingReverseProxy != nil {
|
||||||
|
return status.Errorf(status.AlreadyExists, "reverse proxy with domain %s already exists", reverseProxy.Domain)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = transaction.CreateReverseProxy(ctx, reverseProxy); err != nil {
|
||||||
|
return fmt.Errorf("failed to create reverse proxy: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
m.accountManager.StoreEvent(ctx, userID, reverseProxy.ID, accountID, activity.ReverseProxyCreated, reverseProxy.EventMeta())
|
||||||
|
|
||||||
|
return reverseProxy, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *managerImpl) UpdateReverseProxy(ctx context.Context, accountID, userID string, reverseProxy *reverseproxy.ReverseProxy) (*reverseproxy.ReverseProxy, error) {
|
||||||
|
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Services, operations.Update)
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.NewPermissionValidationError(err)
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
return nil, status.NewPermissionDeniedError()
|
||||||
|
}
|
||||||
|
|
||||||
|
err = m.store.ExecuteInTransaction(ctx, func(transaction store.Store) error {
|
||||||
|
// Get existing reverse proxy
|
||||||
|
existingReverseProxy, err := transaction.GetReverseProxyByID(ctx, store.LockingStrengthUpdate, accountID, reverseProxy.ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if domain changed and if it conflicts
|
||||||
|
if existingReverseProxy.Domain != reverseProxy.Domain {
|
||||||
|
conflictReverseProxy, err := transaction.GetReverseProxyByDomain(ctx, accountID, reverseProxy.Domain)
|
||||||
|
if err != nil {
|
||||||
|
if sErr, ok := status.FromError(err); !ok || sErr.Type() != status.NotFound {
|
||||||
|
return fmt.Errorf("failed to check existing reverse proxy: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if conflictReverseProxy != nil && conflictReverseProxy.ID != reverseProxy.ID {
|
||||||
|
return status.Errorf(status.AlreadyExists, "reverse proxy with domain %s already exists", reverseProxy.Domain)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = transaction.UpdateReverseProxy(ctx, reverseProxy); err != nil {
|
||||||
|
return fmt.Errorf("failed to update reverse proxy: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
m.accountManager.StoreEvent(ctx, userID, reverseProxy.ID, accountID, activity.ReverseProxyUpdated, reverseProxy.EventMeta())
|
||||||
|
|
||||||
|
return reverseProxy, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *managerImpl) DeleteReverseProxy(ctx context.Context, accountID, userID, reverseProxyID string) error {
|
||||||
|
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Services, operations.Delete)
|
||||||
|
if err != nil {
|
||||||
|
return status.NewPermissionValidationError(err)
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
return status.NewPermissionDeniedError()
|
||||||
|
}
|
||||||
|
|
||||||
|
var reverseProxy *reverseproxy.ReverseProxy
|
||||||
|
err = m.store.ExecuteInTransaction(ctx, func(transaction store.Store) error {
|
||||||
|
var err error
|
||||||
|
reverseProxy, err = transaction.GetReverseProxyByID(ctx, store.LockingStrengthUpdate, accountID, reverseProxyID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = transaction.DeleteReverseProxy(ctx, accountID, reverseProxyID); err != nil {
|
||||||
|
return fmt.Errorf("failed to delete reverse proxy: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
m.accountManager.StoreEvent(ctx, userID, reverseProxyID, accountID, activity.ReverseProxyDeleted, reverseProxy.EventMeta())
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
196
management/internals/modules/reverseproxy/reverseproxy.go
Normal file
196
management/internals/modules/reverseproxy/reverseproxy.go
Normal file
@@ -0,0 +1,196 @@
|
|||||||
|
package reverseproxy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/rs/xid"
|
||||||
|
|
||||||
|
"github.com/netbirdio/netbird/shared/management/http/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Target struct {
|
||||||
|
Path *string `json:"path,omitempty"`
|
||||||
|
Host string `json:"host"`
|
||||||
|
Port int `json:"port"`
|
||||||
|
Protocol string `json:"protocol"`
|
||||||
|
TargetId string `json:"target_id"`
|
||||||
|
TargetType string `json:"target_type"`
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PasswordAuthConfig struct {
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PINAuthConfig struct {
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
|
Pin string `json:"pin"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type BearerAuthConfig struct {
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
|
DistributionGroups []string `json:"distribution_groups,omitempty" gorm:"serializer:json"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type LinkAuthConfig struct {
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AuthConfig struct {
|
||||||
|
PasswordAuth *PasswordAuthConfig `json:"password_auth,omitempty" gorm:"serializer:json"`
|
||||||
|
PinAuth *PINAuthConfig `json:"pin_auth,omitempty" gorm:"serializer:json"`
|
||||||
|
BearerAuth *BearerAuthConfig `json:"bearer_auth,omitempty" gorm:"serializer:json"`
|
||||||
|
LinkAuth *LinkAuthConfig `json:"link_auth,omitempty" gorm:"serializer:json"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ReverseProxy struct {
|
||||||
|
ID string `gorm:"primaryKey"`
|
||||||
|
AccountID string `gorm:"index"`
|
||||||
|
Name string
|
||||||
|
Domain string `gorm:"index"`
|
||||||
|
Targets []Target `gorm:"serializer:json"`
|
||||||
|
Enabled bool
|
||||||
|
Auth AuthConfig `gorm:"serializer:json"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewReverseProxy(accountID, name, domain string, targets []Target, enabled bool) *ReverseProxy {
|
||||||
|
return &ReverseProxy{
|
||||||
|
ID: xid.New().String(),
|
||||||
|
AccountID: accountID,
|
||||||
|
Name: name,
|
||||||
|
Domain: domain,
|
||||||
|
Targets: targets,
|
||||||
|
Enabled: enabled,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ReverseProxy) ToAPIResponse() *api.ReverseProxy {
|
||||||
|
authConfig := api.ReverseProxyAuthConfig{}
|
||||||
|
|
||||||
|
if r.Auth.PasswordAuth != nil {
|
||||||
|
authConfig.PasswordAuth = &api.PasswordAuthConfig{
|
||||||
|
Enabled: r.Auth.PasswordAuth.Enabled,
|
||||||
|
Password: r.Auth.PasswordAuth.Password,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.Auth.PinAuth != nil {
|
||||||
|
authConfig.PinAuth = &api.PINAuthConfig{
|
||||||
|
Enabled: r.Auth.PinAuth.Enabled,
|
||||||
|
Pin: r.Auth.PinAuth.Pin,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.Auth.BearerAuth != nil {
|
||||||
|
authConfig.BearerAuth = &api.BearerAuthConfig{
|
||||||
|
Enabled: r.Auth.BearerAuth.Enabled,
|
||||||
|
DistributionGroups: &r.Auth.BearerAuth.DistributionGroups,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.Auth.LinkAuth != nil {
|
||||||
|
authConfig.LinkAuth = &api.LinkAuthConfig{
|
||||||
|
Enabled: r.Auth.LinkAuth.Enabled,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert internal targets to API targets
|
||||||
|
apiTargets := make([]api.ReverseProxyTarget, 0, len(r.Targets))
|
||||||
|
for _, target := range r.Targets {
|
||||||
|
apiTargets = append(apiTargets, api.ReverseProxyTarget{
|
||||||
|
Path: target.Path,
|
||||||
|
Host: target.Host,
|
||||||
|
Port: target.Port,
|
||||||
|
Protocol: api.ReverseProxyTargetProtocol(target.Protocol),
|
||||||
|
TargetId: target.TargetId,
|
||||||
|
TargetType: api.ReverseProxyTargetTargetType(target.TargetType),
|
||||||
|
Enabled: target.Enabled,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return &api.ReverseProxy{
|
||||||
|
Id: r.ID,
|
||||||
|
Name: r.Name,
|
||||||
|
Domain: r.Domain,
|
||||||
|
Targets: apiTargets,
|
||||||
|
Enabled: r.Enabled,
|
||||||
|
Auth: authConfig,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ReverseProxy) FromAPIRequest(req *api.ReverseProxyRequest) {
|
||||||
|
r.Name = req.Name
|
||||||
|
r.Domain = req.Domain
|
||||||
|
|
||||||
|
// Convert API targets to internal targets
|
||||||
|
targets := make([]Target, 0, len(req.Targets))
|
||||||
|
for _, apiTarget := range req.Targets {
|
||||||
|
targets = append(targets, Target{
|
||||||
|
Path: apiTarget.Path,
|
||||||
|
Host: apiTarget.Host,
|
||||||
|
Port: apiTarget.Port,
|
||||||
|
Protocol: string(apiTarget.Protocol),
|
||||||
|
TargetId: apiTarget.TargetId,
|
||||||
|
TargetType: string(apiTarget.TargetType),
|
||||||
|
Enabled: apiTarget.Enabled,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
r.Targets = targets
|
||||||
|
|
||||||
|
r.Enabled = req.Enabled
|
||||||
|
|
||||||
|
if req.Auth.PasswordAuth != nil {
|
||||||
|
r.Auth.PasswordAuth = &PasswordAuthConfig{
|
||||||
|
Enabled: req.Auth.PasswordAuth.Enabled,
|
||||||
|
Password: req.Auth.PasswordAuth.Password,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Auth.PinAuth != nil {
|
||||||
|
r.Auth.PinAuth = &PINAuthConfig{
|
||||||
|
Enabled: req.Auth.PinAuth.Enabled,
|
||||||
|
Pin: req.Auth.PinAuth.Pin,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Auth.BearerAuth != nil {
|
||||||
|
bearerAuth := &BearerAuthConfig{
|
||||||
|
Enabled: req.Auth.BearerAuth.Enabled,
|
||||||
|
}
|
||||||
|
if req.Auth.BearerAuth.DistributionGroups != nil {
|
||||||
|
bearerAuth.DistributionGroups = *req.Auth.BearerAuth.DistributionGroups
|
||||||
|
}
|
||||||
|
r.Auth.BearerAuth = bearerAuth
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Auth.LinkAuth != nil {
|
||||||
|
r.Auth.LinkAuth = &LinkAuthConfig{
|
||||||
|
Enabled: req.Auth.LinkAuth.Enabled,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ReverseProxy) Validate() error {
|
||||||
|
if r.Name == "" {
|
||||||
|
return errors.New("reverse proxy name is required")
|
||||||
|
}
|
||||||
|
if len(r.Name) > 255 {
|
||||||
|
return errors.New("reverse proxy name exceeds maximum length of 255 characters")
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.Domain == "" {
|
||||||
|
return errors.New("reverse proxy domain is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(r.Targets) == 0 {
|
||||||
|
return errors.New("at least one target is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ReverseProxy) EventMeta() map[string]any {
|
||||||
|
return map[string]any{"name": r.Name, "domain": r.Domain}
|
||||||
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
package services
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Manager interface {
|
|
||||||
GetAllServices(ctx context.Context, accountID, userID string) ([]*Service, error)
|
|
||||||
GetService(ctx context.Context, accountID, userID, serviceID string) (*Service, error)
|
|
||||||
CreateService(ctx context.Context, accountID, userID string, service *Service) (*Service, error)
|
|
||||||
UpdateService(ctx context.Context, accountID, userID string, service *Service) (*Service, error)
|
|
||||||
DeleteService(ctx context.Context, accountID, userID, serviceID string) error
|
|
||||||
}
|
|
||||||
@@ -1,161 +0,0 @@
|
|||||||
package manager
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/management/internals/modules/services"
|
|
||||||
nbcontext "github.com/netbirdio/netbird/management/server/context"
|
|
||||||
"github.com/netbirdio/netbird/shared/management/http/api"
|
|
||||||
"github.com/netbirdio/netbird/shared/management/http/util"
|
|
||||||
"github.com/netbirdio/netbird/shared/management/status"
|
|
||||||
)
|
|
||||||
|
|
||||||
type handler struct {
|
|
||||||
manager services.Manager
|
|
||||||
}
|
|
||||||
|
|
||||||
func RegisterEndpoints(router *mux.Router, manager services.Manager) {
|
|
||||||
h := &handler{
|
|
||||||
manager: manager,
|
|
||||||
}
|
|
||||||
|
|
||||||
router.HandleFunc("/services", h.getAllServices).Methods("GET", "OPTIONS")
|
|
||||||
router.HandleFunc("/services", h.createService).Methods("POST", "OPTIONS")
|
|
||||||
router.HandleFunc("/services/{serviceId}", h.getService).Methods("GET", "OPTIONS")
|
|
||||||
router.HandleFunc("/services/{serviceId}", h.updateService).Methods("PUT", "OPTIONS")
|
|
||||||
router.HandleFunc("/services/{serviceId}", h.deleteService).Methods("DELETE", "OPTIONS")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *handler) getAllServices(w http.ResponseWriter, r *http.Request) {
|
|
||||||
userAuth, err := nbcontext.GetUserAuthFromContext(r.Context())
|
|
||||||
if err != nil {
|
|
||||||
util.WriteError(r.Context(), err, w)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
allServices, err := h.manager.GetAllServices(r.Context(), userAuth.AccountId, userAuth.UserId)
|
|
||||||
if err != nil {
|
|
||||||
util.WriteError(r.Context(), err, w)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
apiServices := make([]*api.Service, 0, len(allServices))
|
|
||||||
for _, service := range allServices {
|
|
||||||
apiServices = append(apiServices, service.ToAPIResponse())
|
|
||||||
}
|
|
||||||
|
|
||||||
util.WriteJSONObject(r.Context(), w, apiServices)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *handler) createService(w http.ResponseWriter, r *http.Request) {
|
|
||||||
userAuth, err := nbcontext.GetUserAuthFromContext(r.Context())
|
|
||||||
if err != nil {
|
|
||||||
util.WriteError(r.Context(), err, w)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var req api.PostApiServicesJSONRequestBody
|
|
||||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
||||||
util.WriteErrorResponse("couldn't parse JSON request", http.StatusBadRequest, w)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
service := new(services.Service)
|
|
||||||
service.FromAPIRequest(&req)
|
|
||||||
|
|
||||||
if err = service.Validate(); err != nil {
|
|
||||||
util.WriteError(r.Context(), status.Errorf(status.InvalidArgument, "%s", err.Error()), w)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
createdService, err := h.manager.CreateService(r.Context(), userAuth.AccountId, userAuth.UserId, service)
|
|
||||||
if err != nil {
|
|
||||||
util.WriteError(r.Context(), err, w)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
util.WriteJSONObject(r.Context(), w, createdService.ToAPIResponse())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *handler) getService(w http.ResponseWriter, r *http.Request) {
|
|
||||||
userAuth, err := nbcontext.GetUserAuthFromContext(r.Context())
|
|
||||||
if err != nil {
|
|
||||||
util.WriteError(r.Context(), err, w)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
serviceID := mux.Vars(r)["serviceId"]
|
|
||||||
if serviceID == "" {
|
|
||||||
util.WriteError(r.Context(), status.Errorf(status.InvalidArgument, "service ID is required"), w)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
service, err := h.manager.GetService(r.Context(), userAuth.AccountId, userAuth.UserId, serviceID)
|
|
||||||
if err != nil {
|
|
||||||
util.WriteError(r.Context(), err, w)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
util.WriteJSONObject(r.Context(), w, service.ToAPIResponse())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *handler) updateService(w http.ResponseWriter, r *http.Request) {
|
|
||||||
userAuth, err := nbcontext.GetUserAuthFromContext(r.Context())
|
|
||||||
if err != nil {
|
|
||||||
util.WriteError(r.Context(), err, w)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
serviceID := mux.Vars(r)["serviceId"]
|
|
||||||
if serviceID == "" {
|
|
||||||
util.WriteError(r.Context(), status.Errorf(status.InvalidArgument, "service ID is required"), w)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var req api.PutApiServicesServiceIdJSONRequestBody
|
|
||||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
||||||
util.WriteErrorResponse("couldn't parse JSON request", http.StatusBadRequest, w)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
service := new(services.Service)
|
|
||||||
service.ID = serviceID
|
|
||||||
service.FromAPIRequest(&req)
|
|
||||||
|
|
||||||
if err = service.Validate(); err != nil {
|
|
||||||
util.WriteError(r.Context(), status.Errorf(status.InvalidArgument, "%s", err.Error()), w)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
updatedService, err := h.manager.UpdateService(r.Context(), userAuth.AccountId, userAuth.UserId, service)
|
|
||||||
if err != nil {
|
|
||||||
util.WriteError(r.Context(), err, w)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
util.WriteJSONObject(r.Context(), w, updatedService.ToAPIResponse())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *handler) deleteService(w http.ResponseWriter, r *http.Request) {
|
|
||||||
userAuth, err := nbcontext.GetUserAuthFromContext(r.Context())
|
|
||||||
if err != nil {
|
|
||||||
util.WriteError(r.Context(), err, w)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
serviceID := mux.Vars(r)["serviceId"]
|
|
||||||
if serviceID == "" {
|
|
||||||
util.WriteError(r.Context(), status.Errorf(status.InvalidArgument, "service ID is required"), w)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := h.manager.DeleteService(r.Context(), userAuth.AccountId, userAuth.UserId, serviceID); err != nil {
|
|
||||||
util.WriteError(r.Context(), err, w)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
util.WriteJSONObject(r.Context(), w, util.EmptyObject{})
|
|
||||||
}
|
|
||||||
@@ -1,199 +0,0 @@
|
|||||||
package manager
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/management/internals/modules/services"
|
|
||||||
"github.com/netbirdio/netbird/management/server/account"
|
|
||||||
"github.com/netbirdio/netbird/management/server/activity"
|
|
||||||
"github.com/netbirdio/netbird/management/server/permissions"
|
|
||||||
"github.com/netbirdio/netbird/management/server/permissions/modules"
|
|
||||||
"github.com/netbirdio/netbird/management/server/permissions/operations"
|
|
||||||
"github.com/netbirdio/netbird/management/server/store"
|
|
||||||
"github.com/netbirdio/netbird/shared/management/status"
|
|
||||||
)
|
|
||||||
|
|
||||||
type managerImpl struct {
|
|
||||||
store store.Store
|
|
||||||
accountManager account.Manager
|
|
||||||
permissionsManager permissions.Manager
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewManager(store store.Store, accountManager account.Manager, permissionsManager permissions.Manager) services.Manager {
|
|
||||||
return &managerImpl{
|
|
||||||
store: store,
|
|
||||||
accountManager: accountManager,
|
|
||||||
permissionsManager: permissionsManager,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *managerImpl) GetAllServices(ctx context.Context, accountID, userID string) ([]*services.Service, error) {
|
|
||||||
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Services, operations.Read)
|
|
||||||
if err != nil {
|
|
||||||
return nil, status.NewPermissionValidationError(err)
|
|
||||||
}
|
|
||||||
if !ok {
|
|
||||||
return nil, status.NewPermissionDeniedError()
|
|
||||||
}
|
|
||||||
|
|
||||||
return m.store.GetAccountServices(ctx, store.LockingStrengthNone, accountID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *managerImpl) GetService(ctx context.Context, accountID, userID, serviceID string) (*services.Service, error) {
|
|
||||||
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Services, operations.Read)
|
|
||||||
if err != nil {
|
|
||||||
return nil, status.NewPermissionValidationError(err)
|
|
||||||
}
|
|
||||||
if !ok {
|
|
||||||
return nil, status.NewPermissionDeniedError()
|
|
||||||
}
|
|
||||||
|
|
||||||
return m.store.GetServiceByID(ctx, store.LockingStrengthNone, accountID, serviceID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *managerImpl) CreateService(ctx context.Context, accountID, userID string, service *services.Service) (*services.Service, error) {
|
|
||||||
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Services, operations.Create)
|
|
||||||
if err != nil {
|
|
||||||
return nil, status.NewPermissionValidationError(err)
|
|
||||||
}
|
|
||||||
if !ok {
|
|
||||||
return nil, status.NewPermissionDeniedError()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store auth config before creating new service
|
|
||||||
authType := service.AuthType
|
|
||||||
authBasicUsername := service.AuthBasicUsername
|
|
||||||
authBasicPassword := service.AuthBasicPassword
|
|
||||||
authPINValue := service.AuthPINValue
|
|
||||||
authPINHeader := service.AuthPINHeader
|
|
||||||
authBearerEnabled := service.AuthBearerEnabled
|
|
||||||
|
|
||||||
service = services.NewService(accountID, service.Name, service.Description, service.Domain, service.Targets, service.DistributionGroups, service.Enabled, service.Exposed)
|
|
||||||
|
|
||||||
// Restore auth config
|
|
||||||
service.AuthType = authType
|
|
||||||
service.AuthBasicUsername = authBasicUsername
|
|
||||||
service.AuthBasicPassword = authBasicPassword
|
|
||||||
service.AuthPINValue = authPINValue
|
|
||||||
service.AuthPINHeader = authPINHeader
|
|
||||||
service.AuthBearerEnabled = authBearerEnabled
|
|
||||||
|
|
||||||
err = m.store.ExecuteInTransaction(ctx, func(transaction store.Store) error {
|
|
||||||
// Check for duplicate domain
|
|
||||||
existingService, err := transaction.GetServiceByDomain(ctx, accountID, service.Domain)
|
|
||||||
if err != nil {
|
|
||||||
if sErr, ok := status.FromError(err); !ok || sErr.Type() != status.NotFound {
|
|
||||||
return fmt.Errorf("failed to check existing service: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if existingService != nil {
|
|
||||||
return status.Errorf(status.AlreadyExists, "service with domain %s already exists", service.Domain)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate distribution groups exist
|
|
||||||
for _, groupID := range service.DistributionGroups {
|
|
||||||
_, err = transaction.GetGroupByID(ctx, store.LockingStrengthNone, accountID, groupID)
|
|
||||||
if err != nil {
|
|
||||||
return status.Errorf(status.InvalidArgument, "%s", err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = transaction.CreateService(ctx, service); err != nil {
|
|
||||||
return fmt.Errorf("failed to create service: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
m.accountManager.StoreEvent(ctx, userID, service.ID, accountID, activity.ServiceCreated, service.EventMeta())
|
|
||||||
|
|
||||||
return service, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *managerImpl) UpdateService(ctx context.Context, accountID, userID string, service *services.Service) (*services.Service, error) {
|
|
||||||
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Services, operations.Update)
|
|
||||||
if err != nil {
|
|
||||||
return nil, status.NewPermissionValidationError(err)
|
|
||||||
}
|
|
||||||
if !ok {
|
|
||||||
return nil, status.NewPermissionDeniedError()
|
|
||||||
}
|
|
||||||
|
|
||||||
err = m.store.ExecuteInTransaction(ctx, func(transaction store.Store) error {
|
|
||||||
// Get existing service
|
|
||||||
existingService, err := transaction.GetServiceByID(ctx, store.LockingStrengthUpdate, accountID, service.ID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if domain changed and if it conflicts
|
|
||||||
if existingService.Domain != service.Domain {
|
|
||||||
conflictService, err := transaction.GetServiceByDomain(ctx, accountID, service.Domain)
|
|
||||||
if err != nil {
|
|
||||||
if sErr, ok := status.FromError(err); !ok || sErr.Type() != status.NotFound {
|
|
||||||
return fmt.Errorf("failed to check existing service: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if conflictService != nil && conflictService.ID != service.ID {
|
|
||||||
return status.Errorf(status.AlreadyExists, "service with domain %s already exists", service.Domain)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate distribution groups exist
|
|
||||||
for _, groupID := range service.DistributionGroups {
|
|
||||||
_, err = transaction.GetGroupByID(ctx, store.LockingStrengthNone, accountID, groupID)
|
|
||||||
if err != nil {
|
|
||||||
return status.Errorf(status.InvalidArgument, "%s", err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = transaction.UpdateService(ctx, service); err != nil {
|
|
||||||
return fmt.Errorf("failed to update service: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
m.accountManager.StoreEvent(ctx, userID, service.ID, accountID, activity.ServiceUpdated, service.EventMeta())
|
|
||||||
|
|
||||||
return service, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *managerImpl) DeleteService(ctx context.Context, accountID, userID, serviceID string) error {
|
|
||||||
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Services, operations.Delete)
|
|
||||||
if err != nil {
|
|
||||||
return status.NewPermissionValidationError(err)
|
|
||||||
}
|
|
||||||
if !ok {
|
|
||||||
return status.NewPermissionDeniedError()
|
|
||||||
}
|
|
||||||
|
|
||||||
var service *services.Service
|
|
||||||
err = m.store.ExecuteInTransaction(ctx, func(transaction store.Store) error {
|
|
||||||
var err error
|
|
||||||
service, err = transaction.GetServiceByID(ctx, store.LockingStrengthUpdate, accountID, serviceID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = transaction.DeleteService(ctx, accountID, serviceID); err != nil {
|
|
||||||
return fmt.Errorf("failed to delete service: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
m.accountManager.StoreEvent(ctx, userID, serviceID, accountID, activity.ServiceDeleted, service.EventMeta())
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -1,184 +0,0 @@
|
|||||||
package services
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
|
|
||||||
"github.com/rs/xid"
|
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/shared/management/http/api"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Target struct {
|
|
||||||
Path string `json:"path"`
|
|
||||||
Host string `json:"host"`
|
|
||||||
Enabled bool `json:"enabled"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Service struct {
|
|
||||||
ID string `gorm:"primaryKey"`
|
|
||||||
AccountID string `gorm:"index"`
|
|
||||||
Name string
|
|
||||||
Description string
|
|
||||||
Domain string `gorm:"index"`
|
|
||||||
Targets []Target `gorm:"serializer:json"`
|
|
||||||
DistributionGroups []string `gorm:"serializer:json"`
|
|
||||||
Enabled bool
|
|
||||||
Exposed bool
|
|
||||||
|
|
||||||
// Authentication configuration
|
|
||||||
AuthType string
|
|
||||||
AuthBasicUsername string
|
|
||||||
AuthBasicPassword string
|
|
||||||
AuthPINValue string
|
|
||||||
AuthPINHeader string
|
|
||||||
AuthBearerEnabled bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewService(accountID, name, description, domain string, targets []Target, distributionGroups []string, enabled, exposed bool) *Service {
|
|
||||||
return &Service{
|
|
||||||
ID: xid.New().String(),
|
|
||||||
AccountID: accountID,
|
|
||||||
Name: name,
|
|
||||||
Description: description,
|
|
||||||
Domain: domain,
|
|
||||||
Targets: targets,
|
|
||||||
DistributionGroups: distributionGroups,
|
|
||||||
Enabled: enabled,
|
|
||||||
Exposed: exposed,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) ToAPIResponse() *api.Service {
|
|
||||||
var authConfig *api.ServiceAuthConfig
|
|
||||||
|
|
||||||
switch s.AuthType {
|
|
||||||
case "basic":
|
|
||||||
authConfig = &api.ServiceAuthConfig{
|
|
||||||
Type: "basic",
|
|
||||||
BasicAuth: &api.BasicAuthConfig{
|
|
||||||
Username: s.AuthBasicUsername,
|
|
||||||
Password: s.AuthBasicPassword,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
case "pin":
|
|
||||||
authConfig = &api.ServiceAuthConfig{
|
|
||||||
Type: "pin",
|
|
||||||
PinAuth: &api.PINAuthConfig{
|
|
||||||
Pin: s.AuthPINValue,
|
|
||||||
Header: s.AuthPINHeader,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
case "bearer":
|
|
||||||
authConfig = &api.ServiceAuthConfig{
|
|
||||||
Type: "bearer",
|
|
||||||
BearerAuth: &api.BearerAuthConfig{
|
|
||||||
Enabled: s.AuthBearerEnabled,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert internal targets to API targets
|
|
||||||
apiTargets := make([]api.ServiceTarget, 0, len(s.Targets))
|
|
||||||
for _, target := range s.Targets {
|
|
||||||
apiTargets = append(apiTargets, api.ServiceTarget{
|
|
||||||
Path: target.Path,
|
|
||||||
Host: target.Host,
|
|
||||||
Enabled: target.Enabled,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return &api.Service{
|
|
||||||
Id: s.ID,
|
|
||||||
Name: s.Name,
|
|
||||||
Description: &s.Description,
|
|
||||||
Domain: s.Domain,
|
|
||||||
Targets: apiTargets,
|
|
||||||
DistributionGroups: s.DistributionGroups,
|
|
||||||
Enabled: s.Enabled,
|
|
||||||
Exposed: s.Exposed,
|
|
||||||
Auth: authConfig,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) FromAPIRequest(req *api.ServiceRequest) {
|
|
||||||
s.Name = req.Name
|
|
||||||
s.Domain = req.Domain
|
|
||||||
|
|
||||||
// Convert API targets to internal targets
|
|
||||||
targets := make([]Target, 0, len(req.Targets))
|
|
||||||
for _, apiTarget := range req.Targets {
|
|
||||||
targets = append(targets, Target{
|
|
||||||
Path: apiTarget.Path,
|
|
||||||
Host: apiTarget.Host,
|
|
||||||
Enabled: apiTarget.Enabled,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
s.Targets = targets
|
|
||||||
|
|
||||||
s.DistributionGroups = req.DistributionGroups
|
|
||||||
|
|
||||||
if req.Description != nil {
|
|
||||||
s.Description = *req.Description
|
|
||||||
}
|
|
||||||
|
|
||||||
enabled := true
|
|
||||||
if req.Enabled != nil {
|
|
||||||
enabled = *req.Enabled
|
|
||||||
}
|
|
||||||
s.Enabled = enabled
|
|
||||||
|
|
||||||
exposed := false
|
|
||||||
if req.Exposed != nil {
|
|
||||||
exposed = *req.Exposed
|
|
||||||
}
|
|
||||||
s.Exposed = exposed
|
|
||||||
|
|
||||||
// Handle auth config
|
|
||||||
if req.Auth != nil {
|
|
||||||
s.AuthType = string(req.Auth.Type)
|
|
||||||
|
|
||||||
switch req.Auth.Type {
|
|
||||||
case "basic":
|
|
||||||
if req.Auth.BasicAuth != nil {
|
|
||||||
s.AuthBasicUsername = req.Auth.BasicAuth.Username
|
|
||||||
s.AuthBasicPassword = req.Auth.BasicAuth.Password
|
|
||||||
}
|
|
||||||
case "pin":
|
|
||||||
if req.Auth.PinAuth != nil {
|
|
||||||
s.AuthPINValue = req.Auth.PinAuth.Pin
|
|
||||||
s.AuthPINHeader = req.Auth.PinAuth.Header
|
|
||||||
}
|
|
||||||
case "bearer":
|
|
||||||
if req.Auth.BearerAuth != nil {
|
|
||||||
s.AuthBearerEnabled = req.Auth.BearerAuth.Enabled
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) Validate() error {
|
|
||||||
if s.Name == "" {
|
|
||||||
return errors.New("service name is required")
|
|
||||||
}
|
|
||||||
if len(s.Name) > 255 {
|
|
||||||
return errors.New("service name exceeds maximum length of 255 characters")
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.Domain == "" {
|
|
||||||
return errors.New("service domain is required")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(s.Targets) == 0 {
|
|
||||||
return errors.New("at least one target is required")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(s.DistributionGroups) == 0 {
|
|
||||||
return errors.New("at least one distribution group is required")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) EventMeta() map[string]any {
|
|
||||||
return map[string]any{"name": s.Name, "domain": s.Domain}
|
|
||||||
}
|
|
||||||
@@ -92,7 +92,7 @@ func (s *BaseServer) EventStore() activity.Store {
|
|||||||
|
|
||||||
func (s *BaseServer) APIHandler() http.Handler {
|
func (s *BaseServer) APIHandler() http.Handler {
|
||||||
return Create(s, func() http.Handler {
|
return Create(s, func() http.Handler {
|
||||||
httpAPIHandler, err := nbhttp.NewAPIHandler(context.Background(), s.AccountManager(), s.NetworksManager(), s.ResourcesManager(), s.RoutesManager(), s.GroupsManager(), s.GeoLocationManager(), s.AuthManager(), s.Metrics(), s.IntegratedValidator(), s.ProxyController(), s.PermissionsManager(), s.PeersManager(), s.SettingsManager(), s.ZonesManager(), s.RecordsManager(), s.NetworkMapController(), s.IdpManager(), s.ServiceManager())
|
httpAPIHandler, err := nbhttp.NewAPIHandler(context.Background(), s.AccountManager(), s.NetworksManager(), s.ResourcesManager(), s.RoutesManager(), s.GroupsManager(), s.GeoLocationManager(), s.AuthManager(), s.Metrics(), s.IntegratedValidator(), s.ProxyController(), s.PermissionsManager(), s.PeersManager(), s.SettingsManager(), s.ZonesManager(), s.RecordsManager(), s.NetworkMapController(), s.IdpManager(), s.ReverseProxyManager())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("failed to create API handler: %v", err)
|
log.Fatalf("failed to create API handler: %v", err)
|
||||||
}
|
}
|
||||||
@@ -150,7 +150,7 @@ func (s *BaseServer) GRPCServer() *grpc.Server {
|
|||||||
}
|
}
|
||||||
mgmtProto.RegisterManagementServiceServer(gRPCAPIHandler, srv)
|
mgmtProto.RegisterManagementServiceServer(gRPCAPIHandler, srv)
|
||||||
|
|
||||||
proxyService := nbgrpc.NewProxyServiceServer(s.Store(), s.AccountManager())
|
proxyService := nbgrpc.NewProxyServiceServer(s.Store())
|
||||||
mgmtProto.RegisterProxyServiceServer(gRPCAPIHandler, proxyService)
|
mgmtProto.RegisterProxyServiceServer(gRPCAPIHandler, proxyService)
|
||||||
log.Info("ProxyService registered on gRPC server")
|
log.Info("ProxyService registered on gRPC server")
|
||||||
|
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import (
|
|||||||
|
|
||||||
"github.com/netbirdio/management-integrations/integrations"
|
"github.com/netbirdio/management-integrations/integrations"
|
||||||
"github.com/netbirdio/netbird/management/internals/modules/peers"
|
"github.com/netbirdio/netbird/management/internals/modules/peers"
|
||||||
"github.com/netbirdio/netbird/management/internals/modules/services"
|
"github.com/netbirdio/netbird/management/internals/modules/reverseproxy"
|
||||||
nbservices "github.com/netbirdio/netbird/management/internals/modules/services/manager"
|
nbreverseproxy "github.com/netbirdio/netbird/management/internals/modules/reverseproxy/manager"
|
||||||
"github.com/netbirdio/netbird/management/internals/modules/zones"
|
"github.com/netbirdio/netbird/management/internals/modules/zones"
|
||||||
zonesManager "github.com/netbirdio/netbird/management/internals/modules/zones/manager"
|
zonesManager "github.com/netbirdio/netbird/management/internals/modules/zones/manager"
|
||||||
"github.com/netbirdio/netbird/management/internals/modules/zones/records"
|
"github.com/netbirdio/netbird/management/internals/modules/zones/records"
|
||||||
@@ -177,8 +177,8 @@ func (s *BaseServer) RecordsManager() records.Manager {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *BaseServer) ServiceManager() services.Manager {
|
func (s *BaseServer) ReverseProxyManager() reverseproxy.Manager {
|
||||||
return Create(s, func() services.Manager {
|
return Create(s, func() reverseproxy.Manager {
|
||||||
return nbservices.NewManager(s.Store(), s.AccountManager(), s.PermissionsManager())
|
return nbreverseproxy.NewManager(s.Store(), s.AccountManager(), s.PermissionsManager())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,18 +6,19 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/management/internals/modules/services"
|
|
||||||
"github.com/netbirdio/netbird/management/server/store"
|
|
||||||
"github.com/netbirdio/netbird/management/server/types"
|
|
||||||
"github.com/netbirdio/netbird/shared/management/proto"
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
"google.golang.org/grpc/peer"
|
"google.golang.org/grpc/peer"
|
||||||
"google.golang.org/grpc/status"
|
"google.golang.org/grpc/status"
|
||||||
|
|
||||||
|
"github.com/netbirdio/netbird/management/internals/modules/reverseproxy"
|
||||||
|
"github.com/netbirdio/netbird/management/server/store"
|
||||||
|
"github.com/netbirdio/netbird/management/server/types"
|
||||||
|
"github.com/netbirdio/netbird/shared/management/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
type serviceStore interface {
|
type reverseProxyStore interface {
|
||||||
GetAccountServices(ctx context.Context, lockStrength store.LockingStrength, accountID string) ([]*services.Service, error)
|
GetAccountReverseProxies(ctx context.Context, lockStrength store.LockingStrength, accountID string) ([]*reverseproxy.ReverseProxy, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type keyStore interface {
|
type keyStore interface {
|
||||||
@@ -31,11 +32,11 @@ type ProxyServiceServer struct {
|
|||||||
// Map of connected proxies: proxy_id -> proxy connection
|
// Map of connected proxies: proxy_id -> proxy connection
|
||||||
connectedProxies sync.Map
|
connectedProxies sync.Map
|
||||||
|
|
||||||
// Channel for broadcasting service updates to all proxies
|
// Channel for broadcasting reverse proxy updates to all proxies
|
||||||
updatesChan chan *proto.ProxyMapping
|
updatesChan chan *proto.ProxyMapping
|
||||||
|
|
||||||
// Store of services
|
// Store of reverse proxies
|
||||||
serviceStore serviceStore
|
reverseProxyStore reverseProxyStore
|
||||||
|
|
||||||
// Store for client setup keys
|
// Store for client setup keys
|
||||||
keyStore keyStore
|
keyStore keyStore
|
||||||
@@ -52,10 +53,10 @@ type proxyConnection struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewProxyServiceServer creates a new proxy service server
|
// NewProxyServiceServer creates a new proxy service server
|
||||||
func NewProxyServiceServer(store serviceStore) *ProxyServiceServer {
|
func NewProxyServiceServer(store reverseProxyStore) *ProxyServiceServer {
|
||||||
return &ProxyServiceServer{
|
return &ProxyServiceServer{
|
||||||
updatesChan: make(chan *proto.ProxyMapping, 100),
|
updatesChan: make(chan *proto.ProxyMapping, 100),
|
||||||
serviceStore: store,
|
reverseProxyStore: store,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,51 +111,51 @@ func (s *ProxyServiceServer) GetMappingUpdate(req *proto.GetMappingUpdateRequest
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// sendSnapshot sends the initial snapshot of all services to proxy
|
// sendSnapshot sends the initial snapshot of all reverse proxies to proxy
|
||||||
func (s *ProxyServiceServer) sendSnapshot(ctx context.Context, conn *proxyConnection) error {
|
func (s *ProxyServiceServer) sendSnapshot(ctx context.Context, conn *proxyConnection) error {
|
||||||
svcs, err := s.serviceStore.GetAccountServices(ctx, store.LockingStrengthNone, conn.proxyID) // TODO: check locking strength and accountID.
|
reverseProxies, err := s.reverseProxyStore.GetAccountReverseProxies(ctx, store.LockingStrengthNone, conn.proxyID) // TODO: check locking strength and accountID.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// TODO: something
|
// TODO: something
|
||||||
return fmt.Errorf("get account services from store: %w", err)
|
return fmt.Errorf("get account reverse proxies from store: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, svc := range svcs {
|
for _, rp := range reverseProxies {
|
||||||
if !svc.Enabled || !svc.Exposed {
|
if !rp.Enabled {
|
||||||
// We don't care about disabled services for snapshots.
|
// We don't care about disabled reverse proxies for snapshots.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill auth values.
|
// Fill auth values.
|
||||||
// TODO: This will be removed soon as the management server should be handling authentication rather than the proxy, so probably not much use in fleshing this out too much.
|
// TODO: This will be removed soon as the management server should be handling authentication rather than the proxy, so probably not much use in fleshing this out too much.
|
||||||
auth := &proto.Authentication{}
|
auth := &proto.Authentication{}
|
||||||
if svc.AuthBearerEnabled {
|
if rp.Auth.BearerAuth != nil && rp.Auth.BearerAuth.Enabled {
|
||||||
auth.Oidc = &proto.OIDC{
|
auth.Oidc = &proto.OIDC{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
// TODO: fill other OIDC fields from account OIDC settings.
|
// TODO: fill other OIDC fields from account OIDC settings.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if svc.AuthBasicPassword != "" {
|
if rp.Auth.PasswordAuth != nil && rp.Auth.PasswordAuth.Password != "" {
|
||||||
auth.Basic = &proto.HTTPBasic{
|
auth.Basic = &proto.HTTPBasic{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
Username: svc.AuthBasicUsername,
|
Username: "",
|
||||||
Password: svc.AuthBasicPassword,
|
Password: rp.Auth.PasswordAuth.Password,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if svc.AuthPINValue != "" {
|
if rp.Auth.PinAuth != nil && rp.Auth.PinAuth.Pin != "" {
|
||||||
auth.Pin = &proto.Pin{
|
auth.Pin = &proto.Pin{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
Pin: svc.AuthPINValue,
|
Pin: rp.Auth.PinAuth.Pin,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var paths []*proto.PathMapping
|
var paths []*proto.PathMapping
|
||||||
for _, t := range svc.Targets {
|
for _, t := range rp.Targets {
|
||||||
if !t.Enabled {
|
if !t.Enabled {
|
||||||
// We don't care about disabled service targets for snapshots.
|
// We don't care about disabled reverse proxy targets for snapshots.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
paths = append(paths, &proto.PathMapping{
|
paths = append(paths, &proto.PathMapping{
|
||||||
Path: t.Path,
|
Path: *t.Path,
|
||||||
Target: t.Host,
|
Target: t.Host,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -179,8 +180,8 @@ func (s *ProxyServiceServer) sendSnapshot(ctx context.Context, conn *proxyConnec
|
|||||||
Mapping: []*proto.ProxyMapping{
|
Mapping: []*proto.ProxyMapping{
|
||||||
{
|
{
|
||||||
Type: proto.ProxyMappingUpdateType_UPDATE_TYPE_CREATED, // Initial snapshot, all records are "new" for the proxy.
|
Type: proto.ProxyMappingUpdateType_UPDATE_TYPE_CREATED, // Initial snapshot, all records are "new" for the proxy.
|
||||||
Id: svc.ID,
|
Id: rp.ID,
|
||||||
Domain: svc.Domain,
|
Domain: rp.Domain,
|
||||||
Path: paths,
|
Path: paths,
|
||||||
SetupKey: key.Key,
|
SetupKey: key.Key,
|
||||||
Auth: auth,
|
Auth: auth,
|
||||||
@@ -214,34 +215,34 @@ func (s *ProxyServiceServer) sender(conn *proxyConnection, errChan chan<- error)
|
|||||||
// SendAccessLog processes access log from proxy
|
// SendAccessLog processes access log from proxy
|
||||||
func (s *ProxyServiceServer) SendAccessLog(ctx context.Context, req *proto.SendAccessLogRequest) (*proto.SendAccessLogResponse, error) {
|
func (s *ProxyServiceServer) SendAccessLog(ctx context.Context, req *proto.SendAccessLogRequest) (*proto.SendAccessLogResponse, error) {
|
||||||
log.WithFields(log.Fields{
|
log.WithFields(log.Fields{
|
||||||
"proxy_id": "", // TODO: get proxy id, probably from context or maybe from request message.
|
"proxy_id": "", // TODO: get proxy id, probably from context or maybe from request message.
|
||||||
"service_id": req.GetLog().GetServiceId(),
|
"reverse_proxy_id": req.GetLog().GetServiceId(),
|
||||||
"host": req.GetLog().GetHost(),
|
"host": req.GetLog().GetHost(),
|
||||||
"path": req.GetLog().GetPath(),
|
"path": req.GetLog().GetPath(),
|
||||||
"method": req.GetLog().GetMethod(),
|
"method": req.GetLog().GetMethod(),
|
||||||
"response_code": req.GetLog().GetResponseCode(),
|
"response_code": req.GetLog().GetResponseCode(),
|
||||||
"duration_ms": req.GetLog().GetDurationMs(),
|
"duration_ms": req.GetLog().GetDurationMs(),
|
||||||
"source_ip": req.GetLog().GetSourceIp(),
|
"source_ip": req.GetLog().GetSourceIp(),
|
||||||
"auth_mechanism": req.GetLog().GetAuthMechanism(),
|
"auth_mechanism": req.GetLog().GetAuthMechanism(),
|
||||||
"user_id": req.GetLog().GetUserId(),
|
"user_id": req.GetLog().GetUserId(),
|
||||||
"auth_success": req.GetLog().GetAuthSuccess(),
|
"auth_success": req.GetLog().GetAuthSuccess(),
|
||||||
}).Info("Access log from proxy")
|
}).Info("Access log from proxy")
|
||||||
|
|
||||||
// TODO: Store access log in database/metrics system
|
// TODO: Store access log in database/metrics system
|
||||||
return &proto.SendAccessLogResponse{}, nil
|
return &proto.SendAccessLogResponse{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendServiceUpdate broadcasts a service update to all connected proxies.
|
// SendReverseProxyUpdate broadcasts a reverse proxy update to all connected proxies.
|
||||||
// Management should call this when services are created/updated/removed
|
// Management should call this when reverse proxies are created/updated/removed
|
||||||
func (s *ProxyServiceServer) SendServiceUpdate(update *proto.ProxyMapping) {
|
func (s *ProxyServiceServer) SendReverseProxyUpdate(update *proto.ProxyMapping) {
|
||||||
// Send it to all connected proxies
|
// Send it to all connected proxies
|
||||||
s.connectedProxies.Range(func(key, value interface{}) bool {
|
s.connectedProxies.Range(func(key, value interface{}) bool {
|
||||||
conn := value.(*proxyConnection)
|
conn := value.(*proxyConnection)
|
||||||
select {
|
select {
|
||||||
case conn.sendChan <- update:
|
case conn.sendChan <- update:
|
||||||
log.Debugf("Sent service update to proxy %s", conn.proxyID)
|
log.Debugf("Sent reverse proxy update to proxy %s", conn.proxyID)
|
||||||
default:
|
default:
|
||||||
log.Warnf("Failed to send service update to proxy %s (channel full)", conn.proxyID)
|
log.Warnf("Failed to send reverse proxy update to proxy %s (channel full)", conn.proxyID)
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -204,9 +204,9 @@ const (
|
|||||||
UserInviteLinkRegenerated Activity = 106
|
UserInviteLinkRegenerated Activity = 106
|
||||||
UserInviteLinkDeleted Activity = 107
|
UserInviteLinkDeleted Activity = 107
|
||||||
|
|
||||||
ServiceCreated Activity = 108
|
ReverseProxyCreated Activity = 108
|
||||||
ServiceUpdated Activity = 109
|
ReverseProxyUpdated Activity = 109
|
||||||
ServiceDeleted Activity = 110
|
ReverseProxyDeleted Activity = 110
|
||||||
|
|
||||||
AccountDeleted Activity = 99999
|
AccountDeleted Activity = 99999
|
||||||
)
|
)
|
||||||
@@ -342,9 +342,9 @@ var activityMap = map[Activity]Code{
|
|||||||
UserInviteLinkRegenerated: {"User invite link regenerated", "user.invite.link.regenerate"},
|
UserInviteLinkRegenerated: {"User invite link regenerated", "user.invite.link.regenerate"},
|
||||||
UserInviteLinkDeleted: {"User invite link deleted", "user.invite.link.delete"},
|
UserInviteLinkDeleted: {"User invite link deleted", "user.invite.link.delete"},
|
||||||
|
|
||||||
ServiceCreated: {"Service created", "service.create"},
|
ReverseProxyCreated: {"Reverse proxy created", "reverseproxy.create"},
|
||||||
ServiceUpdated: {"Service updated", "service.update"},
|
ReverseProxyUpdated: {"Reverse proxy updated", "reverseproxy.update"},
|
||||||
ServiceDeleted: {"Service deleted", "service.delete"},
|
ReverseProxyDeleted: {"Reverse proxy deleted", "reverseproxy.delete"},
|
||||||
}
|
}
|
||||||
|
|
||||||
// StringCode returns a string code of the activity
|
// StringCode returns a string code of the activity
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ import (
|
|||||||
"github.com/rs/cors"
|
"github.com/rs/cors"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
nbservices "github.com/netbirdio/netbird/management/internals/modules/services"
|
"github.com/netbirdio/netbird/management/internals/modules/reverseproxy"
|
||||||
services "github.com/netbirdio/netbird/management/internals/modules/services/manager"
|
reverseproxymanager "github.com/netbirdio/netbird/management/internals/modules/reverseproxy/manager"
|
||||||
idpmanager "github.com/netbirdio/netbird/management/server/idp"
|
idpmanager "github.com/netbirdio/netbird/management/server/idp"
|
||||||
|
|
||||||
"github.com/netbirdio/management-integrations/integrations"
|
"github.com/netbirdio/management-integrations/integrations"
|
||||||
@@ -62,7 +62,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// NewAPIHandler creates the Management service HTTP API handler registering all the available endpoints.
|
// NewAPIHandler creates the Management service HTTP API handler registering all the available endpoints.
|
||||||
func NewAPIHandler(ctx context.Context, accountManager account.Manager, networksManager nbnetworks.Manager, resourceManager resources.Manager, routerManager routers.Manager, groupsManager nbgroups.Manager, LocationManager geolocation.Geolocation, authManager auth.Manager, appMetrics telemetry.AppMetrics, integratedValidator integrated_validator.IntegratedValidator, proxyController port_forwarding.Controller, permissionsManager permissions.Manager, peersManager nbpeers.Manager, settingsManager settings.Manager, zManager zones.Manager, rManager records.Manager, networkMapController network_map.Controller, idpManager idpmanager.Manager, serviceManager nbservices.Manager) (http.Handler, error) {
|
func NewAPIHandler(ctx context.Context, accountManager account.Manager, networksManager nbnetworks.Manager, resourceManager resources.Manager, routerManager routers.Manager, groupsManager nbgroups.Manager, LocationManager geolocation.Geolocation, authManager auth.Manager, appMetrics telemetry.AppMetrics, integratedValidator integrated_validator.IntegratedValidator, proxyController port_forwarding.Controller, permissionsManager permissions.Manager, peersManager nbpeers.Manager, settingsManager settings.Manager, zManager zones.Manager, rManager records.Manager, networkMapController network_map.Controller, idpManager idpmanager.Manager, reverseProxyManager reverseproxy.Manager) (http.Handler, error) {
|
||||||
|
|
||||||
// Register bypass paths for unauthenticated endpoints
|
// Register bypass paths for unauthenticated endpoints
|
||||||
if err := bypass.AddBypassPath("/api/instance"); err != nil {
|
if err := bypass.AddBypassPath("/api/instance"); err != nil {
|
||||||
@@ -158,7 +158,7 @@ func NewAPIHandler(ctx context.Context, accountManager account.Manager, networks
|
|||||||
idp.AddEndpoints(accountManager, router)
|
idp.AddEndpoints(accountManager, router)
|
||||||
instance.AddEndpoints(instanceManager, router)
|
instance.AddEndpoints(instanceManager, router)
|
||||||
instance.AddVersionEndpoint(instanceManager, router)
|
instance.AddVersionEndpoint(instanceManager, router)
|
||||||
services.RegisterEndpoints(router, serviceManager)
|
reverseproxymanager.RegisterEndpoints(router, reverseProxyManager)
|
||||||
|
|
||||||
// Mount embedded IdP handler at /oauth2 path if configured
|
// Mount embedded IdP handler at /oauth2 path if configured
|
||||||
if embeddedIdpEnabled {
|
if embeddedIdpEnabled {
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import (
|
|||||||
"gorm.io/gorm/logger"
|
"gorm.io/gorm/logger"
|
||||||
|
|
||||||
nbdns "github.com/netbirdio/netbird/dns"
|
nbdns "github.com/netbirdio/netbird/dns"
|
||||||
"github.com/netbirdio/netbird/management/internals/modules/services"
|
"github.com/netbirdio/netbird/management/internals/modules/reverseproxy"
|
||||||
"github.com/netbirdio/netbird/management/internals/modules/zones"
|
"github.com/netbirdio/netbird/management/internals/modules/zones"
|
||||||
"github.com/netbirdio/netbird/management/internals/modules/zones/records"
|
"github.com/netbirdio/netbird/management/internals/modules/zones/records"
|
||||||
resourceTypes "github.com/netbirdio/netbird/management/server/networks/resources/types"
|
resourceTypes "github.com/netbirdio/netbird/management/server/networks/resources/types"
|
||||||
@@ -127,7 +127,7 @@ func NewSqlStore(ctx context.Context, db *gorm.DB, storeEngine types.Engine, met
|
|||||||
&types.Account{}, &types.Policy{}, &types.PolicyRule{}, &route.Route{}, &nbdns.NameServerGroup{},
|
&types.Account{}, &types.Policy{}, &types.PolicyRule{}, &route.Route{}, &nbdns.NameServerGroup{},
|
||||||
&installation{}, &types.ExtraSettings{}, &posture.Checks{}, &nbpeer.NetworkAddress{},
|
&installation{}, &types.ExtraSettings{}, &posture.Checks{}, &nbpeer.NetworkAddress{},
|
||||||
&networkTypes.Network{}, &routerTypes.NetworkRouter{}, &resourceTypes.NetworkResource{}, &types.AccountOnboarding{},
|
&networkTypes.Network{}, &routerTypes.NetworkRouter{}, &resourceTypes.NetworkResource{}, &types.AccountOnboarding{},
|
||||||
&types.Job{}, &zones.Zone{}, &records.Record{}, &types.UserInviteRecord{}, &services.Service{},
|
&types.Job{}, &zones.Zone{}, &records.Record{}, &types.UserInviteRecord{}, &reverseproxy.ReverseProxy{},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("auto migratePreAuto: %w", err)
|
return nil, fmt.Errorf("auto migratePreAuto: %w", err)
|
||||||
@@ -4604,87 +4604,87 @@ func (s *SqlStore) GetPeerIDByKey(ctx context.Context, lockStrength LockingStren
|
|||||||
return peerID, nil
|
return peerID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SqlStore) CreateService(ctx context.Context, service *services.Service) error {
|
func (s *SqlStore) CreateReverseProxy(ctx context.Context, proxy *reverseproxy.ReverseProxy) error {
|
||||||
result := s.db.Create(service)
|
result := s.db.Create(proxy)
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
log.WithContext(ctx).Errorf("failed to create service to store: %v", result.Error)
|
log.WithContext(ctx).Errorf("failed to create reverse proxy to store: %v", result.Error)
|
||||||
return status.Errorf(status.Internal, "failed to create service to store")
|
return status.Errorf(status.Internal, "failed to create reverse proxy to store")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SqlStore) UpdateService(ctx context.Context, service *services.Service) error {
|
func (s *SqlStore) UpdateReverseProxy(ctx context.Context, proxy *reverseproxy.ReverseProxy) error {
|
||||||
result := s.db.Select("*").Save(service)
|
result := s.db.Select("*").Save(proxy)
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
log.WithContext(ctx).Errorf("failed to update service to store: %v", result.Error)
|
log.WithContext(ctx).Errorf("failed to update reverse proxy to store: %v", result.Error)
|
||||||
return status.Errorf(status.Internal, "failed to update service to store")
|
return status.Errorf(status.Internal, "failed to update reverse proxy to store")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SqlStore) DeleteService(ctx context.Context, accountID, serviceID string) error {
|
func (s *SqlStore) DeleteReverseProxy(ctx context.Context, accountID, proxyID string) error {
|
||||||
result := s.db.Delete(&services.Service{}, accountAndIDQueryCondition, accountID, serviceID)
|
result := s.db.Delete(&reverseproxy.ReverseProxy{}, accountAndIDQueryCondition, accountID, proxyID)
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
log.WithContext(ctx).Errorf("failed to delete service from store: %v", result.Error)
|
log.WithContext(ctx).Errorf("failed to delete reverse proxy from store: %v", result.Error)
|
||||||
return status.Errorf(status.Internal, "failed to delete service from store")
|
return status.Errorf(status.Internal, "failed to delete reverse proxy from store")
|
||||||
}
|
}
|
||||||
|
|
||||||
if result.RowsAffected == 0 {
|
if result.RowsAffected == 0 {
|
||||||
return status.Errorf(status.NotFound, "service %s not found", serviceID)
|
return status.Errorf(status.NotFound, "reverse proxy %s not found", proxyID)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SqlStore) GetServiceByID(ctx context.Context, lockStrength LockingStrength, accountID, serviceID string) (*services.Service, error) {
|
func (s *SqlStore) GetReverseProxyByID(ctx context.Context, lockStrength LockingStrength, accountID, proxyID string) (*reverseproxy.ReverseProxy, error) {
|
||||||
tx := s.db
|
tx := s.db
|
||||||
if lockStrength != LockingStrengthNone {
|
if lockStrength != LockingStrengthNone {
|
||||||
tx = tx.Clauses(clause.Locking{Strength: string(lockStrength)})
|
tx = tx.Clauses(clause.Locking{Strength: string(lockStrength)})
|
||||||
}
|
}
|
||||||
|
|
||||||
var service *services.Service
|
var proxy *reverseproxy.ReverseProxy
|
||||||
result := tx.Take(&service, accountAndIDQueryCondition, accountID, serviceID)
|
result := tx.Take(&proxy, accountAndIDQueryCondition, accountID, proxyID)
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||||
return nil, status.Errorf(status.NotFound, "service %s not found", serviceID)
|
return nil, status.Errorf(status.NotFound, "reverse proxy %s not found", proxyID)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.WithContext(ctx).Errorf("failed to get service from store: %v", result.Error)
|
log.WithContext(ctx).Errorf("failed to get reverse proxy from store: %v", result.Error)
|
||||||
return nil, status.Errorf(status.Internal, "failed to get service from store")
|
return nil, status.Errorf(status.Internal, "failed to get reverse proxy from store")
|
||||||
}
|
}
|
||||||
|
|
||||||
return service, nil
|
return proxy, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SqlStore) GetServiceByDomain(ctx context.Context, accountID, domain string) (*services.Service, error) {
|
func (s *SqlStore) GetReverseProxyByDomain(ctx context.Context, accountID, domain string) (*reverseproxy.ReverseProxy, error) {
|
||||||
var service *services.Service
|
var proxy *reverseproxy.ReverseProxy
|
||||||
result := s.db.Where("account_id = ? AND domain = ?", accountID, domain).First(&service)
|
result := s.db.Where("account_id = ? AND domain = ?", accountID, domain).First(&proxy)
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||||
return nil, status.Errorf(status.NotFound, "service with domain %s not found", domain)
|
return nil, status.Errorf(status.NotFound, "reverse proxy with domain %s not found", domain)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.WithContext(ctx).Errorf("failed to get service by domain from store: %v", result.Error)
|
log.WithContext(ctx).Errorf("failed to get reverse proxy by domain from store: %v", result.Error)
|
||||||
return nil, status.Errorf(status.Internal, "failed to get service by domain from store")
|
return nil, status.Errorf(status.Internal, "failed to get reverse proxy by domain from store")
|
||||||
}
|
}
|
||||||
|
|
||||||
return service, nil
|
return proxy, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SqlStore) GetAccountServices(ctx context.Context, lockStrength LockingStrength, accountID string) ([]*services.Service, error) {
|
func (s *SqlStore) GetAccountReverseProxies(ctx context.Context, lockStrength LockingStrength, accountID string) ([]*reverseproxy.ReverseProxy, error) {
|
||||||
tx := s.db
|
tx := s.db
|
||||||
if lockStrength != LockingStrengthNone {
|
if lockStrength != LockingStrengthNone {
|
||||||
tx = tx.Clauses(clause.Locking{Strength: string(lockStrength)})
|
tx = tx.Clauses(clause.Locking{Strength: string(lockStrength)})
|
||||||
}
|
}
|
||||||
|
|
||||||
var servicesList []*services.Service
|
var proxyList []*reverseproxy.ReverseProxy
|
||||||
result := tx.Find(&servicesList, accountIDCondition, accountID)
|
result := tx.Find(&proxyList, accountIDCondition, accountID)
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
log.WithContext(ctx).Errorf("failed to get services from the store: %s", result.Error)
|
log.WithContext(ctx).Errorf("failed to get reverse proxy from the store: %s", result.Error)
|
||||||
return nil, status.Errorf(status.Internal, "failed to get services from store")
|
return nil, status.Errorf(status.Internal, "failed to get reverse proxy from store")
|
||||||
}
|
}
|
||||||
|
|
||||||
return servicesList, nil
|
return proxyList, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import (
|
|||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/dns"
|
"github.com/netbirdio/netbird/dns"
|
||||||
"github.com/netbirdio/netbird/management/internals/modules/services"
|
"github.com/netbirdio/netbird/management/internals/modules/reverseproxy"
|
||||||
"github.com/netbirdio/netbird/management/internals/modules/zones"
|
"github.com/netbirdio/netbird/management/internals/modules/zones"
|
||||||
"github.com/netbirdio/netbird/management/internals/modules/zones/records"
|
"github.com/netbirdio/netbird/management/internals/modules/zones/records"
|
||||||
"github.com/netbirdio/netbird/management/server/telemetry"
|
"github.com/netbirdio/netbird/management/server/telemetry"
|
||||||
@@ -242,12 +242,12 @@ type Store interface {
|
|||||||
MarkAllPendingJobsAsFailed(ctx context.Context, accountID, peerID, reason string) error
|
MarkAllPendingJobsAsFailed(ctx context.Context, accountID, peerID, reason string) error
|
||||||
GetPeerIDByKey(ctx context.Context, lockStrength LockingStrength, key string) (string, error)
|
GetPeerIDByKey(ctx context.Context, lockStrength LockingStrength, key string) (string, error)
|
||||||
|
|
||||||
CreateService(ctx context.Context, service *services.Service) error
|
CreateReverseProxy(ctx context.Context, service *reverseproxy.ReverseProxy) error
|
||||||
UpdateService(ctx context.Context, service *services.Service) error
|
UpdateReverseProxy(ctx context.Context, service *reverseproxy.ReverseProxy) error
|
||||||
DeleteService(ctx context.Context, accountID, serviceID string) error
|
DeleteReverseProxy(ctx context.Context, accountID, serviceID string) error
|
||||||
GetServiceByID(ctx context.Context, lockStrength LockingStrength, accountID, serviceID string) (*services.Service, error)
|
GetReverseProxyByID(ctx context.Context, lockStrength LockingStrength, accountID, serviceID string) (*reverseproxy.ReverseProxy, error)
|
||||||
GetServiceByDomain(ctx context.Context, accountID, domain string) (*services.Service, error)
|
GetReverseProxyByDomain(ctx context.Context, accountID, domain string) (*reverseproxy.ReverseProxy, error)
|
||||||
GetAccountServices(ctx context.Context, lockStrength LockingStrength, accountID string) ([]*services.Service, error)
|
GetAccountReverseProxies(ctx context.Context, lockStrength LockingStrength, accountID string) ([]*reverseproxy.ReverseProxy, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -2855,10 +2855,6 @@ components:
|
|||||||
ReverseProxyAuthConfig:
|
ReverseProxyAuthConfig:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
type:
|
|
||||||
type: string
|
|
||||||
enum: [password, pin, bearer, link]
|
|
||||||
description: Authentication type
|
|
||||||
password_auth:
|
password_auth:
|
||||||
$ref: '#/components/schemas/PasswordAuthConfig'
|
$ref: '#/components/schemas/PasswordAuthConfig'
|
||||||
pin_auth:
|
pin_auth:
|
||||||
@@ -2867,8 +2863,6 @@ components:
|
|||||||
$ref: '#/components/schemas/BearerAuthConfig'
|
$ref: '#/components/schemas/BearerAuthConfig'
|
||||||
link_auth:
|
link_auth:
|
||||||
$ref: '#/components/schemas/LinkAuthConfig'
|
$ref: '#/components/schemas/LinkAuthConfig'
|
||||||
required:
|
|
||||||
- type
|
|
||||||
PasswordAuthConfig:
|
PasswordAuthConfig:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
// Package api provides primitives to interact with the openapi HTTP API.
|
// Package api provides primitives to interact with the openapi HTTP API.
|
||||||
//
|
//
|
||||||
// Code generated by github.com/deepmap/oapi-codegen version v1.11.1-0.20220912230023-4a1477f6a8ba DO NOT EDIT.
|
// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.5.1 DO NOT EDIT.
|
||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/oapi-codegen/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -21,56 +25,118 @@ const (
|
|||||||
|
|
||||||
// Defines values for EventActivityCode.
|
// Defines values for EventActivityCode.
|
||||||
const (
|
const (
|
||||||
EventActivityCodeAccountCreate EventActivityCode = "account.create"
|
EventActivityCodeAccountCreate EventActivityCode = "account.create"
|
||||||
EventActivityCodeAccountSettingPeerLoginExpirationDisable EventActivityCode = "account.setting.peer.login.expiration.disable"
|
EventActivityCodeAccountDelete EventActivityCode = "account.delete"
|
||||||
EventActivityCodeAccountSettingPeerLoginExpirationEnable EventActivityCode = "account.setting.peer.login.expiration.enable"
|
EventActivityCodeAccountDnsDomainUpdate EventActivityCode = "account.dns.domain.update"
|
||||||
EventActivityCodeAccountSettingPeerLoginExpirationUpdate EventActivityCode = "account.setting.peer.login.expiration.update"
|
EventActivityCodeAccountNetworkRangeUpdate EventActivityCode = "account.network.range.update"
|
||||||
EventActivityCodeDnsSettingDisabledManagementGroupAdd EventActivityCode = "dns.setting.disabled.management.group.add"
|
EventActivityCodeAccountPeerInactivityExpirationDisable EventActivityCode = "account.peer.inactivity.expiration.disable"
|
||||||
EventActivityCodeDnsSettingDisabledManagementGroupDelete EventActivityCode = "dns.setting.disabled.management.group.delete"
|
EventActivityCodeAccountPeerInactivityExpirationEnable EventActivityCode = "account.peer.inactivity.expiration.enable"
|
||||||
EventActivityCodeGroupAdd EventActivityCode = "group.add"
|
EventActivityCodeAccountPeerInactivityExpirationUpdate EventActivityCode = "account.peer.inactivity.expiration.update"
|
||||||
EventActivityCodeGroupUpdate EventActivityCode = "group.update"
|
EventActivityCodeAccountSettingGroupPropagationDisable EventActivityCode = "account.setting.group.propagation.disable"
|
||||||
EventActivityCodeNameserverGroupAdd EventActivityCode = "nameserver.group.add"
|
EventActivityCodeAccountSettingGroupPropagationEnable EventActivityCode = "account.setting.group.propagation.enable"
|
||||||
EventActivityCodeNameserverGroupDelete EventActivityCode = "nameserver.group.delete"
|
EventActivityCodeAccountSettingLazyConnectionDisable EventActivityCode = "account.setting.lazy.connection.disable"
|
||||||
EventActivityCodeNameserverGroupUpdate EventActivityCode = "nameserver.group.update"
|
EventActivityCodeAccountSettingLazyConnectionEnable EventActivityCode = "account.setting.lazy.connection.enable"
|
||||||
EventActivityCodePeerLoginExpirationDisable EventActivityCode = "peer.login.expiration.disable"
|
EventActivityCodeAccountSettingPeerApprovalDisable EventActivityCode = "account.setting.peer.approval.disable"
|
||||||
EventActivityCodePeerLoginExpirationEnable EventActivityCode = "peer.login.expiration.enable"
|
EventActivityCodeAccountSettingPeerApprovalEnable EventActivityCode = "account.setting.peer.approval.enable"
|
||||||
EventActivityCodePeerLoginExpire EventActivityCode = "peer.login.expire"
|
EventActivityCodeAccountSettingPeerLoginExpirationDisable EventActivityCode = "account.setting.peer.login.expiration.disable"
|
||||||
EventActivityCodePeerRename EventActivityCode = "peer.rename"
|
EventActivityCodeAccountSettingPeerLoginExpirationEnable EventActivityCode = "account.setting.peer.login.expiration.enable"
|
||||||
EventActivityCodePeerSshDisable EventActivityCode = "peer.ssh.disable"
|
EventActivityCodeAccountSettingPeerLoginExpirationUpdate EventActivityCode = "account.setting.peer.login.expiration.update"
|
||||||
EventActivityCodePeerSshEnable EventActivityCode = "peer.ssh.enable"
|
EventActivityCodeAccountSettingRoutingPeerDnsResolutionDisable EventActivityCode = "account.setting.routing.peer.dns.resolution.disable"
|
||||||
EventActivityCodePersonalAccessTokenCreate EventActivityCode = "personal.access.token.create"
|
EventActivityCodeAccountSettingRoutingPeerDnsResolutionEnable EventActivityCode = "account.setting.routing.peer.dns.resolution.enable"
|
||||||
EventActivityCodePersonalAccessTokenDelete EventActivityCode = "personal.access.token.delete"
|
EventActivityCodeAccountSettingsAutoVersionUpdate EventActivityCode = "account.settings.auto.version.update"
|
||||||
EventActivityCodePolicyAdd EventActivityCode = "policy.add"
|
EventActivityCodeDashboardLogin EventActivityCode = "dashboard.login"
|
||||||
EventActivityCodePolicyDelete EventActivityCode = "policy.delete"
|
EventActivityCodeDnsSettingDisabledManagementGroupAdd EventActivityCode = "dns.setting.disabled.management.group.add"
|
||||||
EventActivityCodePolicyUpdate EventActivityCode = "policy.update"
|
EventActivityCodeDnsSettingDisabledManagementGroupDelete EventActivityCode = "dns.setting.disabled.management.group.delete"
|
||||||
EventActivityCodeRouteAdd EventActivityCode = "route.add"
|
EventActivityCodeDnsZoneCreate EventActivityCode = "dns.zone.create"
|
||||||
EventActivityCodeRouteDelete EventActivityCode = "route.delete"
|
EventActivityCodeDnsZoneDelete EventActivityCode = "dns.zone.delete"
|
||||||
EventActivityCodeRouteUpdate EventActivityCode = "route.update"
|
EventActivityCodeDnsZoneRecordCreate EventActivityCode = "dns.zone.record.create"
|
||||||
EventActivityCodeRuleAdd EventActivityCode = "rule.add"
|
EventActivityCodeDnsZoneRecordDelete EventActivityCode = "dns.zone.record.delete"
|
||||||
EventActivityCodeRuleDelete EventActivityCode = "rule.delete"
|
EventActivityCodeDnsZoneRecordUpdate EventActivityCode = "dns.zone.record.update"
|
||||||
EventActivityCodeRuleUpdate EventActivityCode = "rule.update"
|
EventActivityCodeDnsZoneUpdate EventActivityCode = "dns.zone.update"
|
||||||
EventActivityCodeServiceCreate EventActivityCode = "service.create"
|
EventActivityCodeGroupAdd EventActivityCode = "group.add"
|
||||||
EventActivityCodeServiceDelete EventActivityCode = "service.delete"
|
EventActivityCodeGroupDelete EventActivityCode = "group.delete"
|
||||||
EventActivityCodeServiceUpdate EventActivityCode = "service.update"
|
EventActivityCodeGroupUpdate EventActivityCode = "group.update"
|
||||||
EventActivityCodeServiceUserCreate EventActivityCode = "service.user.create"
|
EventActivityCodeIdentityproviderCreate EventActivityCode = "identityprovider.create"
|
||||||
EventActivityCodeServiceUserDelete EventActivityCode = "service.user.delete"
|
EventActivityCodeIdentityproviderDelete EventActivityCode = "identityprovider.delete"
|
||||||
EventActivityCodeSetupkeyAdd EventActivityCode = "setupkey.add"
|
EventActivityCodeIdentityproviderUpdate EventActivityCode = "identityprovider.update"
|
||||||
EventActivityCodeSetupkeyGroupAdd EventActivityCode = "setupkey.group.add"
|
EventActivityCodeIntegrationCreate EventActivityCode = "integration.create"
|
||||||
EventActivityCodeSetupkeyGroupDelete EventActivityCode = "setupkey.group.delete"
|
EventActivityCodeIntegrationDelete EventActivityCode = "integration.delete"
|
||||||
EventActivityCodeSetupkeyOveruse EventActivityCode = "setupkey.overuse"
|
EventActivityCodeIntegrationUpdate EventActivityCode = "integration.update"
|
||||||
EventActivityCodeSetupkeyPeerAdd EventActivityCode = "setupkey.peer.add"
|
EventActivityCodeNameserverGroupAdd EventActivityCode = "nameserver.group.add"
|
||||||
EventActivityCodeSetupkeyRevoke EventActivityCode = "setupkey.revoke"
|
EventActivityCodeNameserverGroupDelete EventActivityCode = "nameserver.group.delete"
|
||||||
EventActivityCodeSetupkeyUpdate EventActivityCode = "setupkey.update"
|
EventActivityCodeNameserverGroupUpdate EventActivityCode = "nameserver.group.update"
|
||||||
EventActivityCodeUserBlock EventActivityCode = "user.block"
|
EventActivityCodeNetworkCreate EventActivityCode = "network.create"
|
||||||
EventActivityCodeUserGroupAdd EventActivityCode = "user.group.add"
|
EventActivityCodeNetworkDelete EventActivityCode = "network.delete"
|
||||||
EventActivityCodeUserGroupDelete EventActivityCode = "user.group.delete"
|
EventActivityCodeNetworkResourceCreate EventActivityCode = "network.resource.create"
|
||||||
EventActivityCodeUserInvite EventActivityCode = "user.invite"
|
EventActivityCodeNetworkResourceDelete EventActivityCode = "network.resource.delete"
|
||||||
EventActivityCodeUserJoin EventActivityCode = "user.join"
|
EventActivityCodeNetworkResourceUpdate EventActivityCode = "network.resource.update"
|
||||||
EventActivityCodeUserPeerAdd EventActivityCode = "user.peer.add"
|
EventActivityCodeNetworkRouterCreate EventActivityCode = "network.router.create"
|
||||||
EventActivityCodeUserPeerDelete EventActivityCode = "user.peer.delete"
|
EventActivityCodeNetworkRouterDelete EventActivityCode = "network.router.delete"
|
||||||
EventActivityCodeUserPeerLogin EventActivityCode = "user.peer.login"
|
EventActivityCodeNetworkRouterUpdate EventActivityCode = "network.router.update"
|
||||||
EventActivityCodeUserRoleUpdate EventActivityCode = "user.role.update"
|
EventActivityCodeNetworkUpdate EventActivityCode = "network.update"
|
||||||
EventActivityCodeUserUnblock EventActivityCode = "user.unblock"
|
EventActivityCodePeerApprovalRevoke EventActivityCode = "peer.approval.revoke"
|
||||||
|
EventActivityCodePeerApprove EventActivityCode = "peer.approve"
|
||||||
|
EventActivityCodePeerGroupAdd EventActivityCode = "peer.group.add"
|
||||||
|
EventActivityCodePeerGroupDelete EventActivityCode = "peer.group.delete"
|
||||||
|
EventActivityCodePeerInactivityExpirationDisable EventActivityCode = "peer.inactivity.expiration.disable"
|
||||||
|
EventActivityCodePeerInactivityExpirationEnable EventActivityCode = "peer.inactivity.expiration.enable"
|
||||||
|
EventActivityCodePeerIpUpdate EventActivityCode = "peer.ip.update"
|
||||||
|
EventActivityCodePeerJobCreate EventActivityCode = "peer.job.create"
|
||||||
|
EventActivityCodePeerLoginExpirationDisable EventActivityCode = "peer.login.expiration.disable"
|
||||||
|
EventActivityCodePeerLoginExpirationEnable EventActivityCode = "peer.login.expiration.enable"
|
||||||
|
EventActivityCodePeerLoginExpire EventActivityCode = "peer.login.expire"
|
||||||
|
EventActivityCodePeerRename EventActivityCode = "peer.rename"
|
||||||
|
EventActivityCodePeerSetupkeyAdd EventActivityCode = "peer.setupkey.add"
|
||||||
|
EventActivityCodePeerSshDisable EventActivityCode = "peer.ssh.disable"
|
||||||
|
EventActivityCodePeerSshEnable EventActivityCode = "peer.ssh.enable"
|
||||||
|
EventActivityCodePeerUserAdd EventActivityCode = "peer.user.add"
|
||||||
|
EventActivityCodePersonalAccessTokenCreate EventActivityCode = "personal.access.token.create"
|
||||||
|
EventActivityCodePersonalAccessTokenDelete EventActivityCode = "personal.access.token.delete"
|
||||||
|
EventActivityCodePolicyAdd EventActivityCode = "policy.add"
|
||||||
|
EventActivityCodePolicyDelete EventActivityCode = "policy.delete"
|
||||||
|
EventActivityCodePolicyUpdate EventActivityCode = "policy.update"
|
||||||
|
EventActivityCodePostureCheckCreate EventActivityCode = "posture.check.create"
|
||||||
|
EventActivityCodePostureCheckDelete EventActivityCode = "posture.check.delete"
|
||||||
|
EventActivityCodePostureCheckUpdate EventActivityCode = "posture.check.update"
|
||||||
|
EventActivityCodeResourceGroupAdd EventActivityCode = "resource.group.add"
|
||||||
|
EventActivityCodeResourceGroupDelete EventActivityCode = "resource.group.delete"
|
||||||
|
EventActivityCodeRouteAdd EventActivityCode = "route.add"
|
||||||
|
EventActivityCodeRouteDelete EventActivityCode = "route.delete"
|
||||||
|
EventActivityCodeRouteUpdate EventActivityCode = "route.update"
|
||||||
|
EventActivityCodeRuleAdd EventActivityCode = "rule.add"
|
||||||
|
EventActivityCodeRuleDelete EventActivityCode = "rule.delete"
|
||||||
|
EventActivityCodeRuleUpdate EventActivityCode = "rule.update"
|
||||||
|
EventActivityCodeServiceCreate EventActivityCode = "service.create"
|
||||||
|
EventActivityCodeServiceDelete EventActivityCode = "service.delete"
|
||||||
|
EventActivityCodeServiceUpdate EventActivityCode = "service.update"
|
||||||
|
EventActivityCodeServiceUserCreate EventActivityCode = "service.user.create"
|
||||||
|
EventActivityCodeServiceUserDelete EventActivityCode = "service.user.delete"
|
||||||
|
EventActivityCodeSetupkeyAdd EventActivityCode = "setupkey.add"
|
||||||
|
EventActivityCodeSetupkeyDelete EventActivityCode = "setupkey.delete"
|
||||||
|
EventActivityCodeSetupkeyGroupAdd EventActivityCode = "setupkey.group.add"
|
||||||
|
EventActivityCodeSetupkeyGroupDelete EventActivityCode = "setupkey.group.delete"
|
||||||
|
EventActivityCodeSetupkeyOveruse EventActivityCode = "setupkey.overuse"
|
||||||
|
EventActivityCodeSetupkeyRevoke EventActivityCode = "setupkey.revoke"
|
||||||
|
EventActivityCodeSetupkeyUpdate EventActivityCode = "setupkey.update"
|
||||||
|
EventActivityCodeTransferredOwnerRole EventActivityCode = "transferred.owner.role"
|
||||||
|
EventActivityCodeUserApprove EventActivityCode = "user.approve"
|
||||||
|
EventActivityCodeUserBlock EventActivityCode = "user.block"
|
||||||
|
EventActivityCodeUserCreate EventActivityCode = "user.create"
|
||||||
|
EventActivityCodeUserDelete EventActivityCode = "user.delete"
|
||||||
|
EventActivityCodeUserGroupAdd EventActivityCode = "user.group.add"
|
||||||
|
EventActivityCodeUserGroupDelete EventActivityCode = "user.group.delete"
|
||||||
|
EventActivityCodeUserInvite EventActivityCode = "user.invite"
|
||||||
|
EventActivityCodeUserInviteLinkAccept EventActivityCode = "user.invite.link.accept"
|
||||||
|
EventActivityCodeUserInviteLinkCreate EventActivityCode = "user.invite.link.create"
|
||||||
|
EventActivityCodeUserInviteLinkDelete EventActivityCode = "user.invite.link.delete"
|
||||||
|
EventActivityCodeUserInviteLinkRegenerate EventActivityCode = "user.invite.link.regenerate"
|
||||||
|
EventActivityCodeUserJoin EventActivityCode = "user.join"
|
||||||
|
EventActivityCodeUserPasswordChange EventActivityCode = "user.password.change"
|
||||||
|
EventActivityCodeUserPeerDelete EventActivityCode = "user.peer.delete"
|
||||||
|
EventActivityCodeUserPeerLogin EventActivityCode = "user.peer.login"
|
||||||
|
EventActivityCodeUserReject EventActivityCode = "user.reject"
|
||||||
|
EventActivityCodeUserRoleUpdate EventActivityCode = "user.role.update"
|
||||||
|
EventActivityCodeUserUnblock EventActivityCode = "user.unblock"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Defines values for GeoLocationCheckAction.
|
// Defines values for GeoLocationCheckAction.
|
||||||
@@ -125,6 +191,13 @@ const (
|
|||||||
IngressPortAllocationRequestPortRangeProtocolUdp IngressPortAllocationRequestPortRangeProtocol = "udp"
|
IngressPortAllocationRequestPortRangeProtocolUdp IngressPortAllocationRequestPortRangeProtocol = "udp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Defines values for JobResponseStatus.
|
||||||
|
const (
|
||||||
|
JobResponseStatusFailed JobResponseStatus = "failed"
|
||||||
|
JobResponseStatusPending JobResponseStatus = "pending"
|
||||||
|
JobResponseStatusSucceeded JobResponseStatus = "succeeded"
|
||||||
|
)
|
||||||
|
|
||||||
// Defines values for NameserverNsType.
|
// Defines values for NameserverNsType.
|
||||||
const (
|
const (
|
||||||
NameserverNsTypeUdp NameserverNsType = "udp"
|
NameserverNsTypeUdp NameserverNsType = "udp"
|
||||||
@@ -196,14 +269,6 @@ const (
|
|||||||
ResourceTypeSubnet ResourceType = "subnet"
|
ResourceTypeSubnet ResourceType = "subnet"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Defines values for ReverseProxyAuthConfigType.
|
|
||||||
const (
|
|
||||||
ReverseProxyAuthConfigTypeBearer ReverseProxyAuthConfigType = "bearer"
|
|
||||||
ReverseProxyAuthConfigTypeLink ReverseProxyAuthConfigType = "link"
|
|
||||||
ReverseProxyAuthConfigTypePassword ReverseProxyAuthConfigType = "password"
|
|
||||||
ReverseProxyAuthConfigTypePin ReverseProxyAuthConfigType = "pin"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Defines values for ReverseProxyDomainType.
|
// Defines values for ReverseProxyDomainType.
|
||||||
const (
|
const (
|
||||||
ReverseProxyDomainTypeCustom ReverseProxyDomainType = "custom"
|
ReverseProxyDomainTypeCustom ReverseProxyDomainType = "custom"
|
||||||
@@ -229,6 +294,11 @@ const (
|
|||||||
UserStatusInvited UserStatus = "invited"
|
UserStatusInvited UserStatus = "invited"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Defines values for WorkloadType.
|
||||||
|
const (
|
||||||
|
WorkloadTypeBundle WorkloadType = "bundle"
|
||||||
|
)
|
||||||
|
|
||||||
// Defines values for GetApiEventsNetworkTrafficParamsType.
|
// Defines values for GetApiEventsNetworkTrafficParamsType.
|
||||||
const (
|
const (
|
||||||
GetApiEventsNetworkTrafficParamsTypeTYPEDROP GetApiEventsNetworkTrafficParamsType = "TYPE_DROP"
|
GetApiEventsNetworkTrafficParamsTypeTYPEDROP GetApiEventsNetworkTrafficParamsType = "TYPE_DROP"
|
||||||
@@ -406,6 +476,47 @@ type BearerAuthConfig struct {
|
|||||||
Enabled bool `json:"enabled"`
|
Enabled bool `json:"enabled"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BundleParameters These parameters control what gets included in the bundle and how it is processed.
|
||||||
|
type BundleParameters struct {
|
||||||
|
// Anonymize Whether sensitive data should be anonymized in the bundle.
|
||||||
|
Anonymize bool `json:"anonymize"`
|
||||||
|
|
||||||
|
// BundleFor Whether to generate a bundle for the given timeframe.
|
||||||
|
BundleFor bool `json:"bundle_for"`
|
||||||
|
|
||||||
|
// BundleForTime Time period in minutes for which to generate the bundle.
|
||||||
|
BundleForTime int `json:"bundle_for_time"`
|
||||||
|
|
||||||
|
// LogFileCount Maximum number of log files to include in the bundle.
|
||||||
|
LogFileCount int `json:"log_file_count"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// BundleResult defines model for BundleResult.
|
||||||
|
type BundleResult struct {
|
||||||
|
UploadKey *string `json:"upload_key"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// BundleWorkloadRequest defines model for BundleWorkloadRequest.
|
||||||
|
type BundleWorkloadRequest struct {
|
||||||
|
// Parameters These parameters control what gets included in the bundle and how it is processed.
|
||||||
|
Parameters BundleParameters `json:"parameters"`
|
||||||
|
|
||||||
|
// Type Identifies the type of workload the job will execute.
|
||||||
|
// Currently only `"bundle"` is supported.
|
||||||
|
Type WorkloadType `json:"type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// BundleWorkloadResponse defines model for BundleWorkloadResponse.
|
||||||
|
type BundleWorkloadResponse struct {
|
||||||
|
// Parameters These parameters control what gets included in the bundle and how it is processed.
|
||||||
|
Parameters BundleParameters `json:"parameters"`
|
||||||
|
Result BundleResult `json:"result"`
|
||||||
|
|
||||||
|
// Type Identifies the type of workload the job will execute.
|
||||||
|
// Currently only `"bundle"` is supported.
|
||||||
|
Type WorkloadType `json:"type"`
|
||||||
|
}
|
||||||
|
|
||||||
// Checks List of objects that perform the actual checks
|
// Checks List of objects that perform the actual checks
|
||||||
type Checks struct {
|
type Checks struct {
|
||||||
// GeoLocationCheck Posture check for geo location
|
// GeoLocationCheck Posture check for geo location
|
||||||
@@ -793,6 +904,40 @@ type InstanceStatus struct {
|
|||||||
SetupRequired bool `json:"setup_required"`
|
SetupRequired bool `json:"setup_required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InstanceVersionInfo Version information for NetBird components
|
||||||
|
type InstanceVersionInfo struct {
|
||||||
|
// DashboardAvailableVersion The latest available version of the dashboard (from GitHub releases)
|
||||||
|
DashboardAvailableVersion *string `json:"dashboard_available_version,omitempty"`
|
||||||
|
|
||||||
|
// ManagementAvailableVersion The latest available version of the management server (from GitHub releases)
|
||||||
|
ManagementAvailableVersion *string `json:"management_available_version,omitempty"`
|
||||||
|
|
||||||
|
// ManagementCurrentVersion The current running version of the management server
|
||||||
|
ManagementCurrentVersion string `json:"management_current_version"`
|
||||||
|
|
||||||
|
// ManagementUpdateAvailable Indicates if a newer management version is available
|
||||||
|
ManagementUpdateAvailable bool `json:"management_update_available"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// JobRequest defines model for JobRequest.
|
||||||
|
type JobRequest struct {
|
||||||
|
Workload WorkloadRequest `json:"workload"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// JobResponse defines model for JobResponse.
|
||||||
|
type JobResponse struct {
|
||||||
|
CompletedAt *time.Time `json:"completed_at"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
FailedReason *string `json:"failed_reason"`
|
||||||
|
Id string `json:"id"`
|
||||||
|
Status JobResponseStatus `json:"status"`
|
||||||
|
TriggeredBy string `json:"triggered_by"`
|
||||||
|
Workload WorkloadResponse `json:"workload"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// JobResponseStatus defines model for JobResponse.Status.
|
||||||
|
type JobResponseStatus string
|
||||||
|
|
||||||
// LinkAuthConfig defines model for LinkAuthConfig.
|
// LinkAuthConfig defines model for LinkAuthConfig.
|
||||||
type LinkAuthConfig struct {
|
type LinkAuthConfig struct {
|
||||||
// Enabled Whether link auth is enabled
|
// Enabled Whether link auth is enabled
|
||||||
@@ -1187,6 +1332,15 @@ type PasswordAuthConfig struct {
|
|||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PasswordChangeRequest defines model for PasswordChangeRequest.
|
||||||
|
type PasswordChangeRequest struct {
|
||||||
|
// NewPassword The new password to set
|
||||||
|
NewPassword string `json:"new_password"`
|
||||||
|
|
||||||
|
// OldPassword The current password
|
||||||
|
OldPassword string `json:"old_password"`
|
||||||
|
}
|
||||||
|
|
||||||
// Peer defines model for Peer.
|
// Peer defines model for Peer.
|
||||||
type Peer struct {
|
type Peer struct {
|
||||||
// ApprovalRequired (Cloud only) Indicates whether peer needs approval
|
// ApprovalRequired (Cloud only) Indicates whether peer needs approval
|
||||||
@@ -1774,14 +1928,8 @@ type ReverseProxyAuthConfig struct {
|
|||||||
LinkAuth *LinkAuthConfig `json:"link_auth,omitempty"`
|
LinkAuth *LinkAuthConfig `json:"link_auth,omitempty"`
|
||||||
PasswordAuth *PasswordAuthConfig `json:"password_auth,omitempty"`
|
PasswordAuth *PasswordAuthConfig `json:"password_auth,omitempty"`
|
||||||
PinAuth *PINAuthConfig `json:"pin_auth,omitempty"`
|
PinAuth *PINAuthConfig `json:"pin_auth,omitempty"`
|
||||||
|
|
||||||
// Type Authentication type
|
|
||||||
Type ReverseProxyAuthConfigType `json:"type"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReverseProxyAuthConfigType Authentication type
|
|
||||||
type ReverseProxyAuthConfigType string
|
|
||||||
|
|
||||||
// ReverseProxyDomain defines model for ReverseProxyDomain.
|
// ReverseProxyDomain defines model for ReverseProxyDomain.
|
||||||
type ReverseProxyDomain struct {
|
type ReverseProxyDomain struct {
|
||||||
// Domain Domain name
|
// Domain Domain name
|
||||||
@@ -2190,6 +2338,99 @@ type UserCreateRequest struct {
|
|||||||
Role string `json:"role"`
|
Role string `json:"role"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UserInvite A user invite
|
||||||
|
type UserInvite struct {
|
||||||
|
// AutoGroups Group IDs to auto-assign to peers registered by this user
|
||||||
|
AutoGroups []string `json:"auto_groups"`
|
||||||
|
|
||||||
|
// CreatedAt Invite creation time
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
|
||||||
|
// Email User's email address
|
||||||
|
Email string `json:"email"`
|
||||||
|
|
||||||
|
// Expired Whether the invite has expired
|
||||||
|
Expired bool `json:"expired"`
|
||||||
|
|
||||||
|
// ExpiresAt Invite expiration time
|
||||||
|
ExpiresAt time.Time `json:"expires_at"`
|
||||||
|
|
||||||
|
// Id Invite ID
|
||||||
|
Id string `json:"id"`
|
||||||
|
|
||||||
|
// InviteToken The invite link to be shared with the user. Only returned when the invite is created or regenerated.
|
||||||
|
InviteToken *string `json:"invite_token,omitempty"`
|
||||||
|
|
||||||
|
// Name User's full name
|
||||||
|
Name string `json:"name"`
|
||||||
|
|
||||||
|
// Role User's NetBird account role
|
||||||
|
Role string `json:"role"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserInviteAcceptRequest Request to accept an invite and set password
|
||||||
|
type UserInviteAcceptRequest struct {
|
||||||
|
// Password The password the user wants to set. Must be at least 8 characters long and contain at least one uppercase letter, one digit, and one special character (any character that is not a letter or digit, including spaces).
|
||||||
|
Password string `json:"password"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserInviteAcceptResponse Response after accepting an invite
|
||||||
|
type UserInviteAcceptResponse struct {
|
||||||
|
// Success Whether the invite was accepted successfully
|
||||||
|
Success bool `json:"success"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserInviteCreateRequest Request to create a user invite link
|
||||||
|
type UserInviteCreateRequest struct {
|
||||||
|
// AutoGroups Group IDs to auto-assign to peers registered by this user
|
||||||
|
AutoGroups []string `json:"auto_groups"`
|
||||||
|
|
||||||
|
// Email User's email address
|
||||||
|
Email string `json:"email"`
|
||||||
|
|
||||||
|
// ExpiresIn Invite expiration time in seconds (default 72 hours)
|
||||||
|
ExpiresIn *int `json:"expires_in,omitempty"`
|
||||||
|
|
||||||
|
// Name User's full name
|
||||||
|
Name string `json:"name"`
|
||||||
|
|
||||||
|
// Role User's NetBird account role
|
||||||
|
Role string `json:"role"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserInviteInfo Public information about an invite
|
||||||
|
type UserInviteInfo struct {
|
||||||
|
// Email User's email address
|
||||||
|
Email string `json:"email"`
|
||||||
|
|
||||||
|
// ExpiresAt Invite expiration time
|
||||||
|
ExpiresAt time.Time `json:"expires_at"`
|
||||||
|
|
||||||
|
// InvitedBy Name of the user who sent the invite
|
||||||
|
InvitedBy string `json:"invited_by"`
|
||||||
|
|
||||||
|
// Name User's full name
|
||||||
|
Name string `json:"name"`
|
||||||
|
|
||||||
|
// Valid Whether the invite is still valid (not expired)
|
||||||
|
Valid bool `json:"valid"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserInviteRegenerateRequest Request to regenerate an invite link
|
||||||
|
type UserInviteRegenerateRequest struct {
|
||||||
|
// ExpiresIn Invite expiration time in seconds (default 72 hours)
|
||||||
|
ExpiresIn *int `json:"expires_in,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserInviteRegenerateResponse Response after regenerating an invite
|
||||||
|
type UserInviteRegenerateResponse struct {
|
||||||
|
// InviteExpiresAt New invite expiration time
|
||||||
|
InviteExpiresAt time.Time `json:"invite_expires_at"`
|
||||||
|
|
||||||
|
// InviteToken The new invite token
|
||||||
|
InviteToken string `json:"invite_token"`
|
||||||
|
}
|
||||||
|
|
||||||
// UserPermissions defines model for UserPermissions.
|
// UserPermissions defines model for UserPermissions.
|
||||||
type UserPermissions struct {
|
type UserPermissions struct {
|
||||||
// IsRestricted Indicates whether this User's Peers view is restricted
|
// IsRestricted Indicates whether this User's Peers view is restricted
|
||||||
@@ -2209,6 +2450,20 @@ type UserRequest struct {
|
|||||||
Role string `json:"role"`
|
Role string `json:"role"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WorkloadRequest defines model for WorkloadRequest.
|
||||||
|
type WorkloadRequest struct {
|
||||||
|
union json.RawMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
// WorkloadResponse defines model for WorkloadResponse.
|
||||||
|
type WorkloadResponse struct {
|
||||||
|
union json.RawMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
// WorkloadType Identifies the type of workload the job will execute.
|
||||||
|
// Currently only `"bundle"` is supported.
|
||||||
|
type WorkloadType string
|
||||||
|
|
||||||
// Zone defines model for Zone.
|
// Zone defines model for Zone.
|
||||||
type Zone struct {
|
type Zone struct {
|
||||||
// DistributionGroups Group IDs that defines groups of peers that will resolve this zone
|
// DistributionGroups Group IDs that defines groups of peers that will resolve this zone
|
||||||
@@ -2392,6 +2647,9 @@ type PostApiPeersPeerIdIngressPortsJSONRequestBody = IngressPortAllocationReques
|
|||||||
// PutApiPeersPeerIdIngressPortsAllocationIdJSONRequestBody defines body for PutApiPeersPeerIdIngressPortsAllocationId for application/json ContentType.
|
// PutApiPeersPeerIdIngressPortsAllocationIdJSONRequestBody defines body for PutApiPeersPeerIdIngressPortsAllocationId for application/json ContentType.
|
||||||
type PutApiPeersPeerIdIngressPortsAllocationIdJSONRequestBody = IngressPortAllocationRequest
|
type PutApiPeersPeerIdIngressPortsAllocationIdJSONRequestBody = IngressPortAllocationRequest
|
||||||
|
|
||||||
|
// PostApiPeersPeerIdJobsJSONRequestBody defines body for PostApiPeersPeerIdJobs for application/json ContentType.
|
||||||
|
type PostApiPeersPeerIdJobsJSONRequestBody = JobRequest
|
||||||
|
|
||||||
// PostApiPeersPeerIdTemporaryAccessJSONRequestBody defines body for PostApiPeersPeerIdTemporaryAccess for application/json ContentType.
|
// PostApiPeersPeerIdTemporaryAccessJSONRequestBody defines body for PostApiPeersPeerIdTemporaryAccess for application/json ContentType.
|
||||||
type PostApiPeersPeerIdTemporaryAccessJSONRequestBody = PeerTemporaryAccessRequest
|
type PostApiPeersPeerIdTemporaryAccessJSONRequestBody = PeerTemporaryAccessRequest
|
||||||
|
|
||||||
@@ -2434,8 +2692,138 @@ type PutApiSetupKeysKeyIdJSONRequestBody = SetupKeyRequest
|
|||||||
// PostApiUsersJSONRequestBody defines body for PostApiUsers for application/json ContentType.
|
// PostApiUsersJSONRequestBody defines body for PostApiUsers for application/json ContentType.
|
||||||
type PostApiUsersJSONRequestBody = UserCreateRequest
|
type PostApiUsersJSONRequestBody = UserCreateRequest
|
||||||
|
|
||||||
|
// PostApiUsersInvitesJSONRequestBody defines body for PostApiUsersInvites for application/json ContentType.
|
||||||
|
type PostApiUsersInvitesJSONRequestBody = UserInviteCreateRequest
|
||||||
|
|
||||||
|
// PostApiUsersInvitesInviteIdRegenerateJSONRequestBody defines body for PostApiUsersInvitesInviteIdRegenerate for application/json ContentType.
|
||||||
|
type PostApiUsersInvitesInviteIdRegenerateJSONRequestBody = UserInviteRegenerateRequest
|
||||||
|
|
||||||
|
// PostApiUsersInvitesTokenAcceptJSONRequestBody defines body for PostApiUsersInvitesTokenAccept for application/json ContentType.
|
||||||
|
type PostApiUsersInvitesTokenAcceptJSONRequestBody = UserInviteAcceptRequest
|
||||||
|
|
||||||
// PutApiUsersUserIdJSONRequestBody defines body for PutApiUsersUserId for application/json ContentType.
|
// PutApiUsersUserIdJSONRequestBody defines body for PutApiUsersUserId for application/json ContentType.
|
||||||
type PutApiUsersUserIdJSONRequestBody = UserRequest
|
type PutApiUsersUserIdJSONRequestBody = UserRequest
|
||||||
|
|
||||||
|
// PutApiUsersUserIdPasswordJSONRequestBody defines body for PutApiUsersUserIdPassword for application/json ContentType.
|
||||||
|
type PutApiUsersUserIdPasswordJSONRequestBody = PasswordChangeRequest
|
||||||
|
|
||||||
// PostApiUsersUserIdTokensJSONRequestBody defines body for PostApiUsersUserIdTokens for application/json ContentType.
|
// PostApiUsersUserIdTokensJSONRequestBody defines body for PostApiUsersUserIdTokens for application/json ContentType.
|
||||||
type PostApiUsersUserIdTokensJSONRequestBody = PersonalAccessTokenRequest
|
type PostApiUsersUserIdTokensJSONRequestBody = PersonalAccessTokenRequest
|
||||||
|
|
||||||
|
// AsBundleWorkloadRequest returns the union data inside the WorkloadRequest as a BundleWorkloadRequest
|
||||||
|
func (t WorkloadRequest) AsBundleWorkloadRequest() (BundleWorkloadRequest, error) {
|
||||||
|
var body BundleWorkloadRequest
|
||||||
|
err := json.Unmarshal(t.union, &body)
|
||||||
|
return body, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromBundleWorkloadRequest overwrites any union data inside the WorkloadRequest as the provided BundleWorkloadRequest
|
||||||
|
func (t *WorkloadRequest) FromBundleWorkloadRequest(v BundleWorkloadRequest) error {
|
||||||
|
v.Type = "bundle"
|
||||||
|
b, err := json.Marshal(v)
|
||||||
|
t.union = b
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// MergeBundleWorkloadRequest performs a merge with any union data inside the WorkloadRequest, using the provided BundleWorkloadRequest
|
||||||
|
func (t *WorkloadRequest) MergeBundleWorkloadRequest(v BundleWorkloadRequest) error {
|
||||||
|
v.Type = "bundle"
|
||||||
|
b, err := json.Marshal(v)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
merged, err := runtime.JSONMerge(t.union, b)
|
||||||
|
t.union = merged
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t WorkloadRequest) Discriminator() (string, error) {
|
||||||
|
var discriminator struct {
|
||||||
|
Discriminator string `json:"type"`
|
||||||
|
}
|
||||||
|
err := json.Unmarshal(t.union, &discriminator)
|
||||||
|
return discriminator.Discriminator, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t WorkloadRequest) ValueByDiscriminator() (interface{}, error) {
|
||||||
|
discriminator, err := t.Discriminator()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
switch discriminator {
|
||||||
|
case "bundle":
|
||||||
|
return t.AsBundleWorkloadRequest()
|
||||||
|
default:
|
||||||
|
return nil, errors.New("unknown discriminator value: " + discriminator)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t WorkloadRequest) MarshalJSON() ([]byte, error) {
|
||||||
|
b, err := t.union.MarshalJSON()
|
||||||
|
return b, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *WorkloadRequest) UnmarshalJSON(b []byte) error {
|
||||||
|
err := t.union.UnmarshalJSON(b)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// AsBundleWorkloadResponse returns the union data inside the WorkloadResponse as a BundleWorkloadResponse
|
||||||
|
func (t WorkloadResponse) AsBundleWorkloadResponse() (BundleWorkloadResponse, error) {
|
||||||
|
var body BundleWorkloadResponse
|
||||||
|
err := json.Unmarshal(t.union, &body)
|
||||||
|
return body, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromBundleWorkloadResponse overwrites any union data inside the WorkloadResponse as the provided BundleWorkloadResponse
|
||||||
|
func (t *WorkloadResponse) FromBundleWorkloadResponse(v BundleWorkloadResponse) error {
|
||||||
|
v.Type = "bundle"
|
||||||
|
b, err := json.Marshal(v)
|
||||||
|
t.union = b
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// MergeBundleWorkloadResponse performs a merge with any union data inside the WorkloadResponse, using the provided BundleWorkloadResponse
|
||||||
|
func (t *WorkloadResponse) MergeBundleWorkloadResponse(v BundleWorkloadResponse) error {
|
||||||
|
v.Type = "bundle"
|
||||||
|
b, err := json.Marshal(v)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
merged, err := runtime.JSONMerge(t.union, b)
|
||||||
|
t.union = merged
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t WorkloadResponse) Discriminator() (string, error) {
|
||||||
|
var discriminator struct {
|
||||||
|
Discriminator string `json:"type"`
|
||||||
|
}
|
||||||
|
err := json.Unmarshal(t.union, &discriminator)
|
||||||
|
return discriminator.Discriminator, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t WorkloadResponse) ValueByDiscriminator() (interface{}, error) {
|
||||||
|
discriminator, err := t.Discriminator()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
switch discriminator {
|
||||||
|
case "bundle":
|
||||||
|
return t.AsBundleWorkloadResponse()
|
||||||
|
default:
|
||||||
|
return nil, errors.New("unknown discriminator value: " + discriminator)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t WorkloadResponse) MarshalJSON() ([]byte, error) {
|
||||||
|
b, err := t.union.MarshalJSON()
|
||||||
|
return b, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *WorkloadResponse) UnmarshalJSON(b []byte) error {
|
||||||
|
err := t.union.UnmarshalJSON(b)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user