[NET-494 / ACC-322] New free tier limits (#2495)

* Rename var

* Rename consts and use iota

* Use switch instead of repeated else if

* Rename limits related vars

* Introduce new free tier limits

* Measure new limits and report on license validation

* Separate usage and limits, have new ones

* Don't check for hosts and clients limits, but for machines instead

* Error on egress creation @ free tier w/ internet gateways

* Remove clients and hosts limit from code

* Rename var

* Rename consts and use iota

* Use switch instead of repeated else if

* Rename limits related vars

* Introduce new free tier limits

* Measure new limits and report on license validation

* Separate usage and limits, have new ones

* Don't check for hosts and clients limits, but for machines instead

* Error on egress creation @ free tier w/ internet gateways

* Remove clients and hosts limit from code
This commit is contained in:
Gabriel de Souza Seibel
2023-08-08 14:47:49 -03:00
committed by GitHub
parent 449f3f947b
commit 8ce7da2ce9
14 changed files with 185 additions and 104 deletions

View File

@@ -82,9 +82,10 @@ type ServerConfig struct {
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"` UsersLimit int `yaml:"user_limit"`
ClientsLimit int `yaml:"client_limit"`
NetworksLimit int `yaml:"network_limit"` NetworksLimit int `yaml:"network_limit"`
HostsLimit int `yaml:"host_limit"` MachinesLimit int `yaml:"machines_limit"`
IngressesLimit int `yaml:"ingresses_limit"`
EgressesLimit int `yaml:"egresses_limit"`
DeployedByOperator bool `yaml:"deployed_by_operator"` DeployedByOperator bool `yaml:"deployed_by_operator"`
Environment string `yaml:"environment"` Environment string `yaml:"environment"`
} }

View File

