Browse Source

Merge pull request #546 from gravitl/feature_v0.10.0_refactor

Feature v0.10.0 refactor
Alex 3 years ago
parent
commit
a412596a66
81 changed files with 2848 additions and 3246 deletions
  1. 0 1
      .gitignore
  2. 5 2
      Dockerfile
  3. 1 1
      README.md
  4. 10 9
      auth/auth.go
  5. 4 3
      auth/azure-ad.go
  6. 4 3
      auth/github.go
  7. 4 3
      auth/google.go
  8. 2 2
      compose/docker-compose.caddy.yml
  9. 2 2
      compose/docker-compose.contained.yml
  10. 2 2
      compose/docker-compose.nodns.yml
  11. 2 2
      compose/docker-compose.reference.yml
  12. 1 1
      compose/docker-compose.yml
  13. 9 6
      controllers/auth_grpc.go
  14. 0 95
      controllers/common.go
  15. 0 130
      controllers/common_test.go
  16. 23 13
      controllers/controller.go
  17. 33 0
      controllers/debug.go
  18. 189 0
      controllers/dns.go
  19. 0 450
      controllers/dnsHttpController.go
  20. 58 57
      controllers/dns_test.go
  21. 14 133
      controllers/ext_client.go
  22. 0 0
      controllers/files.go
  23. 23 0
      controllers/logger.go
  24. 298 0
      controllers/network.go
  25. 0 659
      controllers/networkHttpController.go
  26. 37 42
      controllers/network_test.go
  27. 34 261
      controllers/node.go
  28. 18 21
      controllers/node_grpc.go
  29. 20 18
      controllers/node_test.go
  30. 5 137
      controllers/relay.go
  31. 2 2
      controllers/response.go
  32. 0 0
      controllers/response_test.go
  33. 128 0
      controllers/security.go
  34. 1 4
      controllers/server.go
  35. 17 91
      controllers/user.go
  36. 23 23
      controllers/user_test.go
  37. 4 3
      database/database.go
  38. 4 0
      database/postgres.go
  39. 5 1
      database/sqlite.go
  40. 0 169
      functions/helpers.go
  41. 4 3
      functions/local.go
  42. 18 1
      go.mod
  43. 1 1
      kube/netclient-template-doks-uspace.yaml
  44. 2 2
      kube/netclient-template-doks.yaml
  45. 104 0
      logger/logger.go
  46. 167 1
      logic/accesskeys.go
  47. 3 2
      logic/auth.go
  48. 105 1
      logic/dns.go
  49. 105 2
      logic/extpeers.go
  50. 221 0
      logic/gateway.go
  51. 194 4
      logic/networks.go
  52. 32 7
      logic/nodes.go
  53. 140 0
      logic/relay.go
  54. 81 122
      logic/server.go
  55. 3 5
      logic/serverconf.go
  56. 42 53
      logic/util.go
  57. 51 47
      logic/wireguard.go
  58. 35 53
      main.go
  59. 0 1
      models/node.go
  60. 1 1
      models/structs.go
  61. 122 0
      netclient/cli_options/cmds.go
  62. 196 0
      netclient/cli_options/flags.go
  63. 5 0
      netclient/command/commands.go
  64. 1 86
      netclient/config/config.go
  65. 51 58
      netclient/daemon/windows.go
  66. 3 0
      netclient/functions/common.go
  67. 6 352
      netclient/main.go
  68. 51 3
      netclient/ncutils/netclientutils.go
  69. 6 0
      netclient/ncutils/netclientutils_darwin.go
  70. 6 0
      netclient/ncutils/netclientutils_freebsd.go
  71. 6 0
      netclient/ncutils/netclientutils_linux.go
  72. 19 0
      netclient/ncutils/netclientutils_windows.go
  73. 18 19
      netclient/ncutils/peerhelper.go
  74. BIN
      netclient/ncutils/windowsdaemon/winsw.exe
  75. 1 1
      netclient/netclient.exe.manifest.xml
  76. 1 1
      netclient/versioninfo.json
  77. 20 11
      netclient/wireguard/common.go
  78. 29 1
      netclient/wireguard/windows.go
  79. 1 1
      scripts/netclient.sh
  80. 2 15
      servercfg/serverconf.go
  81. 13 46
      serverctl/serverctl.go

+ 0 - 1
.gitignore

@@ -14,5 +14,4 @@ netclient/netclient-32
 netclient/netclient32
 netclient/netclient32
 netclient/netclient.exe
 netclient/netclient.exe
 config/dnsconfig/
 config/dnsconfig/
-winsw.exe
 data/
 data/

+ 5 - 2
Dockerfile

@@ -1,12 +1,15 @@
 #first stage - builder
 #first stage - builder
-FROM golang:1.15-alpine as builder
+FROM golang:1.17-alpine as builder
 ARG version
 ARG version
 RUN apk add build-base
 RUN apk add build-base
 WORKDIR /app
 WORKDIR /app
 COPY . .
 COPY . .
 ENV GO111MODULE=auto
 ENV GO111MODULE=auto
+
+# RUN GOOS=linux CGO_ENABLED=1 go build -tags debug -ldflags="-s -X 'main.version=$version'" -o netmaker main.go
 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 -ldflags="-s -X 'main.version=$version'" -o netmaker main.go
-FROM alpine:3.13.6
+FROM alpine:3.14.3
+
 # add a c lib
 # add a c lib
 RUN apk add gcompat iptables
 RUN apk add gcompat iptables
 # set the working directory
 # set the working directory

+ 1 - 1
README.md

@@ -8,7 +8,7 @@
 
 
 <p align="center">
 <p align="center">
   <a href="https://github.com/gravitl/netmaker/releases">
   <a href="https://github.com/gravitl/netmaker/releases">
-    <img src="https://img.shields.io/badge/Version-0.9.1-informational?style=flat-square" />
+    <img src="https://img.shields.io/badge/Version-0.9.2-informational?style=flat-square" />
   </a>
   </a>
   <a href="https://hub.docker.com/r/gravitl/netmaker/tags">
   <a href="https://hub.docker.com/r/gravitl/netmaker/tags">
     <img src="https://img.shields.io/docker/pulls/gravitl/netmaker" />
     <img src="https://img.shields.io/docker/pulls/gravitl/netmaker" />

+ 10 - 9
auth/auth.go

@@ -7,6 +7,7 @@ import (
 	"net/http"
 	"net/http"
 	"strings"
 	"strings"
 
 
+	"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/servercfg"
 	"github.com/gravitl/netmaker/servercfg"
@@ -53,7 +54,7 @@ func InitializeAuthProvider() string {
 	}
 	}
 	var _, err = fetchPassValue(logic.RandomString(64))
 	var _, err = fetchPassValue(logic.RandomString(64))
 	if err != nil {
 	if err != nil {
-		logic.Log(err.Error(), 0)
+		logger.Log(0, err.Error())
 		return ""
 		return ""
 	}
 	}
 	var currentFrontendURL = servercfg.GetFrontendURL()
 	var currentFrontendURL = servercfg.GetFrontendURL()
@@ -64,10 +65,10 @@ func InitializeAuthProvider() string {
 	var serverConn = servercfg.GetAPIHost()
 	var serverConn = servercfg.GetAPIHost()
 	if strings.Contains(serverConn, "localhost") || strings.Contains(serverConn, "127.0.0.1") {
 	if strings.Contains(serverConn, "localhost") || strings.Contains(serverConn, "127.0.0.1") {
 		serverConn = "http://" + serverConn
 		serverConn = "http://" + serverConn
-		logic.Log("localhost OAuth detected, proceeding with insecure http redirect: "+serverConn+")", 1)
+		logger.Log(1, "localhost OAuth detected, proceeding with insecure http redirect: (", serverConn, ")")
 	} else {
 	} else {
 		serverConn = "https://" + serverConn
 		serverConn = "https://" + serverConn
-		logic.Log("external OAuth detected, proceeding with https redirect: ("+serverConn+")", 1)
+		logger.Log(1, "external OAuth detected, proceeding with https redirect: ("+serverConn+")")
 	}
 	}
 
 
 	functions[init_provider].(func(string, string, string))(serverConn+"/api/oauth/callback", authInfo[1], authInfo[2])
 	functions[init_provider].(func(string, string, string))(serverConn+"/api/oauth/callback", authInfo[1], authInfo[2])
@@ -122,7 +123,7 @@ func IsOauthUser(user *models.User) error {
 func addUser(email string) error {
 func addUser(email string) error {
 	var hasAdmin, err = logic.HasAdmin()
 	var hasAdmin, err = logic.HasAdmin()
 	if err != nil {
 	if err != nil {
-		logic.Log("error checking for existence of admin user during OAuth login for "+email+", user not added", 1)
+		logger.Log(1, "error checking for existence of admin user during OAuth login for", email, "; user not added")
 		return err
 		return err
 	} // generate random password to adapt to current model
 	} // generate random password to adapt to current model
 	var newPass, fetchErr = fetchPassValue("")
 	var newPass, fetchErr = fetchPassValue("")
@@ -135,17 +136,17 @@ func addUser(email string) error {
 	}
 	}
 	if !hasAdmin { // must be first attempt, create an admin
 	if !hasAdmin { // must be first attempt, create an admin
 		if newUser, err = logic.CreateAdmin(newUser); err != nil {
 		if newUser, err = logic.CreateAdmin(newUser); err != nil {
-			logic.Log("error creating admin from user, "+email+", user not added", 1)
+			logger.Log(1, "error creating admin from user,", email, "; user not added")
 		} else {
 		} else {
-			logic.Log("admin created from user, "+email+", was first user added", 0)
+			logger.Log(1, "admin created from user,", email, "; was first user added")
 		}
 		}
 	} else { // otherwise add to db as admin..?
 	} else { // otherwise add to db as admin..?
 		// TODO: add ability to add users with preemptive permissions
 		// TODO: add ability to add users with preemptive permissions
 		newUser.IsAdmin = false
 		newUser.IsAdmin = false
 		if newUser, err = logic.CreateUser(newUser); err != nil {
 		if newUser, err = logic.CreateUser(newUser); err != nil {
-			logic.Log("error creating user, "+email+", user not added", 1)
+			logger.Log(1, "error creating user,", email, "; user not added")
 		} else {
 		} else {
-			logic.Log("user created from, "+email+"", 0)
+			logger.Log(0, "user created from ", email)
 		}
 		}
 	}
 	}
 	return nil
 	return nil
@@ -176,7 +177,7 @@ func fetchPassValue(newValue string) (string, error) {
 
 
 	var b64CurrentValue, b64Err = base64.StdEncoding.DecodeString(newValueHolder.Value)
 	var b64CurrentValue, b64Err = base64.StdEncoding.DecodeString(newValueHolder.Value)
 	if b64Err != nil {
 	if b64Err != nil {
-		logic.Log("could not decode pass", 0)
+		logger.Log(0, "could not decode pass")
 		return "", nil
 		return "", nil
 	}
 	}
 	return string(b64CurrentValue), nil
 	return string(b64CurrentValue), nil

+ 4 - 3
auth/azure-ad.go

@@ -7,6 +7,7 @@ import (
 	"net/http"
 	"net/http"
 	"os"
 	"os"
 
 
+	"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/servercfg"
 	"github.com/gravitl/netmaker/servercfg"
@@ -56,7 +57,7 @@ func handleAzureCallback(w http.ResponseWriter, r *http.Request) {
 
 
 	var content, err = getAzureUserInfo(r.FormValue("state"), r.FormValue("code"))
 	var content, err = getAzureUserInfo(r.FormValue("state"), r.FormValue("code"))
 	if err != nil {
 	if err != nil {
-		logic.Log("error when getting user info from azure: "+err.Error(), 1)
+		logger.Log(1, "error when getting user info from azure:", err.Error())
 		http.Redirect(w, r, servercfg.GetFrontendURL()+"/login?oauth=callback-error", http.StatusTemporaryRedirect)
 		http.Redirect(w, r, servercfg.GetFrontendURL()+"/login?oauth=callback-error", http.StatusTemporaryRedirect)
 		return
 		return
 	}
 	}
@@ -78,11 +79,11 @@ func handleAzureCallback(w http.ResponseWriter, r *http.Request) {
 
 
 	var jwt, jwtErr = logic.VerifyAuthRequest(authRequest)
 	var jwt, jwtErr = logic.VerifyAuthRequest(authRequest)
 	if jwtErr != nil {
 	if jwtErr != nil {
-		logic.Log("could not parse jwt for user "+authRequest.UserName, 1)
+		logger.Log(1, "could not parse jwt for user", authRequest.UserName)
 		return
 		return
 	}
 	}
 
 
-	logic.Log("completed azure OAuth sigin in for "+content.UserPrincipalName, 1)
+	logger.Log(1, "completed azure OAuth sigin in for", content.UserPrincipalName)
 	http.Redirect(w, r, servercfg.GetFrontendURL()+"/login?login="+jwt+"&user="+content.UserPrincipalName, http.StatusPermanentRedirect)
 	http.Redirect(w, r, servercfg.GetFrontendURL()+"/login?login="+jwt+"&user="+content.UserPrincipalName, http.StatusPermanentRedirect)
 }
 }
 
 

+ 4 - 3
auth/github.go

@@ -6,6 +6,7 @@ import (
 	"io/ioutil"
 	"io/ioutil"
 	"net/http"
 	"net/http"
 
 
+	"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/servercfg"
 	"github.com/gravitl/netmaker/servercfg"
@@ -55,7 +56,7 @@ func handleGithubCallback(w http.ResponseWriter, r *http.Request) {
 
 
 	var content, err = getGithubUserInfo(r.URL.Query().Get("state"), r.URL.Query().Get("code"))
 	var content, err = getGithubUserInfo(r.URL.Query().Get("state"), r.URL.Query().Get("code"))
 	if err != nil {
 	if err != nil {
-		logic.Log("error when getting user info from github: "+err.Error(), 1)
+		logger.Log(1, "error when getting user info from github:", err.Error())
 		http.Redirect(w, r, servercfg.GetFrontendURL()+"/login?oauth=callback-error", http.StatusTemporaryRedirect)
 		http.Redirect(w, r, servercfg.GetFrontendURL()+"/login?oauth=callback-error", http.StatusTemporaryRedirect)
 		return
 		return
 	}
 	}
@@ -77,11 +78,11 @@ func handleGithubCallback(w http.ResponseWriter, r *http.Request) {
 
 
 	var jwt, jwtErr = logic.VerifyAuthRequest(authRequest)
 	var jwt, jwtErr = logic.VerifyAuthRequest(authRequest)
 	if jwtErr != nil {
 	if jwtErr != nil {
-		logic.Log("could not parse jwt for user "+authRequest.UserName, 1)
+		logger.Log(1, "could not parse jwt for user", authRequest.UserName)
 		return
 		return
 	}
 	}
 
 
-	logic.Log("completed github OAuth sigin in for "+content.Login, 1)
+	logger.Log(1, "completed github OAuth sigin in for", content.Login)
 	http.Redirect(w, r, servercfg.GetFrontendURL()+"/login?login="+jwt+"&user="+content.Login, http.StatusPermanentRedirect)
 	http.Redirect(w, r, servercfg.GetFrontendURL()+"/login?login="+jwt+"&user="+content.Login, http.StatusPermanentRedirect)
 }
 }
 
 

+ 4 - 3
auth/google.go

@@ -6,6 +6,7 @@ import (
 	"io/ioutil"
 	"io/ioutil"
 	"net/http"
 	"net/http"
 
 
+	"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/servercfg"
 	"github.com/gravitl/netmaker/servercfg"
@@ -55,7 +56,7 @@ func handleGoogleCallback(w http.ResponseWriter, r *http.Request) {
 
 
 	var content, err = getGoogleUserInfo(r.FormValue("state"), r.FormValue("code"))
 	var content, err = getGoogleUserInfo(r.FormValue("state"), r.FormValue("code"))
 	if err != nil {
 	if err != nil {
-		logic.Log("error when getting user info from google: "+err.Error(), 1)
+		logger.Log(1, "error when getting user info from google:", err.Error())
 		http.Redirect(w, r, servercfg.GetFrontendURL()+"/login?oauth=callback-error", http.StatusTemporaryRedirect)
 		http.Redirect(w, r, servercfg.GetFrontendURL()+"/login?oauth=callback-error", http.StatusTemporaryRedirect)
 		return
 		return
 	}
 	}
@@ -77,11 +78,11 @@ func handleGoogleCallback(w http.ResponseWriter, r *http.Request) {
 
 
 	var jwt, jwtErr = logic.VerifyAuthRequest(authRequest)
 	var jwt, jwtErr = logic.VerifyAuthRequest(authRequest)
 	if jwtErr != nil {
 	if jwtErr != nil {
-		logic.Log("could not parse jwt for user "+authRequest.UserName, 1)
+		logger.Log(1, "could not parse jwt for user", authRequest.UserName)
 		return
 		return
 	}
 	}
 
 
-	logic.Log("completed google OAuth sigin in for "+content.Email, 1)
+	logger.Log(1, "completed google OAuth sigin in for", content.Email)
 	http.Redirect(w, r, servercfg.GetFrontendURL()+"/login?login="+jwt+"&user="+content.Email, http.StatusPermanentRedirect)
 	http.Redirect(w, r, servercfg.GetFrontendURL()+"/login?login="+jwt+"&user="+content.Email, http.StatusPermanentRedirect)
 }
 }
 
 

+ 2 - 2
compose/docker-compose.caddy.yml

@@ -3,7 +3,7 @@ version: "3.4"
 services:
 services:
   netmaker:
   netmaker:
     container_name: netmaker
     container_name: netmaker
-    image: gravitl/netmaker:v0.9.1
+    image: gravitl/netmaker:v0.9.2
     volumes:
     volumes:
       - /var/run/dbus/system_bus_socket:/var/run/dbus/system_bus_socket
       - /var/run/dbus/system_bus_socket:/var/run/dbus/system_bus_socket
       - /run/systemd/system:/run/systemd/system
       - /run/systemd/system:/run/systemd/system
@@ -40,7 +40,7 @@ services:
     container_name: netmaker-ui
     container_name: netmaker-ui
     depends_on:
     depends_on:
       - netmaker
       - netmaker
-    image: gravitl/netmaker-ui:v0.9.1
+    image: gravitl/netmaker-ui:v0.9.2
     links:
     links:
       - "netmaker:api"
       - "netmaker:api"
     ports:
     ports:

+ 2 - 2
compose/docker-compose.contained.yml

@@ -3,7 +3,7 @@ version: "3.4"
 services:
 services:
   netmaker:
   netmaker:
     container_name: netmaker
     container_name: netmaker
-    image: gravitl/netmaker:v0.9.1
+    image: gravitl/netmaker:v0.9.2
     volumes:
     volumes:
       - dnsconfig:/root/config/dnsconfig
       - dnsconfig:/root/config/dnsconfig
       - /usr/bin/wg:/usr/bin/wg
       - /usr/bin/wg:/usr/bin/wg
@@ -38,7 +38,7 @@ services:
     container_name: netmaker-ui
     container_name: netmaker-ui
     depends_on:
     depends_on:
       - netmaker
       - netmaker
-    image: gravitl/netmaker-ui:v0.9.1
+    image: gravitl/netmaker-ui:v0.9.2
     links:
     links:
       - "netmaker:api"
       - "netmaker:api"
     ports:
     ports:

+ 2 - 2
compose/docker-compose.nodns.yml

@@ -3,7 +3,7 @@ version: "3.4"
 services:
 services:
   netmaker:
   netmaker:
     container_name: netmaker
     container_name: netmaker
-    image: gravitl/netmaker:v0.9.1
+    image: gravitl/netmaker:v0.9.2
     volumes:
     volumes:
       - /usr/bin/wg:/usr/bin/wg
       - /usr/bin/wg:/usr/bin/wg
       - sqldata:/root/data
       - sqldata:/root/data
@@ -36,7 +36,7 @@ services:
     container_name: netmaker-ui
     container_name: netmaker-ui
     depends_on:
     depends_on:
       - netmaker
       - netmaker
-    image: gravitl/netmaker-ui:v0.9.1
+    image: gravitl/netmaker-ui:v0.9.2
     links:
     links:
       - "netmaker:api"
       - "netmaker:api"
     ports:
     ports:

+ 2 - 2
compose/docker-compose.reference.yml

@@ -11,7 +11,7 @@ services:
     container_name: netmaker
     container_name: netmaker
     depends_on:
     depends_on:
       - rqlite
       - rqlite
-    image: gravitl/netmaker:v0.9.1
+    image: gravitl/netmaker:v0.9.2
     volumes: # Volume mounts necessary for CLIENT_MODE to control wireguard networking on host (except dnsconfig, which is where dns config files are stored for use by CoreDNS)
     volumes: # Volume mounts necessary for CLIENT_MODE to control wireguard networking on host (except dnsconfig, which is where dns config files are stored for use by CoreDNS)
       - dnsconfig:/root/config/dnsconfig # Netmaker writes Corefile to this location, which gets mounted by CoreDNS for DNS configuration.
       - dnsconfig:/root/config/dnsconfig # Netmaker writes Corefile to this location, which gets mounted by CoreDNS for DNS configuration.
       - /usr/bin/wg:/usr/bin/wg
       - /usr/bin/wg:/usr/bin/wg
@@ -41,7 +41,7 @@ services:
     container_name: netmaker-ui
     container_name: netmaker-ui
     depends_on:
     depends_on:
       - netmaker
       - netmaker
-    image: gravitl/netmaker-ui:v0.9.1
+    image: gravitl/netmaker-ui:v0.9.2
     links:
     links:
       - "netmaker:api"
       - "netmaker:api"
     ports:
     ports:

+ 1 - 1
compose/docker-compose.yml

@@ -40,7 +40,7 @@ services:
     container_name: netmaker-ui
     container_name: netmaker-ui
     depends_on:
     depends_on:
       - netmaker
       - netmaker
-    image: gravitl/netmaker-ui:v0.9.1
+    image: gravitl/netmaker-ui:v0.9.2
     links:
     links:
       - "netmaker:api"
       - "netmaker:api"
     ports:
     ports:

+ 9 - 6
controllers/authGrpc.go → controllers/auth_grpc.go

@@ -17,6 +17,7 @@ import (
 	"google.golang.org/grpc/status"
 	"google.golang.org/grpc/status"
 )
 )
 
 
+// AuthServerUnaryInterceptor - auth unary interceptor logic
 func AuthServerUnaryInterceptor(ctx context.Context,
 func AuthServerUnaryInterceptor(ctx context.Context,
 	req interface{},
 	req interface{},
 	info *grpc.UnaryServerInfo,
 	info *grpc.UnaryServerInfo,
@@ -38,6 +39,8 @@ func AuthServerUnaryInterceptor(ctx context.Context,
 
 
 	return h, err
 	return h, err
 }
 }
+
+// AuthServerStreamInterceptor - auth stream interceptor
 func AuthServerStreamInterceptor(
 func AuthServerStreamInterceptor(
 	srv interface{},
 	srv interface{},
 	stream grpc.ServerStream,
 	stream grpc.ServerStream,
@@ -100,7 +103,7 @@ func grpcAuthorize(ctx context.Context) error {
 	return nil
 	return nil
 }
 }
 
 
-//Node authenticates using its password and retrieves a JWT for authorization.
+// Login - node authenticates using its password and retrieves a JWT for authorization.
 func (s *NodeServiceServer) Login(ctx context.Context, req *nodepb.Object) (*nodepb.Object, error) {
 func (s *NodeServiceServer) Login(ctx context.Context, req *nodepb.Object) (*nodepb.Object, error) {
 
 
 	//out := new(LoginResponse)
 	//out := new(LoginResponse)
@@ -114,15 +117,15 @@ func (s *NodeServiceServer) Login(ctx context.Context, req *nodepb.Object) (*nod
 	password := reqNode.Password
 	password := reqNode.Password
 
 
 	var result models.NodeAuth
 	var result models.NodeAuth
-
-	err := errors.New("Generic server error.")
+	var err error
+	// err := errors.New("generic server error")
 
 
 	if macaddress == "" {
 	if macaddress == "" {
 		//TODO: Set Error  response
 		//TODO: Set Error  response
-		err = errors.New("Missing Mac Address.")
+		err = errors.New("missing mac address")
 		return nil, err
 		return nil, err
 	} else if password == "" {
 	} else if password == "" {
-		err = errors.New("Missing Password.")
+		err = errors.New("missing password")
 		return nil, err
 		return nil, err
 	} else {
 	} else {
 		//Search DB for node with Mac Address. Ignore pending nodes (they should not be able to authenticate with API until approved).
 		//Search DB for node with Mac Address. Ignore pending nodes (they should not be able to authenticate with API until approved).
@@ -153,7 +156,7 @@ func (s *NodeServiceServer) Login(ctx context.Context, req *nodepb.Object) (*nod
 				return nil, err
 				return nil, err
 			}
 			}
 			if tokenString == "" {
 			if tokenString == "" {
-				err = errors.New("Something went wrong. Could not retrieve token.")
+				err = errors.New("something went wrong, could not retrieve token")
 				return nil, err
 				return nil, err
 			}
 			}
 
 

+ 0 - 95
controllers/common.go

@@ -1,95 +0,0 @@
-package controller
-
-import (
-	"encoding/json"
-	"strings"
-
-	"github.com/gravitl/netmaker/database"
-	"github.com/gravitl/netmaker/functions"
-	"github.com/gravitl/netmaker/logic"
-	"github.com/gravitl/netmaker/models"
-	"github.com/gravitl/netmaker/servercfg"
-)
-
-/**
- * If being deleted by server, create a record in the DELETED_NODES_TABLE for the client to find
- * If being deleted by the client, delete completely
- */
-func DeleteNode(key string, exterminate bool) error {
-	var err error
-	if !exterminate {
-		args := strings.Split(key, "###")
-		node, err := GetNode(args[0], args[1])
-		if err != nil {
-			return err
-		}
-		node.Action = models.NODE_DELETE
-		nodedata, err := json.Marshal(&node)
-		if err != nil {
-			return err
-		}
-		err = database.Insert(key, string(nodedata), database.DELETED_NODES_TABLE_NAME)
-		if err != nil {
-			return err
-		}
-	} else {
-		if err := database.DeleteRecord(database.DELETED_NODES_TABLE_NAME, key); err != nil {
-			functions.PrintUserLog("", err.Error(), 2)
-		}
-	}
-	if err := database.DeleteRecord(database.NODES_TABLE_NAME, key); err != nil {
-		return err
-	}
-	if servercfg.IsDNSMode() {
-		err = logic.SetDNS()
-	}
-	return err
-}
-
-func DeleteIntClient(clientid string) (bool, error) {
-
-	err := database.DeleteRecord(database.INT_CLIENTS_TABLE_NAME, clientid)
-	if err != nil {
-		return false, err
-	}
-
-	return true, nil
-}
-
-func GetNode(macaddress string, network string) (models.Node, error) {
-
-	var node models.Node
-
-	key, err := logic.GetRecordKey(macaddress, network)
-	if err != nil {
-		return node, err
-	}
-	data, err := database.FetchRecord(database.NODES_TABLE_NAME, key)
-	if err != nil {
-		if data == "" {
-			data, err = database.FetchRecord(database.DELETED_NODES_TABLE_NAME, key)
-			err = json.Unmarshal([]byte(data), &node)
-		}
-		return node, err
-	}
-	if err = json.Unmarshal([]byte(data), &node); err != nil {
-		return node, err
-	}
-	logic.SetNodeDefaults(&node)
-
-	return node, err
-}
-
-func GetIntClient(clientid string) (models.IntClient, error) {
-
-	var client models.IntClient
-
-	value, err := database.FetchRecord(database.INT_CLIENTS_TABLE_NAME, clientid)
-	if err != nil {
-		return client, err
-	}
-	if err = json.Unmarshal([]byte(value), &client); err != nil {
-		return models.IntClient{}, err
-	}
-	return client, nil
-}

+ 0 - 130
controllers/common_test.go

@@ -1,130 +0,0 @@
-package controller
-
-import (
-	"testing"
-
-	"github.com/gravitl/netmaker/database"
-	"github.com/gravitl/netmaker/logic"
-	"github.com/gravitl/netmaker/models"
-	"github.com/stretchr/testify/assert"
-)
-
-func TestGetPeerList(t *testing.T) {
-	database.InitializeDatabase()
-	deleteAllNetworks()
-	createNet()
-	t.Run("NoNodes", func(t *testing.T) {
-		peers, err := logic.GetPeersList("skynet", false, "")
-		assert.Nil(t, err)
-		assert.Nil(t, peers)
-	})
-	node := createTestNode()
-	t.Run("One Node", func(t *testing.T) {
-		peers, err := logic.GetPeersList("skynet", false, "")
-		assert.Nil(t, err)
-		assert.Equal(t, node.Address, peers[0].Address)
-	})
-	t.Run("Multiple Nodes", func(t *testing.T) {
-		createnode := models.Node{PublicKey: "RM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34=", Endpoint: "10.0.0.2", MacAddress: "02:02:03:04:05:06", Password: "password", Network: "skynet"}
-		logic.CreateNode(createnode, "skynet")
-		peers, err := logic.GetPeersList("skynet", false, "")
-		assert.Nil(t, err)
-		assert.Equal(t, len(peers), 2)
-		foundNodeEndpoint := false
-		for _, peer := range peers {
-			if foundNodeEndpoint = peer.Endpoint == createnode.Endpoint; foundNodeEndpoint {
-				break
-			}
-		}
-		assert.True(t, foundNodeEndpoint)
-	})
-}
-
-func TestDeleteNode(t *testing.T) {
-	database.InitializeDatabase()
-	deleteAllNetworks()
-	createNet()
-	node := createTestNode()
-	t.Run("NodeExists", func(t *testing.T) {
-		err := DeleteNode(node.MacAddress, true)
-		assert.Nil(t, err)
-	})
-	t.Run("NonExistantNode", func(t *testing.T) {
-		err := DeleteNode(node.MacAddress, true)
-		assert.Nil(t, err)
-	})
-}
-
-func TestGetNode(t *testing.T) {
-	database.InitializeDatabase()
-	deleteAllNetworks()
-	t.Run("NoNode", func(t *testing.T) {
-		response, err := GetNode("01:02:03:04:05:06", "skynet")
-		assert.Equal(t, models.Node{}, response)
-		assert.EqualError(t, err, "unexpected end of JSON input")
-	})
-	createNet()
-	node := createTestNode()
-
-	t.Run("NodeExists", func(t *testing.T) {
-		response, err := GetNode(node.MacAddress, node.Network)
-		assert.Nil(t, err)
-		assert.Equal(t, "10.0.0.1", response.Endpoint)
-		assert.Equal(t, "DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34=", response.PublicKey)
-		assert.Equal(t, "01:02:03:04:05:06", response.MacAddress)
-		assert.Equal(t, int32(51821), response.ListenPort)
-		assert.NotNil(t, response.Name)
-		assert.Equal(t, "skynet", response.Network)
-		assert.Equal(t, "nm-skynet", response.Interface)
-	})
-	t.Run("BadMac", func(t *testing.T) {
-		response, err := GetNode("01:02:03:04:05:07", node.Network)
-		assert.Equal(t, models.Node{}, response)
-		assert.EqualError(t, err, "unexpected end of JSON input")
-	})
-	t.Run("BadNetwork", func(t *testing.T) {
-		response, err := GetNode(node.MacAddress, "badnet")
-		assert.Equal(t, models.Node{}, response)
-		assert.EqualError(t, err, "unexpected end of JSON input")
-	})
-
-}
-
-func TestCreateNode(t *testing.T) {
-	t.Skip()
-	database.InitializeDatabase()
-	deleteAllNetworks()
-	createNet()
-	createnode := models.Node{PublicKey: "DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34=", Endpoint: "10.0.0.1", MacAddress: "01:02:03:04:05:06", Password: "password", Network: "skynet"}
-	//err := ValidateNodeCreate("skynet", createnode)
-	//assert.Nil(t, err)
-	node, err := logic.CreateNode(createnode, "skynet")
-	assert.Nil(t, err)
-	assert.Equal(t, "10.0.0.1", node.Endpoint)
-	assert.Equal(t, "DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34=", node.PublicKey)
-	assert.Equal(t, "01:02:03:04:05:06", node.MacAddress)
-	assert.Equal(t, int32(51821), node.ListenPort)
-	assert.NotNil(t, node.Name)
-	assert.Equal(t, "skynet", node.Network)
-	assert.Equal(t, "nm-skynet", node.Interface)
-}
-
-func TestSetNetworkNodesLastModified(t *testing.T) {
-	database.InitializeDatabase()
-	deleteAllNetworks()
-	createNet()
-	t.Run("InvalidNetwork", func(t *testing.T) {
-		err := logic.SetNetworkNodesLastModified("badnet")
-		assert.EqualError(t, err, "no result found")
-	})
-	t.Run("NetworkExists", func(t *testing.T) {
-		err := logic.SetNetworkNodesLastModified("skynet")
-		assert.Nil(t, err)
-	})
-}
-
-func createTestNode() models.Node {
-	createnode := models.Node{PublicKey: "DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34=", Name: "testnode", Endpoint: "10.0.0.1", MacAddress: "01:02:03:04:05:06", Password: "password", Network: "skynet"}
-	node, _ := logic.CreateNode(createnode, "skynet")
-	return node
-}

+ 23 - 13
controllers/controller.go

@@ -2,18 +2,30 @@ package controller
 
 
 import (
 import (
 	"context"
 	"context"
-	"log"
+	"fmt"
 	"net/http"
 	"net/http"
 	"os"
 	"os"
 	"os/signal"
 	"os/signal"
 	"sync"
 	"sync"
+	"time"
 
 
 	"github.com/gorilla/handlers"
 	"github.com/gorilla/handlers"
 	"github.com/gorilla/mux"
 	"github.com/gorilla/mux"
-	"github.com/gravitl/netmaker/logic"
+	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/servercfg"
 	"github.com/gravitl/netmaker/servercfg"
 )
 )
 
 
+var HttpHandlers = []interface{}{
+	nodeHandlers,
+	userHandlers,
+	networkHandlers,
+	dnsHandlers,
+	fileHandlers,
+	serverHandlers,
+	extClientHandlers,
+	loggerHandlers,
+}
+
 // HandleRESTRequests - handles the rest requests
 // HandleRESTRequests - handles the rest requests
 func HandleRESTRequests(wg *sync.WaitGroup) {
 func HandleRESTRequests(wg *sync.WaitGroup) {
 	defer wg.Done()
 	defer wg.Done()
@@ -26,13 +38,9 @@ func HandleRESTRequests(wg *sync.WaitGroup) {
 	originsOk := handlers.AllowedOrigins([]string{servercfg.GetAllowedOrigin()})
 	originsOk := handlers.AllowedOrigins([]string{servercfg.GetAllowedOrigin()})
 	methodsOk := handlers.AllowedMethods([]string{"GET", "PUT", "POST", "DELETE"})
 	methodsOk := handlers.AllowedMethods([]string{"GET", "PUT", "POST", "DELETE"})
 
 
-	nodeHandlers(r)
-	userHandlers(r)
-	networkHandlers(r)
-	dnsHandlers(r)
-	fileHandlers(r)
-	serverHandlers(r)
-	extClientHandlers(r)
+	for _, handler := range HttpHandlers {
+		handler.(func(*mux.Router))(r)
+	}
 
 
 	port := servercfg.GetAPIPort()
 	port := servercfg.GetAPIPort()
 
 
@@ -40,10 +48,10 @@ func HandleRESTRequests(wg *sync.WaitGroup) {
 	go func() {
 	go func() {
 		err := srv.ListenAndServe()
 		err := srv.ListenAndServe()
 		if err != nil {
 		if err != nil {
-			log.Println(err)
+			logger.Log(0, err.Error())
 		}
 		}
 	}()
 	}()
-	logic.Log("REST Server successfully started on port "+port+" (REST)", 0)
+	logger.Log(0, "REST Server successfully started on port ", port, " (REST)")
 	c := make(chan os.Signal)
 	c := make(chan os.Signal)
 
 
 	// Relay os.Interrupt to our channel (os.Interrupt = CTRL+C)
 	// Relay os.Interrupt to our channel (os.Interrupt = CTRL+C)
@@ -55,7 +63,9 @@ func HandleRESTRequests(wg *sync.WaitGroup) {
 	<-c
 	<-c
 
 
 	// After receiving CTRL+C Properly stop the server
 	// After receiving CTRL+C Properly stop the server
-	logic.Log("Stopping the REST server...", 0)
+	logger.Log(0, "Stopping the REST server...")
 	srv.Shutdown(context.TODO())
 	srv.Shutdown(context.TODO())
-	logic.Log("REST Server closed.", 0)
+	logger.Log(0, "REST Server closed.")
+	logger.DumpFile(fmt.Sprintf("data/netmaker.log.%s", time.Now().Format(logger.TimeFormatDay)))
+
 }
 }

+ 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())
+	}()
+}

+ 189 - 0
controllers/dns.go

@@ -0,0 +1,189 @@
+package controller
+
+import (
+	"encoding/json"
+	"net/http"
+
+	"github.com/gorilla/mux"
+	"github.com/gravitl/netmaker/database"
+	"github.com/gravitl/netmaker/logger"
+	"github.com/gravitl/netmaker/logic"
+	"github.com/gravitl/netmaker/models"
+)
+
+func dnsHandlers(r *mux.Router) {
+
+	r.HandleFunc("/api/dns", securityCheck(true, http.HandlerFunc(getAllDNS))).Methods("GET")
+	r.HandleFunc("/api/dns/adm/{network}/nodes", securityCheck(false, http.HandlerFunc(getNodeDNS))).Methods("GET")
+	r.HandleFunc("/api/dns/adm/{network}/custom", securityCheck(false, http.HandlerFunc(getCustomDNS))).Methods("GET")
+	r.HandleFunc("/api/dns/adm/{network}", securityCheck(false, http.HandlerFunc(getDNS))).Methods("GET")
+	r.HandleFunc("/api/dns/{network}", securityCheck(false, http.HandlerFunc(createDNS))).Methods("POST")
+	r.HandleFunc("/api/dns/adm/pushdns", securityCheck(false, http.HandlerFunc(pushDNS))).Methods("POST")
+	r.HandleFunc("/api/dns/{network}/{domain}", securityCheck(false, http.HandlerFunc(deleteDNS))).Methods("DELETE")
+}
+
+//Gets all nodes associated with network, including pending nodes
+func getNodeDNS(w http.ResponseWriter, r *http.Request) {
+
+	w.Header().Set("Content-Type", "application/json")
+
+	var dns []models.DNSEntry
+	var params = mux.Vars(r)
+
+	dns, err := logic.GetNodeDNS(params["network"])
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+
+	//Returns all the nodes in JSON format
+	w.WriteHeader(http.StatusOK)
+	json.NewEncoder(w).Encode(dns)
+}
+
+//Gets all nodes associated with network, including pending nodes
+func getAllDNS(w http.ResponseWriter, r *http.Request) {
+	w.Header().Set("Content-Type", "application/json")
+	dns, err := logic.GetAllDNS()
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+	//Returns all the nodes in JSON format
+	w.WriteHeader(http.StatusOK)
+	json.NewEncoder(w).Encode(dns)
+}
+
+//Gets all nodes associated with network, including pending nodes
+func getCustomDNS(w http.ResponseWriter, r *http.Request) {
+
+	w.Header().Set("Content-Type", "application/json")
+
+	var dns []models.DNSEntry
+	var params = mux.Vars(r)
+
+	dns, err := logic.GetCustomDNS(params["network"])
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+
+	//Returns all the nodes in JSON format
+	w.WriteHeader(http.StatusOK)
+	json.NewEncoder(w).Encode(dns)
+}
+
+// Gets all nodes associated with network, including pending nodes
+func getDNS(w http.ResponseWriter, r *http.Request) {
+
+	w.Header().Set("Content-Type", "application/json")
+
+	var dns []models.DNSEntry
+	var params = mux.Vars(r)
+
+	dns, err := logic.GetDNS(params["network"])
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+	w.WriteHeader(http.StatusOK)
+	json.NewEncoder(w).Encode(dns)
+}
+
+func createDNS(w http.ResponseWriter, r *http.Request) {
+	w.Header().Set("Content-Type", "application/json")
+
+	var entry models.DNSEntry
+	var params = mux.Vars(r)
+
+	//get node from body of request
+	_ = json.NewDecoder(r.Body).Decode(&entry)
+	entry.Network = params["network"]
+
+	err := logic.ValidateDNSCreate(entry)
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "badrequest"))
+		return
+	}
+
+	entry, err = CreateDNS(entry)
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+	err = logic.SetDNS()
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+	w.WriteHeader(http.StatusOK)
+	json.NewEncoder(w).Encode(entry)
+}
+
+func deleteDNS(w http.ResponseWriter, r *http.Request) {
+	// Set header
+	w.Header().Set("Content-Type", "application/json")
+
+	// get params
+	var params = mux.Vars(r)
+
+	err := logic.DeleteDNS(params["domain"], params["network"])
+
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+	entrytext := params["domain"] + "." + params["network"]
+	logger.Log(1, "deleted dns entry: ", entrytext)
+	err = logic.SetDNS()
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+	json.NewEncoder(w).Encode(entrytext + " deleted.")
+}
+
+// CreateDNS - creates a DNS entry
+func CreateDNS(entry models.DNSEntry) (models.DNSEntry, error) {
+
+	data, err := json.Marshal(&entry)
+	if err != nil {
+		return models.DNSEntry{}, err
+	}
+	key, err := logic.GetRecordKey(entry.Name, entry.Network)
+	if err != nil {
+		return models.DNSEntry{}, err
+	}
+	err = database.Insert(key, string(data), database.DNS_TABLE_NAME)
+
+	return entry, err
+}
+
+// GetDNSEntry - gets a DNS entry
+func GetDNSEntry(domain string, network string) (models.DNSEntry, error) {
+	var entry models.DNSEntry
+	key, err := logic.GetRecordKey(domain, network)
+	if err != nil {
+		return entry, err
+	}
+	record, err := database.FetchRecord(database.DNS_TABLE_NAME, key)
+	if err != nil {
+		return entry, err
+	}
+	err = json.Unmarshal([]byte(record), &entry)
+	return entry, err
+}
+
+func pushDNS(w http.ResponseWriter, r *http.Request) {
+	// Set header
+	w.Header().Set("Content-Type", "application/json")
+
+	err := logic.SetDNS()
+
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+	logger.Log(1, r.Header.Get("user"), "pushed DNS updates to nameserver")
+	json.NewEncoder(w).Encode("DNS Pushed to CoreDNS")
+}

+ 0 - 450
controllers/dnsHttpController.go

@@ -1,450 +0,0 @@
-package controller
-
-import (
-	"encoding/json"
-	"net/http"
-	"strings"
-
-	"github.com/go-playground/validator/v10"
-	"github.com/gorilla/mux"
-	"github.com/gravitl/netmaker/database"
-	"github.com/gravitl/netmaker/functions"
-	"github.com/gravitl/netmaker/logic"
-	"github.com/gravitl/netmaker/models"
-)
-
-func dnsHandlers(r *mux.Router) {
-
-	r.HandleFunc("/api/dns", securityCheckDNS(true, true, http.HandlerFunc(getAllDNS))).Methods("GET")
-	r.HandleFunc("/api/dns/adm/{network}/nodes", securityCheckDNS(false, true, http.HandlerFunc(getNodeDNS))).Methods("GET")
-	r.HandleFunc("/api/dns/adm/{network}/custom", securityCheckDNS(false, true, http.HandlerFunc(getCustomDNS))).Methods("GET")
-	r.HandleFunc("/api/dns/adm/{network}", securityCheckDNS(false, true, http.HandlerFunc(getDNS))).Methods("GET")
-	r.HandleFunc("/api/dns/{network}", securityCheckDNS(false, false, http.HandlerFunc(createDNS))).Methods("POST")
-	r.HandleFunc("/api/dns/adm/pushdns", securityCheckDNS(false, false, http.HandlerFunc(pushDNS))).Methods("POST")
-	r.HandleFunc("/api/dns/{network}/{domain}", securityCheckDNS(false, false, http.HandlerFunc(deleteDNS))).Methods("DELETE")
-	r.HandleFunc("/api/dns/{network}/{domain}", securityCheckDNS(false, false, http.HandlerFunc(updateDNS))).Methods("PUT")
-}
-
-//Gets all nodes associated with network, including pending nodes
-func getNodeDNS(w http.ResponseWriter, r *http.Request) {
-
-	w.Header().Set("Content-Type", "application/json")
-
-	var dns []models.DNSEntry
-	var params = mux.Vars(r)
-
-	dns, err := GetNodeDNS(params["network"])
-	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "internal"))
-		return
-	}
-
-	//Returns all the nodes in JSON format
-	w.WriteHeader(http.StatusOK)
-	json.NewEncoder(w).Encode(dns)
-}
-
-//Gets all nodes associated with network, including pending nodes
-func getAllDNS(w http.ResponseWriter, r *http.Request) {
-	w.Header().Set("Content-Type", "application/json")
-	dns, err := GetAllDNS()
-	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "internal"))
-		return
-	}
-	//Returns all the nodes in JSON format
-	w.WriteHeader(http.StatusOK)
-	json.NewEncoder(w).Encode(dns)
-}
-
-// GetAllDNS - gets all dns entries
-func GetAllDNS() ([]models.DNSEntry, error) {
-	var dns []models.DNSEntry
-	networks, err := logic.GetNetworks()
-	if err != nil && !database.IsEmptyRecord(err) {
-		return []models.DNSEntry{}, err
-	}
-	for _, net := range networks {
-		netdns, err := logic.GetDNS(net.NetID)
-		if err != nil {
-			return []models.DNSEntry{}, nil
-		}
-		dns = append(dns, netdns...)
-	}
-	return dns, nil
-}
-
-// GetNodeDNS - gets node dns
-func GetNodeDNS(network string) ([]models.DNSEntry, error) {
-
-	var dns []models.DNSEntry
-
-	collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
-	if err != nil {
-		return dns, err
-	}
-
-	for _, value := range collection {
-		var entry models.DNSEntry
-		var node models.Node
-		if err = json.Unmarshal([]byte(value), &node); err != nil {
-			continue
-		}
-		if err = json.Unmarshal([]byte(value), &entry); node.Network == network && err == nil {
-			dns = append(dns, entry)
-		}
-	}
-
-	return dns, nil
-}
-
-//Gets all nodes associated with network, including pending nodes
-func getCustomDNS(w http.ResponseWriter, r *http.Request) {
-
-	w.Header().Set("Content-Type", "application/json")
-
-	var dns []models.DNSEntry
-	var params = mux.Vars(r)
-
-	dns, err := logic.GetCustomDNS(params["network"])
-	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "internal"))
-		return
-	}
-
-	//Returns all the nodes in JSON format
-	w.WriteHeader(http.StatusOK)
-	json.NewEncoder(w).Encode(dns)
-}
-
-// GetDNSEntryNum - gets which entry the dns was
-func GetDNSEntryNum(domain string, network string) (int, error) {
-
-	num := 0
-
-	entries, err := logic.GetDNS(network)
-	if err != nil {
-		return 0, err
-	}
-
-	for i := 0; i < len(entries); i++ {
-
-		if domain == entries[i].Name {
-			num++
-		}
-	}
-
-	return num, nil
-}
-
-// Gets all nodes associated with network, including pending nodes
-func getDNS(w http.ResponseWriter, r *http.Request) {
-
-	w.Header().Set("Content-Type", "application/json")
-
-	var dns []models.DNSEntry
-	var params = mux.Vars(r)
-
-	dns, err := logic.GetDNS(params["network"])
-	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "internal"))
-		return
-	}
-	w.WriteHeader(http.StatusOK)
-	json.NewEncoder(w).Encode(dns)
-}
-
-func createDNS(w http.ResponseWriter, r *http.Request) {
-	w.Header().Set("Content-Type", "application/json")
-
-	var entry models.DNSEntry
-	var params = mux.Vars(r)
-
-	//get node from body of request
-	_ = json.NewDecoder(r.Body).Decode(&entry)
-	entry.Network = params["network"]
-
-	err := ValidateDNSCreate(entry)
-	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "badrequest"))
-		return
-	}
-
-	entry, err = CreateDNS(entry)
-	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "internal"))
-		return
-	}
-	err = logic.SetDNS()
-	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "internal"))
-		return
-	}
-	w.WriteHeader(http.StatusOK)
-	json.NewEncoder(w).Encode(entry)
-}
-
-func updateDNS(w http.ResponseWriter, r *http.Request) {
-	w.Header().Set("Content-Type", "application/json")
-
-	var params = mux.Vars(r)
-
-	var entry models.DNSEntry
-
-	//start here
-	entry, err := GetDNSEntry(params["domain"], params["network"])
-	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "badrequest"))
-		return
-	}
-
-	var dnschange models.DNSEntry
-
-	// we decode our body request params
-	err = json.NewDecoder(r.Body).Decode(&dnschange)
-	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "badrequest"))
-		return
-	}
-	// fill in any missing fields
-	if dnschange.Name == "" {
-		dnschange.Name = entry.Name
-	}
-	if dnschange.Network == "" {
-		dnschange.Network = entry.Network
-	}
-	if dnschange.Address == "" {
-		dnschange.Address = entry.Address
-	}
-
-	err = ValidateDNSUpdate(dnschange, entry)
-
-	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "badrequest"))
-		return
-	}
-
-	entry, err = UpdateDNS(dnschange, entry)
-
-	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "badrequest"))
-		return
-	}
-	err = logic.SetDNS()
-	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "internal"))
-		return
-	}
-	json.NewEncoder(w).Encode(entry)
-}
-
-func deleteDNS(w http.ResponseWriter, r *http.Request) {
-	// Set header
-	w.Header().Set("Content-Type", "application/json")
-
-	// get params
-	var params = mux.Vars(r)
-
-	err := DeleteDNS(params["domain"], params["network"])
-
-	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "internal"))
-		return
-	}
-	entrytext := params["domain"] + "." + params["network"]
-	functions.PrintUserLog(models.NODE_SERVER_NAME, "deleted dns entry: "+entrytext, 1)
-	err = logic.SetDNS()
-	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "internal"))
-		return
-	}
-	json.NewEncoder(w).Encode(entrytext + " deleted.")
-}
-
-// CreateDNS - creates a DNS entry
-func CreateDNS(entry models.DNSEntry) (models.DNSEntry, error) {
-
-	data, err := json.Marshal(&entry)
-	if err != nil {
-		return models.DNSEntry{}, err
-	}
-	key, err := logic.GetRecordKey(entry.Name, entry.Network)
-	if err != nil {
-		return models.DNSEntry{}, err
-	}
-	err = database.Insert(key, string(data), database.DNS_TABLE_NAME)
-
-	return entry, err
-}
-
-// GetDNSEntry - gets a DNS entry
-func GetDNSEntry(domain string, network string) (models.DNSEntry, error) {
-	var entry models.DNSEntry
-	key, err := logic.GetRecordKey(domain, network)
-	if err != nil {
-		return entry, err
-	}
-	record, err := database.FetchRecord(database.DNS_TABLE_NAME, key)
-	if err != nil {
-		return entry, err
-	}
-	err = json.Unmarshal([]byte(record), &entry)
-	return entry, err
-}
-
-// UpdateDNS - updates DNS entry
-func UpdateDNS(dnschange models.DNSEntry, entry models.DNSEntry) (models.DNSEntry, error) {
-
-	key, err := logic.GetRecordKey(entry.Name, entry.Network)
-	if err != nil {
-		return entry, err
-	}
-	if dnschange.Name != "" {
-		entry.Name = dnschange.Name
-	}
-	if dnschange.Address != "" {
-		entry.Address = dnschange.Address
-	}
-	newkey, err := logic.GetRecordKey(entry.Name, entry.Network)
-
-	err = database.DeleteRecord(database.DNS_TABLE_NAME, key)
-	if err != nil {
-		return entry, err
-	}
-
-	data, err := json.Marshal(&entry)
-	err = database.Insert(newkey, string(data), database.DNS_TABLE_NAME)
-	return entry, err
-}
-
-// DeleteDNS - deletes a DNS entry
-func DeleteDNS(domain string, network string) error {
-	key, err := logic.GetRecordKey(domain, network)
-	if err != nil {
-		return err
-	}
-	err = database.DeleteRecord(database.DNS_TABLE_NAME, key)
-	return err
-}
-
-func pushDNS(w http.ResponseWriter, r *http.Request) {
-	// Set header
-	w.Header().Set("Content-Type", "application/json")
-
-	err := logic.SetDNS()
-
-	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "internal"))
-		return
-	}
-	functions.PrintUserLog(r.Header.Get("user"), "pushed DNS updates to nameserver", 1)
-	json.NewEncoder(w).Encode("DNS Pushed to CoreDNS")
-}
-
-// ValidateDNSCreate - checks if an entry is valid
-func ValidateDNSCreate(entry models.DNSEntry) error {
-
-	v := validator.New()
-
-	_ = v.RegisterValidation("name_unique", func(fl validator.FieldLevel) bool {
-		num, err := GetDNSEntryNum(entry.Name, entry.Network)
-		return err == nil && num == 0
-	})
-
-	_ = v.RegisterValidation("network_exists", func(fl validator.FieldLevel) bool {
-		_, err := logic.GetParentNetwork(entry.Network)
-		return err == nil
-	})
-
-	err := v.Struct(entry)
-	if err != nil {
-		for _, e := range err.(validator.ValidationErrors) {
-			functions.PrintUserLog("", e.Error(), 1)
-		}
-	}
-	return err
-}
-
-// ValidateDNSUpdate - validates a DNS update
-func ValidateDNSUpdate(change models.DNSEntry, entry models.DNSEntry) error {
-
-	v := validator.New()
-
-	_ = v.RegisterValidation("name_unique", func(fl validator.FieldLevel) bool {
-		//if name & net not changing name we are good
-		if change.Name == entry.Name && change.Network == entry.Network {
-			return true
-		}
-		num, err := GetDNSEntryNum(change.Name, change.Network)
-		return err == nil && num == 0
-	})
-	_ = v.RegisterValidation("network_exists", func(fl validator.FieldLevel) bool {
-		_, err := logic.GetParentNetwork(change.Network)
-		if err != nil {
-			functions.PrintUserLog("", err.Error(), 0)
-		}
-		return err == nil
-	})
-
-	//	_ = v.RegisterValidation("name_valid", func(fl validator.FieldLevel) bool {
-	//		isvalid := functions.NameInDNSCharSet(entry.Name)
-	//		notEmptyCheck := entry.Name != ""
-	//		return isvalid && notEmptyCheck
-	//	})
-	//
-	//	_ = v.RegisterValidation("address_valid", func(fl validator.FieldLevel) bool {
-	//		isValid := true
-	//		if entry.Address != "" {
-	//			isValid = functions.IsIpNet(entry.Address)
-	//		}
-	//		return isValid
-	//	})
-
-	err := v.Struct(change)
-
-	if err != nil {
-		for _, e := range err.(validator.ValidationErrors) {
-			functions.PrintUserLog("", e.Error(), 1)
-		}
-	}
-	return err
-}
-
-//Security check DNS is middleware for every DNS function and just checks to make sure that its the master or dns token calling
-//Only admin should have access to all these network-level actions
-//DNS token should have access to only read functions
-func securityCheckDNS(reqAdmin bool, allowDNSToken bool, next http.Handler) http.HandlerFunc {
-	return func(w http.ResponseWriter, r *http.Request) {
-		var errorResponse = models.ErrorResponse{
-			Code: http.StatusUnauthorized, Message: "W1R3: It's not you it's me.",
-		}
-
-		var params = mux.Vars(r)
-		bearerToken := r.Header.Get("Authorization")
-		if allowDNSToken && authenticateDNSToken(bearerToken) {
-			r.Header.Set("user", "nameserver")
-			networks, _ := json.Marshal([]string{ALL_NETWORK_ACCESS})
-			r.Header.Set("networks", string(networks))
-			next.ServeHTTP(w, r)
-		} else {
-			err, networks, username := SecurityCheck(reqAdmin, params["networkname"], bearerToken)
-			if err != nil {
-				if strings.Contains(err.Error(), "does not exist") {
-					errorResponse.Code = http.StatusNotFound
-				}
-				errorResponse.Message = err.Error()
-				returnErrorResponse(w, r, errorResponse)
-				return
-			}
-			networksJson, err := json.Marshal(&networks)
-			if err != nil {
-				errorResponse.Message = err.Error()
-				returnErrorResponse(w, r, errorResponse)
-				return
-			}
-			r.Header.Set("user", username)
-			r.Header.Set("networks", string(networksJson))
-			next.ServeHTTP(w, r)
-		}
-	}
-}

+ 58 - 57
controllers/dnsHttpController_test.go → controllers/dns_test.go

@@ -17,21 +17,21 @@ func TestGetAllDNS(t *testing.T) {
 	deleteAllNetworks()
 	deleteAllNetworks()
 	createNet()
 	createNet()
 	t.Run("NoEntries", func(t *testing.T) {
 	t.Run("NoEntries", func(t *testing.T) {
-		entries, err := GetAllDNS()
+		entries, err := logic.GetAllDNS()
 		assert.Nil(t, err)
 		assert.Nil(t, err)
 		assert.Equal(t, []models.DNSEntry(nil), entries)
 		assert.Equal(t, []models.DNSEntry(nil), entries)
 	})
 	})
 	t.Run("OneEntry", func(t *testing.T) {
 	t.Run("OneEntry", func(t *testing.T) {
 		entry := models.DNSEntry{"10.0.0.3", "newhost", "skynet"}
 		entry := models.DNSEntry{"10.0.0.3", "newhost", "skynet"}
 		CreateDNS(entry)
 		CreateDNS(entry)
-		entries, err := GetAllDNS()
+		entries, err := logic.GetAllDNS()
 		assert.Nil(t, err)
 		assert.Nil(t, err)
 		assert.Equal(t, 1, len(entries))
 		assert.Equal(t, 1, len(entries))
 	})
 	})
 	t.Run("MultipleEntry", func(t *testing.T) {
 	t.Run("MultipleEntry", func(t *testing.T) {
 		entry := models.DNSEntry{"10.0.0.7", "anotherhost", "skynet"}
 		entry := models.DNSEntry{"10.0.0.7", "anotherhost", "skynet"}
 		CreateDNS(entry)
 		CreateDNS(entry)
-		entries, err := GetAllDNS()
+		entries, err := logic.GetAllDNS()
 		assert.Nil(t, err)
 		assert.Nil(t, err)
 		assert.Equal(t, 2, len(entries))
 		assert.Equal(t, 2, len(entries))
 	})
 	})
@@ -43,21 +43,21 @@ func TestGetNodeDNS(t *testing.T) {
 	deleteAllNetworks()
 	deleteAllNetworks()
 	createNet()
 	createNet()
 	t.Run("NoNodes", func(t *testing.T) {
 	t.Run("NoNodes", func(t *testing.T) {
-		dns, err := GetNodeDNS("skynet")
+		dns, err := logic.GetNodeDNS("skynet")
 		assert.EqualError(t, err, "could not find any records")
 		assert.EqualError(t, err, "could not find any records")
 		assert.Equal(t, []models.DNSEntry(nil), dns)
 		assert.Equal(t, []models.DNSEntry(nil), dns)
 	})
 	})
 	t.Run("NodeExists", func(t *testing.T) {
 	t.Run("NodeExists", func(t *testing.T) {
 		createTestNode()
 		createTestNode()
-		dns, err := GetNodeDNS("skynet")
+		dns, err := logic.GetNodeDNS("skynet")
 		assert.Nil(t, err)
 		assert.Nil(t, err)
 		assert.Equal(t, "10.0.0.1", dns[0].Address)
 		assert.Equal(t, "10.0.0.1", dns[0].Address)
 	})
 	})
 	t.Run("MultipleNodes", func(t *testing.T) {
 	t.Run("MultipleNodes", func(t *testing.T) {
-		createnode := models.Node{PublicKey: "DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34=", Endpoint: "10.100.100.3", MacAddress: "01:02:03:04:05:07", Password: "password", Network: "skynet"}
-		_, err := logic.CreateNode(createnode, "skynet")
+		createnode := &models.Node{PublicKey: "DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34=", Endpoint: "10.100.100.3", MacAddress: "01:02:03:04:05:07", Password: "password", Network: "skynet"}
+		err := logic.CreateNode(createnode)
 		assert.Nil(t, err)
 		assert.Nil(t, err)
-		dns, err := GetNodeDNS("skynet")
+		dns, err := logic.GetNodeDNS("skynet")
 		assert.Nil(t, err)
 		assert.Nil(t, err)
 		assert.Equal(t, 2, len(dns))
 		assert.Equal(t, 2, len(dns))
 	})
 	})
@@ -105,7 +105,7 @@ func TestGetDNSEntryNum(t *testing.T) {
 	deleteAllNetworks()
 	deleteAllNetworks()
 	createNet()
 	createNet()
 	t.Run("NoNodes", func(t *testing.T) {
 	t.Run("NoNodes", func(t *testing.T) {
-		num, err := GetDNSEntryNum("myhost", "skynet")
+		num, err := logic.GetDNSEntryNum("myhost", "skynet")
 		assert.Nil(t, err)
 		assert.Nil(t, err)
 		assert.Equal(t, 0, num)
 		assert.Equal(t, 0, num)
 	})
 	})
@@ -113,7 +113,7 @@ func TestGetDNSEntryNum(t *testing.T) {
 		entry := models.DNSEntry{"10.0.0.2", "newhost", "skynet"}
 		entry := models.DNSEntry{"10.0.0.2", "newhost", "skynet"}
 		_, err := CreateDNS(entry)
 		_, err := CreateDNS(entry)
 		assert.Nil(t, err)
 		assert.Nil(t, err)
-		num, err := GetDNSEntryNum("newhost", "skynet")
+		num, err := logic.GetDNSEntryNum("newhost", "skynet")
 		assert.Nil(t, err)
 		assert.Nil(t, err)
 		assert.Equal(t, 1, num)
 		assert.Equal(t, 1, num)
 	})
 	})
@@ -248,33 +248,34 @@ func TestGetDNSEntry(t *testing.T) {
 		assert.Equal(t, models.DNSEntry{}, entry)
 		assert.Equal(t, models.DNSEntry{}, entry)
 	})
 	})
 }
 }
-func TestUpdateDNS(t *testing.T) {
-	var newentry models.DNSEntry
-	database.InitializeDatabase()
-	deleteAllDNS(t)
-	deleteAllNetworks()
-	createNet()
-	entry := models.DNSEntry{"10.0.0.2", "newhost", "skynet"}
-	CreateDNS(entry)
-	t.Run("change address", func(t *testing.T) {
-		newentry.Address = "10.0.0.75"
-		updated, err := UpdateDNS(newentry, entry)
-		assert.Nil(t, err)
-		assert.Equal(t, newentry.Address, updated.Address)
-	})
-	t.Run("change name", func(t *testing.T) {
-		newentry.Name = "newname"
-		updated, err := UpdateDNS(newentry, entry)
-		assert.Nil(t, err)
-		assert.Equal(t, newentry.Name, updated.Name)
-	})
-	t.Run("change network", func(t *testing.T) {
-		newentry.Network = "wirecat"
-		updated, err := UpdateDNS(newentry, entry)
-		assert.Nil(t, err)
-		assert.NotEqual(t, newentry.Network, updated.Network)
-	})
-}
+
+// func TestUpdateDNS(t *testing.T) {
+// 	var newentry models.DNSEntry
+// 	database.InitializeDatabase()
+// 	deleteAllDNS(t)
+// 	deleteAllNetworks()
+// 	createNet()
+// 	entry := models.DNSEntry{"10.0.0.2", "newhost", "skynet"}
+// 	CreateDNS(entry)
+// 	t.Run("change address", func(t *testing.T) {
+// 		newentry.Address = "10.0.0.75"
+// 		updated, err := UpdateDNS(newentry, entry)
+// 		assert.Nil(t, err)
+// 		assert.Equal(t, newentry.Address, updated.Address)
+// 	})
+// 	t.Run("change name", func(t *testing.T) {
+// 		newentry.Name = "newname"
+// 		updated, err := UpdateDNS(newentry, entry)
+// 		assert.Nil(t, err)
+// 		assert.Equal(t, newentry.Name, updated.Name)
+// 	})
+// 	t.Run("change network", func(t *testing.T) {
+// 		newentry.Network = "wirecat"
+// 		updated, err := UpdateDNS(newentry, entry)
+// 		assert.Nil(t, err)
+// 		assert.NotEqual(t, newentry.Network, updated.Network)
+// 	})
+// }
 func TestDeleteDNS(t *testing.T) {
 func TestDeleteDNS(t *testing.T) {
 	database.InitializeDatabase()
 	database.InitializeDatabase()
 	deleteAllDNS(t)
 	deleteAllDNS(t)
@@ -283,16 +284,16 @@ func TestDeleteDNS(t *testing.T) {
 	entry := models.DNSEntry{"10.0.0.2", "newhost", "skynet"}
 	entry := models.DNSEntry{"10.0.0.2", "newhost", "skynet"}
 	CreateDNS(entry)
 	CreateDNS(entry)
 	t.Run("EntryExists", func(t *testing.T) {
 	t.Run("EntryExists", func(t *testing.T) {
-		err := DeleteDNS("newhost", "skynet")
+		err := logic.DeleteDNS("newhost", "skynet")
 		assert.Nil(t, err)
 		assert.Nil(t, err)
 	})
 	})
 	t.Run("NodeExists", func(t *testing.T) {
 	t.Run("NodeExists", func(t *testing.T) {
-		err := DeleteDNS("myhost", "skynet")
+		err := logic.DeleteDNS("myhost", "skynet")
 		assert.Nil(t, err)
 		assert.Nil(t, err)
 	})
 	})
 
 
 	t.Run("NoEntries", func(t *testing.T) {
 	t.Run("NoEntries", func(t *testing.T) {
-		err := DeleteDNS("myhost", "skynet")
+		err := logic.DeleteDNS("myhost", "skynet")
 		assert.Nil(t, err)
 		assert.Nil(t, err)
 	})
 	})
 }
 }
@@ -305,34 +306,34 @@ func TestValidateDNSUpdate(t *testing.T) {
 	entry := models.DNSEntry{"10.0.0.2", "myhost", "skynet"}
 	entry := models.DNSEntry{"10.0.0.2", "myhost", "skynet"}
 	t.Run("BadNetwork", func(t *testing.T) {
 	t.Run("BadNetwork", func(t *testing.T) {
 		change := models.DNSEntry{"10.0.0.2", "myhost", "badnet"}
 		change := models.DNSEntry{"10.0.0.2", "myhost", "badnet"}
-		err := ValidateDNSUpdate(change, entry)
+		err := logic.ValidateDNSUpdate(change, entry)
 		assert.NotNil(t, err)
 		assert.NotNil(t, err)
 		assert.Contains(t, err.Error(), "Field validation for 'Network' failed on the 'network_exists' tag")
 		assert.Contains(t, err.Error(), "Field validation for 'Network' failed on the 'network_exists' tag")
 	})
 	})
 	t.Run("EmptyNetwork", func(t *testing.T) {
 	t.Run("EmptyNetwork", func(t *testing.T) {
 		//this can't actually happen as change.Network is populated if is blank
 		//this can't actually happen as change.Network is populated if is blank
 		change := models.DNSEntry{"10.0.0.2", "myhost", ""}
 		change := models.DNSEntry{"10.0.0.2", "myhost", ""}
-		err := ValidateDNSUpdate(change, entry)
+		err := logic.ValidateDNSUpdate(change, entry)
 		assert.NotNil(t, err)
 		assert.NotNil(t, err)
 		assert.Contains(t, err.Error(), "Field validation for 'Network' failed on the 'network_exists' tag")
 		assert.Contains(t, err.Error(), "Field validation for 'Network' failed on the 'network_exists' tag")
 	})
 	})
 	t.Run("EmptyAddress", func(t *testing.T) {
 	t.Run("EmptyAddress", func(t *testing.T) {
 		//this can't actually happen as change.Address is populated if is blank
 		//this can't actually happen as change.Address is populated if is blank
 		change := models.DNSEntry{"", "myhost", "skynet"}
 		change := models.DNSEntry{"", "myhost", "skynet"}
-		err := ValidateDNSUpdate(change, entry)
+		err := logic.ValidateDNSUpdate(change, entry)
 		assert.NotNil(t, err)
 		assert.NotNil(t, err)
 		assert.Contains(t, err.Error(), "Field validation for 'Address' failed on the 'required' tag")
 		assert.Contains(t, err.Error(), "Field validation for 'Address' failed on the 'required' tag")
 	})
 	})
 	t.Run("BadAddress", func(t *testing.T) {
 	t.Run("BadAddress", func(t *testing.T) {
 		change := models.DNSEntry{"10.0.256.1", "myhost", "skynet"}
 		change := models.DNSEntry{"10.0.256.1", "myhost", "skynet"}
-		err := ValidateDNSUpdate(change, entry)
+		err := logic.ValidateDNSUpdate(change, entry)
 		assert.NotNil(t, err)
 		assert.NotNil(t, err)
 		assert.Contains(t, err.Error(), "Field validation for 'Address' failed on the 'ip' tag")
 		assert.Contains(t, err.Error(), "Field validation for 'Address' failed on the 'ip' tag")
 	})
 	})
 	t.Run("EmptyName", func(t *testing.T) {
 	t.Run("EmptyName", func(t *testing.T) {
 		//this can't actually happen as change.Name is populated if is blank
 		//this can't actually happen as change.Name is populated if is blank
 		change := models.DNSEntry{"10.0.0.2", "", "skynet"}
 		change := models.DNSEntry{"10.0.0.2", "", "skynet"}
-		err := ValidateDNSUpdate(change, entry)
+		err := logic.ValidateDNSUpdate(change, entry)
 		assert.NotNil(t, err)
 		assert.NotNil(t, err)
 		assert.Contains(t, err.Error(), "Field validation for 'Name' failed on the 'required' tag")
 		assert.Contains(t, err.Error(), "Field validation for 'Name' failed on the 'required' tag")
 	})
 	})
@@ -342,7 +343,7 @@ func TestValidateDNSUpdate(t *testing.T) {
 			name = name + "a"
 			name = name + "a"
 		}
 		}
 		change := models.DNSEntry{"10.0.0.2", name, "skynet"}
 		change := models.DNSEntry{"10.0.0.2", name, "skynet"}
-		err := ValidateDNSUpdate(change, entry)
+		err := logic.ValidateDNSUpdate(change, entry)
 		assert.NotNil(t, err)
 		assert.NotNil(t, err)
 		assert.Contains(t, err.Error(), "Field validation for 'Name' failed on the 'max' tag")
 		assert.Contains(t, err.Error(), "Field validation for 'Name' failed on the 'max' tag")
 	})
 	})
@@ -350,39 +351,39 @@ func TestValidateDNSUpdate(t *testing.T) {
 		change := models.DNSEntry{"10.0.0.2", "myhost", "wirecat"}
 		change := models.DNSEntry{"10.0.0.2", "myhost", "wirecat"}
 		CreateDNS(entry)
 		CreateDNS(entry)
 		CreateDNS(change)
 		CreateDNS(change)
-		err := ValidateDNSUpdate(change, entry)
+		err := logic.ValidateDNSUpdate(change, entry)
 		assert.NotNil(t, err)
 		assert.NotNil(t, err)
 		assert.Contains(t, err.Error(), "Field validation for 'Name' failed on the 'name_unique' tag")
 		assert.Contains(t, err.Error(), "Field validation for 'Name' failed on the 'name_unique' tag")
 		//cleanup
 		//cleanup
-		err = DeleteDNS("myhost", "wirecat")
+		err = logic.DeleteDNS("myhost", "wirecat")
 		assert.Nil(t, err)
 		assert.Nil(t, err)
 	})
 	})
 
 
 }
 }
 func TestValidateDNSCreate(t *testing.T) {
 func TestValidateDNSCreate(t *testing.T) {
 	database.InitializeDatabase()
 	database.InitializeDatabase()
-	_ = DeleteDNS("mynode", "skynet")
+	_ = logic.DeleteDNS("mynode", "skynet")
 	t.Run("NoNetwork", func(t *testing.T) {
 	t.Run("NoNetwork", func(t *testing.T) {
 		entry := models.DNSEntry{"10.0.0.2", "myhost", "badnet"}
 		entry := models.DNSEntry{"10.0.0.2", "myhost", "badnet"}
-		err := ValidateDNSCreate(entry)
+		err := logic.ValidateDNSCreate(entry)
 		assert.NotNil(t, err)
 		assert.NotNil(t, err)
 		assert.Contains(t, err.Error(), "Field validation for 'Network' failed on the 'network_exists' tag")
 		assert.Contains(t, err.Error(), "Field validation for 'Network' failed on the 'network_exists' tag")
 	})
 	})
 	t.Run("EmptyAddress", func(t *testing.T) {
 	t.Run("EmptyAddress", func(t *testing.T) {
 		entry := models.DNSEntry{"", "myhost", "skynet"}
 		entry := models.DNSEntry{"", "myhost", "skynet"}
-		err := ValidateDNSCreate(entry)
+		err := logic.ValidateDNSCreate(entry)
 		assert.NotNil(t, err)
 		assert.NotNil(t, err)
 		assert.Contains(t, err.Error(), "Field validation for 'Address' failed on the 'required' tag")
 		assert.Contains(t, err.Error(), "Field validation for 'Address' failed on the 'required' tag")
 	})
 	})
 	t.Run("BadAddress", func(t *testing.T) {
 	t.Run("BadAddress", func(t *testing.T) {
 		entry := models.DNSEntry{"10.0.256.1", "myhost", "skynet"}
 		entry := models.DNSEntry{"10.0.256.1", "myhost", "skynet"}
-		err := ValidateDNSCreate(entry)
+		err := logic.ValidateDNSCreate(entry)
 		assert.NotNil(t, err)
 		assert.NotNil(t, err)
 		assert.Contains(t, err.Error(), "Field validation for 'Address' failed on the 'ip' tag")
 		assert.Contains(t, err.Error(), "Field validation for 'Address' failed on the 'ip' tag")
 	})
 	})
 	t.Run("EmptyName", func(t *testing.T) {
 	t.Run("EmptyName", func(t *testing.T) {
 		entry := models.DNSEntry{"10.0.0.2", "", "skynet"}
 		entry := models.DNSEntry{"10.0.0.2", "", "skynet"}
-		err := ValidateDNSCreate(entry)
+		err := logic.ValidateDNSCreate(entry)
 		assert.NotNil(t, err)
 		assert.NotNil(t, err)
 		assert.Contains(t, err.Error(), "Field validation for 'Name' failed on the 'required' tag")
 		assert.Contains(t, err.Error(), "Field validation for 'Name' failed on the 'required' tag")
 	})
 	})
@@ -392,24 +393,24 @@ func TestValidateDNSCreate(t *testing.T) {
 			name = name + "a"
 			name = name + "a"
 		}
 		}
 		entry := models.DNSEntry{"10.0.0.2", name, "skynet"}
 		entry := models.DNSEntry{"10.0.0.2", name, "skynet"}
-		err := ValidateDNSCreate(entry)
+		err := logic.ValidateDNSCreate(entry)
 		assert.NotNil(t, err)
 		assert.NotNil(t, err)
 		assert.Contains(t, err.Error(), "Field validation for 'Name' failed on the 'max' tag")
 		assert.Contains(t, err.Error(), "Field validation for 'Name' failed on the 'max' tag")
 	})
 	})
 	t.Run("NameUnique", func(t *testing.T) {
 	t.Run("NameUnique", func(t *testing.T) {
 		entry := models.DNSEntry{"10.0.0.2", "myhost", "skynet"}
 		entry := models.DNSEntry{"10.0.0.2", "myhost", "skynet"}
 		_, _ = CreateDNS(entry)
 		_, _ = CreateDNS(entry)
-		err := ValidateDNSCreate(entry)
+		err := logic.ValidateDNSCreate(entry)
 		assert.NotNil(t, err)
 		assert.NotNil(t, err)
 		assert.Contains(t, err.Error(), "Field validation for 'Name' failed on the 'name_unique' tag")
 		assert.Contains(t, err.Error(), "Field validation for 'Name' failed on the 'name_unique' tag")
 	})
 	})
 }
 }
 
 
 func deleteAllDNS(t *testing.T) {
 func deleteAllDNS(t *testing.T) {
-	dns, err := GetAllDNS()
+	dns, err := logic.GetAllDNS()
 	assert.Nil(t, err)
 	assert.Nil(t, err)
 	for _, record := range dns {
 	for _, record := range dns {
-		err := DeleteDNS(record.Name, record.Network)
+		err := logic.DeleteDNS(record.Name, record.Network)
 		assert.Nil(t, err)
 		assert.Nil(t, err)
 	}
 	}
 }
 }

+ 14 - 133
controllers/extClientHttpController.go → controllers/ext_client.go

@@ -7,15 +7,14 @@ import (
 	"io"
 	"io"
 	"net/http"
 	"net/http"
 	"strconv"
 	"strconv"
-	"time"
 
 
 	"github.com/gorilla/mux"
 	"github.com/gorilla/mux"
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/functions"
 	"github.com/gravitl/netmaker/functions"
+	"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/skip2/go-qrcode"
 	"github.com/skip2/go-qrcode"
-	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 )
 )
 
 
 func extClientHandlers(r *mux.Router) {
 func extClientHandlers(r *mux.Router) {
@@ -44,7 +43,7 @@ func getNetworkExtClients(w http.ResponseWriter, r *http.Request) {
 
 
 	var extclients []models.ExtClient
 	var extclients []models.ExtClient
 	var params = mux.Vars(r)
 	var params = mux.Vars(r)
-	extclients, err := GetNetworkExtClients(params["network"])
+	extclients, err := logic.GetNetworkExtClients(params["network"])
 	if err != nil {
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 		return
@@ -55,27 +54,6 @@ func getNetworkExtClients(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(extclients)
 	json.NewEncoder(w).Encode(extclients)
 }
 }
 
 
-// GetNetworkExtClients - gets the ext clients of given network
-func GetNetworkExtClients(network string) ([]models.ExtClient, error) {
-	var extclients []models.ExtClient
-
-	records, err := database.FetchRecords(database.EXT_CLIENT_TABLE_NAME)
-	if err != nil {
-		return extclients, err
-	}
-	for _, value := range records {
-		var extclient models.ExtClient
-		err = json.Unmarshal([]byte(value), &extclient)
-		if err != nil {
-			continue
-		}
-		if extclient.Network == network {
-			extclients = append(extclients, extclient)
-		}
-	}
-	return extclients, err
-}
-
 //A separate function to get all extclients, not just extclients for a particular network.
 //A separate function to get all extclients, not just extclients for a particular network.
 //Not quite sure if this is necessary. Probably necessary based on front end but may want to review after iteration 1 if it's being used or not
 //Not quite sure if this is necessary. Probably necessary based on front end but may want to review after iteration 1 if it's being used or not
 func getAllExtClients(w http.ResponseWriter, r *http.Request) {
 func getAllExtClients(w http.ResponseWriter, r *http.Request) {
@@ -99,7 +77,7 @@ func getAllExtClients(w http.ResponseWriter, r *http.Request) {
 		}
 		}
 	} else {
 	} else {
 		for _, network := range networksSlice {
 		for _, network := range networksSlice {
-			extclients, err := GetNetworkExtClients(network)
+			extclients, err := logic.GetNetworkExtClients(network)
 			if err == nil {
 			if err == nil {
 				clients = append(clients, extclients...)
 				clients = append(clients, extclients...)
 			}
 			}
@@ -120,7 +98,7 @@ func getExtClient(w http.ResponseWriter, r *http.Request) {
 
 
 	clientid := params["clientid"]
 	clientid := params["clientid"]
 	network := params["network"]
 	network := params["network"]
-	client, err := GetExtClient(clientid, network)
+	client, err := logic.GetExtClient(clientid, network)
 	if err != nil {
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 		return
@@ -130,22 +108,6 @@ func getExtClient(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(client)
 	json.NewEncoder(w).Encode(client)
 }
 }
 
 
-// GetExtClient - gets a single ext client on a network
-func GetExtClient(clientid string, network string) (models.ExtClient, error) {
-	var extclient models.ExtClient
-	key, err := logic.GetRecordKey(clientid, network)
-	if err != nil {
-		return extclient, err
-	}
-	data, err := database.FetchRecord(database.EXT_CLIENT_TABLE_NAME, key)
-	if err != nil {
-		return extclient, err
-	}
-	err = json.Unmarshal([]byte(data), &extclient)
-
-	return extclient, err
-}
-
 //Get an individual extclient. Nothin fancy here folks.
 //Get an individual extclient. Nothin fancy here folks.
 func getExtClientConf(w http.ResponseWriter, r *http.Request) {
 func getExtClientConf(w http.ResponseWriter, r *http.Request) {
 	// set header.
 	// set header.
@@ -154,7 +116,7 @@ func getExtClientConf(w http.ResponseWriter, r *http.Request) {
 	var params = mux.Vars(r)
 	var params = mux.Vars(r)
 	clientid := params["clientid"]
 	clientid := params["clientid"]
 	networkid := params["network"]
 	networkid := params["network"]
-	client, err := GetExtClient(clientid, networkid)
+	client, err := logic.GetExtClient(clientid, networkid)
 	if err != nil {
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 		return
@@ -162,14 +124,14 @@ func getExtClientConf(w http.ResponseWriter, r *http.Request) {
 
 
 	gwnode, err := logic.GetNodeByMacAddress(client.Network, client.IngressGatewayID)
 	gwnode, err := logic.GetNodeByMacAddress(client.Network, client.IngressGatewayID)
 	if err != nil {
 	if err != nil {
-		functions.PrintUserLog(r.Header.Get("user"), "Could not retrieve Ingress Gateway Node "+client.IngressGatewayID, 1)
+		logger.Log(1, fmt.Sprintf("%s %s %s", r.Header.Get("user"), "Could not retrieve Ingress Gateway Node", client.IngressGatewayID))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 		return
 	}
 	}
 
 
 	network, err := logic.GetParentNetwork(client.Network)
 	network, err := logic.GetParentNetwork(client.Network)
 	if err != nil {
 	if err != nil {
-		functions.PrintUserLog(r.Header.Get("user"), "Could not retrieve Ingress Gateway Network "+client.Network, 1)
+		logger.Log(1, r.Header.Get("user"), "Could not retrieve Ingress Gateway Network", client.Network)
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 		return
 	}
 	}
@@ -234,52 +196,11 @@ Endpoint = %s
 		}
 		}
 		return
 		return
 	}
 	}
-	functions.PrintUserLog(r.Header.Get("user"), "retrieved ext client config", 2)
+	logger.Log(2, r.Header.Get("user"), "retrieved ext client config")
 	w.WriteHeader(http.StatusOK)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(client)
 	json.NewEncoder(w).Encode(client)
 }
 }
 
 
-// CreateExtClient - creates an extclient
-func CreateExtClient(extclient models.ExtClient) error {
-	if extclient.PrivateKey == "" {
-		privateKey, err := wgtypes.GeneratePrivateKey()
-		if err != nil {
-			return err
-		}
-
-		extclient.PrivateKey = privateKey.String()
-		extclient.PublicKey = privateKey.PublicKey().String()
-	}
-
-	if extclient.Address == "" {
-		newAddress, err := logic.UniqueAddress(extclient.Network)
-		if err != nil {
-			return err
-		}
-		extclient.Address = newAddress
-	}
-
-	if extclient.ClientID == "" {
-		extclient.ClientID = models.GenerateNodeName()
-	}
-
-	extclient.LastModified = time.Now().Unix()
-
-	key, err := logic.GetRecordKey(extclient.ClientID, extclient.Network)
-	if err != nil {
-		return err
-	}
-	data, err := json.Marshal(&extclient)
-	if err != nil {
-		return err
-	}
-	if err = database.Insert(key, string(data), database.EXT_CLIENT_TABLE_NAME); err != nil {
-		return err
-	}
-	err = logic.SetNetworkNodesLastModified(extclient.Network)
-	return err
-}
-
 /**
 /**
  * To create a extclient
  * To create a extclient
  * Must have valid key and be unique
  * Must have valid key and be unique
@@ -311,8 +232,7 @@ func createExtClient(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 		return
 	}
 	}
-	err = CreateExtClient(extclient)
-
+	err = logic.CreateExtClient(&extclient)
 	if err != nil {
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 		return
@@ -343,55 +263,16 @@ func updateExtClient(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 		return
 	}
 	}
-	newclient, err := UpdateExtClient(newExtClient.ClientID, params["network"], oldExtClient)
+	newclient, err := logic.UpdateExtClient(newExtClient.ClientID, params["network"], &oldExtClient)
 	if err != nil {
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 		return
 	}
 	}
-	functions.PrintUserLog(r.Header.Get("user"), "updated client "+newExtClient.ClientID, 1)
+	logger.Log(1, r.Header.Get("user"), "updated client", newExtClient.ClientID)
 	w.WriteHeader(http.StatusOK)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(newclient)
 	json.NewEncoder(w).Encode(newclient)
 }
 }
 
 
-// UpdateExtClient - only supports name changes right now
-func UpdateExtClient(newclientid string, network string, client models.ExtClient) (models.ExtClient, error) {
-
-	err := DeleteExtClient(network, client.ClientID)
-	if err != nil {
-		return client, err
-	}
-	client.ClientID = newclientid
-	CreateExtClient(client)
-	return client, err
-}
-
-// DeleteExtClient - deletes an existing ext client
-func DeleteExtClient(network string, clientid string) error {
-	key, err := logic.GetRecordKey(clientid, network)
-	if err != nil {
-		return err
-	}
-	err = database.DeleteRecord(database.EXT_CLIENT_TABLE_NAME, key)
-	return err
-}
-
-// DeleteGatewayExtClients - deletes ext clients based on gateway (mac) of ingress node and network
-func DeleteGatewayExtClients(gatewayID string, networkName string) error {
-	currentExtClients, err := GetNetworkExtClients(networkName)
-	if err != nil && !database.IsEmptyRecord(err) {
-		return err
-	}
-	for _, extClient := range currentExtClients {
-		if extClient.IngressGatewayID == gatewayID {
-			if err = DeleteExtClient(networkName, extClient.ClientID); err != nil {
-				functions.PrintUserLog(models.NODE_SERVER_NAME, "failed to remove ext client "+extClient.ClientID, 2)
-				continue
-			}
-		}
-	}
-	return nil
-}
-
 //Delete a extclient
 //Delete a extclient
 //Pretty straightforward
 //Pretty straightforward
 func deleteExtClient(w http.ResponseWriter, r *http.Request) {
 func deleteExtClient(w http.ResponseWriter, r *http.Request) {
@@ -401,14 +282,14 @@ func deleteExtClient(w http.ResponseWriter, r *http.Request) {
 	// get params
 	// get params
 	var params = mux.Vars(r)
 	var params = mux.Vars(r)
 
 
-	err := DeleteExtClient(params["network"], params["clientid"])
+	err := logic.DeleteExtClient(params["network"], params["clientid"])
 
 
 	if err != nil {
 	if err != nil {
 		err = errors.New("Could not delete extclient " + params["clientid"])
 		err = errors.New("Could not delete extclient " + params["clientid"])
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 		return
 	}
 	}
-	functions.PrintUserLog(r.Header.Get("user"),
-		"Deleted extclient client "+params["clientid"]+" from network "+params["network"], 1)
+	logger.Log(1, r.Header.Get("user"),
+		"Deleted extclient client", params["clientid"], "from network", params["network"])
 	returnSuccessResponse(w, r, params["clientid"]+" deleted.")
 	returnSuccessResponse(w, r, params["clientid"]+" deleted.")
 }
 }

+ 0 - 0
controllers/fileHttpController.go → controllers/files.go


+ 23 - 0
controllers/logger.go

@@ -0,0 +1,23 @@
+package controller
+
+import (
+	"fmt"
+	"net/http"
+	"time"
+
+	"github.com/gorilla/mux"
+	"github.com/gravitl/netmaker/logger"
+)
+
+func loggerHandlers(r *mux.Router) {
+	r.HandleFunc("/api/logs", securityCheck(true, http.HandlerFunc(getLogs))).Methods("GET")
+}
+
+func getLogs(w http.ResponseWriter, r *http.Request) {
+	var currentTime = time.Now().Format(logger.TimeFormatDay)
+	var currentFilePath = fmt.Sprintf("data/netmaker.log.%s", currentTime)
+	logger.DumpFile(currentFilePath)
+	logger.ResetLogs()
+	w.WriteHeader(http.StatusOK)
+	w.Write([]byte(logger.Retrieve(currentFilePath)))
+}

+ 298 - 0
controllers/network.go

@@ -0,0 +1,298 @@
+package controller
+
+import (
+	"encoding/json"
+	"errors"
+	"net/http"
+	"strings"
+
+	"github.com/gorilla/mux"
+	"github.com/gravitl/netmaker/database"
+	"github.com/gravitl/netmaker/logger"
+	"github.com/gravitl/netmaker/logic"
+	"github.com/gravitl/netmaker/models"
+	"github.com/gravitl/netmaker/servercfg"
+	"github.com/gravitl/netmaker/serverctl"
+)
+
+const ALL_NETWORK_ACCESS = "THIS_USER_HAS_ALL"
+const NO_NETWORKS_PRESENT = "THIS_USER_HAS_NONE"
+
+func networkHandlers(r *mux.Router) {
+	r.HandleFunc("/api/networks", securityCheck(false, http.HandlerFunc(getNetworks))).Methods("GET")
+	r.HandleFunc("/api/networks", securityCheck(true, http.HandlerFunc(createNetwork))).Methods("POST")
+	r.HandleFunc("/api/networks/{networkname}", securityCheck(false, http.HandlerFunc(getNetwork))).Methods("GET")
+	r.HandleFunc("/api/networks/{networkname}", securityCheck(false, http.HandlerFunc(updateNetwork))).Methods("PUT")
+	r.HandleFunc("/api/networks/{networkname}/nodelimit", securityCheck(true, http.HandlerFunc(updateNetworkNodeLimit))).Methods("PUT")
+	r.HandleFunc("/api/networks/{networkname}", securityCheck(true, http.HandlerFunc(deleteNetwork))).Methods("DELETE")
+	r.HandleFunc("/api/networks/{networkname}/keyupdate", securityCheck(false, http.HandlerFunc(keyUpdate))).Methods("POST")
+	r.HandleFunc("/api/networks/{networkname}/keys", securityCheck(false, http.HandlerFunc(createAccessKey))).Methods("POST")
+	r.HandleFunc("/api/networks/{networkname}/keys", securityCheck(false, http.HandlerFunc(getAccessKeys))).Methods("GET")
+	r.HandleFunc("/api/networks/{networkname}/keys/{name}", securityCheck(false, http.HandlerFunc(deleteAccessKey))).Methods("DELETE")
+}
+
+//simple get all networks function
+func getNetworks(w http.ResponseWriter, r *http.Request) {
+
+	headerNetworks := r.Header.Get("networks")
+	networksSlice := []string{}
+	marshalErr := json.Unmarshal([]byte(headerNetworks), &networksSlice)
+	if marshalErr != nil {
+		returnErrorResponse(w, r, formatError(marshalErr, "internal"))
+		return
+	}
+	allnetworks := []models.Network{}
+	err := errors.New("Networks Error")
+	if networksSlice[0] == ALL_NETWORK_ACCESS {
+		allnetworks, err = logic.GetNetworks()
+		if err != nil && !database.IsEmptyRecord(err) {
+			returnErrorResponse(w, r, formatError(err, "internal"))
+			return
+		}
+	} else {
+		for _, network := range networksSlice {
+			netObject, parentErr := logic.GetParentNetwork(network)
+			if parentErr == nil {
+				allnetworks = append(allnetworks, netObject)
+			}
+		}
+	}
+	if !servercfg.IsDisplayKeys() {
+		for i, net := range allnetworks {
+			net.AccessKeys = logic.RemoveKeySensitiveInfo(net.AccessKeys)
+			allnetworks[i] = net
+		}
+	}
+	logger.Log(2, r.Header.Get("user"), "fetched networks.")
+	w.WriteHeader(http.StatusOK)
+	json.NewEncoder(w).Encode(allnetworks)
+}
+
+//Simple get network function
+func getNetwork(w http.ResponseWriter, r *http.Request) {
+	// set header.
+	w.Header().Set("Content-Type", "application/json")
+	var params = mux.Vars(r)
+	netname := params["networkname"]
+	network, err := logic.GetNetwork(netname)
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+	if !servercfg.IsDisplayKeys() {
+		network.AccessKeys = logic.RemoveKeySensitiveInfo(network.AccessKeys)
+	}
+	logger.Log(2, r.Header.Get("user"), "fetched network", netname)
+	w.WriteHeader(http.StatusOK)
+	json.NewEncoder(w).Encode(network)
+}
+
+func keyUpdate(w http.ResponseWriter, r *http.Request) {
+	w.Header().Set("Content-Type", "application/json")
+	var params = mux.Vars(r)
+	netname := params["networkname"]
+	network, err := logic.KeyUpdate(netname)
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+	logger.Log(2, r.Header.Get("user"), "updated key on network", netname)
+	w.WriteHeader(http.StatusOK)
+	json.NewEncoder(w).Encode(network)
+}
+
+//Update a network
+func updateNetwork(w http.ResponseWriter, r *http.Request) {
+	w.Header().Set("Content-Type", "application/json")
+	var params = mux.Vars(r)
+	var network models.Network
+	netname := params["networkname"]
+	network, err := logic.GetParentNetwork(netname)
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+	var newNetwork models.Network
+	err = json.NewDecoder(r.Body).Decode(&newNetwork)
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "badrequest"))
+		return
+	}
+
+	rangeupdate, localrangeupdate, err := logic.UpdateNetwork(&network, &newNetwork)
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "badrequest"))
+		return
+	}
+
+	// if newNetwork.IsDualStack != currentNetwork.IsDualStack && newNetwork.IsDualStack == "no" {
+	// 	// Remove IPv6 address from network nodes
+	// 	RemoveNetworkNodeIPv6Addresses(currentNetwork.NetID)
+	// }
+
+	if rangeupdate {
+		err = logic.UpdateNetworkNodeAddresses(network.NetID)
+		if err != nil {
+			returnErrorResponse(w, r, formatError(err, "internal"))
+			return
+		}
+	}
+	if localrangeupdate {
+		err = logic.UpdateNetworkLocalAddresses(network.NetID)
+		if err != nil {
+			returnErrorResponse(w, r, formatError(err, "internal"))
+			return
+		}
+	}
+	logger.Log(1, r.Header.Get("user"), "updated network", netname)
+	w.WriteHeader(http.StatusOK)
+	json.NewEncoder(w).Encode(newNetwork)
+}
+
+func updateNetworkNodeLimit(w http.ResponseWriter, r *http.Request) {
+	w.Header().Set("Content-Type", "application/json")
+	var params = mux.Vars(r)
+	var network models.Network
+	netname := params["networkname"]
+	network, err := logic.GetParentNetwork(netname)
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+
+	var networkChange models.Network
+
+	_ = json.NewDecoder(r.Body).Decode(&networkChange)
+
+	if networkChange.NodeLimit != 0 {
+		network.NodeLimit = networkChange.NodeLimit
+		data, err := json.Marshal(&network)
+		if err != nil {
+			returnErrorResponse(w, r, formatError(err, "badrequest"))
+			return
+		}
+		database.Insert(network.NetID, string(data), database.NETWORKS_TABLE_NAME)
+		logger.Log(1, r.Header.Get("user"), "updated network node limit on", netname)
+	}
+	w.WriteHeader(http.StatusOK)
+	json.NewEncoder(w).Encode(network)
+}
+
+//Delete a network
+//Will stop you if  there's any nodes associated
+func deleteNetwork(w http.ResponseWriter, r *http.Request) {
+	// Set header
+	w.Header().Set("Content-Type", "application/json")
+
+	var params = mux.Vars(r)
+	network := params["networkname"]
+	err := logic.DeleteNetwork(network)
+
+	if err != nil {
+		errtype := "badrequest"
+		if strings.Contains(err.Error(), "Node check failed") {
+			errtype = "forbidden"
+		}
+		returnErrorResponse(w, r, formatError(err, errtype))
+		return
+	}
+	logger.Log(1, r.Header.Get("user"), "deleted network", network)
+	w.WriteHeader(http.StatusOK)
+	json.NewEncoder(w).Encode("success")
+}
+
+func createNetwork(w http.ResponseWriter, r *http.Request) {
+
+	w.Header().Set("Content-Type", "application/json")
+
+	var network models.Network
+
+	// we decode our body request params
+	err := json.NewDecoder(r.Body).Decode(&network)
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+
+	err = logic.CreateNetwork(network)
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "badrequest"))
+		return
+	}
+
+	if servercfg.IsClientMode() != "off" {
+		var success bool
+		success, err = serverctl.AddNetwork(network.NetID)
+		if err != nil || !success {
+			logic.DeleteNetwork(network.NetID)
+			if err == nil {
+				err = errors.New("Failed to add server to network " + network.DisplayName)
+			}
+			returnErrorResponse(w, r, formatError(err, "internal"))
+			return
+		}
+	}
+
+	logger.Log(1, r.Header.Get("user"), "created network", network.NetID)
+	w.WriteHeader(http.StatusOK)
+}
+
+// BEGIN KEY MANAGEMENT SECTION
+func createAccessKey(w http.ResponseWriter, r *http.Request) {
+	w.Header().Set("Content-Type", "application/json")
+	var params = mux.Vars(r)
+	var accesskey models.AccessKey
+	//start here
+	netname := params["networkname"]
+	network, err := logic.GetParentNetwork(netname)
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+	err = json.NewDecoder(r.Body).Decode(&accesskey)
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+	key, err := logic.CreateAccessKey(accesskey, network)
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "badrequest"))
+		return
+	}
+	logger.Log(1, r.Header.Get("user"), "created access key", accesskey.Name, "on", netname)
+	w.WriteHeader(http.StatusOK)
+	json.NewEncoder(w).Encode(key)
+}
+
+// pretty simple get
+func getAccessKeys(w http.ResponseWriter, r *http.Request) {
+	w.Header().Set("Content-Type", "application/json")
+	var params = mux.Vars(r)
+	network := params["networkname"]
+	keys, err := logic.GetKeys(network)
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+	if !servercfg.IsDisplayKeys() {
+		keys = logic.RemoveKeySensitiveInfo(keys)
+	}
+	logger.Log(2, r.Header.Get("user"), "fetched access keys on network", network)
+	w.WriteHeader(http.StatusOK)
+	json.NewEncoder(w).Encode(keys)
+}
+
+// delete key. Has to do a little funky logic since it's not a collection item
+func deleteAccessKey(w http.ResponseWriter, r *http.Request) {
+	w.Header().Set("Content-Type", "application/json")
+	var params = mux.Vars(r)
+	keyname := params["name"]
+	netname := params["networkname"]
+	err := logic.DeleteKey(keyname, netname)
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "badrequest"))
+		return
+	}
+	logger.Log(1, r.Header.Get("user"), "deleted access key", keyname, "on network,", netname)
+	w.WriteHeader(http.StatusOK)
+}

+ 0 - 659
controllers/networkHttpController.go

@@ -1,659 +0,0 @@
-package controller
-
-import (
-	"encoding/base64"
-	"encoding/json"
-	"errors"
-	"net/http"
-	"strings"
-	"time"
-
-	"github.com/go-playground/validator/v10"
-	"github.com/gorilla/mux"
-	"github.com/gravitl/netmaker/database"
-	"github.com/gravitl/netmaker/functions"
-	"github.com/gravitl/netmaker/logic"
-	"github.com/gravitl/netmaker/models"
-	"github.com/gravitl/netmaker/servercfg"
-	"github.com/gravitl/netmaker/serverctl"
-)
-
-const ALL_NETWORK_ACCESS = "THIS_USER_HAS_ALL"
-const NO_NETWORKS_PRESENT = "THIS_USER_HAS_NONE"
-
-func networkHandlers(r *mux.Router) {
-	r.HandleFunc("/api/networks", securityCheck(false, http.HandlerFunc(getNetworks))).Methods("GET")
-	r.HandleFunc("/api/networks", securityCheck(true, http.HandlerFunc(createNetwork))).Methods("POST")
-	r.HandleFunc("/api/networks/{networkname}", securityCheck(false, http.HandlerFunc(getNetwork))).Methods("GET")
-	r.HandleFunc("/api/networks/{networkname}", securityCheck(false, http.HandlerFunc(updateNetwork))).Methods("PUT")
-	r.HandleFunc("/api/networks/{networkname}/nodelimit", securityCheck(true, http.HandlerFunc(updateNetworkNodeLimit))).Methods("PUT")
-	r.HandleFunc("/api/networks/{networkname}", securityCheck(true, http.HandlerFunc(deleteNetwork))).Methods("DELETE")
-	r.HandleFunc("/api/networks/{networkname}/keyupdate", securityCheck(false, http.HandlerFunc(keyUpdate))).Methods("POST")
-	r.HandleFunc("/api/networks/{networkname}/keys", securityCheck(false, http.HandlerFunc(createAccessKey))).Methods("POST")
-	r.HandleFunc("/api/networks/{networkname}/keys", securityCheck(false, http.HandlerFunc(getAccessKeys))).Methods("GET")
-	r.HandleFunc("/api/networks/{networkname}/signuptoken", securityCheck(false, http.HandlerFunc(getSignupToken))).Methods("GET")
-	r.HandleFunc("/api/networks/{networkname}/keys/{name}", securityCheck(false, http.HandlerFunc(deleteAccessKey))).Methods("DELETE")
-}
-
-//Security check is middleware for every function and just checks to make sure that its the master calling
-//Only admin should have access to all these network-level actions
-//or maybe some Users once implemented
-func securityCheck(reqAdmin bool, next http.Handler) http.HandlerFunc {
-	return func(w http.ResponseWriter, r *http.Request) {
-		var errorResponse = models.ErrorResponse{
-			Code: http.StatusUnauthorized, Message: "W1R3: It's not you it's me.",
-		}
-
-		var params = mux.Vars(r)
-		bearerToken := r.Header.Get("Authorization")
-		err, networks, username := SecurityCheck(reqAdmin, params["networkname"], bearerToken)
-		if err != nil {
-			if strings.Contains(err.Error(), "does not exist") {
-				errorResponse.Code = http.StatusNotFound
-			}
-			errorResponse.Message = err.Error()
-			returnErrorResponse(w, r, errorResponse)
-			return
-		}
-		networksJson, err := json.Marshal(&networks)
-		if err != nil {
-			errorResponse.Message = err.Error()
-			returnErrorResponse(w, r, errorResponse)
-			return
-		}
-		r.Header.Set("user", username)
-		r.Header.Set("networks", string(networksJson))
-		next.ServeHTTP(w, r)
-	}
-}
-
-func SecurityCheck(reqAdmin bool, netname string, token string) (error, []string, string) {
-
-	var hasBearer = true
-	var tokenSplit = strings.Split(token, " ")
-	var authToken = ""
-
-	if len(tokenSplit) < 2 {
-		hasBearer = false
-	} else {
-		authToken = tokenSplit[1]
-	}
-	userNetworks := []string{}
-	//all endpoints here require master so not as complicated
-	isMasterAuthenticated := authenticateMaster(authToken)
-	username := ""
-	if !hasBearer || !isMasterAuthenticated {
-		userName, networks, isadmin, err := logic.VerifyUserToken(authToken)
-		username = userName
-		if err != nil {
-			return errors.New("error verifying user token"), nil, username
-		}
-		if !isadmin && reqAdmin {
-			return errors.New("you are unauthorized to access this endpoint"), nil, username
-		}
-		userNetworks = networks
-		if isadmin {
-			userNetworks = []string{ALL_NETWORK_ACCESS}
-		} else {
-			networkexists, err := functions.NetworkExists(netname)
-			if err != nil && !database.IsEmptyRecord(err) {
-				return err, nil, ""
-			}
-			if netname != "" && !networkexists {
-				return errors.New("this network does not exist"), nil, ""
-			}
-		}
-	} else if isMasterAuthenticated {
-		userNetworks = []string{ALL_NETWORK_ACCESS}
-	}
-	if len(userNetworks) == 0 {
-		userNetworks = append(userNetworks, NO_NETWORKS_PRESENT)
-	}
-	return nil, userNetworks, username
-}
-
-//Consider a more secure way of setting master key
-func authenticateMaster(tokenString string) bool {
-	return tokenString == servercfg.GetMasterKey()
-}
-
-//Consider a more secure way of setting master key
-func authenticateDNSToken(tokenString string) bool {
-	tokens := strings.Split(tokenString, " ")
-	if len(tokens) < 2 {
-		return false
-	}
-	return tokens[1] == servercfg.GetDNSKey()
-}
-
-//simple get all networks function
-func getNetworks(w http.ResponseWriter, r *http.Request) {
-
-	headerNetworks := r.Header.Get("networks")
-	networksSlice := []string{}
-	marshalErr := json.Unmarshal([]byte(headerNetworks), &networksSlice)
-	if marshalErr != nil {
-		returnErrorResponse(w, r, formatError(marshalErr, "internal"))
-		return
-	}
-	allnetworks := []models.Network{}
-	err := errors.New("Networks Error")
-	if networksSlice[0] == ALL_NETWORK_ACCESS {
-		allnetworks, err = logic.GetNetworks()
-		if err != nil && !database.IsEmptyRecord(err) {
-			returnErrorResponse(w, r, formatError(err, "internal"))
-			return
-		}
-	} else {
-		for _, network := range networksSlice {
-			netObject, parentErr := logic.GetParentNetwork(network)
-			if parentErr == nil {
-				allnetworks = append(allnetworks, netObject)
-			}
-		}
-	}
-	if !servercfg.IsDisplayKeys() {
-		for i, net := range allnetworks {
-			net.AccessKeys = logic.RemoveKeySensitiveInfo(net.AccessKeys)
-			allnetworks[i] = net
-		}
-	}
-	functions.PrintUserLog(r.Header.Get("user"), "fetched networks.", 2)
-	w.WriteHeader(http.StatusOK)
-	json.NewEncoder(w).Encode(allnetworks)
-}
-
-func ValidateNetworkUpdate(network models.Network) error {
-	v := validator.New()
-
-	_ = v.RegisterValidation("netid_valid", func(fl validator.FieldLevel) bool {
-		if fl.Field().String() == "" {
-			return true
-		}
-		inCharSet := functions.NameInNetworkCharSet(fl.Field().String())
-		return inCharSet
-	})
-
-	err := v.Struct(network)
-
-	if err != nil {
-		for _, e := range err.(validator.ValidationErrors) {
-			functions.PrintUserLog("validator", e.Error(), 1)
-		}
-	}
-	return err
-}
-
-//Simple get network function
-func getNetwork(w http.ResponseWriter, r *http.Request) {
-	// set header.
-	w.Header().Set("Content-Type", "application/json")
-	var params = mux.Vars(r)
-	netname := params["networkname"]
-	network, err := GetNetwork(netname)
-	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "internal"))
-		return
-	}
-	if !servercfg.IsDisplayKeys() {
-		network.AccessKeys = logic.RemoveKeySensitiveInfo(network.AccessKeys)
-	}
-	functions.PrintUserLog(r.Header.Get("user"), "fetched network "+netname, 2)
-	w.WriteHeader(http.StatusOK)
-	json.NewEncoder(w).Encode(network)
-}
-
-func GetNetwork(name string) (models.Network, error) {
-	var network models.Network
-	record, err := database.FetchRecord(database.NETWORKS_TABLE_NAME, name)
-	if err != nil {
-		return network, err
-	}
-
-	if err = json.Unmarshal([]byte(record), &network); err != nil {
-		return models.Network{}, err
-	}
-
-	return network, nil
-}
-
-func keyUpdate(w http.ResponseWriter, r *http.Request) {
-	w.Header().Set("Content-Type", "application/json")
-	var params = mux.Vars(r)
-	netname := params["networkname"]
-	network, err := KeyUpdate(netname)
-	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "internal"))
-		return
-	}
-	functions.PrintUserLog(r.Header.Get("user"), "updated key on network "+netname, 2)
-	w.WriteHeader(http.StatusOK)
-	json.NewEncoder(w).Encode(network)
-}
-
-func KeyUpdate(netname string) (models.Network, error) {
-	err := functions.NetworkNodesUpdateAction(netname, models.NODE_UPDATE_KEY)
-	if err != nil {
-		return models.Network{}, err
-	}
-	return models.Network{}, nil
-}
-
-//Update a network
-func AlertNetwork(netid string) error {
-
-	var network models.Network
-	network, err := logic.GetParentNetwork(netid)
-	if err != nil {
-		return err
-	}
-	updatetime := time.Now().Unix()
-	network.NodesLastModified = updatetime
-	network.NetworkLastModified = updatetime
-	data, err := json.Marshal(&network)
-	if err != nil {
-		return err
-	}
-	database.Insert(netid, string(data), database.NETWORKS_TABLE_NAME)
-	return nil
-}
-
-//Update a network
-func updateNetwork(w http.ResponseWriter, r *http.Request) {
-	w.Header().Set("Content-Type", "application/json")
-	var params = mux.Vars(r)
-	var network models.Network
-	netname := params["networkname"]
-	network, err := logic.GetParentNetwork(netname)
-	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "internal"))
-		return
-	}
-	var newNetwork models.Network
-	err = json.NewDecoder(r.Body).Decode(&newNetwork)
-	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "badrequest"))
-		return
-	}
-
-	rangeupdate, localrangeupdate, err := logic.UpdateNetwork(&network, &newNetwork)
-	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "badrequest"))
-		return
-	}
-
-	// if newNetwork.IsDualStack != currentNetwork.IsDualStack && newNetwork.IsDualStack == "no" {
-	// 	// Remove IPv6 address from network nodes
-	// 	RemoveNetworkNodeIPv6Addresses(currentNetwork.NetID)
-	// }
-
-	if rangeupdate {
-		err = logic.UpdateNetworkNodeAddresses(network.NetID)
-		if err != nil {
-			returnErrorResponse(w, r, formatError(err, "internal"))
-			return
-		}
-	}
-	if localrangeupdate {
-		err = logic.UpdateNetworkLocalAddresses(network.NetID)
-		if err != nil {
-			returnErrorResponse(w, r, formatError(err, "internal"))
-			return
-		}
-	}
-	functions.PrintUserLog(r.Header.Get("user"), "updated network "+netname, 1)
-	w.WriteHeader(http.StatusOK)
-	json.NewEncoder(w).Encode(newNetwork)
-}
-
-func updateNetworkNodeLimit(w http.ResponseWriter, r *http.Request) {
-	w.Header().Set("Content-Type", "application/json")
-	var params = mux.Vars(r)
-	var network models.Network
-	netname := params["networkname"]
-	network, err := logic.GetParentNetwork(netname)
-	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "internal"))
-		return
-	}
-
-	var networkChange models.Network
-
-	_ = json.NewDecoder(r.Body).Decode(&networkChange)
-
-	if networkChange.NodeLimit != 0 {
-		network.NodeLimit = networkChange.NodeLimit
-		data, err := json.Marshal(&network)
-		if err != nil {
-			returnErrorResponse(w, r, formatError(err, "badrequest"))
-			return
-		}
-		database.Insert(network.NetID, string(data), database.NETWORKS_TABLE_NAME)
-		functions.PrintUserLog(r.Header.Get("user"), "updated network node limit on, "+netname, 1)
-	}
-	w.WriteHeader(http.StatusOK)
-	json.NewEncoder(w).Encode(network)
-}
-
-//Delete a network
-//Will stop you if  there's any nodes associated
-func deleteNetwork(w http.ResponseWriter, r *http.Request) {
-	// Set header
-	w.Header().Set("Content-Type", "application/json")
-
-	var params = mux.Vars(r)
-	network := params["networkname"]
-	err := DeleteNetwork(network)
-
-	if err != nil {
-		errtype := "badrequest"
-		if strings.Contains(err.Error(), "Node check failed") {
-			errtype = "forbidden"
-		}
-		returnErrorResponse(w, r, formatError(err, errtype))
-		return
-	}
-	functions.PrintUserLog(r.Header.Get("user"), "deleted network "+network, 1)
-	w.WriteHeader(http.StatusOK)
-	json.NewEncoder(w).Encode("success")
-}
-
-func DeleteNetwork(network string) error {
-	nodeCount, err := functions.GetNetworkNonServerNodeCount(network)
-	if nodeCount == 0 || database.IsEmptyRecord(err) {
-		// delete server nodes first then db records
-		servers, err := logic.GetSortedNetworkServerNodes(network)
-		if err == nil {
-			for _, s := range servers {
-				if err = logic.DeleteNode(&s, true); err != nil {
-					functions.PrintUserLog("", "could not removed server "+s.Name+" before deleting network "+network, 2)
-				} else {
-					functions.PrintUserLog("", "removed server "+s.Name+" before deleting network "+network, 2)
-				}
-			}
-		} else {
-			functions.PrintUserLog("", "could not remove servers before deleting network "+network, 1)
-		}
-		return database.DeleteRecord(database.NETWORKS_TABLE_NAME, network)
-	}
-	return errors.New("node check failed. All nodes must be deleted before deleting network")
-}
-
-//Create a network
-//Pretty simple
-func createNetwork(w http.ResponseWriter, r *http.Request) {
-
-	w.Header().Set("Content-Type", "application/json")
-
-	var network models.Network
-
-	// we decode our body request params
-	err := json.NewDecoder(r.Body).Decode(&network)
-	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "internal"))
-		return
-	}
-
-	err = CreateNetwork(network)
-	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "badrequest"))
-		return
-	}
-	functions.PrintUserLog(r.Header.Get("user"), "created network "+network.NetID, 1)
-	w.WriteHeader(http.StatusOK)
-	//json.NewEncoder(w).Encode(result)
-}
-
-func CreateNetwork(network models.Network) error {
-
-	network.SetDefaults()
-	network.SetNodesLastModified()
-	network.SetNetworkLastModified()
-	network.KeyUpdateTimeStamp = time.Now().Unix()
-
-	err := logic.ValidateNetwork(&network, false)
-	if err != nil {
-		//returnErrorResponse(w, r, formatError(err, "badrequest"))
-		return err
-	}
-
-	data, err := json.Marshal(&network)
-	if err != nil {
-		return err
-	}
-	if err = database.Insert(network.NetID, string(data), database.NETWORKS_TABLE_NAME); err != nil {
-		return err
-	}
-
-	if servercfg.IsClientMode() != "off" {
-		var success bool
-		success, err = serverctl.AddNetwork(network.NetID)
-		if err != nil || !success {
-			DeleteNetwork(network.NetID)
-			if err == nil {
-				err = errors.New("Failed to add server to network " + network.DisplayName)
-			}
-		}
-	}
-
-	return err
-}
-
-// BEGIN KEY MANAGEMENT SECTION
-func createAccessKey(w http.ResponseWriter, r *http.Request) {
-	w.Header().Set("Content-Type", "application/json")
-	var params = mux.Vars(r)
-	var accesskey models.AccessKey
-	//start here
-	netname := params["networkname"]
-	network, err := logic.GetParentNetwork(netname)
-	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "internal"))
-		return
-	}
-	err = json.NewDecoder(r.Body).Decode(&accesskey)
-	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "internal"))
-		return
-	}
-	key, err := CreateAccessKey(accesskey, network)
-	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "badrequest"))
-		return
-	}
-	functions.PrintUserLog(r.Header.Get("user"), "created access key "+accesskey.Name+" on "+netname, 1)
-	w.WriteHeader(http.StatusOK)
-	json.NewEncoder(w).Encode(key)
-	//w.Write([]byte(accesskey.AccessString))
-}
-
-func CreateAccessKey(accesskey models.AccessKey, network models.Network) (models.AccessKey, error) {
-
-	if accesskey.Name == "" {
-		accesskey.Name = functions.GenKeyName()
-	}
-
-	if accesskey.Value == "" {
-		accesskey.Value = functions.GenKey()
-	}
-	if accesskey.Uses == 0 {
-		accesskey.Uses = 1
-	}
-
-	checkkeys, err := GetKeys(network.NetID)
-	if err != nil {
-		return models.AccessKey{}, errors.New("could not retrieve network keys")
-	}
-
-	for _, key := range checkkeys {
-		if key.Name == accesskey.Name {
-			return models.AccessKey{}, errors.New("duplicate AccessKey Name")
-		}
-	}
-	privAddr := ""
-	if network.IsLocal != "" {
-		privAddr = network.LocalRange
-	}
-
-	netID := network.NetID
-
-	var accessToken models.AccessToken
-	s := servercfg.GetServerConfig()
-	servervals := models.ServerConfig{
-		CoreDNSAddr:     s.CoreDNSAddr,
-		APIConnString:   s.APIConnString,
-		APIHost:         s.APIHost,
-		APIPort:         s.APIPort,
-		GRPCConnString:  s.GRPCConnString,
-		GRPCHost:        s.GRPCHost,
-		GRPCPort:        s.GRPCPort,
-		GRPCSSL:         s.GRPCSSL,
-		CheckinInterval: s.CheckinInterval,
-	}
-	accessToken.ServerConfig = servervals
-	accessToken.ClientConfig.Network = netID
-	accessToken.ClientConfig.Key = accesskey.Value
-	accessToken.ClientConfig.LocalRange = privAddr
-
-	tokenjson, err := json.Marshal(accessToken)
-	if err != nil {
-		return accesskey, err
-	}
-
-	accesskey.AccessString = base64.StdEncoding.EncodeToString([]byte(tokenjson))
-
-	//validate accesskey
-	v := validator.New()
-	err = v.Struct(accesskey)
-	if err != nil {
-		for _, e := range err.(validator.ValidationErrors) {
-			functions.PrintUserLog("validator", e.Error(), 1)
-		}
-		return models.AccessKey{}, err
-	}
-
-	network.AccessKeys = append(network.AccessKeys, accesskey)
-	data, err := json.Marshal(&network)
-	if err != nil {
-		return models.AccessKey{}, err
-	}
-	if err = database.Insert(network.NetID, string(data), database.NETWORKS_TABLE_NAME); err != nil {
-		return models.AccessKey{}, err
-	}
-
-	return accesskey, nil
-}
-
-func GetSignupToken(netID string) (models.AccessKey, error) {
-
-	var accesskey models.AccessKey
-	var accessToken models.AccessToken
-	s := servercfg.GetServerConfig()
-	servervals := models.ServerConfig{
-		APIConnString:  s.APIConnString,
-		APIHost:        s.APIHost,
-		APIPort:        s.APIPort,
-		GRPCConnString: s.GRPCConnString,
-		GRPCHost:       s.GRPCHost,
-		GRPCPort:       s.GRPCPort,
-		GRPCSSL:        s.GRPCSSL,
-	}
-	accessToken.ServerConfig = servervals
-
-	tokenjson, err := json.Marshal(accessToken)
-	if err != nil {
-		return accesskey, err
-	}
-
-	accesskey.AccessString = base64.StdEncoding.EncodeToString([]byte(tokenjson))
-	return accesskey, nil
-}
-func getSignupToken(w http.ResponseWriter, r *http.Request) {
-	w.Header().Set("Content-Type", "application/json")
-	var params = mux.Vars(r)
-	netID := params["networkname"]
-
-	token, err := GetSignupToken(netID)
-	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "internal"))
-		return
-	}
-	functions.PrintUserLog(r.Header.Get("user"), "got signup token "+netID, 2)
-	w.WriteHeader(http.StatusOK)
-	json.NewEncoder(w).Encode(token)
-}
-
-//pretty simple get
-func getAccessKeys(w http.ResponseWriter, r *http.Request) {
-	w.Header().Set("Content-Type", "application/json")
-	var params = mux.Vars(r)
-	network := params["networkname"]
-	keys, err := GetKeys(network)
-	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "internal"))
-		return
-	}
-	if !servercfg.IsDisplayKeys() {
-		keys = logic.RemoveKeySensitiveInfo(keys)
-	}
-	functions.PrintUserLog(r.Header.Get("user"), "fetched access keys on network "+network, 2)
-	w.WriteHeader(http.StatusOK)
-	json.NewEncoder(w).Encode(keys)
-}
-func GetKeys(net string) ([]models.AccessKey, error) {
-
-	record, err := database.FetchRecord(database.NETWORKS_TABLE_NAME, net)
-	if err != nil {
-		return []models.AccessKey{}, err
-	}
-	network, err := functions.ParseNetwork(record)
-	if err != nil {
-		return []models.AccessKey{}, err
-	}
-	return network.AccessKeys, nil
-}
-
-//delete key. Has to do a little funky logic since it's not a collection item
-func deleteAccessKey(w http.ResponseWriter, r *http.Request) {
-	w.Header().Set("Content-Type", "application/json")
-	var params = mux.Vars(r)
-	keyname := params["name"]
-	netname := params["networkname"]
-	err := DeleteKey(keyname, netname)
-	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "badrequest"))
-		return
-	}
-	functions.PrintUserLog(r.Header.Get("user"), "deleted access key "+keyname+" on network "+netname, 1)
-	w.WriteHeader(http.StatusOK)
-}
-func DeleteKey(keyname, netname string) error {
-	network, err := logic.GetParentNetwork(netname)
-	if err != nil {
-		return err
-	}
-	//basically, turn the list of access keys into the list of access keys before and after the item
-	//have not done any error handling for if there's like...1 item. I think it works? need to test.
-	found := false
-	var updatedKeys []models.AccessKey
-	for _, currentkey := range network.AccessKeys {
-		if currentkey.Name == keyname {
-			found = true
-		} else {
-			updatedKeys = append(updatedKeys, currentkey)
-		}
-	}
-	if !found {
-		return errors.New("key " + keyname + " does not exist")
-	}
-	network.AccessKeys = updatedKeys
-	data, err := json.Marshal(&network)
-	if err != nil {
-		return err
-	}
-	if err := database.Insert(network.NetID, string(data), database.NETWORKS_TABLE_NAME); err != nil {
-		return err
-	}
-
-	return nil
-}

+ 37 - 42
controllers/networkHttpController_test.go → controllers/network_test.go

@@ -25,7 +25,7 @@ func TestCreateNetwork(t *testing.T) {
 	network.AddressRange = "10.0.0.1/24"
 	network.AddressRange = "10.0.0.1/24"
 	network.DisplayName = "mynetwork"
 	network.DisplayName = "mynetwork"
 
 
-	err := CreateNetwork(network)
+	err := logic.CreateNetwork(network)
 	assert.Nil(t, err)
 	assert.Nil(t, err)
 }
 }
 func TestGetNetwork(t *testing.T) {
 func TestGetNetwork(t *testing.T) {
@@ -33,12 +33,12 @@ func TestGetNetwork(t *testing.T) {
 	createNet()
 	createNet()
 
 
 	t.Run("GetExistingNetwork", func(t *testing.T) {
 	t.Run("GetExistingNetwork", func(t *testing.T) {
-		network, err := GetNetwork("skynet")
+		network, err := logic.GetNetwork("skynet")
 		assert.Nil(t, err)
 		assert.Nil(t, err)
 		assert.Equal(t, "skynet", network.NetID)
 		assert.Equal(t, "skynet", network.NetID)
 	})
 	})
 	t.Run("GetNonExistantNetwork", func(t *testing.T) {
 	t.Run("GetNonExistantNetwork", func(t *testing.T) {
-		network, err := GetNetwork("doesnotexist")
+		network, err := logic.GetNetwork("doesnotexist")
 		assert.EqualError(t, err, "no result found")
 		assert.EqualError(t, err, "no result found")
 		assert.Equal(t, "", network.NetID)
 		assert.Equal(t, "", network.NetID)
 	})
 	})
@@ -51,11 +51,11 @@ func TestDeleteNetwork(t *testing.T) {
 	t.Run("NetworkwithNodes", func(t *testing.T) {
 	t.Run("NetworkwithNodes", func(t *testing.T) {
 	})
 	})
 	t.Run("DeleteExistingNetwork", func(t *testing.T) {
 	t.Run("DeleteExistingNetwork", func(t *testing.T) {
-		err := DeleteNetwork("skynet")
+		err := logic.DeleteNetwork("skynet")
 		assert.Nil(t, err)
 		assert.Nil(t, err)
 	})
 	})
 	t.Run("NonExistantNetwork", func(t *testing.T) {
 	t.Run("NonExistantNetwork", func(t *testing.T) {
-		err := DeleteNetwork("skynet")
+		err := logic.DeleteNetwork("skynet")
 		assert.Nil(t, err)
 		assert.Nil(t, err)
 	})
 	})
 }
 }
@@ -64,12 +64,12 @@ func TestKeyUpdate(t *testing.T) {
 	t.Skip() //test is failing on last assert  --- not sure why
 	t.Skip() //test is failing on last assert  --- not sure why
 	database.InitializeDatabase()
 	database.InitializeDatabase()
 	createNet()
 	createNet()
-	existing, err := GetNetwork("skynet")
+	existing, err := logic.GetNetwork("skynet")
 	assert.Nil(t, err)
 	assert.Nil(t, err)
 	time.Sleep(time.Second * 1)
 	time.Sleep(time.Second * 1)
-	network, err := KeyUpdate("skynet")
+	network, err := logic.KeyUpdate("skynet")
 	assert.Nil(t, err)
 	assert.Nil(t, err)
-	network, err = GetNetwork("skynet")
+	network, err = logic.GetNetwork("skynet")
 	assert.Nil(t, err)
 	assert.Nil(t, err)
 	assert.Greater(t, network.KeyUpdateTimeStamp, existing.KeyUpdateTimeStamp)
 	assert.Greater(t, network.KeyUpdateTimeStamp, existing.KeyUpdateTimeStamp)
 }
 }
@@ -77,70 +77,70 @@ func TestKeyUpdate(t *testing.T) {
 func TestCreateKey(t *testing.T) {
 func TestCreateKey(t *testing.T) {
 	database.InitializeDatabase()
 	database.InitializeDatabase()
 	createNet()
 	createNet()
-	keys, _ := GetKeys("skynet")
+	keys, _ := logic.GetKeys("skynet")
 	for _, key := range keys {
 	for _, key := range keys {
-		DeleteKey(key.Name, "skynet")
+		logic.DeleteKey(key.Name, "skynet")
 	}
 	}
 	var accesskey models.AccessKey
 	var accesskey models.AccessKey
 	var network models.Network
 	var network models.Network
 	network.NetID = "skynet"
 	network.NetID = "skynet"
 	t.Run("NameTooLong", func(t *testing.T) {
 	t.Run("NameTooLong", func(t *testing.T) {
-		network, err := GetNetwork("skynet")
+		network, err := logic.GetNetwork("skynet")
 		assert.Nil(t, err)
 		assert.Nil(t, err)
 		accesskey.Name = "Thisisareallylongkeynamethatwillfail"
 		accesskey.Name = "Thisisareallylongkeynamethatwillfail"
-		_, err = CreateAccessKey(accesskey, network)
+		_, err = logic.CreateAccessKey(accesskey, network)
 		assert.NotNil(t, err)
 		assert.NotNil(t, err)
 		assert.Contains(t, err.Error(), "Field validation for 'Name' failed on the 'max' tag")
 		assert.Contains(t, err.Error(), "Field validation for 'Name' failed on the 'max' tag")
 	})
 	})
 	t.Run("BlankName", func(t *testing.T) {
 	t.Run("BlankName", func(t *testing.T) {
-		network, err := GetNetwork("skynet")
+		network, err := logic.GetNetwork("skynet")
 		assert.Nil(t, err)
 		assert.Nil(t, err)
 		accesskey.Name = ""
 		accesskey.Name = ""
-		key, err := CreateAccessKey(accesskey, network)
+		key, err := logic.CreateAccessKey(accesskey, network)
 		assert.Nil(t, err)
 		assert.Nil(t, err)
 		assert.NotEqual(t, "", key.Name)
 		assert.NotEqual(t, "", key.Name)
 	})
 	})
 	t.Run("InvalidValue", func(t *testing.T) {
 	t.Run("InvalidValue", func(t *testing.T) {
-		network, err := GetNetwork("skynet")
+		network, err := logic.GetNetwork("skynet")
 		assert.Nil(t, err)
 		assert.Nil(t, err)
 		accesskey.Value = "bad-value"
 		accesskey.Value = "bad-value"
-		_, err = CreateAccessKey(accesskey, network)
+		_, err = logic.CreateAccessKey(accesskey, network)
 		assert.NotNil(t, err)
 		assert.NotNil(t, err)
 		assert.Contains(t, err.Error(), "Field validation for 'Value' failed on the 'alphanum' tag")
 		assert.Contains(t, err.Error(), "Field validation for 'Value' failed on the 'alphanum' tag")
 	})
 	})
 	t.Run("BlankValue", func(t *testing.T) {
 	t.Run("BlankValue", func(t *testing.T) {
-		network, err := GetNetwork("skynet")
+		network, err := logic.GetNetwork("skynet")
 		assert.Nil(t, err)
 		assert.Nil(t, err)
 		accesskey.Name = "mykey"
 		accesskey.Name = "mykey"
 		accesskey.Value = ""
 		accesskey.Value = ""
-		key, err := CreateAccessKey(accesskey, network)
+		key, err := logic.CreateAccessKey(accesskey, network)
 		assert.Nil(t, err)
 		assert.Nil(t, err)
 		assert.NotEqual(t, "", key.Value)
 		assert.NotEqual(t, "", key.Value)
 		assert.Equal(t, accesskey.Name, key.Name)
 		assert.Equal(t, accesskey.Name, key.Name)
 	})
 	})
 	t.Run("ValueTooLong", func(t *testing.T) {
 	t.Run("ValueTooLong", func(t *testing.T) {
-		network, err := GetNetwork("skynet")
+		network, err := logic.GetNetwork("skynet")
 		assert.Nil(t, err)
 		assert.Nil(t, err)
 		accesskey.Name = "keyname"
 		accesskey.Name = "keyname"
 		accesskey.Value = "AccessKeyValuethatistoolong"
 		accesskey.Value = "AccessKeyValuethatistoolong"
-		_, err = CreateAccessKey(accesskey, network)
+		_, err = logic.CreateAccessKey(accesskey, network)
 		assert.NotNil(t, err)
 		assert.NotNil(t, err)
 		assert.Contains(t, err.Error(), "Field validation for 'Value' failed on the 'max' tag")
 		assert.Contains(t, err.Error(), "Field validation for 'Value' failed on the 'max' tag")
 	})
 	})
 	t.Run("BlankUses", func(t *testing.T) {
 	t.Run("BlankUses", func(t *testing.T) {
-		network, err := GetNetwork("skynet")
+		network, err := logic.GetNetwork("skynet")
 		assert.Nil(t, err)
 		assert.Nil(t, err)
 		accesskey.Uses = 0
 		accesskey.Uses = 0
 		accesskey.Value = ""
 		accesskey.Value = ""
-		key, err := CreateAccessKey(accesskey, network)
+		key, err := logic.CreateAccessKey(accesskey, network)
 		assert.Nil(t, err)
 		assert.Nil(t, err)
 		assert.Equal(t, 1, key.Uses)
 		assert.Equal(t, 1, key.Uses)
 	})
 	})
 	t.Run("DuplicateKey", func(t *testing.T) {
 	t.Run("DuplicateKey", func(t *testing.T) {
-		network, err := GetNetwork("skynet")
+		network, err := logic.GetNetwork("skynet")
 		assert.Nil(t, err)
 		assert.Nil(t, err)
 		accesskey.Name = "mykey"
 		accesskey.Name = "mykey"
-		_, err = CreateAccessKey(accesskey, network)
+		_, err = logic.CreateAccessKey(accesskey, network)
 		assert.NotNil(t, err)
 		assert.NotNil(t, err)
 		assert.EqualError(t, err, "duplicate AccessKey Name")
 		assert.EqualError(t, err, "duplicate AccessKey Name")
 	})
 	})
@@ -150,21 +150,21 @@ func TestGetKeys(t *testing.T) {
 	database.InitializeDatabase()
 	database.InitializeDatabase()
 	deleteAllNetworks()
 	deleteAllNetworks()
 	createNet()
 	createNet()
-	network, err := GetNetwork("skynet")
+	network, err := logic.GetNetwork("skynet")
 	assert.Nil(t, err)
 	assert.Nil(t, err)
 	var key models.AccessKey
 	var key models.AccessKey
 	key.Name = "mykey"
 	key.Name = "mykey"
-	_, err = CreateAccessKey(key, network)
+	_, err = logic.CreateAccessKey(key, network)
 	assert.Nil(t, err)
 	assert.Nil(t, err)
 	t.Run("KeyExists", func(t *testing.T) {
 	t.Run("KeyExists", func(t *testing.T) {
-		keys, err := GetKeys(network.NetID)
+		keys, err := logic.GetKeys(network.NetID)
 		assert.Nil(t, err)
 		assert.Nil(t, err)
 		assert.NotEqual(t, models.AccessKey{}, keys)
 		assert.NotEqual(t, models.AccessKey{}, keys)
 	})
 	})
 	t.Run("NonExistantKey", func(t *testing.T) {
 	t.Run("NonExistantKey", func(t *testing.T) {
-		err := DeleteKey("mykey", "skynet")
+		err := logic.DeleteKey("mykey", "skynet")
 		assert.Nil(t, err)
 		assert.Nil(t, err)
-		keys, err := GetKeys(network.NetID)
+		keys, err := logic.GetKeys(network.NetID)
 		assert.Nil(t, err)
 		assert.Nil(t, err)
 		assert.Equal(t, []models.AccessKey(nil), keys)
 		assert.Equal(t, []models.AccessKey(nil), keys)
 	})
 	})
@@ -172,18 +172,18 @@ func TestGetKeys(t *testing.T) {
 func TestDeleteKey(t *testing.T) {
 func TestDeleteKey(t *testing.T) {
 	database.InitializeDatabase()
 	database.InitializeDatabase()
 	createNet()
 	createNet()
-	network, err := GetNetwork("skynet")
+	network, err := logic.GetNetwork("skynet")
 	assert.Nil(t, err)
 	assert.Nil(t, err)
 	var key models.AccessKey
 	var key models.AccessKey
 	key.Name = "mykey"
 	key.Name = "mykey"
-	_, err = CreateAccessKey(key, network)
+	_, err = logic.CreateAccessKey(key, network)
 	assert.Nil(t, err)
 	assert.Nil(t, err)
 	t.Run("ExistingKey", func(t *testing.T) {
 	t.Run("ExistingKey", func(t *testing.T) {
-		err := DeleteKey("mykey", "skynet")
+		err := logic.DeleteKey("mykey", "skynet")
 		assert.Nil(t, err)
 		assert.Nil(t, err)
 	})
 	})
 	t.Run("NonExistantKey", func(t *testing.T) {
 	t.Run("NonExistantKey", func(t *testing.T) {
-		err := DeleteKey("mykey", "skynet")
+		err := logic.DeleteKey("mykey", "skynet")
 		assert.NotNil(t, err)
 		assert.NotNil(t, err)
 		assert.Equal(t, "key mykey does not exist", err.Error())
 		assert.Equal(t, "key mykey does not exist", err.Error())
 	})
 	})
@@ -325,7 +325,7 @@ func TestValidateNetworkUpdate(t *testing.T) {
 	for _, tc := range cases {
 	for _, tc := range cases {
 		t.Run(tc.testname, func(t *testing.T) {
 		t.Run(tc.testname, func(t *testing.T) {
 			network := models.Network(tc.network)
 			network := models.Network(tc.network)
-			err := ValidateNetworkUpdate(network)
+			err := logic.ValidateNetworkUpdate(network)
 			assert.NotNil(t, err)
 			assert.NotNil(t, err)
 			assert.Contains(t, err.Error(), tc.errMessage)
 			assert.Contains(t, err.Error(), tc.errMessage)
 		})
 		})
@@ -336,7 +336,7 @@ func deleteAllNetworks() {
 	deleteAllNodes()
 	deleteAllNodes()
 	nets, _ := logic.GetNetworks()
 	nets, _ := logic.GetNetworks()
 	for _, net := range nets {
 	for _, net := range nets {
-		DeleteNetwork(net.NetID)
+		logic.DeleteNetwork(net.NetID)
 	}
 	}
 }
 }
 
 
@@ -345,13 +345,8 @@ func createNet() {
 	network.NetID = "skynet"
 	network.NetID = "skynet"
 	network.AddressRange = "10.0.0.1/24"
 	network.AddressRange = "10.0.0.1/24"
 	network.DisplayName = "mynetwork"
 	network.DisplayName = "mynetwork"
-	_, err := GetNetwork("skynet")
+	_, err := logic.GetNetwork("skynet")
 	if err != nil {
 	if err != nil {
-		CreateNetwork(network)
+		logic.CreateNetwork(network)
 	}
 	}
 }
 }
-
-func getNet() models.Network {
-	network, _ := GetNetwork("skynet")
-	return network
-}

+ 34 - 261
controllers/nodeHttpController.go → controllers/node.go

@@ -2,14 +2,13 @@ package controller
 
 
 import (
 import (
 	"encoding/json"
 	"encoding/json"
-	"errors"
 	"net/http"
 	"net/http"
 	"strings"
 	"strings"
-	"time"
 
 
 	"github.com/gorilla/mux"
 	"github.com/gorilla/mux"
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/functions"
 	"github.com/gravitl/netmaker/functions"
+	"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/servercfg"
 	"github.com/gravitl/netmaker/servercfg"
@@ -36,20 +35,17 @@ func nodeHandlers(r *mux.Router) {
 
 
 }
 }
 
 
-//Node authenticates using its password and retrieves a JWT for authorization.
 func authenticate(response http.ResponseWriter, request *http.Request) {
 func authenticate(response http.ResponseWriter, request *http.Request) {
 
 
 	var params = mux.Vars(request)
 	var params = mux.Vars(request)
 	networkname := params["network"]
 	networkname := params["network"]
-	//Auth request consists of Mac Address and Password (from node that is authorizing
-	//in case of Master, auth is ignored and mac is set to "mastermac"
+
 	var authRequest models.AuthParams
 	var authRequest models.AuthParams
 	var result models.Node
 	var result models.Node
 	var errorResponse = models.ErrorResponse{
 	var errorResponse = models.ErrorResponse{
 		Code: http.StatusInternalServerError, Message: "W1R3: It's not you it's me.",
 		Code: http.StatusInternalServerError, Message: "W1R3: It's not you it's me.",
 	}
 	}
 
 
-	//Get password fnd mac rom request
 	decoder := json.NewDecoder(request.Body)
 	decoder := json.NewDecoder(request.Body)
 	decoderErr := decoder.Decode(&authRequest)
 	decoderErr := decoder.Decode(&authRequest)
 	defer request.Body.Close()
 	defer request.Body.Close()
@@ -71,7 +67,6 @@ func authenticate(response http.ResponseWriter, request *http.Request) {
 			return
 			return
 		} else {
 		} else {
 
 
-			//Search DB for node with Mac Address. Ignore pending nodes (they should not be able to authenticate with API until approved).
 			collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
 			collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
 			if err != nil {
 			if err != nil {
 				errorResponse.Code = http.StatusBadRequest
 				errorResponse.Code = http.StatusBadRequest
@@ -95,9 +90,6 @@ func authenticate(response http.ResponseWriter, request *http.Request) {
 				return
 				return
 			}
 			}
 
 
-			//compare password from request to stored password in database
-			//might be able to have a common hash (certificates?) and compare those so that a password isn't passed in in plain text...
-			//TODO: Consider a way of hashing the password client side before sending, or using certificates
 			err = bcrypt.CompareHashAndPassword([]byte(result.Password), []byte(authRequest.Password))
 			err = bcrypt.CompareHashAndPassword([]byte(result.Password), []byte(authRequest.Password))
 			if err != nil {
 			if err != nil {
 				errorResponse.Code = http.StatusBadRequest
 				errorResponse.Code = http.StatusBadRequest
@@ -105,7 +97,6 @@ func authenticate(response http.ResponseWriter, request *http.Request) {
 				returnErrorResponse(response, request, errorResponse)
 				returnErrorResponse(response, request, errorResponse)
 				return
 				return
 			} else {
 			} else {
-				//Create a new JWT for the node
 				tokenString, _ := logic.CreateJWT(authRequest.MacAddress, result.Network)
 				tokenString, _ := logic.CreateJWT(authRequest.MacAddress, result.Network)
 
 
 				if tokenString == "" {
 				if tokenString == "" {
@@ -123,7 +114,6 @@ func authenticate(response http.ResponseWriter, request *http.Request) {
 						MacAddress: authRequest.MacAddress,
 						MacAddress: authRequest.MacAddress,
 					},
 					},
 				}
 				}
-				//Send back the JWT
 				successJSONResponse, jsonError := json.Marshal(successResponse)
 				successJSONResponse, jsonError := json.Marshal(successResponse)
 
 
 				if jsonError != nil {
 				if jsonError != nil {
@@ -186,10 +176,6 @@ func authorize(networkCheck bool, authNetwork string, next http.Handler) http.Ha
 				return
 				return
 			}
 			}
 
 
-			//This checks if
-			//A: the token is the master password
-			//B: the token corresponds to a mac address, and if so, which one
-			//TODO: There's probably a better way of dealing with the "master token"/master password. Plz Help.
 			var isAuthorized = false
 			var isAuthorized = false
 			var macaddress = ""
 			var macaddress = ""
 			username, networks, isadmin, errN := logic.VerifyUserToken(authToken)
 			username, networks, isadmin, errN := logic.VerifyUserToken(authToken)
@@ -275,7 +261,7 @@ func getNetworkNodes(w http.ResponseWriter, r *http.Request) {
 	}
 	}
 
 
 	//Returns all the nodes in JSON format
 	//Returns all the nodes in JSON format
-	functions.PrintUserLog(r.Header.Get("user"), "fetched nodes on network"+networkName, 2)
+	logger.Log(2, r.Header.Get("user"), "fetched nodes on network", networkName)
 	w.WriteHeader(http.StatusOK)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(nodes)
 	json.NewEncoder(w).Encode(nodes)
 }
 }
@@ -304,7 +290,7 @@ func getAllNodes(w http.ResponseWriter, r *http.Request) {
 		}
 		}
 	}
 	}
 	//Return all the nodes in JSON format
 	//Return all the nodes in JSON format
-	functions.PrintUserLog(r.Header.Get("user"), "fetched nodes", 2)
+	logger.Log(2, r.Header.Get("user"), "fetched nodes")
 	w.WriteHeader(http.StatusOK)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(nodes)
 	json.NewEncoder(w).Encode(nodes)
 }
 }
@@ -329,12 +315,12 @@ func getNode(w http.ResponseWriter, r *http.Request) {
 
 
 	var params = mux.Vars(r)
 	var params = mux.Vars(r)
 
 
-	node, err := GetNode(params["macaddress"], params["network"])
+	node, err := logic.GetNode(params["macaddress"], params["network"])
 	if err != nil {
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 		return
 	}
 	}
-	functions.PrintUserLog(r.Header.Get("user"), "fetched node "+params["macaddress"], 2)
+	logger.Log(2, r.Header.Get("user"), "fetched node", params["macaddress"])
 	w.WriteHeader(http.StatusOK)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(node)
 	json.NewEncoder(w).Encode(node)
 }
 }
@@ -348,12 +334,12 @@ func getLastModified(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")
 
 
 	var params = mux.Vars(r)
 	var params = mux.Vars(r)
-	network, err := GetNetwork(params["network"])
+	network, err := logic.GetNetwork(params["network"])
 	if err != nil {
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 		return
 	}
 	}
-	functions.PrintUserLog(r.Header.Get("user"), "called last modified", 2)
+	logger.Log(2, r.Header.Get("user"), "called last modified")
 	w.WriteHeader(http.StatusOK)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(network.NodesLastModified)
 	json.NewEncoder(w).Encode(network.NodesLastModified)
 }
 }
@@ -380,7 +366,7 @@ func createNode(w http.ResponseWriter, r *http.Request) {
 		return
 		return
 	}
 	}
 
 
-	var node models.Node
+	var node = models.Node{}
 
 
 	//get node from body of request
 	//get node from body of request
 	err = json.NewDecoder(r.Body).Decode(&node)
 	err = json.NewDecoder(r.Body).Decode(&node)
@@ -397,8 +383,6 @@ func createNode(w http.ResponseWriter, r *http.Request) {
 		return
 		return
 	}
 	}
 
 
-	//Check to see if key is valid
-	//TODO: Triple inefficient!!! This is the third call to the DB we make for networks
 	validKey := logic.IsKeyValid(networkName, node.AccessKey)
 	validKey := logic.IsKeyValid(networkName, node.AccessKey)
 
 
 	if !validKey {
 	if !validKey {
@@ -415,12 +399,12 @@ func createNode(w http.ResponseWriter, r *http.Request) {
 		}
 		}
 	}
 	}
 
 
-	node, err = logic.CreateNode(node, networkName)
+	err = logic.CreateNode(&node)
 	if err != nil {
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 		return
 	}
 	}
-	functions.PrintUserLog(r.Header.Get("user"), "created new node "+node.Name+" on network "+node.Network, 1)
+	logger.Log(1, r.Header.Get("user"), "created new node", node.Name, "on network", node.Network)
 	w.WriteHeader(http.StatusOK)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(node)
 	json.NewEncoder(w).Encode(node)
 }
 }
@@ -430,38 +414,16 @@ func createNode(w http.ResponseWriter, r *http.Request) {
 func uncordonNode(w http.ResponseWriter, r *http.Request) {
 func uncordonNode(w http.ResponseWriter, r *http.Request) {
 	var params = mux.Vars(r)
 	var params = mux.Vars(r)
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")
-	node, err := UncordonNode(params["network"], params["macaddress"])
+	node, err := logic.UncordonNode(params["network"], params["macaddress"])
 	if err != nil {
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 		return
 	}
 	}
-	functions.PrintUserLog(r.Header.Get("user"), "uncordoned node "+node.Name, 1)
+	logger.Log(1, r.Header.Get("user"), "uncordoned node", node.Name)
 	w.WriteHeader(http.StatusOK)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode("SUCCESS")
 	json.NewEncoder(w).Encode("SUCCESS")
 }
 }
 
 
-// UncordonNode - approves a node to join a network
-func UncordonNode(network, macaddress string) (models.Node, error) {
-	node, err := logic.GetNodeByMacAddress(network, macaddress)
-	if err != nil {
-		return models.Node{}, err
-	}
-	node.SetLastModified()
-	node.IsPending = "no"
-	node.PullChanges = "yes"
-	data, err := json.Marshal(&node)
-	if err != nil {
-		return node, err
-	}
-	key, err := logic.GetRecordKey(node.MacAddress, node.Network)
-	if err != nil {
-		return node, err
-	}
-
-	err = database.Insert(key, string(data), database.NODES_TABLE_NAME)
-	return node, err
-}
-
 func createEgressGateway(w http.ResponseWriter, r *http.Request) {
 func createEgressGateway(w http.ResponseWriter, r *http.Request) {
 	var gateway models.EgressGatewayRequest
 	var gateway models.EgressGatewayRequest
 	var params = mux.Vars(r)
 	var params = mux.Vars(r)
@@ -473,253 +435,62 @@ func createEgressGateway(w http.ResponseWriter, r *http.Request) {
 	}
 	}
 	gateway.NetID = params["network"]
 	gateway.NetID = params["network"]
 	gateway.NodeID = params["macaddress"]
 	gateway.NodeID = params["macaddress"]
-	node, err := CreateEgressGateway(gateway)
+	node, err := logic.CreateEgressGateway(gateway)
 	if err != nil {
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 		return
 	}
 	}
-	functions.PrintUserLog(r.Header.Get("user"), "created egress gateway on node "+gateway.NodeID+" on network "+gateway.NetID, 1)
+	logger.Log(1, r.Header.Get("user"), "created egress gateway on node", gateway.NodeID, "on network", gateway.NetID)
 	w.WriteHeader(http.StatusOK)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(node)
 	json.NewEncoder(w).Encode(node)
 }
 }
 
 
-// CreateEgressGateway - creates an egress gateway
-func CreateEgressGateway(gateway models.EgressGatewayRequest) (models.Node, error) {
-	node, err := logic.GetNodeByMacAddress(gateway.NetID, gateway.NodeID)
-	if node.OS == "windows" || node.OS == "macos" { // add in darwin later
-		return models.Node{}, errors.New(node.OS + " is unsupported for egress gateways")
-	}
-	if err != nil {
-		return models.Node{}, err
-	}
-	err = ValidateEgressGateway(gateway)
-	if err != nil {
-		return models.Node{}, err
-	}
-	node.IsEgressGateway = "yes"
-	node.EgressGatewayRanges = gateway.Ranges
-	postUpCmd := "iptables -A FORWARD -i " + node.Interface + " -j ACCEPT; iptables -t nat -A POSTROUTING -o " + gateway.Interface + " -j MASQUERADE"
-	postDownCmd := "iptables -D FORWARD -i " + node.Interface + " -j ACCEPT; iptables -t nat -D POSTROUTING -o " + gateway.Interface + " -j MASQUERADE"
-	if gateway.PostUp != "" {
-		postUpCmd = gateway.PostUp
-	}
-	if gateway.PostDown != "" {
-		postDownCmd = gateway.PostDown
-	}
-	if node.PostUp != "" {
-		if !strings.Contains(node.PostUp, postUpCmd) {
-			postUpCmd = node.PostUp + "; " + postUpCmd
-		}
-	}
-	if node.PostDown != "" {
-		if !strings.Contains(node.PostDown, postDownCmd) {
-			postDownCmd = node.PostDown + "; " + postDownCmd
-		}
-	}
-	key, err := logic.GetRecordKey(gateway.NodeID, gateway.NetID)
-	if err != nil {
-		return node, err
-	}
-	node.PostUp = postUpCmd
-	node.PostDown = postDownCmd
-	node.SetLastModified()
-	node.PullChanges = "yes"
-	nodeData, err := json.Marshal(&node)
-	if err != nil {
-		return node, err
-	}
-	if err = database.Insert(key, string(nodeData), database.NODES_TABLE_NAME); err != nil {
-		return models.Node{}, err
-	}
-	if err = functions.NetworkNodesUpdatePullChanges(node.Network); err != nil {
-		return models.Node{}, err
-	}
-	return node, nil
-}
-
-func ValidateEgressGateway(gateway models.EgressGatewayRequest) error {
-	var err error
-	//isIp := functions.IsIpCIDR(gateway.RangeString)
-	empty := len(gateway.Ranges) == 0
-	if empty {
-		err = errors.New("IP Ranges Cannot Be Empty")
-	}
-	empty = gateway.Interface == ""
-	if empty {
-		err = errors.New("Interface cannot be empty")
-	}
-	return err
-}
-
 func deleteEgressGateway(w http.ResponseWriter, r *http.Request) {
 func deleteEgressGateway(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")
 	var params = mux.Vars(r)
 	var params = mux.Vars(r)
 	nodeMac := params["macaddress"]
 	nodeMac := params["macaddress"]
 	netid := params["network"]
 	netid := params["network"]
-	node, err := DeleteEgressGateway(netid, nodeMac)
+	node, err := logic.DeleteEgressGateway(netid, nodeMac)
 	if err != nil {
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 		return
 	}
 	}
-	functions.PrintUserLog(r.Header.Get("user"), "deleted egress gateway "+nodeMac+" on network "+netid, 1)
+	logger.Log(1, r.Header.Get("user"), "deleted egress gateway", nodeMac, "on network", netid)
 	w.WriteHeader(http.StatusOK)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(node)
 	json.NewEncoder(w).Encode(node)
 }
 }
 
 
-// DeleteEgressGateway - deletes egress from node
-func DeleteEgressGateway(network, macaddress string) (models.Node, error) {
-
-	node, err := logic.GetNodeByMacAddress(network, macaddress)
-	if err != nil {
-		return models.Node{}, err
-	}
-
-	node.IsEgressGateway = "no"
-	node.EgressGatewayRanges = []string{}
-	node.PostUp = ""
-	node.PostDown = ""
-	if node.IsIngressGateway == "yes" { // check if node is still an ingress gateway before completely deleting postdown/up rules
-		node.PostUp = "iptables -A FORWARD -i " + node.Interface + " -j ACCEPT; iptables -t nat -A POSTROUTING -o " + node.Interface + " -j MASQUERADE"
-		node.PostDown = "iptables -D FORWARD -i " + node.Interface + " -j ACCEPT; iptables -t nat -D POSTROUTING -o " + node.Interface + " -j MASQUERADE"
-	}
-	node.SetLastModified()
-	node.PullChanges = "yes"
-	key, err := logic.GetRecordKey(node.MacAddress, node.Network)
-	if err != nil {
-		return models.Node{}, err
-	}
-	data, err := json.Marshal(&node)
-	if err != nil {
-		return models.Node{}, err
-	}
-	if err = database.Insert(key, string(data), database.NODES_TABLE_NAME); err != nil {
-		return models.Node{}, err
-	}
-	if err = functions.NetworkNodesUpdatePullChanges(network); err != nil {
-		return models.Node{}, err
-	}
-	return node, nil
-}
-
 // == INGRESS ==
 // == INGRESS ==
+
 func createIngressGateway(w http.ResponseWriter, r *http.Request) {
 func createIngressGateway(w http.ResponseWriter, r *http.Request) {
 	var params = mux.Vars(r)
 	var params = mux.Vars(r)
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")
 	nodeMac := params["macaddress"]
 	nodeMac := params["macaddress"]
 	netid := params["network"]
 	netid := params["network"]
-	node, err := CreateIngressGateway(netid, nodeMac)
+	node, err := logic.CreateIngressGateway(netid, nodeMac)
 	if err != nil {
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 		return
 	}
 	}
-	functions.PrintUserLog(r.Header.Get("user"), "created ingress gateway on node "+nodeMac+" on network "+netid, 1)
+	logger.Log(1, r.Header.Get("user"), "created ingress gateway on node", nodeMac, "on network", netid)
 	w.WriteHeader(http.StatusOK)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(node)
 	json.NewEncoder(w).Encode(node)
 }
 }
 
 
-// CreateIngressGateway - creates an ingress gateway
-func CreateIngressGateway(netid string, macaddress string) (models.Node, error) {
-
-	node, err := logic.GetNodeByMacAddress(netid, macaddress)
-	if node.OS == "windows" || node.OS == "macos" { // add in darwin later
-		return models.Node{}, errors.New(node.OS + " is unsupported for ingress gateways")
-	}
-
-	if err != nil {
-		return models.Node{}, err
-	}
-
-	network, err := logic.GetParentNetwork(netid)
-	if err != nil {
-		return models.Node{}, err
-	}
-	node.IsIngressGateway = "yes"
-	node.IngressGatewayRange = network.AddressRange
-	postUpCmd := "iptables -A FORWARD -i " + node.Interface + " -j ACCEPT; iptables -t nat -A POSTROUTING -o " + node.Interface + " -j MASQUERADE"
-	postDownCmd := "iptables -D FORWARD -i " + node.Interface + " -j ACCEPT; iptables -t nat -D POSTROUTING -o " + node.Interface + " -j MASQUERADE"
-	if node.PostUp != "" {
-		if !strings.Contains(node.PostUp, postUpCmd) {
-			postUpCmd = node.PostUp + "; " + postUpCmd
-		}
-	}
-	if node.PostDown != "" {
-		if !strings.Contains(node.PostDown, postDownCmd) {
-			postDownCmd = node.PostDown + "; " + postDownCmd
-		}
-	}
-	node.SetLastModified()
-	node.PostUp = postUpCmd
-	node.PostDown = postDownCmd
-	node.PullChanges = "yes"
-	node.UDPHolePunch = "no"
-	key, err := logic.GetRecordKey(node.MacAddress, node.Network)
-	if err != nil {
-		return models.Node{}, err
-	}
-	data, err := json.Marshal(&node)
-	if err != nil {
-		return models.Node{}, err
-	}
-	err = database.Insert(key, string(data), database.NODES_TABLE_NAME)
-	if err != nil {
-		return models.Node{}, err
-	}
-	err = logic.SetNetworkNodesLastModified(netid)
-	return node, err
-}
-
 func deleteIngressGateway(w http.ResponseWriter, r *http.Request) {
 func deleteIngressGateway(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")
 	var params = mux.Vars(r)
 	var params = mux.Vars(r)
 	nodeMac := params["macaddress"]
 	nodeMac := params["macaddress"]
-	node, err := DeleteIngressGateway(params["network"], nodeMac)
+	node, err := logic.DeleteIngressGateway(params["network"], nodeMac)
 	if err != nil {
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 		return
 	}
 	}
-	functions.PrintUserLog(r.Header.Get("user"), "deleted ingress gateway"+nodeMac, 1)
+	logger.Log(1, r.Header.Get("user"), "deleted ingress gateway", nodeMac)
 	w.WriteHeader(http.StatusOK)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(node)
 	json.NewEncoder(w).Encode(node)
 }
 }
 
 
-// DeleteIngressGateway - deletes an ingress gateway
-func DeleteIngressGateway(networkName string, macaddress string) (models.Node, error) {
-
-	node, err := logic.GetNodeByMacAddress(networkName, macaddress)
-	if err != nil {
-		return models.Node{}, err
-	}
-	network, err := logic.GetParentNetwork(networkName)
-	if err != nil {
-		return models.Node{}, err
-	}
-	// delete ext clients belonging to ingress gateway
-	if err = DeleteGatewayExtClients(macaddress, networkName); err != nil {
-		return models.Node{}, err
-	}
-
-	node.UDPHolePunch = network.DefaultUDPHolePunch
-	node.LastModified = time.Now().Unix()
-	node.IsIngressGateway = "no"
-	node.IngressGatewayRange = ""
-	node.PullChanges = "yes"
-
-	key, err := logic.GetRecordKey(node.MacAddress, node.Network)
-	if err != nil {
-		return models.Node{}, err
-	}
-	data, err := json.Marshal(&node)
-	if err != nil {
-		return models.Node{}, err
-	}
-	err = database.Insert(key, string(data), database.NODES_TABLE_NAME)
-	if err != nil {
-		return models.Node{}, err
-	}
-	err = logic.SetNetworkNodesLastModified(networkName)
-	return node, err
-}
-
 func updateNode(w http.ResponseWriter, r *http.Request) {
 func updateNode(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")
 
 
@@ -759,9 +530,9 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
 		return
 		return
 	}
 	}
 	if relayupdate {
 	if relayupdate {
-		UpdateRelay(node.Network, node.RelayAddrs, newNode.RelayAddrs)
-		if err = functions.NetworkNodesUpdatePullChanges(node.Network); err != nil {
-			functions.PrintUserLog("netmaker", "error setting relay updates: "+err.Error(), 1)
+		logic.UpdateRelay(node.Network, node.RelayAddrs, newNode.RelayAddrs)
+		if err = logic.NetworkNodesUpdatePullChanges(node.Network); err != nil {
+			logger.Log(1, "error setting relay updates:", err.Error())
 		}
 		}
 	}
 	}
 
 
@@ -772,26 +543,28 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 		return
 	}
 	}
-	functions.PrintUserLog(r.Header.Get("user"), "updated node "+node.MacAddress+" on network "+node.Network, 1)
+	logger.Log(1, r.Header.Get("user"), "updated node", node.MacAddress, "on network", node.Network)
 	w.WriteHeader(http.StatusOK)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(newNode)
 	json.NewEncoder(w).Encode(newNode)
 }
 }
 
 
-//Delete a node
-//Pretty straightforward
 func deleteNode(w http.ResponseWriter, r *http.Request) {
 func deleteNode(w http.ResponseWriter, r *http.Request) {
 	// Set header
 	// Set header
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")
 
 
 	// get params
 	// get params
 	var params = mux.Vars(r)
 	var params = mux.Vars(r)
-
-	err := DeleteNode(params["macaddress"]+"###"+params["network"], false)
-
+	var node, err = logic.GetNode(params["macaddress"], params["network"])
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "badrequest"))
+		return
+	}
+	err = logic.DeleteNode(&node, false)
 	if err != nil {
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 		return
 	}
 	}
-	functions.PrintUserLog(r.Header.Get("user"), "Deleted node "+params["macaddress"]+" from network "+params["network"], 1)
+
+	logger.Log(1, r.Header.Get("user"), "Deleted node", params["macaddress"], "from network", params["network"])
 	returnSuccessResponse(w, r, params["macaddress"]+" deleted.")
 	returnSuccessResponse(w, r, params["macaddress"]+" deleted.")
 }
 }

+ 18 - 21
controllers/nodeGrpcController.go → controllers/node_grpc.go

@@ -6,8 +6,8 @@ import (
 	"errors"
 	"errors"
 	"strings"
 	"strings"
 
 
-	"github.com/gravitl/netmaker/functions"
 	nodepb "github.com/gravitl/netmaker/grpc"
 	nodepb "github.com/gravitl/netmaker/grpc"
+	"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"
 )
 )
@@ -25,7 +25,7 @@ func (s *NodeServiceServer) ReadNode(ctx context.Context, req *nodepb.Object) (*
 	if len(macAndNetwork) != 2 {
 	if len(macAndNetwork) != 2 {
 		return nil, errors.New("could not read node, invalid node id given")
 		return nil, errors.New("could not read node, invalid node id given")
 	}
 	}
-	node, err := GetNode(macAndNetwork[0], macAndNetwork[1])
+	node, err := logic.GetNode(macAndNetwork[0], macAndNetwork[1])
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -49,49 +49,42 @@ func (s *NodeServiceServer) ReadNode(ctx context.Context, req *nodepb.Object) (*
 
 
 // NodeServiceServer.CreateNode - creates a node and responds over gRPC
 // NodeServiceServer.CreateNode - creates a node and responds over gRPC
 func (s *NodeServiceServer) CreateNode(ctx context.Context, req *nodepb.Object) (*nodepb.Object, error) {
 func (s *NodeServiceServer) CreateNode(ctx context.Context, req *nodepb.Object) (*nodepb.Object, error) {
-	// Get the protobuf node type from the protobuf request type
-	// Essentially doing req.Node to access the struct with a nil check
-	var node models.Node
+	var node = models.Node{}
+	var err error
 	data := req.GetData()
 	data := req.GetData()
 	if err := json.Unmarshal([]byte(data), &node); err != nil {
 	if err := json.Unmarshal([]byte(data), &node); err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	//Check to see if key is valid
-	//TODO: Triple inefficient!!! This is the third call to the DB we make for networks
 	validKey := logic.IsKeyValid(node.Network, node.AccessKey)
 	validKey := logic.IsKeyValid(node.Network, node.AccessKey)
-	network, err := logic.GetParentNetwork(node.Network)
+	node.NetworkSettings, err = logic.GetNetworkSettings(node.Network)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
 
 
 	if !validKey {
 	if !validKey {
-		//Check to see if network will allow manual sign up
-		//may want to switch this up with the valid key check and avoid a DB call that way.
-		if network.AllowManualSignUp == "yes" {
+		if node.NetworkSettings.AllowManualSignUp == "yes" {
 			node.IsPending = "yes"
 			node.IsPending = "yes"
 		} else {
 		} else {
 			return nil, errors.New("invalid key, and network does not allow no-key signups")
 			return nil, errors.New("invalid key, and network does not allow no-key signups")
 		}
 		}
 	}
 	}
 
 
-	node, err = logic.CreateNode(node, node.Network)
-	if err != nil {
-		return nil, err
-	}
-	node.NetworkSettings, err = logic.GetNetworkSettings(node.Network)
+	err = logic.CreateNode(&node)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
+
 	nodeData, errN := json.Marshal(&node)
 	nodeData, errN := json.Marshal(&node)
 	if errN != nil {
 	if errN != nil {
 		return nil, err
 		return nil, err
 	}
 	}
-	// return the node in a CreateNodeRes type
+
 	response := &nodepb.Object{
 	response := &nodepb.Object{
 		Data: string(nodeData),
 		Data: string(nodeData),
 		Type: nodepb.NODE_TYPE,
 		Type: nodepb.NODE_TYPE,
 	}
 	}
+
 	err = logic.SetNetworkNodesLastModified(node.Network)
 	err = logic.SetNetworkNodesLastModified(node.Network)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
@@ -135,8 +128,12 @@ func (s *NodeServiceServer) UpdateNode(ctx context.Context, req *nodepb.Object)
 // NodeServiceServer.DeleteNode - deletes a node and responds over gRPC
 // NodeServiceServer.DeleteNode - deletes a node and responds over gRPC
 func (s *NodeServiceServer) DeleteNode(ctx context.Context, req *nodepb.Object) (*nodepb.Object, error) {
 func (s *NodeServiceServer) DeleteNode(ctx context.Context, req *nodepb.Object) (*nodepb.Object, error) {
 	nodeID := req.GetData()
 	nodeID := req.GetData()
-
-	err := DeleteNode(nodeID, true)
+	var nodeInfo = strings.Split(nodeID, "###")
+	if len(nodeInfo) != 2 {
+		return nil, errors.New("node not found")
+	}
+	var node, err = logic.GetNode(nodeInfo[0], nodeInfo[1])
+	err = logic.DeleteNode(&node, true)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -152,7 +149,7 @@ func (s *NodeServiceServer) GetPeers(ctx context.Context, req *nodepb.Object) (*
 	macAndNetwork := strings.Split(req.Data, "###")
 	macAndNetwork := strings.Split(req.Data, "###")
 	if len(macAndNetwork) == 2 {
 	if len(macAndNetwork) == 2 {
 		// TODO: Make constant and new variable for isServer
 		// TODO: Make constant and new variable for isServer
-		node, err := GetNode(macAndNetwork[0], macAndNetwork[1])
+		node, err := logic.GetNode(macAndNetwork[0], macAndNetwork[1])
 		if err != nil {
 		if err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
@@ -170,7 +167,7 @@ func (s *NodeServiceServer) GetPeers(ctx context.Context, req *nodepb.Object) (*
 		}
 		}
 
 
 		peersData, err := json.Marshal(&peers)
 		peersData, err := json.Marshal(&peers)
-		functions.PrintUserLog(node.Address, "checked in successfully", 3)
+		logger.Log(3, node.Address, "checked in successfully")
 		return &nodepb.Object{
 		return &nodepb.Object{
 			Data: string(peersData),
 			Data: string(peersData),
 			Type: nodepb.NODE_TYPE,
 			Type: nodepb.NODE_TYPE,

+ 20 - 18
controllers/nodeHttpController_test.go → controllers/node_test.go

@@ -17,7 +17,7 @@ func TestCreateEgressGateway(t *testing.T) {
 	deleteAllNetworks()
 	deleteAllNetworks()
 	createNet()
 	createNet()
 	t.Run("NoNodes", func(t *testing.T) {
 	t.Run("NoNodes", func(t *testing.T) {
-		node, err := CreateEgressGateway(gateway)
+		node, err := logic.CreateEgressGateway(gateway)
 		assert.Equal(t, models.Node{}, node)
 		assert.Equal(t, models.Node{}, node)
 		assert.EqualError(t, err, "unable to get record key")
 		assert.EqualError(t, err, "unable to get record key")
 	})
 	})
@@ -26,7 +26,7 @@ func TestCreateEgressGateway(t *testing.T) {
 		gateway.NetID = "skynet"
 		gateway.NetID = "skynet"
 		gateway.NodeID = testnode.MacAddress
 		gateway.NodeID = testnode.MacAddress
 
 
-		node, err := CreateEgressGateway(gateway)
+		node, err := logic.CreateEgressGateway(gateway)
 		assert.Nil(t, err)
 		assert.Nil(t, err)
 		assert.Equal(t, "yes", node.IsEgressGateway)
 		assert.Equal(t, "yes", node.IsEgressGateway)
 		assert.Equal(t, gateway.Ranges, node.EgressGatewayRanges)
 		assert.Equal(t, gateway.Ranges, node.EgressGatewayRanges)
@@ -45,11 +45,11 @@ func TestDeleteEgressGateway(t *testing.T) {
 	gateway.NetID = "skynet"
 	gateway.NetID = "skynet"
 	gateway.NodeID = testnode.MacAddress
 	gateway.NodeID = testnode.MacAddress
 	t.Run("Success", func(t *testing.T) {
 	t.Run("Success", func(t *testing.T) {
-		node, err := CreateEgressGateway(gateway)
+		node, err := logic.CreateEgressGateway(gateway)
 		assert.Nil(t, err)
 		assert.Nil(t, err)
 		assert.Equal(t, "yes", node.IsEgressGateway)
 		assert.Equal(t, "yes", node.IsEgressGateway)
 		assert.Equal(t, []string{"10.100.100.0/24"}, node.EgressGatewayRanges)
 		assert.Equal(t, []string{"10.100.100.0/24"}, node.EgressGatewayRanges)
-		node, err = DeleteEgressGateway(gateway.NetID, gateway.NodeID)
+		node, err = logic.DeleteEgressGateway(gateway.NetID, gateway.NodeID)
 		assert.Nil(t, err)
 		assert.Nil(t, err)
 		assert.Equal(t, "no", node.IsEgressGateway)
 		assert.Equal(t, "no", node.IsEgressGateway)
 		assert.Equal(t, []string([]string{}), node.EgressGatewayRanges)
 		assert.Equal(t, []string([]string{}), node.EgressGatewayRanges)
@@ -57,7 +57,7 @@ func TestDeleteEgressGateway(t *testing.T) {
 		assert.Equal(t, "", node.PostDown)
 		assert.Equal(t, "", node.PostDown)
 	})
 	})
 	t.Run("NotGateway", func(t *testing.T) {
 	t.Run("NotGateway", func(t *testing.T) {
-		node, err := DeleteEgressGateway(gateway.NetID, gateway.NodeID)
+		node, err := logic.DeleteEgressGateway(gateway.NetID, gateway.NodeID)
 		assert.Nil(t, err)
 		assert.Nil(t, err)
 		assert.Equal(t, "no", node.IsEgressGateway)
 		assert.Equal(t, "no", node.IsEgressGateway)
 		assert.Equal(t, []string([]string{}), node.EgressGatewayRanges)
 		assert.Equal(t, []string([]string{}), node.EgressGatewayRanges)
@@ -65,12 +65,12 @@ func TestDeleteEgressGateway(t *testing.T) {
 		assert.Equal(t, "", node.PostDown)
 		assert.Equal(t, "", node.PostDown)
 	})
 	})
 	t.Run("BadNode", func(t *testing.T) {
 	t.Run("BadNode", func(t *testing.T) {
-		node, err := DeleteEgressGateway(gateway.NetID, "01:02:03")
+		node, err := logic.DeleteEgressGateway(gateway.NetID, "01:02:03")
 		assert.EqualError(t, err, "no result found")
 		assert.EqualError(t, err, "no result found")
 		assert.Equal(t, models.Node{}, node)
 		assert.Equal(t, models.Node{}, node)
 	})
 	})
 	t.Run("BadNet", func(t *testing.T) {
 	t.Run("BadNet", func(t *testing.T) {
-		node, err := DeleteEgressGateway("badnet", gateway.NodeID)
+		node, err := logic.DeleteEgressGateway("badnet", gateway.NodeID)
 		assert.EqualError(t, err, "no result found")
 		assert.EqualError(t, err, "no result found")
 		assert.Equal(t, models.Node{}, node)
 		assert.Equal(t, models.Node{}, node)
 	})
 	})
@@ -106,17 +106,17 @@ func TestUncordonNode(t *testing.T) {
 	createNet()
 	createNet()
 	node := createTestNode()
 	node := createTestNode()
 	t.Run("BadNet", func(t *testing.T) {
 	t.Run("BadNet", func(t *testing.T) {
-		resp, err := UncordonNode("badnet", node.MacAddress)
+		resp, err := logic.UncordonNode("badnet", node.MacAddress)
 		assert.Equal(t, models.Node{}, resp)
 		assert.Equal(t, models.Node{}, resp)
 		assert.EqualError(t, err, "no result found")
 		assert.EqualError(t, err, "no result found")
 	})
 	})
 	t.Run("BadMac", func(t *testing.T) {
 	t.Run("BadMac", func(t *testing.T) {
-		resp, err := UncordonNode("skynet", "01:02:03")
+		resp, err := logic.UncordonNode("skynet", "01:02:03")
 		assert.Equal(t, models.Node{}, resp)
 		assert.Equal(t, models.Node{}, resp)
 		assert.EqualError(t, err, "no result found")
 		assert.EqualError(t, err, "no result found")
 	})
 	})
 	t.Run("Success", func(t *testing.T) {
 	t.Run("Success", func(t *testing.T) {
-		resp, err := UncordonNode("skynet", node.MacAddress)
+		resp, err := logic.UncordonNode("skynet", node.MacAddress)
 		assert.Nil(t, err)
 		assert.Nil(t, err)
 		assert.Equal(t, "no", resp.IsPending)
 		assert.Equal(t, "no", resp.IsPending)
 	})
 	})
@@ -127,30 +127,32 @@ func TestValidateEgressGateway(t *testing.T) {
 	t.Run("EmptyRange", func(t *testing.T) {
 	t.Run("EmptyRange", func(t *testing.T) {
 		gateway.Interface = "eth0"
 		gateway.Interface = "eth0"
 		gateway.Ranges = []string{}
 		gateway.Ranges = []string{}
-		err := ValidateEgressGateway(gateway)
+		err := logic.ValidateEgressGateway(gateway)
 		assert.EqualError(t, err, "IP Ranges Cannot Be Empty")
 		assert.EqualError(t, err, "IP Ranges Cannot Be Empty")
 	})
 	})
 	t.Run("EmptyInterface", func(t *testing.T) {
 	t.Run("EmptyInterface", func(t *testing.T) {
 		gateway.Interface = ""
 		gateway.Interface = ""
-		err := ValidateEgressGateway(gateway)
+		err := logic.ValidateEgressGateway(gateway)
 		assert.NotNil(t, err)
 		assert.NotNil(t, err)
 		assert.Equal(t, "Interface cannot be empty", err.Error())
 		assert.Equal(t, "Interface cannot be empty", err.Error())
 	})
 	})
 	t.Run("Success", func(t *testing.T) {
 	t.Run("Success", func(t *testing.T) {
 		gateway.Interface = "eth0"
 		gateway.Interface = "eth0"
 		gateway.Ranges = []string{"10.100.100.0/24"}
 		gateway.Ranges = []string{"10.100.100.0/24"}
-		err := ValidateEgressGateway(gateway)
+		err := logic.ValidateEgressGateway(gateway)
 		assert.Nil(t, err)
 		assert.Nil(t, err)
 	})
 	})
 }
 }
 
 
-//
-////func TestUpdateNode(t *testing.T) {
-////}
 func deleteAllNodes() {
 func deleteAllNodes() {
 	nodes, _ := logic.GetAllNodes()
 	nodes, _ := logic.GetAllNodes()
 	for _, node := range nodes {
 	for _, node := range nodes {
-		key := node.MacAddress + "###" + node.Network
-		DeleteNode(key, true)
+		logic.DeleteNode(&node, true)
 	}
 	}
 }
 }
+
+func createTestNode() *models.Node {
+	createnode := models.Node{PublicKey: "DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34=", Name: "testnode", Endpoint: "10.0.0.1", MacAddress: "01:02:03:04:05:06", Password: "password", Network: "skynet"}
+	logic.CreateNode(&createnode)
+	return &createnode
+}

+ 5 - 137
controllers/relay.go

@@ -2,13 +2,10 @@ package controller
 
 
 import (
 import (
 	"encoding/json"
 	"encoding/json"
-	"errors"
 	"net/http"
 	"net/http"
-	"time"
 
 
 	"github.com/gorilla/mux"
 	"github.com/gorilla/mux"
-	"github.com/gravitl/netmaker/database"
-	"github.com/gravitl/netmaker/functions"
+	"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"
 )
 )
@@ -24,156 +21,27 @@ func createRelay(w http.ResponseWriter, r *http.Request) {
 	}
 	}
 	relay.NetID = params["network"]
 	relay.NetID = params["network"]
 	relay.NodeID = params["macaddress"]
 	relay.NodeID = params["macaddress"]
-	node, err := CreateRelay(relay)
+	node, err := logic.CreateRelay(relay)
 	if err != nil {
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 		return
 	}
 	}
-	functions.PrintUserLog(r.Header.Get("user"), "created relay on node "+relay.NodeID+" on network "+relay.NetID, 1)
+	logger.Log(1, r.Header.Get("user"), "created relay on node", relay.NodeID, "on network", relay.NetID)
 	w.WriteHeader(http.StatusOK)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(node)
 	json.NewEncoder(w).Encode(node)
 }
 }
 
 
-// CreateRelay - creates a relay
-func CreateRelay(relay models.RelayRequest) (models.Node, error) {
-	node, err := logic.GetNodeByMacAddress(relay.NetID, relay.NodeID)
-	if node.OS == "macos" { // add in darwin later
-		return models.Node{}, errors.New(node.OS + " is unsupported for relay")
-	}
-	if err != nil {
-		return models.Node{}, err
-	}
-	err = ValidateRelay(relay)
-	if err != nil {
-		return models.Node{}, err
-	}
-	node.IsRelay = "yes"
-	node.RelayAddrs = relay.RelayAddrs
-
-	key, err := logic.GetRecordKey(relay.NodeID, relay.NetID)
-	if err != nil {
-		return node, err
-	}
-	node.SetLastModified()
-	node.PullChanges = "yes"
-	nodeData, err := json.Marshal(&node)
-	if err != nil {
-		return node, err
-	}
-	if err = database.Insert(key, string(nodeData), database.NODES_TABLE_NAME); err != nil {
-		return models.Node{}, err
-	}
-	err = SetRelayedNodes("yes", node.Network, node.RelayAddrs)
-	if err != nil {
-		return node, err
-	}
-
-	if err = functions.NetworkNodesUpdatePullChanges(node.Network); err != nil {
-		return models.Node{}, err
-	}
-	return node, nil
-}
-
 func deleteRelay(w http.ResponseWriter, r *http.Request) {
 func deleteRelay(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")
 	var params = mux.Vars(r)
 	var params = mux.Vars(r)
 	nodeMac := params["macaddress"]
 	nodeMac := params["macaddress"]
 	netid := params["network"]
 	netid := params["network"]
-	node, err := DeleteRelay(netid, nodeMac)
+	node, err := logic.DeleteRelay(netid, nodeMac)
 	if err != nil {
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 		return
 	}
 	}
-	functions.PrintUserLog(r.Header.Get("user"), "deleted egress gateway "+nodeMac+" on network "+netid, 1)
+	logger.Log(1, r.Header.Get("user"), "deleted egress gateway", nodeMac, "on network", netid)
 	w.WriteHeader(http.StatusOK)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(node)
 	json.NewEncoder(w).Encode(node)
 }
 }
-
-// SetRelayedNodes- set relayed nodes
-func SetRelayedNodes(yesOrno string, networkName string, addrs []string) error {
-
-	collections, err := database.FetchRecords(database.NODES_TABLE_NAME)
-	if err != nil {
-		return err
-	}
-
-	for _, value := range collections {
-
-		var node models.Node
-		err := json.Unmarshal([]byte(value), &node)
-		if err != nil {
-			return err
-		}
-		if node.Network == networkName {
-			for _, addr := range addrs {
-				if addr == node.Address || addr == node.Address6 {
-					node.IsRelayed = yesOrno
-					data, err := json.Marshal(&node)
-					if err != nil {
-						return err
-					}
-					node.SetID()
-					database.Insert(node.ID, string(data), database.NODES_TABLE_NAME)
-				}
-			}
-		}
-	}
-	return nil
-}
-
-// ValidateRelay - checks if relay is valid
-func ValidateRelay(relay models.RelayRequest) error {
-	var err error
-	//isIp := functions.IsIpCIDR(gateway.RangeString)
-	empty := len(relay.RelayAddrs) == 0
-	if empty {
-		err = errors.New("IP Ranges Cannot Be Empty")
-	}
-	return err
-}
-
-// UpdateRelay - updates a relay
-func UpdateRelay(network string, oldAddrs []string, newAddrs []string) {
-	time.Sleep(time.Second / 4)
-	err := SetRelayedNodes("no", network, oldAddrs)
-	if err != nil {
-		functions.PrintUserLog("netmaker", err.Error(), 1)
-	}
-	err = SetRelayedNodes("yes", network, newAddrs)
-	if err != nil {
-		functions.PrintUserLog("netmaker", err.Error(), 1)
-	}
-}
-
-// DeleteRelay - deletes a relay
-func DeleteRelay(network, macaddress string) (models.Node, error) {
-
-	node, err := logic.GetNodeByMacAddress(network, macaddress)
-	if err != nil {
-		return models.Node{}, err
-	}
-	err = SetRelayedNodes("no", node.Network, node.RelayAddrs)
-	if err != nil {
-		return node, err
-	}
-
-	node.IsRelay = "no"
-	node.RelayAddrs = []string{}
-	node.SetLastModified()
-	node.PullChanges = "yes"
-	key, err := logic.GetRecordKey(node.MacAddress, node.Network)
-	if err != nil {
-		return models.Node{}, err
-	}
-	data, err := json.Marshal(&node)
-	if err != nil {
-		return models.Node{}, err
-	}
-	if err = database.Insert(key, string(data), database.NODES_TABLE_NAME); err != nil {
-		return models.Node{}, err
-	}
-	if err = functions.NetworkNodesUpdatePullChanges(network); err != nil {
-		return models.Node{}, err
-	}
-	return node, nil
-}

+ 2 - 2
controllers/responseHttp.go → controllers/response.go

@@ -4,7 +4,7 @@ import (
 	"encoding/json"
 	"encoding/json"
 	"net/http"
 	"net/http"
 
 
-	"github.com/gravitl/netmaker/logic"
+	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/models"
 )
 )
 
 
@@ -48,7 +48,7 @@ func returnErrorResponse(response http.ResponseWriter, request *http.Request, er
 	if err != nil {
 	if err != nil {
 		panic(err)
 		panic(err)
 	}
 	}
-	logic.Log("processed request error: "+errorMessage.Message, 1)
+	logger.Log(1, "processed request error:", errorMessage.Message)
 	response.Header().Set("Content-Type", "application/json")
 	response.Header().Set("Content-Type", "application/json")
 	response.WriteHeader(errorMessage.Code)
 	response.WriteHeader(errorMessage.Code)
 	response.Write(jsonResponse)
 	response.Write(jsonResponse)

+ 0 - 0
controllers/responseHttp_test.go → controllers/response_test.go


+ 128 - 0
controllers/security.go

@@ -0,0 +1,128 @@
+package controller
+
+import (
+	"encoding/json"
+	"errors"
+	"net/http"
+	"strings"
+
+	"github.com/gorilla/mux"
+	"github.com/gravitl/netmaker/database"
+	"github.com/gravitl/netmaker/functions"
+	"github.com/gravitl/netmaker/logic"
+	"github.com/gravitl/netmaker/models"
+	"github.com/gravitl/netmaker/servercfg"
+)
+
+func securityCheck(reqAdmin bool, next http.Handler) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		var errorResponse = models.ErrorResponse{
+			Code: http.StatusUnauthorized, Message: "W1R3: It's not you it's me.",
+		}
+
+		var params = mux.Vars(r)
+		bearerToken := r.Header.Get("Authorization")
+		if strings.Contains(r.RequestURI, "/dns") && strings.ToUpper(r.Method) == "GET" && authenticateDNSToken(bearerToken) {
+			// do dns stuff
+			r.Header.Set("user", "nameserver")
+			networks, _ := json.Marshal([]string{ALL_NETWORK_ACCESS})
+			r.Header.Set("networks", string(networks))
+			next.ServeHTTP(w, r)
+			return
+		}
+
+		err, networks, username := SecurityCheck(reqAdmin, params["networkname"], bearerToken)
+		if err != nil {
+			if strings.Contains(err.Error(), "does not exist") {
+				errorResponse.Code = http.StatusNotFound
+			}
+			errorResponse.Message = err.Error()
+			returnErrorResponse(w, r, errorResponse)
+			return
+		}
+		networksJson, err := json.Marshal(&networks)
+		if err != nil {
+			errorResponse.Message = err.Error()
+			returnErrorResponse(w, r, errorResponse)
+			return
+		}
+		r.Header.Set("user", username)
+		r.Header.Set("networks", string(networksJson))
+		next.ServeHTTP(w, r)
+	}
+}
+
+// SecurityCheck - checks token stuff
+func SecurityCheck(reqAdmin bool, netname string, token string) (error, []string, string) {
+
+	var hasBearer = true
+	var tokenSplit = strings.Split(token, " ")
+	var authToken = ""
+
+	if len(tokenSplit) < 2 {
+		hasBearer = false
+	} else {
+		authToken = tokenSplit[1]
+	}
+	userNetworks := []string{}
+	//all endpoints here require master so not as complicated
+	isMasterAuthenticated := authenticateMaster(authToken)
+	username := ""
+	if !hasBearer || !isMasterAuthenticated {
+		userName, networks, isadmin, err := logic.VerifyUserToken(authToken)
+		username = userName
+		if err != nil {
+			return errors.New("error verifying user token"), nil, username
+		}
+		if !isadmin && reqAdmin {
+			return errors.New("you are unauthorized to access this endpoint"), nil, username
+		}
+		userNetworks = networks
+		if isadmin {
+			userNetworks = []string{ALL_NETWORK_ACCESS}
+		} else {
+			networkexists, err := functions.NetworkExists(netname)
+			if err != nil && !database.IsEmptyRecord(err) {
+				return err, nil, ""
+			}
+			if netname != "" && !networkexists {
+				return errors.New("this network does not exist"), nil, ""
+			}
+		}
+	} else if isMasterAuthenticated {
+		userNetworks = []string{ALL_NETWORK_ACCESS}
+	}
+	if len(userNetworks) == 0 {
+		userNetworks = append(userNetworks, NO_NETWORKS_PRESENT)
+	}
+	return nil, userNetworks, username
+}
+
+//Consider a more secure way of setting master key
+func authenticateMaster(tokenString string) bool {
+	return tokenString == servercfg.GetMasterKey()
+}
+
+//Consider a more secure way of setting master key
+func authenticateDNSToken(tokenString string) bool {
+	tokens := strings.Split(tokenString, " ")
+	if len(tokens) < 2 {
+		return false
+	}
+	return tokens[1] == servercfg.GetDNSKey()
+}
+
+func continueIfUserMatch(next http.Handler) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		var errorResponse = models.ErrorResponse{
+			Code: http.StatusUnauthorized, Message: "W1R3: This doesn't look like you.",
+		}
+		var params = mux.Vars(r)
+		var requestedUser = params["username"]
+		if requestedUser != r.Header.Get("user") {
+			returnErrorResponse(w, r, errorResponse)
+			return
+		}
+		next.ServeHTTP(w, r)
+	}
+}

+ 1 - 4
controllers/serverHttpController.go → controllers/server.go

@@ -60,10 +60,7 @@ func securityCheckServer(adminonly bool, next http.Handler) http.HandlerFunc {
 
 
 //Consider a more secure way of setting master key
 //Consider a more secure way of setting master key
 func authenticateMasterServer(tokenString string) bool {
 func authenticateMasterServer(tokenString string) bool {
-	if tokenString == servercfg.GetMasterKey() {
-		return true
-	}
-	return false
+	return tokenString == servercfg.GetMasterKey()
 }
 }
 
 
 func removeNetwork(w http.ResponseWriter, r *http.Request) {
 func removeNetwork(w http.ResponseWriter, r *http.Request) {

+ 17 - 91
controllers/userHttpController.go → controllers/user.go

@@ -5,12 +5,11 @@ import (
 	"errors"
 	"errors"
 	"fmt"
 	"fmt"
 	"net/http"
 	"net/http"
-	"strings"
 
 
 	"github.com/gorilla/mux"
 	"github.com/gorilla/mux"
 	"github.com/gravitl/netmaker/auth"
 	"github.com/gravitl/netmaker/auth"
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/database"
-	"github.com/gravitl/netmaker/functions"
+	"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"
 )
 )
@@ -20,13 +19,13 @@ func userHandlers(r *mux.Router) {
 	r.HandleFunc("/api/users/adm/hasadmin", hasAdmin).Methods("GET")
 	r.HandleFunc("/api/users/adm/hasadmin", hasAdmin).Methods("GET")
 	r.HandleFunc("/api/users/adm/createadmin", createAdmin).Methods("POST")
 	r.HandleFunc("/api/users/adm/createadmin", createAdmin).Methods("POST")
 	r.HandleFunc("/api/users/adm/authenticate", authenticateUser).Methods("POST")
 	r.HandleFunc("/api/users/adm/authenticate", authenticateUser).Methods("POST")
-	r.HandleFunc("/api/users/{username}", authorizeUser(http.HandlerFunc(updateUser))).Methods("PUT")
-	r.HandleFunc("/api/users/networks/{username}", authorizeUserAdm(http.HandlerFunc(updateUserNetworks))).Methods("PUT")
-	r.HandleFunc("/api/users/{username}/adm", authorizeUserAdm(http.HandlerFunc(updateUserAdm))).Methods("PUT")
-	r.HandleFunc("/api/users/{username}", authorizeUserAdm(http.HandlerFunc(createUser))).Methods("POST")
-	r.HandleFunc("/api/users/{username}", authorizeUser(http.HandlerFunc(deleteUser))).Methods("DELETE")
-	r.HandleFunc("/api/users/{username}", authorizeUser(http.HandlerFunc(getUser))).Methods("GET")
-	r.HandleFunc("/api/users", authorizeUserAdm(http.HandlerFunc(getUsers))).Methods("GET")
+	r.HandleFunc("/api/users/{username}", securityCheck(false, continueIfUserMatch(http.HandlerFunc(updateUser)))).Methods("PUT")
+	r.HandleFunc("/api/users/networks/{username}", securityCheck(true, http.HandlerFunc(updateUserNetworks))).Methods("PUT")
+	r.HandleFunc("/api/users/{username}/adm", securityCheck(true, http.HandlerFunc(updateUserAdm))).Methods("PUT")
+	r.HandleFunc("/api/users/{username}", securityCheck(true, http.HandlerFunc(createUser))).Methods("POST")
+	r.HandleFunc("/api/users/{username}", securityCheck(false, continueIfUserMatch(http.HandlerFunc(deleteUser)))).Methods("DELETE")
+	r.HandleFunc("/api/users/{username}", securityCheck(false, continueIfUserMatch(http.HandlerFunc(getUser)))).Methods("GET")
+	r.HandleFunc("/api/users", securityCheck(true, http.HandlerFunc(getUsers))).Methods("GET")
 	r.HandleFunc("/api/oauth/login", auth.HandleAuthLogin).Methods("GET")
 	r.HandleFunc("/api/oauth/login", auth.HandleAuthLogin).Methods("GET")
 	r.HandleFunc("/api/oauth/callback", auth.HandleAuthCallback).Methods("GET")
 	r.HandleFunc("/api/oauth/callback", auth.HandleAuthCallback).Methods("GET")
 }
 }
@@ -77,84 +76,11 @@ func authenticateUser(response http.ResponseWriter, request *http.Request) {
 		returnErrorResponse(response, request, errorResponse)
 		returnErrorResponse(response, request, errorResponse)
 		return
 		return
 	}
 	}
-	functions.PrintUserLog(username, "was authenticated", 2)
+	logger.Log(2, username, "was authenticated")
 	response.Header().Set("Content-Type", "application/json")
 	response.Header().Set("Content-Type", "application/json")
 	response.Write(successJSONResponse)
 	response.Write(successJSONResponse)
 }
 }
 
 
-// The middleware for most requests to the API
-// They all pass  through here first
-// This will validate the JWT (or check for master token)
-// This will also check against the authNetwork and make sure the node should be accessing that endpoint,
-// even if it's technically ok
-// This is kind of a poor man's RBAC. There's probably a better/smarter way.
-// TODO: Consider better RBAC implementations
-func authorizeUser(next http.Handler) http.HandlerFunc {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "application/json")
-		var params = mux.Vars(r)
-
-		// get the auth token
-		bearerToken := r.Header.Get("Authorization")
-		username := params["username"]
-		err := ValidateUserToken(bearerToken, username, false)
-		if err != nil {
-			returnErrorResponse(w, r, formatError(err, "unauthorized"))
-			return
-		}
-		r.Header.Set("user", username)
-		next.ServeHTTP(w, r)
-	}
-}
-
-func authorizeUserAdm(next http.Handler) http.HandlerFunc {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "application/json")
-		var params = mux.Vars(r)
-
-		//get the auth token
-		bearerToken := r.Header.Get("Authorization")
-		username := params["username"]
-		err := ValidateUserToken(bearerToken, username, true)
-		if err != nil {
-			returnErrorResponse(w, r, formatError(err, "unauthorized"))
-			return
-		}
-		r.Header.Set("user", username)
-		next.ServeHTTP(w, r)
-	}
-}
-
-// ValidateUserToken - self explained
-func ValidateUserToken(token string, user string, adminonly bool) error {
-	var tokenSplit = strings.Split(token, " ")
-	//I put this in in case the user doesn't put in a token at all (in which case it's empty)
-	//There's probably a smarter way of handling this.
-	var authToken = "928rt238tghgwe@TY@$Y@#WQAEGB2FC#@HG#@$Hddd"
-
-	if len(tokenSplit) > 1 {
-		authToken = tokenSplit[1]
-	} else {
-		return errors.New("Missing Auth Token.")
-	}
-
-	username, _, isadmin, err := logic.VerifyUserToken(authToken)
-	if err != nil {
-		return errors.New("Error Verifying Auth Token")
-	}
-	isAuthorized := false
-	if adminonly {
-		isAuthorized = isadmin
-	} else {
-		isAuthorized = username == user || isadmin
-	}
-	if !isAuthorized {
-		return errors.New("You are unauthorized to access this endpoint.")
-	}
-
-	return nil
-}
-
 func hasAdmin(w http.ResponseWriter, r *http.Request) {
 func hasAdmin(w http.ResponseWriter, r *http.Request) {
 
 
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")
@@ -196,7 +122,7 @@ func getUser(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 		return
 	}
 	}
-	functions.PrintUserLog(r.Header.Get("user"), "fetched user "+usernameFetched, 2)
+	logger.Log(2, r.Header.Get("user"), "fetched user", usernameFetched)
 	json.NewEncoder(w).Encode(user)
 	json.NewEncoder(w).Encode(user)
 }
 }
 
 
@@ -212,7 +138,7 @@ func getUsers(w http.ResponseWriter, r *http.Request) {
 		return
 		return
 	}
 	}
 
 
-	functions.PrintUserLog(r.Header.Get("user"), "fetched users", 2)
+	logger.Log(2, r.Header.Get("user"), "fetched users")
 	json.NewEncoder(w).Encode(users)
 	json.NewEncoder(w).Encode(users)
 }
 }
 
 
@@ -229,7 +155,7 @@ func createAdmin(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 		return
 	}
 	}
-	functions.PrintUserLog(admin.UserName, "was made a new admin", 1)
+	logger.Log(1, admin.UserName, "was made a new admin")
 	json.NewEncoder(w).Encode(admin)
 	json.NewEncoder(w).Encode(admin)
 }
 }
 
 
@@ -246,7 +172,7 @@ func createUser(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 		return
 	}
 	}
-	functions.PrintUserLog(user.UserName, "was created", 1)
+	logger.Log(1, user.UserName, "was created")
 	json.NewEncoder(w).Encode(user)
 	json.NewEncoder(w).Encode(user)
 }
 }
 
 
@@ -274,7 +200,7 @@ func updateUserNetworks(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 		return
 	}
 	}
-	functions.PrintUserLog(username, "status was updated", 1)
+	logger.Log(1, username, "status was updated")
 	json.NewEncoder(w).Encode(user)
 	json.NewEncoder(w).Encode(user)
 }
 }
 
 
@@ -306,7 +232,7 @@ func updateUser(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 		return
 	}
 	}
-	functions.PrintUserLog(username, "was updated", 1)
+	logger.Log(1, username, "was updated")
 	json.NewEncoder(w).Encode(user)
 	json.NewEncoder(w).Encode(user)
 }
 }
 
 
@@ -337,7 +263,7 @@ func updateUserAdm(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 		return
 	}
 	}
-	functions.PrintUserLog(username, "was updated (admin)", 1)
+	logger.Log(1, username, "was updated (admin)")
 	json.NewEncoder(w).Encode(user)
 	json.NewEncoder(w).Encode(user)
 }
 }
 
 
@@ -359,6 +285,6 @@ func deleteUser(w http.ResponseWriter, r *http.Request) {
 		return
 		return
 	}
 	}
 
 
-	functions.PrintUserLog(username, "was deleted", 1)
+	logger.Log(1, username, "was deleted")
 	json.NewEncoder(w).Encode(params["username"] + " deleted.")
 	json.NewEncoder(w).Encode(params["username"] + " deleted.")
 }
 }

+ 23 - 23
controllers/userHttpController_test.go → controllers/user_test.go

@@ -241,29 +241,29 @@ func TestUpdateUser(t *testing.T) {
 	})
 	})
 }
 }
 
 
-func TestValidateUserToken(t *testing.T) {
-	t.Run("EmptyToken", func(t *testing.T) {
-		err := ValidateUserToken("", "", false)
-		assert.NotNil(t, err)
-		assert.Equal(t, "Missing Auth Token.", err.Error())
-	})
-	t.Run("InvalidToken", func(t *testing.T) {
-		err := ValidateUserToken("Bearer: badtoken", "", false)
-		assert.NotNil(t, err)
-		assert.Equal(t, "Error Verifying Auth Token", err.Error())
-	})
-	t.Run("InvalidUser", func(t *testing.T) {
-		t.Skip()
-		err := ValidateUserToken("Bearer: secretkey", "baduser", false)
-		assert.NotNil(t, err)
-		assert.Equal(t, "Error Verifying Auth Token", err.Error())
-		//need authorization
-	})
-	t.Run("ValidToken", func(t *testing.T) {
-		err := ValidateUserToken("Bearer: secretkey", "", true)
-		assert.Nil(t, err)
-	})
-}
+// func TestValidateUserToken(t *testing.T) {
+// 	t.Run("EmptyToken", func(t *testing.T) {
+// 		err := ValidateUserToken("", "", false)
+// 		assert.NotNil(t, err)
+// 		assert.Equal(t, "Missing Auth Token.", err.Error())
+// 	})
+// 	t.Run("InvalidToken", func(t *testing.T) {
+// 		err := ValidateUserToken("Bearer: badtoken", "", false)
+// 		assert.NotNil(t, err)
+// 		assert.Equal(t, "Error Verifying Auth Token", err.Error())
+// 	})
+// 	t.Run("InvalidUser", func(t *testing.T) {
+// 		t.Skip()
+// 		err := ValidateUserToken("Bearer: secretkey", "baduser", false)
+// 		assert.NotNil(t, err)
+// 		assert.Equal(t, "Error Verifying Auth Token", err.Error())
+// 		//need authorization
+// 	})
+// 	t.Run("ValidToken", func(t *testing.T) {
+// 		err := ValidateUserToken("Bearer: secretkey", "", true)
+// 		assert.Nil(t, err)
+// 	})
+// }
 
 
 func TestVerifyAuthRequest(t *testing.T) {
 func TestVerifyAuthRequest(t *testing.T) {
 	database.InitializeDatabase()
 	database.InitializeDatabase()

+ 4 - 3
database/database.go

@@ -3,9 +3,9 @@ package database
 import (
 import (
 	"encoding/json"
 	"encoding/json"
 	"errors"
 	"errors"
-	"log"
 	"time"
 	"time"
 
 
+	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/servercfg"
 	"github.com/gravitl/netmaker/servercfg"
 )
 )
 
 
@@ -89,12 +89,13 @@ func getCurrentDB() map[string]interface{} {
 	}
 	}
 }
 }
 
 
+// InitializeDatabase - initializes database
 func InitializeDatabase() error {
 func InitializeDatabase() error {
-	log.Println("[netmaker] connecting to", servercfg.GetDB())
+	logger.Log(0, "connecting to", servercfg.GetDB())
 	tperiod := time.Now().Add(10 * time.Second)
 	tperiod := time.Now().Add(10 * time.Second)
 	for {
 	for {
 		if err := getCurrentDB()[INIT_DB].(func() error)(); err != nil {
 		if err := getCurrentDB()[INIT_DB].(func() error)(); err != nil {
-			log.Println("[netmaker] unable to connect to db, retrying . . .")
+			logger.Log(0, "unable to connect to db, retrying . . .")
 			if time.Now().After(tperiod) {
 			if time.Now().After(tperiod) {
 				return err
 				return err
 			}
 			}

+ 4 - 0
database/postgres.go

@@ -49,6 +49,7 @@ func pgCreateTable(tableName string) error {
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
+	defer statement.Close()
 	_, err = statement.Exec()
 	_, err = statement.Exec()
 	if err != nil {
 	if err != nil {
 		return err
 		return err
@@ -63,6 +64,7 @@ func pgInsert(key string, value string, tableName string) error {
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
+		defer statement.Close()
 		_, err = statement.Exec(key, value, value)
 		_, err = statement.Exec(key, value, value)
 		if err != nil {
 		if err != nil {
 			return err
 			return err
@@ -91,6 +93,7 @@ func pgDeleteRecord(tableName string, key string) error {
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
+	defer statement.Close()
 	if _, err = statement.Exec(key); err != nil {
 	if _, err = statement.Exec(key); err != nil {
 		return err
 		return err
 	}
 	}
@@ -103,6 +106,7 @@ func pgDeleteAllRecords(tableName string) error {
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
+	defer statement.Close()
 	if _, err = statement.Exec(); err != nil {
 	if _, err = statement.Exec(); err != nil {
 		return err
 		return err
 	}
 	}

+ 5 - 1
database/sqlite.go

@@ -12,7 +12,7 @@ import (
 // == sqlite ==
 // == sqlite ==
 const dbFilename = "netmaker.db"
 const dbFilename = "netmaker.db"
 
 
-// SqliteDB is the db object fro sqlite database connections
+// SqliteDB is the db object for sqlite database connections
 var SqliteDB *sql.DB
 var SqliteDB *sql.DB
 
 
 // SQLITE_FUNCTIONS - contains a map of the functions for sqlite
 // SQLITE_FUNCTIONS - contains a map of the functions for sqlite
@@ -50,6 +50,7 @@ func sqliteCreateTable(tableName string) error {
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
+	defer statement.Close()
 	_, err = statement.Exec()
 	_, err = statement.Exec()
 	if err != nil {
 	if err != nil {
 		return err
 		return err
@@ -64,6 +65,7 @@ func sqliteInsert(key string, value string, tableName string) error {
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
+		defer statement.Close()
 		_, err = statement.Exec(key, value)
 		_, err = statement.Exec(key, value)
 		if err != nil {
 		if err != nil {
 			return err
 			return err
@@ -90,6 +92,7 @@ func sqliteDeleteRecord(tableName string, key string) error {
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
+	defer statement.Close()
 	if _, err = statement.Exec(); err != nil {
 	if _, err = statement.Exec(); err != nil {
 		return err
 		return err
 	}
 	}
@@ -102,6 +105,7 @@ func sqliteDeleteAllRecords(tableName string) error {
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
+	defer statement.Close()
 	if _, err = statement.Exec(); err != nil {
 	if _, err = statement.Exec(); err != nil {
 		return err
 		return err
 	}
 	}

+ 0 - 169
functions/helpers.go

@@ -2,33 +2,14 @@ package functions
 
 
 import (
 import (
 	"encoding/json"
 	"encoding/json"
-	"fmt"
 	"log"
 	"log"
-	"math/rand"
 	"strings"
 	"strings"
-	"time"
 
 
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/models"
-	"github.com/gravitl/netmaker/servercfg"
 )
 )
 
 
-// PrintUserLog - prints a log with a given username
-func PrintUserLog(username string, message string, loglevel int) {
-	log.SetFlags(log.Flags() &^ (log.Llongfile | log.Lshortfile))
-	if int32(loglevel) <= servercfg.GetVerbose() && servercfg.GetVerbose() != 0 {
-		log.Println("[netmaker]", username, message)
-	}
-}
-
-// ParseNetwork - parses a network into a model
-func ParseNetwork(value string) (models.Network, error) {
-	var network models.Network
-	err := json.Unmarshal([]byte(value), &network)
-	return network, err
-}
-
 // ParseNode - parses a node into a model
 // ParseNode - parses a node into a model
 func ParseNode(value string) (models.Node, error) {
 func ParseNode(value string) (models.Node, error) {
 	var node models.Node
 	var node models.Node
@@ -140,72 +121,6 @@ func NetworkExists(name string) (bool, error) {
 	return len(network) > 0, nil
 	return len(network) > 0, nil
 }
 }
 
 
-// NetworkNodesUpdateAction - updates action of network nodes
-func NetworkNodesUpdateAction(networkName string, action string) error {
-
-	collections, err := database.FetchRecords(database.NODES_TABLE_NAME)
-	if err != nil {
-		if database.IsEmptyRecord(err) {
-			return nil
-		}
-		return err
-	}
-
-	for _, value := range collections {
-		var node models.Node
-		err := json.Unmarshal([]byte(value), &node)
-		if err != nil {
-			fmt.Println("error in node address assignment!")
-			return err
-		}
-		if action == models.NODE_UPDATE_KEY && node.IsStatic == "yes" {
-			continue
-		}
-		if node.Network == networkName {
-			node.Action = action
-			data, err := json.Marshal(&node)
-			if err != nil {
-				return err
-			}
-			node.SetID()
-			database.Insert(node.ID, string(data), database.NODES_TABLE_NAME)
-		}
-	}
-	return nil
-}
-
-// NetworkNodesUpdatePullChanges - tells nodes on network to pull
-func NetworkNodesUpdatePullChanges(networkName string) error {
-
-	collections, err := database.FetchRecords(database.NODES_TABLE_NAME)
-	if err != nil {
-		if database.IsEmptyRecord(err) {
-			return nil
-		}
-		return err
-	}
-
-	for _, value := range collections {
-		var node models.Node
-		err := json.Unmarshal([]byte(value), &node)
-		if err != nil {
-			fmt.Println("error in node address assignment!")
-			return err
-		}
-		if node.Network == networkName {
-			node.PullChanges = "yes"
-			data, err := json.Marshal(&node)
-			if err != nil {
-				return err
-			}
-			node.SetID()
-			database.Insert(node.ID, string(data), database.NODES_TABLE_NAME)
-		}
-	}
-
-	return nil
-}
-
 // IsNetworkDisplayNameUnique - checks if network display name unique
 // IsNetworkDisplayNameUnique - checks if network display name unique
 func IsNetworkDisplayNameUnique(name string) (bool, error) {
 func IsNetworkDisplayNameUnique(name string) (bool, error) {
 
 
@@ -237,28 +152,6 @@ func IsMacAddressUnique(macaddress string, networkName string) (bool, error) {
 	return true, nil
 	return true, nil
 }
 }
 
 
-// GetNetworkNonServerNodeCount - get number of network non server nodes
-func GetNetworkNonServerNodeCount(networkName string) (int, error) {
-
-	collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
-	count := 0
-	if err != nil && !database.IsEmptyRecord(err) {
-		return count, err
-	}
-	for _, value := range collection {
-		var node models.Node
-		if err = json.Unmarshal([]byte(value), &node); err != nil {
-			return count, err
-		} else {
-			if node.Network == networkName && node.IsServer != "yes" {
-				count++
-			}
-		}
-	}
-
-	return count, nil
-}
-
 // IsKeyValidGlobal - checks if a key is valid globally
 // IsKeyValidGlobal - checks if a key is valid globally
 func IsKeyValidGlobal(keyvalue string) bool {
 func IsKeyValidGlobal(keyvalue string) bool {
 
 
@@ -287,31 +180,6 @@ func IsKeyValidGlobal(keyvalue string) bool {
 	return isvalid
 	return isvalid
 }
 }
 
 
-//TODO: Contains a fatal error return. Need to change
-//This just gets a network object from a network name
-//Should probably just be GetNetwork. kind of a dumb name.
-//Used in contexts where it's not the Parent network.
-
-//Similar to above but checks if Cidr range is valid
-//At least this guy's got some print statements
-//still not good error handling
-
-//This  checks to  make sure a network name is valid.
-//Switch to REGEX?
-
-// NameInNetworkCharSet - see if name is in charset for networks
-func NameInNetworkCharSet(name string) bool {
-
-	charset := "abcdefghijklmnopqrstuvwxyz1234567890-_."
-
-	for _, char := range name {
-		if !strings.Contains(charset, strings.ToLower(string(char))) {
-			return false
-		}
-	}
-	return true
-}
-
 // NameInDNSCharSet - name in dns char set
 // NameInDNSCharSet - name in dns char set
 func NameInDNSCharSet(name string) bool {
 func NameInDNSCharSet(name string) bool {
 
 
@@ -396,43 +264,6 @@ func GetAllExtClients() ([]models.ExtClient, error) {
 	return extclients, nil
 	return extclients, nil
 }
 }
 
 
-// GenKey - generates access key
-func GenKey() string {
-
-	var seededRand *rand.Rand = rand.New(
-		rand.NewSource(time.Now().UnixNano()))
-
-	length := 16
-	charset := "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
-
-	b := make([]byte, length)
-	for i := range b {
-		b[i] = charset[seededRand.Intn(len(charset))]
-	}
-	return string(b)
-}
-
-//generate a key value
-//we should probably just have 1 random string generator
-//that  can be used across all functions
-//have a "base string" a "length" and a "charset"
-
-// GenKeyName - generates a key name
-func GenKeyName() string {
-
-	var seededRand *rand.Rand = rand.New(
-		rand.NewSource(time.Now().UnixNano()))
-
-	length := 5
-	charset := "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
-
-	b := make([]byte, length)
-	for i := range b {
-		b[i] = charset[seededRand.Intn(len(charset))]
-	}
-	return "key" + string(b)
-}
-
 // DeleteKey - deletes a key
 // DeleteKey - deletes a key
 func DeleteKey(network models.Network, i int) {
 func DeleteKey(network models.Network, i int) {
 
 

+ 4 - 3
functions/local.go

@@ -3,6 +3,7 @@ package functions
 import (
 import (
 	"os"
 	"os"
 
 
+	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/logic"
 )
 )
 
 
@@ -25,21 +26,21 @@ func SetDNSDir() error {
 	if os.IsNotExist(err) {
 	if os.IsNotExist(err) {
 		os.Mkdir(dir+"/config/dnsconfig", 0744)
 		os.Mkdir(dir+"/config/dnsconfig", 0744)
 	} else if err != nil {
 	} else if err != nil {
-		PrintUserLog("", "couldnt find or create /config/dnsconfig", 0)
+		logger.Log(0, "couldnt find or create /config/dnsconfig")
 		return err
 		return err
 	}
 	}
 	_, err = os.Stat(dir + "/config/dnsconfig/Corefile")
 	_, err = os.Stat(dir + "/config/dnsconfig/Corefile")
 	if os.IsNotExist(err) {
 	if os.IsNotExist(err) {
 		err = logic.SetCorefile(".")
 		err = logic.SetCorefile(".")
 		if err != nil {
 		if err != nil {
-			PrintUserLog("", err.Error(), 0)
+			logger.Log(0, err.Error())
 		}
 		}
 	}
 	}
 	_, err = os.Stat(dir + "/config/dnsconfig/netmaker.hosts")
 	_, err = os.Stat(dir + "/config/dnsconfig/netmaker.hosts")
 	if os.IsNotExist(err) {
 	if os.IsNotExist(err) {
 		_, err = os.Create(dir + "/config/dnsconfig/netmaker.hosts")
 		_, err = os.Create(dir + "/config/dnsconfig/netmaker.hosts")
 		if err != nil {
 		if err != nil {
-			PrintUserLog("", err.Error(), 0)
+			logger.Log(0, err.Error())
 		}
 		}
 	}
 	}
 	return nil
 	return nil

+ 18 - 1
go.mod

@@ -1,6 +1,6 @@
 module github.com/gravitl/netmaker
 module github.com/gravitl/netmaker
 
 
-go 1.15
+go 1.17
 
 
 require (
 require (
 	github.com/go-playground/validator/v10 v10.9.0
 	github.com/go-playground/validator/v10 v10.9.0
@@ -27,3 +27,20 @@ require (
 	google.golang.org/protobuf v1.27.1
 	google.golang.org/protobuf v1.27.1
 	gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
 	gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
 )
 )
+
+require (
+	cloud.google.com/go v0.34.0 // indirect
+	github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d // indirect
+	github.com/felixge/httpsnoop v1.0.1 // indirect
+	github.com/go-playground/locales v0.14.0 // indirect
+	github.com/go-playground/universal-translator v0.18.0 // indirect
+	github.com/google/go-cmp v0.5.5 // indirect
+	github.com/josharian/native v0.0.0-20200817173448-b6b71def0850 // indirect
+	github.com/leodido/go-urn v1.2.1 // indirect
+	github.com/mdlayher/genetlink v1.0.0 // indirect
+	github.com/mdlayher/netlink v1.4.0 // indirect
+	github.com/pmezard/go-difflib v1.0.0 // indirect
+	github.com/russross/blackfriday/v2 v2.0.1 // indirect
+	github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
+	google.golang.org/appengine v1.4.0 // indirect
+)

+ 1 - 1
kube/netclient-template-doks-uspace.yaml

@@ -16,7 +16,7 @@ spec:
       hostNetwork: true
       hostNetwork: true
       containers:
       containers:
       - name: netclient-1
       - name: netclient-1
-        image: gravitl/netclient:0.9.1-doks-uspace
+        image: gravitl/netclient:0.9.2-doks-uspace
         env:
         env:
         - name: NETCLIENT_ROAMING
         - name: NETCLIENT_ROAMING
           value: "no"
           value: "no"

+ 2 - 2
kube/netclient-template-doks.yaml

@@ -16,7 +16,7 @@ spec:
       hostNetwork: true
       hostNetwork: true
       containers:
       containers:
       - name: netclient-1
       - name: netclient-1
-        image: gravitl/netclient:0.9.1-doks
+        image: gravitl/netclient:0.9.2-doks
         env:
         env:
         - name: NETCLIENT_ROAMING
         - name: NETCLIENT_ROAMING
           value: "no"
           value: "no"
@@ -64,7 +64,7 @@ spec:
     spec:
     spec:
       hostNetwork: true
       hostNetwork: true
       containers:
       containers:
-      - image: gravitl/netclient:0.9.1-doks
+      - image: gravitl/netclient:0.9.2-doks
         imagePullPolicy: IfNotPresent
         imagePullPolicy: IfNotPresent
         name: wg-installer
         name: wg-installer
         command: ['bash', '-c']
         command: ['bash', '-c']

+ 104 - 0
logger/logger.go

@@ -0,0 +1,104 @@
+package logger
+
+import (
+	"fmt"
+	"io/ioutil"
+	"os"
+	"sort"
+	"strconv"
+	"strings"
+	"time"
+)
+
+const TimeFormatDay = "2006-01-02"
+const TimeFormat = "2006-01-02 15:04:05"
+
+var currentLogs = make(map[string]string)
+
+func makeString(message ...string) string {
+	return strings.Join(message, " ")
+}
+
+func getVerbose() int32 {
+	level, err := strconv.Atoi(os.Getenv("VERBOSITY"))
+	if err != nil || level < 0 {
+		level = 0
+	}
+	if level > 3 {
+		level = 3
+	}
+	return int32(level)
+}
+
+// ResetLogs - reallocates logs map
+func ResetLogs() {
+	currentLogs = make(map[string]string)
+}
+
+// Log - handles adding logs
+func Log(verbosity int, message ...string) {
+	var currentTime = time.Now()
+	var currentMessage = makeString(message...)
+	if int32(verbosity) <= getVerbose() && getVerbose() >= 0 {
+		fmt.Printf("[netmaker] %s %s \n", currentTime.Format(TimeFormat), currentMessage)
+	}
+	currentLogs[currentMessage] = currentTime.Format("2006-01-02 15:04:05.999999999")
+}
+
+// Dump - dumps all logs into a formatted string
+func Dump() string {
+	var dumpString = ""
+	type keyVal struct {
+		Key   string
+		Value time.Time
+	}
+	var dumpLogs = make([]keyVal, 0, len(currentLogs))
+	for key, value := range currentLogs {
+		parsedTime, err := time.Parse(TimeFormat, value)
+		if err == nil {
+			dumpLogs = append(dumpLogs, keyVal{
+				Key:   key,
+				Value: parsedTime,
+			})
+		}
+	}
+	sort.Slice(dumpLogs, func(i, j int) bool {
+		return dumpLogs[i].Value.Before(dumpLogs[j].Value)
+	})
+
+	for i := range dumpLogs {
+		var currLog = dumpLogs[i]
+		dumpString += fmt.Sprintf("[netmaker] %s %s \n", currLog.Value.Format(TimeFormat), currLog.Key)
+	}
+
+	return dumpString
+}
+
+// DumpFile - appends log dump log file
+func DumpFile(filePath string) {
+	f, err := os.OpenFile(filePath, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
+	if err != nil {
+		panic(err)
+	}
+
+	defer f.Close()
+
+	if _, err = f.WriteString(Dump()); err != nil {
+		panic(err)
+	}
+}
+
+// Retrieve - retrieves logs from given file
+func Retrieve(filePath string) string {
+	contents, err := ioutil.ReadFile(filePath)
+	if err != nil {
+		panic(err)
+	}
+	return string(contents)
+}
+
+// FatalLog - exits os after logging
+func FatalLog(message ...string) {
+	fmt.Printf("[netmaker] Fatal: %s \n", makeString(message...))
+	os.Exit(2)
+}

+ 167 - 1
logic/accesskeys.go

@@ -1,12 +1,147 @@
 package logic
 package logic
 
 
 import (
 import (
+	"encoding/base64"
 	"encoding/json"
 	"encoding/json"
+	"errors"
+	"math/rand"
+	"time"
 
 
+	"github.com/go-playground/validator/v10"
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/database"
+	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/models"
+	"github.com/gravitl/netmaker/servercfg"
 )
 )
 
 
+const (
+	charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
+)
+
+// CreateAccessKey - create access key
+func CreateAccessKey(accesskey models.AccessKey, network models.Network) (models.AccessKey, error) {
+
+	if accesskey.Name == "" {
+		accesskey.Name = genKeyName()
+	}
+
+	if accesskey.Value == "" {
+		accesskey.Value = genKey()
+	}
+	if accesskey.Uses == 0 {
+		accesskey.Uses = 1
+	}
+
+	checkkeys, err := GetKeys(network.NetID)
+	if err != nil {
+		return models.AccessKey{}, errors.New("could not retrieve network keys")
+	}
+
+	for _, key := range checkkeys {
+		if key.Name == accesskey.Name {
+			return models.AccessKey{}, errors.New("duplicate AccessKey Name")
+		}
+	}
+	privAddr := ""
+	if network.IsLocal != "" {
+		privAddr = network.LocalRange
+	}
+
+	netID := network.NetID
+
+	var accessToken models.AccessToken
+	s := servercfg.GetServerConfig()
+	servervals := models.ServerConfig{
+		CoreDNSAddr:     s.CoreDNSAddr,
+		APIConnString:   s.APIConnString,
+		APIHost:         s.APIHost,
+		APIPort:         s.APIPort,
+		GRPCConnString:  s.GRPCConnString,
+		GRPCHost:        s.GRPCHost,
+		GRPCPort:        s.GRPCPort,
+		GRPCSSL:         s.GRPCSSL,
+		CheckinInterval: s.CheckinInterval,
+	}
+	accessToken.ServerConfig = servervals
+	accessToken.ClientConfig.Network = netID
+	accessToken.ClientConfig.Key = accesskey.Value
+	accessToken.ClientConfig.LocalRange = privAddr
+
+	tokenjson, err := json.Marshal(accessToken)
+	if err != nil {
+		return accesskey, err
+	}
+
+	accesskey.AccessString = base64.StdEncoding.EncodeToString([]byte(tokenjson))
+
+	//validate accesskey
+	v := validator.New()
+	err = v.Struct(accesskey)
+	if err != nil {
+		for _, e := range err.(validator.ValidationErrors) {
+			logger.Log(1, "validator", e.Error())
+		}
+		return models.AccessKey{}, err
+	}
+
+	network.AccessKeys = append(network.AccessKeys, accesskey)
+	data, err := json.Marshal(&network)
+	if err != nil {
+		return models.AccessKey{}, err
+	}
+	if err = database.Insert(network.NetID, string(data), database.NETWORKS_TABLE_NAME); err != nil {
+		return models.AccessKey{}, err
+	}
+
+	return accesskey, nil
+}
+
+// DeleteKey - deletes a key
+func DeleteKey(keyname, netname string) error {
+	network, err := GetParentNetwork(netname)
+	if err != nil {
+		return err
+	}
+	//basically, turn the list of access keys into the list of access keys before and after the item
+	//have not done any error handling for if there's like...1 item. I think it works? need to test.
+	found := false
+	var updatedKeys []models.AccessKey
+	for _, currentkey := range network.AccessKeys {
+		if currentkey.Name == keyname {
+			found = true
+		} else {
+			updatedKeys = append(updatedKeys, currentkey)
+		}
+	}
+	if !found {
+		return errors.New("key " + keyname + " does not exist")
+	}
+	network.AccessKeys = updatedKeys
+	data, err := json.Marshal(&network)
+	if err != nil {
+		return err
+	}
+	if err := database.Insert(network.NetID, string(data), database.NETWORKS_TABLE_NAME); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// GetKeys - fetches keys for network
+func GetKeys(net string) ([]models.AccessKey, error) {
+
+	record, err := database.FetchRecord(database.NETWORKS_TABLE_NAME, net)
+	if err != nil {
+		return []models.AccessKey{}, err
+	}
+	network, err := ParseNetwork(record)
+	if err != nil {
+		return []models.AccessKey{}, err
+	}
+	return network.AccessKeys, nil
+}
+
 // DecrimentKey - decriments key uses
 // DecrimentKey - decriments key uses
 func DecrimentKey(networkName string, keyvalue string) {
 func DecrimentKey(networkName string, keyvalue string) {
 
 
@@ -31,7 +166,7 @@ func DecrimentKey(networkName string, keyvalue string) {
 	}
 	}
 
 
 	if newNetworkData, err := json.Marshal(&network); err != nil {
 	if newNetworkData, err := json.Marshal(&network); err != nil {
-		Log("failed to decrement key", 2)
+		logger.Log(2, "failed to decrement key")
 		return
 		return
 	} else {
 	} else {
 		database.Insert(network.NetID, string(newNetworkData), database.NETWORKS_TABLE_NAME)
 		database.Insert(network.NetID, string(newNetworkData), database.NETWORKS_TABLE_NAME)
@@ -61,6 +196,7 @@ func IsKeyValid(networkname string, keyvalue string) bool {
 	return isvalid
 	return isvalid
 }
 }
 
 
+// RemoveKeySensitiveInfo - remove sensitive key info
 func RemoveKeySensitiveInfo(keys []models.AccessKey) []models.AccessKey {
 func RemoveKeySensitiveInfo(keys []models.AccessKey) []models.AccessKey {
 	var returnKeys []models.AccessKey
 	var returnKeys []models.AccessKey
 	for _, key := range keys {
 	for _, key := range keys {
@@ -70,3 +206,33 @@ func RemoveKeySensitiveInfo(keys []models.AccessKey) []models.AccessKey {
 	}
 	}
 	return returnKeys
 	return returnKeys
 }
 }
+
+// == private methods ==
+
+func genKeyName() string {
+
+	var seededRand *rand.Rand = rand.New(
+		rand.NewSource(time.Now().UnixNano()))
+
+	length := 5
+
+	b := make([]byte, length)
+	for i := range b {
+		b[i] = charset[seededRand.Intn(len(charset))]
+	}
+	return "key" + string(b)
+}
+
+func genKey() string {
+
+	var seededRand *rand.Rand = rand.New(
+		rand.NewSource(time.Now().UnixNano()))
+
+	length := 16
+
+	b := make([]byte, length)
+	for i := range b {
+		b[i] = charset[seededRand.Intn(len(charset))]
+	}
+	return string(b)
+}

+ 3 - 2
logic/auth.go

@@ -7,6 +7,7 @@ import (
 
 
 	"github.com/go-playground/validator/v10"
 	"github.com/go-playground/validator/v10"
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/database"
+	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/models"
 	"golang.org/x/crypto/bcrypt"
 	"golang.org/x/crypto/bcrypt"
 )
 )
@@ -220,7 +221,7 @@ func UpdateUser(userchange models.User, user models.User) (models.User, error) {
 	if err = database.Insert(user.UserName, string(data), database.USERS_TABLE_NAME); err != nil {
 	if err = database.Insert(user.UserName, string(data), database.USERS_TABLE_NAME); err != nil {
 		return models.User{}, err
 		return models.User{}, err
 	}
 	}
-	Log("updated user "+queryUser, 1)
+	logger.Log(1, "updated user", queryUser)
 	return user, nil
 	return user, nil
 }
 }
 
 
@@ -232,7 +233,7 @@ func ValidateUser(user models.User) error {
 
 
 	if err != nil {
 	if err != nil {
 		for _, e := range err.(validator.ValidationErrors) {
 		for _, e := range err.(validator.ValidationErrors) {
-			Log(e.Error(), 2)
+			logger.Log(2, e.Error())
 		}
 		}
 	}
 	}
 
 

+ 105 - 1
logic/dns.go

@@ -5,7 +5,9 @@ import (
 	"io/ioutil"
 	"io/ioutil"
 	"os"
 	"os"
 
 
+	"github.com/go-playground/validator/v10"
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/database"
+	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/servercfg"
 	"github.com/gravitl/netmaker/servercfg"
 	"github.com/txn2/txeh"
 	"github.com/txn2/txeh"
@@ -118,7 +120,7 @@ func SetCorefile(domains string) error {
 	if os.IsNotExist(err) {
 	if os.IsNotExist(err) {
 		os.Mkdir(dir+"/config/dnsconfig", 744)
 		os.Mkdir(dir+"/config/dnsconfig", 744)
 	} else if err != nil {
 	} else if err != nil {
-		Log("couldnt find or create /config/dnsconfig", 0)
+		logger.Log(0, "couldnt find or create /config/dnsconfig")
 		return err
 		return err
 	}
 	}
 
 
@@ -139,3 +141,105 @@ func SetCorefile(domains string) error {
 	}
 	}
 	return err
 	return err
 }
 }
+
+// GetAllDNS - gets all dns entries
+func GetAllDNS() ([]models.DNSEntry, error) {
+	var dns []models.DNSEntry
+	networks, err := GetNetworks()
+	if err != nil && !database.IsEmptyRecord(err) {
+		return []models.DNSEntry{}, err
+	}
+	for _, net := range networks {
+		netdns, err := GetDNS(net.NetID)
+		if err != nil {
+			return []models.DNSEntry{}, nil
+		}
+		dns = append(dns, netdns...)
+	}
+	return dns, nil
+}
+
+// GetDNSEntryNum - gets which entry the dns was
+func GetDNSEntryNum(domain string, network string) (int, error) {
+
+	num := 0
+
+	entries, err := GetDNS(network)
+	if err != nil {
+		return 0, err
+	}
+
+	for i := 0; i < len(entries); i++ {
+
+		if domain == entries[i].Name {
+			num++
+		}
+	}
+
+	return num, nil
+}
+
+// ValidateDNSCreate - checks if an entry is valid
+func ValidateDNSCreate(entry models.DNSEntry) error {
+
+	v := validator.New()
+
+	_ = v.RegisterValidation("name_unique", func(fl validator.FieldLevel) bool {
+		num, err := GetDNSEntryNum(entry.Name, entry.Network)
+		return err == nil && num == 0
+	})
+
+	_ = v.RegisterValidation("network_exists", func(fl validator.FieldLevel) bool {
+		_, err := GetParentNetwork(entry.Network)
+		return err == nil
+	})
+
+	err := v.Struct(entry)
+	if err != nil {
+		for _, e := range err.(validator.ValidationErrors) {
+			logger.Log(1, e.Error())
+		}
+	}
+	return err
+}
+
+// ValidateDNSUpdate - validates a DNS update
+func ValidateDNSUpdate(change models.DNSEntry, entry models.DNSEntry) error {
+
+	v := validator.New()
+
+	_ = v.RegisterValidation("name_unique", func(fl validator.FieldLevel) bool {
+		//if name & net not changing name we are good
+		if change.Name == entry.Name && change.Network == entry.Network {
+			return true
+		}
+		num, err := GetDNSEntryNum(change.Name, change.Network)
+		return err == nil && num == 0
+	})
+	_ = v.RegisterValidation("network_exists", func(fl validator.FieldLevel) bool {
+		_, err := GetParentNetwork(change.Network)
+		if err != nil {
+			logger.Log(0, err.Error())
+		}
+		return err == nil
+	})
+
+	err := v.Struct(change)
+
+	if err != nil {
+		for _, e := range err.(validator.ValidationErrors) {
+			logger.Log(1, e.Error())
+		}
+	}
+	return err
+}
+
+// DeleteDNS - deletes a DNS entry
+func DeleteDNS(domain string, network string) error {
+	key, err := GetRecordKey(domain, network)
+	if err != nil {
+		return err
+	}
+	err = database.DeleteRecord(database.DNS_TABLE_NAME, key)
+	return err
+}

+ 105 - 2
logic/extpeers.go

@@ -2,9 +2,12 @@ package logic
 
 
 import (
 import (
 	"encoding/json"
 	"encoding/json"
+	"time"
 
 
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/database"
+	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/models"
+	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 )
 )
 
 
 // GetExtPeersList - gets the ext peers lists
 // GetExtPeersList - gets the ext peers lists
@@ -22,12 +25,12 @@ func GetExtPeersList(macaddress string, networkName string) ([]models.ExtPeersRe
 		var extClient models.ExtClient
 		var extClient models.ExtClient
 		err = json.Unmarshal([]byte(value), &peer)
 		err = json.Unmarshal([]byte(value), &peer)
 		if err != nil {
 		if err != nil {
-			Log("failed to unmarshal peer when getting ext peer list", 2)
+			logger.Log(2, "failed to unmarshal peer when getting ext peer list")
 			continue
 			continue
 		}
 		}
 		err = json.Unmarshal([]byte(value), &extClient)
 		err = json.Unmarshal([]byte(value), &extClient)
 		if err != nil {
 		if err != nil {
-			Log("failed to unmarshal ext client", 2)
+			logger.Log(2, "failed to unmarshal ext client")
 			continue
 			continue
 		}
 		}
 		if extClient.Network == networkName && extClient.IngressGatewayID == macaddress {
 		if extClient.Network == networkName && extClient.IngressGatewayID == macaddress {
@@ -62,3 +65,103 @@ func GetEgressRangesOnNetwork(client *models.ExtClient) ([]string, error) {
 
 
 	return result, nil
 	return result, nil
 }
 }
+
+// DeleteExtClient - deletes an existing ext client
+func DeleteExtClient(network string, clientid string) error {
+	key, err := GetRecordKey(clientid, network)
+	if err != nil {
+		return err
+	}
+	err = database.DeleteRecord(database.EXT_CLIENT_TABLE_NAME, key)
+	return err
+}
+
+// GetNetworkExtClients - gets the ext clients of given network
+func GetNetworkExtClients(network string) ([]models.ExtClient, error) {
+	var extclients []models.ExtClient
+
+	records, err := database.FetchRecords(database.EXT_CLIENT_TABLE_NAME)
+	if err != nil {
+		return extclients, err
+	}
+	for _, value := range records {
+		var extclient models.ExtClient
+		err = json.Unmarshal([]byte(value), &extclient)
+		if err != nil {
+			continue
+		}
+		if extclient.Network == network {
+			extclients = append(extclients, extclient)
+		}
+	}
+	return extclients, err
+}
+
+// GetExtClient - gets a single ext client on a network
+func GetExtClient(clientid string, network string) (models.ExtClient, error) {
+	var extclient models.ExtClient
+	key, err := GetRecordKey(clientid, network)
+	if err != nil {
+		return extclient, err
+	}
+	data, err := database.FetchRecord(database.EXT_CLIENT_TABLE_NAME, key)
+	if err != nil {
+		return extclient, err
+	}
+	err = json.Unmarshal([]byte(data), &extclient)
+
+	return extclient, err
+}
+
+// CreateExtClient - creates an extclient
+func CreateExtClient(extclient *models.ExtClient) error {
+	if extclient.PrivateKey == "" {
+		privateKey, err := wgtypes.GeneratePrivateKey()
+		if err != nil {
+			return err
+		}
+
+		extclient.PrivateKey = privateKey.String()
+		extclient.PublicKey = privateKey.PublicKey().String()
+	}
+
+	if extclient.Address == "" {
+		newAddress, err := UniqueAddress(extclient.Network)
+		if err != nil {
+			return err
+		}
+		extclient.Address = newAddress
+	}
+
+	if extclient.ClientID == "" {
+		extclient.ClientID = models.GenerateNodeName()
+	}
+
+	extclient.LastModified = time.Now().Unix()
+
+	key, err := GetRecordKey(extclient.ClientID, extclient.Network)
+	if err != nil {
+		return err
+	}
+	data, err := json.Marshal(&extclient)
+	if err != nil {
+		return err
+	}
+	if err = database.Insert(key, string(data), database.EXT_CLIENT_TABLE_NAME); err != nil {
+		return err
+	}
+	err = SetNetworkNodesLastModified(extclient.Network)
+	return err
+}
+
+// UpdateExtClient - only supports name changes right now
+func UpdateExtClient(newclientid string, network string, client *models.ExtClient) (*models.ExtClient, error) {
+
+	err := DeleteExtClient(network, client.ClientID)
+	if err != nil {
+		return client, err
+	}
+	client.ClientID = newclientid
+	CreateExtClient(client)
+	return client, err
+}

+ 221 - 0
logic/gateway.go

@@ -0,0 +1,221 @@
+package logic
+
+import (
+	"encoding/json"
+	"errors"
+	"strings"
+	"time"
+
+	"github.com/gravitl/netmaker/database"
+	"github.com/gravitl/netmaker/logger"
+	"github.com/gravitl/netmaker/models"
+)
+
+// CreateEgressGateway - creates an egress gateway
+func CreateEgressGateway(gateway models.EgressGatewayRequest) (models.Node, error) {
+	node, err := GetNodeByMacAddress(gateway.NetID, gateway.NodeID)
+	if node.OS == "windows" || node.OS == "macos" { // add in darwin later
+		return models.Node{}, errors.New(node.OS + " is unsupported for egress gateways")
+	}
+	if err != nil {
+		return models.Node{}, err
+	}
+	err = ValidateEgressGateway(gateway)
+	if err != nil {
+		return models.Node{}, err
+	}
+	node.IsEgressGateway = "yes"
+	node.EgressGatewayRanges = gateway.Ranges
+	postUpCmd := "iptables -A FORWARD -i " + node.Interface + " -j ACCEPT; iptables -t nat -A POSTROUTING -o " + gateway.Interface + " -j MASQUERADE"
+	postDownCmd := "iptables -D FORWARD -i " + node.Interface + " -j ACCEPT; iptables -t nat -D POSTROUTING -o " + gateway.Interface + " -j MASQUERADE"
+	if gateway.PostUp != "" {
+		postUpCmd = gateway.PostUp
+	}
+	if gateway.PostDown != "" {
+		postDownCmd = gateway.PostDown
+	}
+	if node.PostUp != "" {
+		if !strings.Contains(node.PostUp, postUpCmd) {
+			postUpCmd = node.PostUp + "; " + postUpCmd
+		}
+	}
+	if node.PostDown != "" {
+		if !strings.Contains(node.PostDown, postDownCmd) {
+			postDownCmd = node.PostDown + "; " + postDownCmd
+		}
+	}
+	key, err := GetRecordKey(gateway.NodeID, gateway.NetID)
+	if err != nil {
+		return node, err
+	}
+	node.PostUp = postUpCmd
+	node.PostDown = postDownCmd
+	node.SetLastModified()
+	node.PullChanges = "yes"
+	nodeData, err := json.Marshal(&node)
+	if err != nil {
+		return node, err
+	}
+	if err = database.Insert(key, string(nodeData), database.NODES_TABLE_NAME); err != nil {
+		return models.Node{}, err
+	}
+	if err = NetworkNodesUpdatePullChanges(node.Network); err != nil {
+		return models.Node{}, err
+	}
+	return node, nil
+}
+
+func ValidateEgressGateway(gateway models.EgressGatewayRequest) error {
+	var err error
+
+	empty := len(gateway.Ranges) == 0
+	if empty {
+		err = errors.New("IP Ranges Cannot Be Empty")
+	}
+	empty = gateway.Interface == ""
+	if empty {
+		err = errors.New("Interface cannot be empty")
+	}
+	return err
+}
+
+// DeleteEgressGateway - deletes egress from node
+func DeleteEgressGateway(network, macaddress string) (models.Node, error) {
+
+	node, err := GetNodeByMacAddress(network, macaddress)
+	if err != nil {
+		return models.Node{}, err
+	}
+
+	node.IsEgressGateway = "no"
+	node.EgressGatewayRanges = []string{}
+	node.PostUp = ""
+	node.PostDown = ""
+	if node.IsIngressGateway == "yes" { // check if node is still an ingress gateway before completely deleting postdown/up rules
+		node.PostUp = "iptables -A FORWARD -i " + node.Interface + " -j ACCEPT; iptables -t nat -A POSTROUTING -o " + node.Interface + " -j MASQUERADE"
+		node.PostDown = "iptables -D FORWARD -i " + node.Interface + " -j ACCEPT; iptables -t nat -D POSTROUTING -o " + node.Interface + " -j MASQUERADE"
+	}
+	node.SetLastModified()
+	node.PullChanges = "yes"
+	key, err := GetRecordKey(node.MacAddress, node.Network)
+	if err != nil {
+		return models.Node{}, err
+	}
+	data, err := json.Marshal(&node)
+	if err != nil {
+		return models.Node{}, err
+	}
+	if err = database.Insert(key, string(data), database.NODES_TABLE_NAME); err != nil {
+		return models.Node{}, err
+	}
+	if err = NetworkNodesUpdatePullChanges(network); err != nil {
+		return models.Node{}, err
+	}
+	return node, nil
+}
+
+// CreateIngressGateway - creates an ingress gateway
+func CreateIngressGateway(netid string, macaddress string) (models.Node, error) {
+
+	node, err := GetNodeByMacAddress(netid, macaddress)
+	if node.OS == "windows" || node.OS == "macos" { // add in darwin later
+		return models.Node{}, errors.New(node.OS + " is unsupported for ingress gateways")
+	}
+
+	if err != nil {
+		return models.Node{}, err
+	}
+
+	network, err := GetParentNetwork(netid)
+	if err != nil {
+		return models.Node{}, err
+	}
+	node.IsIngressGateway = "yes"
+	node.IngressGatewayRange = network.AddressRange
+	postUpCmd := "iptables -A FORWARD -i " + node.Interface + " -j ACCEPT; iptables -t nat -A POSTROUTING -o " + node.Interface + " -j MASQUERADE"
+	postDownCmd := "iptables -D FORWARD -i " + node.Interface + " -j ACCEPT; iptables -t nat -D POSTROUTING -o " + node.Interface + " -j MASQUERADE"
+	if node.PostUp != "" {
+		if !strings.Contains(node.PostUp, postUpCmd) {
+			postUpCmd = node.PostUp + "; " + postUpCmd
+		}
+	}
+	if node.PostDown != "" {
+		if !strings.Contains(node.PostDown, postDownCmd) {
+			postDownCmd = node.PostDown + "; " + postDownCmd
+		}
+	}
+	node.SetLastModified()
+	node.PostUp = postUpCmd
+	node.PostDown = postDownCmd
+	node.PullChanges = "yes"
+	node.UDPHolePunch = "no"
+	key, err := GetRecordKey(node.MacAddress, node.Network)
+	if err != nil {
+		return models.Node{}, err
+	}
+	data, err := json.Marshal(&node)
+	if err != nil {
+		return models.Node{}, err
+	}
+	err = database.Insert(key, string(data), database.NODES_TABLE_NAME)
+	if err != nil {
+		return models.Node{}, err
+	}
+	err = SetNetworkNodesLastModified(netid)
+	return node, err
+}
+
+// DeleteIngressGateway - deletes an ingress gateway
+func DeleteIngressGateway(networkName string, macaddress string) (models.Node, error) {
+
+	node, err := GetNodeByMacAddress(networkName, macaddress)
+	if err != nil {
+		return models.Node{}, err
+	}
+	network, err := GetParentNetwork(networkName)
+	if err != nil {
+		return models.Node{}, err
+	}
+	// delete ext clients belonging to ingress gateway
+	if err = DeleteGatewayExtClients(macaddress, networkName); err != nil {
+		return models.Node{}, err
+	}
+
+	node.UDPHolePunch = network.DefaultUDPHolePunch
+	node.LastModified = time.Now().Unix()
+	node.IsIngressGateway = "no"
+	node.IngressGatewayRange = ""
+	node.PullChanges = "yes"
+
+	key, err := GetRecordKey(node.MacAddress, node.Network)
+	if err != nil {
+		return models.Node{}, err
+	}
+	data, err := json.Marshal(&node)
+	if err != nil {
+		return models.Node{}, err
+	}
+	err = database.Insert(key, string(data), database.NODES_TABLE_NAME)
+	if err != nil {
+		return models.Node{}, err
+	}
+	err = SetNetworkNodesLastModified(networkName)
+	return node, err
+}
+
+// DeleteGatewayExtClients - deletes ext clients based on gateway (mac) of ingress node and network
+func DeleteGatewayExtClients(gatewayID string, networkName string) error {
+	currentExtClients, err := GetNetworkExtClients(networkName)
+	if err != nil && !database.IsEmptyRecord(err) {
+		return err
+	}
+	for _, extClient := range currentExtClients {
+		if extClient.IngressGatewayID == gatewayID {
+			if err = DeleteExtClient(networkName, extClient.ClientID); err != nil {
+				logger.Log(1, "failed to remove ext client", extClient.ClientID)
+				continue
+			}
+		}
+	}
+	return nil
+}

+ 194 - 4
logic/networks.go

@@ -7,9 +7,11 @@ import (
 	"net"
 	"net"
 	"os/exec"
 	"os/exec"
 	"strings"
 	"strings"
+	"time"
 
 
 	"github.com/go-playground/validator/v10"
 	"github.com/go-playground/validator/v10"
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/database"
+	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/validation"
 	"github.com/gravitl/netmaker/validation"
@@ -37,6 +39,107 @@ func GetNetworks() ([]models.Network, error) {
 	return networks, err
 	return networks, err
 }
 }
 
 
+// DeleteNetwork - deletes a network
+func DeleteNetwork(network string) error {
+	nodeCount, err := GetNetworkNonServerNodeCount(network)
+	if nodeCount == 0 || database.IsEmptyRecord(err) {
+		// delete server nodes first then db records
+		servers, err := GetSortedNetworkServerNodes(network)
+		if err == nil {
+			for _, s := range servers {
+				if err = DeleteNode(&s, true); err != nil {
+					logger.Log(2, "could not removed server", s.Name, "before deleting network", network)
+				} else {
+					logger.Log(2, "removed server", s.Name, "before deleting network", network)
+				}
+			}
+		} else {
+			logger.Log(1, "could not remove servers before deleting network", network)
+		}
+		return database.DeleteRecord(database.NETWORKS_TABLE_NAME, network)
+	}
+	return errors.New("node check failed. All nodes must be deleted before deleting network")
+}
+
+// CreateNetwork - creates a network in database
+func CreateNetwork(network models.Network) error {
+
+	network.SetDefaults()
+	network.SetNodesLastModified()
+	network.SetNetworkLastModified()
+	network.KeyUpdateTimeStamp = time.Now().Unix()
+
+	err := ValidateNetwork(&network, false)
+	if err != nil {
+		//returnErrorResponse(w, r, formatError(err, "badrequest"))
+		return err
+	}
+
+	data, err := json.Marshal(&network)
+	if err != nil {
+		return err
+	}
+	if err = database.Insert(network.NetID, string(data), database.NETWORKS_TABLE_NAME); err != nil {
+		return err
+	}
+
+	return err
+}
+
+// NetworkNodesUpdatePullChanges - tells nodes on network to pull
+func NetworkNodesUpdatePullChanges(networkName string) error {
+
+	collections, err := database.FetchRecords(database.NODES_TABLE_NAME)
+	if err != nil {
+		if database.IsEmptyRecord(err) {
+			return nil
+		}
+		return err
+	}
+
+	for _, value := range collections {
+		var node models.Node
+		err := json.Unmarshal([]byte(value), &node)
+		if err != nil {
+			fmt.Println("error in node address assignment!")
+			return err
+		}
+		if node.Network == networkName {
+			node.PullChanges = "yes"
+			data, err := json.Marshal(&node)
+			if err != nil {
+				return err
+			}
+			node.SetID()
+			database.Insert(node.ID, string(data), database.NODES_TABLE_NAME)
+		}
+	}
+
+	return nil
+}
+
+// GetNetworkNonServerNodeCount - get number of network non server nodes
+func GetNetworkNonServerNodeCount(networkName string) (int, error) {
+
+	collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
+	count := 0
+	if err != nil && !database.IsEmptyRecord(err) {
+		return count, err
+	}
+	for _, value := range collection {
+		var node models.Node
+		if err = json.Unmarshal([]byte(value), &node); err != nil {
+			return count, err
+		} else {
+			if node.Network == networkName && node.IsServer != "yes" {
+				count++
+			}
+		}
+	}
+
+	return count, nil
+}
+
 // GetParentNetwork - get parent network
 // GetParentNetwork - get parent network
 func GetParentNetwork(networkname string) (models.Network, error) {
 func GetParentNetwork(networkname string) (models.Network, error) {
 
 
@@ -461,8 +564,91 @@ func ValidateNetwork(network *models.Network, isUpdate bool) error {
 	return err
 	return err
 }
 }
 
 
+// ParseNetwork - parses a network into a model
+func ParseNetwork(value string) (models.Network, error) {
+	var network models.Network
+	err := json.Unmarshal([]byte(value), &network)
+	return network, err
+}
+
+// ValidateNetworkUpdate - checks if network is valid to update
+func ValidateNetworkUpdate(network models.Network) error {
+	v := validator.New()
+
+	_ = v.RegisterValidation("netid_valid", func(fl validator.FieldLevel) bool {
+		if fl.Field().String() == "" {
+			return true
+		}
+		inCharSet := nameInNetworkCharSet(fl.Field().String())
+		return inCharSet
+	})
+
+	err := v.Struct(network)
+
+	if err != nil {
+		for _, e := range err.(validator.ValidationErrors) {
+			logger.Log(1, "validator", e.Error())
+		}
+	}
+	return err
+}
+
+// KeyUpdate - updates keys on network
+func KeyUpdate(netname string) (models.Network, error) {
+	err := networkNodesUpdateAction(netname, models.NODE_UPDATE_KEY)
+	if err != nil {
+		return models.Network{}, err
+	}
+	return models.Network{}, nil
+}
+
 // == Private ==
 // == Private ==
 
 
+func networkNodesUpdateAction(networkName string, action string) error {
+
+	collections, err := database.FetchRecords(database.NODES_TABLE_NAME)
+	if err != nil {
+		if database.IsEmptyRecord(err) {
+			return nil
+		}
+		return err
+	}
+
+	for _, value := range collections {
+		var node models.Node
+		err := json.Unmarshal([]byte(value), &node)
+		if err != nil {
+			fmt.Println("error in node address assignment!")
+			return err
+		}
+		if action == models.NODE_UPDATE_KEY && node.IsStatic == "yes" {
+			continue
+		}
+		if node.Network == networkName {
+			node.Action = action
+			data, err := json.Marshal(&node)
+			if err != nil {
+				return err
+			}
+			node.SetID()
+			database.Insert(node.ID, string(data), database.NODES_TABLE_NAME)
+		}
+	}
+	return nil
+}
+
+func nameInNetworkCharSet(name string) bool {
+
+	charset := "abcdefghijklmnopqrstuvwxyz1234567890-_."
+
+	for _, char := range name {
+		if !strings.Contains(charset, strings.ToLower(string(char))) {
+			return false
+		}
+	}
+	return true
+}
+
 func deleteInterface(ifacename string, postdown string) error {
 func deleteInterface(ifacename string, postdown string) error {
 	var err error
 	var err error
 	if !ncutils.IsKernel() {
 	if !ncutils.IsKernel() {
@@ -471,7 +657,7 @@ func deleteInterface(ifacename string, postdown string) error {
 		ipExec, errN := exec.LookPath("ip")
 		ipExec, errN := exec.LookPath("ip")
 		err = errN
 		err = errN
 		if err != nil {
 		if err != nil {
-			Log(err.Error(), 1)
+			logger.Log(1, err.Error())
 		}
 		}
 		_, err = ncutils.RunCmd(ipExec+" link del "+ifacename, false)
 		_, err = ncutils.RunCmd(ipExec+" link del "+ifacename, false)
 		if postdown != "" {
 		if postdown != "" {
@@ -487,7 +673,7 @@ func isInterfacePresent(iface string, address string) (string, bool) {
 	var err error
 	var err error
 	interfaces, err = net.Interfaces()
 	interfaces, err = net.Interfaces()
 	if err != nil {
 	if err != nil {
-		Log("ERROR: could not read interfaces", 0)
+		logger.Log(0, "ERROR: could not read interfaces")
 		return "", true
 		return "", true
 	}
 	}
 	for _, currIface := range interfaces {
 	for _, currIface := range interfaces {
@@ -498,11 +684,15 @@ func isInterfacePresent(iface string, address string) (string, bool) {
 		}
 		}
 		for _, addr := range currAddrs {
 		for _, addr := range currAddrs {
 			if strings.Contains(addr.String(), address) && currIface.Name != iface {
 			if strings.Contains(addr.String(), address) && currIface.Name != iface {
-				Log("found iface "+addr.String()+" "+currIface.Name, 2)
+				logger.Log(2, "found iface", addr.String(), currIface.Name)
+				interfaces = nil
+				currAddrs = nil
 				return currIface.Name, false
 				return currIface.Name, false
 			}
 			}
 		}
 		}
+		currAddrs = nil
 	}
 	}
-	Log("failed to find iface "+iface, 2)
+	interfaces = nil
+	logger.Log(2, "failed to find iface", iface)
 	return "", true
 	return "", true
 }
 }

+ 32 - 7
logic/nodes.go

@@ -9,6 +9,7 @@ import (
 
 
 	"github.com/go-playground/validator/v10"
 	"github.com/go-playground/validator/v10"
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/database"
+	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/validation"
 	"github.com/gravitl/netmaker/validation"
 )
 )
@@ -62,10 +63,32 @@ func GetSortedNetworkServerNodes(network string) ([]models.Node, error) {
 	return nodes, nil
 	return nodes, nil
 }
 }
 
 
+// UncordonNode - approves a node to join a network
+func UncordonNode(network, macaddress string) (models.Node, error) {
+	node, err := GetNodeByMacAddress(network, macaddress)
+	if err != nil {
+		return models.Node{}, err
+	}
+	node.SetLastModified()
+	node.IsPending = "no"
+	node.PullChanges = "yes"
+	data, err := json.Marshal(&node)
+	if err != nil {
+		return node, err
+	}
+	key, err := GetRecordKey(node.MacAddress, node.Network)
+	if err != nil {
+		return node, err
+	}
+
+	err = database.Insert(key, string(data), database.NODES_TABLE_NAME)
+	return node, err
+}
+
 // GetPeers - gets the peers of a given node
 // GetPeers - gets the peers of a given node
-func GetPeers(node models.Node) ([]models.Node, error) {
-	if node.IsServer == "yes" && IsLeader(&node) {
-		SetNetworkServerPeers(&node)
+func GetPeers(node *models.Node) ([]models.Node, error) {
+	if IsLeader(node) {
+		SetNetworkServerPeers(node)
 	}
 	}
 	excludeIsRelayed := node.IsRelay != "yes"
 	excludeIsRelayed := node.IsRelay != "yes"
 	var relayedNode string
 	var relayedNode string
@@ -83,7 +106,7 @@ func GetPeers(node models.Node) ([]models.Node, error) {
 func IsLeader(node *models.Node) bool {
 func IsLeader(node *models.Node) bool {
 	nodes, err := GetSortedNetworkServerNodes(node.Network)
 	nodes, err := GetSortedNetworkServerNodes(node.Network)
 	if err != nil {
 	if err != nil {
-		Log("ERROR: COULD NOT RETRIEVE SERVER NODES. THIS WILL BREAK HOLE PUNCHING.", 0)
+		logger.Log(0, "ERROR: COULD NOT RETRIEVE SERVER NODES. THIS WILL BREAK HOLE PUNCHING.")
 		return false
 		return false
 	}
 	}
 	for _, n := range nodes {
 	for _, n := range nodes {
@@ -114,11 +137,13 @@ func UpdateNode(currentNode *models.Node, newNode *models.Node) error {
 	return fmt.Errorf("failed to update node " + newNode.MacAddress + ", cannot change macaddress.")
 	return fmt.Errorf("failed to update node " + newNode.MacAddress + ", cannot change macaddress.")
 }
 }
 
 
+// IsNodeIDUnique - checks if node id is unique
 func IsNodeIDUnique(node *models.Node) (bool, error) {
 func IsNodeIDUnique(node *models.Node) (bool, error) {
 	_, err := database.FetchRecord(database.NODES_TABLE_NAME, node.ID)
 	_, err := database.FetchRecord(database.NODES_TABLE_NAME, node.ID)
 	return database.IsEmptyRecord(err), err
 	return database.IsEmptyRecord(err), err
 }
 }
 
 
+// ValidateNode - validates node values
 func ValidateNode(node *models.Node, isUpdate bool) error {
 func ValidateNode(node *models.Node, isUpdate bool) error {
 	v := validator.New()
 	v := validator.New()
 	_ = v.RegisterValidation("macaddress_unique", func(fl validator.FieldLevel) bool {
 	_ = v.RegisterValidation("macaddress_unique", func(fl validator.FieldLevel) bool {
@@ -189,7 +214,7 @@ func CheckIsServer(node *models.Node) bool {
 // GetNetworkByNode - gets the network model from a node
 // GetNetworkByNode - gets the network model from a node
 func GetNetworkByNode(node *models.Node) (models.Network, error) {
 func GetNetworkByNode(node *models.Node) (models.Network, error) {
 
 
-	var network models.Network
+	var network = models.Network{}
 	networkData, err := database.FetchRecord(database.NETWORKS_TABLE_NAME, node.Network)
 	networkData, err := database.FetchRecord(database.NETWORKS_TABLE_NAME, node.Network)
 	if err != nil {
 	if err != nil {
 		return network, err
 		return network, err
@@ -332,13 +357,13 @@ func GetNodeRelay(network string, relayedNodeAddr string) (models.Node, error) {
 		if database.IsEmptyRecord(err) {
 		if database.IsEmptyRecord(err) {
 			return relay, nil
 			return relay, nil
 		}
 		}
-		Log(err.Error(), 2)
+		logger.Log(2, err.Error())
 		return relay, err
 		return relay, err
 	}
 	}
 	for _, value := range collection {
 	for _, value := range collection {
 		err := json.Unmarshal([]byte(value), &relay)
 		err := json.Unmarshal([]byte(value), &relay)
 		if err != nil {
 		if err != nil {
-			Log(err.Error(), 2)
+			logger.Log(2, err.Error())
 			continue
 			continue
 		}
 		}
 		if relay.IsRelay == "yes" {
 		if relay.IsRelay == "yes" {

+ 140 - 0
logic/relay.go

@@ -0,0 +1,140 @@
+package logic
+
+import (
+	"encoding/json"
+	"errors"
+	"time"
+
+	"github.com/gravitl/netmaker/database"
+	"github.com/gravitl/netmaker/logger"
+	"github.com/gravitl/netmaker/models"
+)
+
+// CreateRelay - creates a relay
+func CreateRelay(relay models.RelayRequest) (models.Node, error) {
+	node, err := GetNodeByMacAddress(relay.NetID, relay.NodeID)
+	if node.OS == "macos" { // add in darwin later
+		return models.Node{}, errors.New(node.OS + " is unsupported for relay")
+	}
+	if err != nil {
+		return models.Node{}, err
+	}
+	err = ValidateRelay(relay)
+	if err != nil {
+		return models.Node{}, err
+	}
+	node.IsRelay = "yes"
+	node.RelayAddrs = relay.RelayAddrs
+
+	key, err := GetRecordKey(relay.NodeID, relay.NetID)
+	if err != nil {
+		return node, err
+	}
+	node.SetLastModified()
+	node.PullChanges = "yes"
+	nodeData, err := json.Marshal(&node)
+	if err != nil {
+		return node, err
+	}
+	if err = database.Insert(key, string(nodeData), database.NODES_TABLE_NAME); err != nil {
+		return models.Node{}, err
+	}
+	err = SetRelayedNodes("yes", node.Network, node.RelayAddrs)
+	if err != nil {
+		return node, err
+	}
+
+	if err = NetworkNodesUpdatePullChanges(node.Network); err != nil {
+		return models.Node{}, err
+	}
+	return node, nil
+}
+
+// SetRelayedNodes- set relayed nodes
+func SetRelayedNodes(yesOrno string, networkName string, addrs []string) error {
+
+	collections, err := database.FetchRecords(database.NODES_TABLE_NAME)
+	if err != nil {
+		return err
+	}
+
+	for _, value := range collections {
+
+		var node models.Node
+		err := json.Unmarshal([]byte(value), &node)
+		if err != nil {
+			return err
+		}
+		if node.Network == networkName {
+			for _, addr := range addrs {
+				if addr == node.Address || addr == node.Address6 {
+					node.IsRelayed = yesOrno
+					data, err := json.Marshal(&node)
+					if err != nil {
+						return err
+					}
+					node.SetID()
+					database.Insert(node.ID, string(data), database.NODES_TABLE_NAME)
+				}
+			}
+		}
+	}
+	return nil
+}
+
+// ValidateRelay - checks if relay is valid
+func ValidateRelay(relay models.RelayRequest) error {
+	var err error
+	//isIp := functions.IsIpCIDR(gateway.RangeString)
+	empty := len(relay.RelayAddrs) == 0
+	if empty {
+		err = errors.New("IP Ranges Cannot Be Empty")
+	}
+	return err
+}
+
+// UpdateRelay - updates a relay
+func UpdateRelay(network string, oldAddrs []string, newAddrs []string) {
+	time.Sleep(time.Second / 4)
+	err := SetRelayedNodes("no", network, oldAddrs)
+	if err != nil {
+		logger.Log(1, err.Error())
+	}
+	err = SetRelayedNodes("yes", network, newAddrs)
+	if err != nil {
+		logger.Log(1, err.Error())
+	}
+}
+
+// DeleteRelay - deletes a relay
+func DeleteRelay(network, macaddress string) (models.Node, error) {
+
+	node, err := GetNodeByMacAddress(network, macaddress)
+	if err != nil {
+		return models.Node{}, err
+	}
+	err = SetRelayedNodes("no", node.Network, node.RelayAddrs)
+	if err != nil {
+		return node, err
+	}
+
+	node.IsRelay = "no"
+	node.RelayAddrs = []string{}
+	node.SetLastModified()
+	node.PullChanges = "yes"
+	key, err := GetRecordKey(node.MacAddress, node.Network)
+	if err != nil {
+		return models.Node{}, err
+	}
+	data, err := json.Marshal(&node)
+	if err != nil {
+		return models.Node{}, err
+	}
+	if err = database.Insert(key, string(data), database.NODES_TABLE_NAME); err != nil {
+		return models.Node{}, err
+	}
+	if err = NetworkNodesUpdatePullChanges(network); err != nil {
+		return models.Node{}, err
+	}
+	return node, nil
+}

+ 81 - 122
logic/server.go

@@ -10,6 +10,7 @@ import (
 	"strings"
 	"strings"
 	"time"
 	"time"
 
 
+	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/servercfg"
 	"github.com/gravitl/netmaker/servercfg"
@@ -20,6 +21,8 @@ import (
 
 
 // KUBERNETES_LISTEN_PORT - starting port for Kubernetes in order to use NodePort range
 // KUBERNETES_LISTEN_PORT - starting port for Kubernetes in order to use NodePort range
 const KUBERNETES_LISTEN_PORT = 31821
 const KUBERNETES_LISTEN_PORT = 31821
+
+// KUBERNETES_SERVER_MTU - ideal mtu for kubernetes deployments right now
 const KUBERNETES_SERVER_MTU = 1024
 const KUBERNETES_SERVER_MTU = 1024
 
 
 // ServerJoin - responsible for joining a server to a network
 // ServerJoin - responsible for joining a server to a network
@@ -30,8 +33,7 @@ func ServerJoin(network string, serverID string, privateKey string) error {
 	}
 	}
 
 
 	var err error
 	var err error
-	var node *models.Node // fill this object with server node specifics
-	node = &models.Node{
+	var node = &models.Node{
 		IsServer:     "yes",
 		IsServer:     "yes",
 		DNSOn:        "no",
 		DNSOn:        "no",
 		IsStatic:     "yes",
 		IsStatic:     "yes",
@@ -47,7 +49,7 @@ func ServerJoin(network string, serverID string, privateKey string) error {
 	}
 	}
 
 
 	if node.LocalRange != "" && node.LocalAddress == "" {
 	if node.LocalRange != "" && node.LocalAddress == "" {
-		Log("local vpn, getting local address from range: "+node.LocalRange, 1)
+		logger.Log(1, "local vpn, getting local address from range:", node.LocalRange)
 		node.LocalAddress = GetLocalIP(*node)
 		node.LocalAddress = GetLocalIP(*node)
 	}
 	}
 
 
@@ -58,7 +60,7 @@ func ServerJoin(network string, serverID string, privateKey string) error {
 			node.Endpoint, err = ncutils.GetPublicIP()
 			node.Endpoint, err = ncutils.GetPublicIP()
 		}
 		}
 		if err != nil || node.Endpoint == "" {
 		if err != nil || node.Endpoint == "" {
-			Log("Error setting server node Endpoint.", 0)
+			logger.Log(0, "Error setting server node Endpoint.")
 			return err
 			return err
 		}
 		}
 	}
 	}
@@ -67,36 +69,17 @@ func ServerJoin(network string, serverID string, privateKey string) error {
 	if privateKey == "" {
 	if privateKey == "" {
 		wgPrivatekey, err := wgtypes.GeneratePrivateKey()
 		wgPrivatekey, err := wgtypes.GeneratePrivateKey()
 		if err != nil {
 		if err != nil {
-			Log(err.Error(), 1)
+			logger.Log(1, err.Error())
 			return err
 			return err
 		}
 		}
 		privateKey = wgPrivatekey.String()
 		privateKey = wgPrivatekey.String()
 		node.PublicKey = wgPrivatekey.PublicKey().String()
 		node.PublicKey = wgPrivatekey.PublicKey().String()
 	}
 	}
-	// should never set mac address for server anymore
-
-	var postnode *models.Node
-	postnode = &models.Node{
-		Password:            node.Password,
-		MacAddress:          node.MacAddress,
-		AccessKey:           node.AccessKey,
-		Network:             network,
-		ListenPort:          node.ListenPort,
-		PostUp:              node.PostUp,
-		PostDown:            node.PostDown,
-		PersistentKeepalive: node.PersistentKeepalive,
-		LocalAddress:        node.LocalAddress,
-		Interface:           node.Interface,
-		PublicKey:           node.PublicKey,
-		DNSOn:               node.DNSOn,
-		Name:                node.Name,
-		Endpoint:            node.Endpoint,
-		SaveConfig:          node.SaveConfig,
-		UDPHolePunch:        node.UDPHolePunch,
-	}
 
 
-	Log("adding a server instance on network "+postnode.Network, 2)
-	*node, err = CreateNode(*postnode, network)
+	node.Network = network
+
+	logger.Log(2, "adding a server instance on network", node.Network)
+	err = CreateNode(node)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
@@ -108,9 +91,9 @@ func ServerJoin(network string, serverID string, privateKey string) error {
 	// get free port based on returned default listen port
 	// get free port based on returned default listen port
 	node.ListenPort, err = ncutils.GetFreePort(node.ListenPort)
 	node.ListenPort, err = ncutils.GetFreePort(node.ListenPort)
 	if err != nil {
 	if err != nil {
-		Log("Error retrieving port: "+err.Error(), 2)
+		logger.Log(2, "Error retrieving port:", err.Error())
 	} else {
 	} else {
-		Log("Set client port to "+fmt.Sprintf("%d", node.ListenPort)+" for network "+node.Network, 1)
+		logger.Log(1, "Set client port to", fmt.Sprintf("%d", node.ListenPort), "for network", node.Network)
 	}
 	}
 
 
 	// safety check. If returned node from server is local, but not currently configured as local, set to local addr
 	// safety check. If returned node from server is local, but not currently configured as local, set to local addr
@@ -130,13 +113,13 @@ func ServerJoin(network string, serverID string, privateKey string) error {
 		return err
 		return err
 	}
 	}
 
 
-	peers, hasGateway, gateways, err := GetServerPeers(node.MacAddress, network, node.IsDualStack == "yes", node.IsIngressGateway == "yes")
+	peers, hasGateway, gateways, err := GetServerPeers(node)
 	if err != nil && !ncutils.IsEmptyRecord(err) {
 	if err != nil && !ncutils.IsEmptyRecord(err) {
-		Log("failed to retrieve peers", 1)
+		logger.Log(1, "failed to retrieve peers")
 		return err
 		return err
 	}
 	}
 
 
-	err = initWireguard(node, privateKey, peers, hasGateway, gateways)
+	err = initWireguard(node, privateKey, peers[:], hasGateway, gateways[:])
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
@@ -146,71 +129,68 @@ func ServerJoin(network string, serverID string, privateKey string) error {
 
 
 // ServerCheckin - runs pulls and pushes for server
 // ServerCheckin - runs pulls and pushes for server
 func ServerCheckin(mac string, network string) error {
 func ServerCheckin(mac string, network string) error {
-	var serverNode models.Node
-	var newNode *models.Node
-	var err error
-	serverNode, err = GetNode(mac, network)
+	var serverNode = &models.Node{}
+	var currentNode, err = GetNode(mac, network)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
+	serverNode = &currentNode
 
 
-	newNode, err = ServerPull(&serverNode, false)
+	err = ServerPull(serverNode, false)
 	if isDeleteError(err) {
 	if isDeleteError(err) {
 		return ServerLeave(mac, network)
 		return ServerLeave(mac, network)
 	} else if err != nil {
 	} else if err != nil {
 		return err
 		return err
 	}
 	}
 
 
-	actionCompleted := checkNodeActions(newNode, network, &serverNode)
+	actionCompleted := checkNodeActions(serverNode)
 	if actionCompleted == models.NODE_DELETE {
 	if actionCompleted == models.NODE_DELETE {
 		return errors.New("node has been removed")
 		return errors.New("node has been removed")
 	}
 	}
 
 
-	return ServerPush(newNode)
+	return ServerPush(serverNode)
 }
 }
 
 
 // ServerPull - pulls current config/peers for server
 // ServerPull - pulls current config/peers for server
-func ServerPull(serverNode *models.Node, onErr bool) (*models.Node, error) {
+func ServerPull(serverNode *models.Node, onErr bool) error {
 
 
 	var err error
 	var err error
 	if serverNode.IPForwarding == "yes" {
 	if serverNode.IPForwarding == "yes" {
 		if err = setIPForwardingLinux(); err != nil {
 		if err = setIPForwardingLinux(); err != nil {
-			return serverNode, err
+			return err
 		}
 		}
 	}
 	}
 	serverNode.OS = runtime.GOOS
 	serverNode.OS = runtime.GOOS
 
 
 	if serverNode.PullChanges == "yes" || onErr {
 	if serverNode.PullChanges == "yes" || onErr {
 		// check for interface change
 		// check for interface change
-		var isIfacePresent bool
-		var oldIfaceName string
 		// checks if address is in use by another interface
 		// checks if address is in use by another interface
-		oldIfaceName, isIfacePresent = isInterfacePresent(serverNode.Interface, serverNode.Address)
+		var oldIfaceName, isIfacePresent = isInterfacePresent(serverNode.Interface, serverNode.Address)
 		if !isIfacePresent {
 		if !isIfacePresent {
 			if err = deleteInterface(oldIfaceName, serverNode.PostDown); err != nil {
 			if err = deleteInterface(oldIfaceName, serverNode.PostDown); err != nil {
-				Log("could not delete old interface "+oldIfaceName, 1)
+				logger.Log(1, "could not delete old interface", oldIfaceName)
 			}
 			}
-			Log("removed old interface "+oldIfaceName, 1)
+			logger.Log(1, "removed old interface", oldIfaceName)
 		}
 		}
 		serverNode.PullChanges = "no"
 		serverNode.PullChanges = "no"
-		if err = setWGConfig(*serverNode, serverNode.Network, false); err != nil {
-			return serverNode, err
+		if err = setWGConfig(serverNode, false); err != nil {
+			return err
 		}
 		}
 		// handle server side update
 		// handle server side update
 		if err = UpdateNode(serverNode, serverNode); err != nil {
 		if err = UpdateNode(serverNode, serverNode); err != nil {
-			return serverNode, err
+			return err
 		}
 		}
 	} else {
 	} else {
-		if err = setWGConfig(*serverNode, serverNode.Network, true); err != nil {
+		if err = setWGConfig(serverNode, true); err != nil {
 			if errors.Is(err, os.ErrNotExist) {
 			if errors.Is(err, os.ErrNotExist) {
 				return ServerPull(serverNode, true)
 				return ServerPull(serverNode, true)
 			} else {
 			} else {
-				return serverNode, err
+				return err
 			}
 			}
 		}
 		}
 	}
 	}
 
 
-	return serverNode, nil
+	return nil
 }
 }
 
 
 // ServerPush - pushes config changes for server checkins/join
 // ServerPush - pushes config changes for server checkins/join
@@ -223,9 +203,7 @@ func ServerPush(serverNode *models.Node) error {
 // ServerLeave - removes a server node
 // ServerLeave - removes a server node
 func ServerLeave(mac string, network string) error {
 func ServerLeave(mac string, network string) error {
 
 
-	var serverNode models.Node
-	var err error
-	serverNode, err = GetNode(mac, network)
+	var serverNode, err = GetNode(mac, network)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
@@ -233,36 +211,38 @@ func ServerLeave(mac string, network string) error {
 	return DeleteNode(&serverNode, true)
 	return DeleteNode(&serverNode, true)
 }
 }
 
 
+/**
+ * Below function needs major refactor
+ *
+ */
+
 // GetServerPeers - gets peers of server
 // GetServerPeers - gets peers of server
-func GetServerPeers(macaddress string, network string, dualstack bool, isIngressGateway bool) ([]wgtypes.PeerConfig, bool, []string, error) {
+func GetServerPeers(serverNode *models.Node) ([]wgtypes.PeerConfig, bool, []string, error) {
 	hasGateway := false
 	hasGateway := false
-	var err error
 	var gateways []string
 	var gateways []string
 	var peers []wgtypes.PeerConfig
 	var peers []wgtypes.PeerConfig
-	var nodecfg models.Node
 	var nodes []models.Node // fill above fields from server or client
 	var nodes []models.Node // fill above fields from server or client
 
 
-	nodecfg, err = GetNode(macaddress, network)
+	var nodecfg, err = GetNode(serverNode.MacAddress, serverNode.Network)
 	if err != nil {
 	if err != nil {
 		return nil, hasGateway, gateways, err
 		return nil, hasGateway, gateways, err
 	}
 	}
-	nodes, err = GetPeers(nodecfg)
+	nodes, err = GetPeers(&nodecfg)
 	if err != nil {
 	if err != nil {
 		return nil, hasGateway, gateways, err
 		return nil, hasGateway, gateways, err
 	}
 	}
 
 
 	keepalive := nodecfg.PersistentKeepalive
 	keepalive := nodecfg.PersistentKeepalive
 	keepalivedur, err := time.ParseDuration(strconv.FormatInt(int64(keepalive), 10) + "s")
 	keepalivedur, err := time.ParseDuration(strconv.FormatInt(int64(keepalive), 10) + "s")
-	keepaliveserver, err := time.ParseDuration(strconv.FormatInt(int64(5), 10) + "s")
 	if err != nil {
 	if err != nil {
-		Log("Issue with format of keepalive value. Please view server config. "+err.Error(), 1)
+		logger.Log(1, "Issue with format of keepalive duration value, Please view server config:", err.Error())
 		return nil, hasGateway, gateways, err
 		return nil, hasGateway, gateways, err
 	}
 	}
 
 
 	for _, node := range nodes {
 	for _, node := range nodes {
 		pubkey, err := wgtypes.ParseKey(node.PublicKey)
 		pubkey, err := wgtypes.ParseKey(node.PublicKey)
 		if err != nil {
 		if err != nil {
-			Log("error parsing key "+pubkey.String(), 1)
+			logger.Log(1, "error parsing key", pubkey.String())
 			return peers, hasGateway, gateways, err
 			return peers, hasGateway, gateways, err
 		}
 		}
 
 
@@ -282,8 +262,9 @@ func GetServerPeers(macaddress string, network string, dualstack bool, isIngress
 			IP:   net.ParseIP(node.Address),
 			IP:   net.ParseIP(node.Address),
 			Mask: net.CIDRMask(32, 32),
 			Mask: net.CIDRMask(32, 32),
 		}
 		}
-		var allowedips []net.IPNet
-		allowedips = append(allowedips, peeraddr)
+		var allowedips = []net.IPNet{
+			peeraddr,
+		}
 		// handle manually set peers
 		// handle manually set peers
 		for _, allowedIp := range node.AllowedIPs {
 		for _, allowedIp := range node.AllowedIPs {
 			if _, ipnet, err := net.ParseCIDR(allowedIp); err == nil {
 			if _, ipnet, err := net.ParseCIDR(allowedIp); err == nil {
@@ -306,92 +287,66 @@ func GetServerPeers(macaddress string, network string, dualstack bool, isIngress
 			for _, iprange := range ranges { // go through each cidr for egress gateway
 			for _, iprange := range ranges { // go through each cidr for egress gateway
 				_, ipnet, err := net.ParseCIDR(iprange) // confirming it's valid cidr
 				_, ipnet, err := net.ParseCIDR(iprange) // confirming it's valid cidr
 				if err != nil {
 				if err != nil {
-					Log("could not parse gateway IP range. Not adding "+iprange, 1)
+					logger.Log(1, "could not parse gateway IP range. Not adding", iprange)
 					continue // if can't parse CIDR
 					continue // if can't parse CIDR
 				}
 				}
 				nodeEndpointArr := strings.Split(node.Endpoint, ":") // getting the public ip of node
 				nodeEndpointArr := strings.Split(node.Endpoint, ":") // getting the public ip of node
 				if ipnet.Contains(net.ParseIP(nodeEndpointArr[0])) { // ensuring egress gateway range does not contain public ip of node
 				if ipnet.Contains(net.ParseIP(nodeEndpointArr[0])) { // ensuring egress gateway range does not contain public ip of node
-					Log("egress IP range of "+iprange+" overlaps with "+node.Endpoint+", omitting", 2)
+					logger.Log(2, "egress IP range of", iprange, "overlaps with", node.Endpoint, ", omitting")
 					continue // skip adding egress range if overlaps with node's ip
 					continue // skip adding egress range if overlaps with node's ip
 				}
 				}
 				if ipnet.Contains(net.ParseIP(nodecfg.LocalAddress)) { // ensuring egress gateway range does not contain public ip of node
 				if ipnet.Contains(net.ParseIP(nodecfg.LocalAddress)) { // ensuring egress gateway range does not contain public ip of node
-					Log("egress IP range of "+iprange+" overlaps with "+nodecfg.LocalAddress+", omitting", 2)
+					logger.Log(2, "egress IP range of", iprange, "overlaps with", nodecfg.LocalAddress, ", omitting")
 					continue // skip adding egress range if overlaps with node's local ip
 					continue // skip adding egress range if overlaps with node's local ip
 				}
 				}
 				gateways = append(gateways, iprange)
 				gateways = append(gateways, iprange)
 				if err != nil {
 				if err != nil {
-					Log("ERROR ENCOUNTERED SETTING GATEWAY", 1)
+					logger.Log(1, "ERROR ENCOUNTERED SETTING GATEWAY:", err.Error())
 				} else {
 				} else {
 					allowedips = append(allowedips, *ipnet)
 					allowedips = append(allowedips, *ipnet)
 				}
 				}
 			}
 			}
+			ranges = nil
 		}
 		}
-		if node.Address6 != "" && dualstack {
+		if node.Address6 != "" && serverNode.IsDualStack == "yes" {
 			var addr6 = net.IPNet{
 			var addr6 = net.IPNet{
 				IP:   net.ParseIP(node.Address6),
 				IP:   net.ParseIP(node.Address6),
 				Mask: net.CIDRMask(128, 128),
 				Mask: net.CIDRMask(128, 128),
 			}
 			}
 			allowedips = append(allowedips, addr6)
 			allowedips = append(allowedips, addr6)
 		}
 		}
-		if nodecfg.IsServer == "yes" && !(node.IsServer == "yes") {
-			peer = wgtypes.PeerConfig{
-				PublicKey:                   pubkey,
-				PersistentKeepaliveInterval: &keepaliveserver,
-				ReplaceAllowedIPs:           true,
-				AllowedIPs:                  allowedips,
-			}
-		} else if keepalive != 0 {
-			peer = wgtypes.PeerConfig{
-				PublicKey:                   pubkey,
-				PersistentKeepaliveInterval: &keepalivedur,
-				Endpoint: &net.UDPAddr{
-					IP:   net.ParseIP(node.Endpoint),
-					Port: int(node.ListenPort),
-				},
-				ReplaceAllowedIPs: true,
-				AllowedIPs:        allowedips,
-			}
-		} else {
-			peer = wgtypes.PeerConfig{
-				PublicKey: pubkey,
-				Endpoint: &net.UDPAddr{
-					IP:   net.ParseIP(node.Endpoint),
-					Port: int(node.ListenPort),
-				},
-				ReplaceAllowedIPs: true,
-				AllowedIPs:        allowedips,
-			}
+		peer = wgtypes.PeerConfig{
+			PublicKey:                   pubkey,
+			PersistentKeepaliveInterval: &(keepalivedur),
+			ReplaceAllowedIPs:           true,
+			AllowedIPs:                  allowedips,
 		}
 		}
 		peers = append(peers, peer)
 		peers = append(peers, peer)
 	}
 	}
-	if isIngressGateway {
-		extPeers, err := GetServerExtPeers(macaddress, network, dualstack)
+	if serverNode.IsIngressGateway == "yes" {
+		extPeers, err := GetServerExtPeers(serverNode)
 		if err == nil {
 		if err == nil {
 			peers = append(peers, extPeers...)
 			peers = append(peers, extPeers...)
 		} else {
 		} else {
-			Log("ERROR RETRIEVING EXTERNAL PEERS ON SERVER", 1)
+			logger.Log(1, "ERROR RETRIEVING EXTERNAL PEERS ON SERVER:", err.Error())
 		}
 		}
+		extPeers = nil
 	}
 	}
 	return peers, hasGateway, gateways, err
 	return peers, hasGateway, gateways, err
 }
 }
 
 
 // GetServerExtPeers - gets the extpeers for a client
 // GetServerExtPeers - gets the extpeers for a client
-func GetServerExtPeers(macaddress string, network string, dualstack bool) ([]wgtypes.PeerConfig, error) {
+func GetServerExtPeers(serverNode *models.Node) ([]wgtypes.PeerConfig, error) {
 	var peers []wgtypes.PeerConfig
 	var peers []wgtypes.PeerConfig
-	var nodecfg models.Node
 	var extPeers []models.Node
 	var extPeers []models.Node
 	var err error
 	var err error
-	// fill above fields from either client or server
-
-	nodecfg, err = GetNode(macaddress, network)
-	if err != nil {
-		return nil, err
-	}
 	var tempPeers []models.ExtPeersResponse
 	var tempPeers []models.ExtPeersResponse
-	tempPeers, err = GetExtPeersList(nodecfg.MacAddress, nodecfg.Network)
+
+	tempPeers, err = GetExtPeersList(serverNode.MacAddress, serverNode.Network)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
+
 	for i := 0; i < len(tempPeers); i++ {
 	for i := 0; i < len(tempPeers); i++ {
 		extPeers = append(extPeers, models.Node{
 		extPeers = append(extPeers, models.Node{
 			Address:             tempPeers[i].Address,
 			Address:             tempPeers[i].Address,
@@ -409,7 +364,7 @@ func GetServerExtPeers(macaddress string, network string, dualstack bool) ([]wgt
 			return peers, err
 			return peers, err
 		}
 		}
 
 
-		if nodecfg.PublicKey == extPeer.PublicKey {
+		if serverNode.PublicKey == extPeer.PublicKey {
 			continue
 			continue
 		}
 		}
 
 
@@ -418,10 +373,11 @@ func GetServerExtPeers(macaddress string, network string, dualstack bool) ([]wgt
 			IP:   net.ParseIP(extPeer.Address),
 			IP:   net.ParseIP(extPeer.Address),
 			Mask: net.CIDRMask(32, 32),
 			Mask: net.CIDRMask(32, 32),
 		}
 		}
-		var allowedips []net.IPNet
-		allowedips = append(allowedips, peeraddr)
+		var allowedips = []net.IPNet{
+			peeraddr,
+		}
 
 
-		if extPeer.Address6 != "" && dualstack {
+		if extPeer.Address6 != "" && serverNode.IsDualStack == "yes" {
 			var addr6 = net.IPNet{
 			var addr6 = net.IPNet{
 				IP:   net.ParseIP(extPeer.Address6),
 				IP:   net.ParseIP(extPeer.Address6),
 				Mask: net.CIDRMask(128, 128),
 				Mask: net.CIDRMask(128, 128),
@@ -434,7 +390,10 @@ func GetServerExtPeers(macaddress string, network string, dualstack bool) ([]wgt
 			AllowedIPs:        allowedips,
 			AllowedIPs:        allowedips,
 		}
 		}
 		peers = append(peers, peer)
 		peers = append(peers, peer)
+		allowedips = nil
 	}
 	}
+	tempPeers = nil
+	extPeers = nil
 	return peers, err
 	return peers, err
 }
 }
 
 
@@ -444,19 +403,19 @@ func isDeleteError(err error) bool {
 	return err != nil && strings.Contains(err.Error(), models.NODE_DELETE)
 	return err != nil && strings.Contains(err.Error(), models.NODE_DELETE)
 }
 }
 
 
-func checkNodeActions(node *models.Node, networkName string, localNode *models.Node) string {
-	if (node.Action == models.NODE_UPDATE_KEY || localNode.Action == models.NODE_UPDATE_KEY) &&
+func checkNodeActions(node *models.Node) string {
+	if (node.Action == models.NODE_UPDATE_KEY) &&
 		node.IsStatic != "yes" {
 		node.IsStatic != "yes" {
-		err := setWGKeyConfig(*node)
+		err := setWGKeyConfig(node)
 		if err != nil {
 		if err != nil {
-			Log("unable to process reset keys request: "+err.Error(), 1)
+			logger.Log(1, "unable to process reset keys request:", err.Error())
 			return ""
 			return ""
 		}
 		}
 	}
 	}
-	if node.Action == models.NODE_DELETE || localNode.Action == models.NODE_DELETE {
-		err := ServerLeave(node.MacAddress, networkName)
+	if node.Action == models.NODE_DELETE {
+		err := ServerLeave(node.MacAddress, node.Network)
 		if err != nil {
 		if err != nil {
-			Log("error deleting locally: "+err.Error(), 1)
+			logger.Log(1, "error deleting locally:", err.Error())
 		}
 		}
 		return models.NODE_DELETE
 		return models.NODE_DELETE
 	}
 	}

+ 3 - 5
logic/serverconf.go

@@ -12,12 +12,11 @@ type serverData struct {
 
 
 // StorePrivKey - stores server client WireGuard privatekey if needed
 // StorePrivKey - stores server client WireGuard privatekey if needed
 func StorePrivKey(serverID string, privateKey string) error {
 func StorePrivKey(serverID string, privateKey string) error {
-	var newData *serverData
-	newData = &serverData{}
+	var newData = serverData{}
 	var err error
 	var err error
 	var data []byte
 	var data []byte
 	newData.PrivateKey = privateKey
 	newData.PrivateKey = privateKey
-	data, err = json.Marshal(newData)
+	data, err = json.Marshal(&newData)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
@@ -28,8 +27,7 @@ func StorePrivKey(serverID string, privateKey string) error {
 func FetchPrivKey(serverID string) (string, error) {
 func FetchPrivKey(serverID string) (string, error) {
 	var dbData string
 	var dbData string
 	var err error
 	var err error
-	var fetchedData serverData
-	fetchedData = serverData{}
+	var fetchedData = serverData{}
 	dbData, err = database.FetchRecord(database.SERVERCONF_TABLE_NAME, serverID)
 	dbData, err = database.FetchRecord(database.SERVERCONF_TABLE_NAME, serverID)
 	if err != nil {
 	if err != nil {
 		return "", err
 		return "", err

+ 42 - 53
logic/util.go

@@ -4,13 +4,13 @@ package logic
 import (
 import (
 	"encoding/base64"
 	"encoding/base64"
 	"encoding/json"
 	"encoding/json"
-	"log"
 	"math/rand"
 	"math/rand"
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
 	"time"
 	"time"
 
 
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/database"
+	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/servercfg"
 	"github.com/gravitl/netmaker/servercfg"
@@ -34,10 +34,10 @@ func CheckEndpoint(endpoint string) bool {
 func SetNetworkServerPeers(node *models.Node) {
 func SetNetworkServerPeers(node *models.Node) {
 	if currentPeersList, err := GetSystemPeers(node); err == nil {
 	if currentPeersList, err := GetSystemPeers(node); err == nil {
 		if database.SetPeers(currentPeersList, node.Network) {
 		if database.SetPeers(currentPeersList, node.Network) {
-			Log("set new peers on network "+node.Network, 1)
+			logger.Log(1, "set new peers on network", node.Network)
 		}
 		}
 	} else {
 	} else {
-		Log("could not set peers on network "+node.Network+"\n"+err.Error(), 1)
+		logger.Log(1, "could not set peers on network", node.Network, ":", err.Error())
 	}
 	}
 }
 }
 
 
@@ -63,31 +63,28 @@ func DeleteNode(node *models.Node, exterminate bool) error {
 		}
 		}
 	} else {
 	} else {
 		if err := database.DeleteRecord(database.DELETED_NODES_TABLE_NAME, key); err != nil {
 		if err := database.DeleteRecord(database.DELETED_NODES_TABLE_NAME, key); err != nil {
-			Log(err.Error(), 2)
+			logger.Log(2, err.Error())
 		}
 		}
 	}
 	}
 	if err = database.DeleteRecord(database.NODES_TABLE_NAME, key); err != nil {
 	if err = database.DeleteRecord(database.NODES_TABLE_NAME, key); err != nil {
 		return err
 		return err
 	}
 	}
 	if servercfg.IsDNSMode() {
 	if servercfg.IsDNSMode() {
-		err = SetDNS()
+		SetDNS()
 	}
 	}
 	return removeLocalServer(node)
 	return removeLocalServer(node)
 }
 }
 
 
 // CreateNode - creates a node in database
 // CreateNode - creates a node in database
-func CreateNode(node models.Node, networkName string) (models.Node, error) {
+func CreateNode(node *models.Node) error {
 
 
 	//encrypt that password so we never see it
 	//encrypt that password so we never see it
 	hash, err := bcrypt.GenerateFromPassword([]byte(node.Password), 5)
 	hash, err := bcrypt.GenerateFromPassword([]byte(node.Password), 5)
-
 	if err != nil {
 	if err != nil {
-		return node, err
+		return err
 	}
 	}
 	//set password to encrypted password
 	//set password to encrypted password
 	node.Password = string(hash)
 	node.Password = string(hash)
-
-	node.Network = networkName
 	if node.Name == models.NODE_SERVER_NAME {
 	if node.Name == models.NODE_SERVER_NAME {
 		node.IsServer = "yes"
 		node.IsServer = "yes"
 	}
 	}
@@ -98,36 +95,36 @@ func CreateNode(node models.Node, networkName string) (models.Node, error) {
 			node.DNSOn = "no"
 			node.DNSOn = "no"
 		}
 		}
 	}
 	}
-	SetNodeDefaults(&node)
-	node.Address, err = UniqueAddress(networkName)
+	SetNodeDefaults(node)
+	node.Address, err = UniqueAddress(node.Network)
 	if err != nil {
 	if err != nil {
-		return node, err
+		return err
 	}
 	}
-	node.Address6, err = UniqueAddress6(networkName)
+	node.Address6, err = UniqueAddress6(node.Network)
 	if err != nil {
 	if err != nil {
-		return node, err
+		return err
 	}
 	}
 	//Create a JWT for the node
 	//Create a JWT for the node
-	tokenString, _ := CreateJWT(node.MacAddress, networkName)
+	tokenString, _ := CreateJWT(node.MacAddress, node.Network)
 	if tokenString == "" {
 	if tokenString == "" {
 		//returnErrorResponse(w, r, errorResponse)
 		//returnErrorResponse(w, r, errorResponse)
-		return node, err
+		return err
 	}
 	}
-	err = ValidateNode(&node, false)
+	err = ValidateNode(node, false)
 	if err != nil {
 	if err != nil {
-		return node, err
+		return err
 	}
 	}
 	key, err := GetRecordKey(node.MacAddress, node.Network)
 	key, err := GetRecordKey(node.MacAddress, node.Network)
 	if err != nil {
 	if err != nil {
-		return node, err
+		return err
 	}
 	}
 	nodebytes, err := json.Marshal(&node)
 	nodebytes, err := json.Marshal(&node)
 	if err != nil {
 	if err != nil {
-		return node, err
+		return err
 	}
 	}
 	err = database.Insert(key, string(nodebytes), database.NODES_TABLE_NAME)
 	err = database.Insert(key, string(nodebytes), database.NODES_TABLE_NAME)
 	if err != nil {
 	if err != nil {
-		return node, err
+		return err
 	}
 	}
 	if node.IsPending != "yes" {
 	if node.IsPending != "yes" {
 		DecrimentKey(node.Network, node.AccessKey)
 		DecrimentKey(node.Network, node.AccessKey)
@@ -136,7 +133,7 @@ func CreateNode(node models.Node, networkName string) (models.Node, error) {
 	if servercfg.IsDNSMode() {
 	if servercfg.IsDNSMode() {
 		err = SetDNS()
 		err = SetDNS()
 	}
 	}
-	return node, err
+	return err
 }
 }
 
 
 // SetNetworkNodesLastModified - sets the network nodes last modified
 // SetNetworkNodesLastModified - sets the network nodes last modified
@@ -171,7 +168,7 @@ func GetNode(macaddress string, network string) (models.Node, error) {
 	data, err := database.FetchRecord(database.NODES_TABLE_NAME, key)
 	data, err := database.FetchRecord(database.NODES_TABLE_NAME, key)
 	if err != nil {
 	if err != nil {
 		if data == "" {
 		if data == "" {
-			data, err = database.FetchRecord(database.DELETED_NODES_TABLE_NAME, key)
+			data, _ = database.FetchRecord(database.DELETED_NODES_TABLE_NAME, key)
 			err = json.Unmarshal([]byte(data), &node)
 			err = json.Unmarshal([]byte(data), &node)
 		}
 		}
 		return node, err
 		return node, err
@@ -192,19 +189,19 @@ func GetNodePeers(networkName string, excludeRelayed bool) ([]models.Node, error
 		if database.IsEmptyRecord(err) {
 		if database.IsEmptyRecord(err) {
 			return peers, nil
 			return peers, nil
 		}
 		}
-		Log(err.Error(), 2)
+		logger.Log(2, err.Error())
 		return nil, err
 		return nil, err
 	}
 	}
 	udppeers, errN := database.GetPeers(networkName)
 	udppeers, errN := database.GetPeers(networkName)
 	if errN != nil {
 	if errN != nil {
-		Log(errN.Error(), 2)
+		logger.Log(2, errN.Error())
 	}
 	}
 	for _, value := range collection {
 	for _, value := range collection {
-		var node models.Node
-		var peer models.Node
-		err := json.Unmarshal([]byte(value), &node)
+		var node = &models.Node{}
+		var peer = models.Node{}
+		err := json.Unmarshal([]byte(value), node)
 		if err != nil {
 		if err != nil {
-			Log(err.Error(), 2)
+			logger.Log(2, err.Error())
 			continue
 			continue
 		}
 		}
 		if node.IsEgressGateway == "yes" { // handle egress stuff
 		if node.IsEgressGateway == "yes" { // handle egress stuff
@@ -244,32 +241,31 @@ func GetNodePeers(networkName string, excludeRelayed bool) ([]models.Node, error
 // GetPeersList - gets the peers of a given network
 // GetPeersList - gets the peers of a given network
 func GetPeersList(networkName string, excludeRelayed bool, relayedNodeAddr string) ([]models.Node, error) {
 func GetPeersList(networkName string, excludeRelayed bool, relayedNodeAddr string) ([]models.Node, error) {
 	var peers []models.Node
 	var peers []models.Node
-	var relayNode models.Node
 	var err error
 	var err error
 	if relayedNodeAddr == "" {
 	if relayedNodeAddr == "" {
 		peers, err = GetNodePeers(networkName, excludeRelayed)
 		peers, err = GetNodePeers(networkName, excludeRelayed)
-
 	} else {
 	} else {
+		var relayNode models.Node
 		relayNode, err = GetNodeRelay(networkName, relayedNodeAddr)
 		relayNode, err = GetNodeRelay(networkName, relayedNodeAddr)
 		if relayNode.Address != "" {
 		if relayNode.Address != "" {
-			relayNode = setPeerInfo(relayNode)
+			var peerNode = setPeerInfo(&relayNode)
 			network, err := GetNetwork(networkName)
 			network, err := GetNetwork(networkName)
 			if err == nil {
 			if err == nil {
-				relayNode.AllowedIPs = append(relayNode.AllowedIPs, network.AddressRange)
+				peerNode.AllowedIPs = append(peerNode.AllowedIPs, network.AddressRange)
 			} else {
 			} else {
-				relayNode.AllowedIPs = append(relayNode.AllowedIPs, relayNode.RelayAddrs...)
+				peerNode.AllowedIPs = append(peerNode.AllowedIPs, peerNode.RelayAddrs...)
 			}
 			}
 			nodepeers, err := GetNodePeers(networkName, false)
 			nodepeers, err := GetNodePeers(networkName, false)
-			if err == nil && relayNode.UDPHolePunch == "yes" {
+			if err == nil && peerNode.UDPHolePunch == "yes" {
 				for _, nodepeer := range nodepeers {
 				for _, nodepeer := range nodepeers {
-					if nodepeer.Address == relayNode.Address {
-						relayNode.Endpoint = nodepeer.Endpoint
-						relayNode.ListenPort = nodepeer.ListenPort
+					if nodepeer.Address == peerNode.Address {
+						peerNode.Endpoint = nodepeer.Endpoint
+						peerNode.ListenPort = nodepeer.ListenPort
 					}
 					}
 				}
 				}
 			}
 			}
 
 
-			peers = append(peers, relayNode)
+			peers = append(peers, peerNode)
 		}
 		}
 	}
 	}
 	return peers, err
 	return peers, err
@@ -277,7 +273,7 @@ func GetPeersList(networkName string, excludeRelayed bool, relayedNodeAddr strin
 
 
 // RandomString - returns a random string in a charset
 // RandomString - returns a random string in a charset
 func RandomString(length int) string {
 func RandomString(length int) string {
-	const charset = "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
+	const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
 
 
 	var seededRand *rand.Rand = rand.New(rand.NewSource(time.Now().UnixNano()))
 	var seededRand *rand.Rand = rand.New(rand.NewSource(time.Now().UnixNano()))
 
 
@@ -288,7 +284,9 @@ func RandomString(length int) string {
 	return string(b)
 	return string(b)
 }
 }
 
 
-func setPeerInfo(node models.Node) models.Node {
+// == Private Methods ==
+
+func setPeerInfo(node *models.Node) models.Node {
 	var peer models.Node
 	var peer models.Node
 	peer.RelayAddrs = node.RelayAddrs
 	peer.RelayAddrs = node.RelayAddrs
 	peer.IsRelay = node.IsRelay
 	peer.IsRelay = node.IsRelay
@@ -311,26 +309,17 @@ func setPeerInfo(node models.Node) models.Node {
 	return peer
 	return peer
 }
 }
 
 
-func Log(message string, loglevel int) {
-	log.SetFlags(log.Flags() &^ (log.Llongfile | log.Lshortfile))
-	if int32(loglevel) <= servercfg.GetVerbose() && servercfg.GetVerbose() >= 0 {
-		log.Println("[netmaker] " + message)
-	}
-}
-
-// == Private Methods ==
-
 func setIPForwardingLinux() error {
 func setIPForwardingLinux() error {
 	out, err := ncutils.RunCmd("sysctl net.ipv4.ip_forward", true)
 	out, err := ncutils.RunCmd("sysctl net.ipv4.ip_forward", true)
 	if err != nil {
 	if err != nil {
-		log.Println("WARNING: Error encountered setting ip forwarding. This can break functionality.")
+		logger.Log(0, "WARNING: Error encountered setting ip forwarding. This can break functionality.")
 		return err
 		return err
 	} else {
 	} else {
 		s := strings.Fields(string(out))
 		s := strings.Fields(string(out))
 		if s[2] != "1" {
 		if s[2] != "1" {
 			_, err = ncutils.RunCmd("sysctl -w net.ipv4.ip_forward=1", true)
 			_, err = ncutils.RunCmd("sysctl -w net.ipv4.ip_forward=1", true)
 			if err != nil {
 			if err != nil {
-				log.Println("WARNING: Error encountered setting ip forwarding. You may want to investigate this.")
+				logger.Log(0, "WARNING: Error encountered setting ip forwarding. You may want to investigate this.")
 				return err
 				return err
 			}
 			}
 		}
 		}

+ 51 - 47
logic/wireguard.go

@@ -4,13 +4,13 @@ import (
 	"errors"
 	"errors"
 	"fmt"
 	"fmt"
 	"io/ioutil"
 	"io/ioutil"
-	"log"
 	"os"
 	"os"
 	"os/exec"
 	"os/exec"
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
 	"time"
 	"time"
 
 
+	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"golang.zx2c4.com/wireguard/wgctrl"
 	"golang.zx2c4.com/wireguard/wgctrl"
@@ -25,6 +25,7 @@ func GetSystemPeers(node *models.Node) (map[string]string, error) {
 	if err != nil {
 	if err != nil {
 		return peers, err
 		return peers, err
 	}
 	}
+	defer client.Close()
 	device, err := client.Device(node.Interface)
 	device, err := client.Device(node.Interface)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
@@ -45,7 +46,7 @@ func RemoveConf(iface string, printlog bool) error {
 	return err
 	return err
 }
 }
 
 
-// Private Functions
+// == Private Functions ==
 
 
 func initWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig, hasGateway bool, gateways []string) error {
 func initWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig, hasGateway bool, gateways []string) error {
 
 
@@ -64,14 +65,14 @@ func initWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig
 	if node.Interface != "" {
 	if node.Interface != "" {
 		ifacename = node.Interface
 		ifacename = node.Interface
 	} else {
 	} else {
-		Log("no server interface provided to configure", 2)
+		logger.Log(2, "no server interface provided to configure")
 	}
 	}
 	if node.Address == "" {
 	if node.Address == "" {
-		Log("no server address to provided configure", 2)
+		logger.Log(2, "no server address to provided configure")
 	}
 	}
 
 
 	if ncutils.IsKernel() {
 	if ncutils.IsKernel() {
-		Log("setting kernel device "+ifacename, 2)
+		logger.Log(2, "setting kernel device", ifacename)
 		setKernelDevice(ifacename, node.Address)
 		setKernelDevice(ifacename, node.Address)
 	}
 	}
 
 
@@ -87,18 +88,18 @@ func initWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig
 		var newConf string
 		var newConf string
 		newConf, _ = ncutils.CreateUserSpaceConf(node.Address, key.String(), strconv.FormatInt(int64(node.ListenPort), 10), node.MTU, node.PersistentKeepalive, peers)
 		newConf, _ = ncutils.CreateUserSpaceConf(node.Address, key.String(), strconv.FormatInt(int64(node.ListenPort), 10), node.MTU, node.PersistentKeepalive, peers)
 		confPath := ncutils.GetNetclientPathSpecific() + ifacename + ".conf"
 		confPath := ncutils.GetNetclientPathSpecific() + ifacename + ".conf"
-		Log("writing wg conf file to: "+confPath, 1)
+		logger.Log(1, "writing wg conf file to:", confPath)
 		err = ioutil.WriteFile(confPath, []byte(newConf), 0644)
 		err = ioutil.WriteFile(confPath, []byte(newConf), 0644)
 		if err != nil {
 		if err != nil {
-			Log("error writing wg conf file to "+confPath+": "+err.Error(), 1)
+			logger.Log(1, "error writing wg conf file to", confPath, ":", err.Error())
 			return err
 			return err
 		}
 		}
 		if ncutils.IsWindows() {
 		if ncutils.IsWindows() {
 			wgConfPath := ncutils.GetWGPathSpecific() + ifacename + ".conf"
 			wgConfPath := ncutils.GetWGPathSpecific() + ifacename + ".conf"
-			Log("writing wg conf file to: "+confPath, 1)
+			logger.Log(1, "writing wg conf file to:", confPath)
 			err = ioutil.WriteFile(wgConfPath, []byte(newConf), 0644)
 			err = ioutil.WriteFile(wgConfPath, []byte(newConf), 0644)
 			if err != nil {
 			if err != nil {
-				Log("error writing wg conf file to "+wgConfPath+": "+err.Error(), 1)
+				logger.Log(1, "error writing wg conf file to", wgConfPath, ":", err.Error())
 				return err
 				return err
 			}
 			}
 			confPath = wgConfPath
 			confPath = wgConfPath
@@ -114,7 +115,7 @@ func initWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig
 		time.Sleep(time.Second >> 2)
 		time.Sleep(time.Second >> 2)
 		err = applyWGQuickConf(confPath)
 		err = applyWGQuickConf(confPath)
 		if err != nil {
 		if err != nil {
-			Log("failed to create wireguard interface", 1)
+			logger.Log(1, "failed to create wireguard interface")
 			return err
 			return err
 		}
 		}
 	} else {
 	} else {
@@ -144,7 +145,7 @@ func initWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig
 		}
 		}
 
 
 		if _, err := ncutils.RunCmd(ipExec+" link set down dev "+ifacename, false); err != nil {
 		if _, err := ncutils.RunCmd(ipExec+" link set down dev "+ifacename, false); err != nil {
-			Log("attempted to remove interface before editing", 2)
+			logger.Log(2, "attempted to remove interface before editing")
 			return err
 			return err
 		}
 		}
 
 
@@ -154,7 +155,7 @@ func initWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig
 		}
 		}
 		// set MTU of node interface
 		// set MTU of node interface
 		if _, err := ncutils.RunCmd(ipExec+" link set mtu "+strconv.Itoa(int(node.MTU))+" up dev "+ifacename, true); err != nil {
 		if _, err := ncutils.RunCmd(ipExec+" link set mtu "+strconv.Itoa(int(node.MTU))+" up dev "+ifacename, true); err != nil {
-			Log("failed to create interface with mtu "+strconv.Itoa(int(node.MTU))+" - "+ifacename, 2)
+			logger.Log(2, "failed to create interface with mtu", strconv.Itoa(int(node.MTU)), "-", ifacename)
 			return err
 			return err
 		}
 		}
 
 
@@ -168,7 +169,7 @@ func initWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig
 			}
 			}
 		}
 		}
 		if node.Address6 != "" && node.IsDualStack == "yes" {
 		if node.Address6 != "" && node.IsDualStack == "yes" {
-			log.Println("[netclient] adding address: "+node.Address6, 1)
+			logger.Log(1, "adding address:", node.Address6)
 			_, _ = ncutils.RunCmd(ipExec+" address add dev "+ifacename+" "+node.Address6+"/64", true)
 			_, _ = ncutils.RunCmd(ipExec+" address add dev "+ifacename+" "+node.Address6+"/64", true)
 		}
 		}
 	}
 	}
@@ -207,29 +208,31 @@ func setServerPeers(iface string, keepalive int32, peers []wgtypes.PeerConfig) e
 
 
 	client, err := wgctrl.New()
 	client, err := wgctrl.New()
 	if err != nil {
 	if err != nil {
-		Log("failed to start wgctrl", 0)
+		logger.Log(0, "failed to start wgctrl")
 		return err
 		return err
 	}
 	}
+	defer client.Close()
 
 
 	device, err := client.Device(iface)
 	device, err := client.Device(iface)
 	if err != nil {
 	if err != nil {
-		Log("failed to parse interface", 0)
+		logger.Log(1, "failed to parse interface")
 		return err
 		return err
 	}
 	}
 	devicePeers := device.Peers
 	devicePeers := device.Peers
 	if len(devicePeers) > 1 && len(peers) == 0 {
 	if len(devicePeers) > 1 && len(peers) == 0 {
-		Log("no peers pulled", 1)
+		logger.Log(1, "no peers pulled")
 		return err
 		return err
 	}
 	}
 
 
 	for _, peer := range peers {
 	for _, peer := range peers {
-
-		for _, currentPeer := range devicePeers {
-			if currentPeer.AllowedIPs[0].String() == peer.AllowedIPs[0].String() &&
-				currentPeer.PublicKey.String() != peer.PublicKey.String() {
-				_, err := ncutils.RunCmd("wg set "+iface+" peer "+currentPeer.PublicKey.String()+" remove", true)
-				if err != nil {
-					log.Println("error removing peer", peer.Endpoint.String())
+		if len(peer.AllowedIPs) > 0 {
+			for _, currentPeer := range devicePeers {
+				if len(currentPeer.AllowedIPs) > 0 && currentPeer.AllowedIPs[0].String() == peer.AllowedIPs[0].String() &&
+					currentPeer.PublicKey.String() != peer.PublicKey.String() {
+					_, err := ncutils.RunCmd("wg set "+iface+" peer "+currentPeer.PublicKey.String()+" remove", true)
+					if err != nil {
+						logger.Log(0, "error removing peer", peer.Endpoint.String())
+					}
 				}
 				}
 			}
 			}
 		}
 		}
@@ -255,21 +258,23 @@ func setServerPeers(iface string, keepalive int32, peers []wgtypes.PeerConfig) e
 				" allowed-ips "+allowedips, true)
 				" allowed-ips "+allowedips, true)
 		}
 		}
 		if err != nil {
 		if err != nil {
-			Log("error setting peer "+peer.PublicKey.String(), 1)
+			logger.Log(2, "error setting peer", peer.PublicKey.String())
 		}
 		}
 	}
 	}
 
 
 	for _, currentPeer := range devicePeers {
 	for _, currentPeer := range devicePeers {
-		shouldDelete := true
-		for _, peer := range peers {
-			if peer.AllowedIPs[0].String() == currentPeer.AllowedIPs[0].String() {
-				shouldDelete = false
+		if len(currentPeer.AllowedIPs) > 0 {
+			shouldDelete := true
+			for _, peer := range peers {
+				if len(peer.AllowedIPs) > 0 && peer.AllowedIPs[0].String() == currentPeer.AllowedIPs[0].String() {
+					shouldDelete = false
+				}
 			}
 			}
-		}
-		if shouldDelete {
-			output, err := ncutils.RunCmd("wg set "+iface+" peer "+currentPeer.PublicKey.String()+" remove", true)
-			if err != nil {
-				log.Println(output, "error removing peer", currentPeer.PublicKey.String())
+			if shouldDelete {
+				output, err := ncutils.RunCmd("wg set "+iface+" peer "+currentPeer.PublicKey.String()+" remove", true)
+				if err != nil {
+					logger.Log(0, output, "error removing peer", currentPeer.PublicKey.String())
+				}
 			}
 			}
 		}
 		}
 	}
 	}
@@ -277,10 +282,10 @@ func setServerPeers(iface string, keepalive int32, peers []wgtypes.PeerConfig) e
 	return nil
 	return nil
 }
 }
 
 
-func setWGConfig(node models.Node, network string, peerupdate bool) error {
+func setWGConfig(node *models.Node, peerupdate bool) error {
 
 
 	node.SetID()
 	node.SetID()
-	peers, hasGateway, gateways, err := GetServerPeers(node.MacAddress, node.Network, node.IsDualStack == "yes", node.IsIngressGateway == "yes")
+	peers, hasGateway, gateways, err := GetServerPeers(node)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
@@ -289,17 +294,17 @@ func setWGConfig(node models.Node, network string, peerupdate bool) error {
 		return err
 		return err
 	}
 	}
 	if peerupdate {
 	if peerupdate {
-		var iface string = node.Interface
-		err = setServerPeers(iface, node.PersistentKeepalive, peers)
-		Log("updated peers on server "+node.Name, 2)
+		err = setServerPeers(node.Interface, node.PersistentKeepalive, peers[:])
+		logger.Log(2, "updated peers on server", node.Name)
 	} else {
 	} else {
-		err = initWireguard(&node, privkey, peers, hasGateway, gateways)
-		Log("finished setting wg config on server "+node.Name, 3)
+		err = initWireguard(node, privkey, peers[:], hasGateway, gateways[:])
+		logger.Log(3, "finished setting wg config on server", node.Name)
 	}
 	}
+	peers = nil
 	return err
 	return err
 }
 }
 
 
-func setWGKeyConfig(node models.Node) error {
+func setWGKeyConfig(node *models.Node) error {
 
 
 	node.SetID()
 	node.SetID()
 	privatekey, err := wgtypes.GeneratePrivateKey()
 	privatekey, err := wgtypes.GeneratePrivateKey()
@@ -308,7 +313,6 @@ func setWGKeyConfig(node models.Node) error {
 	}
 	}
 	privkeystring := privatekey.String()
 	privkeystring := privatekey.String()
 	publickey := privatekey.PublicKey()
 	publickey := privatekey.PublicKey()
-
 	node.PublicKey = publickey.String()
 	node.PublicKey = publickey.String()
 
 
 	err = StorePrivKey(node.ID, privkeystring)
 	err = StorePrivKey(node.ID, privkeystring)
@@ -319,19 +323,19 @@ func setWGKeyConfig(node models.Node) error {
 		node.Action = models.NODE_NOOP
 		node.Action = models.NODE_NOOP
 	}
 	}
 
 
-	return setWGConfig(node, node.Network, false)
+	return setWGConfig(node, false)
 }
 }
 
 
 func removeLocalServer(node *models.Node) error {
 func removeLocalServer(node *models.Node) error {
 	var ifacename = node.Interface
 	var ifacename = node.Interface
 	var err error
 	var err error
 	if err = RemovePrivKey(node.ID); err != nil {
 	if err = RemovePrivKey(node.ID); err != nil {
-		Log("failed to remove server conf from db "+node.ID, 1)
+		logger.Log(1, "failed to remove server conf from db", node.ID)
 	}
 	}
 	if ifacename != "" {
 	if ifacename != "" {
 		if !ncutils.IsKernel() {
 		if !ncutils.IsKernel() {
 			if err = RemoveConf(ifacename, true); err == nil {
 			if err = RemoveConf(ifacename, true); err == nil {
-				Log("removed WireGuard interface: "+ifacename, 1)
+				logger.Log(1, "removed WireGuard interface:", ifacename)
 			}
 			}
 		} else {
 		} else {
 			ipExec, err := exec.LookPath("ip")
 			ipExec, err := exec.LookPath("ip")
@@ -341,8 +345,8 @@ func removeLocalServer(node *models.Node) error {
 			out, err := ncutils.RunCmd(ipExec+" link del "+ifacename, false)
 			out, err := ncutils.RunCmd(ipExec+" link del "+ifacename, false)
 			dontprint := strings.Contains(out, "does not exist") || strings.Contains(out, "Cannot find device")
 			dontprint := strings.Contains(out, "does not exist") || strings.Contains(out, "Cannot find device")
 			if err != nil && !dontprint {
 			if err != nil && !dontprint {
-				Log("error running command: "+ipExec+" link del "+ifacename, 1)
-				Log(out, 1)
+				logger.Log(1, "error running command:", ipExec, "link del", ifacename)
+				logger.Log(1, out)
 			}
 			}
 			if node.PostDown != "" {
 			if node.PostDown != "" {
 				runcmds := strings.Split(node.PostDown, "; ")
 				runcmds := strings.Split(node.PostDown, "; ")

+ 35 - 53
main.go

@@ -1,11 +1,7 @@
-//TODO: Harden. Add failover for every method and agent calls
-//TODO: Figure out why mongodb keeps failing (log rotation?)
-
 package main
 package main
 
 
 import (
 import (
 	"fmt"
 	"fmt"
-	"log"
 	"net"
 	"net"
 	"os"
 	"os"
 	"os/signal"
 	"os/signal"
@@ -19,6 +15,7 @@ import (
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/functions"
 	"github.com/gravitl/netmaker/functions"
 	nodepb "github.com/gravitl/netmaker/grpc"
 	nodepb "github.com/gravitl/netmaker/grpc"
+	"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/netclient/ncutils"
 	"github.com/gravitl/netmaker/netclient/ncutils"
@@ -40,41 +37,38 @@ func initialize() { // Client Mode Prereq Check
 	var err error
 	var err error
 
 
 	if err = database.InitializeDatabase(); err != nil {
 	if err = database.InitializeDatabase(); err != nil {
-		logic.Log("Error connecting to database", 0)
-		log.Fatal(err)
+		logger.FatalLog("Error connecting to database")
 	}
 	}
-	logic.Log("database successfully connected", 0)
+	logger.Log(0, "database successfully connected")
 
 
 	var authProvider = auth.InitializeAuthProvider()
 	var authProvider = auth.InitializeAuthProvider()
 	if authProvider != "" {
 	if authProvider != "" {
-		logic.Log("OAuth provider, "+authProvider+", initialized", 0)
+		logger.Log(0, "OAuth provider, ", authProvider, ", initialized")
 	} else {
 	} else {
-		logic.Log("no OAuth provider found or not configured, continuing without OAuth", 0)
+		logger.Log(0, "no OAuth provider found or not configured, continuing without OAuth")
 	}
 	}
 
 
 	if servercfg.IsClientMode() != "off" {
 	if servercfg.IsClientMode() != "off" {
 		output, err := ncutils.RunCmd("id -u", true)
 		output, err := ncutils.RunCmd("id -u", true)
 		if err != nil {
 		if err != nil {
-			logic.Log("Error running 'id -u' for prereq check. Please investigate or disable client mode.", 0)
-			log.Fatal(output, err)
+			logger.FatalLog("Error running 'id -u' for prereq check. Please investigate or disable client mode.", output, err.Error())
 		}
 		}
 		uid, err := strconv.Atoi(string(output[:len(output)-1]))
 		uid, err := strconv.Atoi(string(output[:len(output)-1]))
 		if err != nil {
 		if err != nil {
-			logic.Log("Error retrieving uid from 'id -u' for prereq check. Please investigate or disable client mode.", 0)
-			log.Fatal(err)
+			logger.FatalLog("Error retrieving uid from 'id -u' for prereq check. Please investigate or disable client mode.", err.Error())
 		}
 		}
 		if uid != 0 {
 		if uid != 0 {
-			log.Fatal("To run in client mode requires root privileges. Either disable client mode or run with sudo.")
+			logger.FatalLog("To run in client mode requires root privileges. Either disable client mode or run with sudo.")
 		}
 		}
 		if err := serverctl.InitServerNetclient(); err != nil {
 		if err := serverctl.InitServerNetclient(); err != nil {
-			log.Fatal("Did not find netclient to use CLIENT_MODE")
+			logger.FatalLog("Did not find netclient to use CLIENT_MODE")
 		}
 		}
 	}
 	}
 
 
 	if servercfg.IsDNSMode() {
 	if servercfg.IsDNSMode() {
 		err := functions.SetDNSDir()
 		err := functions.SetDNSDir()
 		if err != nil {
 		if err != nil {
-			log.Fatal(err)
+			logger.FatalLog(err.Error())
 		}
 		}
 	}
 	}
 }
 }
@@ -86,23 +80,17 @@ func startControllers() {
 		if !(servercfg.DisableRemoteIPCheck()) && servercfg.GetGRPCHost() == "127.0.0.1" {
 		if !(servercfg.DisableRemoteIPCheck()) && servercfg.GetGRPCHost() == "127.0.0.1" {
 			err := servercfg.SetHost()
 			err := servercfg.SetHost()
 			if err != nil {
 			if err != nil {
-				logic.Log("Unable to Set host. Exiting...", 0)
-				log.Fatal(err)
+				logger.FatalLog("Unable to Set host. Exiting...", err.Error())
 			}
 			}
 		}
 		}
 		waitnetwork.Add(1)
 		waitnetwork.Add(1)
 		go runGRPC(&waitnetwork)
 		go runGRPC(&waitnetwork)
 	}
 	}
 
 
-	if servercfg.IsClientMode() == "on" {
-		waitnetwork.Add(1)
-		go runClient(&waitnetwork)
-	}
-
 	if servercfg.IsDNSMode() {
 	if servercfg.IsDNSMode() {
 		err := logic.SetDNS()
 		err := logic.SetDNS()
 		if err != nil {
 		if err != nil {
-			logic.Log("error occurred initializing DNS: "+err.Error(), 0)
+			logger.Log(0, "error occurred initializing DNS: ", err.Error())
 		}
 		}
 	}
 	}
 	//Run Rest Server
 	//Run Rest Server
@@ -110,48 +98,46 @@ func startControllers() {
 		if !servercfg.DisableRemoteIPCheck() && servercfg.GetAPIHost() == "127.0.0.1" {
 		if !servercfg.DisableRemoteIPCheck() && servercfg.GetAPIHost() == "127.0.0.1" {
 			err := servercfg.SetHost()
 			err := servercfg.SetHost()
 			if err != nil {
 			if err != nil {
-				logic.Log("Unable to Set host. Exiting...", 0)
-				log.Fatal(err)
+				logger.FatalLog("Unable to Set host. Exiting...", err.Error())
 			}
 			}
 		}
 		}
 		waitnetwork.Add(1)
 		waitnetwork.Add(1)
-		controller.HandleRESTRequests(&waitnetwork)
+		go controller.HandleRESTRequests(&waitnetwork)
 	}
 	}
+
 	if !servercfg.IsAgentBackend() && !servercfg.IsRestBackend() {
 	if !servercfg.IsAgentBackend() && !servercfg.IsRestBackend() {
-		logic.Log("No Server Mode selected, so nothing is being served! Set either Agent mode (AGENT_BACKEND) or Rest mode (REST_BACKEND) to 'true'.", 0)
+		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 serverGroup sync.WaitGroup
+			serverGroup.Add(1)
+			go runClient(&serverGroup)
+			serverGroup.Wait()
+			time.Sleep(checkintime)
+		}
 	}
 	}
 
 
 	waitnetwork.Wait()
 	waitnetwork.Wait()
-	logic.Log("exiting", 0)
 }
 }
 
 
 func runClient(wg *sync.WaitGroup) {
 func runClient(wg *sync.WaitGroup) {
 	defer wg.Done()
 	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) {
 func runGRPC(wg *sync.WaitGroup) {
 
 
 	defer wg.Done()
 	defer wg.Done()
 
 
-	// Configure 'log' package to give file name and line number on eg. log.Fatal
-	// Pipe flags to one another (log.LstdFLags = log.Ldate | log.Ltime)
-	log.SetFlags(log.LstdFlags | log.Lshortfile)
-
 	grpcport := servercfg.GetGRPCPort()
 	grpcport := servercfg.GetGRPCPort()
 
 
 	listener, err := net.Listen("tcp", ":"+grpcport)
 	listener, err := net.Listen("tcp", ":"+grpcport)
 	// Handle errors if any
 	// Handle errors if any
 	if err != nil {
 	if err != nil {
-		log.Fatalf("[netmaker] Unable to listen on port "+grpcport+", error: %v", err)
+		logger.FatalLog("[netmaker] Unable to listen on port", grpcport, ": error:", err.Error())
 	}
 	}
 
 
 	s := grpc.NewServer(
 	s := grpc.NewServer(
@@ -166,14 +152,14 @@ func runGRPC(wg *sync.WaitGroup) {
 	// Start the server in a child routine
 	// Start the server in a child routine
 	go func() {
 	go func() {
 		if err := s.Serve(listener); err != nil {
 		if err := s.Serve(listener); err != nil {
-			log.Fatalf("Failed to serve: %v", err)
+			logger.FatalLog("Failed to serve:", err.Error())
 		}
 		}
 	}()
 	}()
-	logic.Log("Agent Server successfully started on port "+grpcport+" (gRPC)", 0)
+	logger.Log(0, "Agent Server successfully started on port ", grpcport, "(gRPC)")
 
 
 	// Right way to stop the server using a SHUTDOWN HOOK
 	// Right way to stop the server using a SHUTDOWN HOOK
 	// Create a channel to receive OS signals
 	// Create a channel to receive OS signals
-	c := make(chan os.Signal)
+	c := make(chan os.Signal, 1)
 
 
 	// Relay os.Interrupt to our channel (os.Interrupt = CTRL+C)
 	// Relay os.Interrupt to our channel (os.Interrupt = CTRL+C)
 	// Ignore other incoming signals
 	// Ignore other incoming signals
@@ -184,11 +170,11 @@ func runGRPC(wg *sync.WaitGroup) {
 	<-c
 	<-c
 
 
 	// After receiving CTRL+C Properly stop the server
 	// After receiving CTRL+C Properly stop the server
-	logic.Log("Stopping the Agent server...", 0)
+	logger.Log(0, "Stopping the Agent server...")
 	s.Stop()
 	s.Stop()
 	listener.Close()
 	listener.Close()
-	logic.Log("Agent server closed..", 0)
-	logic.Log("Closed DB connection.", 0)
+	logger.Log(0, "Agent server closed..")
+	logger.Log(0, "Closed DB connection.")
 }
 }
 
 
 func authServerUnaryInterceptor() grpc.ServerOption {
 func authServerUnaryInterceptor() grpc.ServerOption {
@@ -201,7 +187,3 @@ func setGarbageCollection() {
 		debug.SetGCPercent(ncutils.DEFAULT_GC_PERCENT)
 		debug.SetGCPercent(ncutils.DEFAULT_GC_PERCENT)
 	}
 	}
 }
 }
-
-// func authServerStreamInterceptor() grpc.ServerOption {
-// 	return grpc.StreamInterceptor(controller.AuthServerStreamInterceptor)
-// }

+ 0 - 1
models/node.go

@@ -11,7 +11,6 @@ import (
 	"golang.org/x/crypto/bcrypt"
 	"golang.org/x/crypto/bcrypt"
 )
 )
 
 
-const charset = "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
 const TEN_YEARS_IN_SECONDS = 300000000
 const TEN_YEARS_IN_SECONDS = 300000000
 const MAX_NAME_LENGTH = 62
 const MAX_NAME_LENGTH = 62
 
 

+ 1 - 1
models/structs.go

@@ -85,7 +85,7 @@ type AccessKey struct {
 	Name         string `json:"name" bson:"name" validate:"omitempty,max=20"`
 	Name         string `json:"name" bson:"name" validate:"omitempty,max=20"`
 	Value        string `json:"value" bson:"value" validate:"omitempty,alphanum,max=16"`
 	Value        string `json:"value" bson:"value" validate:"omitempty,alphanum,max=16"`
 	AccessString string `json:"accessstring" bson:"accessstring"`
 	AccessString string `json:"accessstring" bson:"accessstring"`
-	Uses         int    `json:"uses" bson:"uses"`
+	Uses         int    `json:"uses" bson:"uses" validate:"numeric,min=0"`
 }
 }
 
 
 // DisplayKey - what is displayed for key
 // DisplayKey - what is displayed for key

+ 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.",
+		},
+	}
+}

+ 5 - 0
netclient/command/commands.go

@@ -58,6 +58,11 @@ func Join(cfg config.ClientConfig, privateKey string) error {
 	if cfg.Daemon != "off" {
 	if cfg.Daemon != "off" {
 		err = daemon.InstallDaemon(cfg)
 		err = daemon.InstallDaemon(cfg)
 	}
 	}
+	if ncutils.IsWindows() {
+		ncutils.PrintLog("setting up WireGuard app", 0)
+		time.Sleep(time.Second >> 1)
+		functions.Pull(cfg.Network, true)
+	}
 	return err
 	return err
 }
 }
 
 

+ 1 - 86
netclient/config/config.go

@@ -72,90 +72,6 @@ func Write(config *ClientConfig, network string) error {
 	return err
 	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
 // ClientConfig.ReadConfig - used to read config from client disk into memory
 func (config *ClientConfig) ReadConfig() {
 func (config *ClientConfig) ReadConfig() {
 
 
@@ -192,7 +108,6 @@ func (config *ClientConfig) ReadConfig() {
 // ModConfig - overwrites the node inside client config on disk
 // ModConfig - overwrites the node inside client config on disk
 func ModConfig(node *models.Node) error {
 func ModConfig(node *models.Node) error {
 	network := node.Network
 	network := node.Network
-	networksettings := node.NetworkSettings
 	if network == "" {
 	if network == "" {
 		return errors.New("no network provided")
 		return errors.New("no network provided")
 	}
 	}
@@ -207,7 +122,7 @@ func ModConfig(node *models.Node) error {
 	}
 	}
 
 
 	modconfig.Node = (*node)
 	modconfig.Node = (*node)
-	modconfig.NetworkSettings = (networksettings)
+	modconfig.NetworkSettings = node.NetworkSettings
 	err = Write(&modconfig, network)
 	err = Write(&modconfig, network)
 	return err
 	return err
 }
 }

+ 51 - 58
netclient/daemon/windows.go

@@ -2,10 +2,8 @@ package daemon
 
 
 import (
 import (
 	"fmt"
 	"fmt"
-	"io"
 	"io/ioutil"
 	"io/ioutil"
 	"log"
 	"log"
-	"net/http"
 	"os"
 	"os"
 	"strings"
 	"strings"
 
 
@@ -23,13 +21,7 @@ func SetupWindowsDaemon() error {
 
 
 	if !ncutils.FileExists(ncutils.GetNetclientPathSpecific() + "winsw.exe") {
 	if !ncutils.FileExists(ncutils.GetNetclientPathSpecific() + "winsw.exe") {
 		ncutils.Log("performing first time daemon setup")
 		ncutils.Log("performing first time daemon setup")
-		if !ncutils.FileExists(".\\winsw.exe") {
-			err := downloadWinsw()
-			if err != nil {
-				return err
-			}
-		}
-		err := copyWinswOver()
+		err := ncutils.GetEmbedded()
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
@@ -90,56 +82,57 @@ func RemoveWindowsDaemon() {
 	ncutils.Log("uninstalled Windows, Netclient daemon")
 	ncutils.Log("uninstalled Windows, Netclient daemon")
 }
 }
 
 
-func copyWinswOver() error {
+// func copyWinswOver() error {
 
 
-	input, err := ioutil.ReadFile(".\\winsw.exe")
-	if err != nil {
-		ncutils.Log("failed to find winsw.exe")
-		return err
-	}
-	if err = ioutil.WriteFile(ncutils.GetNetclientPathSpecific()+"winsw.exe", input, 0644); err != nil {
-		ncutils.Log("failed to copy winsw.exe to " + ncutils.GetNetclientPath())
-		return err
-	}
-	if err = os.Remove(".\\winsw.exe"); err != nil {
-		ncutils.Log("failed to cleanup local winsw.exe, feel free to delete it")
-		return err
-	}
-	ncutils.Log("finished copying winsw.exe")
-	return nil
-}
+// 	input, err := ioutil.ReadFile(".\\winsw.exe")
+// 	if err != nil {
+// 		ncutils.Log("failed to find winsw.exe")
+// 		return err
+// 	}
+// 	if err = ioutil.WriteFile(ncutils.GetNetclientPathSpecific()+"winsw.exe", input, 0644); err != nil {
+// 		ncutils.Log("failed to copy winsw.exe to " + ncutils.GetNetclientPath())
+// 		return err
+// 	}
+// 	if err = os.Remove(".\\winsw.exe"); err != nil {
+// 		ncutils.Log("failed to cleanup local winsw.exe, feel free to delete it")
+// 		return err
+// 	}
+// 	ncutils.Log("finished copying winsw.exe")
+// 	return nil
+// }
 
 
-func downloadWinsw() error {
-	fullURLFile := "https://github.com/winsw/winsw/releases/download/v2.11.0/WinSW-x64.exe"
-	fileName := "winsw.exe"
+// func downloadWinsw() error {
+// 	fullURLFile := "https://github.com/winsw/winsw/releases/download/v2.11.0/WinSW-x64.exe"
+// 	fileName := "winsw.exe"
 
 
-	// Create the file
-	file, err := os.Create(fileName)
-	if err != nil {
-		ncutils.Log("could not create file on OS for Winsw")
-		return err
-	}
-	client := http.Client{
-		CheckRedirect: func(r *http.Request, via []*http.Request) error {
-			r.URL.Opaque = r.URL.Path
-			return nil
-		},
-	}
-	// Put content on file
-	ncutils.Log("downloading service tool...")
-	resp, err := client.Get(fullURLFile)
-	if err != nil {
-		ncutils.Log("could not GET Winsw")
-		return err
-	}
-	defer resp.Body.Close()
+// 	// Create the file
+// 	file, err := os.Create(fileName)
+// 	if err != nil {
+// 		ncutils.Log("could not create file on OS for Winsw")
+// 		return err
+// 	}
+// 	defer file.Close()
 
 
-	_, err = io.Copy(file, resp.Body)
-	if err != nil {
-		ncutils.Log("could not mount winsw.exe")
-		return err
-	}
-	defer file.Close()
-	ncutils.Log("finished downloading Winsw")
-	return nil
-}
+// 	client := http.Client{
+// 		CheckRedirect: func(r *http.Request, via []*http.Request) error {
+// 			r.URL.Opaque = r.URL.Path
+// 			return nil
+// 		},
+// 	}
+// 	// Put content on file
+// 	ncutils.Log("downloading service tool...")
+// 	resp, err := client.Get(fullURLFile)
+// 	if err != nil {
+// 		ncutils.Log("could not GET Winsw")
+// 		return err
+// 	}
+// 	defer resp.Body.Close()
+
+// 	_, err = io.Copy(file, resp.Body)
+// 	if err != nil {
+// 		ncutils.Log("could not mount winsw.exe")
+// 		return err
+// 	}
+// 	ncutils.Log("finished downloading Winsw")
+// 	return nil
+// }

+ 3 - 0
netclient/functions/common.go

@@ -33,6 +33,7 @@ func ListPorts() error {
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
+	defer wgclient.Close()
 	devices, err := wgclient.Devices()
 	devices, err := wgclient.Devices()
 	if err != nil {
 	if err != nil {
 		return err
 		return err
@@ -215,6 +216,8 @@ func LeaveNetwork(network string) error {
 		_, _ = ncutils.RunCmd("route delete "+ip+" mask "+mask+" "+node.Address, true)
 		_, _ = ncutils.RunCmd("route delete "+ip+" mask "+mask+" "+node.Address, true)
 	} else if ncutils.IsFreeBSD() {
 	} else if ncutils.IsFreeBSD() {
 		_, _ = ncutils.RunCmd("route del -net "+node.NetworkSettings.AddressRange+" -interface "+node.Interface, true)
 		_, _ = ncutils.RunCmd("route del -net "+node.NetworkSettings.AddressRange+" -interface "+node.Interface, true)
+	} else if ncutils.IsLinux() {
+		_, _ = ncutils.RunCmd("ip -4 route del "+node.NetworkSettings.AddressRange+" dev "+node.Interface, false)
 	}
 	}
 	return RemoveLocalInstance(cfg, network)
 	return RemoveLocalInstance(cfg, network)
 }
 }

+ 6 - 352
netclient/main.go

@@ -3,18 +3,12 @@
 package main
 package main
 
 
 import (
 import (
-	"errors"
 	"log"
 	"log"
 	"os"
 	"os"
-	"os/exec"
-	"os/signal"
 	"runtime/debug"
 	"runtime/debug"
-	"strconv"
-	"syscall"
 
 
+	"github.com/gravitl/netmaker/netclient/cli_options"
 	"github.com/gravitl/netmaker/netclient/command"
 	"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/ncutils"
 	"github.com/gravitl/netmaker/netclient/ncwindows"
 	"github.com/gravitl/netmaker/netclient/ncwindows"
 	"github.com/urfave/cli/v2"
 	"github.com/urfave/cli/v2"
@@ -24,360 +18,20 @@ func main() {
 	app := cli.NewApp()
 	app := cli.NewApp()
 	app.Name = "Netclient CLI"
 	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.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()
 	setGarbageCollection()
 
 
 	if ncutils.IsWindows() {
 	if ncutils.IsWindows() {
 		ncwindows.InitWindows()
 		ncwindows.InitWindows()
 	} else {
 	} 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() {
 	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()
 		command.RunUserspaceDaemon()
 	} else {
 	} else {
 		err := app.Run(os.Args)
 		err := app.Run(os.Args)

+ 51 - 3
netclient/ncutils/netclientutils.go

@@ -24,6 +24,9 @@ import (
 	"google.golang.org/grpc/credentials"
 	"google.golang.org/grpc/credentials"
 )
 )
 
 
+// MAX_NAME_LENGTH - maximum node name length
+const MAX_NAME_LENGTH = 62
+
 // NO_DB_RECORD - error message result
 // NO_DB_RECORD - error message result
 const NO_DB_RECORD = "no result found"
 const NO_DB_RECORD = "no result found"
 
 
@@ -37,7 +40,7 @@ const LINUX_APP_DATA_PATH = "/etc/netclient"
 const WINDOWS_APP_DATA_PATH = "C:\\ProgramData\\Netclient"
 const WINDOWS_APP_DATA_PATH = "C:\\ProgramData\\Netclient"
 
 
 // WINDOWS_APP_DATA_PATH - windows path
 // WINDOWS_APP_DATA_PATH - windows path
-const WINDOWS_WG_DATA_PATH = "C:\\Program Files\\WireGuard\\Data\\Configurations"
+const WINDOWS_WG_DPAPI_PATH = "C:\\Program Files\\WireGuard\\Data\\Configurations"
 
 
 // WINDOWS_SVC_NAME - service name
 // WINDOWS_SVC_NAME - service name
 const WINDOWS_SVC_NAME = "netclient"
 const WINDOWS_SVC_NAME = "netclient"
@@ -107,7 +110,7 @@ func GenPass() string {
 		rand.NewSource(time.Now().UnixNano()))
 		rand.NewSource(time.Now().UnixNano()))
 
 
 	length := 16
 	length := 16
-	charset := "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
+	charset := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
 
 
 	b := make([]byte, length)
 	b := make([]byte, length)
 	for i := range b {
 	for i := range b {
@@ -258,6 +261,7 @@ func GetFreePort(rangestart int32) (int32, error) {
 	if err != nil {
 	if err != nil {
 		return 0, err
 		return 0, err
 	}
 	}
+	defer wgclient.Close()
 	devices, err := wgclient.Devices()
 	devices, err := wgclient.Devices()
 	if err != nil {
 	if err != nil {
 		return 0, err
 		return 0, err
@@ -318,7 +322,7 @@ func GetNetclientPathSpecific() string {
 // GetNetclientPathSpecific - gets specific netclient config path
 // GetNetclientPathSpecific - gets specific netclient config path
 func GetWGPathSpecific() string {
 func GetWGPathSpecific() string {
 	if IsWindows() {
 	if IsWindows() {
-		return WINDOWS_WG_DATA_PATH + "\\"
+		return WINDOWS_APP_DATA_PATH + "\\"
 	} else {
 	} else {
 		return "/etc/wireguard/"
 		return "/etc/wireguard/"
 	}
 	}
@@ -447,3 +451,47 @@ func DNSFormatString(input string) string {
 	}
 	}
 	return reg.ReplaceAllString(input, "")
 	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)
+	}
+}

+ 6 - 0
netclient/ncutils/netclientutils_darwin.go

@@ -23,10 +23,16 @@ func RunCmd(command string, printerr bool) (string, error) {
 	return string(out), err
 	return string(out), err
 }
 }
 
 
+// RunCmdFormatted - run a command formatted for MacOS
 func RunCmdFormatted(command string, printerr bool) (string, error) {
 func RunCmdFormatted(command string, printerr bool) (string, error) {
 	return "", nil
 	return "", nil
 }
 }
 
 
+// GetEmbedded - if files required for MacOS, put here
+func GetEmbedded() error {
+	return nil
+}
+
 // CreateUserSpaceConf - creates a user space WireGuard conf
 // CreateUserSpaceConf - creates a user space WireGuard conf
 func CreateUserSpaceConf(address string, privatekey string, listenPort string, mtu int32, perskeepalive int32, peers []wgtypes.PeerConfig) (string, error) {
 func CreateUserSpaceConf(address string, privatekey string, listenPort string, mtu int32, perskeepalive int32, peers []wgtypes.PeerConfig) (string, error) {
 	peersString, err := parsePeers(perskeepalive, peers)
 	peersString, err := parsePeers(perskeepalive, peers)

+ 6 - 0
netclient/ncutils/netclientutils_freebsd.go

@@ -12,10 +12,16 @@ import (
 	"time"
 	"time"
 )
 )
 
 
+// RunCmdFormatted - run a command formatted for freebsd
 func RunCmdFormatted(command string, printerr bool) (string, error) {
 func RunCmdFormatted(command string, printerr bool) (string, error) {
 	return "", nil
 	return "", nil
 }
 }
 
 
+// GetEmbedded - if files required for freebsd, put here
+func GetEmbedded() error {
+	return nil
+}
+
 // Runs Commands for FreeBSD
 // Runs Commands for FreeBSD
 func RunCmd(command string, printerr bool) (string, error) {
 func RunCmd(command string, printerr bool) (string, error) {
 	args := strings.Fields(command)
 	args := strings.Fields(command)

+ 6 - 0
netclient/ncutils/netclientutils_linux.go

@@ -23,10 +23,16 @@ func RunCmd(command string, printerr bool) (string, error) {
 	return string(out), err
 	return string(out), err
 }
 }
 
 
+// RunCmdFormatted - does nothing for linux
 func RunCmdFormatted(command string, printerr bool) (string, error) {
 func RunCmdFormatted(command string, printerr bool) (string, error) {
 	return "", nil
 	return "", nil
 }
 }
 
 
+// GetEmbedded - if files required for linux, put here
+func GetEmbedded() error {
+	return nil
+}
+
 // CreateUserSpaceConf - creates a user space WireGuard conf
 // CreateUserSpaceConf - creates a user space WireGuard conf
 func CreateUserSpaceConf(address string, privatekey string, listenPort string, mtu int32, perskeepalive int32, peers []wgtypes.PeerConfig) (string, error) {
 func CreateUserSpaceConf(address string, privatekey string, listenPort string, mtu int32, perskeepalive int32, peers []wgtypes.PeerConfig) (string, error) {
 	peersString, err := parsePeers(perskeepalive, peers)
 	peersString, err := parsePeers(perskeepalive, peers)

+ 19 - 0
netclient/ncutils/netclientutils_windows.go

@@ -1,6 +1,7 @@
 package ncutils
 package ncutils
 
 
 import (
 import (
+	"embed"
 	"fmt"
 	"fmt"
 	"log"
 	"log"
 	"os"
 	"os"
@@ -12,6 +13,9 @@ import (
 	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 )
 )
 
 
+//go:embed windowsdaemon/winsw.exe
+var winswContent embed.FS
+
 // RunCmd - runs a local command
 // RunCmd - runs a local command
 func RunCmd(command string, printerr bool) (string, error) {
 func RunCmd(command string, printerr bool) (string, error) {
 	args := strings.Fields(command)
 	args := strings.Fields(command)
@@ -72,3 +76,18 @@ MTU = %s
 		peersString)
 		peersString)
 	return config, nil
 	return config, nil
 }
 }
+
+// GetEmbedded - Gets the Windows daemon creator
+func GetEmbedded() error {
+	data, err := winswContent.ReadFile("windowsdaemon/winsw.exe")
+	if err != nil {
+		return err
+	}
+	fileName := fmt.Sprintf("%swinsw.exe", GetNetclientPathSpecific())
+	err = os.WriteFile(fileName, data, 0700)
+	if err != nil {
+		Log("could not mount winsw.exe")
+		return err
+	}
+	return nil
+}

+ 18 - 19
netclient/ncutils/peerhelper.go

@@ -1,17 +1,17 @@
 package ncutils
 package ncutils
 
 
 import (
 import (
+	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
+	"net"
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
-	"net"
 	"time"
 	"time"
-	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 )
 )
 
 
 func GetPeers(iface string) ([]wgtypes.Peer, error) {
 func GetPeers(iface string) ([]wgtypes.Peer, error) {
 
 
 	var peers []wgtypes.Peer
 	var peers []wgtypes.Peer
-	output, err := RunCmd("wg show "+iface+" dump",true)
+	output, err := RunCmd("wg show "+iface+" dump", true)
 	if err != nil {
 	if err != nil {
 		return peers, err
 		return peers, err
 	}
 	}
@@ -22,7 +22,7 @@ func GetPeers(iface string) ([]wgtypes.Peer, error) {
 		var allowedIPs []net.IPNet
 		var allowedIPs []net.IPNet
 		fields := strings.Fields(line)
 		fields := strings.Fields(line)
 		if len(fields) < 4 {
 		if len(fields) < 4 {
-			Log("error parsing peer: "+line)
+			Log("error parsing peer: " + line)
 			continue
 			continue
 		}
 		}
 		pubkeystring := fields[0]
 		pubkeystring := fields[0]
@@ -36,13 +36,13 @@ func GetPeers(iface string) ([]wgtypes.Peer, error) {
 
 
 		pubkey, err := wgtypes.ParseKey(pubkeystring)
 		pubkey, err := wgtypes.ParseKey(pubkeystring)
 		if err != nil {
 		if err != nil {
-			Log("error parsing peer key "+pubkeystring)
+			Log("error parsing peer key " + pubkeystring)
 			continue
 			continue
 		}
 		}
 		ipstrings := strings.Split(allowedipstring, ",")
 		ipstrings := strings.Split(allowedipstring, ",")
 		for _, ipstring := range ipstrings {
 		for _, ipstring := range ipstrings {
 			var netip net.IP
 			var netip net.IP
-			if netip = net.ParseIP(strings.Split(ipstring,"/")[0]); netip != nil {
+			if netip = net.ParseIP(strings.Split(ipstring, "/")[0]); netip != nil {
 				allowedIPs = append(
 				allowedIPs = append(
 					allowedIPs,
 					allowedIPs,
 					net.IPNet{
 					net.IPNet{
@@ -53,40 +53,39 @@ func GetPeers(iface string) ([]wgtypes.Peer, error) {
 			}
 			}
 		}
 		}
 		if len(allowedIPs) == 0 {
 		if len(allowedIPs) == 0 {
-			Log("error parsing peer "+pubkeystring+", no allowedips found")
+			Log("error parsing peer " + pubkeystring + ", no allowedips found")
 			continue
 			continue
 		}
 		}
 		var endpointarr []string
 		var endpointarr []string
 		var endpointip net.IP
 		var endpointip net.IP
-		if endpointarr = strings.Split(endpointstring,":"); len(endpointarr) != 2 {
-			Log("error parsing peer "+pubkeystring+", could not parse endpoint: "+endpointstring)
+		if endpointarr = strings.Split(endpointstring, ":"); len(endpointarr) != 2 {
+			Log("error parsing peer " + pubkeystring + ", could not parse endpoint: " + endpointstring)
 			continue
 			continue
 		}
 		}
 		if endpointip = net.ParseIP(endpointarr[0]); endpointip == nil {
 		if endpointip = net.ParseIP(endpointarr[0]); endpointip == nil {
-			Log("error parsing peer "+pubkeystring+", could not parse endpoint: "+endpointarr[0])
+			Log("error parsing peer " + pubkeystring + ", could not parse endpoint: " + endpointarr[0])
 			continue
 			continue
 		}
 		}
 		var port int
 		var port int
 		if port, err = strconv.Atoi(endpointarr[1]); err != nil {
 		if port, err = strconv.Atoi(endpointarr[1]); err != nil {
-			Log("error parsing peer "+pubkeystring+", could not parse port: "+err.Error())
+			Log("error parsing peer " + pubkeystring + ", could not parse port: " + err.Error())
 			continue
 			continue
 		}
 		}
-		var endpoint = net.UDPAddr {
-			IP: endpointip,
+		var endpoint = net.UDPAddr{
+			IP:   endpointip,
 			Port: port,
 			Port: port,
 		}
 		}
 		var dur time.Duration
 		var dur time.Duration
 		if pkeepalivestring != "" {
 		if pkeepalivestring != "" {
-			if dur, err = time.ParseDuration(pkeepalivestring+"s"); err != nil {
-				Log("error parsing peer "+pubkeystring+", could not parse keepalive: "+err.Error())
+			if dur, err = time.ParseDuration(pkeepalivestring + "s"); err != nil {
+				Log("error parsing peer " + pubkeystring + ", could not parse keepalive: " + err.Error())
 			}
 			}
 		}
 		}
 
 
-
 		peers = append(peers, wgtypes.Peer{
 		peers = append(peers, wgtypes.Peer{
-			PublicKey:         pubkey,
-			Endpoint:          &endpoint,
-			AllowedIPs:        allowedIPs,
+			PublicKey:                   pubkey,
+			Endpoint:                    &endpoint,
+			AllowedIPs:                  allowedIPs,
 			PersistentKeepaliveInterval: dur,
 			PersistentKeepaliveInterval: dur,
 		})
 		})
 	}
 	}

BIN
netclient/ncutils/windowsdaemon/winsw.exe


+ 1 - 1
netclient/netclient.exe.manifest.xml

@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
 <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
     <assemblyIdentity
     <assemblyIdentity
-            version="0.9.1.0"
+            version="0.9.2.0"
             processorArchitecture="*"
             processorArchitecture="*"
             name="netclient.exe"
             name="netclient.exe"
             type="win32"
             type="win32"

+ 1 - 1
netclient/versioninfo.json

@@ -29,7 +29,7 @@
         "OriginalFilename": "",
         "OriginalFilename": "",
         "PrivateBuild": "",
         "PrivateBuild": "",
         "ProductName": "Netclient",
         "ProductName": "Netclient",
-        "ProductVersion": "v0.9.1.0",
+        "ProductVersion": "v0.9.2.0",
         "SpecialBuild": ""
         "SpecialBuild": ""
     },
     },
     "VarFileInfo": {
     "VarFileInfo": {

+ 20 - 11
netclient/wireguard/common.go

@@ -36,6 +36,7 @@ func SetPeers(iface string, keepalive int32, peers []wgtypes.PeerConfig) error {
 			ncutils.PrintLog("failed to start wgctrl", 0)
 			ncutils.PrintLog("failed to start wgctrl", 0)
 			return err
 			return err
 		}
 		}
+		defer client.Close()
 		device, err := client.Device(iface)
 		device, err := client.Device(iface)
 		if err != nil {
 		if err != nil {
 			ncutils.PrintLog("failed to parse interface", 0)
 			ncutils.PrintLog("failed to parse interface", 0)
@@ -114,7 +115,7 @@ func InitWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
-
+	defer wgclient.Close()
 	modcfg, err := config.ReadConfig(node.Network)
 	modcfg, err := config.ReadConfig(node.Network)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
@@ -125,7 +126,6 @@ func InitWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig
 	if err != nil {
 	if err != nil {
 		log.Fatalf("failed to open client: %v", err)
 		log.Fatalf("failed to open client: %v", err)
 	}
 	}
-	defer wgclient.Close()
 
 
 	var ifacename string
 	var ifacename string
 	if nodecfg.Interface != "" {
 	if nodecfg.Interface != "" {
@@ -202,6 +202,7 @@ func InitWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig
 			}
 			}
 		}
 		}
 		if syncconf {
 		if syncconf {
+			log.Println("syncing conf")
 			err = SyncWGQuickConf(ifacename, confPath)
 			err = SyncWGQuickConf(ifacename, confPath)
 		} else {
 		} else {
 			d, _ := wgclient.Device(deviceiface)
 			d, _ := wgclient.Device(deviceiface)
@@ -210,19 +211,22 @@ func InitWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig
 				time.Sleep(time.Second >> 2)
 				time.Sleep(time.Second >> 2)
 				d, _ = wgclient.Device(deviceiface)
 				d, _ = wgclient.Device(deviceiface)
 			}
 			}
-			err = ApplyConf(confPath)
-			if err != nil {
-				ncutils.PrintLog("failed to create wireguard interface", 1)
-				return err
-			}
-			if ncutils.IsWindows() {
+			if !ncutils.IsWindows() {
+				err = ApplyConf(confPath)
+				if err != nil {
+					ncutils.PrintLog("failed to create wireguard interface", 1)
+					return err
+				}
+			} else {
 				var output string
 				var output string
 				starttime := time.Now()
 				starttime := time.Now()
+				RemoveConf(ifacename, false)
+				time.Sleep(time.Second >> 2)
 				ncutils.PrintLog("waiting for interface...", 1)
 				ncutils.PrintLog("waiting for interface...", 1)
 				for !strings.Contains(output, ifacename) && !(time.Now().After(starttime.Add(time.Duration(10) * time.Second))) {
 				for !strings.Contains(output, ifacename) && !(time.Now().After(starttime.Add(time.Duration(10) * time.Second))) {
 					output, _ = ncutils.RunCmd("wg", false)
 					output, _ = ncutils.RunCmd("wg", false)
-					time.Sleep(time.Second >> 1)
 					err = ApplyConf(confPath)
 					err = ApplyConf(confPath)
+					time.Sleep(time.Second)
 				}
 				}
 				if !strings.Contains(output, ifacename) {
 				if !strings.Contains(output, ifacename) {
 					return errors.New("could not create wg interface for " + ifacename)
 					return errors.New("could not create wg interface for " + ifacename)
@@ -232,7 +236,9 @@ func InitWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig
 					log.Println(err.Error())
 					log.Println(err.Error())
 					return err
 					return err
 				}
 				}
-				_, _ = ncutils.RunCmd("route add "+ip+" mask "+mask+" "+node.Address, true)
+				ncutils.RunCmd("route add "+ip+" mask "+mask+" "+node.Address, true)
+				time.Sleep(time.Second >> 2)
+				ncutils.RunCmd("route change "+ip+" mask "+mask+" "+node.Address, true)
 			}
 			}
 		}
 		}
 	} else {
 	} else {
@@ -296,9 +302,11 @@ func InitWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig
 		}
 		}
 	}
 	}
 
 
-	//extra network route setting required for freebsd and windows
+	//extra network route setting
 	if ncutils.IsFreeBSD() {
 	if ncutils.IsFreeBSD() {
 		_, _ = ncutils.RunCmd("route add -net "+nodecfg.NetworkSettings.AddressRange+" -interface "+ifacename, true)
 		_, _ = ncutils.RunCmd("route add -net "+nodecfg.NetworkSettings.AddressRange+" -interface "+ifacename, true)
+	} else if ncutils.IsLinux() {
+		_, _ = ncutils.RunCmd("ip -4 route add "+nodecfg.NetworkSettings.AddressRange+" dev "+ifacename, false)
 	}
 	}
 
 
 	return err
 	return err
@@ -346,6 +354,7 @@ func RemoveConf(iface string, printlog bool) error {
 	var err error
 	var err error
 	switch os {
 	switch os {
 	case "windows":
 	case "windows":
+
 		err = RemoveWindowsConf(iface, printlog)
 		err = RemoveWindowsConf(iface, printlog)
 	default:
 	default:
 		confPath := ncutils.GetNetclientPathSpecific() + iface + ".conf"
 		confPath := ncutils.GetNetclientPathSpecific() + iface + ".conf"

+ 29 - 1
netclient/wireguard/windows.go

@@ -2,11 +2,23 @@ package wireguard
 
 
 import (
 import (
 	"fmt"
 	"fmt"
+	"os"
+	"strings"
+	"time"
 
 
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 )
 )
 
 
+// ApplyWindowsConf - applies the WireGuard configuration file on Windows
 func ApplyWindowsConf(confPath string) error {
 func ApplyWindowsConf(confPath string) error {
+	pathStrings := strings.Split(confPath, ncutils.GetWGPathSpecific())
+	if len(pathStrings) == 2 {
+		copyConfPath := fmt.Sprintf("%s\\%s", ncutils.WINDOWS_WG_DPAPI_PATH, pathStrings[1])
+		err := ncutils.Copy(confPath, copyConfPath)
+		if err != nil {
+			ncutils.PrintLog(err.Error(), 1)
+		}
+	}
 	var commandLine = fmt.Sprintf(`wireguard.exe /installtunnelservice "%s"`, confPath)
 	var commandLine = fmt.Sprintf(`wireguard.exe /installtunnelservice "%s"`, confPath)
 	if _, err := ncutils.RunCmdFormatted(commandLine, false); err != nil {
 	if _, err := ncutils.RunCmdFormatted(commandLine, false); err != nil {
 		return err
 		return err
@@ -14,9 +26,25 @@ func ApplyWindowsConf(confPath string) error {
 	return nil
 	return nil
 }
 }
 
 
+// RemoveWindowsConf - removes the WireGuard configuration file on Windows and dpapi file
 func RemoveWindowsConf(ifacename string, printlog bool) error {
 func RemoveWindowsConf(ifacename string, printlog bool) error {
 	if _, err := ncutils.RunCmd("wireguard.exe /uninstalltunnelservice "+ifacename, printlog); err != nil {
 	if _, err := ncutils.RunCmd("wireguard.exe /uninstalltunnelservice "+ifacename, printlog); err != nil {
-		return err
+		ncutils.PrintLog(err.Error(), 1)
+	}
+	dpapipath := fmt.Sprintf("%s\\%s.conf.dpapi", ncutils.WINDOWS_WG_DPAPI_PATH, ifacename)
+	confpath := fmt.Sprintf("%s\\%s.conf", ncutils.WINDOWS_WG_DPAPI_PATH, ifacename)
+	if ncutils.FileExists(confpath) {
+		err := os.Remove(confpath)
+		if err != nil {
+			ncutils.PrintLog(err.Error(), 1)
+		}
+	}
+	time.Sleep(time.Second >> 2)
+	if ncutils.FileExists(dpapipath) {
+		err := os.Remove(dpapipath)
+		if err != nil {
+			ncutils.PrintLog(err.Error(), 1)
+		}
 	}
 	}
 	return nil
 	return nil
 }
 }

+ 1 - 1
scripts/netclient.sh

@@ -11,7 +11,7 @@ if [ "$TOKEN" != "" ]; then
     TOKEN_CMD="-t $TOKEN"
     TOKEN_CMD="-t $TOKEN"
 fi
 fi
 
 
-/root/netclient join $TOKEN_CMD -daemon off -dnson no
+/root/netclient join $TOKEN_CMD -daemon off -dnson no -udpholepunch no
 if [ $? -ne 0 ]; then { echo "Failed to join, quitting." ; exit 1; } fi
 if [ $? -ne 0 ]; then { echo "Failed to join, quitting." ; exit 1; } fi
 
 
 echo "[netclient] Starting netclient checkin"
 echo "[netclient] Starting netclient checkin"

+ 2 - 15
servercfg/serverconf.go

@@ -36,7 +36,6 @@ func GetServerConfig() config.ServerConfig {
 	cfg.DNSKey = "(hidden)"
 	cfg.DNSKey = "(hidden)"
 	cfg.AllowedOrigin = GetAllowedOrigin()
 	cfg.AllowedOrigin = GetAllowedOrigin()
 	cfg.RestBackend = "off"
 	cfg.RestBackend = "off"
-	cfg.Verbosity = GetVerbose()
 	cfg.NodeID = GetNodeID()
 	cfg.NodeID = GetNodeID()
 	cfg.CheckinInterval = GetCheckinInterval()
 	cfg.CheckinInterval = GetCheckinInterval()
 	cfg.ServerCheckinInterval = GetServerCheckinInterval()
 	cfg.ServerCheckinInterval = GetServerCheckinInterval()
@@ -109,7 +108,7 @@ func GetAPIConnString() string {
 
 
 // GetVersion - version of netmaker
 // GetVersion - version of netmaker
 func GetVersion() string {
 func GetVersion() string {
-	version := "0.9.1"
+	version := "0.9.2"
 	if config.Config.Server.Version != "" {
 	if config.Config.Server.Version != "" {
 		version = config.Config.Server.Version
 		version = config.Config.Server.Version
 	}
 	}
@@ -422,23 +421,11 @@ func GetPublicIP() (string, error) {
 		}
 		}
 	}
 	}
 	if err == nil && endpoint == "" {
 	if err == nil && endpoint == "" {
-		err = errors.New("Public Address Not Found.")
+		err = errors.New("public address not found")
 	}
 	}
 	return endpoint, err
 	return endpoint, err
 }
 }
 
 
-// GetVerbose - get the verbosity of server
-func GetVerbose() int32 {
-	level, err := strconv.Atoi(os.Getenv("VERBOSITY"))
-	if err != nil || level < 0 {
-		level = 0
-	}
-	if level > 3 {
-		level = 3
-	}
-	return int32(level)
-}
-
 // GetPlatform - get the system type of server
 // GetPlatform - get the system type of server
 func GetPlatform() string {
 func GetPlatform() string {
 	platform := "linux"
 	platform := "linux"

+ 13 - 46
serverctl/serverctl.go

@@ -3,13 +3,12 @@ package serverctl
 import (
 import (
 	"encoding/json"
 	"encoding/json"
 	"errors"
 	"errors"
-	"io"
-	"log"
 	"net"
 	"net"
 	"os"
 	"os"
 	"strings"
 	"strings"
 
 
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/database"
+	"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/netclient/ncutils"
 	"github.com/gravitl/netmaker/netclient/ncutils"
@@ -41,35 +40,6 @@ func FileExists(f string) bool {
 	return !info.IsDir()
 	return !info.IsDir()
 }
 }
 
 
-func copy(src, dst string) (int64, error) {
-	sourceFileStat, err := os.Stat(src)
-	if err != nil {
-		return 0, err
-	}
-
-	if !sourceFileStat.Mode().IsRegular() {
-		return 0, errors.New(src + " is not a regular file")
-	}
-
-	source, err := os.Open(src)
-	if err != nil {
-		return 0, err
-	}
-	defer source.Close()
-
-	destination, err := os.Create(dst)
-	if err != nil {
-		return 0, err
-	}
-	defer destination.Close()
-	nBytes, err := io.Copy(destination, source)
-	err = os.Chmod(dst, 0755)
-	if err != nil {
-		logic.Log(err.Error(), 1)
-	}
-	return nBytes, err
-}
-
 // RemoveNetwork - removes a network locally on server
 // RemoveNetwork - removes a network locally on server
 func RemoveNetwork(network string) (bool, error) {
 func RemoveNetwork(network string) (bool, error) {
 	err := logic.ServerLeave(servercfg.GetNodeID(), network)
 	err := logic.ServerLeave(servercfg.GetNodeID(), network)
@@ -81,9 +51,9 @@ func InitServerNetclient() error {
 	netclientDir := ncutils.GetNetclientPath()
 	netclientDir := ncutils.GetNetclientPath()
 	_, err := os.Stat(netclientDir + "/config")
 	_, err := os.Stat(netclientDir + "/config")
 	if os.IsNotExist(err) {
 	if os.IsNotExist(err) {
-		os.MkdirAll(netclientDir+"/config", 744)
+		os.MkdirAll(netclientDir+"/config", 0744)
 	} else if err != nil {
 	} else if err != nil {
-		logic.Log("[netmaker] could not find or create "+netclientDir, 1)
+		logger.Log(1, "could not find or create", netclientDir)
 		return err
 		return err
 	}
 	}
 	return nil
 	return nil
@@ -102,16 +72,17 @@ func HandleContainedClient() error {
 		for _, serverNet := range servernets {
 		for _, serverNet := range servernets {
 			err = logic.ServerCheckin(servercfg.GetNodeID(), serverNet.NetID)
 			err = logic.ServerCheckin(servercfg.GetNodeID(), serverNet.NetID)
 			if err != nil {
 			if err != nil {
-				logic.Log("error occurred during server checkin: "+err.Error(), 1)
+				logger.Log(1, "error occurred during server checkin:", err.Error())
 			} else {
 			} else {
-				logic.Log("completed peers check of network "+serverNet.NetID, 3)
+				logger.Log(3, "completed peers check of network", serverNet.NetID)
 			}
 			}
 		}
 		}
-		err := SyncNetworks(servernets)
-		if err != nil {
-			logic.Log("error syncing networks: "+err.Error(), 1)
+		syncErr := SyncNetworks(servernets[:])
+		if syncErr != nil {
+			logger.Log(1, "error syncing networks:", syncErr.Error())
+			syncErr = nil
 		}
 		}
-		// logic.Log("completed a checkin call", 3)
+		// logger.Log("completed a checkin call", 3)
 	}
 	}
 	return nil
 	return nil
 }
 }
@@ -137,10 +108,8 @@ func SyncNetworks(servernets []models.Network) error {
 				if err == nil {
 				if err == nil {
 					err = errors.New("network add failed for " + servernet.NetID)
 					err = errors.New("network add failed for " + servernet.NetID)
 				}
 				}
-				if servercfg.GetVerbose() >= 1 {
-					if !strings.Contains(err.Error(), "macaddress_unique") { // ignore macaddress unique error throws
-						log.Printf("[netmaker] error adding network %s during sync %s \n", servernet.NetID, err)
-					}
+				if !strings.Contains(err.Error(), "macaddress_unique") { // ignore macaddress unique error throws
+					logger.Log(1, "error adding network", servernet.NetID, "during sync:", err.Error())
 				}
 				}
 			}
 			}
 		}
 		}
@@ -160,9 +129,7 @@ func SyncNetworks(servernets []models.Network) error {
 					if err == nil {
 					if err == nil {
 						err = errors.New("network delete failed for " + exists)
 						err = errors.New("network delete failed for " + exists)
 					}
 					}
-					if servercfg.GetVerbose() >= 1 {
-						log.Printf("[netmaker] error removing network %s during sync %s \n", exists, err)
-					}
+					logger.Log(1, "error removing network", exists, "during sync", err.Error())
 				}
 				}
 			}
 			}
 		}
 		}