Browse Source

Merge pull request #2786 from gravitl/NET-898

NET-898: Pro Trial
Abhishek K 1 year ago
parent
commit
1d1b9bb484
12 changed files with 521 additions and 383 deletions
  1. 2 2
      README.md
  2. 24 9
      controllers/server.go
  3. 22 22
      database/database.go
  4. 14 33
      logic/peers.go
  5. 6 34
      logic/serverconf.go
  6. 6 6
      logic/telemetry.go
  7. 4 3
      logic/timer.go
  8. 2 2
      logic/traffic.go
  9. 47 8
      pro/initialize.go
  10. 27 0
      pro/logic/failover.go
  11. 161 0
      pro/trial.go
  12. 206 264
      scripts/nm-quick.sh

+ 2 - 2
README.md

@@ -53,7 +53,7 @@ If you're just looking to use Netmaker, you can create an account for free at [n
 
 
 # Self-Hosted Quick Start  
 # Self-Hosted Quick Start  
 
 
-These are the instructions for deploying a Netmaker server on your own cloud VM as quickly as possible. For more detailed instructions, visit the [Install Docs](https://netmaker.readthedocs.io/en/master/install.html).  
+These are the instructions for deploying a Netmaker server on your own cloud VM as quickly as possible. For more detailed instructions, visit the [Install Docs](https://docs.netmaker.io/install.html).  
 
 
 1. Get a cloud VM with Ubuntu 22.04 and a public IP.
 1. Get a cloud VM with Ubuntu 22.04 and a public IP.
 2. Open ports 443, 80, 3479, 8089 and 51821-51830/udp on the VM firewall and in cloud security settings.
 2. Open ports 443, 80, 3479, 8089 and 51821-51830/udp on the VM firewall and in cloud security settings.
@@ -68,7 +68,7 @@ This script gives you the option to deploy the Community or Enterprise version o
 <img src="https://raw.githubusercontent.com/gravitl/netmaker-docs/master/images/netmaker-github/readme.gif" />
 <img src="https://raw.githubusercontent.com/gravitl/netmaker-docs/master/images/netmaker-github/readme.gif" />
 </p>
 </p>
 
 
-After installing Netmaker, check out the [Walkthrough](https://itnext.io/getting-started-with-netmaker-a-wireguard-virtual-networking-platform-3d563fbd87f0) and [Getting Started](https://netmaker.readthedocs.io/en/master/getting-started.html) guides to learn more about configuring networks. Or, check out some of our other [Tutorials](https://www.netmaker.io/blog) for different use cases, including Kubernetes.
+After installing Netmaker, check out the [Walkthrough](https://itnext.io/getting-started-with-netmaker-a-wireguard-virtual-networking-platform-3d563fbd87f0) and [Getting Started](https://docs.netmaker.io/getting-started.html) guides to learn more about configuring networks. Or, check out some of our other [Tutorials](https://www.netmaker.io/blog) for different use cases, including Kubernetes.
 
 
 # Get Support
 # Get Support
 
 

+ 24 - 9
controllers/server.go

@@ -5,6 +5,7 @@ import (
 	"net/http"
 	"net/http"
 	"strings"
 	"strings"
 	"syscall"
 	"syscall"
+	"time"
 
 
 	"github.com/gorilla/mux"
 	"github.com/gorilla/mux"
 	"golang.org/x/exp/slog"
 	"golang.org/x/exp/slog"
@@ -109,22 +110,36 @@ func getUsage(w http.ResponseWriter, _ *http.Request) {
 //				200: serverConfigResponse
 //				200: serverConfigResponse
 func getStatus(w http.ResponseWriter, r *http.Request) {
 func getStatus(w http.ResponseWriter, r *http.Request) {
 	type status struct {
 	type status struct {
-		DB           bool   `json:"db_connected"`
-		Broker       bool   `json:"broker_connected"`
-		LicenseError string `json:"license_error"`
-		IsPro        bool   `json:"is_pro"`
+		DB               bool      `json:"db_connected"`
+		Broker           bool      `json:"broker_connected"`
+		LicenseError     string    `json:"license_error"`
+		IsPro            bool      `json:"is_pro"`
+		TrialEndDate     time.Time `json:"trial_end_date"`
+		IsOnTrialLicense bool      `json:"is_on_trial_license"`
 	}
 	}
 
 
 	licenseErr := ""
 	licenseErr := ""
 	if servercfg.ErrLicenseValidation != nil {
 	if servercfg.ErrLicenseValidation != nil {
 		licenseErr = servercfg.ErrLicenseValidation.Error()
 		licenseErr = servercfg.ErrLicenseValidation.Error()
 	}
 	}
-
+	var trialEndDate time.Time
+	var err error
+	isOnTrial := false
+	if servercfg.IsPro && (servercfg.GetLicenseKey() == "" || servercfg.GetNetmakerTenantID() == "") {
+		trialEndDate, err = logic.GetTrialEndDate()
+		if err != nil {
+			slog.Error("failed to get trial end date", "error", err)
+		} else {
+			isOnTrial = true
+		}
+	}
 	currentServerStatus := status{
 	currentServerStatus := status{
-		DB:           database.IsConnected(),
-		Broker:       mq.IsConnected(),
-		LicenseError: licenseErr,
-		IsPro:        servercfg.IsPro,
+		DB:               database.IsConnected(),
+		Broker:           mq.IsConnected(),
+		LicenseError:     licenseErr,
+		IsPro:            servercfg.IsPro,
+		TrialEndDate:     trialEndDate,
+		IsOnTrialLicense: isOnTrial,
 	}
 	}
 
 
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")

+ 22 - 22
database/database.go

@@ -124,29 +124,29 @@ func InitializeDatabase() error {
 }
 }
 
 
 func createTables() {
 func createTables() {
-	createTable(NETWORKS_TABLE_NAME)
-	createTable(NODES_TABLE_NAME)
-	createTable(CERTS_TABLE_NAME)
-	createTable(DELETED_NODES_TABLE_NAME)
-	createTable(USERS_TABLE_NAME)
-	createTable(DNS_TABLE_NAME)
-	createTable(EXT_CLIENT_TABLE_NAME)
-	createTable(PEERS_TABLE_NAME)
-	createTable(SERVERCONF_TABLE_NAME)
-	createTable(SERVER_UUID_TABLE_NAME)
-	createTable(GENERATED_TABLE_NAME)
-	createTable(NODE_ACLS_TABLE_NAME)
-	createTable(SSO_STATE_CACHE)
-	createTable(METRICS_TABLE_NAME)
-	createTable(NETWORK_USER_TABLE_NAME)
-	createTable(USER_GROUPS_TABLE_NAME)
-	createTable(CACHE_TABLE_NAME)
-	createTable(HOSTS_TABLE_NAME)
-	createTable(ENROLLMENT_KEYS_TABLE_NAME)
-	createTable(HOST_ACTIONS_TABLE_NAME)
+	CreateTable(NETWORKS_TABLE_NAME)
+	CreateTable(NODES_TABLE_NAME)
+	CreateTable(CERTS_TABLE_NAME)
+	CreateTable(DELETED_NODES_TABLE_NAME)
+	CreateTable(USERS_TABLE_NAME)
+	CreateTable(DNS_TABLE_NAME)
+	CreateTable(EXT_CLIENT_TABLE_NAME)
+	CreateTable(PEERS_TABLE_NAME)
+	CreateTable(SERVERCONF_TABLE_NAME)
+	CreateTable(SERVER_UUID_TABLE_NAME)
+	CreateTable(GENERATED_TABLE_NAME)
+	CreateTable(NODE_ACLS_TABLE_NAME)
+	CreateTable(SSO_STATE_CACHE)
+	CreateTable(METRICS_TABLE_NAME)
+	CreateTable(NETWORK_USER_TABLE_NAME)
+	CreateTable(USER_GROUPS_TABLE_NAME)
+	CreateTable(CACHE_TABLE_NAME)
+	CreateTable(HOSTS_TABLE_NAME)
+	CreateTable(ENROLLMENT_KEYS_TABLE_NAME)
+	CreateTable(HOST_ACTIONS_TABLE_NAME)
 }
 }
 
 
-func createTable(tableName string) error {
+func CreateTable(tableName string) error {
 	return getCurrentDB()[CREATE_TABLE].(func(string) error)(tableName)
 	return getCurrentDB()[CREATE_TABLE].(func(string) error)(tableName)
 }
 }
 
 
@@ -194,7 +194,7 @@ func DeleteAllRecords(tableName string) error {
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
-	err = createTable(tableName)
+	err = CreateTable(tableName)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}

+ 14 - 33
logic/peers.go

@@ -24,6 +24,10 @@ var (
 	ResetFailedOverPeer = func(failedOverNode *models.Node) error {
 	ResetFailedOverPeer = func(failedOverNode *models.Node) error {
 		return nil
 		return nil
 	}
 	}
+	// GetFailOverPeerIps - gets failover peerips
+	GetFailOverPeerIps = func(peer, node *models.Node) []net.IPNet {
+		return []net.IPNet{}
+	}
 )
 )
 
 
 // GetPeerUpdateForHost - gets the consolidated peer update for the host from all networks
 // GetPeerUpdateForHost - gets the consolidated peer update for the host from all networks
@@ -144,16 +148,18 @@ func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.N
 				hostPeerUpdate.EgressRoutes = append(hostPeerUpdate.EgressRoutes, getExtpeersExtraRoutes(peer.Network)...)
 				hostPeerUpdate.EgressRoutes = append(hostPeerUpdate.EgressRoutes, getExtpeersExtraRoutes(peer.Network)...)
 			}
 			}
 			_, isFailOverPeer := node.FailOverPeers[peer.ID.String()]
 			_, isFailOverPeer := node.FailOverPeers[peer.ID.String()]
-			if (node.IsRelayed && node.RelayedBy != peer.ID.String()) ||
-				(peer.IsRelayed && peer.RelayedBy != node.ID.String()) || isFailOverPeer {
-				// if node is relayed and peer is not the relay, set remove to true
-				if _, ok := peerIndexMap[peerHost.PublicKey.String()]; ok {
+			if servercfg.IsPro {
+				if (node.IsRelayed && node.RelayedBy != peer.ID.String()) ||
+					(peer.IsRelayed && peer.RelayedBy != node.ID.String()) || isFailOverPeer {
+					// if node is relayed and peer is not the relay, set remove to true
+					if _, ok := peerIndexMap[peerHost.PublicKey.String()]; ok {
+						continue
+					}
+					peerConfig.Remove = true
+					hostPeerUpdate.Peers = append(hostPeerUpdate.Peers, peerConfig)
+					peerIndexMap[peerHost.PublicKey.String()] = len(hostPeerUpdate.Peers) - 1
 					continue
 					continue
 				}
 				}
-				peerConfig.Remove = true
-				hostPeerUpdate.Peers = append(hostPeerUpdate.Peers, peerConfig)
-				peerIndexMap[peerHost.PublicKey.String()] = len(hostPeerUpdate.Peers) - 1
-				continue
 			}
 			}
 
 
 			uselocal := false
 			uselocal := false
@@ -362,31 +368,6 @@ func GetAllowedIPs(node, peer *models.Node, metrics *models.Metrics) []net.IPNet
 	return allowedips
 	return allowedips
 }
 }
 
 
-func GetFailOverPeerIps(peer, node *models.Node) []net.IPNet {
-	allowedips := []net.IPNet{}
-	for failOverpeerID := range node.FailOverPeers {
-		failOverpeer, err := GetNodeByID(failOverpeerID)
-		if err == nil && failOverpeer.FailedOverBy == peer.ID {
-			if failOverpeer.Address.IP != nil {
-				allowed := net.IPNet{
-					IP:   failOverpeer.Address.IP,
-					Mask: net.CIDRMask(32, 32),
-				}
-				allowedips = append(allowedips, allowed)
-			}
-			if failOverpeer.Address6.IP != nil {
-				allowed := net.IPNet{
-					IP:   failOverpeer.Address6.IP,
-					Mask: net.CIDRMask(128, 128),
-				}
-				allowedips = append(allowedips, allowed)
-			}
-
-		}
-	}
-	return allowedips
-}
-
 func GetEgressIPs(peer *models.Node) []net.IPNet {
 func GetEgressIPs(peer *models.Node) []net.IPNet {
 
 
 	peerHost, err := GetHost(peer.HostID.String())
 	peerHost, err := GetHost(peer.HostID.String())

+ 6 - 34
logic/serverconf.go

@@ -2,6 +2,8 @@ package logic
 
 
 import (
 import (
 	"encoding/json"
 	"encoding/json"
+	"time"
+
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/servercfg"
 	"github.com/gravitl/netmaker/servercfg"
 )
 )
@@ -19,46 +21,16 @@ var (
 	EgressesLimit = 1000000000
 	EgressesLimit = 1000000000
 	// FreeTier - specifies if free tier
 	// FreeTier - specifies if free tier
 	FreeTier = false
 	FreeTier = false
+
+	GetTrialEndDate = func() (time.Time, error) {
+		return time.Time{}, nil
+	}
 )
 )
 
 
 type serverData struct {
 type serverData struct {
 	PrivateKey string `json:"privatekey,omitempty" bson:"privatekey,omitempty"`
 	PrivateKey string `json:"privatekey,omitempty" bson:"privatekey,omitempty"`
 }
 }
 
 
-// StorePrivKey - stores server client WireGuard privatekey if needed
-func StorePrivKey(serverID string, privateKey string) error {
-	var newData = serverData{}
-	var err error
-	var data []byte
-	newData.PrivateKey = privateKey
-	data, err = json.Marshal(&newData)
-	if err != nil {
-		return err
-	}
-	return database.Insert(serverID, string(data), database.SERVERCONF_TABLE_NAME)
-}
-
-// FetchPrivKey - fetches private key
-func FetchPrivKey(serverID string) (string, error) {
-	var dbData string
-	var err error
-	var fetchedData = serverData{}
-	dbData, err = database.FetchRecord(database.SERVERCONF_TABLE_NAME, serverID)
-	if err != nil {
-		return "", err
-	}
-	err = json.Unmarshal([]byte(dbData), &fetchedData)
-	if err != nil {
-		return "", err
-	}
-	return fetchedData.PrivateKey, nil
-}
-
-// RemovePrivKey - removes a private key
-func RemovePrivKey(serverID string) error {
-	return database.DeleteRecord(database.SERVERCONF_TABLE_NAME, serverID)
-}
-
 // FetchJWTSecret - fetches jwt secret from db
 // FetchJWTSecret - fetches jwt secret from db
 func FetchJWTSecret() (string, error) {
 func FetchJWTSecret() (string, error) {
 	var dbData string
 	var dbData string

+ 6 - 6
logic/telemetry.go

@@ -32,12 +32,12 @@ func sendTelemetry() error {
 		return nil
 		return nil
 	}
 	}
 
 
-	var telRecord, err = fetchTelemetryRecord()
+	var telRecord, err = FetchTelemetryRecord()
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 	// get telemetry data
 	// get telemetry data
-	d, err := fetchTelemetryData()
+	d, err := FetchTelemetryData()
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
@@ -71,8 +71,8 @@ func sendTelemetry() error {
 	})
 	})
 }
 }
 
 
