ソースを参照

resolve merge conflicts

abhishek9686 11 ヶ月 前
コミット
0f0b5d624a

+ 1 - 2
controllers/middleware.go

@@ -2,7 +2,6 @@ package controller
 
 import (
 	"net/http"
-	"net/url"
 	"strings"
 
 	"github.com/gorilla/mux"
@@ -96,7 +95,7 @@ func userMiddleWare(handler http.Handler) http.Handler {
 		if userID, ok := params["username"]; ok {
 			r.Header.Set("TARGET_RSRC_ID", userID)
 		} else {
-			username, _ := url.QueryUnescape(r.URL.Query().Get("username"))
+			username := r.URL.Query().Get("username")
 			if username != "" {
 				r.Header.Set("TARGET_RSRC_ID", username)
 			}

+ 44 - 0
controllers/network.go

@@ -24,6 +24,8 @@ import (
 func networkHandlers(r *mux.Router) {
 	r.HandleFunc("/api/networks", logic.SecurityCheck(true, http.HandlerFunc(getNetworks))).
 		Methods(http.MethodGet)
+	r.HandleFunc("/api/v1/networks/stats", logic.SecurityCheck(true, http.HandlerFunc(getNetworksStats))).
+		Methods(http.MethodGet)
 	r.HandleFunc("/api/networks", logic.SecurityCheck(true, checkFreeTierLimits(limitChoiceNetworks, http.HandlerFunc(createNetwork)))).
 		Methods(http.MethodPost)
 	r.HandleFunc("/api/networks/{networkname}", logic.SecurityCheck(true, http.HandlerFunc(getNetwork))).
@@ -74,6 +76,48 @@ func getNetworks(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(allnetworks)
 }
 
+// @Summary     Lists all networks with stats
+// @Router      /api/v1/networks/stats [get]
+// @Tags        Networks
+// @Security    oauth
+// @Produce     json
+// @Success     200 {object} models.SuccessResponse
+// @Failure     500 {object} models.ErrorResponse
+func getNetworksStats(w http.ResponseWriter, r *http.Request) {
+
+	var err error
+	allnetworks, err := logic.GetNetworks()
+	if err != nil && !database.IsEmptyRecord(err) {
+		slog.Error("failed to fetch networks", "error", err.Error())
+		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
+		return
+	}
+	if r.Header.Get("ismaster") != "yes" {
+		username := r.Header.Get("user")
+		user, err := logic.GetUser(username)
+		if err != nil {
+			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
+			return
+		}
+		allnetworks = logic.FilterNetworksByRole(allnetworks, *user)
+	}
+	allNodes, err := logic.GetAllNodes()
+	if err != nil {
+		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
+		return
+	}
+	netstats := []models.NetworkStatResp{}
+	logic.SortNetworks(allnetworks[:])
+	for _, network := range allnetworks {
+		netstats = append(netstats, models.NetworkStatResp{
+			Network: network,
+			Hosts:   len(logic.GetNetworkNodesMemory(allNodes, network.NetID)),
+		})
+	}
+	logger.Log(2, r.Header.Get("user"), "fetched networks.")
+	logic.ReturnSuccessResponseWithJson(w, r, netstats, "fetched networks with stats")
+}
+
 // @Summary     Get a network
 // @Router      /api/networks/{networkname} [get]
 // @Tags        Networks

+ 1 - 2
controllers/user.go

@@ -5,7 +5,6 @@ import (
 	"errors"
 	"fmt"
 	"net/http"
-	"net/url"
 	"reflect"
 
 	"github.com/gorilla/mux"
@@ -240,7 +239,7 @@ func getUser(w http.ResponseWriter, r *http.Request) {
 func getUserV1(w http.ResponseWriter, r *http.Request) {
 	// set header.
 	w.Header().Set("Content-Type", "application/json")
-	usernameFetched, _ := url.QueryUnescape(r.URL.Query().Get("username"))
+	usernameFetched := r.URL.Query().Get("username")
 	if usernameFetched == "" {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("username is required"), "badrequest"))
 		return

+ 1 - 1
go.mod

@@ -3,7 +3,7 @@ module github.com/gravitl/netmaker
 go 1.23
 
 require (
-	github.com/eclipse/paho.mqtt.golang v1.5.0
+	github.com/eclipse/paho.mqtt.golang v1.4.3
 	github.com/go-playground/validator/v10 v10.22.0
 	github.com/golang-jwt/jwt/v4 v4.5.0
 	github.com/google/uuid v1.6.0

+ 2 - 2
go.sum

@@ -10,8 +10,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/eclipse/paho.mqtt.golang v1.5.0 h1:EH+bUVJNgttidWFkLLVKaQPGmkTUfQQqjOsyvMGvD6o=
-github.com/eclipse/paho.mqtt.golang v1.5.0/go.mod h1:du/2qNQVqJf/Sqs4MEL77kR8QTqANF7XU7Fk0aOTAgk=
+github.com/eclipse/paho.mqtt.golang v1.4.3 h1:2kwcUGn8seMUfWndX0hGbvH8r7crgcJguQNCyp70xik=
+github.com/eclipse/paho.mqtt.golang v1.4.3/go.mod h1:CSYvoAlsMkhYOXh/oKyxa8EcBci6dVkLCbo5tTC1RIE=
 github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
 github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
 github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=

+ 9 - 5
logic/nodes.go

@@ -393,7 +393,7 @@ func GetNetworkByNode(node *models.Node) (models.Network, error) {
 }
 
 // SetNodeDefaults - sets the defaults of a node to avoid empty fields
-func SetNodeDefaults(node *models.Node) {
+func SetNodeDefaults(node *models.Node, resetConnected bool) {
 
 	parentNetwork, _ := GetNetworkByNode(node)
 	_, cidr, err := net.ParseCIDR(parentNetwork.AddressRange)
@@ -413,8 +413,12 @@ func SetNodeDefaults(node *models.Node) {
 	}
 
 	node.SetLastModified()
-	node.SetLastCheckIn()
-	node.SetDefaultConnected()
+	if node.LastCheckIn.IsZero() {
+		node.SetLastCheckIn()
+	}
+	if resetConnected {
+		node.SetDefaultConnected()
+	}
 	node.SetExpirationDateTime()
 }
 
@@ -461,7 +465,7 @@ func GetDeletedNodeByID(uuid string) (models.Node, error) {
 		return models.Node{}, err
 	}
 
-	SetNodeDefaults(&node)
+	SetNodeDefaults(&node, true)
 
 	return node, nil
 }
@@ -531,7 +535,7 @@ func createNode(node *models.Node) error {
 		}
 	}
 
-	SetNodeDefaults(node)
+	SetNodeDefaults(node, true)
 
 	defaultACLVal := acls.Allowed
 	parentNetwork, err := GetNetwork(node.Network)

+ 1 - 2
logic/security.go

@@ -2,7 +2,6 @@ package logic
 
 import (
 	"net/http"
-	"net/url"
 	"strings"
 
 	"github.com/gorilla/mux"
@@ -97,7 +96,7 @@ func ContinueIfUserMatch(next http.Handler) http.HandlerFunc {
 		var params = mux.Vars(r)
 		var requestedUser = params["username"]
 		if requestedUser == "" {
-			requestedUser, _ = url.QueryUnescape(r.URL.Query().Get("username"))
+			requestedUser = r.URL.Query().Get("username")
 		}
 		if requestedUser != r.Header.Get("user") {
 			ReturnErrorResponse(w, r, errorResponse)

+ 16 - 1
migrate/migrate.go

@@ -21,11 +21,11 @@ import (
 func Run() {
 	updateEnrollmentKeys()
 	assignSuperAdmin()
+	removeOldUserGrps()
 	syncUsers()
 	updateHosts()
 	updateNodes()
 	updateAcls()
-
 }
 
 func assignSuperAdmin() {
@@ -124,6 +124,20 @@ func updateEnrollmentKeys() {
 	}
 }
 
+func removeOldUserGrps() {
+	rows, err := database.FetchRecords(database.USER_GROUPS_TABLE_NAME)
+	if err != nil {
+		return
+	}
+	for key, row := range rows {
+		userG := models.UserGroup{}
+		_ = json.Unmarshal([]byte(row), &userG)
+		if userG.ID == "" {
+			database.DeleteRecord(database.USER_GROUPS_TABLE_NAME, key)
+		}
+	}
+}
+
 func updateHosts() {
 	rows, err := database.FetchRecords(database.HOSTS_TABLE_NAME)
 	if err != nil {
@@ -319,6 +333,7 @@ func syncUsers() {
 		nodes, err := logic.GetAllNodes()
 		if err == nil {
 			for _, netI := range networks {
+				logic.CreateDefaultNetworkRolesAndGroups(models.NetworkID(netI.NetID))
 				networkNodes := logic.GetNetworkNodesMemory(nodes, netI.NetID)
 				for _, networkNodeI := range networkNodes {
 					if networkNodeI.IsIngressGateway {

+ 5 - 0
models/network.go

@@ -97,3 +97,8 @@ func (network *Network) GetNetworkNetworkCIDR6() *net.IPNet {
 	_, netCidr, _ := net.ParseCIDR(network.AddressRange6)
 	return netCidr
 }
+
+type NetworkStatResp struct {
+	Network
+	Hosts int `json:"hosts"`
+}

+ 12 - 12
pro/controllers/users.go

@@ -72,8 +72,8 @@ func UserHandlers(r *mux.Router) {
 //	Responses:
 //		200: ReturnSuccessResponse
 func userInviteSignUp(w http.ResponseWriter, r *http.Request) {
-	email, _ := url.QueryUnescape(r.URL.Query().Get("email"))
-	code, _ := url.QueryUnescape(r.URL.Query().Get("invite_code"))
+	email := r.URL.Query().Get("email")
+	code := r.URL.Query().Get("invite_code")
 	in, err := logic.GetUserInvite(email)
 	if err != nil {
 		logger.Log(0, "failed to fetch users: ", err.Error())
@@ -134,8 +134,8 @@ func userInviteSignUp(w http.ResponseWriter, r *http.Request) {
 //	Responses:
 //		200: ReturnSuccessResponse
 func userInviteVerify(w http.ResponseWriter, r *http.Request) {
-	email, _ := url.QueryUnescape(r.URL.Query().Get("email"))
-	code, _ := url.QueryUnescape(r.URL.Query().Get("invite_code"))
+	email := r.URL.Query().Get("email")
+	code := r.URL.Query().Get("invite_code")
 	err := logic.ValidateAndApproveUserInvite(email, code)
 	if err != nil {
 		logger.Log(0, "failed to fetch users: ", err.Error())
@@ -299,7 +299,7 @@ func listUserInvites(w http.ResponseWriter, r *http.Request) {
 //			Responses:
 //				200: ReturnSuccessResponse
 func deleteUserInvite(w http.ResponseWriter, r *http.Request) {
-	email, _ := url.QueryUnescape(r.URL.Query().Get("invitee_email"))
+	email := r.URL.Query().Get("invitee_email")
 	err := logic.DeleteUserInvite(email)
 	if err != nil {
 		logger.Log(0, "failed to delete user invite: ", email, err.Error())
@@ -365,7 +365,7 @@ func listUserGroups(w http.ResponseWriter, r *http.Request) {
 //				200: userBodyResponse
 func getUserGroup(w http.ResponseWriter, r *http.Request) {
 
-	gid, _ := url.QueryUnescape(r.URL.Query().Get("group_id"))
+	gid := r.URL.Query().Get("group_id")
 	if gid == "" {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("group id is required"), "badrequest"))
 		return
@@ -486,14 +486,14 @@ func updateUserGroup(w http.ResponseWriter, r *http.Request) {
 // @Failure     500 {object} models.ErrorResponse
 func deleteUserGroup(w http.ResponseWriter, r *http.Request) {
 
-	gid, _ := url.QueryUnescape(r.URL.Query().Get("group_id"))
+	gid := r.URL.Query().Get("group_id")
 	if gid == "" {
-		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("role is required"), "badrequest"))
+		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("group id is required"), "badrequest"))
 		return
 	}
 	userG, err := proLogic.GetUserGroup(models.UserGroupID(gid))
 	if err != nil {
-		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("role is required"), "badrequest"))
+		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("failed to fetch group details"), "badrequest"))
 		return
 	}
 	err = proLogic.DeleteUserGroup(models.UserGroupID(gid))
@@ -512,7 +512,7 @@ func deleteUserGroup(w http.ResponseWriter, r *http.Request) {
 // @Success     200 {object}  []models.UserRolePermissionTemplate
 // @Failure     500 {object} models.ErrorResponse
 func ListRoles(w http.ResponseWriter, r *http.Request) {
-	platform, _ := url.QueryUnescape(r.URL.Query().Get("platform"))
+	platform := r.URL.Query().Get("platform")
 	var roles []models.UserRolePermissionTemplate
 	var err error
 	if platform == "true" {
@@ -538,7 +538,7 @@ func ListRoles(w http.ResponseWriter, r *http.Request) {
 // @Success     200 {object} models.UserRolePermissionTemplate
 // @Failure     500 {object} models.ErrorResponse
 func getRole(w http.ResponseWriter, r *http.Request) {
-	rid, _ := url.QueryUnescape(r.URL.Query().Get("role_id"))
+	rid := r.URL.Query().Get("role_id")
 	if rid == "" {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("role is required"), "badrequest"))
 		return
@@ -628,7 +628,7 @@ func updateRole(w http.ResponseWriter, r *http.Request) {
 // @Failure     500 {object} models.ErrorResponse
 func deleteRole(w http.ResponseWriter, r *http.Request) {
 
-	rid, _ := url.QueryUnescape(r.URL.Query().Get("role_id"))
+	rid := r.URL.Query().Get("role_id")
 	if rid == "" {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("role is required"), "badrequest"))
 		return

+ 44 - 5
pro/email/invite.go

@@ -2,6 +2,7 @@ package email
 
 import (
 	"fmt"
+	"github.com/gravitl/netmaker/servercfg"
 )
 
 // UserInvitedMail - mail for users that are invited to a tenant
@@ -12,16 +13,54 @@ type UserInvitedMail struct {
 
 // GetSubject - gets the subject of the email
 func (UserInvitedMail) GetSubject(info Notification) string {
-	return "Netmaker: Pending Invitation"
+	return "You're invited to join Netmaker"
 }
 
 // GetBody - gets the body of the email
 func (invite UserInvitedMail) GetBody(info Notification) string {
+	if servercfg.DeployedByOperator() {
+		return invite.BodyBuilder.
+			WithParagraph("Hi there,").
+			WithParagraph("<br>").
+			WithParagraph("Great news! Your colleague has invited you to join their Netmaker SaaS Tenant.").
+			WithParagraph("Click the button to accept your invitation:").
+			WithParagraph("<br>").
+			WithParagraph(fmt.Sprintf("<a class=\"x-button\" href=\"%s\">Accept Invitation</a>", invite.InviteURL)).
+			WithParagraph("<br>").
+			WithParagraph("Why you'll love Netmaker:").
+			WithParagraph("<ul>").
+			WithParagraph("<li>Blazing-fast connections with our WireGuard®-powered mesh VPN</li>").
+			WithParagraph("<li>Seamless multi-cloud and hybrid-cloud networking</li>").
+			WithParagraph("<li>Automated Kubernetes networking across any infrastructure</li>").
+			WithParagraph("<li>Enterprise-grade security with simple management</li>").
+			WithParagraph("</ul>").
+			WithParagraph("Got questions? Our team is here to help you every step of the way.").
+			WithParagraph("<br>").
+			WithParagraph("Welcome aboard,").
+			WithParagraph("<h2>The Netmaker Team</h2>").
+			WithParagraph("P.S. Curious to learn more before accepting? Check out our quick start tutorial at <a href=\"https://netmaker.io/tutorials\">netmaker.io/tutorials</a>").
+			Build()
+	}
 
 	return invite.BodyBuilder.
-		WithHeadline("Join Netmaker from this invite!").
-		WithParagraph("Hello from Netmaker,").
-		WithParagraph("You have been invited to join Netmaker.").
-		WithParagraph(fmt.Sprintf("Join Using This Invite Link <a href=\"%s\">Netmaker</a>", invite.InviteURL)).
+		WithParagraph("Hi there,").
+		WithParagraph("<br>").
+		WithParagraph("Great news! Your colleague has invited you to join their Netmaker network.").
+		WithParagraph("Click the button to accept your invitation:").
+		WithParagraph("<br>").
+		WithParagraph(fmt.Sprintf("<a class=\"x-button\" href=\"%s\">Accept Invitation</a>", invite.InviteURL)).
+		WithParagraph("<br>").
+		WithParagraph("Why you'll love Netmaker:").
+		WithParagraph("<ul>").
+		WithParagraph("<li>Blazing-fast connections with our WireGuard®-powered mesh VPN</li>").
+		WithParagraph("<li>Seamless multi-cloud and hybrid-cloud networking</li>").
+		WithParagraph("<li>Automated Kubernetes networking across any infrastructure</li>").
+		WithParagraph("<li>Enterprise-grade security with simple management</li>").
+		WithParagraph("</ul>").
+		WithParagraph("Got questions? Our team is here to help you every step of the way.").
+		WithParagraph("<br>").
+		WithParagraph("Welcome aboard,").
+		WithParagraph("<h2>The Netmaker Team</h2>").
+		WithParagraph("P.S. Curious to learn more before accepting? Check out our quick start tutorial at <a href=\"https://netmaker.io/tutorials\">netmaker.io/tutorials</a>").
 		Build()
 }

+ 1 - 1
pro/email/utils.go

@@ -73,7 +73,7 @@ func (b *EmailBodyBuilderWithH1HeadlineAndImage) Build() string {
 		    </xml>
 		    <![endif]-->
 		    <style>
-		        *{box-sizing:border-box}body{margin:0;padding:0}a[x-apple-data-detectors]{color:inherit!important;text-decoration:inherit!important}#MessageViewBody a{color:inherit;text-decoration:none}p{line-height:inherit}.desktop_hide,.desktop_hide table{mso-hide:all;display:none;max-height:0;overflow:hidden}@media (max-width:720px){.desktop_hide table.icons-inner{display:inline-block!important}.icons-inner{text-align:center}.icons-inner td{margin:0 auto}.image_block img.big,.row-content{width:100%!important}.mobile_hide{display:none}.stack .column{width:100%;display:block}.mobile_hide{min-height:0;max-height:0;max-width:0;overflow:hidden;font-size:0}.desktop_hide,.desktop_hide table{display:table!important;max-height:none!important}}
+		        *{box-sizing:border-box}body{margin:0;padding:0}a[x-apple-data-detectors]{color:inherit!important;text-decoration:inherit!important}#MessageViewBody a{color:inherit;text-decoration:none}p{line-height:inherit}.desktop_hide,.desktop_hide table{mso-hide:all;display:none;max-height:0;overflow:hidden}@media (max-width:720px){.desktop_hide table.icons-inner{display:inline-block!important}.icons-inner{text-align:center}.icons-inner td{margin:0 auto}.image_block img.big,.row-content{width:100%!important}.mobile_hide{display:none}.stack .column{width:100%;display:block}.mobile_hide{min-height:0;max-height:0;max-width:0;overflow:hidden;font-size:0}.desktop_hide,.desktop_hide table{display:table!important;max-height:none!important}} .x-button{background:#5E5DF0;border-radius:999px;box-shadow:#5E5DF0 0 10px 20px -10px;box-sizing:border-box;color:#FFFFFF !important;cursor:pointer;font-family:Inter,Helvetica,"Apple Color Emoji","Segoe UI Emoji",NotoColorEmoji,"Noto Color Emoji","Segoe UI Symbol","Android Emoji",EmojiSymbols,-apple-system,system-ui,"Segoe UI",Roboto,"Helvetica Neue","Noto Sans",sans-serif;font-size:16px;font-weight:700;line-height:24px;opacity:1;outline:0 solid transparent;padding:8px 18px;user-select:none;-webkit-user-select:none;touch-action:manipulation;width:fit-content;word-break:break-word;border:0;margin:20px 20px 20px 0px;text-decoration:none;}
 		    </style>
 		</head>
 		<body style="background-color:transparent;margin:0;padding:0;-webkit-text-size-adjust:none;text-size-adjust:none">

+ 5 - 2
pro/logic/user_mgmt.go

@@ -75,6 +75,9 @@ func UserRolesInit() {
 }
 
 func CreateDefaultNetworkRolesAndGroups(netID models.NetworkID) {
+	if netID.String() == "" {
+		return
+	}
 	var NetworkAdminPermissionTemplate = models.UserRolePermissionTemplate{
 		ID:                 models.UserRoleID(fmt.Sprintf("%s-%s", netID, models.NetworkAdmin)),
 		Default:            true,
@@ -120,7 +123,7 @@ func CreateDefaultNetworkRolesAndGroups(netID models.NetworkID) {
 				models.UserRoleID(fmt.Sprintf("%s-%s", netID, models.NetworkAdmin)): {},
 			},
 		},
-		MetaData: "The network role was automatically created by Netmaker.",
+		MetaData: "The network group was automatically created by Netmaker.",
 	}
 	var NetworkUserGroup = models.UserGroup{
 		ID: models.UserGroupID(fmt.Sprintf("%s-%s-grp", netID, models.NetworkUser)),
@@ -129,7 +132,7 @@ func CreateDefaultNetworkRolesAndGroups(netID models.NetworkID) {
 				models.UserRoleID(fmt.Sprintf("%s-%s", netID, models.NetworkUser)): {},
 			},
 		},
-		MetaData: "The network role was automatically created by Netmaker.",
+		MetaData: "The network group was automatically created by Netmaker.",
 	}
 	d, _ = json.Marshal(NetworkAdminGroup)
 	database.Insert(NetworkAdminGroup.ID.String(), string(d), database.USER_GROUPS_TABLE_NAME)

+ 3 - 4
scripts/nm-quick.sh

@@ -738,17 +738,16 @@ setup_mesh() {
 
 	# add a network if none present
 	if [ "$networkCount" -lt 1 ]; then
-		echo "Creating netmaker network (10.101.0.0/16)"
-
+		echo "Creating netmaker network (100.64.0.0/16)"
 		# TODO causes "Error Status: 400 Response: {"Code":400,"Message":"could not find any records"}"
-		nmctl network create --name netmaker --ipv4_addr 100.172.188.0/24
+		nmctl network create --name netmaker --ipv4_addr 100.64.0.0/16
 
 		wait_seconds 5
 	fi
 
 	echo "Obtaining a netmaker enrollment key..."
 	local netmakerTag=$(nmctl enrollment_key list | jq -r '.[] | .tags[0]')
-	if [ ${netmakerTag} = "netmaker" ]; then
+	if [[ ${netmakerTag} = "netmaker" ]]; then
 		# key exists already, fetch token
 		TOKEN=$(nmctl enrollment_key list | jq -r '.[] | select(.tags[0]=="netmaker") | .token')
 	else

+ 1 - 1
serverctl/serverctl.go

@@ -40,7 +40,7 @@ func setNodeDefaults() error {
 		return err
 	}
 	for i := range nodes {
-		logic.SetNodeDefaults(&nodes[i])
+		logic.SetNodeDefaults(&nodes[i], false)
 		logic.UpdateNode(&nodes[i], &nodes[i])
 		currentNodeACL, err := nodeacls.FetchNodeACL(nodeacls.NetworkID(nodes[i].Network), nodeacls.NodeID(nodes[i].ID.String()))
 		if (err != nil && (database.IsEmptyRecord(err) || strings.Contains(err.Error(), "no node ACL present"))) || currentNodeACL == nil {