@@ -29,7 +29,7 @@ func extClientHandlers(r *mux.Router) {
r.HandleFunc("/api/extclients/{network}/{clientid}/{type}", logic.NetUserSecurityCheck(false, true, http.HandlerFunc(getExtClientConf))).Methods(http.MethodGet) r.HandleFunc("/api/extclients/{network}/{clientid}/{type}", logic.NetUserSecurityCheck(false, true, http.HandlerFunc(getExtClientConf))).Methods(http.MethodGet)
r.HandleFunc("/api/extclients/{network}/{clientid}", logic.NetUserSecurityCheck(false, true, http.HandlerFunc(updateExtClient))).Methods(http.MethodPut) r.HandleFunc("/api/extclients/{network}/{clientid}", logic.NetUserSecurityCheck(false, true, http.HandlerFunc(updateExtClient))).Methods(http.MethodPut)
r.HandleFunc("/api/extclients/{network}/{clientid}", logic.NetUserSecurityCheck(false, true, http.HandlerFunc(deleteExtClient))).Methods(http.MethodDelete) r.HandleFunc("/api/extclients/{network}/{clientid}", logic.NetUserSecurityCheck(false, true, http.HandlerFunc(deleteExtClient))).Methods(http.MethodDelete)
r.HandleFunc("/api/extclients/{network}/{nodeid}", logic.NetUserSecurityCheck(false, true, checkFreeTierLimits(clients_l, http.HandlerFunc(createExtClient)))).Methods(http.MethodPost) r.HandleFunc("/api/extclients/{network}/{nodeid}", logic.NetUserSecurityCheck(false, true, checkFreeTierLimits(limitChoiceMachines, http.HandlerFunc(createExtClient)))).Methods(http.MethodPost)
} }
func checkIngressExists(nodeID string) bool { func checkIngressExists(nodeID string) bool {

View File

@@ -10,36 +10,60 @@ import (
// limit consts // limit consts
const ( const (
node_l = 0 limitChoiceNetworks = iota
networks_l = 1 limitChoiceUsers
users_l = 2 limitChoiceMachines
clients_l = 3 limitChoiceIngress
limitChoiceEgress
) )
func checkFreeTierLimits(limit_choice int, next http.Handler) http.HandlerFunc { func checkFreeTierLimits(limitChoice int, next http.Handler) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
var errorResponse = models.ErrorResponse{ var errorResponse = models.ErrorResponse{
Code: http.StatusForbidden, Message: "free tier limits exceeded on networks", Code: http.StatusForbidden, Message: "free tier limits exceeded on ",
} }
if logic.Free_Tier { // check that free tier limits not exceeded if logic.FreeTier { // check that free tier limits not exceeded
if limit_choice == networks_l { switch limitChoice {
case limitChoiceNetworks:
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.NetworksLimit {
errorResponse.Message += "networks"
logic.ReturnErrorResponse(w, r, errorResponse) logic.ReturnErrorResponse(w, r, errorResponse)
return return
} }
} else if limit_choice == users_l { case limitChoiceUsers:
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)) ||
errorResponse.Message = "free tier limits exceeded on users" len(users) >= logic.UsersLimit {
errorResponse.Message += "users"
logic.ReturnErrorResponse(w, r, errorResponse) logic.ReturnErrorResponse(w, r, errorResponse)
return return
} }
} else if limit_choice == clients_l { case limitChoiceMachines:
clients, err := logic.GetAllExtClients() hosts, hErr := logic.GetAllHosts()
if (err != nil && !database.IsEmptyRecord(err)) || len(clients) >= logic.Clients_Limit { clients, cErr := logic.GetAllExtClients()
errorResponse.Message = "free tier limits exceeded on external clients" if (hErr != nil && !database.IsEmptyRecord(hErr)) ||
(cErr != nil && !database.IsEmptyRecord(cErr)) ||
len(hosts)+len(clients) >= logic.MachinesLimit {
errorResponse.Message += "machines"
logic.ReturnErrorResponse(w, r, errorResponse)
return
}
case limitChoiceIngress:
ingresses, err := logic.GetAllIngresses()
if (err != nil && !database.IsEmptyRecord(err)) ||
len(ingresses) >= logic.IngressesLimit {
errorResponse.Message += "ingresses"
logic.ReturnErrorResponse(w, r, errorResponse)
return
}
case limitChoiceEgress:
egresses, err := logic.GetAllEgresses()
if (err != nil && !database.IsEmptyRecord(err)) ||
len(egresses) >= logic.EgressesLimit {
errorResponse.Message += "egresses"
logic.ReturnErrorResponse(w, r, errorResponse) logic.ReturnErrorResponse(w, r, errorResponse)
return return
} }

View File

@@ -21,7 +21,7 @@ import (
func networkHandlers(r *mux.Router) { func networkHandlers(r *mux.Router) {
r.HandleFunc("/api/networks", logic.SecurityCheck(false, http.HandlerFunc(getNetworks))).Methods(http.MethodGet) r.HandleFunc("/api/networks", logic.SecurityCheck(false, http.HandlerFunc(getNetworks))).Methods(http.MethodGet)
r.HandleFunc("/api/networks", logic.SecurityCheck(true, checkFreeTierLimits(networks_l, http.HandlerFunc(createNetwork)))).Methods(http.MethodPost) r.HandleFunc("/api/networks", logic.SecurityCheck(true, checkFreeTierLimits(limitChoiceNetworks, http.HandlerFunc(createNetwork)))).Methods(http.MethodPost)
r.HandleFunc("/api/networks/{networkname}", logic.SecurityCheck(false, http.HandlerFunc(getNetwork))).Methods(http.MethodGet) r.HandleFunc("/api/networks/{networkname}", logic.SecurityCheck(false, http.HandlerFunc(getNetwork))).Methods(http.MethodGet)
r.HandleFunc("/api/networks/{networkname}", logic.SecurityCheck(true, http.HandlerFunc(deleteNetwork))).Methods(http.MethodDelete) r.HandleFunc("/api/networks/{networkname}", logic.SecurityCheck(true, http.HandlerFunc(deleteNetwork))).Methods(http.MethodDelete)
r.HandleFunc("/api/networks/{networkname}", logic.SecurityCheck(true, http.HandlerFunc(updateNetwork))).Methods(http.MethodPut) r.HandleFunc("/api/networks/{networkname}", logic.SecurityCheck(true, http.HandlerFunc(updateNetwork))).Methods(http.MethodPut)

View File

@@ -28,9 +28,9 @@ func nodeHandlers(r *mux.Router) {
r.HandleFunc("/api/nodes/{network}/{nodeid}", Authorize(true, true, "node", http.HandlerFunc(getNode))).Methods(http.MethodGet) r.HandleFunc("/api/nodes/{network}/{nodeid}", Authorize(true, true, "node", http.HandlerFunc(getNode))).Methods(http.MethodGet)
r.HandleFunc("/api/nodes/{network}/{nodeid}", Authorize(false, true, "node", http.HandlerFunc(updateNode))).Methods(http.MethodPut) r.HandleFunc("/api/nodes/{network}/{nodeid}", Authorize(false, true, "node", http.HandlerFunc(updateNode))).Methods(http.MethodPut)
r.HandleFunc("/api/nodes/{network}/{nodeid}", Authorize(true, true, "node", http.HandlerFunc(deleteNode))).Methods(http.MethodDelete) r.HandleFunc("/api/nodes/{network}/{nodeid}", Authorize(true, true, "node", http.HandlerFunc(deleteNode))).Methods(http.MethodDelete)
r.HandleFunc("/api/nodes/{network}/{nodeid}/creategateway", Authorize(false, true, "user", http.HandlerFunc(createEgressGateway))).Methods(http.MethodPost) r.HandleFunc("/api/nodes/{network}/{nodeid}/creategateway", Authorize(false, true, "user", checkFreeTierLimits(limitChoiceEgress, http.HandlerFunc(createEgressGateway)))).Methods(http.MethodPost)
r.HandleFunc("/api/nodes/{network}/{nodeid}/deletegateway", Authorize(false, true, "user", http.HandlerFunc(deleteEgressGateway))).Methods(http.MethodDelete) r.HandleFunc("/api/nodes/{network}/{nodeid}/deletegateway", Authorize(false, true, "user", http.HandlerFunc(deleteEgressGateway))).Methods(http.MethodDelete)
r.HandleFunc("/api/nodes/{network}/{nodeid}/createingress", logic.SecurityCheck(false, http.HandlerFunc(createIngressGateway))).Methods(http.MethodPost) r.HandleFunc("/api/nodes/{network}/{nodeid}/createingress", logic.SecurityCheck(false, checkFreeTierLimits(limitChoiceIngress, http.HandlerFunc(createIngressGateway)))).Methods(http.MethodPost)
r.HandleFunc("/api/nodes/{network}/{nodeid}/deleteingress", logic.SecurityCheck(false, http.HandlerFunc(deleteIngressGateway))).Methods(http.MethodDelete) r.HandleFunc("/api/nodes/{network}/{nodeid}/deleteingress", logic.SecurityCheck(false, http.HandlerFunc(deleteIngressGateway))).Methods(http.MethodDelete)
r.HandleFunc("/api/nodes/{network}/{nodeid}", Authorize(true, true, "node", http.HandlerFunc(updateNode))).Methods(http.MethodPost) r.HandleFunc("/api/nodes/{network}/{nodeid}", Authorize(true, true, "node", http.HandlerFunc(updateNode))).Methods(http.MethodPost)
r.HandleFunc("/api/nodes/adm/{network}/authenticate", authenticate).Methods(http.MethodPost) r.HandleFunc("/api/nodes/adm/{network}/authenticate", authenticate).Methods(http.MethodPost)

View File

@@ -24,12 +24,16 @@ func serverHandlers(r *mux.Router) {
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) r.HandleFunc("/api/server/usage", Authorize(true, false, "user", http.HandlerFunc(getUsage))).Methods(http.MethodGet)
} }
// TODO move to EE package? there is a function and a type there for that already
func getUsage(w http.ResponseWriter, r *http.Request) { func getUsage(w http.ResponseWriter, r *http.Request) {
type usage struct { type usage struct {
Hosts int `json:"hosts"` Hosts int `json:"hosts"`
Clients int `json:"clients"` Clients int `json:"clients"`
Networks int `json:"networks"` Networks int `json:"networks"`
Users int `json:"users"` Users int `json:"users"`
Ingresses int `json:"ingresses"`
Egresses int `json:"egresses"`
} }
var serverUsage usage var serverUsage usage
hosts, err := logic.GetAllHosts() hosts, err := logic.GetAllHosts()
@@ -48,6 +52,14 @@ func getUsage(w http.ResponseWriter, r *http.Request) {
if err == nil { if err == nil {
serverUsage.Networks = len(networks) serverUsage.Networks = len(networks)
} }
ingresses, err := logic.GetAllIngresses()
if err == nil {
serverUsage.Ingresses = len(ingresses)
}
egresses, err := logic.GetAllEgresses()
if err == nil {
serverUsage.Egresses = len(egresses)
}
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(models.SuccessResponse{ json.NewEncoder(w).Encode(models.SuccessResponse{
Code: http.StatusOK, Code: http.StatusOK,

View File

@@ -30,7 +30,7 @@ func userHandlers(r *mux.Router) {
r.HandleFunc("/api/users/{username}", logic.SecurityCheck(false, logic.ContinueIfUserMatch(http.HandlerFunc(updateUser)))).Methods(http.MethodPut) r.HandleFunc("/api/users/{username}", logic.SecurityCheck(false, logic.ContinueIfUserMatch(http.HandlerFunc(updateUser)))).Methods(http.MethodPut)
r.HandleFunc("/api/users/networks/{username}", logic.SecurityCheck(true, http.HandlerFunc(updateUserNetworks))).Methods(http.MethodPut) r.HandleFunc("/api/users/networks/{username}", logic.SecurityCheck(true, http.HandlerFunc(updateUserNetworks))).Methods(http.MethodPut)
r.HandleFunc("/api/users/{username}/adm", logic.SecurityCheck(true, http.HandlerFunc(updateUserAdm))).Methods(http.MethodPut) r.HandleFunc("/api/users/{username}/adm", logic.SecurityCheck(true, http.HandlerFunc(updateUserAdm))).Methods(http.MethodPut)
r.HandleFunc("/api/users/{username}", logic.SecurityCheck(true, checkFreeTierLimits(users_l, http.HandlerFunc(createUser)))).Methods(http.MethodPost) r.HandleFunc("/api/users/{username}", logic.SecurityCheck(true, checkFreeTierLimits(limitChoiceUsers, http.HandlerFunc(createUser)))).Methods(http.MethodPost)
r.HandleFunc("/api/users/{username}", logic.SecurityCheck(true, http.HandlerFunc(deleteUser))).Methods(http.MethodDelete) r.HandleFunc("/api/users/{username}", logic.SecurityCheck(true, http.HandlerFunc(deleteUser))).Methods(http.MethodDelete)
r.HandleFunc("/api/users/{username}", logic.SecurityCheck(false, logic.ContinueIfUserMatch(http.HandlerFunc(getUser)))).Methods(http.MethodGet) r.HandleFunc("/api/users/{username}", logic.SecurityCheck(false, logic.ContinueIfUserMatch(http.HandlerFunc(getUser)))).Methods(http.MethodGet)
r.HandleFunc("/api/users", logic.SecurityCheck(true, http.HandlerFunc(getUsers))).Methods(http.MethodGet) r.HandleFunc("/api/users", logic.SecurityCheck(true, http.HandlerFunc(getUsers))).Methods(http.MethodGet)

View File

@@ -81,7 +81,7 @@ func ValidateLicense() (err error) {
licenseSecret := LicenseSecret{ licenseSecret := LicenseSecret{
AssociatedID: netmakerTenantID, AssociatedID: netmakerTenantID,
Limits: getCurrentServerLimit(), Usage: getCurrentServerUsage(),
} }
secretData, err := json.Marshal(&licenseSecret) secretData, err := json.Marshal(&licenseSecret)

View File

@@ -26,11 +26,13 @@ var errValidation = fmt.Errorf(license_validation_err_msg)
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"` UsageServers int `json:"usage_servers"`
LimitUsers int `json:"limit_users"` UsageUsers int `json:"usage_users"`
LimitHosts int `json:"limit_hosts"` UsageClients int `json:"usage_clients"`
LimitNetworks int `json:"limit_networks"` UsageHosts int `json:"usage_hosts"`
LimitClients int `json:"limit_clients"` UsageNetworks int `json:"usage_networks"`
UsageIngresses int `json:"usage_ingresses"`
UsageEgresses int `json:"usage_egresses"`
Metadata string `json:"metadata"` Metadata string `json:"metadata"`
IsActive bool `json:"is_active"` // yes if active IsActive bool `json:"is_active"` // yes if active
} }
@@ -44,25 +46,29 @@ 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 {
AssociatedID string `json:"associated_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"` Usage Usage `json:"usage" binding:"required"`
} }
// LicenseLimits - struct license limits // Usage - struct for license usage
type LicenseLimits struct { type Usage struct {
Servers int `json:"servers"` Servers int `json:"servers"`
Users int `json:"users"` Users int `json:"users"`
Hosts int `json:"hosts"` Hosts int `json:"hosts"`
Clients int `json:"clients"` Clients int `json:"clients"`
Networks int `json:"networks"` Networks int `json:"networks"`
Ingresses int `json:"ingresses"`
Egresses int `json:"egresses"`
} }
// LicenseLimits.SetDefaults - sets the default values for limits // Usage.SetDefaults - sets the default values for usage
func (l *LicenseLimits) SetDefaults() { func (l *Usage) SetDefaults() {
l.Clients = 0 l.Clients = 0
l.Servers = 1 l.Servers = 1
l.Hosts = 0 l.Hosts = 0
l.Users = 1 l.Users = 1
l.Networks = 0 l.Networks = 0
l.Ingresses = 0
l.Egresses = 0
} }
// ValidateLicenseRequest - used for request to validate license endpoint // ValidateLicenseRequest - used for request to validate license endpoint

View File

@@ -30,14 +30,15 @@ func base64decode(input string) []byte {
return bytes return bytes
} }
func getCurrentServerLimit() (limits LicenseLimits) {
func getCurrentServerUsage() (limits Usage) {
limits.SetDefaults() limits.SetDefaults()
hosts, err := logic.GetAllHosts() hosts, hErr := logic.GetAllHosts()
if err == nil { if hErr == nil {
limits.Hosts = len(hosts) limits.Hosts = len(hosts)
} }
clients, err := logic.GetAllExtClients() clients, cErr := logic.GetAllExtClients()
if err == nil { if cErr == nil {
limits.Clients = len(clients) limits.Clients = len(clients)
} }
users, err := logic.GetUsers() users, err := logic.GetUsers()
@@ -48,5 +49,13 @@ func getCurrentServerLimit() (limits LicenseLimits) {
if err == nil { if err == nil {
limits.Networks = len(networks) limits.Networks = len(networks)
} }
ingresses, err := logic.GetAllIngresses()
if err == nil {
limits.Ingresses = len(ingresses)
}
egresses, err := logic.GetAllEgresses()
if err == nil {
limits.Egresses = len(egresses)
}
return return
} }

View File

@@ -11,6 +11,36 @@ import (
"github.com/gravitl/netmaker/servercfg" "github.com/gravitl/netmaker/servercfg"
) )
// GetAllIngresses - gets all the hosts that are ingresses
func GetAllIngresses() ([]models.Node, error) {
nodes, err := GetAllNodes()
if err != nil {
return nil, err
}
ingresses := make([]models.Node, 0)
for _, node := range nodes {
if node.IsIngressGateway {
ingresses = append(ingresses, node)
}
}
return ingresses, nil
}
// GetAllEgresses - gets all the hosts that are egresses
func GetAllEgresses() ([]models.Node, error) {
nodes, err := GetAllNodes()
if err != nil {
return nil, err
}
egresses := make([]models.Node, 0)
for _, node := range nodes {
if node.IsEgressGateway {
egresses = append(egresses, node)
}
}
return egresses, nil
}
// CreateEgressGateway - creates an egress gateway // CreateEgressGateway - creates an egress gateway
func CreateEgressGateway(gateway models.EgressGatewayRequest) (models.Node, error) { func CreateEgressGateway(gateway models.EgressGatewayRequest) (models.Node, error) {
node, err := GetNodeByID(gateway.NodeID) node, err := GetNodeByID(gateway.NodeID)
@@ -28,10 +58,13 @@ func CreateEgressGateway(gateway models.EgressGatewayRequest) (models.Node, erro
return models.Node{}, errors.New("firewall is not supported for egress gateways") return models.Node{}, errors.New("firewall is not supported for egress gateways")
} }
for i := len(gateway.Ranges) - 1; i >= 0; i-- { for i := len(gateway.Ranges) - 1; i >= 0; i-- {
// check if internet gateway IPv4
if gateway.Ranges[i] == "0.0.0.0/0" && FreeTier {
return models.Node{}, fmt.Errorf("currently IPv4 internet gateways are not supported on the free tier: %s", gateway.Ranges[i])
}
// check if internet gateway IPv6
if gateway.Ranges[i] == "::/0" { if gateway.Ranges[i] == "::/0" {
logger.Log(0, "currently IPv6 internet gateways are not supported", gateway.Ranges[i]) return models.Node{}, fmt.Errorf("currently IPv6 internet gateways are not supported: %s", gateway.Ranges[i])
gateway.Ranges = append(gateway.Ranges[:i], gateway.Ranges[i+1:]...)
continue
} }
normalized, err := NormalizeCIDR(gateway.Ranges[i]) normalized, err := NormalizeCIDR(gateway.Ranges[i])
if err != nil { if err != nil {
@@ -150,15 +183,6 @@ func DeleteIngressGateway(nodeid string) (models.Node, bool, []models.ExtClient,
node.IsIngressGateway = false node.IsIngressGateway = false
node.IngressGatewayRange = "" node.IngressGatewayRange = ""
node.Failover = false node.Failover = false
//logger.Log(3, "deleting ingress gateway firewall in use is '", host.FirewallInUse, "' and isEgressGateway is", node.IsEgressGateway)
if node.EgressGatewayRequest.NodeID != "" {
_, err := CreateEgressGateway(node.EgressGatewayRequest)
if err != nil {
logger.Log(0, fmt.Sprintf("failed to create egress gateway on node [%s] on network [%s]: %v",
node.EgressGatewayRequest.NodeID, node.EgressGatewayRequest.NetID, err))
}
}
err = UpsertNode(&node) err = UpsertNode(&node)
if err != nil { if err != nil {
return models.Node{}, wasFailover, removedClients, err return models.Node{}, wasFailover, removedClients, err

View File

@@ -158,14 +158,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 {
hosts, err := GetAllHosts() hosts, hErr := GetAllHosts()
if err != nil && !database.IsEmptyRecord(err) { clients, cErr := GetAllExtClients()
return err if (hErr != nil && !database.IsEmptyRecord(hErr)) ||
(cErr != nil && !database.IsEmptyRecord(cErr)) ||
len(hosts)+len(clients) >= MachinesLimit {
return errors.New("free tier limits exceeded on machines")
} }
if len(hosts) >= Hosts_Limit { _, err := GetHost(h.ID.String())
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
} }

View File

@@ -2,22 +2,23 @@ package logic
import ( import (
"encoding/json" "encoding/json"
"github.com/gravitl/netmaker/database" "github.com/gravitl/netmaker/database"
"github.com/gravitl/netmaker/servercfg" "github.com/gravitl/netmaker/servercfg"
) )
var ( var (
// Networks_Limit - dummy var for community // NetworksLimit - dummy var for community
Networks_Limit = 1000000000 NetworksLimit = 1000000000
// Users_Limit - dummy var for community // UsersLimit - dummy var for community
Users_Limit = 1000000000 UsersLimit = 1000000000
// Clients_Limit - dummy var for community // MachinesLimit - dummy var for community
Clients_Limit = 1000000000 MachinesLimit = 1000000000
// Hosts_Limit - dummy var for community // IngressesLimit - dummy var for community
Hosts_Limit = 1000000000 IngressesLimit = 1000000000
// Free_Tier - specifies if free tier // EgressesLimit - dummy var for community
Free_Tier = false EgressesLimit = 1000000000
// FreeTier - specifies if free tier
FreeTier = false
) )
type serverData struct { type serverData struct {
@@ -87,10 +88,12 @@ 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)
} }
// SetFreeTierLimits - sets limits for free tier
func SetFreeTierLimits() { func SetFreeTierLimits() {
Free_Tier = true FreeTier = true
Users_Limit = servercfg.GetUserLimit() UsersLimit = servercfg.GetUserLimit()
Clients_Limit = servercfg.GetClientLimit() NetworksLimit = servercfg.GetNetworkLimit()
Networks_Limit = servercfg.GetNetworkLimit() MachinesLimit = servercfg.GetMachinesLimit()
Hosts_Limit = servercfg.GetHostLimit() IngressesLimit = servercfg.GetIngressLimit()
EgressesLimit = servercfg.GetEgressLimit()
} }

View File

@@ -753,26 +753,28 @@ func GetNetworkLimit() int {
return networkslimit return networkslimit
} }
// GetClientLimit - fetches free tier limits on ext. clients // GetMachinesLimit - fetches free tier limits on machines (clients + hosts)
func GetClientLimit() int { func GetMachinesLimit() int {
var clientsLimit int if l, err := strconv.Atoi(os.Getenv("MACHINES_LIMIT")); err == nil {
if os.Getenv("CLIENTS_LIMIT") != "" { return l
clientsLimit, _ = strconv.Atoi(os.Getenv("CLIENTS_LIMIT"))
} else {
clientsLimit = config.Config.Server.ClientsLimit
} }
return clientsLimit return config.Config.Server.MachinesLimit
} }
// GetHostLimit - fetches free tier limits on hosts // GetIngressLimit - fetches free tier limits on ingresses
func GetHostLimit() int { func GetIngressLimit() int {
var hostsLimit int if l, err := strconv.Atoi(os.Getenv("INGRESSES_LIMIT")); err == nil {
if os.Getenv("HOSTS_LIMIT") != "" { return l
hostsLimit, _ = strconv.Atoi(os.Getenv("HOSTS_LIMIT"))
} else {
hostsLimit = config.Config.Server.HostsLimit
} }
return hostsLimit return config.Config.Server.IngressesLimit
}
// GetEgressLimit - fetches free tier limits on egresses
func GetEgressLimit() int {
if l, err := strconv.Atoi(os.Getenv("EGRESSES_LIMIT")); err == nil {
return l
}
return config.Config.Server.EgressesLimit
} }
// DeployedByOperator - returns true if the instance is deployed by netmaker operator // DeployedByOperator - returns true if the instance is deployed by netmaker operator