-// fetchTelemetry - fetches telemetry data: count of various object types in DB
-func fetchTelemetryData() (telemetryData, error) {
+// FetchTelemetryData - fetches telemetry data: count of various object types in DB
+func FetchTelemetryData() (telemetryData, error) {
 	var data telemetryData
 	var data telemetryData
 
 
 	data.IsPro = servercfg.IsPro
 	data.IsPro = servercfg.IsPro
@@ -138,8 +138,8 @@ func getClientCount(nodes []models.Node) clientCount {
 	return count
 	return count
 }
 }
 
 
-// fetchTelemetryRecord - get the existing UUID and Timestamp from the DB
-func fetchTelemetryRecord() (models.Telemetry, error) {
+// FetchTelemetryRecord - get the existing UUID and Timestamp from the DB
+func FetchTelemetryRecord() (models.Telemetry, error) {
 	var rawData string
 	var rawData string
 	var telObj models.Telemetry
 	var telObj models.Telemetry
 	var err error
 	var err error

+ 4 - 3
logic/timer.go

@@ -3,11 +3,12 @@ package logic
 import (
 import (
 	"context"
 	"context"
 	"fmt"
 	"fmt"
-	"github.com/gravitl/netmaker/logger"
-	"golang.org/x/exp/slog"
 	"sync"
 	"sync"
 	"time"
 	"time"
 
 
+	"github.com/gravitl/netmaker/logger"
+	"golang.org/x/exp/slog"
+
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/models"
 )
 )
 
 
@@ -24,7 +25,7 @@ var HookManagerCh = make(chan models.HookDetails, 3)
 // 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
 func TimerCheckpoint() error {
 func TimerCheckpoint() error {
 	// get the telemetry record in the DB, which contains a timestamp
 	// get the telemetry record in the DB, which contains a timestamp
-	telRecord, err := fetchTelemetryRecord()
+	telRecord, err := FetchTelemetryRecord()
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}

+ 2 - 2
logic/traffic.go

@@ -2,7 +2,7 @@ package logic
 
 
 // RetrievePrivateTrafficKey - retrieves private key of server
 // RetrievePrivateTrafficKey - retrieves private key of server
 func RetrievePrivateTrafficKey() ([]byte, error) {
 func RetrievePrivateTrafficKey() ([]byte, error) {
-	var telRecord, err = fetchTelemetryRecord()
+	var telRecord, err = FetchTelemetryRecord()
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -12,7 +12,7 @@ func RetrievePrivateTrafficKey() ([]byte, error) {
 
 
 // RetrievePublicTrafficKey - retrieves public key of server
 // RetrievePublicTrafficKey - retrieves public key of server
 func RetrievePublicTrafficKey() ([]byte, error) {
 func RetrievePublicTrafficKey() ([]byte, error) {
-	var telRecord, err = fetchTelemetryRecord()
+	var telRecord, err = FetchTelemetryRecord()
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}

+ 47 - 8
pro/initialize.go

@@ -4,7 +4,10 @@
 package pro
 package pro
 
 
 import (
 import (
+	"time"
+
 	controller "github.com/gravitl/netmaker/controllers"
 	controller "github.com/gravitl/netmaker/controllers"
+	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/mq"
 	"github.com/gravitl/netmaker/mq"
@@ -31,21 +34,56 @@ func InitPro() {
 	)
 	)
 	logic.EnterpriseCheckFuncs = append(logic.EnterpriseCheckFuncs, func() {
 	logic.EnterpriseCheckFuncs = append(logic.EnterpriseCheckFuncs, func() {
 		// == License Handling ==
 		// == License Handling ==
-		ClearLicenseCache()
-		if err := ValidateLicense(); err != nil {
-			slog.Error(err.Error())
-			return
+		enableLicenseHook := false
+		licenseKeyValue := servercfg.GetLicenseKey()
+		netmakerTenantID := servercfg.GetNetmakerTenantID()
+		if licenseKeyValue != "" && netmakerTenantID != "" {
+			enableLicenseHook = true
+		}
+		if !enableLicenseHook {
+			err := initTrial()
+			if err != nil {
+				logger.Log(0, "failed to init trial", err.Error())
+				enableLicenseHook = true
+			}
+			trialEndDate, err := getTrialEndDate()
+			if err != nil {
+				slog.Error("failed to get trial end date", "error", err)
+				enableLicenseHook = true
+			} else {
+				// check if trial ended
+				if time.Now().After(trialEndDate) {
+					// trial ended already
+					enableLicenseHook = true
+				}
+			}
+
 		}
 		}
-		slog.Info("proceeding with Paid Tier license")
-		logic.SetFreeTierForTelemetry(false)
-		// == End License Handling ==
-		AddLicenseHooks()
+
+		if enableLicenseHook {
+			logger.Log(0, "starting license checker")
+			ClearLicenseCache()
+			if err := ValidateLicense(); err != nil {
+				slog.Error(err.Error())
+				return
+			}
+			logger.Log(0, "proceeding with Paid Tier license")
+			logic.SetFreeTierForTelemetry(false)
+			// == End License Handling ==
+			AddLicenseHooks()
+		} else {
+			logger.Log(0, "starting trial license hook")
+			addTrialLicenseHook()
+		}
+
 		if servercfg.GetServerConfig().RacAutoDisable {
 		if servercfg.GetServerConfig().RacAutoDisable {
 			AddRacHooks()
 			AddRacHooks()
 		}
 		}
+
 	})
 	})
 	logic.ResetFailOver = proLogic.ResetFailOver
 	logic.ResetFailOver = proLogic.ResetFailOver
 	logic.ResetFailedOverPeer = proLogic.ResetFailedOverPeer
 	logic.ResetFailedOverPeer = proLogic.ResetFailedOverPeer
+	logic.GetFailOverPeerIps = proLogic.GetFailOverPeerIps
 	logic.DenyClientNodeAccess = proLogic.DenyClientNode
 	logic.DenyClientNodeAccess = proLogic.DenyClientNode
 	logic.IsClientNodeAllowed = proLogic.IsClientNodeAllowed
 	logic.IsClientNodeAllowed = proLogic.IsClientNodeAllowed
 	logic.AllowClientNodeAccess = proLogic.RemoveDeniedNodeFromClient
 	logic.AllowClientNodeAccess = proLogic.RemoveDeniedNodeFromClient
@@ -63,6 +101,7 @@ func InitPro() {
 	logic.RelayUpdates = proLogic.RelayUpdates
 	logic.RelayUpdates = proLogic.RelayUpdates
 	logic.IsInternetGw = proLogic.IsInternetGw
 	logic.IsInternetGw = proLogic.IsInternetGw
 	logic.SetInternetGw = proLogic.SetInternetGw
 	logic.SetInternetGw = proLogic.SetInternetGw
+	logic.GetTrialEndDate = getTrialEndDate
 	mq.UpdateMetrics = proLogic.MQUpdateMetrics
 	mq.UpdateMetrics = proLogic.MQUpdateMetrics
 	mq.UpdateMetricsFallBack = proLogic.MQUpdateMetricsFallBack
 	mq.UpdateMetricsFallBack = proLogic.MQUpdateMetricsFallBack
 }
 }

+ 27 - 0
pro/logic/failover.go

@@ -2,6 +2,7 @@ package logic
 
 
 import (
 import (
 	"errors"
 	"errors"
+	"net"
 
 
 	"github.com/google/uuid"
 	"github.com/google/uuid"
 	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/logic"
@@ -96,3 +97,29 @@ func ResetFailOver(failOverNode *models.Node) error {
 	}
 	}
 	return nil
 	return nil
 }
 }
+
+// GetFailOverPeerIps - adds the failedOvered peerIps by the peer
+func GetFailOverPeerIps(peer, node *models.Node) []net.IPNet {
+	allowedips := []net.IPNet{}
+	for failOverpeerID := range node.FailOverPeers {
+		failOverpeer, err := logic.GetNodeByID(failOverpeerID)
+		if err == nil && failOverpeer.FailedOverBy == peer.ID {
+			if failOverpeer.Address.IP != nil {
+				allowed := net.IPNet{
+					IP:   failOverpeer.Address.IP,
+					Mask: net.CIDRMask(32, 32),
+				}
+				allowedips = append(allowedips, allowed)
+			}
+			if failOverpeer.Address6.IP != nil {
+				allowed := net.IPNet{
+					IP:   failOverpeer.Address6.IP,
+					Mask: net.CIDRMask(128, 128),
+				}
+				allowedips = append(allowedips, allowed)
+			}
+
+		}
+	}
+	return allowedips
+}

+ 161 - 0
pro/trial.go

@@ -0,0 +1,161 @@
+package pro
+
+import (
+	"crypto/rand"
+	"encoding/json"
+	"errors"
+	"time"
+
+	"github.com/gravitl/netmaker/database"
+	"github.com/gravitl/netmaker/logger"
+	"github.com/gravitl/netmaker/logic"
+	"github.com/gravitl/netmaker/models"
+	"github.com/gravitl/netmaker/netclient/ncutils"
+	"github.com/gravitl/netmaker/servercfg"
+	"golang.org/x/crypto/nacl/box"
+)
+
+type TrialInfo struct {
+	PrivKey []byte `json:"priv_key"`
+	PubKey  []byte `json:"pub_key"`
+	Secret  []byte `json:"secret"`
+}
+
+func addTrialLicenseHook() {
+	logic.HookManagerCh <- models.HookDetails{
+		Hook:     TrialLicenseHook,
+		Interval: time.Hour,
+	}
+}
+
+type TrialDates struct {
+	TrialStartedAt time.Time `json:"trial_started_at"`
+	TrialEndsAt    time.Time `json:"trial_ends_at"`
+}
+
+const trial_table_name = "trial"
+
+const trial_data_key = "trialdata"
+
+// stores trial end date
+func initTrial() error {
+	telData, err := logic.FetchTelemetryData()
+	if err != nil {
+		return err
+	}
+	if telData.Hosts > 0 || telData.Networks > 0 || telData.Users > 0 {
+		return nil // database is already populated, so skip creating trial
+	}
+	database.CreateTable(trial_table_name)
+	records, err := database.FetchRecords(trial_table_name)
+	if err != nil && !database.IsEmptyRecord(err) {
+		return err
+	}
+	if len(records) > 0 {
+		return nil
+	}
+	// setup encryption keys
+	trafficPubKey, trafficPrivKey, err := box.GenerateKey(rand.Reader) // generate traffic keys
+	if err != nil {
+		return err
+	}
+	tPriv, err := ncutils.ConvertKeyToBytes(trafficPrivKey)
+	if err != nil {
+		return err
+	}
+
+	tPub, err := ncutils.ConvertKeyToBytes(trafficPubKey)
+	if err != nil {
+		return err
+	}
+	trialDates := TrialDates{
+		TrialStartedAt: time.Now(),
+		TrialEndsAt:    time.Now().Add(time.Hour * 24 * 14),
+	}
+	t := TrialInfo{
+		PrivKey: tPriv,
+		PubKey:  tPub,
+	}
+	tel, err := logic.FetchTelemetryRecord()
+	if err != nil {
+		return err
+	}
+
+	trialDatesData, err := json.Marshal(trialDates)
+	if err != nil {
+		return err
+	}
+	telePubKey, err := ncutils.ConvertBytesToKey(tel.TrafficKeyPub)
+	if err != nil {
+		return err
+	}
+	trialDatesSecret, err := ncutils.BoxEncrypt(trialDatesData, telePubKey, trafficPrivKey)
+	if err != nil {
+		return err
+	}
+	t.Secret = trialDatesSecret
+	trialData, err := json.Marshal(t)
+	if err != nil {
+		return err
+	}
+	err = database.Insert(trial_data_key, string(trialData), trial_table_name)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+// TrialLicenseHook - hook func to check if pro trial has ended
+func TrialLicenseHook() error {
+	endDate, err := getTrialEndDate()
+	if err != nil {
+		logger.FatalLog0("failed to trial end date", err.Error())
+	}
+	if time.Now().After(endDate) {
+		logger.Log(0, "***IMPORTANT: Your Trial Has Ended, to continue using pro version, please visit https://app.netmaker.io/ and create on-prem tenant to obtain a license***\nIf you wish to downgrade to community version, please run this command `/root/nm-quick.sh -d`")
+		err = errors.New("your trial has ended")
+		servercfg.ErrLicenseValidation = err
+		return err
+	}
+	return nil
+}
+
+// get trial date
+func getTrialEndDate() (time.Time, error) {
+	record, err := database.FetchRecord(trial_table_name, trial_data_key)
+	if err != nil {
+		return time.Time{}, err
+	}
+	var trialInfo TrialInfo
+	err = json.Unmarshal([]byte(record), &trialInfo)
+	if err != nil {
+		return time.Time{}, err
+	}
+	tel, err := logic.FetchTelemetryRecord()
+	if err != nil {
+		return time.Time{}, err
+	}
+	telePrivKey, err := ncutils.ConvertBytesToKey(tel.TrafficKeyPriv)
+	if err != nil {
+		return time.Time{}, err
+	}
+	trialPubKey, err := ncutils.ConvertBytesToKey(trialInfo.PubKey)
+	if err != nil {
+		return time.Time{}, err
+	}
+	// decrypt secret
+	secretDecrypt, err := ncutils.BoxDecrypt(trialInfo.Secret, trialPubKey, telePrivKey)
+	if err != nil {
+		return time.Time{}, err
+	}
+	trialDates := TrialDates{}
+	err = json.Unmarshal(secretDecrypt, &trialDates)
+	if err != nil {
+		return time.Time{}, err
+	}
+	if trialDates.TrialEndsAt.IsZero() {
+		return time.Time{}, errors.New("invalid date")
+	}
+	return trialDates.TrialEndsAt, nil
+
+}

+ 206 - 264
scripts/nm-quick.sh

@@ -11,64 +11,25 @@ if [ $(id -u) -ne 0 ]; then
 	echo "This script must be run as root"
 	echo "This script must be run as root"
 	exit 1
 	exit 1
 fi
 fi
-
+# increase the timeouts
+export DOCKER_CLIENT_TIMEOUT=120
+export COMPOSE_HTTP_TIMEOUT=120
 unset INSTALL_TYPE
 unset INSTALL_TYPE
-unset BUILD_TYPE
 unset BUILD_TAG
 unset BUILD_TAG
 unset IMAGE_TAG
 unset IMAGE_TAG
-unset AUTO_BUILD
 unset NETMAKER_BASE_DOMAIN
 unset NETMAKER_BASE_DOMAIN
-
+unset UPGRADE_FLAG
 # usage - displays usage instructions
 # usage - displays usage instructions
 usage() {
 usage() {
 	echo "nm-quick.sh v$NM_QUICK_VERSION"
 	echo "nm-quick.sh v$NM_QUICK_VERSION"
-	echo "usage: ./nm-quick.sh [-e] [-b buildtype] [-t tag] [-a auto] [-d domain]"
-	echo "  -e      if specified, will install netmaker pro"
-	echo "  -b      type of build; options:"
-	echo "          \"version\" - will install a specific version of Netmaker using remote git and dockerhub"
-	echo "          \"local\": - will install by cloning repo and building images from git"
-	echo "          \"branch\": - will install a specific branch using remote git and dockerhub"
-	echo "  -t      tag of build; if buildtype=version, tag=version. If builtype=branch or builtype=local, tag=branch"
-	echo "  -a      auto-build; skip prompts and use defaults, if none provided"
-	echo "  -d      domain; if specified, will use this domain instead of auto-generating one"
-	echo "examples:"
-	echo "          nm-quick.sh -e -b version -t $LATEST"
-	echo "          nm-quick.sh -e -b local -t feature_v0.17.2_newfeature"
-	echo "          nm-quick.sh -e -b branch -t develop"
-	echo "          nm-quick.sh -e -b version -t $LATEST -a -d example.com"
+	echo "usage: ./nm-quick.sh [-c]"
+	echo " -c  if specified, will install netmaker community version"
+	echo " -u  if specified, will upgrade netmaker to pro version"
+	echo " -d if specified, will downgrade netmaker to community version"
 	exit 1
 	exit 1
 }
 }
 
 
-while getopts evab:d:t: flag; do
-	case "${flag}" in
-	e)
-		INSTALL_TYPE="pro"
-		UPGRADE_FLAG="yes"
-		;;
-	v)
-		usage
-		exit 0
-		;;
-	a)
-		AUTO_BUILD="on"
-		;;
-	b)
-		BUILD_TYPE=${OPTARG}
-		if [[ ! "$BUILD_TYPE" =~ ^(version|local|branch)$ ]]; then
-			echo "error: $BUILD_TYPE is invalid"
-			echo "valid options: version, local, branch"
-			usage
-			exit 1
-		fi
-		;;
-	t)
-		BUILD_TAG=${OPTARG}
-		;;
-	d)
-		NETMAKER_BASE_DOMAIN=${OPTARG}
-		;;
-	esac
-done
+
 
 
 # print_logo - prints the netmaker logo
 # print_logo - prints the netmaker logo
 print_logo() {
 print_logo() {
@@ -93,32 +54,12 @@ EOF
 # set_buildinfo - sets the information based on script input for how the installation should be run
 # set_buildinfo - sets the information based on script input for how the installation should be run
 set_buildinfo() {
 set_buildinfo() {
 
 
-	if [ -z "$BUILD_TYPE" ]; then
-		BUILD_TYPE="version"
-		BUILD_TAG=$LATEST
-	fi
-
-	if [ -z "$BUILD_TAG" ] && [ "$BUILD_TYPE" = "version" ]; then
-		BUILD_TAG=$LATEST
-	fi
-
-	if [ -z "$BUILD_TAG" ] && [ ! -z "$BUILD_TYPE" ]; then
-		echo "error: must specify build tag when build type \"$BUILD_TYPE\" is specified"
-		usage
-		exit 1
-	fi
 
 
+	
+	BUILD_TAG=$LATEST
 	IMAGE_TAG=$(sed 's/\//-/g' <<<"$BUILD_TAG")
 	IMAGE_TAG=$(sed 's/\//-/g' <<<"$BUILD_TAG")
 
 
-	if [ "$1" = "ce" ]; then
-		INSTALL_TYPE="ce"
-	elif [ "$1" = "pro" ]; then
-		INSTALL_TYPE="pro"
-	fi
-
-	if [ "$AUTO_BUILD" = "on" ] && [ -z "$INSTALL_TYPE" ]; then
-		INSTALL_TYPE="ce"
-	elif [ -z "$INSTALL_TYPE" ]; then
+	if [ -z "$INSTALL_TYPE" ]; then
 		echo "-----------------------------------------------------"
 		echo "-----------------------------------------------------"
 		echo "Would you like to install Netmaker Community Edition (CE), or Netmaker Enterprise Edition (pro)?"
 		echo "Would you like to install Netmaker Community Edition (CE), or Netmaker Enterprise Edition (pro)?"
 		echo "pro will require you to create an account at https://app.netmaker.io"
 		echo "pro will require you to create an account at https://app.netmaker.io"
@@ -141,7 +82,6 @@ set_buildinfo() {
 	fi
 	fi
 	echo "-----------Build Options-----------------------------"
 	echo "-----------Build Options-----------------------------"
 	echo "   Pro or CE: $INSTALL_TYPE"
 	echo "   Pro or CE: $INSTALL_TYPE"
-	echo "  Build Type: $BUILD_TYPE"
 	echo "   Build Tag: $BUILD_TAG"
 	echo "   Build Tag: $BUILD_TAG"
 	echo "   Image Tag: $IMAGE_TAG"
 	echo "   Image Tag: $IMAGE_TAG"
 	echo "   Installer: v$NM_QUICK_VERSION"
 	echo "   Installer: v$NM_QUICK_VERSION"
@@ -173,7 +113,9 @@ install_yq() {
 setup_netclient() {
 setup_netclient() {
 
 
 	set +e
 	set +e
-	netclient uninstall
+	if [ -x "$(command -v netclient)" ]; then
+		netclient uninstall
+	fi
 	set -e
 	set -e
 
 
 	wget -qO netclient https://github.com/gravitl/netclient/releases/download/$LATEST/netclient-linux-$ARCH
 	wget -qO netclient https://github.com/gravitl/netclient/releases/download/$LATEST/netclient-linux-$ARCH
@@ -257,9 +199,6 @@ wait_seconds() { (
 
 
 # confirm - get user input to confirm that they want to perform the next step
 # confirm - get user input to confirm that they want to perform the next step
 confirm() { (
 confirm() { (
-	if [ "$AUTO_BUILD" = "on" ]; then
-		return 0
-	fi
 	while true; do
 	while true; do
 		read -p 'Does everything look right? [y/n]: ' yn
 		read -p 'Does everything look right? [y/n]: ' yn
 		case $yn in
 		case $yn in
@@ -277,28 +216,26 @@ confirm() { (
 	done
 	done
 ) }
 ) }
 
 
+
 save_config() { (
 save_config() { (
 	echo "Saving the config to $CONFIG_PATH"
 	echo "Saving the config to $CONFIG_PATH"
 	touch "$CONFIG_PATH"
 	touch "$CONFIG_PATH"
-	save_config_item NM_EMAIL "$EMAIL"
-	save_config_item NM_DOMAIN "$NETMAKER_BASE_DOMAIN"
-	save_config_item UI_IMAGE_TAG "$IMAGE_TAG"
-	if [ "$BUILD_TYPE" = "local" ]; then
-		save_config_item UI_IMAGE_TAG "$LATEST"
-	else
-		save_config_item UI_IMAGE_TAG "$IMAGE_TAG"
+	if [ -n "$EMAIL" ]; then 
+		save_config_item NM_EMAIL "$EMAIL"
+	fi
+	if [ -n "$NETMAKER_BASE_DOMAIN" ]; then
+		save_config_item NM_DOMAIN "$NETMAKER_BASE_DOMAIN"
 	fi
 	fi
+	save_config_item UI_IMAGE_TAG "$IMAGE_TAG"
 	# version-specific entries
 	# version-specific entries
 	if [ "$INSTALL_TYPE" = "pro" ]; then
 	if [ "$INSTALL_TYPE" = "pro" ]; then
 		save_config_item NETMAKER_TENANT_ID "$TENANT_ID"
 		save_config_item NETMAKER_TENANT_ID "$TENANT_ID"
 		save_config_item LICENSE_KEY "$LICENSE_KEY"
 		save_config_item LICENSE_KEY "$LICENSE_KEY"
-		save_config_item METRICS_EXPORTER "on"
-		save_config_item PROMETHEUS "on"
-		if [ "$BUILD_TYPE" = "version" ]; then
-			save_config_item SERVER_IMAGE_TAG "$IMAGE_TAG-ee"
-		else
-			save_config_item SERVER_IMAGE_TAG "$IMAGE_TAG"
+		if [ "$UPGRADE_FLAG" = "yes" ];then
+			save_config_item METRICS_EXPORTER "on"
+			save_config_item PROMETHEUS "on"
 		fi
 		fi
+		save_config_item SERVER_IMAGE_TAG "$IMAGE_TAG-ee"
 	else
 	else
 		save_config_item METRICS_EXPORTER "off"
 		save_config_item METRICS_EXPORTER "off"
 		save_config_item PROMETHEUS "off"
 		save_config_item PROMETHEUS "off"
@@ -309,7 +246,7 @@ save_config() { (
 		"INSTALL_TYPE" "NODE_ID" "DNS_MODE" "NETCLIENT_AUTO_UPDATE" "API_PORT"
 		"INSTALL_TYPE" "NODE_ID" "DNS_MODE" "NETCLIENT_AUTO_UPDATE" "API_PORT"
 		"CORS_ALLOWED_ORIGIN" "DISPLAY_KEYS" "DATABASE" "SERVER_BROKER_ENDPOINT" "VERBOSITY"
 		"CORS_ALLOWED_ORIGIN" "DISPLAY_KEYS" "DATABASE" "SERVER_BROKER_ENDPOINT" "VERBOSITY"
 		"DEBUG_MODE"  "REST_BACKEND" "DISABLE_REMOTE_IP_CHECK" "TELEMETRY" "AUTH_PROVIDER" "CLIENT_ID" "CLIENT_SECRET"
 		"DEBUG_MODE"  "REST_BACKEND" "DISABLE_REMOTE_IP_CHECK" "TELEMETRY" "AUTH_PROVIDER" "CLIENT_ID" "CLIENT_SECRET"
-		"FRONTEND_URL" "AZURE_TENANT" "OIDC_ISSUER" "EXPORTER_API_PORT" "JWT_VALIDITY_DURATION" "RAC_AUTO_DISABLE")
+		"FRONTEND_URL" "AZURE_TENANT" "OIDC_ISSUER" "EXPORTER_API_PORT" "JWT_VALIDITY_DURATION" "RAC_AUTO_DISABLE" "CACHING_ENABLED")
 	for name in "${toCopy[@]}"; do
 	for name in "${toCopy[@]}"; do
 		save_config_item $name "${!name}"
 		save_config_item $name "${!name}"
 	done
 	done
@@ -345,38 +282,7 @@ save_config_item() { (
 	fi
 	fi
 ); }
 ); }
 
 
-# local_install_setup - builds artifacts based on specified branch locally to use in install
-local_install_setup() { (
-	if test -z "$NM_SKIP_CLONE"; then
-		rm -rf netmaker-tmp
-		mkdir netmaker-tmp
-		cd netmaker-tmp
-		git clone --single-branch --depth=1 --branch=$BUILD_TAG https://www.github.com/gravitl/netmaker
-	else
-		cd netmaker-tmp
-		echo "Skipping git clone on NM_SKIP_CLONE"
-	fi
-	cd netmaker
-	if test -z "$NM_SKIP_BUILD"; then
-		docker build --no-cache --build-arg version=$IMAGE_TAG -t gravitl/netmaker:$IMAGE_TAG .
-	else
-		echo "Skipping build on NM_SKIP_BUILD"
-	fi
-	cp compose/docker-compose.yml "$SCRIPT_DIR/docker-compose.yml"
-	if [ "$INSTALL_TYPE" = "pro" ]; then
-		cp compose/docker-compose.ee.yml "$SCRIPT_DIR/docker-compose.override.yml"
-		cp docker/Caddyfile-pro "$SCRIPT_DIR/Caddyfile"
-	else
-		cp docker/Caddyfile "$SCRIPT_DIR/Caddyfile"
-	fi
-	cp scripts/netmaker.default.env "$SCRIPT_DIR/netmaker.default.env"
-	cp docker/mosquitto.conf "$SCRIPT_DIR/mosquitto.conf"
-	cp docker/wait.sh "$SCRIPT_DIR/wait.sh"
-	cd ../../
-	if test -z "$NM_SKIP_CLONE"; then
-		rm -rf netmaker-tmp
-	fi
-); }
+
 
 
 # install_dependencies - install necessary packages to run netmaker
 # install_dependencies - install necessary packages to run netmaker
 install_dependencies() {
 install_dependencies() {
@@ -520,27 +426,23 @@ set_install_vars() {
 	echo "For this reason, we STRONGLY RECOMMEND using your own domain. Using the auto-generated domain may lead to a failed installation due to rate limiting."
 	echo "For this reason, we STRONGLY RECOMMEND using your own domain. Using the auto-generated domain may lead to a failed installation due to rate limiting."
 	echo "-----------------------------------------------------"
 	echo "-----------------------------------------------------"
 
 
-	if [ "$AUTO_BUILD" = "on" ]; then
-		DOMAIN_TYPE="auto"
-	else
-		select domain_option in "Auto Generated ($NETMAKER_BASE_DOMAIN)" "Custom Domain (e.x: netmaker.example.com)"; do
-			case $REPLY in
-			1)
-				echo "using $NETMAKER_BASE_DOMAIN for base domain"
-				DOMAIN_TYPE="auto"
-				break
-				;;
-			2)
-				read -p "Enter Custom Domain (make sure  *.domain points to $SERVER_HOST first): " domain
-				NETMAKER_BASE_DOMAIN=$domain
-				echo "using $NETMAKER_BASE_DOMAIN"
-				DOMAIN_TYPE="custom"
-				break
-				;;
-			*) echo "invalid option $REPLY" ;;
-			esac
-		done
-	fi
+	select domain_option in "Auto Generated ($NETMAKER_BASE_DOMAIN)" "Custom Domain (e.x: netmaker.example.com)"; do
+		case $REPLY in
+		1)
+			echo "using $NETMAKER_BASE_DOMAIN for base domain"
+			DOMAIN_TYPE="auto"
+			break
+			;;
+		2)
+			read -p "Enter Custom Domain (make sure  *.domain points to $SERVER_HOST first): " domain
+			NETMAKER_BASE_DOMAIN=$domain
+			echo "using $NETMAKER_BASE_DOMAIN"
+			DOMAIN_TYPE="custom"
+			break
+			;;
+		*) echo "invalid option $REPLY" ;;
+		esac
+	done
 
 
 	wait_seconds 2
 	wait_seconds 2
 
 
@@ -550,7 +452,7 @@ set_install_vars() {
 	echo "                api.$NETMAKER_BASE_DOMAIN"
 	echo "                api.$NETMAKER_BASE_DOMAIN"
 	echo "             broker.$NETMAKER_BASE_DOMAIN"
 	echo "             broker.$NETMAKER_BASE_DOMAIN"
 
 
-	if [ "$INSTALL_TYPE" = "pro" ]; then
+	if [ "$UPGRADE_FLAG" = "yes" ]; then
 		echo "         prometheus.$NETMAKER_BASE_DOMAIN"
 		echo "         prometheus.$NETMAKER_BASE_DOMAIN"
 		echo "  netmaker-exporter.$NETMAKER_BASE_DOMAIN"
 		echo "  netmaker-exporter.$NETMAKER_BASE_DOMAIN"
 		echo "            grafana.$NETMAKER_BASE_DOMAIN"
 		echo "            grafana.$NETMAKER_BASE_DOMAIN"
@@ -565,33 +467,13 @@ set_install_vars() {
 
 
 	wait_seconds 1
 	wait_seconds 1
 
 
-	if [ "$INSTALL_TYPE" = "pro" ]; then
-
-		echo "-----------------------------------------------------"
-		echo "Provide Details for pro installation:"
-		echo "    1. Log into https://app.netmaker.io"
-		echo "    2. follow instructions to get a license at: https://docs.netmaker.io/ee/ee-setup.html"
-		echo "    3. Retrieve License and Tenant ID"
-		echo "    4. note email address"
-		echo "-----------------------------------------------------"
-		unset LICENSE_KEY
-		while [ -z "$LICENSE_KEY" ]; do
-			read -p "License Key: " LICENSE_KEY
-		done
-		unset TENANT_ID
-		while [ -z ${TENANT_ID} ]; do
-			read -p "Tenant ID: " TENANT_ID
-		done
-	fi
 
 
 	unset GET_EMAIL
 	unset GET_EMAIL
 	unset RAND_EMAIL
 	unset RAND_EMAIL
 	RAND_EMAIL="$(echo $RANDOM | md5sum | head -c 16)@email.com"
 	RAND_EMAIL="$(echo $RANDOM | md5sum | head -c 16)@email.com"
 	# suggest the prev email or a random one
 	# suggest the prev email or a random one
 	EMAIL_SUGGESTED=${NM_EMAIL:-$RAND_EMAIL}
 	EMAIL_SUGGESTED=${NM_EMAIL:-$RAND_EMAIL}
-	if [ -z $AUTO_BUILD ]; then
-		read -p "Email Address for Domain Registration (click 'enter' to use $EMAIL_SUGGESTED): " GET_EMAIL
-	fi
+	read -p "Email Address for Domain Registration (click 'enter' to use $EMAIL_SUGGESTED): " GET_EMAIL
 	if [ -z "$GET_EMAIL" ]; then
 	if [ -z "$GET_EMAIL" ]; then
 		EMAIL="$EMAIL_SUGGESTED"
 		EMAIL="$EMAIL_SUGGESTED"
 		if [ "$EMAIL" = "$NM_EMAIL" ]; then
 		if [ "$EMAIL" = "$NM_EMAIL" ]; then
@@ -609,9 +491,8 @@ set_install_vars() {
 	unset GET_MQ_PASSWORD
 	unset GET_MQ_PASSWORD
 	unset CONFIRM_MQ_PASSWORD
 	unset CONFIRM_MQ_PASSWORD
 	echo "Enter Credentials For MQ..."
 	echo "Enter Credentials For MQ..."
-	if [ -z $AUTO_BUILD ]; then
-		read -p "MQ Username (click 'enter' to use 'netmaker'): " GET_MQ_USERNAME
-	fi
+	
+	read -p "MQ Username (click 'enter' to use 'netmaker'): " GET_MQ_USERNAME
 	if [ -z "$GET_MQ_USERNAME" ]; then
 	if [ -z "$GET_MQ_USERNAME" ]; then
 		echo "using default username for mq"
 		echo "using default username for mq"
 		MQ_USERNAME="netmaker"
 		MQ_USERNAME="netmaker"
@@ -626,33 +507,33 @@ set_install_vars() {
 		)
 		)
 	fi
 	fi
 
 
-	if [ -z $AUTO_BUILD ]; then
-		select domain_option in "Auto Generated / Config Password" "Input Your Own Password"; do
-			case $REPLY in
-			1)
-				echo "using random password for mq"
-				break
-				;;
-			2)
-				while true; do
-					echo "Enter your Password For MQ: "
-					read -s GET_MQ_PASSWORD
-					echo "Enter your password again to confirm: "
-					read -s CONFIRM_MQ_PASSWORD
-					if [ ${GET_MQ_PASSWORD} != ${CONFIRM_MQ_PASSWORD} ]; then
-						echo "wrong password entered, try again..."
-						continue
-					fi
-					MQ_PASSWORD="$GET_MQ_PASSWORD"
-					echo "MQ Password Saved Successfully!!"
-					break
-				done
+
+	select domain_option in "Auto Generated / Config Password" "Input Your Own Password"; do
+		case $REPLY in
+		1)
+			echo "using random password for mq"
+			break
+			;;
+		2)
+			while true; do
+				echo "Enter your Password For MQ: "
+				read -s GET_MQ_PASSWORD
+				echo "Enter your password again to confirm: "
+				read -s CONFIRM_MQ_PASSWORD
+				if [ ${GET_MQ_PASSWORD} != ${CONFIRM_MQ_PASSWORD} ]; then
+					echo "wrong password entered, try again..."
+					continue
+				fi
+				MQ_PASSWORD="$GET_MQ_PASSWORD"
+				echo "MQ Password Saved Successfully!!"
 				break
 				break
-				;;
-			*) echo "invalid option $REPLY" ;;
-			esac
-		done
-	fi
+			done
+			break
+			;;
+		*) echo "invalid option $REPLY" ;;
+		esac
+	done
+	
 
 
 	wait_seconds 2
 	wait_seconds 2
 
 
@@ -662,18 +543,10 @@ set_install_vars() {
 	echo "        domain: $NETMAKER_BASE_DOMAIN"
 	echo "        domain: $NETMAKER_BASE_DOMAIN"
 	echo "         email: $EMAIL"
 	echo "         email: $EMAIL"
 	echo "     public ip: $SERVER_HOST"
 	echo "     public ip: $SERVER_HOST"
-	if [ "$INSTALL_TYPE" = "pro" ]; then
-		echo "       license: $LICENSE_KEY"
-		echo "    account id: $TENANT_ID"
-	fi
 	echo "-----------------------------------------------------------------"
 	echo "-----------------------------------------------------------------"
 	echo "Confirm Settings for Installation"
 	echo "Confirm Settings for Installation"
 	echo "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"
 	echo "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"
 
 
-	if [ ! "$BUILD_TYPE" = "local" ]; then
-		IMAGE_TAG="$LATEST"
-	fi
-
 	confirm
 	confirm
 }
 }
 
 
@@ -688,26 +561,24 @@ install_netmaker() {
 
 
 	echo "Pulling config files..."
 	echo "Pulling config files..."
 
 
-	if [ "$BUILD_TYPE" = "local" ]; then
-		local_install_setup
-	else
-		local BASE_URL="https://raw.githubusercontent.com/gravitl/netmaker/$BUILD_TAG"
-
-		local COMPOSE_URL="$BASE_URL/compose/docker-compose.yml"
-		local CADDY_URL="$BASE_URL/docker/Caddyfile"
-		if [ "$INSTALL_TYPE" = "pro" ]; then
-			local COMPOSE_OVERRIDE_URL="$BASE_URL/compose/docker-compose.pro.yml"
-			local CADDY_URL="$BASE_URL/docker/Caddyfile-pro"
-		fi
-		wget -qO "$SCRIPT_DIR"/docker-compose.yml $COMPOSE_URL
-		if test -n "$COMPOSE_OVERRIDE_URL"; then
-			wget -qO "$SCRIPT_DIR"/docker-compose.override.yml $COMPOSE_OVERRIDE_URL
-		fi
-		wget -qO "$SCRIPT_DIR"/Caddyfile "$CADDY_URL"
-		wget -qO "$SCRIPT_DIR"/netmaker.default.env "$BASE_URL/scripts/netmaker.default.env"
-		wget -qO "$SCRIPT_DIR"/mosquitto.conf "$BASE_URL/docker/mosquitto.conf"
-		wget -qO "$SCRIPT_DIR"/wait.sh "$BASE_URL/docker/wait.sh"
+	
+	local BASE_URL="https://raw.githubusercontent.com/gravitl/netmaker/$BUILD_TAG"
+	local COMPOSE_URL="$BASE_URL/compose/docker-compose.yml"
+	local CADDY_URL="$BASE_URL/docker/Caddyfile"
+	if [ "$INSTALL_TYPE" = "pro" ]; then
+		local COMPOSE_OVERRIDE_URL="$BASE_URL/compose/docker-compose.pro.yml"
+		local CADDY_URL="$BASE_URL/docker/Caddyfile-pro"
+	fi
+	wget -qO "$SCRIPT_DIR"/docker-compose.yml $COMPOSE_URL
+	if [ "$UPGRADE_FLAG" = "yes" ]; then
+		wget -qO "$SCRIPT_DIR"/docker-compose.override.yml $COMPOSE_OVERRIDE_URL
+	elif [ -a "$SCRIPT_DIR"/docker-compose.override.yml ]; then
+		rm -f "$SCRIPT_DIR"/docker-compose.override.yml
 	fi
 	fi
+	wget -qO "$SCRIPT_DIR"/Caddyfile "$CADDY_URL"
+	wget -qO "$SCRIPT_DIR"/netmaker.default.env "$BASE_URL/scripts/netmaker.default.env"
+	wget -qO "$SCRIPT_DIR"/mosquitto.conf "$BASE_URL/docker/mosquitto.conf"
+	wget -qO "$SCRIPT_DIR"/wait.sh "$BASE_URL/docker/wait.sh"
 
 
 	chmod +x "$SCRIPT_DIR"/wait.sh
 	chmod +x "$SCRIPT_DIR"/wait.sh
 	mkdir -p /etc/netmaker
 	mkdir -p /etc/netmaker
@@ -718,9 +589,7 @@ install_netmaker() {
 
 
 	echo "Starting containers..."
 	echo "Starting containers..."
 
 
-	# increase the timeouts
-	export DOCKER_CLIENT_TIMEOUT=120
-	export COMPOSE_HTTP_TIMEOUT=120
+	
 
 
 	# start docker and rebuild containers / networks
 	# start docker and rebuild containers / networks
 	cd "${SCRIPT_DIR}"
 	cd "${SCRIPT_DIR}"
@@ -800,6 +669,9 @@ print_success() {
 
 
 cleanup() {
 cleanup() {
 	# remove the existing netclient's instance from the existing network
 	# remove the existing netclient's instance from the existing network
+	if ! command -v netclient >/dev/null 2>&1; then
+		return
+	fi
 	if command -v nmctl >/dev/null 2>&1; then
 	if command -v nmctl >/dev/null 2>&1; then
 		local node_id=$(netclient list | jq '.[0].node_id' 2>/dev/null)
 		local node_id=$(netclient list | jq '.[0].node_id' 2>/dev/null)
 		# trim doublequotes
 		# trim doublequotes
@@ -810,7 +682,11 @@ cleanup() {
 		fi
 		fi
 	fi
 	fi
 
 
-	echo "Stopping all containers..."
+	stop_services
+}
+
+stop_services(){
+	echo "Stopping all containers, this will take a while please wait..."
 	local containers=("mq" "netmaker-ui" "coredns" "turn" "caddy" "netmaker" "netmaker-exporter" "prometheus" "grafana")
 	local containers=("mq" "netmaker-ui" "coredns" "turn" "caddy" "netmaker" "netmaker-exporter" "prometheus" "grafana")
 	for name in "${containers[@]}"; do
 	for name in "${containers[@]}"; do
 		local running=$(docker ps | grep -w "$name")
 		local running=$(docker ps | grep -w "$name")
@@ -824,61 +700,127 @@ cleanup() {
 	done
 	done
 }
 }
 
 
-# 1. print netmaker logo
-print_logo
+upgrade() {
+	print_logo
+	unset IMAGE_TAG
+	unset BUILD_TAG
+	IMAGE_TAG=$UI_IMAGE_TAG
+	BUILD_TAG=$UI_IMAGE_TAG
+	echo "-----------------------------------------------------"
+	echo "Provide Details for pro installation:"
+	echo "    1. Log into https://app.netmaker.io"
+	echo "    2. follow instructions to get a license at: https://docs.netmaker.io/ee/ee-setup.html"
+	echo "    3. Retrieve License and Tenant ID"
+	echo "-----------------------------------------------------"
+	unset LICENSE_KEY
+	while [ -z "$LICENSE_KEY" ]; do
+		read -p "License Key: " LICENSE_KEY
+	done
+	unset TENANT_ID
+	while [ -z ${TENANT_ID} ]; do
+		read -p "Tenant ID: " TENANT_ID
+	done
+	save_config
+	# start docker and rebuild containers / networks
+	stop_services
+	install_netmaker
+}
 
 
-# read the config
-if [ -f "$CONFIG_PATH" ]; then
-	echo "Using config: $CONFIG_PATH"
-	source "$CONFIG_PATH"
-	if [ "$UPGRADE_FLAG" = "yes" ]; then
-		INSTALL_TYPE="pro"
+downgrade () {
+	print_logo
+	unset IMAGE_TAG
+	unset BUILD_TAG
+	IMAGE_TAG=$UI_IMAGE_TAG
+	BUILD_TAG=$UI_IMAGE_TAG
+	save_config
+	if [ -a "$SCRIPT_DIR"/docker-compose.override.yml ]; then
+		rm -f "$SCRIPT_DIR"/docker-compose.override.yml
 	fi
 	fi
-fi
+	# start docker and rebuild containers / networks
+	stop_services
+	install_netmaker
+}
+
+
+main (){
 
 
-# 2. setup the build instructions
-set_buildinfo
+	# read the config
+	if [ -f "$CONFIG_PATH" ]; then
+		echo "Using config: $CONFIG_PATH"
+		source "$CONFIG_PATH"
+	fi
+
+	INSTALL_TYPE="pro"
+	while getopts :cudv flag; do
+	case "${flag}" in
+	c)
+		INSTALL_TYPE="ce"
+		;;
+	u)
+		echo "upgrading to pro version..."
+		INSTALL_TYPE="pro"
+		UPGRADE_FLAG="yes"
+		upgrade
+		exit 0
+		;;
+	d) 
+		echo "downgrading to community version..."
+		INSTALL_TYPE="ce"
+		downgrade
+		exit 0
+		;;
+	v)
+		usage
+		exit 0
+		;;
+	esac
+done
 
 
-set +e
+	# 1. print netmaker logo
+	print_logo
 
 
-# 3. install necessary packages
-install_dependencies
+	# 2. setup the build instructions
+	set_buildinfo
+	set +e
+	# 3. install necessary packages
+	install_dependencies
 
 
-# 4. install yq if necessary
-install_yq
+	# 4. install yq if necessary
+	install_yq
 
 
-set -e
+	set -e
 
 
-# 6. get user input for variables
-set_install_vars
+	# 6. get user input for variables
+	set_install_vars
 
 
-set +e
-cleanup
-set -e
+	set +e
+	cleanup
+	set -e
 
 
-# 7. get and set config files, startup docker-compose
-install_netmaker
+	# 7. get and set config files, startup docker-compose
+	install_netmaker
 
 
-set +e
+	set +e
 
 
-# 8. make sure Caddy certs are working
-test_connection
+	# 8. make sure Caddy certs are working
+	test_connection
 
 
-# 9. install the netmaker CLI
-setup_nmctl
+	# 9. install the netmaker CLI
+	setup_nmctl
 
 
-# 10. create a default mesh network for netmaker
-setup_mesh
+	# 10. create a default mesh network for netmaker
+	setup_mesh
 
 
-set -e
+	set -e
 
 
-# 11. add netclient to docker-compose and start it up
-setup_netclient
+	# 11. add netclient to docker-compose and start it up
+	setup_netclient
 
 
-# 12. make the netclient a default host and ingress gw
-configure_netclient
+	# 12. make the netclient a default host and ingress gw
+	configure_netclient
 
 
-# 13. print success message
-print_success
+	# 13. print success message
+	print_success
+}
 
 
-# cp -f /etc/skel/.bashrc /root/.bashrc
+main "${@}"