mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-18 00:06:38 +00:00
add management API to store
This commit is contained in:
13
management/internals/modules/services/interface.go
Normal file
13
management/internals/modules/services/interface.go
Normal file
@@ -0,0 +1,13 @@
|
||||
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
|
||||
}
|
||||
161
management/internals/modules/services/manager/api.go
Normal file
161
management/internals/modules/services/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/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{})
|
||||
}
|
||||
199
management/internals/modules/services/manager/manager.go
Normal file
199
management/internals/modules/services/manager/manager.go
Normal file
@@ -0,0 +1,199 @@
|
||||
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
|
||||
}
|
||||
184
management/internals/modules/services/service.go
Normal file
184
management/internals/modules/services/service.go
Normal file
@@ -0,0 +1,184 @@
|
||||
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 {
|
||||
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())
|
||||
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())
|
||||
if err != nil {
|
||||
log.Fatalf("failed to create API handler: %v", err)
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ import (
|
||||
|
||||
"github.com/netbirdio/management-integrations/integrations"
|
||||
"github.com/netbirdio/netbird/management/internals/modules/peers"
|
||||
"github.com/netbirdio/netbird/management/internals/modules/services"
|
||||
nbservices "github.com/netbirdio/netbird/management/internals/modules/services/manager"
|
||||
"github.com/netbirdio/netbird/management/internals/modules/zones"
|
||||
zonesManager "github.com/netbirdio/netbird/management/internals/modules/zones/manager"
|
||||
"github.com/netbirdio/netbird/management/internals/modules/zones/records"
|
||||
@@ -174,3 +176,9 @@ func (s *BaseServer) RecordsManager() records.Manager {
|
||||
return recordsManager.NewManager(s.Store(), s.AccountManager(), s.PermissionsManager())
|
||||
})
|
||||
}
|
||||
|
||||
func (s *BaseServer) ServiceManager() services.Manager {
|
||||
return Create(s, func() services.Manager {
|
||||
return nbservices.NewManager(s.Store(), s.AccountManager(), s.PermissionsManager())
|
||||
})
|
||||
}
|
||||
|
||||
@@ -195,6 +195,10 @@ const (
|
||||
DNSRecordUpdated Activity = 100
|
||||
DNSRecordDeleted Activity = 101
|
||||
|
||||
ServiceCreated Activity = 102
|
||||
ServiceUpdated Activity = 103
|
||||
ServiceDeleted Activity = 104
|
||||
|
||||
AccountDeleted Activity = 99999
|
||||
)
|
||||
|
||||
@@ -319,6 +323,10 @@ var activityMap = map[Activity]Code{
|
||||
DNSRecordCreated: {"DNS zone record created", "dns.zone.record.create"},
|
||||
DNSRecordUpdated: {"DNS zone record updated", "dns.zone.record.update"},
|
||||
DNSRecordDeleted: {"DNS zone record deleted", "dns.zone.record.delete"},
|
||||
|
||||
ServiceCreated: {"Service created", "service.create"},
|
||||
ServiceUpdated: {"Service updated", "service.update"},
|
||||
ServiceDeleted: {"Service deleted", "service.delete"},
|
||||
}
|
||||
|
||||
// StringCode returns a string code of the activity
|
||||
|
||||
@@ -9,10 +9,13 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
idpmanager "github.com/netbirdio/netbird/management/server/idp"
|
||||
"github.com/rs/cors"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
nbservices "github.com/netbirdio/netbird/management/internals/modules/services"
|
||||
services "github.com/netbirdio/netbird/management/internals/modules/services/manager"
|
||||
idpmanager "github.com/netbirdio/netbird/management/server/idp"
|
||||
|
||||
"github.com/netbirdio/management-integrations/integrations"
|
||||
"github.com/netbirdio/netbird/management/internals/controllers/network_map"
|
||||
"github.com/netbirdio/netbird/management/internals/modules/zones"
|
||||
@@ -59,7 +62,7 @@ const (
|
||||
)
|
||||
|
||||
// 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) (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, serviceManager nbservices.Manager) (http.Handler, error) {
|
||||
|
||||
// Register bypass paths for unauthenticated endpoints
|
||||
if err := bypass.AddBypassPath("/api/instance"); err != nil {
|
||||
@@ -145,6 +148,7 @@ func NewAPIHandler(ctx context.Context, accountManager account.Manager, networks
|
||||
recordsManager.RegisterEndpoints(router, rManager)
|
||||
idp.AddEndpoints(accountManager, router)
|
||||
instance.AddEndpoints(instanceManager, router)
|
||||
services.RegisterEndpoints(router, serviceManager)
|
||||
|
||||
// Mount embedded IdP handler at /oauth2 path if configured
|
||||
if embeddedIdpEnabled {
|
||||
|
||||
@@ -17,6 +17,7 @@ const (
|
||||
SetupKeys Module = "setup_keys"
|
||||
Pats Module = "pats"
|
||||
IdentityProviders Module = "identity_providers"
|
||||
Services Module = "services"
|
||||
)
|
||||
|
||||
var All = map[Module]struct{}{
|
||||
|
||||
@@ -27,6 +27,7 @@ import (
|
||||
"gorm.io/gorm/logger"
|
||||
|
||||
nbdns "github.com/netbirdio/netbird/dns"
|
||||
"github.com/netbirdio/netbird/management/internals/modules/services"
|
||||
"github.com/netbirdio/netbird/management/internals/modules/zones"
|
||||
"github.com/netbirdio/netbird/management/internals/modules/zones/records"
|
||||
resourceTypes "github.com/netbirdio/netbird/management/server/networks/resources/types"
|
||||
@@ -125,7 +126,7 @@ func NewSqlStore(ctx context.Context, db *gorm.DB, storeEngine types.Engine, met
|
||||
&types.Account{}, &types.Policy{}, &types.PolicyRule{}, &route.Route{}, &nbdns.NameServerGroup{},
|
||||
&installation{}, &types.ExtraSettings{}, &posture.Checks{}, &nbpeer.NetworkAddress{},
|
||||
&networkTypes.Network{}, &routerTypes.NetworkRouter{}, &resourceTypes.NetworkResource{}, &types.AccountOnboarding{},
|
||||
&zones.Zone{}, &records.Record{},
|
||||
&zones.Zone{}, &records.Record{}, &services.Service{},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("auto migratePreAuto: %w", err)
|
||||
@@ -4363,3 +4364,88 @@ func (s *SqlStore) DeleteZoneDNSRecords(ctx context.Context, accountID, zoneID s
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SqlStore) CreateService(ctx context.Context, service *services.Service) error {
|
||||
result := s.db.Create(service)
|
||||
if result.Error != nil {
|
||||
log.WithContext(ctx).Errorf("failed to create service to store: %v", result.Error)
|
||||
return status.Errorf(status.Internal, "failed to create service to store")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SqlStore) UpdateService(ctx context.Context, service *services.Service) error {
|
||||
result := s.db.Select("*").Save(service)
|
||||
if result.Error != nil {
|
||||
log.WithContext(ctx).Errorf("failed to update service to store: %v", result.Error)
|
||||
return status.Errorf(status.Internal, "failed to update service to store")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SqlStore) DeleteService(ctx context.Context, accountID, serviceID string) error {
|
||||
result := s.db.Delete(&services.Service{}, accountAndIDQueryCondition, accountID, serviceID)
|
||||
if result.Error != nil {
|
||||
log.WithContext(ctx).Errorf("failed to delete service from store: %v", result.Error)
|
||||
return status.Errorf(status.Internal, "failed to delete service from store")
|
||||
}
|
||||
|
||||
if result.RowsAffected == 0 {
|
||||
return status.Errorf(status.NotFound, "service %s not found", serviceID)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SqlStore) GetServiceByID(ctx context.Context, lockStrength LockingStrength, accountID, serviceID string) (*services.Service, error) {
|
||||
tx := s.db
|
||||
if lockStrength != LockingStrengthNone {
|
||||
tx = tx.Clauses(clause.Locking{Strength: string(lockStrength)})
|
||||
}
|
||||
|
||||
var service *services.Service
|
||||
result := tx.Take(&service, accountAndIDQueryCondition, accountID, serviceID)
|
||||
if result.Error != nil {
|
||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||
return nil, status.Errorf(status.NotFound, "service %s not found", serviceID)
|
||||
}
|
||||
|
||||
log.WithContext(ctx).Errorf("failed to get service from store: %v", result.Error)
|
||||
return nil, status.Errorf(status.Internal, "failed to get service from store")
|
||||
}
|
||||
|
||||
return service, nil
|
||||
}
|
||||
|
||||
func (s *SqlStore) GetServiceByDomain(ctx context.Context, accountID, domain string) (*services.Service, error) {
|
||||
var service *services.Service
|
||||
result := s.db.Where("account_id = ? AND domain = ?", accountID, domain).First(&service)
|
||||
if result.Error != nil {
|
||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||
return nil, status.Errorf(status.NotFound, "service with domain %s not found", domain)
|
||||
}
|
||||
|
||||
log.WithContext(ctx).Errorf("failed to get service by domain from store: %v", result.Error)
|
||||
return nil, status.Errorf(status.Internal, "failed to get service by domain from store")
|
||||
}
|
||||
|
||||
return service, nil
|
||||
}
|
||||
|
||||
func (s *SqlStore) GetAccountServices(ctx context.Context, lockStrength LockingStrength, accountID string) ([]*services.Service, error) {
|
||||
tx := s.db
|
||||
if lockStrength != LockingStrengthNone {
|
||||
tx = tx.Clauses(clause.Locking{Strength: string(lockStrength)})
|
||||
}
|
||||
|
||||
var servicesList []*services.Service
|
||||
result := tx.Find(&servicesList, accountIDCondition, accountID)
|
||||
if result.Error != nil {
|
||||
log.WithContext(ctx).Errorf("failed to get services from the store: %s", result.Error)
|
||||
return nil, status.Errorf(status.Internal, "failed to get services from store")
|
||||
}
|
||||
|
||||
return servicesList, nil
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/netbirdio/netbird/dns"
|
||||
"github.com/netbirdio/netbird/management/internals/modules/services"
|
||||
"github.com/netbirdio/netbird/management/internals/modules/zones"
|
||||
"github.com/netbirdio/netbird/management/internals/modules/zones/records"
|
||||
"github.com/netbirdio/netbird/management/server/telemetry"
|
||||
@@ -226,6 +227,13 @@ type Store interface {
|
||||
GetZoneDNSRecords(ctx context.Context, lockStrength LockingStrength, accountID, zoneID string) ([]*records.Record, error)
|
||||
GetZoneDNSRecordsByName(ctx context.Context, lockStrength LockingStrength, accountID, zoneID, name string) ([]*records.Record, error)
|
||||
DeleteZoneDNSRecords(ctx context.Context, accountID, zoneID string) error
|
||||
|
||||
CreateService(ctx context.Context, service *services.Service) error
|
||||
UpdateService(ctx context.Context, service *services.Service) error
|
||||
DeleteService(ctx context.Context, accountID, serviceID string) error
|
||||
GetServiceByID(ctx context.Context, lockStrength LockingStrength, accountID, serviceID string) (*services.Service, error)
|
||||
GetServiceByDomain(ctx context.Context, accountID, domain string) (*services.Service, error)
|
||||
GetAccountServices(ctx context.Context, lockStrength LockingStrength, accountID string) ([]*services.Service, error)
|
||||
}
|
||||
|
||||
const (
|
||||
|
||||
@@ -36,6 +36,8 @@ tags:
|
||||
x-cloud-only: true
|
||||
- name: Identity Providers
|
||||
description: Interact with and view information about identity providers.
|
||||
- name: Services
|
||||
description: Interact with and view information about exposed services.
|
||||
- name: Instance
|
||||
description: Instance setup and status endpoints for initial configuration.
|
||||
components:
|
||||
@@ -1905,7 +1907,8 @@ components:
|
||||
"route.add", "route.delete", "route.update",
|
||||
"nameserver.group.add", "nameserver.group.delete", "nameserver.group.update",
|
||||
"peer.ssh.disable", "peer.ssh.enable", "peer.rename", "peer.login.expiration.disable", "peer.login.expiration.enable", "peer.login.expire",
|
||||
"service.user.create", "personal.access.token.create", "service.user.delete", "personal.access.token.delete" ]
|
||||
"service.user.create", "personal.access.token.create", "service.user.delete", "personal.access.token.delete",
|
||||
"service.create", "service.update", "service.delete" ]
|
||||
example: route.add
|
||||
initiator_id:
|
||||
description: The ID of the initiator of the event. E.g., an ID of a user that triggered the event.
|
||||
@@ -2428,6 +2431,147 @@ components:
|
||||
- issuer
|
||||
- client_id
|
||||
- client_secret
|
||||
Service:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
description: Service ID
|
||||
name:
|
||||
type: string
|
||||
description: Service name
|
||||
description:
|
||||
type: string
|
||||
description: Service description
|
||||
domain:
|
||||
type: string
|
||||
description: Domain for the service
|
||||
targets:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/ServiceTarget'
|
||||
description: List of target backends for this service
|
||||
distribution_groups:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
description: List of group IDs that can access this service
|
||||
enabled:
|
||||
type: boolean
|
||||
description: Whether the service is enabled
|
||||
exposed:
|
||||
type: boolean
|
||||
description: Whether the service is exposed
|
||||
auth:
|
||||
$ref: '#/components/schemas/ServiceAuthConfig'
|
||||
required:
|
||||
- id
|
||||
- name
|
||||
- domain
|
||||
- targets
|
||||
- distribution_groups
|
||||
- enabled
|
||||
- exposed
|
||||
ServiceRequest:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
description: Service name
|
||||
description:
|
||||
type: string
|
||||
description: Service description
|
||||
domain:
|
||||
type: string
|
||||
description: Domain for the service
|
||||
targets:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/ServiceTarget'
|
||||
description: List of target backends for this service
|
||||
distribution_groups:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
description: List of group IDs that can access this service
|
||||
enabled:
|
||||
type: boolean
|
||||
description: Whether the service is enabled
|
||||
default: true
|
||||
exposed:
|
||||
type: boolean
|
||||
description: Whether the service is exposed
|
||||
default: false
|
||||
auth:
|
||||
$ref: '#/components/schemas/ServiceAuthConfig'
|
||||
required:
|
||||
- name
|
||||
- domain
|
||||
- targets
|
||||
- distribution_groups
|
||||
ServiceTarget:
|
||||
type: object
|
||||
properties:
|
||||
path:
|
||||
type: string
|
||||
description: URL path prefix for this target
|
||||
host:
|
||||
type: string
|
||||
description: Backend host:port for this target
|
||||
enabled:
|
||||
type: boolean
|
||||
description: Whether this target is enabled
|
||||
required:
|
||||
- path
|
||||
- host
|
||||
- enabled
|
||||
ServiceAuthConfig:
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
type: string
|
||||
enum: [basic, pin, bearer]
|
||||
description: Authentication type
|
||||
basic_auth:
|
||||
$ref: '#/components/schemas/BasicAuthConfig'
|
||||
pin_auth:
|
||||
$ref: '#/components/schemas/PINAuthConfig'
|
||||
bearer_auth:
|
||||
$ref: '#/components/schemas/BearerAuthConfig'
|
||||
required:
|
||||
- type
|
||||
BasicAuthConfig:
|
||||
type: object
|
||||
properties:
|
||||
username:
|
||||
type: string
|
||||
description: Basic auth username
|
||||
password:
|
||||
type: string
|
||||
description: Basic auth password
|
||||
required:
|
||||
- username
|
||||
- password
|
||||
PINAuthConfig:
|
||||
type: object
|
||||
properties:
|
||||
pin:
|
||||
type: string
|
||||
description: PIN value
|
||||
header:
|
||||
type: string
|
||||
description: HTTP header name for PIN
|
||||
required:
|
||||
- pin
|
||||
- header
|
||||
BearerAuthConfig:
|
||||
type: object
|
||||
properties:
|
||||
enabled:
|
||||
type: boolean
|
||||
description: Whether bearer auth is enabled
|
||||
required:
|
||||
- enabled
|
||||
InstanceStatus:
|
||||
type: object
|
||||
description: Instance status information
|
||||
@@ -5629,3 +5773,150 @@ paths:
|
||||
"$ref": "#/components/responses/forbidden"
|
||||
'500':
|
||||
"$ref": "#/components/responses/internal_error"
|
||||
/api/services:
|
||||
get:
|
||||
summary: List all Services
|
||||
description: Returns a list of all exposed services
|
||||
tags: [ Services ]
|
||||
security:
|
||||
- BearerAuth: [ ]
|
||||
- TokenAuth: [ ]
|
||||
responses:
|
||||
'200':
|
||||
description: A JSON Array of Services
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/Service'
|
||||
'401':
|
||||
"$ref": "#/components/responses/requires_authentication"
|
||||
'403':
|
||||
"$ref": "#/components/responses/forbidden"
|
||||
'500':
|
||||
"$ref": "#/components/responses/internal_error"
|
||||
post:
|
||||
summary: Create a Service
|
||||
description: Creates a new exposed service
|
||||
tags: [ Services ]
|
||||
security:
|
||||
- BearerAuth: [ ]
|
||||
- TokenAuth: [ ]
|
||||
requestBody:
|
||||
description: New service request
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ServiceRequest'
|
||||
responses:
|
||||
'200':
|
||||
description: Service created
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Service'
|
||||
'400':
|
||||
"$ref": "#/components/responses/bad_request"
|
||||
'401':
|
||||
"$ref": "#/components/responses/requires_authentication"
|
||||
'403':
|
||||
"$ref": "#/components/responses/forbidden"
|
||||
'500':
|
||||
"$ref": "#/components/responses/internal_error"
|
||||
/api/services/{serviceId}:
|
||||
get:
|
||||
summary: Retrieve a Service
|
||||
description: Get information about a specific service
|
||||
tags: [ Services ]
|
||||
security:
|
||||
- BearerAuth: [ ]
|
||||
- TokenAuth: [ ]
|
||||
parameters:
|
||||
- in: path
|
||||
name: serviceId
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
description: The unique identifier of a service
|
||||
responses:
|
||||
'200':
|
||||
description: A Service object
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Service'
|
||||
'400':
|
||||
"$ref": "#/components/responses/bad_request"
|
||||
'401':
|
||||
"$ref": "#/components/responses/requires_authentication"
|
||||
'403':
|
||||
"$ref": "#/components/responses/forbidden"
|
||||
'404':
|
||||
"$ref": "#/components/responses/not_found"
|
||||
'500':
|
||||
"$ref": "#/components/responses/internal_error"
|
||||
put:
|
||||
summary: Update a Service
|
||||
description: Update an existing service configuration
|
||||
tags: [ Services ]
|
||||
security:
|
||||
- BearerAuth: [ ]
|
||||
- TokenAuth: [ ]
|
||||
parameters:
|
||||
- in: path
|
||||
name: serviceId
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
description: The unique identifier of a service
|
||||
requestBody:
|
||||
description: Service update request
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ServiceRequest'
|
||||
responses:
|
||||
'200':
|
||||
description: Service updated
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Service'
|
||||
'400':
|
||||
"$ref": "#/components/responses/bad_request"
|
||||
'401':
|
||||
"$ref": "#/components/responses/requires_authentication"
|
||||
'403':
|
||||
"$ref": "#/components/responses/forbidden"
|
||||
'404':
|
||||
"$ref": "#/components/responses/not_found"
|
||||
'500':
|
||||
"$ref": "#/components/responses/internal_error"
|
||||
delete:
|
||||
summary: Delete a Service
|
||||
description: Delete an existing service
|
||||
tags: [ Services ]
|
||||
security:
|
||||
- BearerAuth: [ ]
|
||||
- TokenAuth: [ ]
|
||||
parameters:
|
||||
- in: path
|
||||
name: serviceId
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
description: The unique identifier of a service
|
||||
responses:
|
||||
'200':
|
||||
description: Service deleted
|
||||
'400':
|
||||
"$ref": "#/components/responses/bad_request"
|
||||
'401':
|
||||
"$ref": "#/components/responses/requires_authentication"
|
||||
'403':
|
||||
"$ref": "#/components/responses/forbidden"
|
||||
'404':
|
||||
"$ref": "#/components/responses/not_found"
|
||||
'500':
|
||||
"$ref": "#/components/responses/internal_error"
|
||||
|
||||
@@ -193,6 +193,13 @@ const (
|
||||
ResourceTypeSubnet ResourceType = "subnet"
|
||||
)
|
||||
|
||||
// Defines values for ServiceAuthConfigType.
|
||||
const (
|
||||
ServiceAuthConfigTypeBasic ServiceAuthConfigType = "basic"
|
||||
ServiceAuthConfigTypeBearer ServiceAuthConfigType = "bearer"
|
||||
ServiceAuthConfigTypePin ServiceAuthConfigType = "pin"
|
||||
)
|
||||
|
||||
// Defines values for UserStatus.
|
||||
const (
|
||||
UserStatusActive UserStatus = "active"
|
||||
@@ -368,6 +375,21 @@ type AvailablePorts struct {
|
||||
Udp int `json:"udp"`
|
||||
}
|
||||
|
||||
// BasicAuthConfig defines model for BasicAuthConfig.
|
||||
type BasicAuthConfig struct {
|
||||
// Password Basic auth password
|
||||
Password string `json:"password"`
|
||||
|
||||
// Username Basic auth username
|
||||
Username string `json:"username"`
|
||||
}
|
||||
|
||||
// BearerAuthConfig defines model for BearerAuthConfig.
|
||||
type BearerAuthConfig struct {
|
||||
// Enabled Whether bearer auth is enabled
|
||||
Enabled bool `json:"enabled"`
|
||||
}
|
||||
|
||||
// Checks List of objects that perform the actual checks
|
||||
type Checks struct {
|
||||
// GeoLocationCheck Posture check for geo location
|
||||
@@ -1125,6 +1147,15 @@ type OSVersionCheck struct {
|
||||
Windows *MinKernelVersionCheck `json:"windows,omitempty"`
|
||||
}
|
||||
|
||||
// PINAuthConfig defines model for PINAuthConfig.
|
||||
type PINAuthConfig struct {
|
||||
// Header HTTP header name for PIN
|
||||
Header string `json:"header"`
|
||||
|
||||
// Pin PIN value
|
||||
Pin string `json:"pin"`
|
||||
}
|
||||
|
||||
// Peer defines model for Peer.
|
||||
type Peer struct {
|
||||
// ApprovalRequired (Cloud only) Indicates whether peer needs approval
|
||||
@@ -1785,6 +1816,86 @@ type RulePortRange struct {
|
||||
Start int `json:"start"`
|
||||
}
|
||||
|
||||
// Service defines model for Service.
|
||||
type Service struct {
|
||||
Auth *ServiceAuthConfig `json:"auth,omitempty"`
|
||||
|
||||
// Description Service description
|
||||
Description *string `json:"description,omitempty"`
|
||||
|
||||
// DistributionGroups List of group IDs that can access this service
|
||||
DistributionGroups []string `json:"distribution_groups"`
|
||||
|
||||
// Domain Domain for the service
|
||||
Domain string `json:"domain"`
|
||||
|
||||
// Enabled Whether the service is enabled
|
||||
Enabled bool `json:"enabled"`
|
||||
|
||||
// Exposed Whether the service is exposed
|
||||
Exposed bool `json:"exposed"`
|
||||
|
||||
// Id Service ID
|
||||
Id string `json:"id"`
|
||||
|
||||
// Name Service name
|
||||
Name string `json:"name"`
|
||||
|
||||
// Targets List of target backends for this service
|
||||
Targets []ServiceTarget `json:"targets"`
|
||||
}
|
||||
|
||||
// ServiceAuthConfig defines model for ServiceAuthConfig.
|
||||
type ServiceAuthConfig struct {
|
||||
BasicAuth *BasicAuthConfig `json:"basic_auth,omitempty"`
|
||||
BearerAuth *BearerAuthConfig `json:"bearer_auth,omitempty"`
|
||||
PinAuth *PINAuthConfig `json:"pin_auth,omitempty"`
|
||||
|
||||
// Type Authentication type
|
||||
Type ServiceAuthConfigType `json:"type"`
|
||||
}
|
||||
|
||||
// ServiceAuthConfigType Authentication type
|
||||
type ServiceAuthConfigType string
|
||||
|
||||
// ServiceRequest defines model for ServiceRequest.
|
||||
type ServiceRequest struct {
|
||||
Auth *ServiceAuthConfig `json:"auth,omitempty"`
|
||||
|
||||
// Description Service description
|
||||
Description *string `json:"description,omitempty"`
|
||||
|
||||
// DistributionGroups List of group IDs that can access this service
|
||||
DistributionGroups []string `json:"distribution_groups"`
|
||||
|
||||
// Domain Domain for the service
|
||||
Domain string `json:"domain"`
|
||||
|
||||
// Enabled Whether the service is enabled
|
||||
Enabled *bool `json:"enabled,omitempty"`
|
||||
|
||||
// Exposed Whether the service is exposed
|
||||
Exposed *bool `json:"exposed,omitempty"`
|
||||
|
||||
// Name Service name
|
||||
Name string `json:"name"`
|
||||
|
||||
// Targets List of target backends for this service
|
||||
Targets []ServiceTarget `json:"targets"`
|
||||
}
|
||||
|
||||
// ServiceTarget defines model for ServiceTarget.
|
||||
type ServiceTarget struct {
|
||||
// Enabled Whether this target is enabled
|
||||
Enabled bool `json:"enabled"`
|
||||
|
||||
// Host Backend host:port for this target
|
||||
Host string `json:"host"`
|
||||
|
||||
// Path URL path prefix for this target
|
||||
Path string `json:"path"`
|
||||
}
|
||||
|
||||
// SetupKey defines model for SetupKey.
|
||||
type SetupKey struct {
|
||||
// AllowExtraDnsLabels Allow extra DNS labels to be added to the peer
|
||||
@@ -2246,6 +2357,12 @@ type PostApiRoutesJSONRequestBody = RouteRequest
|
||||
// PutApiRoutesRouteIdJSONRequestBody defines body for PutApiRoutesRouteId for application/json ContentType.
|
||||
type PutApiRoutesRouteIdJSONRequestBody = RouteRequest
|
||||
|
||||
// PostApiServicesJSONRequestBody defines body for PostApiServices for application/json ContentType.
|
||||
type PostApiServicesJSONRequestBody = ServiceRequest
|
||||
|
||||
// PutApiServicesServiceIdJSONRequestBody defines body for PutApiServicesServiceId for application/json ContentType.
|
||||
type PutApiServicesServiceIdJSONRequestBody = ServiceRequest
|
||||
|
||||
// PostApiSetupJSONRequestBody defines body for PostApiSetup for application/json ContentType.
|
||||
type PostApiSetupJSONRequestBody = SetupRequest
|
||||
|
||||
|
||||
Reference in New Issue
Block a user