mirror of
				https://github.com/gravitl/netmaker.git
				synced 2025-10-31 20:22:44 +08:00 
			
		
		
		
	migration (#2509)
* create gateways during migration * set version for testing * restruct migration * debug logging * enforce unique names for ext client names (#2476) * enforce unique names for ext client names * only check for unique id on creation * check for unique id if changed * prune(NET-483): remove defunct host.internetgateway field (#2487) * don't reference host on err (#2493) * deprecrate netclient install scripts (#2490) * Net 500: validate network parameter passed to node endpoints (#2480) * enforce unique names for ext client names * only check for unique id on creation * check for unique id if changed * validate network parameter passed to node endpoints --------- Co-authored-by: Abhishek K <32607604+abhishek9686@users.noreply.github.com> * NET-513 (#2492) nm-certs.sh now requests certificate for EE and CE edition domains accordingly. * [NET-404] Run in limited mode when ee checks fail (#2474) * Add limited http handlers functionality to rest handler * Export ee.errValidation (ee.ErrValidation) * Export a fatal error handled by the hook manager * Export a new status variable for unlicensed server * Mark server as unlicensed when ee checks fail * Handle license validation failures with a (re)boot in a limited state * Revert "Export a fatal error handled by the hook manager" This reverts commit 069c21974a8d36e889c73ad78023448d787d62a5. * Revert "Export ee.errValidation (ee.ErrValidation)" This reverts commit 59dbab8c79773ca5d879f28cbaf53f3dd4297b9b. * Revert "Add limited http handlers functionality to rest handler" This reverts commit e2f1f28facaca54713db76a588839cd2733cf673. * Revert "Handle license validation failures with a (re)boot in a limited state" This reverts commit 58cfbbaf522a1345aac1fa67964ebff0a6d60cd8. * Revert "Mark server as unlicensed when ee checks fail" This reverts commit 77c6dbdd3c9cfa6e7d6becedef6251e8617ae367. * Handle license validation failures with a middleware * Forbid responses if unlicensed ee and not in status api * Remove unused func * feat(NET-449): add sync feature to request a host pull from server (#2491) * fix(NET-486): change client name length validation (#2498) set limit to 5<=x<=32 * [NET-477] Pick AMB URL dynamically (#2489) * Introduce config for environment * Introduce func to get environment * Choose accounts api host from environment * Test the ee package on workflows * Use build tag ee for license_test.go * [Feature]: nm-quick script tackling arm TODO support (#2488) * domain flag for auto installs * use static servers with custom domain (#2421) * send delete peer update always * fix add/remove host api calls * keep mq updates in a single go func * move branch test logic to devops (#2443) * handle IOT OS * save server name to env (#2460) * ensure branch test servers available after test runs (#2467) * save server name to env * free server always; add PR to discord messages * use correct method to delete droplets (#2468) * quick fix for the launcher * removed exit when triggering not supported exit and removed the TODO comments related to this issue --------- Co-authored-by: Matthew R Kasun <mkasun@nusak.ca> Co-authored-by: Alex Feiszli <31018251+afeiszli@users.noreply.github.com> Co-authored-by: Christopher Blaha <crispspiceguitar@gmail.com> Co-authored-by: Abhishek Kondur <abhi281342@gmail.com> Co-authored-by: Abhishek K <32607604+abhishek9686@users.noreply.github.com> * rebase conflict * include pass and os in mirgration data * node network ranges * remove debugging logs * add gateways * use sent node * upgrade shell script * associate node to host during migration * add node to host.Nodes and publish peer update * save host outside loop * fix script name * simplify upgrade script * don't migrate relays * simplify upgrade script even more * guard against blank address or address6 * typos --------- Co-authored-by: Aceix <aceixsmartX@gmail.com> Co-authored-by: Abhishek K <32607604+abhishek9686@users.noreply.github.com> Co-authored-by: Farukh Khan <farukhkhan21@gmail.com> Co-authored-by: Gabriel de Souza Seibel <gabrielseibel1@gmail.com> Co-authored-by: bornav <51048565+bornav@users.noreply.github.com> Co-authored-by: Alex Feiszli <31018251+afeiszli@users.noreply.github.com> Co-authored-by: Christopher Blaha <crispspiceguitar@gmail.com> Co-authored-by: Abhishek Kondur <abhi281342@gmail.com>
This commit is contained in:
		| @@ -2,15 +2,22 @@ package controller | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
|  | 	"fmt" | ||||||
|  | 	"net" | ||||||
| 	"net/http" | 	"net/http" | ||||||
|  | 	"strconv" | ||||||
|  | 	"time" | ||||||
|  |  | ||||||
| 	"github.com/gravitl/netmaker/auth" | 	"github.com/google/uuid" | ||||||
| 	"github.com/gravitl/netmaker/database" | 	"github.com/gravitl/netmaker/database" | ||||||
| 	"github.com/gravitl/netmaker/logger" | 	"github.com/gravitl/netmaker/logger" | ||||||
| 	"github.com/gravitl/netmaker/logic" | 	"github.com/gravitl/netmaker/logic" | ||||||
| 	"github.com/gravitl/netmaker/models" | 	"github.com/gravitl/netmaker/models" | ||||||
|  | 	"github.com/gravitl/netmaker/mq" | ||||||
| 	"github.com/gravitl/netmaker/servercfg" | 	"github.com/gravitl/netmaker/servercfg" | ||||||
| 	"golang.org/x/crypto/bcrypt" | 	"golang.org/x/crypto/bcrypt" | ||||||
|  | 	"golang.org/x/exp/slog" | ||||||
|  | 	"golang.zx2c4.com/wireguard/wgctrl/wgtypes" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // swagger:route PUT /api/v1/nodes/migrate nodes migrateNode | // swagger:route PUT /api/v1/nodes/migrate nodes migrateNode | ||||||
| @@ -26,63 +33,182 @@ import ( | |||||||
| //				200: nodeJoinResponse | //				200: nodeJoinResponse | ||||||
| func migrate(w http.ResponseWriter, r *http.Request) { | func migrate(w http.ResponseWriter, r *http.Request) { | ||||||
| 	data := models.MigrationData{} | 	data := models.MigrationData{} | ||||||
|  | 	host := models.Host{} | ||||||
|  | 	node := models.Node{} | ||||||
|  | 	nodes := []models.Node{} | ||||||
|  | 	server := models.ServerConfig{} | ||||||
| 	err := json.NewDecoder(r.Body).Decode(&data) | 	err := json.NewDecoder(r.Body).Decode(&data) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		logger.Log(0, r.Header.Get("user"), "error decoding request body: ", err.Error()) | 		logger.Log(0, r.Header.Get("user"), "error decoding request body: ", err.Error()) | ||||||
| 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) | 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  | 	for i, legacy := range data.LegacyNodes { | ||||||
| 	var networksToAdd = []string{} | 		record, err := database.FetchRecord(database.NODES_TABLE_NAME, legacy.ID) | ||||||
| 	for i := range data.LegacyNodes { |  | ||||||
| 		legacyNode := data.LegacyNodes[i] |  | ||||||
| 		record, err := database.FetchRecord(database.NODES_TABLE_NAME, legacyNode.ID) |  | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			logger.Log(0, "no record for legacy node", legacyNode.ID, err.Error()) | 			slog.Error("legacy node not found", "error", err) | ||||||
| 			continue | 			logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("legacy node not found %w", err), "badrequest")) | ||||||
| 		} else { |  | ||||||
| 			var oldLegacyNode models.LegacyNode |  | ||||||
| 			if err = json.Unmarshal([]byte(record), &oldLegacyNode); err != nil { |  | ||||||
| 				logger.Log(0, "error decoding legacy node", err.Error()) |  | ||||||
| 				logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) |  | ||||||
| 				continue |  | ||||||
| 			} |  | ||||||
| 			if err := bcrypt.CompareHashAndPassword([]byte(oldLegacyNode.Password), []byte(legacyNode.Password)); err != nil { |  | ||||||
| 				logger.Log(0, "error decoding legacy password", err.Error()) |  | ||||||
| 				logic.ReturnErrorResponse(w, r, logic.FormatError(err, "unauthorized")) |  | ||||||
| 				continue |  | ||||||
| 			} |  | ||||||
| 			networksToAdd = append(networksToAdd, oldLegacyNode.Network) |  | ||||||
| 			_ = database.DeleteRecord(database.NODES_TABLE_NAME, oldLegacyNode.ID) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	if len(networksToAdd) == 0 { |  | ||||||
| 		logger.Log(0, "no valid networks to migrate for host", data.NewHost.Name) |  | ||||||
| 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "unauthorized")) |  | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
| 	if !logic.HostExists(&data.NewHost) { | 		var legacyNode models.LegacyNode | ||||||
| 		logic.CheckHostPorts(&data.NewHost) | 		if err = json.Unmarshal([]byte(record), &legacyNode); err != nil { | ||||||
| 		if err = logic.CreateHost(&data.NewHost); err != nil { | 			slog.Error("decoding legacy node", "errror", err) | ||||||
|  | 			logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("decode legacy node %w", err), "badrequest")) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 		if err := bcrypt.CompareHashAndPassword([]byte(legacyNode.Password), []byte(legacy.Password)); err != nil { | ||||||
|  | 			slog.Error("legacy node invalid password", "error", err) | ||||||
|  | 			logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("invalid password %w", err), "unauthorized")) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 		if i == 0 { | ||||||
|  | 			host, node = convertLegacyHostNode(legacy) | ||||||
|  | 			host.Name = data.HostName | ||||||
|  | 			host.HostPass = data.Password | ||||||
|  | 			host.OS = data.OS | ||||||
|  | 			if err := logic.CreateHost(&host); err != nil { | ||||||
|  | 				slog.Error("create host", "error", err) | ||||||
| 				logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) | 				logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) | ||||||
| 				return | 				return | ||||||
| 			} | 			} | ||||||
|  | 			server = servercfg.GetServerInfo() | ||||||
|  | 			if servercfg.GetBrokerType() == servercfg.EmqxBrokerType { | ||||||
|  | 				server.MQUserName = host.ID.String() | ||||||
| 			} | 			} | ||||||
| 			key, keyErr := logic.RetrievePublicTrafficKey() | 			key, keyErr := logic.RetrievePublicTrafficKey() | ||||||
| 			if keyErr != nil { | 			if keyErr != nil { | ||||||
| 		logger.Log(0, "error retrieving key:", keyErr.Error()) | 				slog.Error("retrieving traffickey", "error", err) | ||||||
| 				logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) | 				logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) | ||||||
| 				return | 				return | ||||||
| 			} | 			} | ||||||
| 	server := servercfg.GetServerInfo() |  | ||||||
| 			server.TrafficKey = key | 			server.TrafficKey = key | ||||||
| 	response := models.RegisterResponse{ | 		} else { | ||||||
| 		ServerConf:    server, | 			node = convertLegacyNode(legacyNode, host.ID) | ||||||
| 		RequestedHost: data.NewHost, | 		} | ||||||
|  | 		if err := logic.UpsertNode(&node); err != nil { | ||||||
|  | 			slog.Error("update node", "error", err) | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		host.Nodes = append(host.Nodes, node.ID.String()) | ||||||
|  |  | ||||||
|  | 		nodes = append(nodes, node) | ||||||
|  | 	} | ||||||
|  | 	if err := logic.UpsertHost(&host); err != nil { | ||||||
|  | 		slog.Error("save host", "error", err) | ||||||
|  | 	} | ||||||
|  | 	go mq.PublishPeerUpdate() | ||||||
|  | 	response := models.HostPull{ | ||||||
|  | 		Host:         host, | ||||||
|  | 		Nodes:        nodes, | ||||||
|  | 		ServerConfig: server, | ||||||
| 	} | 	} | ||||||
| 	w.WriteHeader(http.StatusOK) | 	w.WriteHeader(http.StatusOK) | ||||||
| 	json.NewEncoder(w).Encode(&response) | 	json.NewEncoder(w).Encode(&response) | ||||||
| 	logger.Log(0, "successfully migrated host", data.NewHost.Name, data.NewHost.ID.String()) |  | ||||||
| 	// notify host of changes, peer and node updates | 	slog.Info("migrated nodes") | ||||||
| 	go auth.CheckNetRegAndHostUpdate(networksToAdd, &data.NewHost) | 	// check for gateways | ||||||
|  | 	for _, node := range data.LegacyNodes { | ||||||
|  | 		if node.IsEgressGateway == "yes" { | ||||||
|  | 			egressGateway := models.EgressGatewayRequest{ | ||||||
|  | 				NodeID:     node.ID, | ||||||
|  | 				Ranges:     node.EgressGatewayRanges, | ||||||
|  | 				NatEnabled: node.EgressGatewayNatEnabled, | ||||||
|  | 			} | ||||||
|  | 			if _, err := logic.CreateEgressGateway(egressGateway); err != nil { | ||||||
|  | 				logger.Log(0, "error creating egress gateway for node", node.ID, err.Error()) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		if node.IsIngressGateway == "yes" { | ||||||
|  | 			ingressGateway := models.IngressRequest{} | ||||||
|  | 			ingressNode, err := logic.CreateIngressGateway(node.Network, node.ID, ingressGateway) | ||||||
|  | 			if err != nil { | ||||||
|  | 				logger.Log(0, "error creating ingress gateway for node", node.ID, err.Error()) | ||||||
|  | 			} | ||||||
|  | 			runUpdates(&ingressNode, true) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func convertLegacyHostNode(legacy models.LegacyNode) (models.Host, models.Node) { | ||||||
|  | 	//convert host | ||||||
|  | 	host := models.Host{} | ||||||
|  | 	host.ID = uuid.New() | ||||||
|  | 	host.IPForwarding = models.ParseBool(legacy.IPForwarding) | ||||||
|  | 	host.AutoUpdate = servercfg.AutoUpdateEnabled() | ||||||
|  | 	host.Interface = "netmaker" | ||||||
|  | 	host.ListenPort = int(legacy.ListenPort) | ||||||
|  | 	host.MTU = int(legacy.MTU) | ||||||
|  | 	host.PublicKey, _ = wgtypes.ParseKey(legacy.PublicKey) | ||||||
|  | 	host.MacAddress = net.HardwareAddr(legacy.MacAddress) | ||||||
|  | 	host.TrafficKeyPublic = legacy.TrafficKeys.Mine | ||||||
|  | 	host.Nodes = append([]string{}, legacy.ID) | ||||||
|  | 	host.Interfaces = legacy.Interfaces | ||||||
|  | 	//host.DefaultInterface = legacy.Defaul | ||||||
|  | 	host.EndpointIP = net.ParseIP(legacy.Endpoint) | ||||||
|  | 	host.IsDocker = models.ParseBool(legacy.IsDocker) | ||||||
|  | 	host.IsK8S = models.ParseBool(legacy.IsK8S) | ||||||
|  | 	host.IsStatic = models.ParseBool(legacy.IsStatic) | ||||||
|  | 	node := convertLegacyNode(legacy, host.ID) | ||||||
|  | 	return host, node | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func convertLegacyNode(legacy models.LegacyNode, hostID uuid.UUID) models.Node { | ||||||
|  | 	//convert node | ||||||
|  | 	node := models.Node{} | ||||||
|  | 	node.ID, _ = uuid.Parse(legacy.ID) | ||||||
|  | 	node.HostID = hostID | ||||||
|  | 	node.Network = legacy.Network | ||||||
|  | 	valid4 := true | ||||||
|  | 	valid6 := true | ||||||
|  | 	_, cidr4, err := net.ParseCIDR(legacy.NetworkSettings.AddressRange) | ||||||
|  | 	if err != nil { | ||||||
|  | 		valid4 = false | ||||||
|  | 		slog.Warn("parsing address range", "error", err) | ||||||
|  | 	} else { | ||||||
|  | 		node.NetworkRange = *cidr4 | ||||||
|  | 	} | ||||||
|  | 	_, cidr6, err := net.ParseCIDR(legacy.NetworkSettings.AddressRange6) | ||||||
|  | 	if err != nil { | ||||||
|  | 		valid6 = false | ||||||
|  | 		slog.Warn("parsing address range6", "error", err) | ||||||
|  | 	} else { | ||||||
|  | 		node.NetworkRange6 = *cidr6 | ||||||
|  | 	} | ||||||
|  | 	node.Server = servercfg.GetServer() | ||||||
|  | 	node.Connected = models.ParseBool(legacy.Connected) | ||||||
|  | 	if valid4 { | ||||||
|  | 		node.Address = net.IPNet{ | ||||||
|  | 			IP:   net.ParseIP(legacy.Address), | ||||||
|  | 			Mask: cidr4.Mask, | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if valid6 { | ||||||
|  | 		node.Address6 = net.IPNet{ | ||||||
|  | 			IP:   net.ParseIP(legacy.Address6), | ||||||
|  | 			Mask: cidr6.Mask, | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	node.Action = models.NODE_NOOP | ||||||
|  | 	node.LocalAddress = net.IPNet{ | ||||||
|  | 		IP: net.ParseIP(legacy.LocalAddress), | ||||||
|  | 	} | ||||||
|  | 	node.IsEgressGateway = models.ParseBool(legacy.IsEgressGateway) | ||||||
|  | 	node.EgressGatewayRanges = legacy.EgressGatewayRanges | ||||||
|  | 	node.IsIngressGateway = models.ParseBool(legacy.IsIngressGateway) | ||||||
|  | 	node.IsRelayed = false | ||||||
|  | 	node.IsRelay = false | ||||||
|  | 	node.RelayedNodes = []string{} | ||||||
|  | 	node.DNSOn = models.ParseBool(legacy.DNSOn) | ||||||
|  | 	node.PersistentKeepalive = time.Duration(legacy.PersistentKeepalive) | ||||||
|  | 	node.LastModified = time.Now() | ||||||
|  | 	node.ExpirationDateTime, _ = time.Parse(strconv.Itoa(int(legacy.ExpirationDateTime)), "0") | ||||||
|  | 	node.EgressGatewayNatEnabled = models.ParseBool(legacy.EgressGatewayNatEnabled) | ||||||
|  | 	node.EgressGatewayRequest = legacy.EgressGatewayRequest | ||||||
|  | 	node.IngressGatewayRange = legacy.IngressGatewayRange | ||||||
|  | 	node.IngressGatewayRange6 = legacy.IngressGatewayRange6 | ||||||
|  | 	node.DefaultACL = legacy.DefaultACL | ||||||
|  | 	node.OwnerID = legacy.OwnerID | ||||||
|  | 	node.FailoverNode, _ = uuid.Parse(legacy.FailoverNode) | ||||||
|  | 	node.Failover = models.ParseBool(legacy.Failover) | ||||||
|  | 	return node | ||||||
| } | } | ||||||
|   | |||||||
| @@ -2,6 +2,8 @@ package models | |||||||
|  |  | ||||||
| // MigrationData struct needed to create new v0.18.0 node from v.0.17.X node | // MigrationData struct needed to create new v0.18.0 node from v.0.17.X node | ||||||
| type MigrationData struct { | type MigrationData struct { | ||||||
| 	NewHost     Host | 	HostName    string | ||||||
|  | 	Password    string | ||||||
|  | 	OS          string | ||||||
| 	LegacyNodes []LegacyNode | 	LegacyNodes []LegacyNode | ||||||
| } | } | ||||||
|   | |||||||
| @@ -100,7 +100,6 @@ type Node struct { | |||||||
| // LegacyNode - legacy struct for node model | // LegacyNode - legacy struct for node model | ||||||
| type LegacyNode struct { | type LegacyNode struct { | ||||||
| 	ID                      string               `json:"id,omitempty" bson:"id,omitempty" yaml:"id,omitempty" validate:"required,min=5,id_unique"` | 	ID                      string               `json:"id,omitempty" bson:"id,omitempty" yaml:"id,omitempty" validate:"required,min=5,id_unique"` | ||||||
| 	HostID                  string               `json:"hostid,omitempty" bson:"id,omitempty" yaml:"hostid,omitempty" validate:"required,min=5,id_unique"` |  | ||||||
| 	Address                 string               `json:"address" bson:"address" yaml:"address" validate:"omitempty,ipv4"` | 	Address                 string               `json:"address" bson:"address" yaml:"address" validate:"omitempty,ipv4"` | ||||||
| 	Address6                string               `json:"address6" bson:"address6" yaml:"address6" validate:"omitempty,ipv6"` | 	Address6                string               `json:"address6" bson:"address6" yaml:"address6" validate:"omitempty,ipv6"` | ||||||
| 	LocalAddress            string               `json:"localaddress" bson:"localaddress" yaml:"localaddress" validate:"omitempty"` | 	LocalAddress            string               `json:"localaddress" bson:"localaddress" yaml:"localaddress" validate:"omitempty"` | ||||||
| @@ -109,7 +108,6 @@ type LegacyNode struct { | |||||||
| 	NetworkSettings         Network              `json:"networksettings" bson:"networksettings" yaml:"networksettings" validate:"-"` | 	NetworkSettings         Network              `json:"networksettings" bson:"networksettings" yaml:"networksettings" validate:"-"` | ||||||
| 	ListenPort              int32                `json:"listenport" bson:"listenport" yaml:"listenport" validate:"omitempty,numeric,min=1024,max=65535"` | 	ListenPort              int32                `json:"listenport" bson:"listenport" yaml:"listenport" validate:"omitempty,numeric,min=1024,max=65535"` | ||||||
| 	LocalListenPort         int32                `json:"locallistenport" bson:"locallistenport" yaml:"locallistenport" validate:"numeric,min=0,max=65535"` | 	LocalListenPort         int32                `json:"locallistenport" bson:"locallistenport" yaml:"locallistenport" validate:"numeric,min=0,max=65535"` | ||||||
| 	ProxyListenPort         int32                `json:"proxy_listen_port" bson:"proxy_listen_port" yaml:"proxy_listen_port" validate:"numeric,min=0,max=65535"` |  | ||||||
| 	PublicKey               string               `json:"publickey" bson:"publickey" yaml:"publickey" validate:"required,base64"` | 	PublicKey               string               `json:"publickey" bson:"publickey" yaml:"publickey" validate:"required,base64"` | ||||||
| 	Endpoint                string               `json:"endpoint" bson:"endpoint" yaml:"endpoint" validate:"required,ip"` | 	Endpoint                string               `json:"endpoint" bson:"endpoint" yaml:"endpoint" validate:"required,ip"` | ||||||
| 	AllowedIPs              []string             `json:"allowedips" bson:"allowedips" yaml:"allowedips"` | 	AllowedIPs              []string             `json:"allowedips" bson:"allowedips" yaml:"allowedips"` | ||||||
| @@ -153,8 +151,6 @@ type LegacyNode struct { | |||||||
| 	FirewallInUse   string      `json:"firewallinuse" bson:"firewallinuse" yaml:"firewallinuse"` | 	FirewallInUse   string      `json:"firewallinuse" bson:"firewallinuse" yaml:"firewallinuse"` | ||||||
| 	InternetGateway string      `json:"internetgateway" bson:"internetgateway" yaml:"internetgateway"` | 	InternetGateway string      `json:"internetgateway" bson:"internetgateway" yaml:"internetgateway"` | ||||||
| 	Connected       string      `json:"connected" bson:"connected" yaml:"connected" validate:"checkyesorno"` | 	Connected       string      `json:"connected" bson:"connected" yaml:"connected" validate:"checkyesorno"` | ||||||
| 	PendingDelete   bool        `json:"pendingdelete" bson:"pendingdelete" yaml:"pendingdelete"` |  | ||||||
| 	Proxy           bool        `json:"proxy" bson:"proxy" yaml:"proxy"` |  | ||||||
| 	// == PRO == | 	// == PRO == | ||||||
| 	DefaultACL string `json:"defaultacl,omitempty" bson:"defaultacl,omitempty" yaml:"defaultacl,omitempty" validate:"checkyesornoorunset"` | 	DefaultACL string `json:"defaultacl,omitempty" bson:"defaultacl,omitempty" yaml:"defaultacl,omitempty" validate:"checkyesornoorunset"` | ||||||
| 	OwnerID    string `json:"ownerid,omitempty" bson:"ownerid,omitempty" yaml:"ownerid,omitempty"` | 	OwnerID    string `json:"ownerid,omitempty" bson:"ownerid,omitempty" yaml:"ownerid,omitempty"` | ||||||
| @@ -527,7 +523,7 @@ func (ln *LegacyNode) ConvertToNewNode() (*Host, *Node) { | |||||||
| func (n *Node) Legacy(h *Host, s *ServerConfig, net *Network) *LegacyNode { | func (n *Node) Legacy(h *Host, s *ServerConfig, net *Network) *LegacyNode { | ||||||
| 	l := LegacyNode{} | 	l := LegacyNode{} | ||||||
| 	l.ID = n.ID.String() | 	l.ID = n.ID.String() | ||||||
| 	l.HostID = h.ID.String() | 	//l.HostID = h.ID.String() | ||||||
| 	l.Address = n.Address.String() | 	l.Address = n.Address.String() | ||||||
| 	l.Address6 = n.Address6.String() | 	l.Address6 = n.Address6.String() | ||||||
| 	l.Interfaces = h.Interfaces | 	l.Interfaces = h.Interfaces | ||||||
|   | |||||||
							
								
								
									
										574
									
								
								scripts/nm-upgrade.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										574
									
								
								scripts/nm-upgrade.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,574 @@ | |||||||
|  | #!/bin/bash | ||||||
|  |  | ||||||
|  | CONFIG_FILE=netmaker.env | ||||||
|  | # location of nm-quick.sh (usually `/root`) | ||||||
|  | SCRIPT_DIR=$(dirname "$(realpath "$0")") | ||||||
|  | CONFIG_PATH="$SCRIPT_DIR/$CONFIG_FILE" | ||||||
|  | NM_QUICK_VERSION="0.1.0" | ||||||
|  | LATEST=$(curl -s https://api.github.com/repos/gravitl/netmaker/releases/latest | grep "tag_name" | cut -d : -f 2,3 | tr -d [:space:],\") | ||||||
|  |  | ||||||
|  | if [ "$(id -u)" -ne 0 ]; then | ||||||
|  | 	echo "This script must be run as root" | ||||||
|  | 	exit 1 | ||||||
|  | fi | ||||||
|  |  | ||||||
|  | unset INSTALL_TYPE | ||||||
|  | unset NETMAKER_BASE_DOMAIN | ||||||
|  |  | ||||||
|  | # usage - displays usage instructions | ||||||
|  | usage() { | ||||||
|  | 	echo "nm-upgrade.sh v$NM_QUICK_VERSION" | ||||||
|  | 	echo "usage: ./nm-upgrade.sh" | ||||||
|  | 	exit 1 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | while getopts v flag; do | ||||||
|  | 	case "${flag}" in | ||||||
|  | 	v) | ||||||
|  | 		usage | ||||||
|  | 		exit 0 | ||||||
|  | 		;; | ||||||
|  | 	*) | ||||||
|  | 		usage | ||||||
|  | 		exit 0 | ||||||
|  | 		;; | ||||||
|  | 	esac | ||||||
|  | done | ||||||
|  |  | ||||||
|  | # print_logo - prints the netmaker logo | ||||||
|  | print_logo() { | ||||||
|  | 	cat <<"EOF" | ||||||
|  | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||||
|  | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||||
|  | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||||
|  |                                                                                           | ||||||
|  |  __   __     ______     ______   __    __     ______     __  __     ______     ______     | ||||||
|  | /\ "-.\ \   /\  ___\   /\__  _\ /\ "-./  \   /\  __ \   /\ \/ /    /\  ___\   /\  == \    | ||||||
|  | \ \ \-.  \  \ \  __\   \/_/\ \/ \ \ \-./\ \  \ \  __ \  \ \  _"-.  \ \  __\   \ \  __<    | ||||||
|  |  \ \_\\"\_\  \ \_____\    \ \_\  \ \_\ \ \_\  \ \_\ \_\  \ \_\ \_\  \ \_____\  \ \_\ \_\  | ||||||
|  |   \/_/ \/_/   \/_____/     \/_/   \/_/  \/_/   \/_/\/_/   \/_/\/_/   \/_____/   \/_/ /_/  | ||||||
|  |                                                                                                                                                                                                   | ||||||
|  |  | ||||||
|  | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||||
|  | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||||
|  | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||||
|  | EOF | ||||||
|  | } | ||||||
|  |  | ||||||
|  | # set_buildinfo - sets the information based on script input for how the installation should be run | ||||||
|  | set_buildinfo() { | ||||||
|  |  | ||||||
|  | 	MASTERKEY=$(grep MASTER_KEY docker-compose.yml | awk '{print $2;}' | tr -d '"') | ||||||
|  | 	EMAIL=$(grep email Caddyfile | awk '{print $2;}' | tr -d '"') | ||||||
|  | 	BROKER=$(grep SERVER_NAME docker-compose.yml | awk '{print $2;}' | tr -d '"') | ||||||
|  | 	PREFIX="broker." | ||||||
|  | 	NETMAKER_BASE_DOMAIN=${BROKER/#$PREFIX} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 		echo "-----------------------------------------------------" | ||||||
|  | 		echo "Would you like to install Netmaker Community Edition (CE), or Netmaker Enterprise Edition (EE)?" | ||||||
|  | 		echo "EE will require you to create an account at https://app.netmaker.io" | ||||||
|  | 		echo "-----------------------------------------------------" | ||||||
|  | 		select install_option in "Community Edition" "Enterprise Edition"; do | ||||||
|  | 			case $REPLY in | ||||||
|  | 			1) | ||||||
|  | 				echo "installing Netmaker CE" | ||||||
|  | 				INSTALL_TYPE="ce" | ||||||
|  | 				break | ||||||
|  | 				;; | ||||||
|  | 			2) | ||||||
|  | 				echo "installing Netmaker EE" | ||||||
|  | 				INSTALL_TYPE="ee" | ||||||
|  | 				break | ||||||
|  | 				;; | ||||||
|  | 			*) echo "invalid option $REPLY" ;; | ||||||
|  | 			esac | ||||||
|  | 		done | ||||||
|  |  | ||||||
|  | 	echo "-----------Build Options-----------------------------" | ||||||
|  | 	echo "    EE or CE: $INSTALL_TYPE" | ||||||
|  | 	echo "   Version: $LATEST" | ||||||
|  | 	echo "   Installer: v$NM_QUICK_VERSION" | ||||||
|  | 	echo "-----------------------------------------------------" | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | # install_yq - install yq if not present | ||||||
|  | install_yq() { | ||||||
|  | 	if ! command -v yq &>/dev/null; then | ||||||
|  | 		wget -qO /usr/bin/yq https://github.com/mikefarah/yq/releases/download/v4.31.1/yq_linux_$(dpkg --print-architecture) | ||||||
|  | 		chmod +x /usr/bin/yq | ||||||
|  | 	fi | ||||||
|  | 	set +e | ||||||
|  | 	if ! command -v yq &>/dev/null; then | ||||||
|  | 		set -e | ||||||
|  | 		wget -qO /usr/bin/yq https://github.com/mikefarah/yq/releases/download/v4.31.1/yq_linux_amd64 | ||||||
|  | 		chmod +x /usr/bin/yq | ||||||
|  | 	fi | ||||||
|  | 	set -e | ||||||
|  | 	if ! command -v yq &>/dev/null; then | ||||||
|  | 		echo "failed to install yq. Please install yq and try again." | ||||||
|  | 		echo "https://github.com/mikefarah/yq/#install" | ||||||
|  | 		exit 1 | ||||||
|  | 	fi | ||||||
|  | } | ||||||
|  |  | ||||||
|  | # install and run upgrade tool | ||||||
|  | upgrade() { | ||||||
|  | 	wget -qO /tmp/nm-upgrade https://fileserver.netmaker.io/upgrade/nm-upgrade-${ARCH} | ||||||
|  | 	chmod +x /tmp/nm-upgrade | ||||||
|  | 	echo "generating netclient configuration files" | ||||||
|  | 	/tmp/nm-upgrade | ||||||
|  | } | ||||||
|  |  | ||||||
|  | # setup_netclient - installs netclient  | ||||||
|  | setup_netclient() { | ||||||
|  | 	wget -qO netclient https://github.com/gravitl/netclient/releases/download/$LATEST/netclient-linux-$ARCH | ||||||
|  | 	chmod +x netclient | ||||||
|  | 	./netclient install -v 3 | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | # wait_seconds - wait for the specified period of time | ||||||
|  | wait_seconds() { ( | ||||||
|  | 	for ((a = 1; a <= $1; a++)); do | ||||||
|  | 		echo ". . ." | ||||||
|  | 		sleep 1 | ||||||
|  | 	done | ||||||
|  | ); } | ||||||
|  |  | ||||||
|  | # confirm - get user input to confirm that they want to perform the next step | ||||||
|  | confirm() { ( | ||||||
|  | 	while true; do | ||||||
|  | 		read -p 'Does everything look right? [y/n]: ' yn | ||||||
|  | 		case $yn in | ||||||
|  | 		[Yy]*) | ||||||
|  | 			override="true" | ||||||
|  | 			break | ||||||
|  | 			;; | ||||||
|  | 		[Nn]*) | ||||||
|  | 			echo "exiting..." | ||||||
|  | 			exit 1 | ||||||
|  | 			# TODO start from the beginning instead | ||||||
|  | 			;; | ||||||
|  | 		*) echo "Please answer yes or no." ;; | ||||||
|  | 		esac | ||||||
|  | 	done | ||||||
|  | ) } | ||||||
|  |  | ||||||
|  | save_config() { ( | ||||||
|  | 	echo "Saving the config to $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 "$LATEST" | ||||||
|  | 	# version-specific entries | ||||||
|  | 	if [ "$INSTALL_TYPE" = "ee" ]; then | ||||||
|  | 		save_config_item NETMAKER_TENANT_ID "$TENANT_ID" | ||||||
|  | 		save_config_item LICENSE_KEY "$LICENSE_KEY" | ||||||
|  | 		save_config_item METRICS_EXPORTER "on" | ||||||
|  | 		save_config_item PROMETHEUS "on" | ||||||
|  | 		ave_config_item SERVER_IMAGE_TAG "$LATEST-ee" | ||||||
|  | 	else | ||||||
|  | 		save_config_item METRICS_EXPORTER "off" | ||||||
|  | 		save_config_item PROMETHEUS "off" | ||||||
|  | 		save_config_item SERVER_IMAGE_TAG "$LATEST" | ||||||
|  | 	fi | ||||||
|  | 	# copy entries from the previous config | ||||||
|  | 	local toCopy=("SERVER_HOST" "MASTER_KEY" "TURN_USERNAME" "TURN_PASSWORD" "MQ_USERNAME" "MQ_PASSWORD" | ||||||
|  | 		"INSTALL_TYPE" "NODE_ID" "DNS_MODE" "NETCLIENT_AUTO_UPDATE" "API_PORT" | ||||||
|  | 		"CORS_ALLOWED_ORIGIN" "DISPLAY_KEYS" "DATABASE" "SERVER_BROKER_ENDPOINT" "STUN_PORT" "VERBOSITY" | ||||||
|  | 		"TURN_PORT" "USE_TURN" "DEBUG_MODE" "TURN_API_PORT" "REST_BACKEND" | ||||||
|  | 		"DISABLE_REMOTE_IP_CHECK" "NETCLIENT_ENDPOINT_DETECTION" "TELEMETRY" "AUTH_PROVIDER" "CLIENT_ID" "CLIENT_SECRET" | ||||||
|  | 		"FRONTEND_URL" "AZURE_TENANT" "OIDC_ISSUER" "EXPORTER_API_PORT") | ||||||
|  | 	for name in "${toCopy[@]}"; do | ||||||
|  | 		save_config_item $name "${!name}" | ||||||
|  | 	done | ||||||
|  | 	# preserve debug entries | ||||||
|  | 	if test -n "$NM_SKIP_BUILD"; then | ||||||
|  | 		save_config_item NM_SKIP_BUILD "$NM_SKIP_BUILD" | ||||||
|  | 	fi | ||||||
|  | 	if test -n "$NM_SKIP_CLONE"; then | ||||||
|  | 		save_config_item NM_SKIP_CLONE "$NM_SKIP_CLONE" | ||||||
|  | 	fi | ||||||
|  | 	if test -n "$NM_SKIP_DEPS"; then | ||||||
|  | 		save_config_item NM_SKIP_DEPS "$NM_SKIP_DEPS" | ||||||
|  | 	fi | ||||||
|  | ); } | ||||||
|  |  | ||||||
|  | save_config_item() { ( | ||||||
|  | 	local NAME="$1" | ||||||
|  | 	local VALUE="$2" | ||||||
|  | 	#echo "$NAME=$VALUE" | ||||||
|  | 	if test -z "$VALUE"; then | ||||||
|  | 		# load the default for empty values | ||||||
|  | 		VALUE=$(awk -F'=' "/^$NAME/ { print \$2}"  "$SCRIPT_DIR/netmaker.default.env") | ||||||
|  | 		# trim quotes for docker | ||||||
|  | 		VALUE=$(echo "$VALUE" | sed -E "s|^(['\"])(.*)\1$|\2|g") | ||||||
|  | 		#echo "Default for $NAME=$VALUE" | ||||||
|  | 	fi | ||||||
|  | 	# TODO single quote passwords | ||||||
|  | 	if grep -q "^$NAME=" "$CONFIG_PATH"; then | ||||||
|  | 		# TODO escape | in the value | ||||||
|  | 		sed -i "s|$NAME=.*|$NAME=$VALUE|" "$CONFIG_PATH" | ||||||
|  | 	else | ||||||
|  | 		echo "$NAME=$VALUE" >>"$CONFIG_PATH" | ||||||
|  | 	fi | ||||||
|  | ); } | ||||||
|  |  | ||||||
|  | # install_dependencies - install necessary packages to run netmaker | ||||||
|  | install_dependencies() { | ||||||
|  |  | ||||||
|  | 	if test -n "$NM_SKIP_DEPS"; then | ||||||
|  | 		return | ||||||
|  | 	fi | ||||||
|  |  | ||||||
|  | 	echo "checking dependencies..." | ||||||
|  |  | ||||||
|  | 	OS=$(uname) | ||||||
|  | 	if [ -f /etc/debian_version ]; then | ||||||
|  | 		dependencies="git wireguard wireguard-tools dnsutils jq docker.io docker-compose grep gawk" | ||||||
|  | 		update_cmd='apt update' | ||||||
|  | 		install_cmd='apt-get install -y' | ||||||
|  | 	elif [ -f /etc/alpine-release ]; then | ||||||
|  | 		dependencies="git wireguard jq docker.io docker-compose grep gawk" | ||||||
|  | 		update_cmd='apk update' | ||||||
|  | 		install_cmd='apk --update add' | ||||||
|  | 	elif [ -f /etc/centos-release ]; then | ||||||
|  | 		dependencies="git wireguard jq bind-utils docker.io docker-compose grep gawk" | ||||||
|  | 		update_cmd='yum update' | ||||||
|  | 		install_cmd='yum install -y' | ||||||
|  | 	elif [ -f /etc/fedora-release ]; then | ||||||
|  | 		dependencies="git wireguard bind-utils jq docker.io docker-compose grep gawk" | ||||||
|  | 		update_cmd='dnf update' | ||||||
|  | 		install_cmd='dnf install -y' | ||||||
|  | 	elif [ -f /etc/redhat-release ]; then | ||||||
|  | 		dependencies="git wireguard jq docker.io bind-utils docker-compose grep gawk" | ||||||
|  | 		update_cmd='yum update' | ||||||
|  | 		install_cmd='yum install -y' | ||||||
|  | 	elif [ -f /etc/arch-release ]; then | ||||||
|  | 		dependencies="git wireguard-tools dnsutils jq docker.io docker-compose grep gawk" | ||||||
|  | 		update_cmd='pacman -Sy' | ||||||
|  | 		install_cmd='pacman -S --noconfirm' | ||||||
|  | 	elif [ "${OS}" = "FreeBSD" ]; then | ||||||
|  | 		dependencies="git wireguard wget jq docker.io docker-compose grep gawk" | ||||||
|  | 		update_cmd='pkg update' | ||||||
|  | 		install_cmd='pkg install -y' | ||||||
|  | 	else | ||||||
|  | 		install_cmd='' | ||||||
|  | 	fi | ||||||
|  |  | ||||||
|  | 	if [ -z "${install_cmd}" ]; then | ||||||
|  | 		echo "OS unsupported for automatic dependency install" | ||||||
|  | 		# TODO shouldnt exit, check if deps available, if not | ||||||
|  | 		#  ask the user to install manually and continue when ready | ||||||
|  | 		exit 1 | ||||||
|  | 	fi | ||||||
|  | 	# TODO add other supported architectures | ||||||
|  | 	ARCH=$(uname -m) | ||||||
|  |     if [ "$ARCH" = "x86_64" ]; then | ||||||
|  |     	ARCH=amd64 | ||||||
|  |     elif [ "$ARCH" = "aarch64" ]; then | ||||||
|  |     	ARCH=arm64 | ||||||
|  |     else | ||||||
|  |     	echo "Unsupported architechure" | ||||||
|  |     	# exit 1 | ||||||
|  |     fi | ||||||
|  | 	set -- $dependencies | ||||||
|  |  | ||||||
|  | 	${update_cmd} | ||||||
|  |  | ||||||
|  | 	while [ -n "$1" ]; do | ||||||
|  | 		if [ "${OS}" = "FreeBSD" ]; then | ||||||
|  | 			is_installed=$(pkg check -d $1 | grep "Checking" | grep "done") | ||||||
|  | 			if [ "$is_installed" != "" ]; then | ||||||
|  | 				echo "  " $1 is installed | ||||||
|  | 			else | ||||||
|  | 				echo "  " $1 is not installed. Attempting install. | ||||||
|  | 				${install_cmd} $1 | ||||||
|  | 				sleep 5 | ||||||
|  | 				is_installed=$(pkg check -d $1 | grep "Checking" | grep "done") | ||||||
|  | 				if [ "$is_installed" != "" ]; then | ||||||
|  | 					echo "  " $1 is installed | ||||||
|  | 				elif [ -x "$(command -v $1)" ]; then | ||||||
|  | 					echo "  " $1 is installed | ||||||
|  | 				else | ||||||
|  | 					echo "  " FAILED TO INSTALL $1 | ||||||
|  | 					echo "  " This may break functionality. | ||||||
|  | 				fi | ||||||
|  | 			fi | ||||||
|  | 		else | ||||||
|  | 			if [ "${OS}" = "OpenWRT" ] || [ "${OS}" = "TurrisOS" ]; then | ||||||
|  | 				is_installed=$(opkg list-installed $1 | grep $1) | ||||||
|  | 			else | ||||||
|  | 				is_installed=$(dpkg-query -W --showformat='${Status}\n' $1 | grep "install ok installed") | ||||||
|  | 			fi | ||||||
|  | 			if [ "${is_installed}" != "" ]; then | ||||||
|  | 				echo "    " $1 is installed | ||||||
|  | 			else | ||||||
|  | 				echo "    " $1 is not installed. Attempting install. | ||||||
|  | 				${install_cmd} $1 | ||||||
|  | 				sleep 5 | ||||||
|  | 				if [ "${OS}" = "OpenWRT" ] || [ "${OS}" = "TurrisOS" ]; then | ||||||
|  | 					is_installed=$(opkg list-installed $1 | grep $1) | ||||||
|  | 				else | ||||||
|  | 					is_installed=$(dpkg-query -W --showformat='${Status}\n' $1 | grep "install ok installed") | ||||||
|  | 				fi | ||||||
|  | 				if [ "${is_installed}" != "" ]; then | ||||||
|  | 					echo "    " $1 is installed | ||||||
|  | 				elif [ -x "$(command -v $1)" ]; then | ||||||
|  | 					echo "  " $1 is installed | ||||||
|  | 				else | ||||||
|  | 					echo "  " FAILED TO INSTALL $1 | ||||||
|  | 					echo "  " This may break functionality. | ||||||
|  | 				fi | ||||||
|  | 			fi | ||||||
|  | 		fi | ||||||
|  | 		shift | ||||||
|  | 	done | ||||||
|  |  | ||||||
|  | 	echo "-----------------------------------------------------" | ||||||
|  | 	echo "dependency check complete" | ||||||
|  | 	echo "-----------------------------------------------------" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | # set_install_vars - sets the variables that will be used throughout installation | ||||||
|  | set_install_vars() { | ||||||
|  |  | ||||||
|  | 	IP_ADDR=$(dig -4 myip.opendns.com @resolver1.opendns.com +short) | ||||||
|  | 	if [ "$IP_ADDR" = "" ]; then | ||||||
|  | 		IP_ADDR=$(curl -s ifconfig.me) | ||||||
|  | 	fi | ||||||
|  | 	if [ "$NETMAKER_BASE_DOMAIN" = "" ]; then | ||||||
|  | 		NETMAKER_BASE_DOMAIN=nm.$(echo $IP_ADDR | tr . -).nip.io | ||||||
|  | 	fi | ||||||
|  | 	SERVER_HOST=$IP_ADDR | ||||||
|  | 	if test -z "$MASTER_KEY"; then | ||||||
|  | 		MASTER_KEY=$( | ||||||
|  | 			tr -dc A-Za-z0-9 </dev/urandom | head -c 30 | ||||||
|  | 			echo '' | ||||||
|  | 		) | ||||||
|  | 	fi | ||||||
|  | 	DOMAIN_TYPE="auto" | ||||||
|  |  | ||||||
|  | 	echo "-----------------------------------------------------" | ||||||
|  | 	echo "The following subdomains will be used:" | ||||||
|  | 	echo "          dashboard.$NETMAKER_BASE_DOMAIN" | ||||||
|  | 	echo "                api.$NETMAKER_BASE_DOMAIN" | ||||||
|  | 	echo "             broker.$NETMAKER_BASE_DOMAIN" | ||||||
|  | 	echo "               turn.$NETMAKER_BASE_DOMAIN" | ||||||
|  | 	echo "            turnapi.$NETMAKER_BASE_DOMAIN" | ||||||
|  |  | ||||||
|  | 	if [ "$INSTALL_TYPE" = "ee" ]; then | ||||||
|  | 		echo "         prometheus.$NETMAKER_BASE_DOMAIN" | ||||||
|  | 		echo "  netmaker-exporter.$NETMAKER_BASE_DOMAIN" | ||||||
|  | 		echo "            grafana.$NETMAKER_BASE_DOMAIN" | ||||||
|  | 	fi | ||||||
|  |  | ||||||
|  | 	echo "-----------------------------------------------------" | ||||||
|  |  | ||||||
|  | 	if [ "$INSTALL_TYPE" = "ee" ]; then | ||||||
|  |  | ||||||
|  | 		echo "-----------------------------------------------------" | ||||||
|  | 		echo "Provide Details for EE 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 | ||||||
|  |  | ||||||
|  | 	echo "using default username/random pass for MQ" | ||||||
|  | 	MQ_USERNAME="netmaker" | ||||||
|  | 	MQ_PASSWORD=$( | ||||||
|  | 		tr -dc A-Za-z0-9 </dev/urandom | head -c 30 | ||||||
|  | 		echo '' | ||||||
|  | 	) | ||||||
|  |  | ||||||
|  | 	echo "using default username/random pass for TURN" | ||||||
|  | 	TURN_USERNAME="netmaker" | ||||||
|  | 	TURN_PASSWORD=$( | ||||||
|  | 		tr -dc A-Za-z0-9 </dev/urandom | head -c 30 | ||||||
|  | 		echo '' | ||||||
|  | 	) | ||||||
|  | 	echo "-----------------------------------------------------------------" | ||||||
|  | 	echo "                SETUP ARGUMENTS" | ||||||
|  | 	echo "-----------------------------------------------------------------" | ||||||
|  | 	echo "        domain: $NETMAKER_BASE_DOMAIN" | ||||||
|  | 	echo "         email: $EMAIL" | ||||||
|  | 	echo "     public ip: $SERVER_HOST" | ||||||
|  | 	if [ "$INSTALL_TYPE" = "ee" ]; then | ||||||
|  | 		echo "       license: $LICENSE_KEY" | ||||||
|  | 		echo "    account id: $TENANT_ID" | ||||||
|  | 	fi | ||||||
|  | 	echo "-----------------------------------------------------------------" | ||||||
|  | 	echo "Confirm Settings for Installation" | ||||||
|  | 	echo "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -" | ||||||
|  |  | ||||||
|  | 	confirm | ||||||
|  | } | ||||||
|  |  | ||||||
|  | # install_netmaker - sets the config files and starts docker-compose | ||||||
|  | install_netmaker() { | ||||||
|  |  | ||||||
|  | 	echo "-----------------------------------------------------------------" | ||||||
|  | 	echo "Beginning installation..." | ||||||
|  | 	echo "-----------------------------------------------------------------" | ||||||
|  |  | ||||||
|  | 	wait_seconds 3 | ||||||
|  |  | ||||||
|  | 	echo "Pulling config files..." | ||||||
|  |  | ||||||
|  | 		local BASE_URL="https://raw.githubusercontent.com/gravitl/netmaker/$LATEST" | ||||||
|  |  | ||||||
|  | 		local COMPOSE_URL="$BASE_URL/compose/docker-compose.yml" | ||||||
|  | 		local CADDY_URL="$BASE_URL/docker/Caddyfile" | ||||||
|  | 		if [ "$INSTALL_TYPE" = "ee" ]; then | ||||||
|  | 			local COMPOSE_OVERRIDE_URL="$BASE_URL/compose/docker-compose.ee.yml" | ||||||
|  | 			local CADDY_URL="$BASE_URL/docker/Caddyfile-EE" | ||||||
|  | 		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"/nm-certs.sh "$BASE_URL/scripts/nm-certs.sh" | ||||||
|  | 		wget -qO "$SCRIPT_DIR"/wait.sh "$BASE_URL/docker/wait.sh" | ||||||
|  |  | ||||||
|  | 	chmod +x "$SCRIPT_DIR"/wait.sh | ||||||
|  | 	mkdir -p /etc/netmaker | ||||||
|  |  | ||||||
|  | 	# link .env to the user config | ||||||
|  | 	ln -fs "$SCRIPT_DIR/netmaker.env" "$SCRIPT_DIR/.env" | ||||||
|  | 	save_config | ||||||
|  |  | ||||||
|  | 	# Fetch / update certs using certbot | ||||||
|  | 	chmod +x "$SCRIPT_DIR"/nm-certs.sh | ||||||
|  | 	"$SCRIPT_DIR"/nm-certs.sh | ||||||
|  |  | ||||||
|  | 	echo "Starting containers..." | ||||||
|  |  | ||||||
|  | 	# increase the timeouts | ||||||
|  | 	export DOCKER_CLIENT_TIMEOUT=120 | ||||||
|  | 	export COMPOSE_HTTP_TIMEOUT=120 | ||||||
|  |  | ||||||
|  | 	# start docker and rebuild containers / networks | ||||||
|  | 	docker-compose -f "$SCRIPT_DIR"/docker-compose.yml up -d --force-recreate | ||||||
|  |  | ||||||
|  | 	wait_seconds 2 | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | # test_connection - tests to make sure Caddy has proper SSL certs | ||||||
|  | test_connection() { | ||||||
|  |  | ||||||
|  | 	echo "Testing Caddy setup (please be patient, this may take 1-2 minutes)" | ||||||
|  | 	for i in 1 2 3 4 5 6 7 8; do | ||||||
|  | 		curlresponse=$(curl -vIs https://api.${NETMAKER_BASE_DOMAIN} 2>&1) | ||||||
|  |  | ||||||
|  | 		if [[ "$i" == 8 ]]; then | ||||||
|  | 			echo "    Caddy is having an issue setting up certificates, please investigate (docker logs caddy)" | ||||||
|  | 			echo "    Exiting..." | ||||||
|  | 			exit 1 | ||||||
|  | 		elif [[ "$curlresponse" == *"failed to verify the legitimacy of the server"* ]]; then | ||||||
|  | 			echo "    Certificates not yet configured, retrying..." | ||||||
|  |  | ||||||
|  | 		elif [[ "$curlresponse" == *"left intact"* ]]; then | ||||||
|  | 			echo "    Certificates ok" | ||||||
|  | 			break | ||||||
|  | 		else | ||||||
|  | 			secs=$(($i * 5 + 10)) | ||||||
|  | 			echo "    Issue establishing connection...retrying in $secs seconds..." | ||||||
|  | 		fi | ||||||
|  | 		sleep $secs | ||||||
|  | 	done | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | # print_success - prints a success message upon completion | ||||||
|  | print_success() { | ||||||
|  | 	echo "-----------------------------------------------------------------" | ||||||
|  | 	echo "-----------------------------------------------------------------" | ||||||
|  | 	echo "Netmaker setup is now complete. You are ready to begin using Netmaker." | ||||||
|  | 	echo "Visit dashboard.$NETMAKER_BASE_DOMAIN to log in" | ||||||
|  | 	echo "-----------------------------------------------------------------" | ||||||
|  | 	echo "-----------------------------------------------------------------" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | cleanup() { | ||||||
|  | 	echo "Stopping all containers..." | ||||||
|  | 	local containers=("mq" "netmaker-ui" "coredns" "turn" "caddy" "netmaker" "netmaker-exporter" "prometheus" "grafana") | ||||||
|  | 	for name in "${containers[@]}"; do | ||||||
|  | 		local running=$(docker ps | grep -w "$name") | ||||||
|  | 		local exists=$(docker ps -a | grep -w "$name") | ||||||
|  | 		if test -n "$running"; then | ||||||
|  | 			docker stop "$name" 1>/dev/null | ||||||
|  | 		fi | ||||||
|  | 		if test -n "$exists"; then | ||||||
|  | 			docker rm "$name" 1>/dev/null | ||||||
|  | 		fi | ||||||
|  | 	done | ||||||
|  | } | ||||||
|  |  | ||||||
|  | # print netmaker logo | ||||||
|  | print_logo | ||||||
|  |  | ||||||
|  | # read the config | ||||||
|  | if [ -f "$CONFIG_PATH" ]; then | ||||||
|  | 	echo "Using config: $CONFIG_PATH" | ||||||
|  | 	source "$CONFIG_PATH" | ||||||
|  | 	if [ "$UPGRADE_FLAG" = "yes" ]; then | ||||||
|  | 		INSTALL_TYPE="ee" | ||||||
|  | 	fi | ||||||
|  | fi | ||||||
|  |  | ||||||
|  | # setup the build instructions | ||||||
|  | set_buildinfo | ||||||
|  |  | ||||||
|  | set +e | ||||||
|  |  | ||||||
|  | # install necessary packages | ||||||
|  | install_dependencies | ||||||
|  |  | ||||||
|  | # install yq if necessary | ||||||
|  | install_yq | ||||||
|  |  | ||||||
|  | set -e | ||||||
|  |  | ||||||
|  | # get user input for variables | ||||||
|  | set_install_vars | ||||||
|  |  | ||||||
|  | set +e | ||||||
|  | cleanup | ||||||
|  | set -e | ||||||
|  |  | ||||||
|  | # get upgrade tool and run | ||||||
|  | upgrade | ||||||
|  |  | ||||||
|  | # get and set config files, startup docker-compose | ||||||
|  | install_netmaker | ||||||
|  |  | ||||||
|  | set +e | ||||||
|  |  | ||||||
|  | # make sure Caddy certs are working | ||||||
|  | test_connection | ||||||
|  |  | ||||||
|  | set -e | ||||||
|  |  | ||||||
|  | # install netclient  | ||||||
|  | setup_netclient | ||||||
|  |  | ||||||
|  |  | ||||||
|  | # print success message | ||||||
|  | print_success | ||||||
|  |  | ||||||
		Reference in New Issue
	
	Block a user
	 Matthew R Kasun
					Matthew R Kasun