Browse Source

memory issue work

0xdcarns 3 years ago
parent
commit
85e8c0abb6

+ 1 - 1
Dockerfile

@@ -5,7 +5,7 @@ RUN apk add build-base
 WORKDIR /app
 COPY . .
 ENV GO111MODULE=auto
-RUN GOOS=linux CGO_ENABLED=1 go build -ldflags="-s -X 'main.version=$version'" -o netmaker main.go
+RUN GOOS=linux CGO_ENABLED=1 go build -tags debug -ldflags="-s -X 'main.version=$version'" -o netmaker main.go
 FROM alpine:3.13.6
 # add a c lib
 RUN apk add gcompat iptables

+ 14 - 8
controllers/controller.go

@@ -15,6 +15,17 @@ import (
 	"github.com/gravitl/netmaker/servercfg"
 )
 
+var HttpHandlers = []interface{}{
+	nodeHandlers,
+	userHandlers,
+	networkHandlers,
+	dnsHandlers,
+	fileHandlers,
+	serverHandlers,
+	extClientHandlers,
+	loggerHandlers,
+}
+
 // HandleRESTRequests - handles the rest requests
 func HandleRESTRequests(wg *sync.WaitGroup) {
 	defer wg.Done()
@@ -27,14 +38,9 @@ func HandleRESTRequests(wg *sync.WaitGroup) {
 	originsOk := handlers.AllowedOrigins([]string{servercfg.GetAllowedOrigin()})
 	methodsOk := handlers.AllowedMethods([]string{"GET", "PUT", "POST", "DELETE"})
 
-	nodeHandlers(r)
-	userHandlers(r)
-	networkHandlers(r)
-	dnsHandlers(r)
-	fileHandlers(r)
-	serverHandlers(r)
-	extClientHandlers(r)
-	loggerHandlers(r)
+	for _, handler := range HttpHandlers {
+		handler.(func(*mux.Router))(r)
+	}
 
 	port := servercfg.GetAPIPort()
 

+ 33 - 0
controllers/debug.go

@@ -0,0 +1,33 @@
+//go:build debug
+
+package controller
+
+import (
+	"context"
+	"net/http"
+	_ "net/http/pprof"
+	"os"
+	"os/signal"
+
+	"github.com/gravitl/netmaker/logger"
+)
+
+func init() {
+	srv := &http.Server{Addr: "0.0.0.0:6060", Handler: nil}
+	go func() {
+		logger.Log(0, "Debug mode active")
+		err := srv.ListenAndServe()
+		if err != nil {
+			logger.Log(0, err.Error())
+		}
+		c := make(chan os.Signal)
+
+		// Relay os.Interrupt to our channel (os.Interrupt = CTRL+C)
+		// Ignore other incoming signals
+		signal.Notify(c, os.Interrupt)
+		// Block main routine until a signal is received
+		// As long as user doesn't press CTRL+C a message is not passed and our main routine keeps running
+		<-c
+		srv.Shutdown(context.TODO())
+	}()
+}

+ 4 - 4
logic/networks.go

@@ -155,15 +155,15 @@ func GetParentNetwork(networkname string) (models.Network, error) {
 }
 
 // GetParentNetwork - get parent network
-func GetNetworkSettings(networkname string) (models.Network, error) {
+func GetNetworkSettings(networkname string) (*models.Network, error) {
 
-	var network models.Network
+	var network *models.Network
 	networkData, err := database.FetchRecord(database.NETWORKS_TABLE_NAME, networkname)
 	if err != nil {
 		return network, err
 	}
-	if err = json.Unmarshal([]byte(networkData), &network); err != nil {
-		return models.Network{}, err
+	if err = json.Unmarshal([]byte(networkData), network); err != nil {
+		return &models.Network{}, err
 	}
 	network.AccessKeys = []models.AccessKey{}
 	return network, nil

+ 1 - 1
logic/wireguard.go

@@ -213,7 +213,7 @@ func setServerPeers(iface string, keepalive int32, peers []wgtypes.PeerConfig) e
 
 	device, err := client.Device(iface)
 	if err != nil {
-		logger.Log(0, "failed to parse interface")
+		logger.Log(1, "failed to parse interface")
 		return err
 	}
 	devicePeers := device.Peers

+ 15 - 20
main.go

@@ -92,11 +92,6 @@ func startControllers() {
 		go runGRPC(&waitnetwork)
 	}
 
-	if servercfg.IsClientMode() == "on" {
-		waitnetwork.Add(1)
-		go runClient(&waitnetwork)
-	}
-
 	if servercfg.IsDNSMode() {
 		err := logic.SetDNS()
 		if err != nil {
@@ -112,27 +107,31 @@ func startControllers() {
 			}
 		}
 		waitnetwork.Add(1)
-		controller.HandleRESTRequests(&waitnetwork)
+		go controller.HandleRESTRequests(&waitnetwork)
 	}
+
 	if !servercfg.IsAgentBackend() && !servercfg.IsRestBackend() {
 		logger.Log(0, "No Server Mode selected, so nothing is being served! Set either Agent mode (AGENT_BACKEND) or Rest mode (REST_BACKEND) to 'true'.")
 	}
 
+	if servercfg.IsClientMode() == "on" {
+		var checkintime = time.Duration(servercfg.GetServerCheckinInterval()) * time.Second
+		for { // best effort currently
+			var netSyncGroup sync.WaitGroup
+			netSyncGroup.Add(1)
+			go runClient(&netSyncGroup)
+			netSyncGroup.Wait()
+			logger.Log(0, "ran a checkin")
+			time.Sleep(checkintime)
+		}
+	}
+
 	waitnetwork.Wait()
-	logger.Log(0, "exiting")
 }
 
 func runClient(wg *sync.WaitGroup) {
 	defer wg.Done()
-	go func() {
-		for {
-			if err := serverctl.HandleContainedClient(); err != nil {
-				// PASS
-			}
-			var checkintime = time.Duration(servercfg.GetServerCheckinInterval()) * time.Second
-			time.Sleep(checkintime)
-		}
-	}()
+	go serverctl.HandleContainedClient()
 }
 
 func runGRPC(wg *sync.WaitGroup) {
@@ -198,7 +197,3 @@ func setGarbageCollection() {
 		debug.SetGCPercent(ncutils.DEFAULT_GC_PERCENT)
 	}
 }
-
-// func authServerStreamInterceptor() grpc.ServerOption {
-// 	return grpc.StreamInterceptor(controller.AuthServerStreamInterceptor)
-// }

+ 5 - 6
models/node.go

@@ -11,7 +11,6 @@ import (
 	"golang.org/x/crypto/bcrypt"
 )
 
-const charset = "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
 const TEN_YEARS_IN_SECONDS = 300000000
 const MAX_NAME_LENGTH = 62
 
@@ -32,7 +31,7 @@ type Node struct {
 	Address6            string   `json:"address6" bson:"address6" yaml:"address6" validate:"omitempty,ipv6"`
 	LocalAddress        string   `json:"localaddress" bson:"localaddress" yaml:"localaddress" validate:"omitempty,ip"`
 	Name                string   `json:"name" bson:"name" yaml:"name" validate:"omitempty,max=62,in_charset"`
-	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"`
 	PublicKey           string   `json:"publickey" bson:"publickey" yaml:"publickey" validate:"required,base64"`
 	Endpoint            string   `json:"endpoint" bson:"endpoint" yaml:"endpoint" validate:"required,ip"`
@@ -240,7 +239,7 @@ func (newNode *Node) Fill(currentNode *Node) {
 		newNode.PostDown = currentNode.PostDown
 	}
 	if newNode.AllowedIPs == nil {
-		newNode.AllowedIPs = currentNode.AllowedIPs
+		newNode.AllowedIPs = currentNode.AllowedIPs[:]
 	}
 	if newNode.PersistentKeepalive == 0 {
 		newNode.PersistentKeepalive = currentNode.PersistentKeepalive
@@ -299,10 +298,10 @@ func (newNode *Node) Fill(currentNode *Node) {
 		newNode.IsIngressGateway = currentNode.IsIngressGateway
 	}
 	if newNode.EgressGatewayRanges == nil {
-		newNode.EgressGatewayRanges = currentNode.EgressGatewayRanges
+		newNode.EgressGatewayRanges = currentNode.EgressGatewayRanges[:]
 	}
 	if newNode.IngressGatewayRange == "" {
-		newNode.IngressGatewayRange = currentNode.IngressGatewayRange
+		newNode.IngressGatewayRange = currentNode.IngressGatewayRange[:]
 	}
 	if newNode.IsStatic == "" {
 		newNode.IsStatic = currentNode.IsStatic
@@ -344,7 +343,7 @@ func (newNode *Node) Fill(currentNode *Node) {
 		newNode.OS = currentNode.OS
 	}
 	if newNode.RelayAddrs == nil {
-		newNode.RelayAddrs = currentNode.RelayAddrs
+		newNode.RelayAddrs = currentNode.RelayAddrs[:]
 	}
 	if newNode.IsRelay == "" {
 		newNode.IsRelay = currentNode.IsRelay

+ 122 - 0
netclient/cli_options/cmds.go

@@ -0,0 +1,122 @@
+package cli_options
+
+import (
+	"errors"
+
+	"github.com/gravitl/netmaker/netclient/command"
+	"github.com/gravitl/netmaker/netclient/config"
+	"github.com/urfave/cli/v2"
+)
+
+// GetCommands - return commands that CLI uses
+func GetCommands(cliFlags []cli.Flag) []*cli.Command {
+	return []*cli.Command{
+		{
+			Name:  "join",
+			Usage: "Join a Netmaker network.",
+			Flags: cliFlags,
+			Action: func(c *cli.Context) error {
+				cfg, pvtKey, err := config.GetCLIConfig(c)
+				if err != nil {
+					return err
+				}
+				if cfg.Network == "all" {
+					err = errors.New("No network provided.")
+					return err
+				}
+				if cfg.Server.GRPCAddress == "" {
+					err = errors.New("No server address provided.")
+					return err
+				}
+				err = command.Join(cfg, pvtKey)
+				return err
+			},
+		},
+		{
+			Name:  "leave",
+			Usage: "Leave a Netmaker network.",
+			Flags: cliFlags,
+			// the action, or code that will be executed when
+			// we execute our `ns` command
+			Action: func(c *cli.Context) error {
+				cfg, _, err := config.GetCLIConfig(c)
+				if err != nil {
+					return err
+				}
+				err = command.Leave(cfg)
+				return err
+			},
+		},
+		{
+			Name:  "checkin",
+			Usage: "Checks for local changes and then checks into the specified Netmaker network to ask about remote changes.",
+			Flags: cliFlags,
+			// the action, or code that will be executed when
+			// we execute our `ns` command
+			Action: func(c *cli.Context) error {
+				cfg, _, err := config.GetCLIConfig(c)
+				if err != nil {
+					return err
+				}
+				err = command.CheckIn(cfg)
+				return err
+			},
+		},
+		{
+			Name:  "push",
+			Usage: "Push configuration changes to server.",
+			Flags: cliFlags,
+			// the action, or code that will be executed when
+			// we execute our `ns` command
+			Action: func(c *cli.Context) error {
+				cfg, _, err := config.GetCLIConfig(c)
+				if err != nil {
+					return err
+				}
+				err = command.Push(cfg)
+				return err
+			},
+		},
+		{
+			Name:  "pull",
+			Usage: "Pull latest configuration and peers from server.",
+			Flags: cliFlags,
+			// the action, or code that will be executed when
+			// we execute our `ns` command
+			Action: func(c *cli.Context) error {
+				cfg, _, err := config.GetCLIConfig(c)
+				if err != nil {
+					return err
+				}
+				err = command.Pull(cfg)
+				return err
+			},
+		},
+		{
+			Name:  "list",
+			Usage: "Get list of networks.",
+			Flags: cliFlags,
+			// the action, or code that will be executed when
+			// we execute our `ns` command
+			Action: func(c *cli.Context) error {
+				cfg, _, err := config.GetCLIConfig(c)
+				if err != nil {
+					return err
+				}
+				err = command.List(cfg)
+				return err
+			},
+		},
+		{
+			Name:  "uninstall",
+			Usage: "Uninstall the netclient system service.",
+			Flags: cliFlags,
+			// the action, or code that will be executed when
+			// we execute our `ns` command
+			Action: func(c *cli.Context) error {
+				err := command.Uninstall()
+				return err
+			},
+		},
+	}
+}

+ 196 - 0
netclient/cli_options/flags.go

@@ -0,0 +1,196 @@
+package cli_options
+
+import "github.com/urfave/cli/v2"
+
+// GetFlags - Returns the flags used by cli
+func GetFlags(hostname string) []cli.Flag {
+	return []cli.Flag{
+		&cli.StringFlag{
+			Name:    "network",
+			Aliases: []string{"n"},
+			EnvVars: []string{"NETCLIENT_NETWORK"},
+			Value:   "all",
+			Usage:   "Network to perform specified action against.",
+		},
+		&cli.StringFlag{
+			Name:    "password",
+			Aliases: []string{"p"},
+			EnvVars: []string{"NETCLIENT_PASSWORD"},
+			Value:   "",
+			Usage:   "Password for authenticating with netmaker.",
+		},
+		&cli.StringFlag{
+			Name:    "endpoint",
+			Aliases: []string{"e"},
+			EnvVars: []string{"NETCLIENT_ENDPOINT"},
+			Value:   "",
+			Usage:   "Reachable (usually public) address for WireGuard (not the private WG address).",
+		},
+		&cli.StringFlag{
+			Name:    "macaddress",
+			Aliases: []string{"m"},
+			EnvVars: []string{"NETCLIENT_MACADDRESS"},
+			Value:   "",
+			Usage:   "Mac Address for this machine. Used as a unique identifier within Netmaker network.",
+		},
+		&cli.StringFlag{
+			Name:    "publickey",
+			Aliases: []string{"pubkey"},
+			EnvVars: []string{"NETCLIENT_PUBLICKEY"},
+			Value:   "",
+			Usage:   "Public Key for WireGuard Interface.",
+		},
+		&cli.StringFlag{
+			Name:    "privatekey",
+			Aliases: []string{"privkey"},
+			EnvVars: []string{"NETCLIENT_PRIVATEKEY"},
+			Value:   "",
+			Usage:   "Private Key for WireGuard Interface.",
+		},
+		&cli.StringFlag{
+			Name:    "port",
+			EnvVars: []string{"NETCLIENT_PORT"},
+			Value:   "",
+			Usage:   "Port for WireGuard Interface.",
+		},
+		&cli.IntFlag{
+			Name:    "keepalive",
+			EnvVars: []string{"NETCLIENT_KEEPALIVE"},
+			Value:   0,
+			Usage:   "Default PersistentKeepAlive for Peers in WireGuard Interface.",
+		},
+		&cli.StringFlag{
+			Name:    "operatingsystem",
+			Aliases: []string{"os"},
+			EnvVars: []string{"NETCLIENT_OS"},
+			Value:   "",
+			Usage:   "Identifiable name for machine within Netmaker network.",
+		},
+		&cli.StringFlag{
+			Name:    "name",
+			EnvVars: []string{"NETCLIENT_NAME"},
+			Value:   hostname,
+			Usage:   "Identifiable name for machine within Netmaker network.",
+		},
+		&cli.StringFlag{
+			Name:    "localaddress",
+			EnvVars: []string{"NETCLIENT_LOCALADDRESS"},
+			Value:   "",
+			Usage:   "Local address for machine. Can be used in place of Endpoint for machines on the same LAN.",
+		},
+		&cli.StringFlag{
+			Name:    "isstatic",
+			Aliases: []string{"st"},
+			EnvVars: []string{"NETCLIENT_IS_STATIC"},
+			Value:   "",
+			Usage:   "Indicates if client is static by default (will not change addresses automatically).",
+		},
+		&cli.StringFlag{
+			Name:    "address",
+			Aliases: []string{"a"},
+			EnvVars: []string{"NETCLIENT_ADDRESS"},
+			Value:   "",
+			Usage:   "WireGuard address for machine within Netmaker network.",
+		},
+		&cli.StringFlag{
+			Name:    "addressIPv6",
+			Aliases: []string{"a6"},
+			EnvVars: []string{"NETCLIENT_ADDRESSIPV6"},
+			Value:   "",
+			Usage:   "WireGuard address for machine within Netmaker network.",
+		},
+		&cli.StringFlag{
+			Name:    "interface",
+			Aliases: []string{"i"},
+			EnvVars: []string{"NETCLIENT_INTERFACE"},
+			Value:   "",
+			Usage:   "WireGuard local network interface name.",
+		},
+		&cli.StringFlag{
+			Name:    "apiserver",
+			EnvVars: []string{"NETCLIENT_API_SERVER"},
+			Value:   "",
+			Usage:   "Address + GRPC Port (e.g. 1.2.3.4:50051) of Netmaker server.",
+		},
+		&cli.StringFlag{
+			Name:    "grpcserver",
+			EnvVars: []string{"NETCLIENT_GRPC_SERVER"},
+			Value:   "",
+			Usage:   "Address + API Port (e.g. 1.2.3.4:8081) of Netmaker server.",
+		},
+		&cli.StringFlag{
+			Name:    "key",
+			Aliases: []string{"k"},
+			EnvVars: []string{"NETCLIENT_ACCESSKEY"},
+			Value:   "",
+			Usage:   "Access Key for signing up machine with Netmaker server during initial 'add'.",
+		},
+		&cli.StringFlag{
+			Name:    "token",
+			Aliases: []string{"t"},
+			EnvVars: []string{"NETCLIENT_ACCESSTOKEN"},
+			Value:   "",
+			Usage:   "Access Token for signing up machine with Netmaker server during initial 'add'.",
+		},
+		&cli.StringFlag{
+			Name:    "localrange",
+			EnvVars: []string{"NETCLIENT_LOCALRANGE"},
+			Value:   "",
+			Usage:   "Local Range if network is local, for instance 192.168.1.0/24.",
+		},
+		&cli.StringFlag{
+			Name:    "dnson",
+			EnvVars: []string{"NETCLIENT_DNS"},
+			Value:   "yes",
+			Usage:   "Sets private dns if 'yes'. Ignores if 'no'. Will retrieve from network if unset.",
+		},
+		&cli.StringFlag{
+			Name:    "islocal",
+			EnvVars: []string{"NETCLIENT_IS_LOCAL"},
+			Value:   "",
+			Usage:   "Sets endpoint to local address if 'yes'. Ignores if 'no'. Will retrieve from network if unset.",
+		},
+		&cli.StringFlag{
+			Name:    "isdualstack",
+			EnvVars: []string{"NETCLIENT_IS_DUALSTACK"},
+			Value:   "",
+			Usage:   "Sets ipv6 address if 'yes'. Ignores if 'no'. Will retrieve from network if unset.",
+		},
+		&cli.StringFlag{
+			Name:    "udpholepunch",
+			EnvVars: []string{"NETCLIENT_UDP_HOLEPUNCH"},
+			Value:   "",
+			Usage:   "Turns on udp holepunching if 'yes'. Ignores if 'no'. Will retrieve from network if unset.",
+		},
+		&cli.StringFlag{
+			Name:    "ipforwarding",
+			EnvVars: []string{"NETCLIENT_IPFORWARDING"},
+			Value:   "on",
+			Usage:   "Sets ip forwarding on if 'on'. Ignores if 'off'. On by default.",
+		},
+		&cli.StringFlag{
+			Name:    "postup",
+			EnvVars: []string{"NETCLIENT_POSTUP"},
+			Value:   "",
+			Usage:   "Sets PostUp command for WireGuard.",
+		},
+		&cli.StringFlag{
+			Name:    "postdown",
+			EnvVars: []string{"NETCLIENT_POSTDOWN"},
+			Value:   "",
+			Usage:   "Sets PostDown command for WireGuard.",
+		},
+		&cli.StringFlag{
+			Name:    "daemon",
+			EnvVars: []string{"NETCLIENT_DAEMON"},
+			Value:   "on",
+			Usage:   "Installs daemon if 'on'. Ignores if 'off'. On by default.",
+		},
+		&cli.StringFlag{
+			Name:    "roaming",
+			EnvVars: []string{"NETCLIENT_ROAMING"},
+			Value:   "yes",
+			Usage:   "Checks for IP changes if 'yes'. Ignores if 'no'. Yes by default.",
+		},
+	}
+}

+ 1 - 86
netclient/config/config.go

@@ -72,90 +72,6 @@ func Write(config *ClientConfig, network string) error {
 	return err
 }
 
-// WriteServer - writes the config of a server to disk for client
-func WriteServer(server string, accesskey string, network string) error {
-	if network == "" {
-		err := errors.New("no network provided - exiting")
-		return err
-	}
-	nofile := false
-	//home, err := homedir.Dir()
-	_, err := os.Stat(ncutils.GetNetclientPath() + "/config")
-	if os.IsNotExist(err) {
-		os.MkdirAll(ncutils.GetNetclientPath()+"/config", 0744)
-	} else if err != nil {
-		fmt.Println("couldnt find or create", ncutils.GetNetclientPath())
-		return err
-	}
-	home := ncutils.GetNetclientPathSpecific()
-
-	file := fmt.Sprintf(home + "netconfig-" + network)
-	//f, err := os.Open(file)
-	f, err := os.OpenFile(file, os.O_CREATE|os.O_RDWR, 0666)
-	//f, err := ioutil.ReadFile(file)
-	if err != nil {
-		fmt.Println("couldnt open netconfig-" + network)
-		fmt.Println(err)
-		nofile = true
-		//err = nil
-		return err
-	}
-	defer f.Close()
-
-	//cfg := &ClientConfig{}
-	var cfg ClientConfig
-
-	if !nofile {
-		fmt.Println("Writing to existing config file at " + home + "netconfig-" + network)
-		decoder := yaml.NewDecoder(f)
-		err = decoder.Decode(&cfg)
-		//err = yaml.Unmarshal(f, &cfg)
-		if err != nil {
-			//fmt.Println(err)
-			//return err
-		}
-		f.Close()
-		f, err = os.OpenFile(file, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0666)
-		if err != nil {
-			fmt.Println("couldnt open netconfig")
-			fmt.Println(err)
-			nofile = true
-			//err = nil
-			return err
-		}
-		defer f.Close()
-
-		if err != nil {
-			fmt.Println("trouble opening file")
-			fmt.Println(err)
-		}
-
-		cfg.Server.GRPCAddress = server
-		cfg.Server.AccessKey = accesskey
-
-		err = yaml.NewEncoder(f).Encode(cfg)
-		//_, err = yaml.Marshal(f, &cfg)
-		if err != nil {
-			fmt.Println("trouble encoding file")
-			return err
-		}
-	} else {
-		fmt.Println("Creating new config file at " + home + "netconfig-" + network)
-
-		cfg.Server.GRPCAddress = server
-		cfg.Server.AccessKey = accesskey
-
-		newf, err := os.Create(home + "netconfig-" + network)
-		err = yaml.NewEncoder(newf).Encode(cfg)
-		defer newf.Close()
-		if err != nil {
-			return err
-		}
-	}
-
-	return err
-}
-
 // ClientConfig.ReadConfig - used to read config from client disk into memory
 func (config *ClientConfig) ReadConfig() {
 
@@ -192,7 +108,6 @@ func (config *ClientConfig) ReadConfig() {
 // ModConfig - overwrites the node inside client config on disk
 func ModConfig(node *models.Node) error {
 	network := node.Network
-	networksettings := node.NetworkSettings
 	if network == "" {
 		return errors.New("no network provided")
 	}
@@ -207,7 +122,7 @@ func ModConfig(node *models.Node) error {
 	}
 
 	modconfig.Node = (*node)
-	modconfig.NetworkSettings = (networksettings)
+	modconfig.NetworkSettings = (*node.NetworkSettings)
 	err = Write(&modconfig, network)
 	return err
 }

+ 6 - 352
netclient/main.go

@@ -3,18 +3,12 @@
 package main
 
 import (
-	"errors"
 	"log"
 	"os"
-	"os/exec"
-	"os/signal"
 	"runtime/debug"
-	"strconv"
-	"syscall"
 
+	"github.com/gravitl/netmaker/netclient/cli_options"
 	"github.com/gravitl/netmaker/netclient/command"
-	"github.com/gravitl/netmaker/netclient/config"
-	"github.com/gravitl/netmaker/netclient/local"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/netclient/ncwindows"
 	"github.com/urfave/cli/v2"
@@ -24,360 +18,20 @@ func main() {
 	app := cli.NewApp()
 	app.Name = "Netclient CLI"
 	app.Usage = "Netmaker's netclient agent and CLI. Used to perform interactions with Netmaker server and set local WireGuard config."
-	app.Version = "v0.9.1"
+	app.Version = "v0.9.2"
 
-	hostname, err := os.Hostname()
-	if err != nil {
-		hostname = ""
-	}
-
-	cliFlags := []cli.Flag{
-		&cli.StringFlag{
-			Name:    "network",
-			Aliases: []string{"n"},
-			EnvVars: []string{"NETCLIENT_NETWORK"},
-			Value:   "all",
-			Usage:   "Network to perform specified action against.",
-		},
-		&cli.StringFlag{
-			Name:    "password",
-			Aliases: []string{"p"},
-			EnvVars: []string{"NETCLIENT_PASSWORD"},
-			Value:   "",
-			Usage:   "Password for authenticating with netmaker.",
-		},
-		&cli.StringFlag{
-			Name:    "endpoint",
-			Aliases: []string{"e"},
-			EnvVars: []string{"NETCLIENT_ENDPOINT"},
-			Value:   "",
-			Usage:   "Reachable (usually public) address for WireGuard (not the private WG address).",
-		},
-		&cli.StringFlag{
-			Name:    "macaddress",
-			Aliases: []string{"m"},
-			EnvVars: []string{"NETCLIENT_MACADDRESS"},
-			Value:   "",
-			Usage:   "Mac Address for this machine. Used as a unique identifier within Netmaker network.",
-		},
-		&cli.StringFlag{
-			Name:    "publickey",
-			Aliases: []string{"pubkey"},
-			EnvVars: []string{"NETCLIENT_PUBLICKEY"},
-			Value:   "",
-			Usage:   "Public Key for WireGuard Interface.",
-		},
-		&cli.StringFlag{
-			Name:    "privatekey",
-			Aliases: []string{"privkey"},
-			EnvVars: []string{"NETCLIENT_PRIVATEKEY"},
-			Value:   "",
-			Usage:   "Private Key for WireGuard Interface.",
-		},
-		&cli.StringFlag{
-			Name:    "port",
-			EnvVars: []string{"NETCLIENT_PORT"},
-			Value:   "",
-			Usage:   "Port for WireGuard Interface.",
-		},
-		&cli.IntFlag{
-			Name:    "keepalive",
-			EnvVars: []string{"NETCLIENT_KEEPALIVE"},
-			Value:   0,
-			Usage:   "Default PersistentKeepAlive for Peers in WireGuard Interface.",
-		},
-		&cli.StringFlag{
-			Name:    "operatingsystem",
-			Aliases: []string{"os"},
-			EnvVars: []string{"NETCLIENT_OS"},
-			Value:   "",
-			Usage:   "Identifiable name for machine within Netmaker network.",
-		},
-		&cli.StringFlag{
-			Name:    "name",
-			EnvVars: []string{"NETCLIENT_NAME"},
-			Value:   hostname,
-			Usage:   "Identifiable name for machine within Netmaker network.",
-		},
-		&cli.StringFlag{
-			Name:    "localaddress",
-			EnvVars: []string{"NETCLIENT_LOCALADDRESS"},
-			Value:   "",
-			Usage:   "Local address for machine. Can be used in place of Endpoint for machines on the same LAN.",
-		},
-		&cli.StringFlag{
-			Name:    "isstatic",
-			Aliases: []string{"st"},
-			EnvVars: []string{"NETCLIENT_IS_STATIC"},
-			Value:   "",
-			Usage:   "Indicates if client is static by default (will not change addresses automatically).",
-		},
-		&cli.StringFlag{
-			Name:    "address",
-			Aliases: []string{"a"},
-			EnvVars: []string{"NETCLIENT_ADDRESS"},
-			Value:   "",
-			Usage:   "WireGuard address for machine within Netmaker network.",
-		},
-		&cli.StringFlag{
-			Name:    "addressIPv6",
-			Aliases: []string{"a6"},
-			EnvVars: []string{"NETCLIENT_ADDRESSIPV6"},
-			Value:   "",
-			Usage:   "WireGuard address for machine within Netmaker network.",
-		},
-		&cli.StringFlag{
-			Name:    "interface",
-			Aliases: []string{"i"},
-			EnvVars: []string{"NETCLIENT_INTERFACE"},
-			Value:   "",
-			Usage:   "WireGuard local network interface name.",
-		},
-		&cli.StringFlag{
-			Name:    "apiserver",
-			EnvVars: []string{"NETCLIENT_API_SERVER"},
-			Value:   "",
-			Usage:   "Address + GRPC Port (e.g. 1.2.3.4:50051) of Netmaker server.",
-		},
-		&cli.StringFlag{
-			Name:    "grpcserver",
-			EnvVars: []string{"NETCLIENT_GRPC_SERVER"},
-			Value:   "",
-			Usage:   "Address + API Port (e.g. 1.2.3.4:8081) of Netmaker server.",
-		},
-		&cli.StringFlag{
-			Name:    "key",
-			Aliases: []string{"k"},
-			EnvVars: []string{"NETCLIENT_ACCESSKEY"},
-			Value:   "",
-			Usage:   "Access Key for signing up machine with Netmaker server during initial 'add'.",
-		},
-		&cli.StringFlag{
-			Name:    "token",
-			Aliases: []string{"t"},
-			EnvVars: []string{"NETCLIENT_ACCESSTOKEN"},
-			Value:   "",
-			Usage:   "Access Token for signing up machine with Netmaker server during initial 'add'.",
-		},
-		&cli.StringFlag{
-			Name:    "localrange",
-			EnvVars: []string{"NETCLIENT_LOCALRANGE"},
-			Value:   "",
-			Usage:   "Local Range if network is local, for instance 192.168.1.0/24.",
-		},
-		&cli.StringFlag{
-			Name:    "dnson",
-			EnvVars: []string{"NETCLIENT_DNS"},
-			Value:   "yes",
-			Usage:   "Sets private dns if 'yes'. Ignores if 'no'. Will retrieve from network if unset.",
-		},
-		&cli.StringFlag{
-			Name:    "islocal",
-			EnvVars: []string{"NETCLIENT_IS_LOCAL"},
-			Value:   "",
-			Usage:   "Sets endpoint to local address if 'yes'. Ignores if 'no'. Will retrieve from network if unset.",
-		},
-		&cli.StringFlag{
-			Name:    "isdualstack",
-			EnvVars: []string{"NETCLIENT_IS_DUALSTACK"},
-			Value:   "",
-			Usage:   "Sets ipv6 address if 'yes'. Ignores if 'no'. Will retrieve from network if unset.",
-		},
-		&cli.StringFlag{
-			Name:    "udpholepunch",
-			EnvVars: []string{"NETCLIENT_UDP_HOLEPUNCH"},
-			Value:   "",
-			Usage:   "Turns on udp holepunching if 'yes'. Ignores if 'no'. Will retrieve from network if unset.",
-		},
-		&cli.StringFlag{
-			Name:    "ipforwarding",
-			EnvVars: []string{"NETCLIENT_IPFORWARDING"},
-			Value:   "on",
-			Usage:   "Sets ip forwarding on if 'on'. Ignores if 'off'. On by default.",
-		},
-		&cli.StringFlag{
-			Name:    "postup",
-			EnvVars: []string{"NETCLIENT_POSTUP"},
-			Value:   "",
-			Usage:   "Sets PostUp command for WireGuard.",
-		},
-		&cli.StringFlag{
-			Name:    "postdown",
-			EnvVars: []string{"NETCLIENT_POSTDOWN"},
-			Value:   "",
-			Usage:   "Sets PostDown command for WireGuard.",
-		},
-		&cli.StringFlag{
-			Name:    "daemon",
-			EnvVars: []string{"NETCLIENT_DAEMON"},
-			Value:   "on",
-			Usage:   "Installs daemon if 'on'. Ignores if 'off'. On by default.",
-		},
-		&cli.StringFlag{
-			Name:    "roaming",
-			EnvVars: []string{"NETCLIENT_ROAMING"},
-			Value:   "yes",
-			Usage:   "Checks for IP changes if 'yes'. Ignores if 'no'. Yes by default.",
-		},
-	}
-
-	app.Commands = []*cli.Command{
-		{
-			Name:  "join",
-			Usage: "Join a Netmaker network.",
-			Flags: cliFlags,
-			Action: func(c *cli.Context) error {
-				cfg, pvtKey, err := config.GetCLIConfig(c)
-				if err != nil {
-					return err
-				}
-				if cfg.Network == "all" {
-					err = errors.New("No network provided.")
-					return err
-				}
-				if cfg.Server.GRPCAddress == "" {
-					err = errors.New("No server address provided.")
-					return err
-				}
-				err = command.Join(cfg, pvtKey)
-				return err
-			},
-		},
-		{
-			Name:  "leave",
-			Usage: "Leave a Netmaker network.",
-			Flags: cliFlags,
-			// the action, or code that will be executed when
-			// we execute our `ns` command
-			Action: func(c *cli.Context) error {
-				cfg, _, err := config.GetCLIConfig(c)
-				if err != nil {
-					return err
-				}
-				err = command.Leave(cfg)
-				return err
-			},
-		},
-		{
-			Name:  "checkin",
-			Usage: "Checks for local changes and then checks into the specified Netmaker network to ask about remote changes.",
-			Flags: cliFlags,
-			// the action, or code that will be executed when
-			// we execute our `ns` command
-			Action: func(c *cli.Context) error {
-				cfg, _, err := config.GetCLIConfig(c)
-				if err != nil {
-					return err
-				}
-				err = command.CheckIn(cfg)
-				return err
-			},
-		},
-		{
-			Name:  "push",
-			Usage: "Push configuration changes to server.",
-			Flags: cliFlags,
-			// the action, or code that will be executed when
-			// we execute our `ns` command
-			Action: func(c *cli.Context) error {
-				cfg, _, err := config.GetCLIConfig(c)
-				if err != nil {
-					return err
-				}
-				err = command.Push(cfg)
-				return err
-			},
-		},
-		{
-			Name:  "pull",
-			Usage: "Pull latest configuration and peers from server.",
-			Flags: cliFlags,
-			// the action, or code that will be executed when
-			// we execute our `ns` command
-			Action: func(c *cli.Context) error {
-				cfg, _, err := config.GetCLIConfig(c)
-				if err != nil {
-					return err
-				}
-				err = command.Pull(cfg)
-				return err
-			},
-		},
-		{
-			Name:  "list",
-			Usage: "Get list of networks.",
-			Flags: cliFlags,
-			// the action, or code that will be executed when
-			// we execute our `ns` command
-			Action: func(c *cli.Context) error {
-				cfg, _, err := config.GetCLIConfig(c)
-				if err != nil {
-					return err
-				}
-				err = command.List(cfg)
-				return err
-			},
-		},
-		{
-			Name:  "uninstall",
-			Usage: "Uninstall the netclient system service.",
-			Flags: cliFlags,
-			// the action, or code that will be executed when
-			// we execute our `ns` command
-			Action: func(c *cli.Context) error {
-				err := command.Uninstall()
-				return err
-			},
-		},
-	}
+	cliFlags := cli_options.GetFlags(ncutils.GetHostname())
+	app.Commands = cli_options.GetCommands(cliFlags[:])
 
 	setGarbageCollection()
 
 	if ncutils.IsWindows() {
 		ncwindows.InitWindows()
 	} else {
-		// start our application
-		out, err := ncutils.RunCmd("id -u", true)
-
-		if err != nil {
-			log.Fatal(out, err)
-		}
-		id, err := strconv.Atoi(string(out[:len(out)-1]))
-
-		if err != nil {
-			log.Fatal(err)
-		}
-
-		if id != 0 {
-			log.Fatal("This program must be run with elevated privileges (sudo). This program installs a SystemD service and configures WireGuard and networking rules. Please re-run with sudo/root.")
-		}
-
-		_, err = exec.LookPath("wg")
-		uspace := ncutils.GetWireGuard()
-		if err != nil {
-			if uspace == "wg" {
-				log.Println(err)
-				log.Fatal("WireGuard not installed. Please install WireGuard (wireguard-tools) and try again.")
-			}
-			ncutils.PrintLog("Running with userspace wireguard: "+uspace, 0)
-		} else if uspace != "wg" {
-			log.Println("running userspace WireGuard with " + uspace)
-		}
-	}
-	if !ncutils.IsKernel() {
-		if !local.IsWGInstalled() {
-			log.Fatal("Please install WireGuard before using Gravitl Netclient. https://download.wireguard.com")
-		}
+		ncutils.CheckUID()
+		ncutils.CheckWG()
 	}
 	if len(os.Args) == 1 && ncutils.IsWindows() {
-
-		c := make(chan os.Signal)
-		signal.Notify(c, os.Interrupt, syscall.SIGTERM)
-		go func() {
-			<-c
-			log.Println("closing Gravitl Netclient")
-			os.Exit(0)
-		}()
 		command.RunUserspaceDaemon()
 	} else {
 		err := app.Run(os.Args)

+ 47 - 0
netclient/ncutils/netclientutils.go

@@ -24,6 +24,9 @@ import (
 	"google.golang.org/grpc/credentials"
 )
 
+// MAX_NAME_LENGTH - maximum node name length
+const MAX_NAME_LENGTH = 62
+
 // NO_DB_RECORD - error message result
 const NO_DB_RECORD = "no result found"
 
@@ -447,3 +450,47 @@ func DNSFormatString(input string) string {
 	}
 	return reg.ReplaceAllString(input, "")
 }
+
+func GetHostname() string {
+	hostname, err := os.Hostname()
+	if err != nil {
+		return ""
+	}
+	if len(hostname) > MAX_NAME_LENGTH {
+		hostname = hostname[0:MAX_NAME_LENGTH]
+	}
+	return hostname
+}
+
+func CheckUID() {
+	// start our application
+	out, err := RunCmd("id -u", true)
+
+	if err != nil {
+		log.Fatal(out, err)
+	}
+	id, err := strconv.Atoi(string(out[:len(out)-1]))
+
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	if id != 0 {
+		log.Fatal("This program must be run with elevated privileges (sudo). This program installs a SystemD service and configures WireGuard and networking rules. Please re-run with sudo/root.")
+	}
+}
+
+// CheckWG - Checks if WireGuard is installed. If not, exit
+func CheckWG() {
+	var _, err = exec.LookPath("wg")
+	uspace := GetWireGuard()
+	if err != nil {
+		if uspace == "wg" {
+			PrintLog(err.Error(), 0)
+			log.Fatal("WireGuard not installed. Please install WireGuard (wireguard-tools) and try again.")
+		}
+		PrintLog("Running with userspace wireguard: "+uspace, 0)
+	} else if uspace != "wg" {
+		log.Println("running userspace WireGuard with " + uspace)
+	}
+}