mirror of
https://github.com/gravitl/netmaker.git
synced 2025-10-05 16:57:51 +08:00
GRA-1298: License check changes, free tier limits for saas (#2418)
* set free tier limits through config * add host limit to config * check for host limit on free tier * fix license validation, replace node limit with hosts * add hosts to telemetry data * debug init * validate license every 1hr * hook manager, api to fetch server usage * hook manager, server usage api * encode json server usage api * update ngork url * update license validation endpoint * avoid setting limits on eer * adding hotfix * correct users limits env var * add comments to exported funcs --------- Co-authored-by: afeiszli <alex.feiszli@gmail.com>
This commit is contained in:
@@ -83,6 +83,11 @@ type ServerConfig struct {
|
|||||||
TurnUserName string `yaml:"turn_username"`
|
TurnUserName string `yaml:"turn_username"`
|
||||||
TurnPassword string `yaml:"turn_password"`
|
TurnPassword string `yaml:"turn_password"`
|
||||||
UseTurn bool `yaml:"use_turn"`
|
UseTurn bool `yaml:"use_turn"`
|
||||||
|
UsersLimit int `yaml:"user_limit"`
|
||||||
|
ClientsLimit int `yaml:"client_limit"`
|
||||||
|
NetworksLimit int `yaml:"network_limit"`
|
||||||
|
HostsLimit int `yaml:"host_limit"`
|
||||||
|
DeployedByOperator bool `yaml:"deployed_by_operator"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProxyMode - default proxy mode for server
|
// ProxyMode - default proxy mode for server
|
||||||
|
@@ -6,7 +6,6 @@ import (
|
|||||||
"github.com/gravitl/netmaker/database"
|
"github.com/gravitl/netmaker/database"
|
||||||
"github.com/gravitl/netmaker/logic"
|
"github.com/gravitl/netmaker/logic"
|
||||||
"github.com/gravitl/netmaker/models"
|
"github.com/gravitl/netmaker/models"
|
||||||
"github.com/gravitl/netmaker/servercfg"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// limit consts
|
// limit consts
|
||||||
@@ -23,20 +22,13 @@ func checkFreeTierLimits(limit_choice int, next http.Handler) http.HandlerFunc {
|
|||||||
Code: http.StatusForbidden, Message: "free tier limits exceeded on networks",
|
Code: http.StatusForbidden, Message: "free tier limits exceeded on networks",
|
||||||
}
|
}
|
||||||
|
|
||||||
if logic.Free_Tier && servercfg.Is_EE { // check that free tier limits not exceeded
|
if logic.Free_Tier { // check that free tier limits not exceeded
|
||||||
if limit_choice == networks_l {
|
if limit_choice == networks_l {
|
||||||
currentNetworks, err := logic.GetNetworks()
|
currentNetworks, err := logic.GetNetworks()
|
||||||
if (err != nil && !database.IsEmptyRecord(err)) || len(currentNetworks) >= logic.Networks_Limit {
|
if (err != nil && !database.IsEmptyRecord(err)) || len(currentNetworks) >= logic.Networks_Limit {
|
||||||
logic.ReturnErrorResponse(w, r, errorResponse)
|
logic.ReturnErrorResponse(w, r, errorResponse)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else if limit_choice == node_l {
|
|
||||||
nodes, err := logic.GetAllNodes()
|
|
||||||
if (err != nil && !database.IsEmptyRecord(err)) || len(nodes) >= logic.Node_Limit {
|
|
||||||
errorResponse.Message = "free tier limits exceeded on nodes"
|
|
||||||
logic.ReturnErrorResponse(w, r, errorResponse)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else if limit_choice == users_l {
|
} else if limit_choice == users_l {
|
||||||
users, err := logic.GetUsers()
|
users, err := logic.GetUsers()
|
||||||
if (err != nil && !database.IsEmptyRecord(err)) || len(users) >= logic.Users_Limit {
|
if (err != nil && !database.IsEmptyRecord(err)) || len(users) >= logic.Users_Limit {
|
||||||
|
@@ -22,6 +22,38 @@ func serverHandlers(r *mux.Router) {
|
|||||||
r.HandleFunc("/api/server/getconfig", allowUsers(http.HandlerFunc(getConfig))).Methods(http.MethodGet)
|
r.HandleFunc("/api/server/getconfig", allowUsers(http.HandlerFunc(getConfig))).Methods(http.MethodGet)
|
||||||
r.HandleFunc("/api/server/getserverinfo", Authorize(true, false, "node", http.HandlerFunc(getServerInfo))).Methods(http.MethodGet)
|
r.HandleFunc("/api/server/getserverinfo", Authorize(true, false, "node", http.HandlerFunc(getServerInfo))).Methods(http.MethodGet)
|
||||||
r.HandleFunc("/api/server/status", http.HandlerFunc(getStatus)).Methods(http.MethodGet)
|
r.HandleFunc("/api/server/status", http.HandlerFunc(getStatus)).Methods(http.MethodGet)
|
||||||
|
r.HandleFunc("/api/server/usage", Authorize(true, false, "user", http.HandlerFunc(getUsage))).Methods(http.MethodGet)
|
||||||
|
}
|
||||||
|
func getUsage(w http.ResponseWriter, r *http.Request) {
|
||||||
|
type usage struct {
|
||||||
|
Hosts int `json:"hosts"`
|
||||||
|
Clients int `json:"clients"`
|
||||||
|
Networks int `json:"networks"`
|
||||||
|
Users int `json:"users"`
|
||||||
|
}
|
||||||
|
var serverUsage usage
|
||||||
|
hosts, err := logic.GetAllHosts()
|
||||||
|
if err == nil {
|
||||||
|
serverUsage.Hosts = len(hosts)
|
||||||
|
}
|
||||||
|
clients, err := logic.GetAllExtClients()
|
||||||
|
if err == nil {
|
||||||
|
serverUsage.Clients = len(clients)
|
||||||
|
}
|
||||||
|
users, err := logic.GetUsers()
|
||||||
|
if err == nil {
|
||||||
|
serverUsage.Users = len(users)
|
||||||
|
}
|
||||||
|
networks, err := logic.GetNetworks()
|
||||||
|
if err == nil {
|
||||||
|
serverUsage.Networks = len(networks)
|
||||||
|
}
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
json.NewEncoder(w).Encode(models.SuccessResponse{
|
||||||
|
Code: http.StatusOK,
|
||||||
|
Response: serverUsage,
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// swagger:route GET /api/server/status server getStatus
|
// swagger:route GET /api/server/status server getStatus
|
||||||
@@ -41,6 +73,12 @@ func getStatus(w http.ResponseWriter, r *http.Request) {
|
|||||||
type status struct {
|
type status struct {
|
||||||
DB bool `json:"db_connected"`
|
DB bool `json:"db_connected"`
|
||||||
Broker bool `json:"broker_connected"`
|
Broker bool `json:"broker_connected"`
|
||||||
|
Usage struct {
|
||||||
|
Hosts int `json:"hosts"`
|
||||||
|
Clients int `json:"clients"`
|
||||||
|
Networks int `json:"networks"`
|
||||||
|
Users int `json:"users"`
|
||||||
|
} `json:"usage"`
|
||||||
}
|
}
|
||||||
|
|
||||||
currentServerStatus := status{
|
currentServerStatus := status{
|
||||||
|
@@ -16,6 +16,7 @@ import (
|
|||||||
// InitEE - Initialize EE Logic
|
// InitEE - Initialize EE Logic
|
||||||
func InitEE() {
|
func InitEE() {
|
||||||
setIsEnterprise()
|
setIsEnterprise()
|
||||||
|
servercfg.Is_EE = true
|
||||||
models.SetLogo(retrieveEELogo())
|
models.SetLogo(retrieveEELogo())
|
||||||
controller.HttpHandlers = append(
|
controller.HttpHandlers = append(
|
||||||
controller.HttpHandlers,
|
controller.HttpHandlers,
|
||||||
@@ -27,13 +28,8 @@ func InitEE() {
|
|||||||
logic.EnterpriseCheckFuncs = append(logic.EnterpriseCheckFuncs, func() {
|
logic.EnterpriseCheckFuncs = append(logic.EnterpriseCheckFuncs, func() {
|
||||||
// == License Handling ==
|
// == License Handling ==
|
||||||
ValidateLicense()
|
ValidateLicense()
|
||||||
if Limits.FreeTier {
|
|
||||||
logger.Log(0, "proceeding with Free Tier license")
|
|
||||||
logic.SetFreeTierForTelemetry(true)
|
|
||||||
} else {
|
|
||||||
logger.Log(0, "proceeding with Paid Tier license")
|
logger.Log(0, "proceeding with Paid Tier license")
|
||||||
logic.SetFreeTierForTelemetry(false)
|
logic.SetFreeTierForTelemetry(false)
|
||||||
}
|
|
||||||
// == End License Handling ==
|
// == End License Handling ==
|
||||||
AddLicenseHooks()
|
AddLicenseHooks()
|
||||||
resetFailover()
|
resetFailover()
|
||||||
@@ -46,17 +42,6 @@ func InitEE() {
|
|||||||
logic.AllowClientNodeAccess = eelogic.RemoveDeniedNodeFromClient
|
logic.AllowClientNodeAccess = eelogic.RemoveDeniedNodeFromClient
|
||||||
}
|
}
|
||||||
|
|
||||||
func setControllerLimits() {
|
|
||||||
logic.Node_Limit = Limits.Nodes
|
|
||||||
logic.Users_Limit = Limits.Users
|
|
||||||
logic.Clients_Limit = Limits.Clients
|
|
||||||
logic.Free_Tier = Limits.FreeTier
|
|
||||||
servercfg.Is_EE = true
|
|
||||||
if logic.Free_Tier {
|
|
||||||
logic.Networks_Limit = 3
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func resetFailover() {
|
func resetFailover() {
|
||||||
nets, err := logic.GetNetworks()
|
nets, err := logic.GetNetworks()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@@ -9,12 +9,13 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/gravitl/netmaker/database"
|
"github.com/gravitl/netmaker/database"
|
||||||
"github.com/gravitl/netmaker/logger"
|
"github.com/gravitl/netmaker/logger"
|
||||||
"github.com/gravitl/netmaker/logic"
|
"github.com/gravitl/netmaker/logic"
|
||||||
|
"github.com/gravitl/netmaker/models"
|
||||||
"github.com/gravitl/netmaker/netclient/ncutils"
|
"github.com/gravitl/netmaker/netclient/ncutils"
|
||||||
"github.com/gravitl/netmaker/servercfg"
|
"github.com/gravitl/netmaker/servercfg"
|
||||||
"golang.org/x/crypto/nacl/box"
|
"golang.org/x/crypto/nacl/box"
|
||||||
@@ -31,8 +32,14 @@ type apiServerConf struct {
|
|||||||
|
|
||||||
// AddLicenseHooks - adds the validation and cache clear hooks
|
// AddLicenseHooks - adds the validation and cache clear hooks
|
||||||
func AddLicenseHooks() {
|
func AddLicenseHooks() {
|
||||||
logic.AddHook(ValidateLicense)
|
logic.HookManagerCh <- models.HookDetails{
|
||||||
logic.AddHook(ClearLicenseCache)
|
Hook: ValidateLicense,
|
||||||
|
Interval: time.Hour,
|
||||||
|
}
|
||||||
|
logic.HookManagerCh <- models.HookDetails{
|
||||||
|
Hook: ClearLicenseCache,
|
||||||
|
Interval: time.Hour,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateLicense - the initial license check for netmaker server
|
// ValidateLicense - the initial license check for netmaker server
|
||||||
@@ -58,7 +65,7 @@ func ValidateLicense() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
licenseSecret := LicenseSecret{
|
licenseSecret := LicenseSecret{
|
||||||
UserID: netmakerAccountID,
|
AssociatedID: netmakerAccountID,
|
||||||
Limits: getCurrentServerLimit(),
|
Limits: getCurrentServerLimit(),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,17 +99,6 @@ func ValidateLicense() error {
|
|||||||
logger.FatalLog0(errValidation.Error())
|
logger.FatalLog0(errValidation.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
Limits.Networks = math.MaxInt
|
|
||||||
Limits.FreeTier = license.FreeTier == "yes"
|
|
||||||
Limits.Clients = license.LimitClients
|
|
||||||
Limits.Nodes = license.LimitNodes
|
|
||||||
Limits.Servers = license.LimitServers
|
|
||||||
Limits.Users = license.LimitUsers
|
|
||||||
if Limits.FreeTier {
|
|
||||||
Limits.Networks = 3
|
|
||||||
}
|
|
||||||
setControllerLimits()
|
|
||||||
|
|
||||||
logger.Log(0, "License validation succeeded!")
|
logger.Log(0, "License validation succeeded!")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -167,6 +163,7 @@ func validateLicenseKey(encryptedData []byte, publicKey *[32]byte) ([]byte, erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
msg := ValidateLicenseRequest{
|
msg := ValidateLicenseRequest{
|
||||||
|
LicenseKey: servercfg.GetLicenseKey(),
|
||||||
NmServerPubKey: base64encode(publicKeyBytes),
|
NmServerPubKey: base64encode(publicKeyBytes),
|
||||||
EncryptedPart: base64encode(encryptedData),
|
EncryptedPart: base64encode(encryptedData),
|
||||||
}
|
}
|
||||||
@@ -180,9 +177,6 @@ func validateLicenseKey(encryptedData []byte, publicKey *[32]byte) ([]byte, erro
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
reqParams := req.URL.Query()
|
|
||||||
reqParams.Add("licensevalue", servercfg.GetLicenseKey())
|
|
||||||
req.URL.RawQuery = reqParams.Encode()
|
|
||||||
req.Header.Add("Content-Type", "application/json")
|
req.Header.Add("Content-Type", "application/json")
|
||||||
req.Header.Add("Accept", "application/json")
|
req.Header.Add("Accept", "application/json")
|
||||||
client := &http.Client{}
|
client := &http.Client{}
|
||||||
|
44
ee/types.go
44
ee/types.go
@@ -3,7 +3,7 @@ package ee
|
|||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
api_endpoint = "https://api.controller.netmaker.io/api/v1/license/validate"
|
api_endpoint = "https://api.accounts.netmaker.io/api/v1/license/validate"
|
||||||
license_cache_key = "license_response_cache"
|
license_cache_key = "license_response_cache"
|
||||||
license_validation_err_msg = "invalid license"
|
license_validation_err_msg = "invalid license"
|
||||||
server_id_key = "nm-server-id"
|
server_id_key = "nm-server-id"
|
||||||
@@ -11,38 +11,17 @@ const (
|
|||||||
|
|
||||||
var errValidation = fmt.Errorf(license_validation_err_msg)
|
var errValidation = fmt.Errorf(license_validation_err_msg)
|
||||||
|
|
||||||
// Limits - limits to be referenced throughout server
|
|
||||||
var Limits = GlobalLimits{
|
|
||||||
Servers: 0,
|
|
||||||
Users: 0,
|
|
||||||
Nodes: 0,
|
|
||||||
Clients: 0,
|
|
||||||
Networks: 0,
|
|
||||||
FreeTier: false,
|
|
||||||
}
|
|
||||||
|
|
||||||
// GlobalLimits - struct for holding global limits on this netmaker server in memory
|
|
||||||
type GlobalLimits struct {
|
|
||||||
Servers int
|
|
||||||
Users int
|
|
||||||
Nodes int
|
|
||||||
Clients int
|
|
||||||
FreeTier bool
|
|
||||||
Networks int
|
|
||||||
}
|
|
||||||
|
|
||||||
// LicenseKey - the license key struct representation with associated data
|
// LicenseKey - the license key struct representation with associated data
|
||||||
type LicenseKey struct {
|
type LicenseKey struct {
|
||||||
LicenseValue string `json:"license_value"` // actual (public) key and the unique value for the key
|
LicenseValue string `json:"license_value"` // actual (public) key and the unique value for the key
|
||||||
Expiration int64 `json:"expiration"`
|
Expiration int64 `json:"expiration"`
|
||||||
LimitServers int `json:"limit_servers"`
|
LimitServers int `json:"limit_servers"`
|
||||||
LimitUsers int `json:"limit_users"`
|
LimitUsers int `json:"limit_users"`
|
||||||
LimitNodes int `json:"limit_nodes"`
|
LimitHosts int `json:"limit_hosts"`
|
||||||
|
LimitNetworks int `json:"limit_networks"`
|
||||||
LimitClients int `json:"limit_clients"`
|
LimitClients int `json:"limit_clients"`
|
||||||
Metadata string `json:"metadata"`
|
Metadata string `json:"metadata"`
|
||||||
SubscriptionID string `json:"subscription_id"` // for a paid subscription (non-free-tier license)
|
IsActive bool `json:"is_active"` // yes if active
|
||||||
FreeTier string `json:"free_tier"` // yes if free tier
|
|
||||||
IsActive string `json:"is_active"` // yes if active
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidatedLicense - the validated license struct
|
// ValidatedLicense - the validated license struct
|
||||||
@@ -53,28 +32,31 @@ type ValidatedLicense struct {
|
|||||||
|
|
||||||
// LicenseSecret - the encrypted struct for sending user-id
|
// LicenseSecret - the encrypted struct for sending user-id
|
||||||
type LicenseSecret struct {
|
type LicenseSecret struct {
|
||||||
UserID string `json:"user_id" binding:"required"` // UUID for user foreign key to User table
|
AssociatedID string `json:"associated_id" binding:"required"` // UUID for user foreign key to User table
|
||||||
Limits LicenseLimits `json:"limits" binding:"required"`
|
Limits LicenseLimits `json:"limits" binding:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// LicenseLimits - struct license limits
|
// LicenseLimits - struct license limits
|
||||||
type LicenseLimits struct {
|
type LicenseLimits struct {
|
||||||
Servers int `json:"servers" binding:"required"`
|
Servers int `json:"servers"`
|
||||||
Users int `json:"users" binding:"required"`
|
Users int `json:"users"`
|
||||||
Nodes int `json:"nodes" binding:"required"`
|
Hosts int `json:"hosts"`
|
||||||
Clients int `json:"clients" binding:"required"`
|
Clients int `json:"clients"`
|
||||||
|
Networks int `json:"networks"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// LicenseLimits.SetDefaults - sets the default values for limits
|
// LicenseLimits.SetDefaults - sets the default values for limits
|
||||||
func (l *LicenseLimits) SetDefaults() {
|
func (l *LicenseLimits) SetDefaults() {
|
||||||
l.Clients = 0
|
l.Clients = 0
|
||||||
l.Servers = 1
|
l.Servers = 1
|
||||||
l.Nodes = 0
|
l.Hosts = 0
|
||||||
l.Users = 1
|
l.Users = 1
|
||||||
|
l.Networks = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateLicenseRequest - used for request to validate license endpoint
|
// ValidateLicenseRequest - used for request to validate license endpoint
|
||||||
type ValidateLicenseRequest struct {
|
type ValidateLicenseRequest struct {
|
||||||
|
LicenseKey string `json:"license_key" binding:"required"`
|
||||||
NmServerPubKey string `json:"nm_server_pub_key" binding:"required"` // Netmaker server public key used to send data back to Netmaker for the Netmaker server to decrypt (eg output from validating license)
|
NmServerPubKey string `json:"nm_server_pub_key" binding:"required"` // Netmaker server public key used to send data back to Netmaker for the Netmaker server to decrypt (eg output from validating license)
|
||||||
EncryptedPart string `json:"secret" binding:"required"`
|
EncryptedPart string `json:"secret" binding:"required"`
|
||||||
}
|
}
|
||||||
|
@@ -30,12 +30,11 @@ func base64decode(input string) []byte {
|
|||||||
|
|
||||||
return bytes
|
return bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
func getCurrentServerLimit() (limits LicenseLimits) {
|
func getCurrentServerLimit() (limits LicenseLimits) {
|
||||||
limits.SetDefaults()
|
limits.SetDefaults()
|
||||||
nodes, err := logic.GetAllNodes()
|
hosts, err := logic.GetAllHosts()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
limits.Nodes = len(nodes)
|
limits.Hosts = len(hosts)
|
||||||
}
|
}
|
||||||
clients, err := logic.GetAllExtClients()
|
clients, err := logic.GetAllExtClients()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@@ -45,5 +44,9 @@ func getCurrentServerLimit() (limits LicenseLimits) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
limits.Users = len(users)
|
limits.Users = len(users)
|
||||||
}
|
}
|
||||||
|
networks, err := logic.GetNetworks()
|
||||||
|
if err == nil {
|
||||||
|
limits.Networks = len(networks)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@@ -93,7 +93,14 @@ func GetHost(hostid string) (*models.Host, error) {
|
|||||||
|
|
||||||
// CreateHost - creates a host if not exist
|
// CreateHost - creates a host if not exist
|
||||||
func CreateHost(h *models.Host) error {
|
func CreateHost(h *models.Host) error {
|
||||||
_, err := GetHost(h.ID.String())
|
hosts, err := GetAllHosts()
|
||||||
|
if err != nil && !database.IsEmptyRecord(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(hosts) >= Hosts_Limit {
|
||||||
|
return errors.New("free tier limits exceeded on hosts")
|
||||||
|
}
|
||||||
|
_, err = GetHost(h.ID.String())
|
||||||
if (err != nil && !database.IsEmptyRecord(err)) || (err == nil) {
|
if (err != nil && !database.IsEmptyRecord(err)) || (err == nil) {
|
||||||
return ErrHostExists
|
return ErrHostExists
|
||||||
}
|
}
|
||||||
|
@@ -4,17 +4,18 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/gravitl/netmaker/database"
|
"github.com/gravitl/netmaker/database"
|
||||||
|
"github.com/gravitl/netmaker/servercfg"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// Node_Limit - dummy var for community
|
|
||||||
Node_Limit = 1000000000
|
|
||||||
// Networks_Limit - dummy var for community
|
// Networks_Limit - dummy var for community
|
||||||
Networks_Limit = 1000000000
|
Networks_Limit = 1000000000
|
||||||
// Users_Limit - dummy var for community
|
// Users_Limit - dummy var for community
|
||||||
Users_Limit = 1000000000
|
Users_Limit = 1000000000
|
||||||
// Clients_Limit - dummy var for community
|
// Clients_Limit - dummy var for community
|
||||||
Clients_Limit = 1000000000
|
Clients_Limit = 1000000000
|
||||||
|
// Hosts_Limit - dummy var for community
|
||||||
|
Hosts_Limit = 1000000000
|
||||||
// Free_Tier - specifies if free tier
|
// Free_Tier - specifies if free tier
|
||||||
Free_Tier = false
|
Free_Tier = false
|
||||||
)
|
)
|
||||||
@@ -85,3 +86,11 @@ func StoreJWTSecret(privateKey string) error {
|
|||||||
}
|
}
|
||||||
return database.Insert("nm-jwt-secret", string(data), database.SERVERCONF_TABLE_NAME)
|
return database.Insert("nm-jwt-secret", string(data), database.SERVERCONF_TABLE_NAME)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SetFreeTierLimits() {
|
||||||
|
Free_Tier = true
|
||||||
|
Users_Limit = servercfg.GetUserLimit()
|
||||||
|
Clients_Limit = servercfg.GetClientLimit()
|
||||||
|
Networks_Limit = servercfg.GetNetworkLimit()
|
||||||
|
Hosts_Limit = servercfg.GetHostLimit()
|
||||||
|
}
|
||||||
|
@@ -60,6 +60,7 @@ func sendTelemetry() error {
|
|||||||
Event: "daily checkin",
|
Event: "daily checkin",
|
||||||
Properties: posthog.NewProperties().
|
Properties: posthog.NewProperties().
|
||||||
Set("nodes", d.Nodes).
|
Set("nodes", d.Nodes).
|
||||||
|
Set("hosts", d.Hosts).
|
||||||
Set("servers", d.Servers).
|
Set("servers", d.Servers).
|
||||||
Set("non-server nodes", d.Count.NonServer).
|
Set("non-server nodes", d.Count.NonServer).
|
||||||
Set("extclients", d.ExtClients).
|
Set("extclients", d.ExtClients).
|
||||||
@@ -84,6 +85,7 @@ func fetchTelemetryData() (telemetryData, error) {
|
|||||||
data.ExtClients = getDBLength(database.EXT_CLIENT_TABLE_NAME)
|
data.ExtClients = getDBLength(database.EXT_CLIENT_TABLE_NAME)
|
||||||
data.Users = getDBLength(database.USERS_TABLE_NAME)
|
data.Users = getDBLength(database.USERS_TABLE_NAME)
|
||||||
data.Networks = getDBLength(database.NETWORKS_TABLE_NAME)
|
data.Networks = getDBLength(database.NETWORKS_TABLE_NAME)
|
||||||
|
data.Hosts = getDBLength(database.HOSTS_TABLE_NAME)
|
||||||
data.Version = servercfg.GetVersion()
|
data.Version = servercfg.GetVersion()
|
||||||
data.Servers = getServerCount()
|
data.Servers = getServerCount()
|
||||||
nodes, err := GetAllNodes()
|
nodes, err := GetAllNodes()
|
||||||
@@ -167,6 +169,7 @@ func getDBLength(dbname string) int {
|
|||||||
// telemetryData - What data to send to posthog
|
// telemetryData - What data to send to posthog
|
||||||
type telemetryData struct {
|
type telemetryData struct {
|
||||||
Nodes int
|
Nodes int
|
||||||
|
Hosts int
|
||||||
ExtClients int
|
ExtClients int
|
||||||
Users int
|
Users int
|
||||||
Count clientCount
|
Count clientCount
|
||||||
|
@@ -1,10 +1,13 @@
|
|||||||
package logic
|
package logic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gravitl/netmaker/logger"
|
"github.com/gravitl/netmaker/logger"
|
||||||
|
"github.com/gravitl/netmaker/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
// == Constants ==
|
// == Constants ==
|
||||||
@@ -12,6 +15,9 @@ import (
|
|||||||
// How long to wait before sending telemetry to server (24 hours)
|
// How long to wait before sending telemetry to server (24 hours)
|
||||||
const timer_hours_between_runs = 24
|
const timer_hours_between_runs = 24
|
||||||
|
|
||||||
|
// HookManagerCh - channel to add any new hooks
|
||||||
|
var HookManagerCh = make(chan models.HookDetails, 2)
|
||||||
|
|
||||||
// == Public ==
|
// == Public ==
|
||||||
|
|
||||||
// TimerCheckpoint - Checks if 24 hours has passed since telemetry was last sent. If so, sends telemetry data to posthog
|
// TimerCheckpoint - Checks if 24 hours has passed since telemetry was last sent. If so, sends telemetry data to posthog
|
||||||
@@ -40,6 +46,36 @@ func AddHook(ifaceToAdd interface{}) {
|
|||||||
timeHooks = append(timeHooks, ifaceToAdd)
|
timeHooks = append(timeHooks, ifaceToAdd)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StartHookManager - listens on `HookManagerCh` to run any hook
|
||||||
|
func StartHookManager(ctx context.Context, wg *sync.WaitGroup) {
|
||||||
|
defer wg.Done()
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
logger.Log(0, "## Stopping Hook Manager")
|
||||||
|
return
|
||||||
|
case newhook := <-HookManagerCh:
|
||||||
|
wg.Add(1)
|
||||||
|
go addHookWithInterval(ctx, wg, newhook.Hook, newhook.Interval)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func addHookWithInterval(ctx context.Context, wg *sync.WaitGroup, hook func() error, interval time.Duration) {
|
||||||
|
defer wg.Done()
|
||||||
|
ticker := time.NewTicker(interval)
|
||||||
|
defer ticker.Stop()
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
case <-ticker.C:
|
||||||
|
hook()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// == private ==
|
// == private ==
|
||||||
|
|
||||||
// timeHooks - functions to run once a day, functions must take no parameters
|
// timeHooks - functions to run once a day, functions must take no parameters
|
||||||
|
7
main.go
7
main.go
@@ -42,6 +42,9 @@ func main() {
|
|||||||
initialize() // initial db and acls
|
initialize() // initial db and acls
|
||||||
setGarbageCollection()
|
setGarbageCollection()
|
||||||
setVerbosity()
|
setVerbosity()
|
||||||
|
if servercfg.DeployedByOperator() && !servercfg.Is_EE {
|
||||||
|
logic.SetFreeTierLimits()
|
||||||
|
}
|
||||||
defer database.CloseDB()
|
defer database.CloseDB()
|
||||||
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGTERM, os.Interrupt)
|
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGTERM, os.Interrupt)
|
||||||
defer stop()
|
defer stop()
|
||||||
@@ -89,7 +92,6 @@ func initialize() { // Client Mode Prereq Check
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Log(1, "Timer error occurred: ", err.Error())
|
logger.Log(1, "Timer error occurred: ", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
logic.EnterpriseCheck()
|
logic.EnterpriseCheck()
|
||||||
|
|
||||||
var authProvider = auth.InitializeAuthProvider()
|
var authProvider = auth.InitializeAuthProvider()
|
||||||
@@ -150,6 +152,9 @@ func startControllers(wg *sync.WaitGroup, ctx context.Context) {
|
|||||||
// starts the stun server
|
// starts the stun server
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go stunserver.Start(wg, ctx)
|
go stunserver.Start(wg, ctx)
|
||||||
|
|
||||||
|
wg.Add(1)
|
||||||
|
go logic.StartHookManager(ctx, wg)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should we be using a context vice a waitgroup????????????
|
// Should we be using a context vice a waitgroup????????????
|
||||||
|
@@ -2,6 +2,7 @@ package models
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
jwt "github.com/golang-jwt/jwt/v4"
|
jwt "github.com/golang-jwt/jwt/v4"
|
||||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||||
@@ -274,3 +275,18 @@ type StunServer struct {
|
|||||||
Domain string `json:"domain" yaml:"domain"`
|
Domain string `json:"domain" yaml:"domain"`
|
||||||
Port int `json:"port" yaml:"port"`
|
Port int `json:"port" yaml:"port"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HookDetails - struct to hold hook info
|
||||||
|
type HookDetails struct {
|
||||||
|
Hook func() error
|
||||||
|
Interval time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
// LicenseLimits - struct license limits
|
||||||
|
type LicenseLimits struct {
|
||||||
|
Servers int `json:"servers"`
|
||||||
|
Users int `json:"users"`
|
||||||
|
Hosts int `json:"hosts"`
|
||||||
|
Clients int `json:"clients"`
|
||||||
|
Networks int `json:"networks"`
|
||||||
|
}
|
||||||
|
@@ -6,11 +6,14 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/gravitl/netmaker/servercfg"
|
"github.com/gravitl/netmaker/servercfg"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const already_exists = "ALREADY_EXISTS"
|
||||||
|
|
||||||
type (
|
type (
|
||||||
emqxUser struct {
|
emqxUser struct {
|
||||||
UserID string `json:"user_id"`
|
UserID string `json:"user_id"`
|
||||||
@@ -99,8 +102,10 @@ func CreateEmqxUser(username, password string, admin bool) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if !strings.Contains(string(msg), already_exists) {
|
||||||
return fmt.Errorf("error creating EMQX user %v", string(msg))
|
return fmt.Errorf("error creating EMQX user %v", string(msg))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -10,6 +10,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gravitl/netmaker/config"
|
"github.com/gravitl/netmaker/config"
|
||||||
|
|
||||||
"github.com/gravitl/netmaker/models"
|
"github.com/gravitl/netmaker/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -741,6 +742,58 @@ func IsProxyEnabled() bool {
|
|||||||
return enabled
|
return enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetNetworkLimit - fetches free tier limits on users
|
||||||
|
func GetUserLimit() int {
|
||||||
|
var userslimit int
|
||||||
|
if os.Getenv("USERS_LIMIT") != "" {
|
||||||
|
userslimit, _ = strconv.Atoi(os.Getenv("USERS_LIMIT"))
|
||||||
|
} else {
|
||||||
|
userslimit = config.Config.Server.UsersLimit
|
||||||
|
}
|
||||||
|
return userslimit
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNetworkLimit - fetches free tier limits on networks
|
||||||
|
func GetNetworkLimit() int {
|
||||||
|
var networkslimit int
|
||||||
|
if os.Getenv("NETWORKS_LIMIT") != "" {
|
||||||
|
networkslimit, _ = strconv.Atoi(os.Getenv("NETWORKS_LIMIT"))
|
||||||
|
} else {
|
||||||
|
networkslimit = config.Config.Server.NetworksLimit
|
||||||
|
}
|
||||||
|
return networkslimit
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetClientLimit - fetches free tier limits on ext. clients
|
||||||
|
func GetClientLimit() int {
|
||||||
|
var clientsLimit int
|
||||||
|
if os.Getenv("CLIENTS_LIMIT") != "" {
|
||||||
|
clientsLimit, _ = strconv.Atoi(os.Getenv("CLIENTS_LIMIT"))
|
||||||
|
} else {
|
||||||
|
clientsLimit = config.Config.Server.ClientsLimit
|
||||||
|
}
|
||||||
|
return clientsLimit
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHostLimit - fetches free tier limits on hosts
|
||||||
|
func GetHostLimit() int {
|
||||||
|
var hostsLimit int
|
||||||
|
if os.Getenv("HOSTS_LIMIT") != "" {
|
||||||
|
hostsLimit, _ = strconv.Atoi(os.Getenv("HOSTS_LIMIT"))
|
||||||
|
} else {
|
||||||
|
hostsLimit = config.Config.Server.HostsLimit
|
||||||
|
}
|
||||||
|
return hostsLimit
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeployedByOperator - returns true if the instance is deployed by netmaker operator
|
||||||
|
func DeployedByOperator() bool {
|
||||||
|
if os.Getenv("DEPLOYED_BY_OPERATOR") != "" {
|
||||||
|
return os.Getenv("DEPLOYED_BY_OPERATOR") == "true"
|
||||||
|
}
|
||||||
|
return config.Config.Server.DeployedByOperator
|
||||||
|
}
|
||||||
|
|
||||||
// GetDefaultProxyMode - default proxy mode for a server
|
// GetDefaultProxyMode - default proxy mode for a server
|
||||||
func GetDefaultProxyMode() config.ProxyMode {
|
func GetDefaultProxyMode() config.ProxyMode {
|
||||||
var (
|
var (
|
||||||
|
Reference in New Issue
Block a user