From 8ce7da2ce96989481c719ab8b8eaa977a7bb077c Mon Sep 17 00:00:00 2001 From: Gabriel de Souza Seibel Date: Tue, 8 Aug 2023 14:47:49 -0300 Subject: [PATCH] [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 --- config/config.go | 5 ++-- controllers/ext_client.go | 2 +- controllers/limits.go | 56 ++++++++++++++++++++++++++++----------- controllers/network.go | 2 +- controllers/node.go | 4 +-- controllers/server.go | 20 +++++++++++--- controllers/user.go | 2 +- ee/license.go | 2 +- ee/types.go | 46 ++++++++++++++++++-------------- ee/util.go | 19 +++++++++---- logic/gateway.go | 48 ++++++++++++++++++++++++--------- logic/hosts.go | 14 +++++----- logic/serverconf.go | 35 +++++++++++++----------- servercfg/serverconf.go | 34 +++++++++++++----------- 14 files changed, 185 insertions(+), 104 deletions(-) diff --git a/config/config.go b/config/config.go index 934837a38..569d430af 100644 --- a/config/config.go +++ b/config/config.go @@ -82,9 +82,10 @@ type ServerConfig struct { TurnPassword string `yaml:"turn_password"` 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"` + MachinesLimit int `yaml:"machines_limit"` + IngressesLimit int `yaml:"ingresses_limit"` + EgressesLimit int `yaml:"egresses_limit"` DeployedByOperator bool `yaml:"deployed_by_operator"` Environment string `yaml:"environment"` } diff --git a/controllers/ext_client.go b/controllers/ext_client.go index c372064cb..35d6358ae 100644 --- a/controllers/ext_client.go +++ b/controllers/ext_client.go @@ -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}", 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}/{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 { diff --git a/controllers/limits.go b/controllers/limits.go index 2b4cee159..e3a7b7b16 100644 --- a/controllers/limits.go +++ b/controllers/limits.go @@ -10,36 +10,60 @@ import ( // limit consts const ( - node_l = 0 - networks_l = 1 - users_l = 2 - clients_l = 3 + limitChoiceNetworks = iota + limitChoiceUsers + limitChoiceMachines + 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) { 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 limit_choice == networks_l { + if logic.FreeTier { // check that free tier limits not exceeded + switch limitChoice { + case limitChoiceNetworks: 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) return } - } else if limit_choice == users_l { + case limitChoiceUsers: users, err := logic.GetUsers() - if (err != nil && !database.IsEmptyRecord(err)) || len(users) >= logic.Users_Limit { - errorResponse.Message = "free tier limits exceeded on users" + if (err != nil && !database.IsEmptyRecord(err)) || + len(users) >= logic.UsersLimit { + errorResponse.Message += "users" logic.ReturnErrorResponse(w, r, errorResponse) return } - } else if limit_choice == clients_l { - clients, err := logic.GetAllExtClients() - if (err != nil && !database.IsEmptyRecord(err)) || len(clients) >= logic.Clients_Limit { - errorResponse.Message = "free tier limits exceeded on external clients" + case limitChoiceMachines: + hosts, hErr := logic.GetAllHosts() + clients, cErr := logic.GetAllExtClients() + 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) return } diff --git a/controllers/network.go b/controllers/network.go index 8558b13f4..b3e799b71 100644 --- a/controllers/network.go +++ b/controllers/network.go @@ -21,7 +21,7 @@ import ( func networkHandlers(r *mux.Router) { 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(true, http.HandlerFunc(deleteNetwork))).Methods(http.MethodDelete) r.HandleFunc("/api/networks/{networkname}", logic.SecurityCheck(true, http.HandlerFunc(updateNetwork))).Methods(http.MethodPut) diff --git a/controllers/node.go b/controllers/node.go index 64055ebd4..28de485d1 100644 --- a/controllers/node.go +++ b/controllers/node.go @@ -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(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}/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}/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}", Authorize(true, true, "node", http.HandlerFunc(updateNode))).Methods(http.MethodPost) r.HandleFunc("/api/nodes/adm/{network}/authenticate", authenticate).Methods(http.MethodPost) diff --git a/controllers/server.go b/controllers/server.go index 79c8e21f0..df23f1229 100644 --- a/controllers/server.go +++ b/controllers/server.go @@ -24,12 +24,16 @@ func serverHandlers(r *mux.Router) { 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) } + +// TODO move to EE package? there is a function and a type there for that already 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"` + Hosts int `json:"hosts"` + Clients int `json:"clients"` + Networks int `json:"networks"` + Users int `json:"users"` + Ingresses int `json:"ingresses"` + Egresses int `json:"egresses"` } var serverUsage usage hosts, err := logic.GetAllHosts() @@ -48,6 +52,14 @@ func getUsage(w http.ResponseWriter, r *http.Request) { if err == nil { 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") json.NewEncoder(w).Encode(models.SuccessResponse{ Code: http.StatusOK, diff --git a/controllers/user.go b/controllers/user.go index fdd59fca5..0a7229c17 100644 --- a/controllers/user.go +++ b/controllers/user.go @@ -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/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}", 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(false, logic.ContinueIfUserMatch(http.HandlerFunc(getUser)))).Methods(http.MethodGet) r.HandleFunc("/api/users", logic.SecurityCheck(true, http.HandlerFunc(getUsers))).Methods(http.MethodGet) diff --git a/ee/license.go b/ee/license.go index aeb9b3f7f..8bf7345ba 100644 --- a/ee/license.go +++ b/ee/license.go @@ -81,7 +81,7 @@ func ValidateLicense() (err error) { licenseSecret := LicenseSecret{ AssociatedID: netmakerTenantID, - Limits: getCurrentServerLimit(), + Usage: getCurrentServerUsage(), } secretData, err := json.Marshal(&licenseSecret) diff --git a/ee/types.go b/ee/types.go index e7f77464e..355bc6d3a 100644 --- a/ee/types.go +++ b/ee/types.go @@ -24,15 +24,17 @@ var errValidation = fmt.Errorf(license_validation_err_msg) // LicenseKey - the license key struct representation with associated data type LicenseKey struct { - LicenseValue string `json:"license_value"` // actual (public) key and the unique value for the key - Expiration int64 `json:"expiration"` - LimitServers int `json:"limit_servers"` - LimitUsers int `json:"limit_users"` - LimitHosts int `json:"limit_hosts"` - LimitNetworks int `json:"limit_networks"` - LimitClients int `json:"limit_clients"` - Metadata string `json:"metadata"` - IsActive bool `json:"is_active"` // yes if active + LicenseValue string `json:"license_value"` // actual (public) key and the unique value for the key + Expiration int64 `json:"expiration"` + UsageServers int `json:"usage_servers"` + UsageUsers int `json:"usage_users"` + UsageClients int `json:"usage_clients"` + UsageHosts int `json:"usage_hosts"` + UsageNetworks int `json:"usage_networks"` + UsageIngresses int `json:"usage_ingresses"` + UsageEgresses int `json:"usage_egresses"` + Metadata string `json:"metadata"` + IsActive bool `json:"is_active"` // yes if active } // ValidatedLicense - the validated license struct @@ -43,26 +45,30 @@ type ValidatedLicense struct { // LicenseSecret - the encrypted struct for sending user-id type LicenseSecret struct { - AssociatedID string `json:"associated_id" binding:"required"` // UUID for user foreign key to User table - Limits LicenseLimits `json:"limits" binding:"required"` + AssociatedID string `json:"associated_id" binding:"required"` // UUID for user foreign key to User table + Usage Usage `json:"usage" binding:"required"` } -// 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"` +// Usage - struct for license usage +type Usage struct { + Servers int `json:"servers"` + Users int `json:"users"` + Hosts int `json:"hosts"` + Clients int `json:"clients"` + Networks int `json:"networks"` + Ingresses int `json:"ingresses"` + Egresses int `json:"egresses"` } -// LicenseLimits.SetDefaults - sets the default values for limits -func (l *LicenseLimits) SetDefaults() { +// Usage.SetDefaults - sets the default values for usage +func (l *Usage) SetDefaults() { l.Clients = 0 l.Servers = 1 l.Hosts = 0 l.Users = 1 l.Networks = 0 + l.Ingresses = 0 + l.Egresses = 0 } // ValidateLicenseRequest - used for request to validate license endpoint diff --git a/ee/util.go b/ee/util.go index b63cf1582..8712981f9 100644 --- a/ee/util.go +++ b/ee/util.go @@ -30,14 +30,15 @@ func base64decode(input string) []byte { return bytes } -func getCurrentServerLimit() (limits LicenseLimits) { + +func getCurrentServerUsage() (limits Usage) { limits.SetDefaults() - hosts, err := logic.GetAllHosts() - if err == nil { + hosts, hErr := logic.GetAllHosts() + if hErr == nil { limits.Hosts = len(hosts) } - clients, err := logic.GetAllExtClients() - if err == nil { + clients, cErr := logic.GetAllExtClients() + if cErr == nil { limits.Clients = len(clients) } users, err := logic.GetUsers() @@ -48,5 +49,13 @@ func getCurrentServerLimit() (limits LicenseLimits) { if err == nil { 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 } diff --git a/logic/gateway.go b/logic/gateway.go index 90827e13f..094ffa800 100644 --- a/logic/gateway.go +++ b/logic/gateway.go @@ -11,6 +11,36 @@ import ( "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 func CreateEgressGateway(gateway models.EgressGatewayRequest) (models.Node, error) { 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") } 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" { - logger.Log(0, "currently IPv6 internet gateways are not supported", gateway.Ranges[i]) - gateway.Ranges = append(gateway.Ranges[:i], gateway.Ranges[i+1:]...) - continue + return models.Node{}, fmt.Errorf("currently IPv6 internet gateways are not supported: %s", gateway.Ranges[i]) } normalized, err := NormalizeCIDR(gateway.Ranges[i]) if err != nil { @@ -150,15 +183,6 @@ func DeleteIngressGateway(nodeid string) (models.Node, bool, []models.ExtClient, node.IsIngressGateway = false node.IngressGatewayRange = "" 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) if err != nil { return models.Node{}, wasFailover, removedClients, err diff --git a/logic/hosts.go b/logic/hosts.go index e53ed730b..895f571e5 100644 --- a/logic/hosts.go +++ b/logic/hosts.go @@ -158,14 +158,14 @@ func GetHost(hostid string) (*models.Host, error) { // CreateHost - creates a host if not exist func CreateHost(h *models.Host) error { - hosts, err := GetAllHosts() - if err != nil && !database.IsEmptyRecord(err) { - return err + hosts, hErr := GetAllHosts() + clients, cErr := GetAllExtClients() + 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 { - return errors.New("free tier limits exceeded on hosts") - } - _, err = GetHost(h.ID.String()) + _, err := GetHost(h.ID.String()) if (err != nil && !database.IsEmptyRecord(err)) || (err == nil) { return ErrHostExists } diff --git a/logic/serverconf.go b/logic/serverconf.go index 4d73980dd..c307c29d5 100644 --- a/logic/serverconf.go +++ b/logic/serverconf.go @@ -2,22 +2,23 @@ package logic import ( "encoding/json" - "github.com/gravitl/netmaker/database" "github.com/gravitl/netmaker/servercfg" ) var ( - // Networks_Limit - dummy var for community - Networks_Limit = 1000000000 - // Users_Limit - dummy var for community - Users_Limit = 1000000000 - // Clients_Limit - dummy var for community - Clients_Limit = 1000000000 - // Hosts_Limit - dummy var for community - Hosts_Limit = 1000000000 - // Free_Tier - specifies if free tier - Free_Tier = false + // NetworksLimit - dummy var for community + NetworksLimit = 1000000000 + // UsersLimit - dummy var for community + UsersLimit = 1000000000 + // MachinesLimit - dummy var for community + MachinesLimit = 1000000000 + // IngressesLimit - dummy var for community + IngressesLimit = 1000000000 + // EgressesLimit - dummy var for community + EgressesLimit = 1000000000 + // FreeTier - specifies if free tier + FreeTier = false ) type serverData struct { @@ -87,10 +88,12 @@ func StoreJWTSecret(privateKey string) error { return database.Insert("nm-jwt-secret", string(data), database.SERVERCONF_TABLE_NAME) } +// SetFreeTierLimits - sets limits for free tier func SetFreeTierLimits() { - Free_Tier = true - Users_Limit = servercfg.GetUserLimit() - Clients_Limit = servercfg.GetClientLimit() - Networks_Limit = servercfg.GetNetworkLimit() - Hosts_Limit = servercfg.GetHostLimit() + FreeTier = true + UsersLimit = servercfg.GetUserLimit() + NetworksLimit = servercfg.GetNetworkLimit() + MachinesLimit = servercfg.GetMachinesLimit() + IngressesLimit = servercfg.GetIngressLimit() + EgressesLimit = servercfg.GetEgressLimit() } diff --git a/servercfg/serverconf.go b/servercfg/serverconf.go index 9767690e3..4a535c188 100644 --- a/servercfg/serverconf.go +++ b/servercfg/serverconf.go @@ -753,26 +753,28 @@ func GetNetworkLimit() int { 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 +// GetMachinesLimit - fetches free tier limits on machines (clients + hosts) +func GetMachinesLimit() int { + if l, err := strconv.Atoi(os.Getenv("MACHINES_LIMIT")); err == nil { + return l } - return clientsLimit + return config.Config.Server.MachinesLimit } -// 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 +// GetIngressLimit - fetches free tier limits on ingresses +func GetIngressLimit() int { + if l, err := strconv.Atoi(os.Getenv("INGRESSES_LIMIT")); err == nil { + return l + } + 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 hostsLimit + return config.Config.Server.EgressesLimit } // DeployedByOperator - returns true if the instance is deployed by netmaker operator