Browse Source

Merge pull request #1555 from gravitl/release_v0.15.2

Release v0.15.2
Alex Feiszli 2 years ago
parent
commit
f8997a08b6

+ 2 - 1
.github/ISSUE_TEMPLATE/bug-report.yml

@@ -31,7 +31,8 @@ body:
       label: Version
       label: Version
       description: What version are you running?
       description: What version are you running?
       options:
       options:
-        - v0.15.1      
+        - v0.15.2
+        - v0.15.1
         - v0.15.0
         - v0.15.0
         - v0.14.6
         - v0.14.6
         - v0.14.5
         - v0.14.5

+ 1 - 1
README.md

@@ -17,7 +17,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.15.1-informational?style=flat-square" />
+    <img src="https://img.shields.io/badge/Version-0.15.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?label=downloads" />
     <img src="https://img.shields.io/docker/pulls/gravitl/netmaker?label=downloads" />

+ 1 - 1
auth/auth.go

@@ -99,7 +99,7 @@ func HandleAuthCallback(w http.ResponseWriter, r *http.Request) {
 
 
 // swagger:route GET /api/oauth/login nodes HandleAuthLogin
 // swagger:route GET /api/oauth/login nodes HandleAuthLogin
 //
 //
-// Handles OAuth login
+// Handles OAuth login.
 //
 //
 //		Schemes: https
 //		Schemes: https
 //
 //

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

@@ -3,7 +3,7 @@ version: "3.4"
 services:
 services:
   netmaker: # The Primary Server for running Netmaker
   netmaker: # The Primary Server for running Netmaker
     container_name: netmaker
     container_name: netmaker
-    image: gravitl/netmaker:v0.15.1
+    image: gravitl/netmaker:v0.15.2
     cap_add: 
     cap_add: 
       - NET_ADMIN
       - NET_ADMIN
       - NET_RAW
       - NET_RAW
@@ -62,7 +62,7 @@ services:
       - traefik.http.services.netmaker-api.loadbalancer.server.port=8081
       - traefik.http.services.netmaker-api.loadbalancer.server.port=8081
   netmaker-ui:  # The Netmaker UI Component
   netmaker-ui:  # The Netmaker UI Component
     container_name: netmaker-ui
     container_name: netmaker-ui
-    image: gravitl/netmaker-ui:v0.15.1
+    image: gravitl/netmaker-ui:v0.15.2
     depends_on:
     depends_on:
       - netmaker
       - netmaker
     links:
     links:
@@ -140,4 +140,4 @@ volumes:
   sqldata: {} # storage for embedded sqlite
   sqldata: {} # storage for embedded sqlite
   dnsconfig: {} # storage for coredns
   dnsconfig: {} # storage for coredns
   mosquitto_data: {} # storage for mqtt data
   mosquitto_data: {} # storage for mqtt data
-  mosquitto_logs: {} # storage for mqtt logs
+  mosquitto_logs: {} # storage for mqtt logs

+ 2 - 2
compose/docker-compose.yml

@@ -3,7 +3,7 @@ version: "3.4"
 services:
 services:
   netmaker:
   netmaker:
     container_name: netmaker
     container_name: netmaker
-    image: gravitl/netmaker:v0.15.1
+    image: gravitl/netmaker:v0.15.2
     cap_add: 
     cap_add: 
       - NET_ADMIN
       - NET_ADMIN
       - NET_RAW
       - NET_RAW
@@ -51,7 +51,7 @@ services:
       - traefik.http.services.netmaker-api.loadbalancer.server.port=8081
       - traefik.http.services.netmaker-api.loadbalancer.server.port=8081
   netmaker-ui:
   netmaker-ui:
     container_name: netmaker-ui
     container_name: netmaker-ui
-    image: gravitl/netmaker-ui:v0.15.1
+    image: gravitl/netmaker-ui:v0.15.2
     depends_on:
     depends_on:
       - netmaker
       - netmaker
     links:
     links:

+ 31 - 7
controllers/dns.go

@@ -27,7 +27,7 @@ func dnsHandlers(r *mux.Router) {
 
 
 // swagger:route GET /api/dns/adm/{network}/nodes dns getNodeDNS
 // swagger:route GET /api/dns/adm/{network}/nodes dns getNodeDNS
 //
 //
-// Gets node DNS entries associated with a network
+// Gets node DNS entries associated with a network.
 //
 //
 //		Schemes: https
 //		Schemes: https
 //
 //
@@ -53,12 +53,16 @@ func getNodeDNS(w http.ResponseWriter, r *http.Request) {
 
 
 // swagger:route GET /api/dns dns getAllDNS
 // swagger:route GET /api/dns dns getAllDNS
 //
 //
-// Gets all DNS entries
+// Gets all DNS entries.
 //
 //
 //		Schemes: https
 //		Schemes: https
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+// 		Responses:
+//   		200: dnsResponse
+//
 func getAllDNS(w http.ResponseWriter, r *http.Request) {
 func getAllDNS(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")
 	dns, err := logic.GetAllDNS()
 	dns, err := logic.GetAllDNS()
@@ -73,12 +77,16 @@ func getAllDNS(w http.ResponseWriter, r *http.Request) {
 
 
 // swagger:route GET /api/dns/adm/{network}/custom dns getCustomDNS
 // swagger:route GET /api/dns/adm/{network}/custom dns getCustomDNS
 //
 //
-// Gets custom DNS entries associated with a network
+// Gets custom DNS entries associated with a network.
 //
 //
 //		Schemes: https
 //		Schemes: https
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+// 		Responses:
+//   		200: dnsResponse
+//
 func getCustomDNS(w http.ResponseWriter, r *http.Request) {
 func getCustomDNS(w http.ResponseWriter, r *http.Request) {
 
 
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")
@@ -99,12 +107,16 @@ func getCustomDNS(w http.ResponseWriter, r *http.Request) {
 
 
 // swagger:route GET /api/dns/adm/{network} dns getDNS
 // swagger:route GET /api/dns/adm/{network} dns getDNS
 //
 //
-// Gets all DNS entries associated with the network
+// Gets all DNS entries associated with the network.
 //
 //
 //		Schemes: https
 //		Schemes: https
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+// 		Responses:
+//   		200: dnsResponse
+//
 func getDNS(w http.ResponseWriter, r *http.Request) {
 func getDNS(w http.ResponseWriter, r *http.Request) {
 
 
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")
@@ -125,12 +137,16 @@ func getDNS(w http.ResponseWriter, r *http.Request) {
 
 
 // swagger:route POST /api/dns/{network} dns createDNS
 // swagger:route POST /api/dns/{network} dns createDNS
 //
 //
-// Create a DNS entry
+// Create a DNS entry.
 //
 //
 //		Schemes: https
 //		Schemes: https
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+// 		Responses:
+//   		200: dnsResponse
+//
 func createDNS(w http.ResponseWriter, r *http.Request) {
 func createDNS(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")
 
 
@@ -184,12 +200,16 @@ func createDNS(w http.ResponseWriter, r *http.Request) {
 
 
 // swagger:route DELETE /api/dns/{network}/{domain} dns deleteDNS
 // swagger:route DELETE /api/dns/{network}/{domain} dns deleteDNS
 //
 //
-// Delete a DNS entry
+// Delete a DNS entry.
 //
 //
 //		Schemes: https
 //		Schemes: https
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+//		Responses:
+//			200: stringJSONResponse
+//			*: stringJSONResponse
 func deleteDNS(w http.ResponseWriter, r *http.Request) {
 func deleteDNS(w http.ResponseWriter, r *http.Request) {
 	// Set header
 	// Set header
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")
@@ -248,12 +268,16 @@ func GetDNSEntry(domain string, network string) (models.DNSEntry, error) {
 
 
 // swagger:route POST /api/dns/adm/pushdns dns pushDNS
 // swagger:route POST /api/dns/adm/pushdns dns pushDNS
 //
 //
-// Push DNS entries to nameserver
+// Push DNS entries to nameserver.
 //
 //
 //		Schemes: https
 //		Schemes: https
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+//		Responses:
+//			200: dnsStringJSONResponse
+//			*: dnsStringJSONResponse
 func pushDNS(w http.ResponseWriter, r *http.Request) {
 func pushDNS(w http.ResponseWriter, r *http.Request) {
 	// Set header
 	// Set header
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")

+ 374 - 1
controllers/docs.go

@@ -11,7 +11,7 @@
 //
 //
 //     Schemes: https
 //     Schemes: https
 //     BasePath: /
 //     BasePath: /
-//     Version: 0.15.1
+//     Version: 0.15.2
 //     Host: netmaker.io
 //     Host: netmaker.io
 //
 //
 //     Consumes:
 //     Consumes:
@@ -25,3 +25,376 @@
 //
 //
 // swagger:meta
 // swagger:meta
 package controller
 package controller
+
+import (
+	serverconfigpkg "github.com/gravitl/netmaker/config"
+	"github.com/gravitl/netmaker/logic/acls"
+	"github.com/gravitl/netmaker/models"
+	"github.com/gravitl/netmaker/netclient/config"
+)
+
+var _ = useUnused() // "use" the function to prevent "unused function" errors
+
+// swagger:parameters getNodeDNS getCustomDNS getDNS
+type dnsPathParams struct {
+	// Network
+	// in: path
+	Network string `json:"network"`
+}
+
+// swagger:parameters createDNS
+type dnsParams struct {
+	// Network
+	// in: path
+	Network string `json:"network"`
+
+	// DNS Entry
+	// in: body
+	Body []models.DNSEntry `json:"body"`
+}
+
+// Success
+// swagger:response dnsResponse
+type dnsResponse struct {
+	// in: body
+	Body []models.DNSEntry `json:"body"`
+}
+
+// swagger:parameters deleteDNS
+type dnsDeletePathParams struct {
+	// Network
+	// in: path
+	Network string `json:"network"`
+
+	// Domain
+	// in: path
+	Domain string `json:"domain"`
+}
+
+// swagger:response stringJSONResponse
+type stringJSONResponse struct {
+	// Response
+	// in: body
+	Response string `json:"response"`
+}
+
+// swagger:parameters getAllExtClients
+type getAllClientsRequest struct {
+	// Networks
+	// in:body
+	Networks []string `json:"networks"`
+}
+
+// swagger:response extClientSliceResponse
+type extClientSliceResponse struct {
+	// ExtClients
+	// in: body
+	ExtClients []models.ExtClient `json:"ext_clients"`
+}
+
+// swagger:response extClientResponse
+type extClientResponse struct {
+	// ExtClient
+	// in: body
+	ExtClient models.ExtClient `json:"ext_client"`
+}
+
+// swagger:response successResponse
+type successResponse struct {
+	// Success Response
+	// in: body
+	SuccessResponse models.SuccessResponse `json:"success_response"`
+}
+
+// swagger:parameters getExtClient getExtClientConf updateExtClient deleteExtClient
+type extClientPathParams struct {
+	// Client ID
+	// in: path
+	ClientID string `json:"clientid"`
+
+	// Network
+	// in: path
+	Network string `json:"network"`
+}
+
+// swagger:parameters updateExtClient
+type extClientBodyParam struct {
+	// ExtClient
+	// in: body
+	ExtClient models.ExtClient `json:"ext_client"`
+}
+
+// swagger:parameters getNetworkExtClients
+type extClientNetworkPathParam struct {
+	// Network
+	// in: path
+	Network string `json:"network"`
+}
+
+// swagger:parameters createExtClient
+type createExtClientPathParams struct {
+	// Network
+	// in: path
+	Network string `json:"network"`
+
+	// Node ID
+	// in: path
+	NodeID string `json:"node"`
+
+	// Custom ExtClient
+	// in: body
+	CustomExtClient models.CustomExtClient `json:"custom_ext_client"`
+}
+
+// swagger:parameters getNode updateNode deleteNode createRelay deleteRelay createEgressGateway deleteEgressGateway createIngressGateway deleteIngressGateway uncordonNode
+type networkNodePathParams struct {
+	// Network
+	// in: path
+	Network string `json:"network"`
+
+	// Node ID
+	// in: path
+	NodeID string `json:"nodeid"`
+}
+
+// swagger:response byteArrayResponse
+type byteArrayResponse struct {
+	// in: body
+	ByteArray []byte `json:"byte_array"`
+}
+
+// swagger:parameters getNetworks
+type headerNetworks struct {
+	// name: networks
+	// in: header
+	Networks []string `json:"networks"`
+}
+
+// swagger:response getNetworksSliceResponse
+type getNetworksSliceResponse struct {
+	// Networks
+	// in: body
+	Networks []models.Network `json:"networks"`
+}
+
+// swagger:parameters createNetwork updateNetwork
+type networkBodyParam struct {
+	// Network
+	// in: body
+	Network models.Network `json:"network"`
+}
+
+// swagger:parameters updateNetwork getNetwork updateNetwork updateNetworkNodeLimit deleteNetwork keyUpdate createAccessKey getAccessKeys deleteAccessKey updateNetworkACL getNetworkACL
+type networkPathParam struct {
+	// Network Name
+	// in: path
+	NetworkName string `json:"networkname"`
+}
+
+// swagger:parameters deleteAccessKey
+type networkAccessKeyNamePathParam struct {
+	// Access Key Name
+	// in: path
+	AccessKeyName string `json:"access_key_name"`
+}
+
+// swagger:response networkBodyResponse
+type networkBodyResponse struct {
+	// Network
+	// in: body
+	Network models.Network `json:"network"`
+}
+
+// swagger:parameters createAccessKey
+type accessKeyBodyParam struct {
+	// Access Key
+	// in: body
+	AccessKey models.AccessKey `json:"access_key"`
+}
+
+// swagger:response accessKeyBodyResponse
+type accessKeyBodyResponse struct {
+	// Access Key
+	// in: body
+	AccessKey models.AccessKey `json:"access_key"`
+}
+
+// swagger:response accessKeySliceBodyResponse
+type accessKeySliceBodyResponse struct {
+	// Access Keys
+	// in: body
+	AccessKey []models.AccessKey `json:"access_key"`
+}
+
+// swagger:parameters updateNetworkACL getNetworkACL
+type aclContainerBodyParam struct {
+	// ACL Container
+	// in: body
+	ACLContainer acls.ACLContainer `json:"acl_container"`
+}
+
+// swagger:response aclContainerResponse
+type aclContainerResponse struct {
+	// ACL Container
+	// in: body
+	ACLContainer acls.ACLContainer `json:"acl_container"`
+}
+
+// swagger:response nodeSliceResponse
+type nodeSliceResponse struct {
+	// Nodes
+	// in: body
+	Nodes []models.Node `json:"nodes"`
+}
+
+// swagger:response nodeResponse
+type nodeResponse struct {
+	// Node
+	// in: body
+	Node models.Node `json:"node"`
+}
+
+// swagger:parameters updateNode deleteNode
+type nodeBodyParam struct {
+	// Node
+	// in: body
+	Node models.Node `json:"node"`
+}
+
+// swagger:parameters createRelay
+type relayRequestBodyParam struct {
+	// Relay Request
+	// in: body
+	RelayRequest models.RelayRequest `json:"relay_request"`
+}
+
+// swagger:parameters createEgressGateway
+type egressGatewayBodyParam struct {
+	// Egress Gateway Request
+	// in: body
+	EgressGatewayRequest models.EgressGatewayRequest `json:"egress_gateway_request"`
+}
+
+// swagger:parameters authenticate
+type authParamBodyParam struct {
+	// AuthParams
+	// in: body
+	AuthParams models.AuthParams `json:"auth_params"`
+}
+
+// swagger:response serverConfigResponse
+type serverConfigResponse struct {
+	// Server Config
+	// in: body
+	ServerConfig serverconfigpkg.ServerConfig `json:"server_config"`
+}
+
+// swagger:response nodeGetResponse
+type nodeGetResponse struct {
+	// Node Get
+	// in: body
+	NodeGet models.NodeGet `json:"node_get"`
+}
+
+// swagger:response nodeLastModifiedResponse
+type nodeLastModifiedResponse struct {
+	// Node Last Modified
+	// in: body
+	NodesLastModified int64 `json:"nodes_last_modified"`
+}
+
+// swagger:parameters register
+type registerRequestBodyParam struct {
+	// Register Request
+	// in: body
+	RegisterRequest config.RegisterRequest `json:"register_request"`
+}
+
+// swagger:response registerResponse 
+type registerResponse struct {
+	// Register Response
+	// in: body
+	RegisterResponse config.RegisterResponse `json:"register_response"`
+}
+
+// swagger:response boolResponse
+type boolResponse struct {
+	// Boolean Response
+	// in: body
+	BoolResponse bool `json:"bool_response"`
+}
+
+// swagger:parameters createAdmin updateUser updateUserNetworks createUser
+type userBodyParam struct {
+	// User
+	// in: body
+	User models.User `json:"user"`
+}
+
+// swagger:response userBodyResponse
+type userBodyResponse struct {
+	// User
+	// in: body
+	User models.User `json:"user"`
+}
+
+// swagger:parameters authenticateUser
+type userAuthBodyParam struct {
+	// User Auth Params
+	// in: body
+	UserAuthParams models.UserAuthParams `json:"user_auth_params"`
+}
+
+// swagger:parameters updateUser updateUserNetworks updateUserAdm createUser deleteUser getUser
+type usernamePathParam struct {
+	// Username
+	// in: path
+	Username string `json:"username"`
+}
+
+// prevent issues with integration tests for types just used by Swagger docs.
+func useUnused() bool {
+	_ = dnsPathParams{}
+	_ = dnsParams{}
+	_ = dnsResponse{}
+	_ = dnsDeletePathParams{}
+	_ = stringJSONResponse{}
+	_ = getAllClientsRequest{}
+	_ = extClientSliceResponse{}
+	_ = extClientResponse{}
+	_ = successResponse{}
+	_ = extClientPathParams{}
+	_ = extClientBodyParam{}
+	_ = extClientNetworkPathParam{}
+	_ = createExtClientPathParams{}
+	_ = networkNodePathParams{}
+	_ = byteArrayResponse{}
+	_ = headerNetworks{}
+	_ = getNetworksSliceResponse{}
+	_ = networkBodyParam{}
+	_ = networkPathParam{}
+	_ = networkAccessKeyNamePathParam{}
+	_ = networkBodyResponse{}
+	_ = accessKeyBodyParam{}
+	_ = accessKeyBodyResponse{}
+	_ = accessKeySliceBodyResponse{}
+	_ = aclContainerBodyParam{}
+	_ = aclContainerResponse{}
+	_ = nodeSliceResponse{}
+	_ = nodeResponse{}
+	_ = nodeBodyParam{}
+	_ = relayRequestBodyParam{}
+	_ = egressGatewayBodyParam{}
+	_ = authParamBodyParam{}
+	_ = serverConfigResponse{}
+	_ = nodeGetResponse{}
+	_ = nodeLastModifiedResponse{}
+	_ = registerRequestBodyParam{}
+	_ = registerResponse{}
+	_ = boolResponse{}
+	_ = userBodyParam{}
+	_ = userBodyResponse{}
+	_ = userAuthBodyParam{}
+	_ = usernamePathParam{}
+	return false
+}

+ 30 - 9
controllers/ext_client.go

@@ -38,13 +38,17 @@ func checkIngressExists(nodeID string) bool {
 
 
 // swagger:route GET /api/extclients/{network} ext_client getNetworkExtClients
 // swagger:route GET /api/extclients/{network} ext_client getNetworkExtClients
 //
 //
-// Get all extclients associated with network
-// Gets all extclients associated with network, including pending extclients
+// Get all extclients associated with network.
+// Gets all extclients associated with network, including pending extclients.
 //
 //
 //		Schemes: https
 //		Schemes: https
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+//		Responses:
+//			200: extClientSliceResponse
+//
 func getNetworkExtClients(w http.ResponseWriter, r *http.Request) {
 func getNetworkExtClients(w http.ResponseWriter, r *http.Request) {
 
 
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")
@@ -75,6 +79,9 @@ func getNetworkExtClients(w http.ResponseWriter, r *http.Request) {
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
 //
 //
+//		Responses:
+//			200: extClientSliceResponse
+//
 // Not quite sure if this is necessary. Probably necessary based on front end but may
 // 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
 // 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) {
@@ -113,7 +120,7 @@ func getAllExtClients(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(clients)
 	json.NewEncoder(w).Encode(clients)
 }
 }
 
 
-// swagger:route GET /api/extclients ext_client getExtClient
+// swagger:route GET /api/extclients/{network}/{clientid} ext_client getExtClient
 //
 //
 // Get an individual extclient.
 // Get an individual extclient.
 //
 //
@@ -122,6 +129,9 @@ func getAllExtClients(w http.ResponseWriter, r *http.Request) {
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
 //
 //
+//		Responses:
+//			200: extClientResponse
+//
 func getExtClient(w http.ResponseWriter, r *http.Request) {
 func getExtClient(w http.ResponseWriter, r *http.Request) {
 	// set header.
 	// set header.
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")
@@ -151,6 +161,9 @@ func getExtClient(w http.ResponseWriter, r *http.Request) {
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
 //
 //
+//		Responses:
+//			200: extClientResponse
+//
 func getExtClientConf(w http.ResponseWriter, r *http.Request) {
 func getExtClientConf(w http.ResponseWriter, r *http.Request) {
 	// set header.
 	// set header.
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")
@@ -289,7 +302,7 @@ func createExtClient(w http.ResponseWriter, r *http.Request) {
 	var params = mux.Vars(r)
 	var params = mux.Vars(r)
 	networkName := params["network"]
 	networkName := params["network"]
 	nodeid := params["nodeid"]
 	nodeid := params["nodeid"]
-	
+
 	ingressExists := checkIngressExists(nodeid)
 	ingressExists := checkIngressExists(nodeid)
 	if !ingressExists {
 	if !ingressExists {
 		err := errors.New("ingress does not exist")
 		err := errors.New("ingress does not exist")
@@ -301,11 +314,13 @@ func createExtClient(w http.ResponseWriter, r *http.Request) {
 
 
 	var extclient models.ExtClient
 	var extclient models.ExtClient
 	var CustomExtClient models.CustomExtClient
 	var CustomExtClient models.CustomExtClient
-	
-	err := json.NewDecoder(r.Body).Decode(&CustomExtClient);
-	
-	if err == nil { extclient.ClientID = CustomExtClient.ClientID }
-	
+
+	err := json.NewDecoder(r.Body).Decode(&CustomExtClient)
+
+	if err == nil {
+		extclient.ClientID = CustomExtClient.ClientID
+	}
+
 	extclient.Network = networkName
 	extclient.Network = networkName
 	extclient.IngressGatewayID = nodeid
 	extclient.IngressGatewayID = nodeid
 	node, err := logic.GetNodeByID(nodeid)
 	node, err := logic.GetNodeByID(nodeid)
@@ -346,6 +361,9 @@ func createExtClient(w http.ResponseWriter, r *http.Request) {
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
 //
 //
+//		Responses:
+//			200: extClientResponse
+//
 func updateExtClient(w http.ResponseWriter, r *http.Request) {
 func updateExtClient(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")
 
 
@@ -414,6 +432,9 @@ func updateExtClient(w http.ResponseWriter, r *http.Request) {
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
 //
 //
+//		Responses:
+//			200: successResponse
+//
 func deleteExtClient(w http.ResponseWriter, r *http.Request) {
 func deleteExtClient(w http.ResponseWriter, r *http.Request) {
 	// Set header
 	// Set header
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")

+ 1 - 1
controllers/files.go

@@ -9,7 +9,7 @@ import (
 func fileHandlers(r *mux.Router) {
 func fileHandlers(r *mux.Router) {
 	// swagger:route GET /meshclient/files/{filename} meshclient fileServer
 	// swagger:route GET /meshclient/files/{filename} meshclient fileServer
 	//
 	//
-	// Retrieve a file from the file server
+	// Retrieve a file from the file server.
 	//
 	//
 	//		Schemes: https
 	//		Schemes: https
 	//
 	//

+ 4 - 1
controllers/ipservice.go

@@ -16,13 +16,16 @@ func ipHandlers(r *mux.Router) {
 
 
 // swagger:route GET /api/getip ipservice getPublicIP
 // swagger:route GET /api/getip ipservice getPublicIP
 //
 //
-// Get the current public IP address
+// Get the current public IP address.
 //
 //
 //		Schemes: https
 //		Schemes: https
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
 //
 //
+//		Responses:
+//			200: byteArrayResponse
+//
 func getPublicIP(w http.ResponseWriter, r *http.Request) {
 func getPublicIP(w http.ResponseWriter, r *http.Request) {
 	r.Header.Set("Connection", "close")
 	r.Header.Set("Connection", "close")
 	ip, err := parseIP(r)
 	ip, err := parseIP(r)

+ 44 - 7
controllers/network.go

@@ -41,12 +41,15 @@ func networkHandlers(r *mux.Router) {
 
 
 // swagger:route GET /api/networks networks getNetworks
 // swagger:route GET /api/networks networks getNetworks
 //
 //
-// Lists all networks
+// Lists all networks.
 //
 //
 //		Schemes: https
 //		Schemes: https
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+//		Responses:
+//			200: getNetworksSliceResponse
 func getNetworks(w http.ResponseWriter, r *http.Request) {
 func getNetworks(w http.ResponseWriter, r *http.Request) {
 
 
 	headerNetworks := r.Header.Get("networks")
 	headerNetworks := r.Header.Get("networks")
@@ -87,14 +90,17 @@ func getNetworks(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(allnetworks)
 	json.NewEncoder(w).Encode(allnetworks)
 }
 }
 
 
-// swagger:route GET /api/networks networks getNetwork
+// swagger:route GET /api/networks/{networkname} networks getNetwork
 //
 //
-// Get a network
+// Get a network.
 //
 //
 //		Schemes: https
 //		Schemes: https
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+//		Responses:
+//			200: networkBodyResponse
 func getNetwork(w http.ResponseWriter, r *http.Request) {
 func getNetwork(w http.ResponseWriter, r *http.Request) {
 	// set header.
 	// set header.
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")
@@ -123,6 +129,9 @@ func getNetwork(w http.ResponseWriter, r *http.Request) {
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+//		Responses:
+//			200: networkBodyResponse
 func keyUpdate(w http.ResponseWriter, r *http.Request) {
 func keyUpdate(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)
@@ -154,12 +163,15 @@ func keyUpdate(w http.ResponseWriter, r *http.Request) {
 
 
 // swagger:route PUT /api/networks/{networkname} networks updateNetwork
 // swagger:route PUT /api/networks/{networkname} networks updateNetwork
 //
 //
-// Update a network
+// Update a network.
 //
 //
 //		Schemes: https
 //		Schemes: https
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+//		Responses:
+//			200: networkBodyResponse
 func updateNetwork(w http.ResponseWriter, r *http.Request) {
 func updateNetwork(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)
@@ -256,12 +268,15 @@ func updateNetwork(w http.ResponseWriter, r *http.Request) {
 
 
 // swagger:route PUT /api/networks/{networkname}/nodelimit networks updateNetworkNodeLimit
 // swagger:route PUT /api/networks/{networkname}/nodelimit networks updateNetworkNodeLimit
 //
 //
-// Update a network's node limit
+// Update a network's node limit.
 //
 //
 //		Schemes: https
 //		Schemes: https
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+//		Responses:
+//			200: networkBodyResponse
 func updateNetworkNodeLimit(w http.ResponseWriter, r *http.Request) {
 func updateNetworkNodeLimit(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)
@@ -309,6 +324,9 @@ func updateNetworkNodeLimit(w http.ResponseWriter, r *http.Request) {
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+//		Responses:
+//			200: aclContainerResponse
 func updateNetworkACL(w http.ResponseWriter, r *http.Request) {
 func updateNetworkACL(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)
@@ -364,6 +382,9 @@ func updateNetworkACL(w http.ResponseWriter, r *http.Request) {
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+//		Responses:
+//			200: aclContainerResponse
 func getNetworkACL(w http.ResponseWriter, r *http.Request) {
 func getNetworkACL(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)
@@ -389,6 +410,9 @@ func getNetworkACL(w http.ResponseWriter, r *http.Request) {
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+//		Responses:
+//			200: stringJSONResponse
 func deleteNetwork(w http.ResponseWriter, r *http.Request) {
 func deleteNetwork(w http.ResponseWriter, r *http.Request) {
 	// Set header
 	// Set header
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")
@@ -413,12 +437,15 @@ func deleteNetwork(w http.ResponseWriter, r *http.Request) {
 
 
 // swagger:route POST /api/networks networks createNetwork
 // swagger:route POST /api/networks networks createNetwork
 //
 //
-// Create a network
+// Create a network.
 //
 //
 //		Schemes: https
 //		Schemes: https
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+//		Responses:
+//			200: networkBodyResponse
 func createNetwork(w http.ResponseWriter, r *http.Request) {
 func createNetwork(w http.ResponseWriter, r *http.Request) {
 
 
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")
@@ -478,6 +505,9 @@ func createNetwork(w http.ResponseWriter, r *http.Request) {
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
 //
 //
+//		Responses:
+//			200: accessKeyBodyResponse
+//
 // BEGIN KEY MANAGEMENT SECTION
 // BEGIN KEY MANAGEMENT SECTION
 func createAccessKey(w http.ResponseWriter, r *http.Request) {
 func createAccessKey(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")
@@ -519,6 +549,9 @@ func createAccessKey(w http.ResponseWriter, r *http.Request) {
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+//		Responses:
+//			200: accessKeySliceBodyResponse
 func getAccessKeys(w http.ResponseWriter, r *http.Request) {
 func getAccessKeys(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)
@@ -538,7 +571,7 @@ func getAccessKeys(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(keys)
 	json.NewEncoder(w).Encode(keys)
 }
 }
 
 
-// swagger:route GET /api/networks/{networkname}/keys/{name} networks deleteAccessKey
+// swagger:route DELETE /api/networks/{networkname}/keys/{name} networks deleteAccessKey
 //
 //
 // Delete a network access key.
 // Delete a network access key.
 //
 //
@@ -547,6 +580,10 @@ func getAccessKeys(w http.ResponseWriter, r *http.Request) {
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
 //
 //
+//		Responses:
+//			200:
+//			*: stringJSONResponse
+//
 // delete key. Has to do a little funky logic since it's not a collection item
 // delete key. Has to do a little funky logic since it's not a collection item
 func deleteAccessKey(w http.ResponseWriter, r *http.Request) {
 func deleteAccessKey(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")

+ 40 - 1
controllers/node.go

@@ -44,6 +44,9 @@ func nodeHandlers(r *mux.Router) {
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+//		Responses:
+//			200: successResponse
 func authenticate(response http.ResponseWriter, request *http.Request) {
 func authenticate(response http.ResponseWriter, request *http.Request) {
 
 
 	var authRequest models.AuthParams
 	var authRequest models.AuthParams
@@ -297,12 +300,15 @@ func authorize(nodesAllowed, networkCheck bool, authNetwork string, next http.Ha
 
 
 // swagger:route GET /api/nodes/{network} nodes getNetworkNodes
 // swagger:route GET /api/nodes/{network} nodes getNetworkNodes
 //
 //
-// Gets all nodes associated with network including pending nodes
+// Gets all nodes associated with network including pending nodes.
 //
 //
 //		Schemes: https
 //		Schemes: https
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+//		Responses:
+//			200: nodeSliceResponse
 func getNetworkNodes(w http.ResponseWriter, r *http.Request) {
 func getNetworkNodes(w http.ResponseWriter, r *http.Request) {
 
 
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")
@@ -339,6 +345,9 @@ func getNetworkNodes(w http.ResponseWriter, r *http.Request) {
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+//		Responses:
+//			200: nodeSliceResponse
 // 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 getAllNodes(w http.ResponseWriter, r *http.Request) {
 func getAllNodes(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")
@@ -393,6 +402,9 @@ func getUsersNodes(user models.User) ([]models.Node, error) {
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+//		Responses:
+//			200: nodeResponse
 func getNode(w http.ResponseWriter, r *http.Request) {
 func getNode(w http.ResponseWriter, r *http.Request) {
 	// set header.
 	// set header.
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")
@@ -438,6 +450,9 @@ func getNode(w http.ResponseWriter, r *http.Request) {
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+//		Responses:
+//			200: nodeLastModifiedResponse
 // TODO: This needs to be refactored
 // TODO: This needs to be refactored
 // Potential way to do this: On UpdateNode, set a new field for "LastModified"
 // Potential way to do this: On UpdateNode, set a new field for "LastModified"
 // If we go with the existing way, we need to at least set network.NodesLastModified on UpdateNode
 // If we go with the existing way, we need to at least set network.NodesLastModified on UpdateNode
@@ -467,6 +482,9 @@ func getLastModified(w http.ResponseWriter, r *http.Request) {
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+//		Responses:
+//			200: nodeGetResponse
 func createNode(w http.ResponseWriter, r *http.Request) {
 func createNode(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")
 
 
@@ -594,6 +612,9 @@ func createNode(w http.ResponseWriter, r *http.Request) {
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+//		Responses:
+//			200: nodeResponse
 // Takes node out of pending state
 // Takes node out of pending state
 // TODO: May want to use cordon/uncordon terminology instead of "ispending".
 // TODO: May want to use cordon/uncordon terminology instead of "ispending".
 func uncordonNode(w http.ResponseWriter, r *http.Request) {
 func uncordonNode(w http.ResponseWriter, r *http.Request) {
@@ -624,6 +645,9 @@ func uncordonNode(w http.ResponseWriter, r *http.Request) {
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+//		Responses:
+//			200: nodeResponse
 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)
@@ -660,6 +684,9 @@ func createEgressGateway(w http.ResponseWriter, r *http.Request) {
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+//		Responses:
+//			200: nodeResponse
 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)
@@ -691,6 +718,9 @@ func deleteEgressGateway(w http.ResponseWriter, r *http.Request) {
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+//		Responses:
+//			200: nodeResponse
 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")
@@ -720,6 +750,9 @@ func createIngressGateway(w http.ResponseWriter, r *http.Request) {
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+//		Responses:
+//			200: nodeResponse
 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)
@@ -749,6 +782,9 @@ func deleteIngressGateway(w http.ResponseWriter, r *http.Request) {
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+//		Responses:
+//			200: nodeResponse
 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")
 
 
@@ -851,6 +887,9 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+//		Responses:
+//			200: nodeResponse
 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")

+ 6 - 0
controllers/relay.go

@@ -20,6 +20,9 @@ import (
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+//		Responses:
+//			200: nodeResponse
 func createRelay(w http.ResponseWriter, r *http.Request) {
 func createRelay(w http.ResponseWriter, r *http.Request) {
 	var relay models.RelayRequest
 	var relay models.RelayRequest
 	var params = mux.Vars(r)
 	var params = mux.Vars(r)
@@ -59,6 +62,9 @@ func createRelay(w http.ResponseWriter, r *http.Request) {
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+//		Responses:
+//			200: nodeResponse
 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)

+ 13 - 1
controllers/server.go

@@ -75,6 +75,9 @@ func securityCheckServer(adminonly bool, next http.Handler) http.HandlerFunc {
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+//		Responses:
+//			200: stringJSONResponse
 func removeNetwork(w http.ResponseWriter, r *http.Request) {
 func removeNetwork(w http.ResponseWriter, r *http.Request) {
 	// Set header
 	// Set header
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")
@@ -102,6 +105,9 @@ func removeNetwork(w http.ResponseWriter, r *http.Request) {
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+//		Responses:
+//			200: serverConfigResponse
 func getServerInfo(w http.ResponseWriter, r *http.Request) {
 func getServerInfo(w http.ResponseWriter, r *http.Request) {
 	// Set header
 	// Set header
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")
@@ -120,6 +126,9 @@ func getServerInfo(w http.ResponseWriter, r *http.Request) {
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+//		Responses:
+//			200: serverConfigResponse
 func getConfig(w http.ResponseWriter, r *http.Request) {
 func getConfig(w http.ResponseWriter, r *http.Request) {
 	// Set header
 	// Set header
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")
@@ -133,12 +142,15 @@ func getConfig(w http.ResponseWriter, r *http.Request) {
 
 
 // swagger:route POST /api/server/register nodes register
 // swagger:route POST /api/server/register nodes register
 //
 //
-// Registers a client with the server and return the Certificate Authority and certificate
+// Registers a client with the server and return the Certificate Authority and certificate.
 //
 //
 //		Schemes: https
 //		Schemes: https
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+//		Responses:
+//			200: registerResponse
 func register(w http.ResponseWriter, r *http.Request) {
 func register(w http.ResponseWriter, r *http.Request) {
 	logger.Log(2, "processing registration request")
 	logger.Log(2, "processing registration request")
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")

+ 32 - 3
controllers/user.go

@@ -39,6 +39,8 @@ func userHandlers(r *mux.Router) {
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
 //
 //
+//		Responses:
+//			200: successResponse
 func authenticateUser(response http.ResponseWriter, request *http.Request) {
 func authenticateUser(response http.ResponseWriter, request *http.Request) {
 
 
 	// Auth request consists of Mac Address and Password (from node that is authorizing
 	// Auth request consists of Mac Address and Password (from node that is authorizing
@@ -103,6 +105,9 @@ func authenticateUser(response http.ResponseWriter, request *http.Request) {
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+//		Responses:
+//			200: successResponse
 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")
@@ -140,6 +145,9 @@ func GetUserInternal(username string) (models.User, error) {
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+//		Responses:
+//			200: userBodyResponse
 func getUser(w http.ResponseWriter, r *http.Request) {
 func getUser(w http.ResponseWriter, r *http.Request) {
 	// set header.
 	// set header.
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")
@@ -159,12 +167,15 @@ func getUser(w http.ResponseWriter, r *http.Request) {
 
 
 // swagger:route GET /api/users nodes getUsers
 // swagger:route GET /api/users nodes getUsers
 //
 //
-// Get all users
+// Get all users.
 //
 //
 //		Schemes: https
 //		Schemes: https
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+//		Responses:
+//			200: userBodyResponse
 func getUsers(w http.ResponseWriter, r *http.Request) {
 func getUsers(w http.ResponseWriter, r *http.Request) {
 	// set header.
 	// set header.
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")
@@ -189,6 +200,9 @@ func getUsers(w http.ResponseWriter, r *http.Request) {
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+//		Responses:
+//			200: userBodyResponse
 func createAdmin(w http.ResponseWriter, r *http.Request) {
 func createAdmin(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")
 
 
@@ -222,6 +236,9 @@ func createAdmin(w http.ResponseWriter, r *http.Request) {
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+//		Responses:
+//			200: userBodyResponse
 func createUser(w http.ResponseWriter, r *http.Request) {
 func createUser(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")
 
 
@@ -246,12 +263,15 @@ func createUser(w http.ResponseWriter, r *http.Request) {
 
 
 // swagger:route PUT /api/users/networks/{username} nodes updateUserNetworks
 // swagger:route PUT /api/users/networks/{username} nodes updateUserNetworks
 //
 //
-// Updates the networks of the given user
+// Updates the networks of the given user.
 //
 //
 //		Schemes: https
 //		Schemes: https
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+//		Responses:
+//			200: userBodyResponse
 func updateUserNetworks(w http.ResponseWriter, r *http.Request) {
 func updateUserNetworks(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)
@@ -293,6 +313,9 @@ func updateUserNetworks(w http.ResponseWriter, r *http.Request) {
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+//		Responses:
+//			200: userBodyResponse
 func updateUser(w http.ResponseWriter, r *http.Request) {
 func updateUser(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)
@@ -335,12 +358,15 @@ func updateUser(w http.ResponseWriter, r *http.Request) {
 
 
 // swagger:route PUT /api/users/{username}/adm nodes updateUserAdm
 // swagger:route PUT /api/users/{username}/adm nodes updateUserAdm
 //
 //
-// Updates the given admin user's info (as long as the user is an admin)
+// Updates the given admin user's info (as long as the user is an admin).
 //
 //
 //		Schemes: https
 //		Schemes: https
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+//		Responses:
+//			200: userBodyResponse
 func updateUserAdm(w http.ResponseWriter, r *http.Request) {
 func updateUserAdm(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)
@@ -390,6 +416,9 @@ func updateUserAdm(w http.ResponseWriter, r *http.Request) {
 //
 //
 // 		Security:
 // 		Security:
 //   		oauth
 //   		oauth
+//
+//		Responses:
+//			200: userBodyResponse
 func deleteUser(w http.ResponseWriter, r *http.Request) {
 func deleteUser(w http.ResponseWriter, r *http.Request) {
 	// Set header
 	// Set header
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")

+ 1 - 1
k8s/client/netclient-daemonset.yaml

@@ -16,7 +16,7 @@ spec:
       hostNetwork: true
       hostNetwork: true
       containers:
       containers:
       - name: netclient
       - name: netclient
-        image: gravitl/netclient-go:v0.15.1
+        image: gravitl/netclient-go:v0.15.2
         env:
         env:
         - name: TOKEN
         - name: TOKEN
           value: "TOKEN_VALUE"
           value: "TOKEN_VALUE"

+ 2 - 2
k8s/client/netclient.yaml

@@ -28,7 +28,7 @@ spec:
       #           - "<node label value>"
       #           - "<node label value>"
       containers:
       containers:
       - name: netclient
       - name: netclient
-        image: gravitl/netclient:v0.15.1
+        image: gravitl/netclient:v0.15.2
         env:
         env:
         - name: TOKEN
         - name: TOKEN
           value: "TOKEN_VALUE"
           value: "TOKEN_VALUE"
@@ -41,4 +41,4 @@ spec:
       - hostPath:
       - hostPath:
           path: /etc/netclient
           path: /etc/netclient
           type: DirectoryOrCreate
           type: DirectoryOrCreate
-        name: etc-netclient
+        name: etc-netclient

+ 2 - 2
k8s/server/netmaker-server.yaml

@@ -83,7 +83,7 @@ spec:
           value: "Kubernetes"
           value: "Kubernetes"
         - name: VERBOSITY
         - name: VERBOSITY
           value: "3"
           value: "3"
-        image: gravitl/netmaker:v0.15.1
+        image: gravitl/netmaker:v0.15.2
         imagePullPolicy: Always
         imagePullPolicy: Always
         name: netmaker
         name: netmaker
         ports:
         ports:
@@ -225,4 +225,4 @@ spec:
 #           service:
 #           service:
 #             name: netmaker-rest
 #             name: netmaker-rest
 #             port:
 #             port:
-#               number: 8081
+#               number: 8081

+ 2 - 2
k8s/server/netmaker-ui.yaml

@@ -15,7 +15,7 @@ spec:
     spec:
     spec:
       containers:
       containers:
       - name: netmaker-ui
       - name: netmaker-ui
-        image: gravitl/netmaker-ui:v0.15.1
+        image: gravitl/netmaker-ui:v0.15.2
         ports:
         ports:
         - containerPort: 443
         - containerPort: 443
         env:
         env:
@@ -61,4 +61,4 @@ spec:
 #           service:
 #           service:
 #             name: netmaker-ui
 #             name: netmaker-ui
 #             port:
 #             port:
-#               number: 80
+#               number: 80

+ 8 - 3
logic/gateway.go

@@ -14,6 +14,14 @@ import (
 
 
 // CreateEgressGateway - creates an egress gateway
 // CreateEgressGateway - creates an egress gateway
 func CreateEgressGateway(gateway models.EgressGatewayRequest) (models.Node, error) {
 func CreateEgressGateway(gateway models.EgressGatewayRequest) (models.Node, error) {
+	for i, cidr := range gateway.Ranges {
+		normalized, err := NormalizeCIDR(cidr)
+		if err != nil {
+			return models.Node{}, err
+		}
+		gateway.Ranges[i] = normalized
+
+	}
 	node, err := GetNodeByID(gateway.NodeID)
 	node, err := GetNodeByID(gateway.NodeID)
 	if err != nil {
 	if err != nil {
 		return models.Node{}, err
 		return models.Node{}, err
@@ -325,9 +333,6 @@ func firewallNFTCommandsCreateEgress(networkInterface string, gatewayInterface s
 		postUp += "nft add table nat ; "
 		postUp += "nft add table nat ; "
 		postUp += "nft 'add chain ip nat prerouting { type nat hook prerouting priority 0 ;}' ; "
 		postUp += "nft 'add chain ip nat prerouting { type nat hook prerouting priority 0 ;}' ; "
 		postUp += "nft 'add chain ip nat postrouting { type nat hook postrouting priority 0 ;}' ; "
 		postUp += "nft 'add chain ip nat postrouting { type nat hook postrouting priority 0 ;}' ; "
-		for _, networkCIDR := range gatewayranges {
-			postUp += "nft add rule nat postrouting iifname " + networkInterface + " oifname " + gatewayInterface + " ip saddr " + networkCIDR + " masquerade ; "
-		}
 
 
 		postDown += "nft flush table filter ; "
 		postDown += "nft flush table filter ; "
 
 

+ 15 - 2
logic/networks.go

@@ -70,6 +70,20 @@ func DeleteNetwork(network string) error {
 // CreateNetwork - creates a network in database
 // CreateNetwork - creates a network in database
 func CreateNetwork(network models.Network) (models.Network, error) {
 func CreateNetwork(network models.Network) (models.Network, error) {
 
 
+	if network.AddressRange != "" {
+		normalizedRange, err := NormalizeCIDR(network.AddressRange)
+		if err != nil {
+			return models.Network{}, err
+		}
+		network.AddressRange = normalizedRange
+	}
+	if network.AddressRange6 != "" {
+		normalizedRange, err := NormalizeCIDR(network.AddressRange6)
+		if err != nil {
+			return models.Network{}, err
+		}
+		network.AddressRange6 = normalizedRange
+	}
 	network.SetDefaults()
 	network.SetDefaults()
 	network.SetNodesLastModified()
 	network.SetNodesLastModified()
 	network.SetNetworkLastModified()
 	network.SetNetworkLastModified()
@@ -659,8 +673,7 @@ func deleteInterface(ifacename string, postdown string) error {
 		}
 		}
 		_, err = ncutils.RunCmd(ipExec+" link del "+ifacename, false)
 		_, err = ncutils.RunCmd(ipExec+" link del "+ifacename, false)
 		if postdown != "" {
 		if postdown != "" {
-			runcmds := strings.Split(postdown, "; ")
-			err = ncutils.RunCmds(runcmds, false)
+			_, err = ncutils.RunCmd(postdown, false)
 		}
 		}
 	}
 	}
 	return err
 	return err

+ 39 - 0
logic/server.go

@@ -1,6 +1,7 @@
 package logic
 package logic
 
 
 import (
 import (
+	"encoding/json"
 	"errors"
 	"errors"
 	"fmt"
 	"fmt"
 	"net"
 	"net"
@@ -8,6 +9,7 @@ import (
 	"runtime"
 	"runtime"
 	"strings"
 	"strings"
 
 
+	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/logger"
 	"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"
@@ -285,3 +287,40 @@ func serverPush(serverNode *models.Node) error {
 	serverNode.SetLastCheckIn()
 	serverNode.SetLastCheckIn()
 	return UpdateNode(serverNode, serverNode)
 	return UpdateNode(serverNode, serverNode)
 }
 }
+
+// AddServerIDIfNotPresent - add's current server ID to DB if not present
+func AddServerIDIfNotPresent() error {
+	currentNodeID := servercfg.GetNodeID()
+	currentServerIDs := models.ServerIDs{}
+
+	record, err := database.FetchRecord(database.SERVERCONF_TABLE_NAME, server_id_key)
+	if err != nil && !database.IsEmptyRecord(err) {
+		return err
+	} else if err == nil {
+		if err = json.Unmarshal([]byte(record), &currentServerIDs); err != nil {
+			return err
+		}
+	}
+
+	if !StringSliceContains(currentServerIDs.ServerIDs, currentNodeID) {
+		currentServerIDs.ServerIDs = append(currentServerIDs.ServerIDs, currentNodeID)
+		data, err := json.Marshal(&currentServerIDs)
+		if err != nil {
+			return err
+		}
+		return database.Insert(server_id_key, string(data), database.SERVERCONF_TABLE_NAME)
+	}
+
+	return nil
+}
+
+// GetServerCount - fetches server count from DB
+func GetServerCount() int {
+	if record, err := database.FetchRecord(database.SERVERCONF_TABLE_NAME, server_id_key); err == nil {
+		currentServerIDs := models.ServerIDs{}
+		if err = json.Unmarshal([]byte(record), &currentServerIDs); err == nil {
+			return len(currentServerIDs.ServerIDs)
+		}
+	}
+	return 1
+}

+ 3 - 0
logic/serverconf.go

@@ -6,6 +6,9 @@ import (
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/database"
 )
 )
 
 
+// constant for database key for storing server ids
+const server_id_key = "nm-server-id"
+
 type serverData struct {
 type serverData struct {
 	PrivateKey string `json:"privatekey,omitempty" bson:"privatekey,omitempty"`
 	PrivateKey string `json:"privatekey,omitempty" bson:"privatekey,omitempty"`
 }
 }

+ 3 - 0
logic/telemetry.go

@@ -43,6 +43,7 @@ func sendTelemetry() error {
 		Event:      "daily checkin",
 		Event:      "daily checkin",
 		Properties: posthog.NewProperties().
 		Properties: posthog.NewProperties().
 			Set("nodes", d.Nodes).
 			Set("nodes", d.Nodes).
+			Set("servers", d.Servers).
 			Set("non-server nodes", d.Count.NonServer).
 			Set("non-server nodes", d.Count.NonServer).
 			Set("extclients", d.ExtClients).
 			Set("extclients", d.ExtClients).
 			Set("users", d.Users).
 			Set("users", d.Users).
@@ -65,6 +66,7 @@ func fetchTelemetryData() (telemetryData, error) {
 	data.Users = getDBLength(database.USERS_TABLE_NAME)
 	data.Users = getDBLength(database.USERS_TABLE_NAME)
 	data.Networks = getDBLength(database.NETWORKS_TABLE_NAME)
 	data.Networks = getDBLength(database.NETWORKS_TABLE_NAME)
 	data.Version = servercfg.GetVersion()
 	data.Version = servercfg.GetVersion()
+	data.Servers = GetServerCount()
 	nodes, err := GetAllNodes()
 	nodes, err := GetAllNodes()
 	if err == nil {
 	if err == nil {
 		data.Nodes = len(nodes)
 		data.Nodes = len(nodes)
@@ -140,6 +142,7 @@ type telemetryData struct {
 	Users      int
 	Users      int
 	Count      clientCount
 	Count      clientCount
 	Networks   int
 	Networks   int
+	Servers    int
 	Version    string
 	Version    string
 }
 }
 
 

+ 17 - 0
logic/util.go

@@ -13,6 +13,7 @@ import (
 	"strings"
 	"strings"
 	"time"
 	"time"
 
 
+	"github.com/c-robinson/iplib"
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/models"
@@ -170,6 +171,22 @@ func ShouldPublishPeerPorts(serverNode *models.Node) bool {
 	return false
 	return false
 }
 }
 
 
+// NormalCIDR - returns the first address of CIDR
+func NormalizeCIDR(address string) (string, error) {
+	ip, IPNet, err := net.ParseCIDR(address)
+	if err != nil {
+		return "", err
+	}
+	if ip.To4() == nil {
+		net6 := iplib.Net6FromStr(IPNet.String())
+		IPNet.IP = net6.FirstAddress()
+	} else {
+		net4 := iplib.Net4FromStr(IPNet.String())
+		IPNet.IP = net4.NetworkAddress()
+	}
+	return IPNet.String(), nil
+}
+
 func getNetworkProtocols(cidrs []string) (bool, bool) {
 func getNetworkProtocols(cidrs []string) (bool, bool) {
 	ipv4 := false
 	ipv4 := false
 	ipv6 := false
 	ipv6 := false

+ 1 - 2
logic/wireguard.go

@@ -191,8 +191,7 @@ func removeLocalServer(node *models.Node) error {
 				logger.Log(1, out)
 				logger.Log(1, out)
 			}
 			}
 			if node.PostDown != "" {
 			if node.PostDown != "" {
-				runcmds := strings.Split(node.PostDown, "; ")
-				_ = ncutils.RunCmds(runcmds, false)
+				ncutils.RunCmd(node.PostDown, false)
 			}
 			}
 		}
 		}
 	}
 	}

+ 3 - 1
main.go

@@ -74,7 +74,9 @@ func initialize() { // Client Mode Prereq Check
 	}
 	}
 	logger.Log(0, "database successfully connected")
 	logger.Log(0, "database successfully connected")
 	logic.SetJWTSecret()
 	logic.SetJWTSecret()
-
+	if err = logic.AddServerIDIfNotPresent(); err != nil {
+		logger.Log(1, "failed to save server ID")
+	}
 	err = logic.TimerCheckpoint()
 	err = logic.TimerCheckpoint()
 	if err != nil {
 	if err != nil {
 		logger.Log(1, "Timer error occurred: ", err.Error())
 		logger.Log(1, "Timer error occurred: ", err.Error())

+ 7 - 1
models/node.go

@@ -39,12 +39,18 @@ const (
 var seededRand *rand.Rand = rand.New(
 var seededRand *rand.Rand = rand.New(
 	rand.NewSource(time.Now().UnixNano()))
 	rand.NewSource(time.Now().UnixNano()))
 
 
+// NodeCheckin - struct for node checkins with server
+type NodeCheckin struct {
+	Version   string
+	Connected string
+}
+
 // Node - struct for node model
 // Node - struct for node model
 type Node struct {
 type Node struct {
 	ID                      string               `json:"id,omitempty" bson:"id,omitempty" yaml:"id,omitempty" validate:"required,min=5,id_unique"`
 	ID                      string               `json:"id,omitempty" bson:"id,omitempty" yaml:"id,omitempty" validate:"required,min=5,id_unique"`
 	Address                 string               `json:"address" bson:"address" yaml:"address" validate:"omitempty,ipv4"`
 	Address                 string               `json:"address" bson:"address" yaml:"address" validate:"omitempty,ipv4"`
 	Address6                string               `json:"address6" bson:"address6" yaml:"address6" validate:"omitempty,ipv6"`
 	Address6                string               `json:"address6" bson:"address6" yaml:"address6" validate:"omitempty,ipv6"`
-	LocalAddress            string               `json:"localaddress" bson:"localaddress" yaml:"localaddress" validate:"omitempty,ip"`
+	LocalAddress            string               `json:"localaddress" bson:"localaddress" yaml:"localaddress" validate:"omitempty"`
 	Name                    string               `json:"name" bson:"name" yaml:"name" validate:"omitempty,max=62,in_charset"`
 	Name                    string               `json:"name" bson:"name" yaml:"name" validate:"omitempty,max=62,in_charset"`
 	NetworkSettings         Network              `json:"networksettings" bson:"networksettings" yaml:"networksettings" validate:"-"`
 	NetworkSettings         Network              `json:"networksettings" bson:"networksettings" yaml:"networksettings" validate:"-"`
 	ListenPort              int32                `json:"listenport" bson:"listenport" yaml:"listenport" validate:"omitempty,numeric,min=1024,max=65535"`
 	ListenPort              int32                `json:"listenport" bson:"listenport" yaml:"listenport" validate:"omitempty,numeric,min=1024,max=65535"`

+ 5 - 0
models/structs.go

@@ -224,3 +224,8 @@ func (user *User) NameInCharSet() bool {
 	}
 	}
 	return true
 	return true
 }
 }
+
+// ServerIDs - struct to hold server ids.
+type ServerIDs struct {
+	ServerIDs []string `json:"server_ids"`
+}

+ 8 - 2
mq/handlers.go

@@ -36,13 +36,19 @@ func Ping(client mqtt.Client, msg mqtt.Message) {
 			logger.Log(0, record)
 			logger.Log(0, record)
 			return
 			return
 		}
 		}
-		version, decryptErr := decryptMsg(&node, msg.Payload())
+		decrypted, decryptErr := decryptMsg(&node, msg.Payload())
 		if decryptErr != nil {
 		if decryptErr != nil {
 			logger.Log(0, "error decrypting when updating node ", node.ID, decryptErr.Error())
 			logger.Log(0, "error decrypting when updating node ", node.ID, decryptErr.Error())
 			return
 			return
 		}
 		}
+		var checkin models.NodeCheckin
+		if err := json.Unmarshal(decrypted, &checkin); err != nil {
+			logger.Log(1, "error unmarshaling payload ", err.Error())
+			return
+		}
 		node.SetLastCheckIn()
 		node.SetLastCheckIn()
-		node.Version = string(version)
+		node.Version = checkin.Version
+		node.Connected = checkin.Connected
 		if err := logic.UpdateNode(&node, &node); err != nil {
 		if err := logic.UpdateNode(&node, &node); err != nil {
 			logger.Log(0, "error updating node", node.Name, node.ID, " on checkin", err.Error())
 			logger.Log(0, "error updating node", node.Name, node.ID, " on checkin", err.Error())
 			return
 			return

+ 1 - 1
netclient/build/netclient.service

@@ -2,7 +2,7 @@
 Description=Netclient Daemon
 Description=Netclient Daemon
 Documentation=https://docs.netmaker.org https://k8s.netmaker.org
 Documentation=https://docs.netmaker.org https://k8s.netmaker.org
 After=network-online.target
 After=network-online.target
-Wants=network-online.target systemd-networkd-wait-online.service
+Wants=network-online.target 
 
 
 [Service]
 [Service]
 User=root
 User=root

+ 3 - 0
netclient/functions/common.go

@@ -77,6 +77,9 @@ func getPrivateAddr() (string, error) {
 	if local == "" {
 	if local == "" {
 		err = errors.New("could not find local ip")
 		err = errors.New("could not find local ip")
 	}
 	}
+	if net.ParseIP(local).To16() != nil {
+		local = "[" + local + "]"
+	}
 
 
 	return local, err
 	return local, err
 }
 }

+ 13 - 7
netclient/functions/connection.go

@@ -3,8 +3,8 @@ package functions
 import (
 import (
 	"fmt"
 	"fmt"
 
 
-	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/netclient/config"
 	"github.com/gravitl/netmaker/netclient/config"
+	"github.com/gravitl/netmaker/netclient/daemon"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/netclient/wireguard"
 	"github.com/gravitl/netmaker/netclient/wireguard"
 )
 )
@@ -24,11 +24,14 @@ func Connect(network string) error {
 	if err = wireguard.ApplyConf(&cfg.Node, cfg.Node.Interface, filePath); err != nil {
 	if err = wireguard.ApplyConf(&cfg.Node, cfg.Node.Interface, filePath); err != nil {
 		return err
 		return err
 	}
 	}
+	if err := setupMQTTSingleton(cfg); err != nil {
+		return err
+	}
 	if err := PublishNodeUpdate(cfg); err != nil {
 	if err := PublishNodeUpdate(cfg); err != nil {
-		logger.Log(0, "network:", cfg.Node.Network, "could not publish connection change, it will likely get reverted")
+		return err
 	}
 	}
-
-	return config.ModNodeConfig(&cfg.Node)
+	daemon.Restart()
+	return nil
 }
 }
 
 
 // Disconnect - attempts to disconnect a node on given network
 // Disconnect - attempts to disconnect a node on given network
@@ -46,9 +49,12 @@ func Disconnect(network string) error {
 	if err = wireguard.ApplyConf(&cfg.Node, cfg.Node.Interface, filePath); err != nil {
 	if err = wireguard.ApplyConf(&cfg.Node, cfg.Node.Interface, filePath); err != nil {
 		return err
 		return err
 	}
 	}
+	if err := setupMQTTSingleton(cfg); err != nil {
+		return err
+	}
 	if err := PublishNodeUpdate(cfg); err != nil {
 	if err := PublishNodeUpdate(cfg); err != nil {
-		logger.Log(0, "network:", cfg.Node.Network, "could not publish connection change, it will likely get reverted")
+		return err
 	}
 	}
-
-	return config.ModNodeConfig(&cfg.Node)
+	daemon.Restart()
+	return nil
 }
 }

+ 29 - 2
netclient/functions/daemon.go

@@ -87,8 +87,6 @@ func Daemon() error {
 
 
 func startGoRoutines(wg *sync.WaitGroup) context.CancelFunc {
 func startGoRoutines(wg *sync.WaitGroup) context.CancelFunc {
 	ctx, cancel := context.WithCancel(context.Background())
 	ctx, cancel := context.WithCancel(context.Background())
-	wg.Add(1)
-	go Checkin(ctx, wg)
 	serverSet := make(map[string]bool)
 	serverSet := make(map[string]bool)
 	networks, _ := ncutils.GetSystemNetworks()
 	networks, _ := ncutils.GetSystemNetworks()
 	for _, network := range networks {
 	for _, network := range networks {
@@ -116,6 +114,8 @@ func startGoRoutines(wg *sync.WaitGroup) context.CancelFunc {
 			go messageQueue(ctx, wg, &cfg)
 			go messageQueue(ctx, wg, &cfg)
 		}
 		}
 	}
 	}
+	wg.Add(1)
+	go Checkin(ctx, wg)
 	return cancel
 	return cancel
 }
 }
 
 
@@ -232,6 +232,33 @@ func NewTLSConfig(server string) (*tls.Config, error) {
 
 
 }
 }
 
 
+// func setMQTTSingenton creates a connection to broker for single use (ie to publish a message)
+// only to be called from cli (eg. connect/disconnect, join, leave) and not from daemon ---
+func setupMQTTSingleton(cfg *config.ClientConfig) error {
+	opts := mqtt.NewClientOptions()
+	server := cfg.Server.Server
+	port := cfg.Server.MQPort
+	opts.AddBroker("ssl://" + server + ":" + port)
+	tlsConfig, err := NewTLSConfig(server)
+	if err != nil {
+		logger.Log(0, "failed to get TLS config for", server, err.Error())
+		return err
+	}
+	opts.SetTLSConfig(tlsConfig)
+	mqclient = mqtt.NewClient(opts)
+	var connecterr error
+	opts.SetClientID(ncutils.MakeRandomString(23))
+	if token := mqclient.Connect(); !token.WaitTimeout(30*time.Second) || token.Error() != nil {
+		logger.Log(0, "unable to connect to broker, retrying ...")
+		if token.Error() == nil {
+			connecterr = errors.New("connect timeout")
+		} else {
+			connecterr = token.Error()
+		}
+	}
+	return connecterr
+}
+
 // setupMQTT creates a connection to broker and returns client
 // setupMQTT creates a connection to broker and returns client
 // this function is primarily used to create a connection to publish to the broker
 // this function is primarily used to create a connection to publish to the broker
 func setupMQTT(cfg *config.ClientConfig) error {
 func setupMQTT(cfg *config.ClientConfig) error {

+ 13 - 2
netclient/functions/mqpublish.go

@@ -26,13 +26,16 @@ import (
 func Checkin(ctx context.Context, wg *sync.WaitGroup) {
 func Checkin(ctx context.Context, wg *sync.WaitGroup) {
 	logger.Log(2, "starting checkin goroutine")
 	logger.Log(2, "starting checkin goroutine")
 	defer wg.Done()
 	defer wg.Done()
+	checkin()
+	ticker := time.NewTicker(time.Second * 60)
+	defer ticker.Stop()
 	for {
 	for {
 		select {
 		select {
 		case <-ctx.Done():
 		case <-ctx.Done():
 			logger.Log(0, "checkin routine closed")
 			logger.Log(0, "checkin routine closed")
 			return
 			return
 			//delay should be configuraable -> use cfg.Node.NetworkSettings.DefaultCheckInInterval ??
 			//delay should be configuraable -> use cfg.Node.NetworkSettings.DefaultCheckInInterval ??
-		case <-time.After(time.Second * 60):
+		case <-ticker.C:
 			checkin()
 			checkin()
 		}
 		}
 	}
 	}
@@ -123,7 +126,15 @@ func PublishNodeUpdate(nodeCfg *config.ClientConfig) error {
 
 
 // Hello -- ping the broker to let server know node it's alive and well
 // Hello -- ping the broker to let server know node it's alive and well
 func Hello(nodeCfg *config.ClientConfig) {
 func Hello(nodeCfg *config.ClientConfig) {
-	if err := publish(nodeCfg, fmt.Sprintf("ping/%s", nodeCfg.Node.ID), []byte(ncutils.Version), 0); err != nil {
+	var checkin models.NodeCheckin
+	checkin.Version = ncutils.Version
+	checkin.Connected = nodeCfg.Node.Connected
+	data, err := json.Marshal(checkin)
+	if err != nil {
+		logger.Log(0, "unable to marshal checkin data", err.Error())
+		return
+	}
+	if err := publish(nodeCfg, fmt.Sprintf("ping/%s", nodeCfg.Node.ID), data, 0); err != nil {
 		logger.Log(0, fmt.Sprintf("Network: %s error publishing ping, %v", nodeCfg.Node.Network, err))
 		logger.Log(0, fmt.Sprintf("Network: %s error publishing ping, %v", nodeCfg.Node.Network, err))
 		logger.Log(0, "running pull on "+nodeCfg.Node.Network+" to reconnect")
 		logger.Log(0, "running pull on "+nodeCfg.Node.Network+" to reconnect")
 		_, err := Pull(nodeCfg.Node.Network, true)
 		_, err := Pull(nodeCfg.Node.Network, true)

+ 4 - 0
netclient/ncutils/netclientutils.go

@@ -437,6 +437,10 @@ func Copy(src, dst string) error {
 func RunCmds(commands []string, printerr bool) error {
 func RunCmds(commands []string, printerr bool) error {
 	var err error
 	var err error
 	for _, command := range commands {
 	for _, command := range commands {
+		//prevent panic
+		if len(strings.Trim(command, " ")) == 0 {
+			continue
+		}
 		args := strings.Fields(command)
 		args := strings.Fields(command)
 		out, err := exec.Command(args[0], args[1:]...).CombinedOutput()
 		out, err := exec.Command(args[0], args[1:]...).CombinedOutput()
 		if err != nil && printerr {
 		if err != nil && printerr {

+ 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.15.1.0"
+            version="0.15.2.0"
             processorArchitecture="*"
             processorArchitecture="*"
             name="netclient.exe"
             name="netclient.exe"
             type="win32"
             type="win32"

+ 4 - 4
netclient/versioninfo.json

@@ -3,13 +3,13 @@
         "FileVersion": {
         "FileVersion": {
             "Major": 0,
             "Major": 0,
             "Minor": 15,
             "Minor": 15,
-            "Patch": 1,
+            "Patch": 2,
             "Build": 0
             "Build": 0
         },
         },
         "ProductVersion": {
         "ProductVersion": {
             "Major": 0,
             "Major": 0,
             "Minor": 15,
             "Minor": 15,
-            "Patch": 1,
+            "Patch": 2,
             "Build": 0
             "Build": 0
         },
         },
         "FileFlagsMask": "3f",
         "FileFlagsMask": "3f",
@@ -29,7 +29,7 @@
         "OriginalFilename": "",
         "OriginalFilename": "",
         "PrivateBuild": "",
         "PrivateBuild": "",
         "ProductName": "Netclient",
         "ProductName": "Netclient",
-        "ProductVersion": "v0.15.1.0",
+        "ProductVersion": "v0.15.2.0",
         "SpecialBuild": ""
         "SpecialBuild": ""
     },
     },
     "VarFileInfo": {
     "VarFileInfo": {
@@ -40,4 +40,4 @@
     },
     },
     "IconPath": "windowsdata/resource/netclient.ico",
     "IconPath": "windowsdata/resource/netclient.ico",
     "ManifestPath": "netclient.exe.manifest.xml"
     "ManifestPath": "netclient.exe.manifest.xml"
-}
+}

+ 19 - 10
netclient/wireguard/common.go

@@ -335,22 +335,31 @@ func WriteWgConfig(node *models.Node, privateKey string, peers []wgtypes.PeerCon
 	//	wireguard.Section(section_interface).Key("DNS").SetValue(cfg.Server.CoreDNSAddr)
 	//	wireguard.Section(section_interface).Key("DNS").SetValue(cfg.Server.CoreDNSAddr)
 	//}
 	//}
 	//need to split postup/postdown because ini lib adds a ` and the ` breaks freebsd
 	//need to split postup/postdown because ini lib adds a ` and the ` breaks freebsd
+	//works fine on others
 	if node.PostUp != "" {
 	if node.PostUp != "" {
-		parts := strings.Split(node.PostUp, " ; ")
-		for i, part := range parts {
-			if i == 0 {
-				wireguard.Section(section_interface).Key("PostUp").SetValue(part)
+		if node.OS == "freebsd" {
+			parts := strings.Split(node.PostUp, " ; ")
+			for i, part := range parts {
+				if i == 0 {
+					wireguard.Section(section_interface).Key("PostUp").SetValue(part)
+				}
+				wireguard.Section(section_interface).Key("PostUp").AddShadow(part)
 			}
 			}
-			wireguard.Section(section_interface).Key("PostUp").AddShadow(part)
+		} else {
+			wireguard.Section(section_interface).Key("PostUp").SetValue((node.PostUp))
 		}
 		}
 	}
 	}
 	if node.PostDown != "" {
 	if node.PostDown != "" {
-		parts := strings.Split(node.PostDown, " ; ")
-		for i, part := range parts {
-			if i == 0 {
-				wireguard.Section(section_interface).Key("PostDown").SetValue(part)
+		if node.OS == "freebsd" {
+			parts := strings.Split(node.PostDown, " ; ")
+			for i, part := range parts {
+				if i == 0 {
+					wireguard.Section(section_interface).Key("PostDown").SetValue(part)
+				}
+				wireguard.Section(section_interface).Key("PostDown").AddShadow(part)
 			}
 			}
-			wireguard.Section(section_interface).Key("PostDown").AddShadow(part)
+		} else {
+			wireguard.Section(section_interface).Key("PostUp").SetValue((node.PostUp))
 		}
 		}
 	}
 	}
 	if node.MTU != 0 {
 	if node.MTU != 0 {

+ 2 - 4
netclient/wireguard/mac.go

@@ -19,8 +19,7 @@ func WgQuickDownMac(node *models.Node, iface string) error {
 		return err
 		return err
 	}
 	}
 	if node.PostDown != "" {
 	if node.PostDown != "" {
-		runcmds := strings.Split(node.PostDown, "; ")
-		ncutils.RunCmds(runcmds, true)
+		ncutils.RunCmd(node.PostDown, true)
 	}
 	}
 	return nil
 	return nil
 }
 }
@@ -85,8 +84,7 @@ func WgQuickUpMac(node *models.Node, iface string, confPath string) error {
 	//next, wg-quick runs monitor_daemon
 	//next, wg-quick runs monitor_daemon
 	time.Sleep(time.Second / 2)
 	time.Sleep(time.Second / 2)
 	if node.PostUp != "" {
 	if node.PostUp != "" {
-		runcmds := strings.Split(node.PostUp, "; ")
-		ncutils.RunCmds(runcmds, true)
+		ncutils.RunCmd(node.PostUp, true)
 	}
 	}
 	return err
 	return err
 }
 }

+ 3 - 6
netclient/wireguard/noquick.go

@@ -99,8 +99,7 @@ func ApplyWithoutWGQuick(node *models.Node, ifacename, confPath string, isConnec
 		return err
 		return err
 	}
 	}
 	if node.PostDown != "" {
 	if node.PostDown != "" {
-		runcmds := strings.Split(node.PostDown, "; ")
-		_ = ncutils.RunCmds(runcmds, false)
+		ncutils.RunCmd(node.PostDown, false)
 	}
 	}
 	// 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 {
@@ -108,8 +107,7 @@ func ApplyWithoutWGQuick(node *models.Node, ifacename, confPath string, isConnec
 		return err
 		return err
 	}
 	}
 	if node.PostUp != "" {
 	if node.PostUp != "" {
-		runcmds := strings.Split(node.PostUp, "; ")
-		_ = ncutils.RunCmds(runcmds, true)
+		ncutils.RunCmd(node.PostUp, false)
 	}
 	}
 	if node.Address6 != "" {
 	if node.Address6 != "" {
 		logger.Log(1, "adding address: ", node.Address6)
 		logger.Log(1, "adding address: ", node.Address6)
@@ -139,8 +137,7 @@ func RemoveWithoutWGQuick(ifacename string) error {
 	nodeconf, err := config.ReadConfig(network)
 	nodeconf, err := config.ReadConfig(network)
 	if nodeconf != nil && err == nil {
 	if nodeconf != nil && err == nil {
 		if nodeconf.Node.PostDown != "" {
 		if nodeconf.Node.PostDown != "" {
-			runcmds := strings.Split(nodeconf.Node.PostDown, "; ")
-			_ = ncutils.RunCmds(runcmds, false)
+			ncutils.RunCmd(nodeconf.Node.PostDown, false)
 		}
 		}
 	} else if err != nil {
 	} else if err != nil {
 		logger.Log(1, "error retrieving config: ", err.Error())
 		logger.Log(1, "error retrieving config: ", err.Error())

+ 7 - 4
scripts/nm-quick.sh

@@ -230,7 +230,7 @@ echo "Netmaker setup is now complete. You are ready to begin using Netmaker."
 setup_vpn() {( set -e
 setup_vpn() {( set -e
 echo "creating vpn network (10.201.0.0/16)"
 echo "creating vpn network (10.201.0.0/16)"
 
 
-curl -s -o /dev/null -d '{"addressrange":"10.201.0.0/16","netid":"vpn","defaultextclientdns":"8.8.8.8"}' -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' https://api.${NETMAKER_BASE_DOMAIN}/api/networks
+curl -s -o /dev/null -d '{"addressrange":"10.201.0.0/16","netid":"vpn","defaultextclientdns":"10.201.255.254"}' -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' https://api.${NETMAKER_BASE_DOMAIN}/api/networks
 
 
 sleep 5
 sleep 5
 
 
@@ -241,9 +241,9 @@ SERVER_ID=$(jq -r '.[0].id' <<< ${curlresponse})
 
 
 curl -s -o /dev/null -X POST -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' https://api.${NETMAKER_BASE_DOMAIN}/api/nodes/vpn/$SERVER_ID/createingress
 curl -s -o /dev/null -X POST -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' https://api.${NETMAKER_BASE_DOMAIN}/api/nodes/vpn/$SERVER_ID/createingress
 
 
-echo "waiting 10 seconds for server to apply configuration..."
+echo "waiting 5 seconds for server to apply configuration..."
 
 
-sleep 10
+sleep 5
 
 
 
 
 echo "configuring netmaker server vpn gateway..."
 echo "configuring netmaker server vpn gateway..."
@@ -257,11 +257,13 @@ SERVER_ID=$(jq -r '.[0].id' <<< ${curlresponse})
 
 
 EGRESS_JSON=$( jq -n \
 EGRESS_JSON=$( jq -n \
                   --arg gw "$GATEWAY_IFACE" \
                   --arg gw "$GATEWAY_IFACE" \
-                  '{ranges: ["0.0.0.0/0","::/0"], interface: $gw}' )
+                  '{ranges: ["0.0.0.0/0"], interface: $gw}' )
 
 
 echo "egress json: $EGRESS_JSON"
 echo "egress json: $EGRESS_JSON"
 curl -s -o /dev/null -X POST -d "$EGRESS_JSON" -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' https://api.${NETMAKER_BASE_DOMAIN}/api/nodes/vpn/$SERVER_ID/creategateway
 curl -s -o /dev/null -X POST -d "$EGRESS_JSON" -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' https://api.${NETMAKER_BASE_DOMAIN}/api/nodes/vpn/$SERVER_ID/creategateway
 
 
+sleep 3
+
 echo "creating client configs..."
 echo "creating client configs..."
 
 
 for ((a=1; a <= $NUM_CLIENTS; a++))
 for ((a=1; a <= $NUM_CLIENTS; a++))
@@ -271,6 +273,7 @@ do
                   '{clientid: $clientid}' )
                   '{clientid: $clientid}' )
 
 
         curl -s -o /dev/null -d "$CLIENT_JSON" -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' https://api.${NETMAKER_BASE_DOMAIN}/api/extclients/vpn/$SERVER_ID
         curl -s -o /dev/null -d "$CLIENT_JSON" -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' https://api.${NETMAKER_BASE_DOMAIN}/api/extclients/vpn/$SERVER_ID
+        sleep 2
 done
 done
 
 
 echo "finished configuring vpn server."
 echo "finished configuring vpn server."

File diff suppressed because it is too large
+ 911 - 13
swagger.yaml


Some files were not shown because too many files changed in this diff