Browse Source

New Docs (#3034)

* New Docs

CSS update and Dockerfile to include docs folder

flash of unrendered text fix

markdown docs

ignore docs/docs.go

improving the docs generation

github actions for docs generation

go runner version fix

updated docs.yml

update repo action updated

updated actions and dns docs

dns complete

More docs update

Complete docs and updated workflow

Update documentation Tue Aug  6 11:17:42 UTC 2024

Update documentation Thu Aug  8 12:26:57 UTC 2024

clean up

clean up

Dockerfile clean up

Updated workflow

Updated workflow

Update docs.yml

Update docs.yml

* requested changes

* changed ingress gateway to remote access gateway
Sayan Mallick 1 year ago
parent
commit
c551c487ca

+ 50 - 0
.github/workflows/docs.yml

@@ -0,0 +1,50 @@
+name: Generate Documentation
+
+on: 
+  workflow_dispatch:
+    inputs:
+      branch:
+        description: 'Branch to run the workflow against'
+        required: true
+        default: 'master'
+
+jobs:
+  generate-docs:
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v4
+        with:
+          repository: gravitl/netmaker
+          ref: ${{ github.event.inputs.branch || 'master' }}
+
+      - name: Setup Go
+        uses: actions/setup-go@v5
+        with:
+          go-version-file: go.mod
+
+      - name: Install Swag
+        run: go install github.com/swaggo/swag/cmd/swag@latest
+
+      - name: Generating Docs
+        run: |
+          export PATH=$PATH:$(go env GOPATH)/bin
+          swag i --md docs/ --parseDependency  --parseInternal --outputTypes yaml  --parseDepth 1 --output .
+
+      - name: Get current timestamp
+        id: timestamp
+        run: echo "timestamp=$(date +'%Y-%m-%d %H:%M:%S')" >> $GITHUB_OUTPUT
+
+      - name: Create Pull Request
+        uses: peter-evans/create-pull-request@v5
+        with:
+          token: ${{ secrets.GITHUB_TOKEN }}
+          commit-message: "Update documentation ${{ steps.timestamp.outputs.timestamp }}"
+          title: "Update Swagger documentation ${{ steps.timestamp.outputs.timestamp }}"
+          body: |
+            This PR updates the swagger.yml file with the latest documentation changes.
+            
+            Updated on: ${{ steps.timestamp.outputs.timestamp }}
+          branch: update-swagger-docs-${{ github.event.inputs.branch }}
+          base: ${{ github.event.inputs.branch }}
+          delete-branch: true

+ 16 - 4
controllers/controller.go

@@ -35,7 +35,6 @@ var HttpHandlers = []interface{}{
 	legacyHandlers,
 }
 
-// HandleRESTRequests - handles the rest requests
 func HandleRESTRequests(wg *sync.WaitGroup, ctx context.Context) {
 	defer wg.Done()
 
@@ -43,9 +42,19 @@ func HandleRESTRequests(wg *sync.WaitGroup, ctx context.Context) {
 
 	// Currently allowed dev origin is all. Should change in prod
 	// should consider analyzing the allowed methods further
-	headersOk := handlers.AllowedHeaders([]string{"Access-Control-Allow-Origin", "X-Requested-With", "Content-Type", "authorization", "From-Ui"})
+	headersOk := handlers.AllowedHeaders(
+		[]string{
+			"Access-Control-Allow-Origin",
+			"X-Requested-With",
+			"Content-Type",
+			"authorization",
+			"From-Ui",
+		},
+	)
 	originsOk := handlers.AllowedOrigins(strings.Split(servercfg.GetAllowedOrigin(), ","))
-	methodsOk := handlers.AllowedMethods([]string{http.MethodGet, http.MethodPut, http.MethodPost, http.MethodDelete})
+	methodsOk := handlers.AllowedMethods(
+		[]string{http.MethodGet, http.MethodPut, http.MethodPost, http.MethodDelete},
+	)
 
 	for _, middleware := range HttpMiddlewares {
 		r.Use(middleware)
@@ -57,7 +66,10 @@ func HandleRESTRequests(wg *sync.WaitGroup, ctx context.Context) {
 
 	port := servercfg.GetAPIPort()
 
-	srv := &http.Server{Addr: ":" + port, Handler: handlers.CORS(originsOk, headersOk, methodsOk)(r)}
+	srv := &http.Server{
+		Addr:    ":" + port,
+		Handler: handlers.CORS(originsOk, headersOk, methodsOk)(r),
+	}
 	go func() {
 		err := srv.ListenAndServe()
 		if err != nil {

+ 79 - 88
controllers/dns.go

@@ -16,25 +16,29 @@ import (
 
 func dnsHandlers(r *mux.Router) {
 
-	r.HandleFunc("/api/dns", logic.SecurityCheck(true, http.HandlerFunc(getAllDNS))).Methods(http.MethodGet)
-	r.HandleFunc("/api/dns/adm/{network}/nodes", logic.SecurityCheck(true, http.HandlerFunc(getNodeDNS))).Methods(http.MethodGet)
-	r.HandleFunc("/api/dns/adm/{network}/custom", logic.SecurityCheck(true, http.HandlerFunc(getCustomDNS))).Methods(http.MethodGet)
-	r.HandleFunc("/api/dns/adm/{network}", logic.SecurityCheck(true, http.HandlerFunc(getDNS))).Methods(http.MethodGet)
-	r.HandleFunc("/api/dns/{network}", logic.SecurityCheck(true, http.HandlerFunc(createDNS))).Methods(http.MethodPost)
-	r.HandleFunc("/api/dns/adm/pushdns", logic.SecurityCheck(true, http.HandlerFunc(pushDNS))).Methods(http.MethodPost)
-	r.HandleFunc("/api/dns/{network}/{domain}", logic.SecurityCheck(true, http.HandlerFunc(deleteDNS))).Methods(http.MethodDelete)
+	r.HandleFunc("/api/dns", logic.SecurityCheck(true, http.HandlerFunc(getAllDNS))).
+		Methods(http.MethodGet)
+	r.HandleFunc("/api/dns/adm/{network}/nodes", logic.SecurityCheck(true, http.HandlerFunc(getNodeDNS))).
+		Methods(http.MethodGet)
+	r.HandleFunc("/api/dns/adm/{network}/custom", logic.SecurityCheck(true, http.HandlerFunc(getCustomDNS))).
+		Methods(http.MethodGet)
+	r.HandleFunc("/api/dns/adm/{network}", logic.SecurityCheck(true, http.HandlerFunc(getDNS))).
+		Methods(http.MethodGet)
+	r.HandleFunc("/api/dns/{network}", logic.SecurityCheck(true, http.HandlerFunc(createDNS))).
+		Methods(http.MethodPost)
+	r.HandleFunc("/api/dns/adm/pushdns", logic.SecurityCheck(true, http.HandlerFunc(pushDNS))).
+		Methods(http.MethodPost)
+	r.HandleFunc("/api/dns/{network}/{domain}", logic.SecurityCheck(true, http.HandlerFunc(deleteDNS))).
+		Methods(http.MethodDelete)
 }
 
-// swagger:route GET /api/dns/adm/{network}/nodes dns getNodeDNS
-//
-// Gets node DNS entries associated with a network.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//			Responses:
-//			200: dnsResponse
+// @Summary     Gets node DNS entries associated with a network
+// @Router      /api/dns/{network} [get]
+// @Tags        DNS
+// @Accept      json
+// @Param       network path string true "Network identifier"
+// @Success     200 {array} models.DNSEntry
+// @Failure     500 {object} models.ErrorResponse
 func getNodeDNS(w http.ResponseWriter, r *http.Request) {
 
 	w.Header().Set("Content-Type", "application/json")
@@ -53,17 +57,12 @@ func getNodeDNS(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(dns)
 }
 
-// swagger:route GET /api/dns dns getAllDNS
-//
-// Gets all DNS entries.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//	  		200: dnsResponse
+// @Summary     Get all DNS entries
+// @Router      /api/dns [get]
+// @Tags        DNS
+// @Accept      json
+// @Success     200 {array} models.DNSEntry
+// @Failure     500 {object} models.ErrorResponse
 func getAllDNS(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	dns, err := logic.GetAllDNS()
@@ -77,17 +76,13 @@ func getAllDNS(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(dns)
 }
 
-// swagger:route GET /api/dns/adm/{network}/custom dns getCustomDNS
-//
-// Gets custom DNS entries associated with a network.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//	  		200: dnsResponse
+// @Summary     Gets custom DNS entries associated with a network
+// @Router      /api/dns/adm/{network}/custom [get]
+// @Tags        DNS
+// @Accept      json
+// @Param       network path string true "Network identifier"
+// @Success     200 {array} models.DNSEntry
+// @Failure     500 {object} models.ErrorResponse
 func getCustomDNS(w http.ResponseWriter, r *http.Request) {
 
 	w.Header().Set("Content-Type", "application/json")
@@ -97,8 +92,15 @@ func getCustomDNS(w http.ResponseWriter, r *http.Request) {
 	network := params["network"]
 	dns, err := logic.GetCustomDNS(network)
 	if err != nil {
-		logger.Log(0, r.Header.Get("user"),
-			fmt.Sprintf("failed to get custom DNS entries for network [%s]: %v", network, err.Error()))
+		logger.Log(
+			0,
+			r.Header.Get("user"),
+			fmt.Sprintf(
+				"failed to get custom DNS entries for network [%s]: %v",
+				network,
+				err.Error(),
+			),
+		)
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 		return
 	}
@@ -106,17 +108,13 @@ func getCustomDNS(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(dns)
 }
 
-// swagger:route GET /api/dns/adm/{network} dns getDNS
-//
-// Gets all DNS entries associated with the network.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//	  		200: dnsResponse
+// @Summary     Get all DNS entries associated with the network
+// @Router      /api/dns/adm/{network} [get]
+// @Tags        DNS
+// @Accept      json
+// @Param       network path string true "Network identifier"
+// @Success     200 {array} models.DNSEntry
+// @Failure     500 {object} models.ErrorResponse
 func getDNS(w http.ResponseWriter, r *http.Request) {
 
 	w.Header().Set("Content-Type", "application/json")
@@ -135,17 +133,15 @@ func getDNS(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(dns)
 }
 
-// swagger:route POST /api/dns/{network} dns createDNS
-//
-// Create a DNS entry.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//	  		200: dnsResponse
+// @Summary     Create a new DNS entry
+// @Router      /api/dns/adm/{network} [post]
+// @Tags        DNS
+// @Accept      json
+// @Param       network path string true "Network identifier"
+// @Param       body body models.DNSEntry true "DNS entry details"
+// @Success     200 {object} models.DNSEntry
+// @Failure     400 {object} models.ErrorResponse
+// @Failure     500 {object} models.ErrorResponse
 func createDNS(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 
@@ -187,18 +183,14 @@ func createDNS(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(entry)
 }
 
-// swagger:route DELETE /api/dns/{network}/{domain} dns deleteDNS
-//
-// Delete a DNS entry.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: stringJSONResponse
-//				*: stringJSONResponse
+// @Summary     Delete a DNS entry
+// @Router      /api/dns/{network}/{domain} [delete]
+// @Tags        DNS
+// @Accept      json
+// @Param       network path string true "Network identifier"
+// @Param       domain path string true "Domain Name"
+// @Success     200 {array} models.DNSEntry
+// @Failure     500 {object} models.ErrorResponse
 func deleteDNS(w http.ResponseWriter, r *http.Request) {
 	// Set header
 	w.Header().Set("Content-Type", "application/json")
@@ -243,23 +235,22 @@ func GetDNSEntry(domain string, network string) (models.DNSEntry, error) {
 	return entry, err
 }
 
-// swagger:route POST /api/dns/adm/pushdns dns pushDNS
-//
-// Push DNS entries to nameserver.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//			200: dnsResponse
-//				*: dnsResponse
+// @Summary     Push DNS entries to nameserver
+// @Router      /api/dns/adm/pushdns [post]
+// @Tags        DNS
+// @Accept      json
+// @Success     200 {string} string "DNS Pushed to CoreDNS"
+// @Failure     400 {object} models.ErrorResponse
+// @Failure     500 {object} models.ErrorResponse
 func pushDNS(w http.ResponseWriter, r *http.Request) {
 	// Set header
 	w.Header().Set("Content-Type", "application/json")
 	if !servercfg.IsDNSMode() {
-		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("DNS Mode is set to off"), "badrequest"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(errors.New("DNS Mode is set to off"), "badrequest"),
+		)
 		return
 	}
 	err := logic.SetDNS()

+ 0 - 475
controllers/docs.go

@@ -1,475 +0,0 @@
-// Package classification Netmaker
-//
-// # API Usage
-//
-// Most actions that can be performed via API can be performed via UI. We recommend managing your networks using the official netmaker-ui project. However, Netmaker can also be run without the UI, and all functions can be achieved via API calls. If your use case requires using Netmaker without the UI or you need to do some troubleshooting/advanced configuration, using the API directly may help.
-//
-// # Authentication
-//
-// API calls must be authenticated via a header of the format -H “Authorization: Bearer <YOUR_SECRET_KEY>” There are two methods to obtain YOUR_SECRET_KEY: 1. Using the masterkey. By default, this value is “secret key,” but you should change this on your instance and keep it secure. This value can be set via env var at startup or in a config file (config/environments/< env >.yaml). See the [Netmaker](https://docs.netmaker.org/index.html) documentation for more details. 2. Using a JWT received for a node. This can be retrieved by calling the /api/nodes/<network>/authenticate endpoint, as documented below.
-//
-//	Schemes: https
-//	BasePath: /
-//	Version: 0.25.0
-//	Host: api.demo.netmaker.io
-//
-//	Consumes:
-//	- application/json
-//
-//	Produces:
-//	- application/json
-//
-//	Security:
-//	- oauth
-//
-// swagger:meta
-package controller
-
-import (
-	"os"
-
-	"github.com/gravitl/netmaker/config"
-	"github.com/gravitl/netmaker/logic/acls"
-	"github.com/gravitl/netmaker/models"
-)
-
-var _ = useUnused() // "use" the function to prevent "unused function" errors
-
-// swagger:parameters getFile
-type filenameToGet struct {
-	// Filename
-	// in: path
-	// required: true
-	Filename string `json:"filename"`
-}
-
-// swagger:response hasAdmin
-type hasAdmin struct {
-	// in: body
-	Admin bool
-}
-
-// swagger:response apiHostSliceResponse
-type apiHostSliceResponse struct {
-	// in: body
-	Host []models.ApiHost
-}
-
-// swagger:response apiHostResponse
-type apiHostResponse struct {
-	// in: body
-	Host models.ApiHost
-}
-
-// swagger:parameters getNodeDNS getCustomDNS getDNS
-type dnsNetworkPathParam 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:response EnrollmentKey
-type EnrollmentKey struct {
-	// in: body
-	EnrollmentKey models.EnrollmentKey
-}
-
-//swagger:response EnrollmentKeys
-type EnrollmentKeys struct {
-	// in: body
-	EnrollmentKeys []models.EnrollmentKey
-}
-
-// 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 fileResponse
-type fileResponse struct {
-	// in: body
-	File os.File
-}
-
-// swagger:response successResponse
-type successResponse struct {
-	// Success Response
-	// in: body
-	SuccessResponse models.SuccessResponse `json:"success_response"`
-}
-
-// swagger:parameters getExtClientConf
-type extClientConfParams struct {
-	// Client ID
-	// in: path
-	ClientID string `json:"clientid"`
-	// Network
-	// in: path
-	Network string `json:"network"`
-	// Type
-	// in: path
-	Type string `json:"type"`
-}
-
-// 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:"nodeid"`
-
-	// Custom ExtClient
-	// in: body
-	CustomExtClient models.CustomExtClient `json:"custom_ext_client"`
-}
-
-// swagger:parameters getNode updateNode deleteNode createRelay deleteRelay createEgressGateway deleteEgressGateway createIngressGateway deleteIngressGateway ingressGatewayUsers
-type networkNodePathParams struct {
-	// in: path
-	Network string `json:"network"`
-	// in: path
-	NodeID string `json:"nodeid"`
-}
-
-// swagger:response byteArrayResponse
-type byteArrayResponse struct {
-	// in: body
-	ByteArray []byte `json:"byte_array"`
-}
-
-// swagger:parameters getNetwork deleteNetwork updateNetwork getNetworkACL updateNetworkACL
-type NetworkParam struct {
-	// name: network name
-	// in:  path
-	Networkname string `json:"networkname"`
-}
-
-// swagger:response getNetworksSliceResponse
-type getNetworksSliceResponse struct {
-	// Networks
-	// in: body
-	Networks []models.Network `json:"networks"`
-}
-
-// swagger:response hostPull
-type hostPull struct {
-	// hostPull
-	// in: body
-	HostPull models.HostPull
-}
-
-// swagger:parameters createNetwork updateNetwork
-type networkBodyParam struct {
-	// Network
-	// in: body
-	Network models.Network `json:"network"`
-}
-
-// swagger:parameters updateNetworkNodeLimit keyUpdate createAccessKey getAccessKeys getNetworkNodes
-type networkPathParam struct {
-	// Network
-	// in: path
-	Network string `json:"network"`
-}
-
-// swagger:response networkBodyResponse
-type networkBodyResponse struct {
-	// Network
-	// in: body
-	Network models.Network `json:"network"`
-}
-
-// swagger:parameters updateNetworkACL
-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.ApiNode `json:"nodes"`
-}
-
-// swagger:response nodeResponse
-type nodeResponse struct {
-	// Node
-	// in: body
-	Node models.LegacyNode `json:"node"`
-}
-
-// swagger:parameters updateNode deleteNode
-type nodeBodyParam struct {
-	// Node
-	// in: body
-	Node models.LegacyNode `json:"node"`
-}
-
-//swagger:response okResponse
-type okRespone struct{}
-
-// swagger:response RegisterResponse
-type RegisterResponse struct {
-	// in: body
-	RegisterResponse models.RegisterResponse
-}
-
-// 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 attachUserToRemoteAccessGateway removeUserFromRemoteAccessGW getUserRemoteAccessGws
-type RemoteAccessGatewayUser struct {
-	// in: path
-	Username string `json:"username"`
-}
-
-// swagger:parameters authenticate
-type authParamBodyParam struct {
-	// network
-	// in: path
-	Network string `json:"network"`
-	// AuthParams
-	// in: body
-	AuthParams models.AuthParams `json:"auth_params"`
-}
-
-// swagger:response signal
-type signal struct {
-	// in: body
-	Signal models.Signal
-}
-
-// swagger:parameters synchost deleteHost updateHost signalPeer updateKeys
-type HostID struct {
-	// HostID
-	// in: path
-	HostID string `json:"hostid"`
-}
-
-// swagger:parameters addHostToNetwork deleteHostFromNetwork
-type HostFromNetworkParams struct {
-	// hostid to add or delete from network
-	// in: path
-	HostID string `json:"hostid"`
-	// network
-	// in: path
-	Network string `json:"network"`
-}
-
-// swagger:parameters createEnrollmentKey
-type createEnrollmentKeyParams struct {
-	// APIEnrollmentKey
-	// in: body
-	Body models.APIEnrollmentKey `json:"body"`
-}
-
-// swagger:parameters updateEnrollmentKey
-type updateEnrollmentKeyParams struct {
-	// KeyID
-	// in: path
-	KeyID string `json:"keyid"`
-
-	// APIEnrollmentKey
-	// in: body
-	Body models.APIEnrollmentKey `json:"body"`
-}
-
-// swagger:parameters deleteEnrollmentKey
-type deleteEnrollmentKeyParam struct {
-	// in: path
-	KeyID string `json:"keyid"`
-}
-
-// swagger:parameters handleHostRegister
-type RegisterParams struct {
-	// in: path
-	Token string `json:"token"`
-	// in: body
-	Host models.Host `json:"host"`
-}
-
-// swagger:response serverConfigResponse
-type serverConfigResponse struct {
-	// Server Config
-	// in: body
-	// example
-	//{
-	//"mqusername": "xxxxxxx"
-	//}
-	ServerConfig config.ServerConfig `json:"server_config"`
-}
-
-// 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 {
-	_ = dnsParams{}
-	_ = dnsResponse{}
-	_ = dnsDeletePathParams{}
-	_ = stringJSONResponse{}
-	_ = getAllClientsRequest{}
-	_ = extClientSliceResponse{}
-	_ = extClientResponse{}
-	_ = successResponse{}
-	_ = extClientPathParams{}
-	_ = extClientBodyParam{}
-	_ = extClientNetworkPathParam{}
-	_ = createExtClientPathParams{}
-	_ = networkNodePathParams{}
-	_ = byteArrayResponse{}
-	_ = getNetworksSliceResponse{}
-	_ = networkBodyParam{}
-	_ = networkPathParam{}
-	_ = networkBodyResponse{}
-	_ = aclContainerBodyParam{}
-	_ = aclContainerResponse{}
-	_ = nodeSliceResponse{}
-	_ = nodeResponse{}
-	_ = nodeBodyParam{}
-	_ = relayRequestBodyParam{}
-	_ = egressGatewayBodyParam{}
-	_ = authParamBodyParam{}
-	_ = serverConfigResponse{}
-	_ = userBodyParam{}
-	_ = userBodyResponse{}
-	_ = userAuthBodyParam{}
-	_ = usernamePathParam{}
-	_ = hasAdmin{}
-	_ = apiHostSliceResponse{}
-	_ = apiHostResponse{}
-	_ = fileResponse{}
-	_ = extClientConfParams{}
-	_ = hostPull{}
-	_ = okRespone{}
-	_ = signal{}
-	_ = filenameToGet{}
-	_ = dnsNetworkPathParam{}
-	_ = createEnrollmentKeyParams{}
-	_ = updateEnrollmentKeyParams{}
-	_ = deleteEnrollmentKeyParam{}
-	return false
-}

+ 47 - 56
controllers/enrollmentkeys.go

@@ -32,17 +32,12 @@ func enrollmentKeyHandlers(r *mux.Router) {
 		Methods(http.MethodPut)
 }
 
-// swagger:route GET /api/v1/enrollment-keys enrollmentKeys getEnrollmentKeys
-//
-// Lists all EnrollmentKeys for admins.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: EnrollmentKeys
+// @Summary     Lists all EnrollmentKeys for admins
+// @Router      /api/v1/enrollment-keys [get]
+// @Tags        EnrollmentKeys
+// @Security    oauth
+// @Success     200 {array} models.EnrollmentKey
+// @Failure     500 {object} models.ErrorResponse
 func getEnrollmentKeys(w http.ResponseWriter, r *http.Request) {
 	keys, err := logic.GetAllEnrollmentKeys()
 	if err != nil {
@@ -67,17 +62,13 @@ func getEnrollmentKeys(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(ret)
 }
 
-// swagger:route DELETE /api/v1/enrollment-keys/{keyid} enrollmentKeys deleteEnrollmentKey
-//
-// Deletes an EnrollmentKey from Netmaker server.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: okResponse
+// @Summary     Deletes an EnrollmentKey from Netmaker server
+// @Router      /api/v1/enrollment-keys/{keyid} [delete]
+// @Tags        EnrollmentKeys
+// @Security    oauth
+// @Param       keyid path string true "Enrollment Key ID"
+// @Success     200
+// @Failure     500 {object} models.ErrorResponse
 func deleteEnrollmentKey(w http.ResponseWriter, r *http.Request) {
 	params := mux.Vars(r)
 	keyID := params["keyID"]
@@ -91,17 +82,14 @@ func deleteEnrollmentKey(w http.ResponseWriter, r *http.Request) {
 	w.WriteHeader(http.StatusOK)
 }
 
-// swagger:route POST /api/v1/enrollment-keys enrollmentKeys createEnrollmentKey
-//
-// Creates an EnrollmentKey for hosts to use on Netmaker server.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: EnrollmentKey
+// @Summary     Creates an EnrollmentKey for hosts to register with server and join networks
+// @Router      /api/v1/enrollment-keys [post]
+// @Tags        EnrollmentKeys
+// @Security    oauth
+// @Param       body body models.APIEnrollmentKey true "Enrollment Key parameters"
+// @Success     200 {object} models.EnrollmentKey
+// @Failure     400 {object} models.ErrorResponse
+// @Failure     500 {object} models.ErrorResponse
 func createEnrollmentKey(w http.ResponseWriter, r *http.Request) {
 	var enrollmentKeyBody models.APIEnrollmentKey
 
@@ -121,7 +109,14 @@ func createEnrollmentKey(w http.ResponseWriter, r *http.Request) {
 	if err != nil {
 		logger.Log(0, r.Header.Get("user"), "error validating request body: ",
 			err.Error())
-		logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("validation error: name length must be between 3 and 32: %w", err), "badrequest"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(
+				fmt.Errorf("validation error: name length must be between 3 and 32: %w", err),
+				"badrequest",
+			),
+		)
 		return
 	}
 
@@ -180,17 +175,15 @@ func createEnrollmentKey(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(newEnrollmentKey)
 }
 
-// swagger:route PUT /api/v1/enrollment-keys/{keyid} enrollmentKeys updateEnrollmentKey
-//
-// Updates an EnrollmentKey for hosts to use on Netmaker server. Updates only the relay to use.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: EnrollmentKey
+// @Summary     Updates an EnrollmentKey. Updates are only limited to the relay to use
+// @Router      /api/v1/enrollment-keys/{keyid} [put]
+// @Tags        EnrollmentKeys
+// @Security    oauth
+// @Param       keyid path string true "Enrollment Key ID"
+// @Param       body body models.APIEnrollmentKey true "Enrollment Key parameters"
+// @Success     200 {object} models.EnrollmentKey
+// @Failure     400 {object} models.ErrorResponse
+// @Failure     500 {object} models.ErrorResponse
 func updateEnrollmentKey(w http.ResponseWriter, r *http.Request) {
 	var enrollmentKeyBody models.APIEnrollmentKey
 	params := mux.Vars(r)
@@ -231,17 +224,15 @@ func updateEnrollmentKey(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(newEnrollmentKey)
 }
 
-// swagger:route POST /api/v1/enrollment-keys/{token} enrollmentKeys handleHostRegister
-//
-// Handles a Netclient registration with server and add nodes accordingly.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: RegisterResponse
+// @Summary     Handles a Netclient registration with server and add nodes accordingly
+// @Router      /api/v1/host/register/{token} [post]
+// @Tags        EnrollmentKeys
+// @Security    oauth
+// @Param       token path string true "Enrollment Key Token"
+// @Param       body body models.Host true "Host registration parameters"
+// @Success     200 {object} models.RegisterResponse
+// @Failure     400 {object} models.ErrorResponse
+// @Failure     500 {object} models.ErrorResponse
 func handleHostRegister(w http.ResponseWriter, r *http.Request) {
 	params := mux.Vars(r)
 	token := params["token"]

+ 220 - 111
controllers/ext_client.go

@@ -28,13 +28,20 @@ import (
 
 func extClientHandlers(r *mux.Router) {
 
-	r.HandleFunc("/api/extclients", logic.SecurityCheck(true, http.HandlerFunc(getAllExtClients))).Methods(http.MethodGet)
-	r.HandleFunc("/api/extclients/{network}", logic.SecurityCheck(true, http.HandlerFunc(getNetworkExtClients))).Methods(http.MethodGet)
-	r.HandleFunc("/api/extclients/{network}/{clientid}", logic.SecurityCheck(false, http.HandlerFunc(getExtClient))).Methods(http.MethodGet)
-	r.HandleFunc("/api/extclients/{network}/{clientid}/{type}", logic.SecurityCheck(false, http.HandlerFunc(getExtClientConf))).Methods(http.MethodGet)
-	r.HandleFunc("/api/extclients/{network}/{clientid}", logic.SecurityCheck(false, http.HandlerFunc(updateExtClient))).Methods(http.MethodPut)
-	r.HandleFunc("/api/extclients/{network}/{clientid}", logic.SecurityCheck(false, http.HandlerFunc(deleteExtClient))).Methods(http.MethodDelete)
-	r.HandleFunc("/api/extclients/{network}/{nodeid}", logic.SecurityCheck(false, checkFreeTierLimits(limitChoiceMachines, http.HandlerFunc(createExtClient)))).Methods(http.MethodPost)
+	r.HandleFunc("/api/extclients", logic.SecurityCheck(true, http.HandlerFunc(getAllExtClients))).
+		Methods(http.MethodGet)
+	r.HandleFunc("/api/extclients/{network}", logic.SecurityCheck(true, http.HandlerFunc(getNetworkExtClients))).
+		Methods(http.MethodGet)
+	r.HandleFunc("/api/extclients/{network}/{clientid}", logic.SecurityCheck(false, http.HandlerFunc(getExtClient))).
+		Methods(http.MethodGet)
+	r.HandleFunc("/api/extclients/{network}/{clientid}/{type}", logic.SecurityCheck(false, http.HandlerFunc(getExtClientConf))).
+		Methods(http.MethodGet)
+	r.HandleFunc("/api/extclients/{network}/{clientid}", logic.SecurityCheck(false, http.HandlerFunc(updateExtClient))).
+		Methods(http.MethodPut)
+	r.HandleFunc("/api/extclients/{network}/{clientid}", logic.SecurityCheck(false, http.HandlerFunc(deleteExtClient))).
+		Methods(http.MethodDelete)
+	r.HandleFunc("/api/extclients/{network}/{nodeid}", logic.SecurityCheck(false, checkFreeTierLimits(limitChoiceMachines, http.HandlerFunc(createExtClient)))).
+		Methods(http.MethodPost)
 }
 
 func checkIngressExists(nodeID string) bool {
@@ -45,18 +52,12 @@ func checkIngressExists(nodeID string) bool {
 	return node.IsIngressGateway
 }
 
-// swagger:route GET /api/extclients/{network} ext_client getNetworkExtClients
-//
-// Get all extclients associated with network.
-// Gets all extclients associated with network, including pending extclients.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: extClientSliceResponse
+// @Summary     Get all remote access client associated with network
+// @Router      /api/extclients/{network} [get]
+// @Tags        Remote Access Client
+// @Security    oauth2
+// @Success     200 {object} models.ExtClient
+// @Failure     500 {object} models.ErrorResponse
 func getNetworkExtClients(w http.ResponseWriter, r *http.Request) {
 
 	w.Header().Set("Content-Type", "application/json")
@@ -77,18 +78,12 @@ func getNetworkExtClients(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(extclients)
 }
 
-// swagger:route GET /api/extclients ext_client getAllExtClients
-//
-// A separate function to get all extclients, not just extclients for a particular network.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: extClientSliceResponse
-//
+// @Summary     Fetches All Remote Access Clients across all networks
+// @Router      /api/extclients [get]
+// @Tags        Remote Access Client
+// @Security    oauth2
+// @Success     200 {object} models.ExtClient
+// @Failure     500 {object} models.ErrorResponse
 // Not quite sure if this is necessary. Probably necessary based on front end but may
 // want to review after iteration 1 if it's being used or not
 func getAllExtClients(w http.ResponseWriter, r *http.Request) {
@@ -107,17 +102,13 @@ func getAllExtClients(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(clients)
 }
 
-// swagger:route GET /api/extclients/{network}/{clientid} ext_client getExtClient
-//
-// Get an individual extclient.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: extClientResponse
+// @Summary     Get an individual remote access client
+// @Router      /api/extclients/{network}/{clientid} [get]
+// @Tags        Remote Access Client
+// @Security    oauth2
+// @Success     200 {object} models.ExtClient
+// @Failure     500 {object} models.ErrorResponse
+// @Failure     403 {object} models.ErrorResponse
 func getExtClient(w http.ResponseWriter, r *http.Request) {
 	// set header.
 	w.Header().Set("Content-Type", "application/json")
@@ -128,8 +119,12 @@ func getExtClient(w http.ResponseWriter, r *http.Request) {
 	network := params["network"]
 	client, err := logic.GetExtClient(clientid, network)
 	if err != nil {
-		logger.Log(0, r.Header.Get("user"), fmt.Sprintf("failed to get extclient for [%s] on network [%s]: %v",
-			clientid, network, err))
+		logger.Log(
+			0,
+			r.Header.Get("user"),
+			fmt.Sprintf("failed to get extclient for [%s] on network [%s]: %v",
+				clientid, network, err),
+		)
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 		return
 	}
@@ -137,7 +132,11 @@ func getExtClient(w http.ResponseWriter, r *http.Request) {
 		// check if user has access to extclient
 		slog.Error("failed to get extclient", "network", network, "clientID",
 			clientid, "error", errors.New("access is denied"))
-		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("access is denied"), "forbidden"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(errors.New("access is denied"), "forbidden"),
+		)
 		return
 
 	}
@@ -146,17 +145,13 @@ func getExtClient(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(client)
 }
 
-// swagger:route GET /api/extclients/{network}/{clientid}/{type} ext_client getExtClientConf
-//
-// Get an individual extclient.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: extClientResponse
+// @Summary     Get an individual remote access client
+// @Router      /api/extclients/{network}/{clientid}/{type} [get]
+// @Tags        Remote Access Client
+// @Security    oauth2
+// @Success     200 {object} models.ExtClient
+// @Failure     500 {object} models.ErrorResponse
+// @Failure     403 {object} models.ErrorResponse
 func getExtClientConf(w http.ResponseWriter, r *http.Request) {
 	// set header.
 	w.Header().Set("Content-Type", "application/json")
@@ -166,36 +161,63 @@ func getExtClientConf(w http.ResponseWriter, r *http.Request) {
 	networkid := params["network"]
 	client, err := logic.GetExtClient(clientid, networkid)
 	if err != nil {
-		logger.Log(0, r.Header.Get("user"), fmt.Sprintf("failed to get extclient for [%s] on network [%s]: %v",
-			clientid, networkid, err))
+		logger.Log(
+			0,
+			r.Header.Get("user"),
+			fmt.Sprintf("failed to get extclient for [%s] on network [%s]: %v",
+				clientid, networkid, err),
+		)
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 		return
 	}
 	if !logic.IsUserAllowedAccessToExtClient(r.Header.Get("user"), client) {
 		slog.Error("failed to get extclient", "network", networkid, "clientID",
 			clientid, "error", errors.New("access is denied"))
-		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("access is denied"), "forbidden"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(errors.New("access is denied"), "forbidden"),
+		)
 		return
 	}
 
 	gwnode, err := logic.GetNodeByID(client.IngressGatewayID)
 	if err != nil {
-		logger.Log(0, r.Header.Get("user"),
-			fmt.Sprintf("failed to get ingress gateway node [%s] info: %v", client.IngressGatewayID, err))
+		logger.Log(
+			0,
+			r.Header.Get("user"),
+			fmt.Sprintf(
+				"failed to get ingress gateway node [%s] info: %v",
+				client.IngressGatewayID,
+				err,
+			),
+		)
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 		return
 	}
 	host, err := logic.GetHost(gwnode.HostID.String())
 	if err != nil {
-		logger.Log(0, r.Header.Get("user"),
-			fmt.Sprintf("failed to get host for ingress gateway node [%s] info: %v", client.IngressGatewayID, err))
+		logger.Log(
+			0,
+			r.Header.Get("user"),
+			fmt.Sprintf(
+				"failed to get host for ingress gateway node [%s] info: %v",
+				client.IngressGatewayID,
+				err,
+			),
+		)
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 		return
 	}
 
 	network, err := logic.GetParentNetwork(client.Network)
 	if err != nil {
-		logger.Log(1, r.Header.Get("user"), "Could not retrieve Ingress Gateway Network", client.Network)
+		logger.Log(
+			1,
+			r.Header.Get("user"),
+			"Could not retrieve Ingress Gateway Network",
+			client.Network,
+		)
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 		return
 	}
@@ -209,8 +231,19 @@ func getExtClientConf(w http.ResponseWriter, r *http.Request) {
 		allowedPreferredIps = append(allowedPreferredIps, host.EndpointIP.String())
 		allowedPreferredIps = append(allowedPreferredIps, host.EndpointIPv6.String())
 		if !slices.Contains(allowedPreferredIps, preferredIp) {
-			slog.Warn("preferred endpoint ip is not associated with the RAG. proceeding with preferred ip", "preferred ip", preferredIp)
-			logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("preferred endpoint ip is not associated with the RAG"), "badrequest"))
+			slog.Warn(
+				"preferred endpoint ip is not associated with the RAG. proceeding with preferred ip",
+				"preferred ip",
+				preferredIp,
+			)
+			logic.ReturnErrorResponse(
+				w,
+				r,
+				logic.FormatError(
+					errors.New("preferred endpoint ip is not associated with the RAG"),
+					"badrequest",
+				),
+			)
 			return
 		}
 		if net.ParseIP(preferredIp).To4() == nil {
@@ -354,16 +387,14 @@ Endpoint = %s
 	json.NewEncoder(w).Encode(client)
 }
 
-// swagger:route POST /api/extclients/{network}/{nodeid} ext_client createExtClient
-//
-// Create an individual extclient.  Must have valid key and be unique.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//			Responses:
-//			200:  okResponse
+// @Summary     Create an individual remote access client
+// @Router      /api/extclients/{network}/{nodeid} [post]
+// @Tags        Remote Access Client
+// @Security    oauth2
+// @Success     200 {string} string "OK"
+// @Failure     500 {object} models.ErrorResponse
+// @Failure     400 {object} models.ErrorResponse
+// @Failure     403 {object} models.ErrorResponse
 func createExtClient(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 
@@ -466,16 +497,40 @@ func createExtClient(w http.ResponseWriter, r *http.Request) {
 	}
 
 	if err = logic.CreateExtClient(&extclient); err != nil {
-		slog.Error("failed to create extclient", "user", r.Header.Get("user"), "network", node.Network, "error", err)
+		slog.Error(
+			"failed to create extclient",
+			"user",
+			r.Header.Get("user"),
+			"network",
+			node.Network,
+			"error",
+			err,
+		)
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 		return
 	}
 
-	slog.Info("created extclient", "user", r.Header.Get("user"), "network", node.Network, "clientid", extclient.ClientID)
+	slog.Info(
+		"created extclient",
+		"user",
+		r.Header.Get("user"),
+		"network",
+		node.Network,
+		"clientid",
+		extclient.ClientID,
+	)
 	w.WriteHeader(http.StatusOK)
 	go func() {
 		if err := logic.SetClientDefaultACLs(&extclient); err != nil {
-			slog.Error("failed to set default acls for extclient", "user", r.Header.Get("user"), "network", node.Network, "error", err)
+			slog.Error(
+				"failed to set default acls for extclient",
+				"user",
+				r.Header.Get("user"),
+				"network",
+				node.Network,
+				"error",
+				err,
+			)
 			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 			return
 		}
@@ -488,17 +543,14 @@ func createExtClient(w http.ResponseWriter, r *http.Request) {
 	}()
 }
 
-// swagger:route PUT /api/extclients/{network}/{clientid} ext_client updateExtClient
-//
-// Update an individual extclient.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: extClientResponse
+// @Summary     Update an individual remote access client
+// @Router      /api/extclients/{network}/{clientid} [put]
+// @Tags        Remote Access Client
+// @Security    oauth2
+// @Success     200 {object} models.ExtClient
+// @Failure     500 {object} models.ErrorResponse
+// @Failure     400 {object} models.ErrorResponse
+// @Failure     403 {object} models.ErrorResponse
 func updateExtClient(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 
@@ -518,7 +570,15 @@ func updateExtClient(w http.ResponseWriter, r *http.Request) {
 	network := params["network"]
 	oldExtClient, err := logic.GetExtClientByName(clientid)
 	if err != nil {
-		slog.Error("failed to retrieve extclient", "user", r.Header.Get("user"), "id", clientid, "error", err)
+		slog.Error(
+			"failed to retrieve extclient",
+			"user",
+			r.Header.Get("user"),
+			"id",
+			clientid,
+			"error",
+			err,
+		)
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 		return
 	}
@@ -526,7 +586,11 @@ func updateExtClient(w http.ResponseWriter, r *http.Request) {
 		// check if user has access to extclient
 		slog.Error("failed to get extclient", "network", network, "clientID",
 			clientid, "error", errors.New("access is denied"))
-		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("access is denied"), "forbidden"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(errors.New("access is denied"), "forbidden"),
+		)
 		return
 
 	}
@@ -567,12 +631,32 @@ func updateExtClient(w http.ResponseWriter, r *http.Request) {
 	}
 	newclient := logic.UpdateExtClient(&oldExtClient, &update)
 	if err := logic.DeleteExtClient(oldExtClient.Network, oldExtClient.ClientID); err != nil {
-		slog.Error("failed to delete ext client", "user", r.Header.Get("user"), "id", oldExtClient.ClientID, "network", oldExtClient.Network, "error", err)
+		slog.Error(
+			"failed to delete ext client",
+			"user",
+			r.Header.Get("user"),
+			"id",
+			oldExtClient.ClientID,
+			"network",
+			oldExtClient.Network,
+			"error",
+			err,
+		)
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 		return
 	}
 	if err := logic.SaveExtClient(&newclient); err != nil {
-		slog.Error("failed to save ext client", "user", r.Header.Get("user"), "id", newclient.ClientID, "network", newclient.Network, "error", err)
+		slog.Error(
+			"failed to save ext client",
+			"user",
+			r.Header.Get("user"),
+			"id",
+			newclient.ClientID,
+			"network",
+			newclient.Network,
+			"error",
+			err,
+		)
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 		return
 	}
@@ -588,13 +672,25 @@ func updateExtClient(w http.ResponseWriter, r *http.Request) {
 			ingressNode, err := logic.GetNodeByID(newclient.IngressGatewayID)
 			if err == nil {
 				if err = mq.PublishPeerUpdate(false); err != nil {
-					logger.Log(1, "error setting ext peers on", ingressNode.ID.String(), ":", err.Error())
+					logger.Log(
+						1,
+						"error setting ext peers on",
+						ingressNode.ID.String(),
+						":",
+						err.Error(),
+					)
 				}
 			}
 			if !update.Enabled {
 				ingressHost, err := logic.GetHost(ingressNode.HostID.String())
 				if err != nil {
-					slog.Error("Failed to get ingress host", "node", ingressNode.ID.String(), "error", err)
+					slog.Error(
+						"Failed to get ingress host",
+						"node",
+						ingressNode.ID.String(),
+						"error",
+						err,
+					)
 					return
 				}
 				nodes, err := logic.GetAllNodes()
@@ -602,7 +698,13 @@ func updateExtClient(w http.ResponseWriter, r *http.Request) {
 					slog.Error("Failed to get nodes", "error", err)
 					return
 				}
-				go mq.PublishSingleHostPeerUpdate(ingressHost, nodes, nil, []models.ExtClient{oldExtClient}, false)
+				go mq.PublishSingleHostPeerUpdate(
+					ingressHost,
+					nodes,
+					nil,
+					[]models.ExtClient{oldExtClient},
+					false,
+				)
 			}
 		}
 
@@ -610,17 +712,13 @@ func updateExtClient(w http.ResponseWriter, r *http.Request) {
 
 }
 
-// swagger:route DELETE /api/extclients/{network}/{clientid} ext_client deleteExtClient
-//
-// Delete an individual extclient.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: successResponse
+// @Summary     Delete an individual remote access client
+// @Router      /api/extclients/{network}/{clientid} [delete]
+// @Tags        Remote Access Client
+// @Security    oauth2
+// @Success     200
+// @Failure     500 {object} models.ErrorResponse
+// @Failure     403 {object} models.ErrorResponse
 func deleteExtClient(w http.ResponseWriter, r *http.Request) {
 	// Set header
 	w.Header().Set("Content-Type", "application/json")
@@ -640,13 +738,24 @@ func deleteExtClient(w http.ResponseWriter, r *http.Request) {
 	if !logic.IsUserAllowedAccessToExtClient(r.Header.Get("user"), extclient) {
 		slog.Error("user not allowed to delete", "network", network, "clientID",
 			clientid, "error", errors.New("access is denied"))
-		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("access is denied"), "forbidden"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(errors.New("access is denied"), "forbidden"),
+		)
 		return
 	}
 	ingressnode, err := logic.GetNodeByID(extclient.IngressGatewayID)
 	if err != nil {
-		logger.Log(0, r.Header.Get("user"),
-			fmt.Sprintf("failed to get ingress gateway node [%s] info: %v", extclient.IngressGatewayID, err))
+		logger.Log(
+			0,
+			r.Header.Get("user"),
+			fmt.Sprintf(
+				"failed to get ingress gateway node [%s] info: %v",
+				extclient.IngressGatewayID,
+				err,
+			),
+		)
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 		return
 	}

+ 7 - 11
controllers/files.go

@@ -6,16 +6,12 @@ import (
 	"github.com/gorilla/mux"
 )
 
+// @Summary     Retrieve a file from the file server
+// @Router      /meshclient/files/{filename}  [get]
+// @Tags        Meshclient
+// @Success     200 {body} file "file"
+// @Failure     404 {string} string "404 not found"
 func fileHandlers(r *mux.Router) {
-	// swagger:route GET /meshclient/files/{filename} meshclient getFile
-	//
-	// Retrieve a file from the file server.
-	//
-	//		Schemes: https
-	//
-	// 		Security:
-	//   		oauth
-	//		Responses:
-	//		200: fileResponse
-	r.PathPrefix("/meshclient/files").Handler(http.StripPrefix("/meshclient/files", http.FileServer(http.Dir("./meshclient/files"))))
+	r.PathPrefix("/meshclient/files").
+		Handler(http.StripPrefix("/meshclient/files", http.FileServer(http.Dir("./meshclient/files"))))
 }

+ 256 - 174
controllers/hosts.go

@@ -19,23 +19,43 @@ import (
 )
 
 func hostHandlers(r *mux.Router) {
-	r.HandleFunc("/api/hosts", logic.SecurityCheck(true, http.HandlerFunc(getHosts))).Methods(http.MethodGet)
-	r.HandleFunc("/api/hosts/keys", logic.SecurityCheck(true, http.HandlerFunc(updateAllKeys))).Methods(http.MethodPut)
-	r.HandleFunc("/api/hosts/{hostid}/keys", logic.SecurityCheck(true, http.HandlerFunc(updateKeys))).Methods(http.MethodPut)
-	r.HandleFunc("/api/hosts/{hostid}/sync", logic.SecurityCheck(true, http.HandlerFunc(syncHost))).Methods(http.MethodPost)
-	r.HandleFunc("/api/hosts/{hostid}", logic.SecurityCheck(true, http.HandlerFunc(updateHost))).Methods(http.MethodPut)
-	r.HandleFunc("/api/hosts/{hostid}", Authorize(true, false, "all", http.HandlerFunc(deleteHost))).Methods(http.MethodDelete)
-	r.HandleFunc("/api/hosts/{hostid}/upgrade", logic.SecurityCheck(true, http.HandlerFunc(upgradeHost))).Methods(http.MethodPut)
-	r.HandleFunc("/api/hosts/{hostid}/networks/{network}", logic.SecurityCheck(true, http.HandlerFunc(addHostToNetwork))).Methods(http.MethodPost)
-	r.HandleFunc("/api/hosts/{hostid}/networks/{network}", logic.SecurityCheck(true, http.HandlerFunc(deleteHostFromNetwork))).Methods(http.MethodDelete)
+	r.HandleFunc("/api/hosts", logic.SecurityCheck(true, http.HandlerFunc(getHosts))).
+		Methods(http.MethodGet)
+	r.HandleFunc("/api/hosts/keys", logic.SecurityCheck(true, http.HandlerFunc(updateAllKeys))).
+		Methods(http.MethodPut)
+	r.HandleFunc("/api/hosts/{hostid}/keys", logic.SecurityCheck(true, http.HandlerFunc(updateKeys))).
+		Methods(http.MethodPut)
+	r.HandleFunc("/api/hosts/{hostid}/sync", logic.SecurityCheck(true, http.HandlerFunc(syncHost))).
+		Methods(http.MethodPost)
+	r.HandleFunc("/api/hosts/{hostid}", logic.SecurityCheck(true, http.HandlerFunc(updateHost))).
+		Methods(http.MethodPut)
+	r.HandleFunc("/api/hosts/{hostid}", Authorize(true, false, "all", http.HandlerFunc(deleteHost))).
+		Methods(http.MethodDelete)
+	r.HandleFunc("/api/hosts/{hostid}/upgrade", logic.SecurityCheck(true, http.HandlerFunc(upgradeHost))).
+		Methods(http.MethodPut)
+	r.HandleFunc("/api/hosts/{hostid}/networks/{network}", logic.SecurityCheck(true, http.HandlerFunc(addHostToNetwork))).
+		Methods(http.MethodPost)
+	r.HandleFunc("/api/hosts/{hostid}/networks/{network}", logic.SecurityCheck(true, http.HandlerFunc(deleteHostFromNetwork))).
+		Methods(http.MethodDelete)
 	r.HandleFunc("/api/hosts/adm/authenticate", authenticateHost).Methods(http.MethodPost)
-	r.HandleFunc("/api/v1/host", Authorize(true, false, "host", http.HandlerFunc(pull))).Methods(http.MethodGet)
-	r.HandleFunc("/api/v1/host/{hostid}/signalpeer", Authorize(true, false, "host", http.HandlerFunc(signalPeer))).Methods(http.MethodPost)
-	r.HandleFunc("/api/v1/fallback/host/{hostid}", Authorize(true, false, "host", http.HandlerFunc(hostUpdateFallback))).Methods(http.MethodPut)
-	r.HandleFunc("/api/emqx/hosts", logic.SecurityCheck(true, http.HandlerFunc(delEmqxHosts))).Methods(http.MethodDelete)
+	r.HandleFunc("/api/v1/host", Authorize(true, false, "host", http.HandlerFunc(pull))).
+		Methods(http.MethodGet)
+	r.HandleFunc("/api/v1/host/{hostid}/signalpeer", Authorize(true, false, "host", http.HandlerFunc(signalPeer))).
+		Methods(http.MethodPost)
+	r.HandleFunc("/api/v1/fallback/host/{hostid}", Authorize(true, false, "host", http.HandlerFunc(hostUpdateFallback))).
+		Methods(http.MethodPut)
+	r.HandleFunc("/api/emqx/hosts", logic.SecurityCheck(true, http.HandlerFunc(delEmqxHosts))).
+		Methods(http.MethodDelete)
 	r.HandleFunc("/api/v1/auth-register/host", socketHandler)
 }
 
+// @Summary     Upgrade a host
+// @Router      /api/hosts/{hostid}/upgrade [put]
+// @Tags        Hosts
+// @Security    oauth
+// @Param       hostid path string true "Host ID"
+// @Success     200 {string} string "passed message to upgrade host"
+// @Failure     500 {object} models.ErrorResponse
 // upgrade host is a handler to send upgrade message to a host
 func upgradeHost(w http.ResponseWriter, r *http.Request) {
 	host, err := logic.GetHost(mux.Vars(r)["hostid"])
@@ -52,17 +72,12 @@ func upgradeHost(w http.ResponseWriter, r *http.Request) {
 	logic.ReturnSuccessResponse(w, r, "passed message to upgrade host")
 }
 
-// swagger:route GET /api/hosts hosts getHosts
-//
-// Lists all hosts.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: apiHostSliceResponse
+// @Summary     List all hosts
+// @Router      /api/hosts [get]
+// @Tags        Hosts
+// @Security    oauth
+// @Success     200 {array} models.ApiHost
+// @Failure     500 {object} models.ErrorResponse
 func getHosts(w http.ResponseWriter, r *http.Request) {
 	currentHosts, err := logic.GetAllHosts()
 	if err != nil {
@@ -77,23 +92,22 @@ func getHosts(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(apiHosts)
 }
 
-// swagger:route GET /api/v1/host hosts pullHost
-//
-// Used by clients for "pull" command
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: hostPull
+// @Summary     Used by clients for "pull" command
+// @Router      /api/v1/host [get]
+// @Tags        Hosts
+// @Security    oauth
+// @Success     200 {object} models.HostPull
+// @Failure     500 {object} models.ErrorResponse
 func pull(w http.ResponseWriter, r *http.Request) {
 
 	hostID := r.Header.Get(hostIDHeader) // return JSON/API formatted keys
 	if len(hostID) == 0 {
 		logger.Log(0, "no host authorized to pull")
-		logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("no host authorized to pull"), "internal"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(fmt.Errorf("no host authorized to pull"), "internal"),
+		)
 		return
 	}
 	host, err := logic.GetHost(hostID)
@@ -153,17 +167,14 @@ func pull(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(&response)
 }
 
-// swagger:route PUT /api/hosts/{hostid} hosts updateHost
-//
-// Updates a Netclient host on Netmaker server.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: apiHostResponse
+// @Summary     Updates a Netclient host on Netmaker server
+// @Router      /api/hosts/{hostid} [put]
+// @Tags        Hosts
+// @Security    oauth
+// @Param       hostid path string true "Host ID"
+// @Param       body body models.ApiHost true "New host data"
+// @Success     200 {object} models.ApiHost
+// @Failure     500 {object} models.ErrorResponse
 func updateHost(w http.ResponseWriter, r *http.Request) {
 	var newHostData models.ApiHost
 	err := json.NewDecoder(r.Body).Decode(&newHostData)
@@ -194,7 +205,13 @@ func updateHost(w http.ResponseWriter, r *http.Request) {
 		Action: models.UpdateHost,
 		Host:   *newHost,
 	}); err != nil {
-		logger.Log(0, r.Header.Get("user"), "failed to send host update: ", currHost.ID.String(), err.Error())
+		logger.Log(
+			0,
+			r.Header.Get("user"),
+			"failed to send host update: ",
+			currHost.ID.String(),
+			err.Error(),
+		)
 	}
 	go func() {
 		if err := mq.PublishPeerUpdate(false); err != nil {
@@ -213,17 +230,14 @@ func updateHost(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(apiHostData)
 }
 
-// swagger:route PUT /api/v1/fallback/host/{hostid} hosts hostUpdateFallback
-//
-// Updates a Netclient host on Netmaker server.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: apiHostResponse
+// @Summary     Updates a Netclient host on Netmaker server
+// @Router      /api/v1/fallback/host/{hostid} [put]
+// @Tags        Hosts
+// @Security    oauth
+// @Param       hostid path string true "Host ID"
+// @Param       body body models.HostUpdate true "Host update data"
+// @Success     200 {string} string "updated host data"
+// @Failure     500 {object} models.ErrorResponse
 func hostUpdateFallback(w http.ResponseWriter, r *http.Request) {
 	var params = mux.Vars(r)
 	hostid := params["hostid"]
@@ -273,17 +287,14 @@ func hostUpdateFallback(w http.ResponseWriter, r *http.Request) {
 	logic.ReturnSuccessResponse(w, r, "updated host data")
 }
 
-// swagger:route DELETE /api/hosts/{hostid} hosts deleteHost
-//
-// Deletes a Netclient host from Netmaker server.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: apiHostResponse
+// @Summary     Deletes a Netclient host from Netmaker server
+// @Router      /api/hosts/{hostid} [delete]
+// @Tags        Hosts
+// @Security    oauth
+// @Param       hostid path string true "Host ID"
+// @Param       force query bool false "Force delete"
+// @Success     200 {object} models.ApiHost
+// @Failure     500 {object} models.ErrorResponse
 func deleteHost(w http.ResponseWriter, r *http.Request) {
 	var params = mux.Vars(r)
 	hostid := params["hostid"]
@@ -312,14 +323,26 @@ func deleteHost(w http.ResponseWriter, r *http.Request) {
 	if servercfg.GetBrokerType() == servercfg.EmqxBrokerType {
 		// delete EMQX credentials for host
 		if err := mq.GetEmqxHandler().DeleteEmqxUser(currHost.ID.String()); err != nil {
-			slog.Error("failed to remove host credentials from EMQX", "id", currHost.ID, "error", err)
+			slog.Error(
+				"failed to remove host credentials from EMQX",
+				"id",
+				currHost.ID,
+				"error",
+				err,
+			)
 		}
 	}
 	if err = mq.HostUpdate(&models.HostUpdate{
 		Action: models.DeleteHost,
 		Host:   *currHost,
 	}); err != nil {
-		logger.Log(0, r.Header.Get("user"), "failed to send delete host update: ", currHost.ID.String(), err.Error())
+		logger.Log(
+			0,
+			r.Header.Get("user"),
+			"failed to send delete host update: ",
+			currHost.ID.String(),
+			err.Error(),
+		)
 	}
 	if err = logic.RemoveHost(currHost, forceDelete); err != nil {
 		logger.Log(0, r.Header.Get("user"), "failed to delete a host:", err.Error())
@@ -333,23 +356,25 @@ func deleteHost(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(apiHostData)
 }
 
-// swagger:route POST /api/hosts/{hostid}/networks/{network} hosts addHostToNetwork
-//
-// Given a network, a host is added to the network.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//			Responses:
-//				200: okResponse
+// @Summary     To Add Host To Network
+// @Router      /api/hosts/{hostid}/networks/{network} [post]
+// @Tags        Hosts
+// @Security    oauth
+// @Param       hostid path string true "Host ID"
+// @Param       network path string true "Network name"
+// @Success     200 {string} string "OK"
+// @Failure     500 {object} models.ErrorResponse
 func addHostToNetwork(w http.ResponseWriter, r *http.Request) {
 
 	var params = mux.Vars(r)
 	hostid := params["hostid"]
 	network := params["network"]
 	if hostid == "" || network == "" {
-		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("hostid or network cannot be empty"), "badrequest"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(errors.New("hostid or network cannot be empty"), "badrequest"),
+		)
 		return
 	}
 	// confirm host exists
@@ -362,7 +387,14 @@ func addHostToNetwork(w http.ResponseWriter, r *http.Request) {
 
 	newNode, err := logic.UpdateHostNetwork(currHost, network, true)
 	if err != nil {
-		logger.Log(0, r.Header.Get("user"), "failed to add host to network:", hostid, network, err.Error())
+		logger.Log(
+			0,
+			r.Header.Get("user"),
+			"failed to add host to network:",
+			hostid,
+			network,
+			err.Error(),
+		)
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 		return
 	}
@@ -384,21 +416,23 @@ func addHostToNetwork(w http.ResponseWriter, r *http.Request) {
 			logic.SetDNS()
 		}
 	}()
-	logger.Log(2, r.Header.Get("user"), fmt.Sprintf("added host %s to network %s", currHost.Name, network))
+	logger.Log(
+		2,
+		r.Header.Get("user"),
+		fmt.Sprintf("added host %s to network %s", currHost.Name, network),
+	)
 	w.WriteHeader(http.StatusOK)
 }
 
-// swagger:route DELETE /api/hosts/{hostid}/networks/{network} hosts deleteHostFromNetwork
-//
-// Given a network, a host is removed from the network.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: okResponse
+// @Summary     To Remove Host from Network
+// @Router      /api/hosts/{hostid}/networks/{network} [delete]
+// @Tags        Hosts
+// @Security    oauth
+// @Param       hostid path string true "Host ID"
+// @Param       network path string true "Network name"
+// @Param       force query bool false "Force delete"
+// @Success     200 {string} string "OK"
+// @Failure     500 {object} models.ErrorResponse
 func deleteHostFromNetwork(w http.ResponseWriter, r *http.Request) {
 
 	var params = mux.Vars(r)
@@ -406,7 +440,11 @@ func deleteHostFromNetwork(w http.ResponseWriter, r *http.Request) {
 	network := params["network"]
 	forceDelete := r.URL.Query().Get("force") == "true"
 	if hostid == "" || network == "" {
-		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("hostid or network cannot be empty"), "badrequest"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(errors.New("hostid or network cannot be empty"), "badrequest"),
+		)
 		return
 	}
 	// confirm host exists
@@ -416,14 +454,29 @@ func deleteHostFromNetwork(w http.ResponseWriter, r *http.Request) {
 			// check if there is any daemon nodes that needs to be deleted
 			node, err := logic.GetNodeByHostRef(hostid, network)
 			if err != nil {
-				slog.Error("couldn't get node for host", "hostid", hostid, "network", network, "error", err)
+				slog.Error(
+					"couldn't get node for host",
+					"hostid",
+					hostid,
+					"network",
+					network,
+					"error",
+					err,
+				)
 				logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
 				return
 			}
 			if err = logic.DeleteNodeByID(&node); err != nil {
 				slog.Error("failed to force delete daemon node",
 					"nodeid", node.ID.String(), "hostid", hostid, "network", network, "error", err)
-				logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to force delete daemon node: "+err.Error()), "internal"))
+				logic.ReturnErrorResponse(
+					w,
+					r,
+					logic.FormatError(
+						fmt.Errorf("failed to force delete daemon node: "+err.Error()),
+						"internal",
+					),
+				)
 				return
 			}
 			logic.ReturnSuccessResponse(w, r, "force deleted daemon node successfully")
@@ -441,20 +494,42 @@ func deleteHostFromNetwork(w http.ResponseWriter, r *http.Request) {
 			// force cleanup the node
 			node, err := logic.GetNodeByHostRef(hostid, network)
 			if err != nil {
-				slog.Error("couldn't get node for host", "hostid", hostid, "network", network, "error", err)
+				slog.Error(
+					"couldn't get node for host",
+					"hostid",
+					hostid,
+					"network",
+					network,
+					"error",
+					err,
+				)
 				logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
 				return
 			}
 			if err = logic.DeleteNodeByID(&node); err != nil {
 				slog.Error("failed to force delete daemon node",
 					"nodeid", node.ID.String(), "hostid", hostid, "network", network, "error", err)
-				logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to force delete daemon node: "+err.Error()), "internal"))
+				logic.ReturnErrorResponse(
+					w,
+					r,
+					logic.FormatError(
+						fmt.Errorf("failed to force delete daemon node: "+err.Error()),
+						"internal",
+					),
+				)
 				return
 			}
 			logic.ReturnSuccessResponse(w, r, "force deleted daemon node successfully")
 			return
 		}
-		logger.Log(0, r.Header.Get("user"), "failed to remove host from network:", hostid, network, err.Error())
+		logger.Log(
+			0,
+			r.Header.Get("user"),
+			"failed to remove host from network:",
+			hostid,
+			network,
+			err.Error(),
+		)
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 		return
 	}
@@ -464,7 +539,11 @@ func deleteHostFromNetwork(w http.ResponseWriter, r *http.Request) {
 	}
 	logger.Log(1, "deleting node", node.ID.String(), "from host", currHost.Name)
 	if err := logic.DeleteNode(node, forceDelete); err != nil {
-		logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to delete node"), "internal"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(fmt.Errorf("failed to delete node"), "internal"),
+		)
 		return
 	}
 	go func() {
@@ -473,21 +552,23 @@ func deleteHostFromNetwork(w http.ResponseWriter, r *http.Request) {
 			logic.SetDNS()
 		}
 	}()
-	logger.Log(2, r.Header.Get("user"), fmt.Sprintf("removed host %s from network %s", currHost.Name, network))
+	logger.Log(
+		2,
+		r.Header.Get("user"),
+		fmt.Sprintf("removed host %s from network %s", currHost.Name, network),
+	)
 	w.WriteHeader(http.StatusOK)
 }
 
-// swagger:route POST /api/hosts/adm/authenticate authenticate authenticateHost
-//
-// Host based authentication for making further API calls.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: successResponse
+// @Summary     To Fetch Auth Token for a Host
+// @Router      /api/hosts/adm/authenticate [post]
+// @Tags        Auth
+// @Accept      json
+// @Param       body body models.AuthParams true "Authentication parameters"
+// @Success     200 {object} models.SuccessResponse
+// @Failure     400 {object} models.ErrorResponse
+// @Failure     401 {object} models.ErrorResponse
+// @Failure     500 {object} models.ErrorResponse
 func authenticateHost(response http.ResponseWriter, request *http.Request) {
 	var authRequest models.AuthParams
 	var errorResponse = models.ErrorResponse{
@@ -579,17 +660,14 @@ func authenticateHost(response http.ResponseWriter, request *http.Request) {
 	response.Write(successJSONResponse)
 }
 
-// swagger:route POST /api/hosts/{hostid}/signalpeer hosts signalPeer
-//
-// send signal to peer.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: signal
+// @Summary     Send signal to peer
+// @Router      /api/v1/host/{hostid}/signalpeer [post]
+// @Tags        Hosts
+// @Security    oauth
+// @Param       hostid path string true "Host ID"
+// @Param       body body models.Signal true "Signal data"
+// @Success     200 {object} models.Signal
+// @Failure     400 {object} models.ErrorResponse
 func signalPeer(w http.ResponseWriter, r *http.Request) {
 	var params = mux.Vars(r)
 	hostid := params["hostid"]
@@ -617,7 +695,11 @@ func signalPeer(w http.ResponseWriter, r *http.Request) {
 	signal.IsPro = servercfg.IsPro
 	peerHost, err := logic.GetHost(signal.ToHostID)
 	if err != nil {
-		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("failed to signal, peer not found"), "badrequest"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(errors.New("failed to signal, peer not found"), "badrequest"),
+		)
 		return
 	}
 	err = mq.HostUpdate(&models.HostUpdate{
@@ -626,7 +708,14 @@ func signalPeer(w http.ResponseWriter, r *http.Request) {
 		Signal: signal,
 	})
 	if err != nil {
-		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("failed to publish signal to peer: "+err.Error()), "badrequest"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(
+				errors.New("failed to publish signal to peer: "+err.Error()),
+				"badrequest",
+			),
+		)
 		return
 	}
 
@@ -634,17 +723,12 @@ func signalPeer(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(signal)
 }
 
-// swagger:route POST /api/hosts/keys hosts updateAllKeys
-//
-// Update keys for a network.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: networkBodyResponse
+// @Summary     Update keys for all hosts
+// @Router      /api/hosts/keys [put]
+// @Tags        Hosts
+// @Security    oauth
+// @Success     200 {string} string "OK"
+// @Failure     400 {object} models.ErrorResponse
 func updateAllKeys(w http.ResponseWriter, r *http.Request) {
 	var errorResponse = models.ErrorResponse{}
 	w.Header().Set("Content-Type", "application/json")
@@ -664,7 +748,12 @@ func updateAllKeys(w http.ResponseWriter, r *http.Request) {
 			hostUpdate.Host = host
 			logger.Log(2, "updating host", host.ID.String(), " for a key update")
 			if err = mq.HostUpdate(&hostUpdate); err != nil {
-				logger.Log(0, "failed to send update to node during a network wide key update", host.ID.String(), err.Error())
+				logger.Log(
+					0,
+					"failed to send update to node during a network wide key update",
+					host.ID.String(),
+					err.Error(),
+				)
 			}
 		}
 	}()
@@ -672,17 +761,13 @@ func updateAllKeys(w http.ResponseWriter, r *http.Request) {
 	w.WriteHeader(http.StatusOK)
 }
 
-// swagger:route POST /api/hosts/{hostid}keys hosts updateKeys
-//
-// Update keys for a network.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: networkBodyResponse
+// @Summary     Update keys for a host
+// @Router      /api/hosts/{hostid}/keys [put]
+// @Tags        Hosts
+// @Security    oauth
+// @Param       hostid path string true "Host ID"
+// @Success     200 {string} string "OK"
+// @Failure     400 {object} models.ErrorResponse
 func updateKeys(w http.ResponseWriter, r *http.Request) {
 	var errorResponse = models.ErrorResponse{}
 	w.Header().Set("Content-Type", "application/json")
@@ -711,17 +796,13 @@ func updateKeys(w http.ResponseWriter, r *http.Request) {
 	w.WriteHeader(http.StatusOK)
 }
 
-// swagger:route POST /api/hosts/{hostid}/sync hosts synchost
-//
-// Requests a host to pull.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: networkBodyResponse
+// @Summary     Requests a host to pull
+// @Router      /api/hosts/{hostid}/sync [post]
+// @Tags        Hosts
+// @Security    oauth
+// @Param       hostid path string true "Host ID"
+// @Success     200 {string} string "OK"
+// @Failure     400 {object} models.ErrorResponse
 func syncHost(w http.ResponseWriter, r *http.Request) {
 	hostId := mux.Vars(r)["hostid"]
 
@@ -751,17 +832,12 @@ func syncHost(w http.ResponseWriter, r *http.Request) {
 	w.WriteHeader(http.StatusOK)
 }
 
-// swagger:route DELETE /api/emqx/hosts hosts delEmqxHosts
-//
-// Lists all hosts.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: apiHostResponse
+// @Summary     Deletes all EMQX hosts
+// @Router      /api/emqx/hosts [delete]
+// @Tags        Hosts
+// @Security    oauth
+// @Success     200 {string} string "deleted hosts data on emqx"
+// @Failure     500 {object} models.ErrorResponse
 func delEmqxHosts(w http.ResponseWriter, r *http.Request) {
 	currentHosts, err := logic.GetAllHosts()
 	if err != nil {
@@ -777,7 +853,13 @@ func delEmqxHosts(w http.ResponseWriter, r *http.Request) {
 	}
 	err = mq.GetEmqxHandler().DeleteEmqxUser(servercfg.GetMqUserName())
 	if err != nil {
-		slog.Error("failed to remove server credentials from EMQX", "user", servercfg.GetMqUserName(), "error", err)
+		slog.Error(
+			"failed to remove server credentials from EMQX",
+			"user",
+			servercfg.GetMqUserName(),
+			"error",
+			err,
+		)
 	}
 	logic.ReturnSuccessResponse(w, r, "deleted hosts data on emqx")
 }

+ 6 - 11
controllers/ipservice.go

@@ -15,17 +15,12 @@ func ipHandlers(r *mux.Router) {
 	r.HandleFunc("/api/getip", http.HandlerFunc(getPublicIP)).Methods(http.MethodGet)
 }
 
-// swagger:route GET /api/getip ipservice getPublicIP
-//
-// Get the current public IP address.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: byteArrayResponse
+// @Summary     Get the current public IP address.
+// @Router      /api/getip [get]
+// @Tags        IP Service
+// @Security    oauth2
+// @Success     200 {string} string "The public IP address."
+// @Failure     400 {string} string "Invalid IP address or no IP found."
 func getPublicIP(w http.ResponseWriter, r *http.Request) {
 	r.Header.Set("Connection", "close")
 	ip, err := parseIP(r)

+ 8 - 12
controllers/legacy.go

@@ -9,20 +9,16 @@ import (
 )
 
 func legacyHandlers(r *mux.Router) {
-	r.HandleFunc("/api/v1/legacy/nodes", logic.SecurityCheck(true, http.HandlerFunc(wipeLegacyNodes))).Methods(http.MethodDelete)
+	r.HandleFunc("/api/v1/legacy/nodes", logic.SecurityCheck(true, http.HandlerFunc(wipeLegacyNodes))).
+		Methods(http.MethodDelete)
 }
 
-// swagger:route DELETE /api/v1/legacy/nodes nodes wipeLegacyNodes
-//
-// Delete all legacy nodes from DB.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: successResponse
+// @Summary     Delete all legacy nodes from DB.
+// @Router      /api/v1/legacy/nodes [delete]
+// @Tags        Nodes
+// @Security    oauth2
+// @Success     200 {string} string "Wiped all legacy nodes."
+// @Failure     400 {object} models.ErrorResponse
 func wipeLegacyNodes(w http.ResponseWriter, r *http.Request) {
 	// Set header
 	w.Header().Set("Content-Type", "application/json")

+ 127 - 102
controllers/network.go

@@ -22,28 +22,32 @@ import (
 )
 
 func networkHandlers(r *mux.Router) {
-	r.HandleFunc("/api/networks", logic.SecurityCheck(true, http.HandlerFunc(getNetworks))).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))).Methods(http.MethodGet)
-	r.HandleFunc("/api/networks/{networkname}", logic.SecurityCheck(true, http.HandlerFunc(deleteNetwork))).Methods(http.MethodDelete)
-	r.HandleFunc("/api/networks/{networkname}", logic.SecurityCheck(true, http.HandlerFunc(updateNetwork))).Methods(http.MethodPut)
+	r.HandleFunc("/api/networks", logic.SecurityCheck(true, http.HandlerFunc(getNetworks))).
+		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))).
+		Methods(http.MethodGet)
+	r.HandleFunc("/api/networks/{networkname}", logic.SecurityCheck(true, http.HandlerFunc(deleteNetwork))).
+		Methods(http.MethodDelete)
+	r.HandleFunc("/api/networks/{networkname}", logic.SecurityCheck(true, http.HandlerFunc(updateNetwork))).
+		Methods(http.MethodPut)
 	// ACLs
-	r.HandleFunc("/api/networks/{networkname}/acls", logic.SecurityCheck(true, http.HandlerFunc(updateNetworkACL))).Methods(http.MethodPut)
-	r.HandleFunc("/api/networks/{networkname}/acls/v2", logic.SecurityCheck(true, http.HandlerFunc(updateNetworkACLv2))).Methods(http.MethodPut)
-	r.HandleFunc("/api/networks/{networkname}/acls", logic.SecurityCheck(true, http.HandlerFunc(getNetworkACL))).Methods(http.MethodGet)
+	r.HandleFunc("/api/networks/{networkname}/acls", logic.SecurityCheck(true, http.HandlerFunc(updateNetworkACL))).
+		Methods(http.MethodPut)
+	r.HandleFunc("/api/networks/{networkname}/acls/v2", logic.SecurityCheck(true, http.HandlerFunc(updateNetworkACLv2))).
+		Methods(http.MethodPut)
+	r.HandleFunc("/api/networks/{networkname}/acls", logic.SecurityCheck(true, http.HandlerFunc(getNetworkACL))).
+		Methods(http.MethodGet)
 }
 
-// swagger:route GET /api/networks networks getNetworks
-//
-// Lists all networks.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: getNetworksSliceResponse
+// @Summary     Lists all networks
+// @Router      /api/networks [get]
+// @Tags        Networks
+// @Security    oauth
+// @Produce     json
+// @Success     200 {object} models.Network
+// @Failure     500 {object} models.ErrorResponse
 func getNetworks(w http.ResponseWriter, r *http.Request) {
 
 	var err error
@@ -61,17 +65,14 @@ func getNetworks(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(allnetworks)
 }
 
-// swagger:route GET /api/networks/{networkname} networks getNetwork
-//
-// Get a network.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: networkBodyResponse
+// @Summary     Get a network
+// @Router      /api/networks/{networkname} [get]
+// @Tags        Networks
+// @Security    oauth
+// @Param       networkname path string true "Network name"
+// @Produce     json
+// @Success     200 {object} models.Network
+// @Failure     500 {object} models.ErrorResponse
 func getNetwork(w http.ResponseWriter, r *http.Request) {
 	// set header.
 	w.Header().Set("Content-Type", "application/json")
@@ -90,17 +91,16 @@ func getNetwork(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(network)
 }
 
-// swagger:route PUT /api/networks/{networkname}/acls networks updateNetworkACL
-//
-// Update a network ACL (Access Control List).
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: aclContainerResponse
+// @Summary     Update a network ACL (Access Control List)
+// @Router      /api/networks/{networkname}/acls [put]
+// @Tags        Networks
+// @Security    oauth
+// @Param       networkname path string true "Network name"
+// @Param       body body acls.ACLContainer true "ACL container"
+// @Produce     json
+// @Success     200 {object} acls.ACLContainer
+// @Failure     400 {object} models.ErrorResponse
+// @Failure     500 {object} models.ErrorResponse
 func updateNetworkACL(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	var params = mux.Vars(r)
@@ -140,17 +140,16 @@ func updateNetworkACL(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(newNetACL)
 }
 
-// swagger:route PUT /api/networks/{networkname}/acls/v2 networks updateNetworkACL
-//
-// Update a network ACL (Access Control List).
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: aclContainerResponse
+// @Summary     Update a network ACL (Access Control List)
+// @Router      /api/networks/{networkname}/acls/v2 [put]
+// @Tags        Networks
+// @Security    oauth
+// @Param       networkname path string true "Network name"
+// @Param       body body acls.ACLContainer true "ACL container"
+// @Produce     json
+// @Success     200 {object} acls.ACLContainer
+// @Failure     400 {object} models.ErrorResponse
+// @Failure     500 {object} models.ErrorResponse
 func updateNetworkACLv2(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	var params = mux.Vars(r)
@@ -279,13 +278,25 @@ func updateNetworkACLv2(w http.ResponseWriter, r *http.Request) {
 			client := client
 			err := logic.DeleteExtClient(client.Network, client.ClientID)
 			if err != nil {
-				slog.Error("failed to delete client during update", "client", client.ClientID, "error", err.Error())
+				slog.Error(
+					"failed to delete client during update",
+					"client",
+					client.ClientID,
+					"error",
+					err.Error(),
+				)
 				logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 				return
 			}
 			err = logic.SaveExtClient(&client)
 			if err != nil {
-				slog.Error("failed to save client during update", "client", client.ClientID, "error", err.Error())
+				slog.Error(
+					"failed to save client during update",
+					"client",
+					client.ClientID,
+					"error",
+					err.Error(),
+				)
 				logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 				return
 			}
@@ -310,7 +321,11 @@ func updateNetworkACLv2(w http.ResponseWriter, r *http.Request) {
 		// update ingress gateways of associated clients
 		hosts, err := logic.GetAllHosts()
 		if err != nil {
-			slog.Error("failed to fetch hosts after network ACL update. skipping publish extclients ACL", "network", netname)
+			slog.Error(
+				"failed to fetch hosts after network ACL update. skipping publish extclients ACL",
+				"network",
+				netname,
+			)
 			return
 		}
 		hostsMap := make(map[uuid.UUID]models.Host)
@@ -320,7 +335,13 @@ func updateNetworkACLv2(w http.ResponseWriter, r *http.Request) {
 		for hostId, clients := range assocClientsToDisconnectPerHost {
 			if host, ok := hostsMap[hostId]; ok {
 				if err = mq.PublishSingleHostPeerUpdate(&host, allNodes, nil, clients, false); err != nil {
-					slog.Error("failed to publish peer update to ingress after ACL update on network", "network", netname, "host", hostId)
+					slog.Error(
+						"failed to publish peer update to ingress after ACL update on network",
+						"network",
+						netname,
+						"host",
+						hostId,
+					)
 				}
 			}
 		}
@@ -330,17 +351,14 @@ func updateNetworkACLv2(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(networkACLChange)
 }
 
-// swagger:route GET /api/networks/{networkname}/acls networks getNetworkACL
-//
-// Get a network ACL (Access Control List).
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: aclContainerResponse
+// @Summary     Get a network ACL (Access Control List)
+// @Router      /api/networks/{networkname}/acls [get]
+// @Tags        Networks
+// @Security    oauth
+// @Param       networkname path string true "Network name"
+// @Produce     json
+// @Success     200 {object} acls.ACLContainer
+// @Failure     500 {object} models.ErrorResponse
 func getNetworkACL(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	var params = mux.Vars(r)
@@ -364,17 +382,15 @@ func getNetworkACL(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(networkACL)
 }
 
-// swagger:route DELETE /api/networks/{networkname} networks deleteNetwork
-//
-// Delete a network.  Will not delete if there are any nodes that belong to the network.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: successResponse
+// @Summary     Delete a network
+// @Router      /api/networks/{networkname} [delete]
+// @Tags        Networks
+// @Security    oauth
+// @Param       networkname path string true "Network name"
+// @Produce     json
+// @Success     200 {object} models.SuccessResponse
+// @Failure     400 {object} models.ErrorResponse
+// @Failure     403 {object} models.ErrorResponse
 func deleteNetwork(w http.ResponseWriter, r *http.Request) {
 	// Set header
 	w.Header().Set("Content-Type", "application/json")
@@ -398,17 +414,14 @@ func deleteNetwork(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode("success")
 }
 
-// swagger:route POST /api/networks networks createNetwork
-//
-// Create a network.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: networkBodyResponse
+// @Summary     Create a network
+// @Router      /api/networks [post]
+// @Tags        Networks
+// @Security    oauth
+// @Param       body body models.Network true "Network details"
+// @Produce     json
+// @Success     200 {object} models.Network
+// @Failure     400 {object} models.ErrorResponse
 func createNetwork(w http.ResponseWriter, r *http.Request) {
 
 	w.Header().Set("Content-Type", "application/json")
@@ -473,7 +486,14 @@ func createNetwork(w http.ResponseWriter, r *http.Request) {
 			currHost := &defaultHosts[i]
 			newNode, err := logic.UpdateHostNetwork(currHost, network.NetID, true)
 			if err != nil {
-				logger.Log(0, r.Header.Get("user"), "failed to add host to network:", currHost.ID.String(), network.NetID, err.Error())
+				logger.Log(
+					0,
+					r.Header.Get("user"),
+					"failed to add host to network:",
+					currHost.ID.String(),
+					network.NetID,
+					err.Error(),
+				)
 				logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 				return
 			}
@@ -483,7 +503,14 @@ func createNetwork(w http.ResponseWriter, r *http.Request) {
 				Host:   *currHost,
 				Node:   *newNode,
 			}); err != nil {
-				logger.Log(0, r.Header.Get("user"), "failed to add host to network:", currHost.ID.String(), network.NetID, err.Error())
+				logger.Log(
+					0,
+					r.Header.Get("user"),
+					"failed to add host to network:",
+					currHost.ID.String(),
+					network.NetID,
+					err.Error(),
+				)
 			}
 			// make  host failover
 			logic.CreateFailOver(*newNode)
@@ -501,17 +528,15 @@ func createNetwork(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(network)
 }
 
-// swagger:route PUT /api/networks/{networkname} networks updateNetwork
-//
-// Update pro settings for a network.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: networkBodyResponse
+// @Summary     Update network settings
+// @Router      /api/networks/{networkname} [put]
+// @Tags        Networks
+// @Security    oauth
+// @Param       networkname path string true "Network name"
+// @Param       body body models.Network true "Network details"
+// @Produce     json
+// @Success     200 {object} models.Network
+// @Failure     400 {object} models.ErrorResponse
 func updateNetwork(w http.ResponseWriter, r *http.Request) {
 
 	w.Header().Set("Content-Type", "application/json")

+ 144 - 132
controllers/node.go

@@ -21,30 +21,28 @@ var hostIDHeader = "host-id"
 
 func nodeHandlers(r *mux.Router) {
 
-	r.HandleFunc("/api/nodes", Authorize(false, false, "user", http.HandlerFunc(getAllNodes))).Methods(http.MethodGet)
-	r.HandleFunc("/api/nodes/{network}", Authorize(false, true, "network", http.HandlerFunc(getNetworkNodes))).Methods(http.MethodGet)
-	r.HandleFunc("/api/nodes/{network}/{nodeid}", Authorize(true, true, "node", http.HandlerFunc(getNode))).Methods(http.MethodGet)
-	r.HandleFunc("/api/nodes/{network}/{nodeid}", logic.SecurityCheck(true, http.HandlerFunc(updateNode))).Methods(http.MethodPut)
-	r.HandleFunc("/api/nodes/{network}/{nodeid}", Authorize(true, true, "node", http.HandlerFunc(deleteNode))).Methods(http.MethodDelete)
-	r.HandleFunc("/api/nodes/{network}/{nodeid}/creategateway", logic.SecurityCheck(true, checkFreeTierLimits(limitChoiceEgress, http.HandlerFunc(createEgressGateway)))).Methods(http.MethodPost)
-	r.HandleFunc("/api/nodes/{network}/{nodeid}/deletegateway", logic.SecurityCheck(true, http.HandlerFunc(deleteEgressGateway))).Methods(http.MethodDelete)
-	r.HandleFunc("/api/nodes/{network}/{nodeid}/createingress", logic.SecurityCheck(true, checkFreeTierLimits(limitChoiceIngress, http.HandlerFunc(createIngressGateway)))).Methods(http.MethodPost)
-	r.HandleFunc("/api/nodes/{network}/{nodeid}/deleteingress", logic.SecurityCheck(true, http.HandlerFunc(deleteIngressGateway))).Methods(http.MethodDelete)
+	r.HandleFunc("/api/nodes", Authorize(false, false, "user", http.HandlerFunc(getAllNodes))).
+		Methods(http.MethodGet)
+	r.HandleFunc("/api/nodes/{network}", Authorize(false, true, "network", http.HandlerFunc(getNetworkNodes))).
+		Methods(http.MethodGet)
+	r.HandleFunc("/api/nodes/{network}/{nodeid}", Authorize(true, true, "node", http.HandlerFunc(getNode))).
+		Methods(http.MethodGet)
+	r.HandleFunc("/api/nodes/{network}/{nodeid}", logic.SecurityCheck(true, http.HandlerFunc(updateNode))).
+		Methods(http.MethodPut)
+	r.HandleFunc("/api/nodes/{network}/{nodeid}", Authorize(true, true, "node", http.HandlerFunc(deleteNode))).
+		Methods(http.MethodDelete)
+	r.HandleFunc("/api/nodes/{network}/{nodeid}/creategateway", logic.SecurityCheck(true, checkFreeTierLimits(limitChoiceEgress, http.HandlerFunc(createEgressGateway)))).
+		Methods(http.MethodPost)
+	r.HandleFunc("/api/nodes/{network}/{nodeid}/deletegateway", logic.SecurityCheck(true, http.HandlerFunc(deleteEgressGateway))).
+		Methods(http.MethodDelete)
+	r.HandleFunc("/api/nodes/{network}/{nodeid}/createingress", logic.SecurityCheck(true, checkFreeTierLimits(limitChoiceIngress, http.HandlerFunc(createIngressGateway)))).
+		Methods(http.MethodPost)
+	r.HandleFunc("/api/nodes/{network}/{nodeid}/deleteingress", logic.SecurityCheck(true, http.HandlerFunc(deleteIngressGateway))).
+		Methods(http.MethodDelete)
 	r.HandleFunc("/api/nodes/adm/{network}/authenticate", authenticate).Methods(http.MethodPost)
 	r.HandleFunc("/api/v1/nodes/migrate", migrate).Methods(http.MethodPost)
 }
 
-// swagger:route POST /api/nodes/adm/{network}/authenticate authenticate authenticate
-//
-// Authenticate to make further API calls related to a network.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: successResponse
 func authenticate(response http.ResponseWriter, request *http.Request) {
 
 	var authRequest models.AuthParams
@@ -149,7 +147,11 @@ func authenticate(response http.ResponseWriter, request *http.Request) {
 // even if it's technically ok
 // This is kind of a poor man's RBAC. There's probably a better/smarter way.
 // TODO: Consider better RBAC implementations
-func Authorize(hostAllowed, networkCheck bool, authNetwork string, next http.Handler) http.HandlerFunc {
+func Authorize(
+	hostAllowed, networkCheck bool,
+	authNetwork string,
+	next http.Handler,
+) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		var errorResponse = models.ErrorResponse{
 			Code: http.StatusForbidden, Message: logic.Forbidden_Msg,
@@ -258,17 +260,12 @@ func Authorize(hostAllowed, networkCheck bool, authNetwork string, next http.Han
 	}
 }
 
-// swagger:route GET /api/nodes/{network} nodes getNetworkNodes
-//
-// Gets all nodes associated with network including pending nodes.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: nodeSliceResponse
+// @Summary     Gets all nodes associated with network including pending nodes
+// @Router      /api/nodes/adm/{network} [get]
+// @Securitydefinitions.oauth2.application OAuth2Application
+// @Tags        Nodes
+// @Success     200 {array} models.Node
+// @Failure     500 {object} models.ErrorResponse
 func getNetworkNodes(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	var params = mux.Vars(r)
@@ -288,18 +285,12 @@ func getNetworkNodes(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(apiNodes)
 }
 
-// swagger:route GET /api/nodes nodes getAllNodes
-//
-// Get all nodes across all networks.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: nodeSliceResponse
-//
+// @Summary     Get all nodes across all networks
+// @Router      /api/nodes [get]
+// @Tags        Nodes
+// @Securitydefinitions.oauth2.application OAuth2Application
+// @Success     200 {array} models.ApiNode
+// @Failure     500 {object} models.ErrorResponse
 // 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) {
 	w.Header().Set("Content-Type", "application/json")
@@ -327,17 +318,12 @@ func getAllNodes(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(apiNodes)
 }
 
-// swagger:route GET /api/nodes/{network}/{nodeid} nodes getNode
-//
-// Get an individual node.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: nodeResponse
+// @Summary     Get an individual node
+// @Router      /api/nodes/{network}/{nodeid} [get]
+// @Tags        Nodes
+// @Security    oauth2
+// @Success     200 {object} models.NodeGet
+// @Failure     500 {object} models.ErrorResponse
 func getNode(w http.ResponseWriter, r *http.Request) {
 	// set header.
 	w.Header().Set("Content-Type", "application/json")
@@ -359,15 +345,29 @@ func getNode(w http.ResponseWriter, r *http.Request) {
 	}
 	allNodes, err := logic.GetAllNodes()
 	if err != nil {
-		logger.Log(0, r.Header.Get("user"),
-			fmt.Sprintf("error fetching wg peers config for host [ %s ]: %v", host.ID.String(), err))
+		logger.Log(
+			0,
+			r.Header.Get("user"),
+			fmt.Sprintf(
+				"error fetching wg peers config for host [ %s ]: %v",
+				host.ID.String(),
+				err,
+			),
+		)
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 		return
 	}
 	hostPeerUpdate, err := logic.GetPeerUpdateForHost(node.Network, host, allNodes, nil, nil)
 	if err != nil && !database.IsEmptyRecord(err) {
-		logger.Log(0, r.Header.Get("user"),
-			fmt.Sprintf("error fetching wg peers config for host [ %s ]: %v", host.ID.String(), err))
+		logger.Log(
+			0,
+			r.Header.Get("user"),
+			fmt.Sprintf(
+				"error fetching wg peers config for host [ %s ]: %v",
+				host.ID.String(),
+				err,
+			),
+		)
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 		return
 	}
@@ -388,17 +388,12 @@ func getNode(w http.ResponseWriter, r *http.Request) {
 
 // == EGRESS ==
 
-// swagger:route POST /api/nodes/{network}/{nodeid}/creategateway nodes createEgressGateway
-//
-// Create an egress gateway.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: nodeResponse
+// @Summary     Create an egress gateway
+// @Router      /api/nodes/{network}/{nodeid}/creategateway [post]
+// @Tags        Nodes
+// @Security    oauth2
+// @Success     200 {object} models.ApiNode
+// @Failure     500 {object} models.ErrorResponse
 func createEgressGateway(w http.ResponseWriter, r *http.Request) {
 	var gateway models.EgressGatewayRequest
 	var params = mux.Vars(r)
@@ -431,7 +426,14 @@ func createEgressGateway(w http.ResponseWriter, r *http.Request) {
 	}
 
 	apiNode := node.ConvertToAPINode()
-	logger.Log(1, r.Header.Get("user"), "created egress gateway on node", gateway.NodeID, "on network", gateway.NetID)
+	logger.Log(
+		1,
+		r.Header.Get("user"),
+		"created egress gateway on node",
+		gateway.NodeID,
+		"on network",
+		gateway.NetID,
+	)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(apiNode)
 	go func() {
@@ -442,17 +444,12 @@ func createEgressGateway(w http.ResponseWriter, r *http.Request) {
 	}()
 }
 
-// swagger:route DELETE /api/nodes/{network}/{nodeid}/deletegateway nodes deleteEgressGateway
-//
-// Delete an egress gateway.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: nodeResponse
+// @Summary     Delete an egress gateway
+// @Router      /api/nodes/{network}/{nodeid}/deletegateway [delete]
+// @Tags        Nodes
+// @Security    oauth2
+// @Success     200 {object} models.ApiNode
+// @Failure     500 {object} models.ErrorResponse
 func deleteEgressGateway(w http.ResponseWriter, r *http.Request) {
 
 	w.Header().Set("Content-Type", "application/json")
@@ -474,7 +471,14 @@ func deleteEgressGateway(w http.ResponseWriter, r *http.Request) {
 	}
 
 	apiNode := node.ConvertToAPINode()
-	logger.Log(1, r.Header.Get("user"), "deleted egress gateway on node", nodeid, "on network", netid)
+	logger.Log(
+		1,
+		r.Header.Get("user"),
+		"deleted egress gateway on node",
+		nodeid,
+		"on network",
+		netid,
+	)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(apiNode)
 	go func() {
@@ -487,17 +491,12 @@ func deleteEgressGateway(w http.ResponseWriter, r *http.Request) {
 
 // == INGRESS ==
 
-// swagger:route POST /api/nodes/{network}/{nodeid}/createingress nodes createIngressGateway
-//
-// Create an ingress gateway.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: nodeResponse
+// @Summary     Create an remote access gateway
+// @Router      /api/nodes/{network}/{nodeid}/createingress [post]
+// @Tags        Nodes
+// @Security    oauth2
+// @Success     200 {object} models.ApiNode
+// @Failure     500 {object} models.ErrorResponse
 func createIngressGateway(w http.ResponseWriter, r *http.Request) {
 	var params = mux.Vars(r)
 	w.Header().Set("Content-Type", "application/json")
@@ -520,7 +519,14 @@ func createIngressGateway(w http.ResponseWriter, r *http.Request) {
 	}
 
 	apiNode := node.ConvertToAPINode()
-	logger.Log(1, r.Header.Get("user"), "created ingress gateway on node", nodeid, "on network", netid)
+	logger.Log(
+		1,
+		r.Header.Get("user"),
+		"created ingress gateway on node",
+		nodeid,
+		"on network",
+		netid,
+	)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(apiNode)
 	go func() {
@@ -530,17 +536,12 @@ func createIngressGateway(w http.ResponseWriter, r *http.Request) {
 	}()
 }
 
-// swagger:route DELETE /api/nodes/{network}/{nodeid}/deleteingress nodes deleteIngressGateway
-//
-// Delete an ingress gateway.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: nodeResponse
+// @Summary     Delete an remote access gateway
+// @Router      /api/nodes/{network}/{nodeid}/deleteingress [delete]
+// @Tags        Nodes
+// @Security    oauth2
+// @Success     200 {object} models.ApiNode
+// @Failure     500 {object} models.ErrorResponse
 func deleteIngressGateway(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	var params = mux.Vars(r)
@@ -596,7 +597,13 @@ func deleteIngressGateway(w http.ResponseWriter, r *http.Request) {
 					slog.Error("publishSingleHostUpdate", "host", host.Name, "error", err)
 				}
 				if err := mq.NodeUpdate(&node); err != nil {
-					slog.Error("error publishing node update to node", "node", node.ID, "error", err)
+					slog.Error(
+						"error publishing node update to node",
+						"node",
+						node.ID,
+						"error",
+						err,
+					)
 				}
 				if servercfg.IsDNSMode() {
 					logic.SetDNS()
@@ -606,17 +613,12 @@ func deleteIngressGateway(w http.ResponseWriter, r *http.Request) {
 	}
 }
 
-// swagger:route PUT /api/nodes/{network}/{nodeid} nodes updateNode
-//
-// Update an individual node.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: nodeResponse
+// @Summary     Update an individual node
+// @Router      /api/nodes/{network}/{nodeid} [put]
+// @Tags        Nodes
+// @Security    oauth2
+// @Success     200 {object} models.ApiNode
+// @Failure     500 {object} models.ErrorResponse
 func updateNode(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 
@@ -642,7 +644,11 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
 	}
 	newNode := newData.ConvertToServerNode(&currentNode)
 	if newNode == nil {
-		logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("error converting node"), "badrequest"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(fmt.Errorf("error converting node"), "badrequest"),
+		)
 		return
 	}
 	if newNode.IsInternetGateway != currentNode.IsInternetGateway {
@@ -686,7 +692,14 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
 	}
 
 	apiNode := newNode.ConvertToAPINode()
-	logger.Log(1, r.Header.Get("user"), "updated node", currentNode.ID.String(), "on network", currentNode.Network)
+	logger.Log(
+		1,
+		r.Header.Get("user"),
+		"updated node",
+		currentNode.ID.String(),
+		"on network",
+		currentNode.Network,
+	)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(apiNode)
 	go func(aclUpdate, relayupdate bool, newNode *models.Node) {
@@ -704,17 +717,12 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
 	}(aclUpdate, relayUpdate, newNode)
 }
 
-// swagger:route DELETE /api/nodes/{network}/{nodeid} nodes deleteNode
-//
-// Delete an individual node.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: nodeResponse
+// @Summary     Delete an individual node
+// @Router      /api/nodes/{network}/{nodeid} [delete]
+// @Tags        Nodes
+// @Security    oauth2
+// @Success     200 {string} string "Node deleted."
+// @Failure     500 {object} models.ErrorResponse
 func deleteNode(w http.ResponseWriter, r *http.Request) {
 	// Set header
 	w.Header().Set("Content-Type", "application/json")
@@ -735,7 +743,11 @@ func deleteNode(w http.ResponseWriter, r *http.Request) {
 	}
 	purge := forceDelete || fromNode
 	if err := logic.DeleteNode(&node, purge); err != nil {
-		logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to delete node"), "internal"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(fmt.Errorf("failed to delete node"), "internal"),
+		)
 		return
 	}
 

+ 17 - 34
controllers/server.go

@@ -102,18 +102,12 @@ func getUsage(w http.ResponseWriter, _ *http.Request) {
 	})
 }
 
-// swagger:route GET /api/server/status server getStatus
-//
-// Get the server configuration.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: serverConfigResponse
+// @Summary     Get the server status
+// @Router      /api/server/status [get]
+// @Tags        Server
+// @Security    oauth2
 func getStatus(w http.ResponseWriter, r *http.Request) {
+	// @Success     200 {object} status
 	type status struct {
 		DB               bool      `json:"db_connected"`
 		Broker           bool      `json:"broker_connected"`
@@ -131,7 +125,8 @@ func getStatus(w http.ResponseWriter, r *http.Request) {
 	var trialEndDate time.Time
 	var err error
 	isOnTrial := false
-	if servercfg.IsPro && (servercfg.GetLicenseKey() == "" || servercfg.GetNetmakerTenantID() == "") {
+	if servercfg.IsPro &&
+		(servercfg.GetLicenseKey() == "" || servercfg.GetNetmakerTenantID() == "") {
 		trialEndDate, err = logic.GetTrialEndDate()
 		if err != nil {
 			slog.Error("failed to get trial end date", "error", err)
@@ -177,17 +172,11 @@ func allowUsers(next http.Handler) http.HandlerFunc {
 	}
 }
 
-// swagger:route GET /api/server/getserverinfo server getServerInfo
-//
-// Get the server configuration.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: serverConfigResponse
+// @Summary     Get the server information
+// @Router      /api/server/getserverinfo [get]
+// @Tags        Server
+// @Security    oauth2
+// @Success     200 {object} models.ServerConfig
 func getServerInfo(w http.ResponseWriter, r *http.Request) {
 	// Set header
 	w.Header().Set("Content-Type", "application/json")
@@ -198,17 +187,11 @@ func getServerInfo(w http.ResponseWriter, r *http.Request) {
 	// w.WriteHeader(http.StatusOK)
 }
 
-// swagger:route GET /api/server/getconfig server getConfig
-//
-// Get the server configuration.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: serverConfigResponse
+// @Summary     Get the server configuration
+// @Router      /api/server/getconfig [get]
+// @Tags        Server
+// @Security    oauth2
+// @Success     200 {object} config.ServerConfig
 func getConfig(w http.ResponseWriter, r *http.Request) {
 	// Set header
 	w.Header().Set("Content-Type", "application/json")

+ 297 - 182
controllers/user.go

@@ -25,31 +25,39 @@ var (
 func userHandlers(r *mux.Router) {
 	r.HandleFunc("/api/users/adm/hassuperadmin", hasSuperAdmin).Methods(http.MethodGet)
 	r.HandleFunc("/api/users/adm/createsuperadmin", createSuperAdmin).Methods(http.MethodPost)
-	r.HandleFunc("/api/users/adm/transfersuperadmin/{username}", logic.SecurityCheck(true, http.HandlerFunc(transferSuperAdmin))).Methods(http.MethodPost)
+	r.HandleFunc("/api/users/adm/transfersuperadmin/{username}", logic.SecurityCheck(true, http.HandlerFunc(transferSuperAdmin))).
+		Methods(http.MethodPost)
 	r.HandleFunc("/api/users/adm/authenticate", authenticateUser).Methods(http.MethodPost)
-	r.HandleFunc("/api/users/{username}", logic.SecurityCheck(true, http.HandlerFunc(updateUser))).Methods(http.MethodPut)
-	r.HandleFunc("/api/users/{username}", logic.SecurityCheck(true, checkFreeTierLimits(limitChoiceUsers, http.HandlerFunc(createUser)))).Methods(http.MethodPost)
-	r.HandleFunc("/api/users/{username}", logic.SecurityCheck(true, http.HandlerFunc(deleteUser))).Methods(http.MethodDelete)
-	r.HandleFunc("/api/users/{username}", logic.SecurityCheck(false, logic.ContinueIfUserMatch(http.HandlerFunc(getUser)))).Methods(http.MethodGet)
-	r.HandleFunc("/api/users", logic.SecurityCheck(true, http.HandlerFunc(getUsers))).Methods(http.MethodGet)
-	r.HandleFunc("/api/users_pending", logic.SecurityCheck(true, http.HandlerFunc(getPendingUsers))).Methods(http.MethodGet)
-	r.HandleFunc("/api/users_pending", logic.SecurityCheck(true, http.HandlerFunc(deleteAllPendingUsers))).Methods(http.MethodDelete)
-	r.HandleFunc("/api/users_pending/user/{username}", logic.SecurityCheck(true, http.HandlerFunc(deletePendingUser))).Methods(http.MethodDelete)
-	r.HandleFunc("/api/users_pending/user/{username}", logic.SecurityCheck(true, http.HandlerFunc(approvePendingUser))).Methods(http.MethodPost)
+	r.HandleFunc("/api/users/{username}", logic.SecurityCheck(true, http.HandlerFunc(updateUser))).
+		Methods(http.MethodPut)
+	r.HandleFunc("/api/users/{username}", logic.SecurityCheck(true, checkFreeTierLimits(limitChoiceUsers, http.HandlerFunc(createUser)))).
+		Methods(http.MethodPost)
+	r.HandleFunc("/api/users/{username}", logic.SecurityCheck(true, http.HandlerFunc(deleteUser))).
+		Methods(http.MethodDelete)
+	r.HandleFunc("/api/users/{username}", logic.SecurityCheck(false, logic.ContinueIfUserMatch(http.HandlerFunc(getUser)))).
+		Methods(http.MethodGet)
+	r.HandleFunc("/api/users", logic.SecurityCheck(true, http.HandlerFunc(getUsers))).
+		Methods(http.MethodGet)
+	r.HandleFunc("/api/users_pending", logic.SecurityCheck(true, http.HandlerFunc(getPendingUsers))).
+		Methods(http.MethodGet)
+	r.HandleFunc("/api/users_pending", logic.SecurityCheck(true, http.HandlerFunc(deleteAllPendingUsers))).
+		Methods(http.MethodDelete)
+	r.HandleFunc("/api/users_pending/user/{username}", logic.SecurityCheck(true, http.HandlerFunc(deletePendingUser))).
+		Methods(http.MethodDelete)
+	r.HandleFunc("/api/users_pending/user/{username}", logic.SecurityCheck(true, http.HandlerFunc(approvePendingUser))).
+		Methods(http.MethodPost)
 
 }
 
-// swagger:route POST /api/users/adm/authenticate authenticate authenticateUser
-//
-// User authenticates using its password and retrieves a JWT for authorization.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: successResponse
+// @Summary     Authenticate a user to retrieve an authorization token
+// @Router      /api/users/adm/authenticate [post]
+// @Tags        Auth
+// @Accept      json
+// @Param       body body models.UserAuthParams true "Authentication parameters"
+// @Success     200 {object} models.SuccessResponse
+// @Failure     400 {object} models.ErrorResponse
+// @Failure     401 {object} models.ErrorResponse
+// @Failure     500 {object} models.ErrorResponse
 func authenticateUser(response http.ResponseWriter, request *http.Request) {
 
 	// Auth request consists of Mac Address and Password (from node that is authorizing
@@ -60,7 +68,11 @@ func authenticateUser(response http.ResponseWriter, request *http.Request) {
 	}
 
 	if !servercfg.IsBasicAuthEnabled() {
-		logic.ReturnErrorResponse(response, request, logic.FormatError(fmt.Errorf("basic auth is disabled"), "badrequest"))
+		logic.ReturnErrorResponse(
+			response,
+			request,
+			logic.FormatError(fmt.Errorf("basic auth is disabled"), "badrequest"),
+		)
 		return
 	}
 
@@ -83,7 +95,11 @@ func authenticateUser(response http.ResponseWriter, request *http.Request) {
 			return
 		}
 		if !(user.IsAdmin || user.IsSuperAdmin) {
-			logic.ReturnErrorResponse(response, request, logic.FormatError(errors.New("only admins can access dashboard"), "unauthorized"))
+			logic.ReturnErrorResponse(
+				response,
+				request,
+				logic.FormatError(errors.New("only admins can access dashboard"), "unauthorized"),
+			)
 			return
 		}
 	}
@@ -99,7 +115,11 @@ func authenticateUser(response http.ResponseWriter, request *http.Request) {
 	if jwt == "" {
 		// very unlikely that err is !nil and no jwt returned, but handle it anyways.
 		logger.Log(0, username, "jwt token is empty")
-		logic.ReturnErrorResponse(response, request, logic.FormatError(errors.New("no token returned"), "internal"))
+		logic.ReturnErrorResponse(
+			response,
+			request,
+			logic.FormatError(errors.New("no token returned"), "internal"),
+		)
 		return
 	}
 
@@ -133,9 +153,19 @@ func authenticateUser(response http.ResponseWriter, request *http.Request) {
 			}
 			for _, client := range clients {
 				if client.OwnerID == username && !client.Enabled {
-					slog.Info(fmt.Sprintf("enabling ext client %s for user %s due to RAC autodisabling feature", client.ClientID, client.OwnerID))
+					slog.Info(
+						fmt.Sprintf(
+							"enabling ext client %s for user %s due to RAC autodisabling feature",
+							client.ClientID,
+							client.OwnerID,
+						),
+					)
 					if newClient, err := logic.ToggleExtClientConnectivity(&client, true); err != nil {
-						slog.Error("error enabling ext client in RAC autodisable hook", "error", err)
+						slog.Error(
+							"error enabling ext client in RAC autodisable hook",
+							"error",
+							err,
+						)
 						continue // dont return but try for other clients
 					} else {
 						// publish peer update to ingress gateway
@@ -151,17 +181,11 @@ func authenticateUser(response http.ResponseWriter, request *http.Request) {
 	}()
 }
 
-// swagger:route GET /api/users/adm/hassuperadmin user hasSuperAdmin
-//
-// Checks whether the server has an admin.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: hasAdmin
+// @Summary     Check if the server has a super admin
+// @Router      /api/users/adm/hassuperadmin [get]
+// @Tags        Users
+// @Success     200 {object} bool
+// @Failure     500 {object} models.ErrorResponse
 func hasSuperAdmin(w http.ResponseWriter, r *http.Request) {
 
 	w.Header().Set("Content-Type", "application/json")
@@ -177,17 +201,12 @@ func hasSuperAdmin(w http.ResponseWriter, r *http.Request) {
 
 }
 
-// swagger:route GET /api/users/{username} user getUser
-//
-// Get an individual user.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: userBodyResponse
+// @Summary     Get an individual user
+// @Router      /api/users/{username} [get]
+// @Tags        Users
+// @Param       username path string true "Username of the user to fetch"
+// @Success     200 {object} models.User
+// @Failure     500 {object} models.ErrorResponse
 func getUser(w http.ResponseWriter, r *http.Request) {
 	// set header.
 	w.Header().Set("Content-Type", "application/json")
@@ -205,17 +224,11 @@ func getUser(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(user)
 }
 
-// swagger:route GET /api/users user getUsers
-//
-// Get all users.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: userBodyResponse
+// @Summary     Get all users
+// @Router      /api/users [get]
+// @Tags        Users
+// @Success     200 {array} models.User
+// @Failure     500 {object} models.ErrorResponse
 func getUsers(w http.ResponseWriter, r *http.Request) {
 	// set header.
 	w.Header().Set("Content-Type", "application/json")
@@ -233,17 +246,13 @@ func getUsers(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(users)
 }
 
-// swagger:route POST /api/users/adm/createsuperadmin user createAdmin
-//
-// Make a user an admin.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: userBodyResponse
+// @Summary     Create a super admin
+// @Router      /api/users/adm/createsuperadmin [post]
+// @Tags        Users
+// @Param       body body models.User true "User details"
+// @Success     200 {object} models.User
+// @Failure     400 {object} models.ErrorResponse
+// @Failure     500 {object} models.ErrorResponse
 func createSuperAdmin(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 
@@ -257,7 +266,11 @@ func createSuperAdmin(w http.ResponseWriter, r *http.Request) {
 	}
 
 	if !servercfg.IsBasicAuthEnabled() {
-		logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("basic auth is disabled"), "badrequest"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(fmt.Errorf("basic auth is disabled"), "badrequest"),
+		)
 		return
 	}
 
@@ -271,17 +284,13 @@ func createSuperAdmin(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(logic.ToReturnUser(u))
 }
 
-// swagger:route POST /api/users/adm/transfersuperadmin user transferSuperAdmin
-//
-// Transfers superadmin role to an admin user.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: userBodyResponse
+// @Summary     Transfer super admin role to another admin user
+// @Router      /api/users/adm/transfersuperadmin/{username} [post]
+// @Tags        Users
+// @Param       username path string true "Username of the user to transfer super admin role"
+// @Success     200 {object} models.User
+// @Failure     403 {object} models.ErrorResponse
+// @Failure     500 {object} models.ErrorResponse
 func transferSuperAdmin(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	caller, err := logic.GetUser(r.Header.Get("user"))
@@ -289,7 +298,14 @@ func transferSuperAdmin(w http.ResponseWriter, r *http.Request) {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 	}
 	if !caller.IsSuperAdmin {
-		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("only superadmin can assign the superadmin role to another user"), "forbidden"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(
+				errors.New("only superadmin can assign the superadmin role to another user"),
+				"forbidden",
+			),
+		)
 		return
 	}
 	var params = mux.Vars(r)
@@ -301,11 +317,22 @@ func transferSuperAdmin(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 	if !u.IsAdmin {
-		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("only admins can be promoted to superadmin role"), "forbidden"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(
+				errors.New("only admins can be promoted to superadmin role"),
+				"forbidden",
+			),
+		)
 		return
 	}
 	if !servercfg.IsBasicAuthEnabled() {
-		logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("basic auth is disabled"), "badrequest"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(fmt.Errorf("basic auth is disabled"), "badrequest"),
+		)
 		return
 	}
 
@@ -329,17 +356,15 @@ func transferSuperAdmin(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(logic.ToReturnUser(*u))
 }
 
-// swagger:route POST /api/users/{username} user createUser
-//
-// Create a user.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: userBodyResponse
+// @Summary     Create a user
+// @Router      /api/users/{username} [post]
+// @Tags        Users
+// @Param       username path string true "Username of the user to create"
+// @Param       body body models.User true "User details"
+// @Success     200 {object} models.User
+// @Failure     400 {object} models.ErrorResponse
+// @Failure     403 {object} models.ErrorResponse
+// @Failure     500 {object} models.ErrorResponse
 func createUser(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	caller, err := logic.GetUser(r.Header.Get("user"))
@@ -368,7 +393,14 @@ func createUser(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 	if !servercfg.IsPro && !user.IsAdmin {
-		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("non-admins users can only be created on Pro version"), "forbidden"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(
+				errors.New("non-admins users can only be created on Pro version"),
+				"forbidden",
+			),
+		)
 		return
 	}
 
@@ -382,17 +414,15 @@ func createUser(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(logic.ToReturnUser(user))
 }
 
-// swagger:route PUT /api/users/{username} user updateUser
-//
-// Update a user.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: userBodyResponse
+// @Summary     Update a user
+// @Router      /api/users/{username} [put]
+// @Tags        Users
+// @Param       username path string true "Username of the user to update"
+// @Param       body body models.User true "User details"
+// @Success     200 {object} models.User
+// @Failure     400 {object} models.ErrorResponse
+// @Failure     403 {object} models.ErrorResponse
+// @Failure     500 {object} models.ErrorResponse
 func updateUser(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	var params = mux.Vars(r)
@@ -426,7 +456,14 @@ func updateUser(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 	if user.UserName != userchange.UserName {
-		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("user in param and request body not matching"), "badrequest"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(
+				errors.New("user in param and request body not matching"),
+				"badrequest",
+			),
+		)
 		return
 	}
 	selfUpdate := false
@@ -436,23 +473,64 @@ func updateUser(w http.ResponseWriter, r *http.Request) {
 
 	if !ismaster && !selfUpdate {
 		if caller.IsAdmin && user.IsSuperAdmin {
-			slog.Error("non-superadmin user", "caller", caller.UserName, "attempted to update superadmin user", username)
-			logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("cannot update superadmin user"), "forbidden"))
+			slog.Error(
+				"non-superadmin user",
+				"caller",
+				caller.UserName,
+				"attempted to update superadmin user",
+				username,
+			)
+			logic.ReturnErrorResponse(
+				w,
+				r,
+				logic.FormatError(errors.New("cannot update superadmin user"), "forbidden"),
+			)
 			return
 		}
 		if !caller.IsAdmin && !caller.IsSuperAdmin {
-			slog.Error("operation not allowed", "caller", caller.UserName, "attempted to update user", username)
-			logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("cannot update superadmin user"), "forbidden"))
+			slog.Error(
+				"operation not allowed",
+				"caller",
+				caller.UserName,
+				"attempted to update user",
+				username,
+			)
+			logic.ReturnErrorResponse(
+				w,
+				r,
+				logic.FormatError(errors.New("cannot update superadmin user"), "forbidden"),
+			)
 			return
 		}
 		if caller.IsAdmin && user.IsAdmin {
-			slog.Error("admin user cannot update another admin", "caller", caller.UserName, "attempted to update admin user", username)
-			logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("admin user cannot update another admin"), "forbidden"))
+			slog.Error(
+				"admin user cannot update another admin",
+				"caller",
+				caller.UserName,
+				"attempted to update admin user",
+				username,
+			)
+			logic.ReturnErrorResponse(
+				w,
+				r,
+				logic.FormatError(
+					errors.New("admin user cannot update another admin"),
+					"forbidden",
+				),
+			)
 			return
 		}
 		if caller.IsAdmin && userchange.IsAdmin {
 			err = errors.New("admin user cannot update role of an another user to admin")
-			slog.Error("failed to update user", "caller", caller.UserName, "attempted to update user", username, "error", err)
+			slog.Error(
+				"failed to update user",
+				"caller",
+				caller.UserName,
+				"attempted to update user",
+				username,
+				"error",
+				err,
+			)
 			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))
 			return
 		}
@@ -460,16 +538,39 @@ func updateUser(w http.ResponseWriter, r *http.Request) {
 	}
 	if !ismaster && selfUpdate {
 		if user.IsAdmin != userchange.IsAdmin || user.IsSuperAdmin != userchange.IsSuperAdmin {
-			slog.Error("user cannot change his own role", "caller", caller.UserName, "attempted to update user role", username)
-			logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("user not allowed to self assign role"), "forbidden"))
+			slog.Error(
+				"user cannot change his own role",
+				"caller",
+				caller.UserName,
+				"attempted to update user role",
+				username,
+			)
+			logic.ReturnErrorResponse(
+				w,
+				r,
+				logic.FormatError(errors.New("user not allowed to self assign role"), "forbidden"),
+			)
 			return
 
 		}
 	}
 	if ismaster {
 		if !user.IsSuperAdmin && userchange.IsSuperAdmin {
-			slog.Error("operation not allowed", "caller", logic.MasterUser, "attempted to update user role to superadmin", username)
-			logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("attempted to update user role to superadmin"), "forbidden"))
+			slog.Error(
+				"operation not allowed",
+				"caller",
+				logic.MasterUser,
+				"attempted to update user role to superadmin",
+				username,
+			)
+			logic.ReturnErrorResponse(
+				w,
+				r,
+				logic.FormatError(
+					errors.New("attempted to update user role to superadmin"),
+					"forbidden",
+				),
+			)
 			return
 		}
 	}
@@ -491,17 +592,12 @@ func updateUser(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(logic.ToReturnUser(*user))
 }
 
-// swagger:route DELETE /api/users/{username} user deleteUser
-//
-// Delete a user.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: userBodyResponse
+// @Summary     Delete a user
+// @Router      /api/users/{username} [delete]
+// @Tags        Users
+// @Param       username path string true "Username of the user to delete"
+// @Success     200 {string} string
+// @Failure     500 {object} models.ErrorResponse
 func deleteUser(w http.ResponseWriter, r *http.Request) {
 	// Set header
 	w.Header().Set("Content-Type", "application/json")
@@ -523,14 +619,30 @@ func deleteUser(w http.ResponseWriter, r *http.Request) {
 	if user.IsSuperAdmin {
 		slog.Error(
 			"failed to delete user: ", "user", username, "error", "superadmin cannot be deleted")
-		logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("superadmin cannot be deleted"), "internal"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(fmt.Errorf("superadmin cannot be deleted"), "internal"),
+		)
 		return
 	}
 	if !caller.IsSuperAdmin {
 		if caller.IsAdmin && user.IsAdmin {
 			slog.Error(
-				"failed to delete user: ", "user", username, "error", "admin cannot delete another admin user, including oneself")
-			logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("admin cannot delete another admin user, including oneself"), "internal"))
+				"failed to delete user: ",
+				"user",
+				username,
+				"error",
+				"admin cannot delete another admin user, including oneself",
+			)
+			logic.ReturnErrorResponse(
+				w,
+				r,
+				logic.FormatError(
+					fmt.Errorf("admin cannot delete another admin user, including oneself"),
+					"internal",
+				),
+			)
 			return
 		}
 	}
@@ -586,17 +698,11 @@ func socketHandler(w http.ResponseWriter, r *http.Request) {
 	go auth.SessionHandler(conn)
 }
 
-// swagger:route GET /api/users_pending user getPendingUsers
-//
-// Get all pending users.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: userBodyResponse
+// @Summary     Get all pending users
+// @Router      /api/users_pending [get]
+// @Tags        Users
+// @Success     200 {array} models.User
+// @Failure     500 {object} models.ErrorResponse
 func getPendingUsers(w http.ResponseWriter, r *http.Request) {
 	// set header.
 	w.Header().Set("Content-Type", "application/json")
@@ -613,17 +719,12 @@ func getPendingUsers(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(users)
 }
 
-// swagger:route POST /api/users_pending/user/{username} user approvePendingUser
-//
-// approve pending user.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: userBodyResponse
+// @Summary     Approve a pending user
+// @Router      /api/users_pending/user/{username} [post]
+// @Tags        Users
+// @Param       username path string true "Username of the pending user to approve"
+// @Success     200 {string} string
+// @Failure     500 {object} models.ErrorResponse
 func approvePendingUser(w http.ResponseWriter, r *http.Request) {
 	// set header.
 	w.Header().Set("Content-Type", "application/json")
@@ -647,12 +748,23 @@ func approvePendingUser(w http.ResponseWriter, r *http.Request) {
 				UserName: user.UserName,
 				Password: newPass,
 			}); err != nil {
-				logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to create user: %s", err), "internal"))
+				logic.ReturnErrorResponse(
+					w,
+					r,
+					logic.FormatError(fmt.Errorf("failed to create user: %s", err), "internal"),
+				)
 				return
 			}
 			err = logic.DeletePendingUser(username)
 			if err != nil {
-				logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to delete pending user: %s", err), "internal"))
+				logic.ReturnErrorResponse(
+					w,
+					r,
+					logic.FormatError(
+						fmt.Errorf("failed to delete pending user: %s", err),
+						"internal",
+					),
+				)
 				return
 			}
 			break
@@ -661,17 +773,12 @@ func approvePendingUser(w http.ResponseWriter, r *http.Request) {
 	logic.ReturnSuccessResponse(w, r, "approved "+username)
 }
 
-// swagger:route DELETE /api/users_pending/user/{username} user deletePendingUser
-//
-// delete pending user.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: userBodyResponse
+// @Summary     Delete a pending user
+// @Router      /api/users_pending/user/{username} [delete]
+// @Tags        Users
+// @Param       username path string true "Username of the pending user to delete"
+// @Success     200 {string} string
+// @Failure     500 {object} models.ErrorResponse
 func deletePendingUser(w http.ResponseWriter, r *http.Request) {
 	// set header.
 	w.Header().Set("Content-Type", "application/json")
@@ -688,7 +795,14 @@ func deletePendingUser(w http.ResponseWriter, r *http.Request) {
 		if user.UserName == username {
 			err = logic.DeletePendingUser(username)
 			if err != nil {
-				logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to delete pending user: %s", err), "internal"))
+				logic.ReturnErrorResponse(
+					w,
+					r,
+					logic.FormatError(
+						fmt.Errorf("failed to delete pending user: %s", err),
+						"internal",
+					),
+				)
 				return
 			}
 			break
@@ -697,23 +811,24 @@ func deletePendingUser(w http.ResponseWriter, r *http.Request) {
 	logic.ReturnSuccessResponse(w, r, "deleted pending "+username)
 }
 
-// swagger:route DELETE /api/users_pending/{username}/pending user deleteAllPendingUsers
-//
-// delete all pending users.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: userBodyResponse
+// @Summary     Delete all pending users
+// @Router      /api/users_pending [delete]
+// @Tags        Users
+// @Success     200 {string} string
+// @Failure     500 {object} models.ErrorResponse
 func deleteAllPendingUsers(w http.ResponseWriter, r *http.Request) {
 	// set header.
 	w.Header().Set("Content-Type", "application/json")
 	err := database.DeleteAllRecords(database.PENDING_USERS_TABLE_NAME)
 	if err != nil {
-		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("failed to delete all pending users "+err.Error()), "internal"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(
+				errors.New("failed to delete all pending users "+err.Error()),
+				"internal",
+			),
+		)
 		return
 	}
 	logic.ReturnSuccessResponse(w, r, "cleared all pending users")

+ 1 - 0
docs/APIUsage.md

@@ -0,0 +1 @@
+Most actions that can be performed via API can be performed via UI. We recommend managing your networks using the official netmaker-ui project. However, Netmaker can also be run without the UI, and all functions can be achieved via API calls. If your use case requires using Netmaker without the UI or you need to do some troubleshooting/advanced configuration, using the API directly may help.

+ 10 - 0
docs/Authentication.md

@@ -0,0 +1,10 @@
+API calls are primarily authenticated using a user authentication token. This token should be included in the header as follows:
+
+-H "Authorization: Bearer <YOUR_AUTH_TOKEN>"
+
+To obtain YOUR_AUTH_TOKEN:
+Call the api/users/adm/authenticate endpoint (see documentation below for details).
+
+Note: While a MasterKey exists (configurable via env var or config file), it should be considered a backup option, used only when server access is lost. By default, this key is "secret key," but it's crucial to change this and keep it secure in your instance.
+
+For more information on configuration and security best practices, refer to the [Netmaker documentation](https://docs.netmaker.org/index.html).

+ 1 - 0
docs/Pricing.md

@@ -0,0 +1 @@
+Check out our [Pricing](https://www.netmaker.io/pricing). And Feel Free to [Contact Us](https://www.netmaker.io/contact) if you have any questions or need some clarifications.

+ 34 - 4
main.go

@@ -29,6 +29,17 @@ import (
 
 var version = "v0.25.0"
 
+//	@title			NetMaker
+//	@version		0.24.3
+//	@description	NetMaker API Docs
+//	@tag.name	    APIUsage
+//	@tag.description.markdown
+//	@tag.name	    Authentication
+//	@tag.description.markdown
+//	@tag.name	    Pricing
+//	@tag.description.markdown
+//  @host      api.demo.netmaker.io
+
 // Start DB Connection and start API Request Handler
 func main() {
 	absoluteConfigPath := flag.String("c", "", "absolute path to configuration file")
@@ -135,7 +146,10 @@ func startControllers(wg *sync.WaitGroup, ctx context.Context) {
 	}
 
 	if !servercfg.IsRestBackend() && !servercfg.IsMessageQueueBackend() {
-		logger.Log(0, "No Server Mode selected, so nothing is being served! Set Rest mode (REST_BACKEND) or MessageQueue (MESSAGEQUEUE_BACKEND) to 'true'.")
+		logger.Log(
+			0,
+			"No Server Mode selected, so nothing is being served! Set Rest mode (REST_BACKEND) or MessageQueue (MESSAGEQUEUE_BACKEND) to 'true'.",
+		)
 	}
 
 	wg.Add(1)
@@ -167,10 +181,21 @@ func runMessageQueue(wg *sync.WaitGroup, ctx context.Context) {
 			node.Action = models.NODE_DELETE
 			node.PendingDelete = true
 			if err := mq.NodeUpdate(node); err != nil {
-				logger.Log(0, "failed to send peer update for deleted node: ", node.ID.String(), err.Error())
+				logger.Log(
+					0,
+					"failed to send peer update for deleted node: ",
+					node.ID.String(),
+					err.Error(),
+				)
 			}
 			if err := logic.DeleteNode(node, true); err != nil {
-				slog.Error("error deleting expired node", "nodeid", node.ID.String(), "error", err.Error())
+				slog.Error(
+					"error deleting expired node",
+					"nodeid",
+					node.ID.String(),
+					"error",
+					err.Error(),
+				)
 			}
 			go mq.PublishDeletedNodePeerUpdate(node)
 		}
@@ -189,7 +214,12 @@ func setVerbosity() {
 		}
 		return a
 	}
-	logger := slog.New(slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{AddSource: true, ReplaceAttr: replace, Level: logLevel}))
+	logger := slog.New(
+		slog.NewJSONHandler(
+			os.Stderr,
+			&slog.HandlerOptions{AddSource: true, ReplaceAttr: replace, Level: logLevel},
+		),
+	)
 	slog.SetDefault(logger)
 	switch verbose {
 	case 4:

+ 94 - 91
models/node.go

@@ -52,111 +52,111 @@ type Iface struct {
 
 // CommonNode - represents a commonn node data elements shared by netmaker and netclient
 type CommonNode struct {
-	ID                  uuid.UUID `json:"id" yaml:"id"`
-	HostID              uuid.UUID `json:"hostid" yaml:"hostid"`
-	Network             string    `json:"network" yaml:"network"`
-	NetworkRange        net.IPNet `json:"networkrange" yaml:"networkrange"`
-	NetworkRange6       net.IPNet `json:"networkrange6" yaml:"networkrange6"`
-	Server              string    `json:"server" yaml:"server"`
-	Connected           bool      `json:"connected" yaml:"connected"`
-	Address             net.IPNet `json:"address" yaml:"address"`
-	Address6            net.IPNet `json:"address6" yaml:"address6"`
-	Action              string    `json:"action" yaml:"action"`
-	LocalAddress        net.IPNet `json:"localaddress" yaml:"localaddress"`
-	IsEgressGateway     bool      `json:"isegressgateway" yaml:"isegressgateway"`
-	EgressGatewayRanges []string  `json:"egressgatewayranges" bson:"egressgatewayranges" yaml:"egressgatewayranges"`
-	IsIngressGateway    bool      `json:"isingressgateway" yaml:"isingressgateway"`
-	IsRelayed           bool      `json:"isrelayed" bson:"isrelayed" yaml:"isrelayed"`
-	RelayedBy           string    `json:"relayedby" bson:"relayedby" yaml:"relayedby"`
-	IsRelay             bool      `json:"isrelay" bson:"isrelay" yaml:"isrelay"`
-	RelayedNodes        []string  `json:"relaynodes" yaml:"relayedNodes"`
-	IngressDNS          string    `json:"ingressdns" yaml:"ingressdns"`
-	DNSOn               bool      `json:"dnson" yaml:"dnson"`
+	ID                  uuid.UUID `json:"id"                  yaml:"id"`
+	HostID              uuid.UUID `json:"hostid"              yaml:"hostid"`
+	Network             string    `json:"network"             yaml:"network"`
+	NetworkRange        net.IPNet `json:"networkrange"        yaml:"networkrange"        swaggertype:"primitive,integer"`
+	NetworkRange6       net.IPNet `json:"networkrange6"       yaml:"networkrange6"       swaggertype:"primitive,number"`
+	Server              string    `json:"server"              yaml:"server"`
+	Connected           bool      `json:"connected"           yaml:"connected"`
+	Address             net.IPNet `json:"address"             yaml:"address"`
+	Address6            net.IPNet `json:"address6"            yaml:"address6"`
+	Action              string    `json:"action"              yaml:"action"`
+	LocalAddress        net.IPNet `json:"localaddress"        yaml:"localaddress"`
+	IsEgressGateway     bool      `json:"isegressgateway"     yaml:"isegressgateway"`
+	EgressGatewayRanges []string  `json:"egressgatewayranges" yaml:"egressgatewayranges"                                 bson:"egressgatewayranges"`
+	IsIngressGateway    bool      `json:"isingressgateway"    yaml:"isingressgateway"`
+	IsRelayed           bool      `json:"isrelayed"           yaml:"isrelayed"                                           bson:"isrelayed"`
+	RelayedBy           string    `json:"relayedby"           yaml:"relayedby"                                           bson:"relayedby"`
+	IsRelay             bool      `json:"isrelay"             yaml:"isrelay"                                             bson:"isrelay"`
+	RelayedNodes        []string  `json:"relaynodes"          yaml:"relayedNodes"`
+	IngressDNS          string    `json:"ingressdns"          yaml:"ingressdns"`
+	DNSOn               bool      `json:"dnson"               yaml:"dnson"`
 }
 
 // Node - a model of a network node
 type Node struct {
 	CommonNode
-	PendingDelete           bool                 `json:"pendingdelete" bson:"pendingdelete" yaml:"pendingdelete"`
-	LastModified            time.Time            `json:"lastmodified" bson:"lastmodified" yaml:"lastmodified"`
-	LastCheckIn             time.Time            `json:"lastcheckin" bson:"lastcheckin" yaml:"lastcheckin"`
-	LastPeerUpdate          time.Time            `json:"lastpeerupdate" bson:"lastpeerupdate" yaml:"lastpeerupdate"`
-	ExpirationDateTime      time.Time            `json:"expdatetime" bson:"expdatetime" yaml:"expdatetime"`
+	PendingDelete           bool                 `json:"pendingdelete"           bson:"pendingdelete"           yaml:"pendingdelete"`
+	LastModified            time.Time            `json:"lastmodified"            bson:"lastmodified"            yaml:"lastmodified"`
+	LastCheckIn             time.Time            `json:"lastcheckin"             bson:"lastcheckin"             yaml:"lastcheckin"`
+	LastPeerUpdate          time.Time            `json:"lastpeerupdate"          bson:"lastpeerupdate"          yaml:"lastpeerupdate"`
+	ExpirationDateTime      time.Time            `json:"expdatetime"             bson:"expdatetime"             yaml:"expdatetime"`
 	EgressGatewayNatEnabled bool                 `json:"egressgatewaynatenabled" bson:"egressgatewaynatenabled" yaml:"egressgatewaynatenabled"`
-	EgressGatewayRequest    EgressGatewayRequest `json:"egressgatewayrequest" bson:"egressgatewayrequest" yaml:"egressgatewayrequest"`
-	IngressGatewayRange     string               `json:"ingressgatewayrange" bson:"ingressgatewayrange" yaml:"ingressgatewayrange"`
-	IngressGatewayRange6    string               `json:"ingressgatewayrange6" bson:"ingressgatewayrange6" yaml:"ingressgatewayrange6"`
+	EgressGatewayRequest    EgressGatewayRequest `json:"egressgatewayrequest"    bson:"egressgatewayrequest"    yaml:"egressgatewayrequest"`
+	IngressGatewayRange     string               `json:"ingressgatewayrange"     bson:"ingressgatewayrange"     yaml:"ingressgatewayrange"`
+	IngressGatewayRange6    string               `json:"ingressgatewayrange6"    bson:"ingressgatewayrange6"    yaml:"ingressgatewayrange6"`
 	Metadata                string               `json:"metadata"`
 	// == PRO ==
-	DefaultACL        string              `json:"defaultacl,omitempty" bson:"defaultacl,omitempty" yaml:"defaultacl,omitempty" validate:"checkyesornoorunset"`
-	OwnerID           string              `json:"ownerid,omitempty" bson:"ownerid,omitempty" yaml:"ownerid,omitempty"`
-	IsFailOver        bool                `json:"is_fail_over" yaml:"is_fail_over"`
-	FailOverPeers     map[string]struct{} `json:"fail_over_peers" yaml:"fail_over_peers"`
-	FailedOverBy      uuid.UUID           `json:"failed_over_by" yaml:"failed_over_by"`
-	IsInternetGateway bool                `json:"isinternetgateway" yaml:"isinternetgateway"`
-	InetNodeReq       InetNodeReq         `json:"inet_node_req" yaml:"inet_node_req"`
-	InternetGwID      string              `json:"internetgw_node_id" yaml:"internetgw_node_id"`
-	AdditionalRagIps  []net.IP            `json:"additional_rag_ips" yaml:"additional_rag_ips"`
+	DefaultACL        string              `json:"defaultacl,omitempty"    bson:"defaultacl,omitempty"    yaml:"defaultacl,omitempty"    validate:"checkyesornoorunset"`
+	OwnerID           string              `json:"ownerid,omitempty"       bson:"ownerid,omitempty"       yaml:"ownerid,omitempty"`
+	IsFailOver        bool                `json:"is_fail_over"                                           yaml:"is_fail_over"`
+	FailOverPeers     map[string]struct{} `json:"fail_over_peers"                                        yaml:"fail_over_peers"`
+	FailedOverBy      uuid.UUID           `json:"failed_over_by"                                         yaml:"failed_over_by"`
+	IsInternetGateway bool                `json:"isinternetgateway"                                      yaml:"isinternetgateway"`
+	InetNodeReq       InetNodeReq         `json:"inet_node_req"                                          yaml:"inet_node_req"`
+	InternetGwID      string              `json:"internetgw_node_id"                                     yaml:"internetgw_node_id"`
+	AdditionalRagIps  []net.IP            `json:"additional_rag_ips"                                     yaml:"additional_rag_ips"                                     swaggertype:"array,number"`
 }
 
 // LegacyNode - legacy struct for node model
 type LegacyNode struct {
-	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"`
-	Address6                string               `json:"address6" bson:"address6" yaml:"address6" validate:"omitempty,ipv6"`
-	LocalAddress            string               `json:"localaddress" bson:"localaddress" yaml:"localaddress" validate:"omitempty"`
-	Interfaces              []Iface              `json:"interfaces" yaml:"interfaces"`
-	Name                    string               `json:"name" bson:"name" yaml:"name" validate:"omitempty,max=62,in_charset"`
-	NetworkSettings         Network              `json:"networksettings" bson:"networksettings" yaml:"networksettings" validate:"-"`
-	ListenPort              int32                `json:"listenport" bson:"listenport" yaml:"listenport" validate:"omitempty,numeric,min=1024,max=65535"`
-	LocalListenPort         int32                `json:"locallistenport" bson:"locallistenport" yaml:"locallistenport" validate:"numeric,min=0,max=65535"`
-	PublicKey               string               `json:"publickey" bson:"publickey" yaml:"publickey" validate:"required,base64"`
-	Endpoint                string               `json:"endpoint" bson:"endpoint" yaml:"endpoint" validate:"required,ip"`
-	AllowedIPs              []string             `json:"allowedips" bson:"allowedips" yaml:"allowedips"`
-	PersistentKeepalive     int32                `json:"persistentkeepalive" bson:"persistentkeepalive" yaml:"persistentkeepalive" validate:"omitempty,numeric,max=1000"`
-	IsHub                   string               `json:"ishub" bson:"ishub" yaml:"ishub" validate:"checkyesorno"`
-	AccessKey               string               `json:"accesskey" bson:"accesskey" yaml:"accesskey"`
-	Interface               string               `json:"interface" bson:"interface" yaml:"interface"`
-	LastModified            int64                `json:"lastmodified" bson:"lastmodified" yaml:"lastmodified"`
-	ExpirationDateTime      int64                `json:"expdatetime" bson:"expdatetime" yaml:"expdatetime"`
-	LastPeerUpdate          int64                `json:"lastpeerupdate" bson:"lastpeerupdate" yaml:"lastpeerupdate"`
-	LastCheckIn             int64                `json:"lastcheckin" bson:"lastcheckin" yaml:"lastcheckin"`
-	MacAddress              string               `json:"macaddress" bson:"macaddress" yaml:"macaddress"`
-	Password                string               `json:"password" bson:"password" yaml:"password" validate:"required,min=6"`
-	Network                 string               `json:"network" bson:"network" yaml:"network" validate:"network_exists"`
-	IsRelayed               string               `json:"isrelayed" bson:"isrelayed" yaml:"isrelayed"`
-	IsPending               string               `json:"ispending" bson:"ispending" yaml:"ispending"`
-	IsRelay                 string               `json:"isrelay" bson:"isrelay" yaml:"isrelay" validate:"checkyesorno"`
-	IsDocker                string               `json:"isdocker" bson:"isdocker" yaml:"isdocker" validate:"checkyesorno"`
-	IsK8S                   string               `json:"isk8s" bson:"isk8s" yaml:"isk8s" validate:"checkyesorno"`
-	IsEgressGateway         string               `json:"isegressgateway" bson:"isegressgateway" yaml:"isegressgateway" validate:"checkyesorno"`
-	IsIngressGateway        string               `json:"isingressgateway" bson:"isingressgateway" yaml:"isingressgateway" validate:"checkyesorno"`
-	EgressGatewayRanges     []string             `json:"egressgatewayranges" bson:"egressgatewayranges" yaml:"egressgatewayranges"`
+	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"`
+	Address6                string               `json:"address6"                bson:"address6"                yaml:"address6"                validate:"omitempty,ipv6"`
+	LocalAddress            string               `json:"localaddress"            bson:"localaddress"            yaml:"localaddress"            validate:"omitempty"`
+	Interfaces              []Iface              `json:"interfaces"                                             yaml:"interfaces"`
+	Name                    string               `json:"name"                    bson:"name"                    yaml:"name"                    validate:"omitempty,max=62,in_charset"`
+	NetworkSettings         Network              `json:"networksettings"         bson:"networksettings"         yaml:"networksettings"         validate:"-"`
+	ListenPort              int32                `json:"listenport"              bson:"listenport"              yaml:"listenport"              validate:"omitempty,numeric,min=1024,max=65535"`
+	LocalListenPort         int32                `json:"locallistenport"         bson:"locallistenport"         yaml:"locallistenport"         validate:"numeric,min=0,max=65535"`
+	PublicKey               string               `json:"publickey"               bson:"publickey"               yaml:"publickey"               validate:"required,base64"`
+	Endpoint                string               `json:"endpoint"                bson:"endpoint"                yaml:"endpoint"                validate:"required,ip"`
+	AllowedIPs              []string             `json:"allowedips"              bson:"allowedips"              yaml:"allowedips"`
+	PersistentKeepalive     int32                `json:"persistentkeepalive"     bson:"persistentkeepalive"     yaml:"persistentkeepalive"     validate:"omitempty,numeric,max=1000"`
+	IsHub                   string               `json:"ishub"                   bson:"ishub"                   yaml:"ishub"                   validate:"checkyesorno"`
+	AccessKey               string               `json:"accesskey"               bson:"accesskey"               yaml:"accesskey"`
+	Interface               string               `json:"interface"               bson:"interface"               yaml:"interface"`
+	LastModified            int64                `json:"lastmodified"            bson:"lastmodified"            yaml:"lastmodified"`
+	ExpirationDateTime      int64                `json:"expdatetime"             bson:"expdatetime"             yaml:"expdatetime"`
+	LastPeerUpdate          int64                `json:"lastpeerupdate"          bson:"lastpeerupdate"          yaml:"lastpeerupdate"`
+	LastCheckIn             int64                `json:"lastcheckin"             bson:"lastcheckin"             yaml:"lastcheckin"`
+	MacAddress              string               `json:"macaddress"              bson:"macaddress"              yaml:"macaddress"`
+	Password                string               `json:"password"                bson:"password"                yaml:"password"                validate:"required,min=6"`
+	Network                 string               `json:"network"                 bson:"network"                 yaml:"network"                 validate:"network_exists"`
+	IsRelayed               string               `json:"isrelayed"               bson:"isrelayed"               yaml:"isrelayed"`
+	IsPending               string               `json:"ispending"               bson:"ispending"               yaml:"ispending"`
+	IsRelay                 string               `json:"isrelay"                 bson:"isrelay"                 yaml:"isrelay"                 validate:"checkyesorno"`
+	IsDocker                string               `json:"isdocker"                bson:"isdocker"                yaml:"isdocker"                validate:"checkyesorno"`
+	IsK8S                   string               `json:"isk8s"                   bson:"isk8s"                   yaml:"isk8s"                   validate:"checkyesorno"`
+	IsEgressGateway         string               `json:"isegressgateway"         bson:"isegressgateway"         yaml:"isegressgateway"         validate:"checkyesorno"`
+	IsIngressGateway        string               `json:"isingressgateway"        bson:"isingressgateway"        yaml:"isingressgateway"        validate:"checkyesorno"`
+	EgressGatewayRanges     []string             `json:"egressgatewayranges"     bson:"egressgatewayranges"     yaml:"egressgatewayranges"`
 	EgressGatewayNatEnabled string               `json:"egressgatewaynatenabled" bson:"egressgatewaynatenabled" yaml:"egressgatewaynatenabled"`
-	EgressGatewayRequest    EgressGatewayRequest `json:"egressgatewayrequest" bson:"egressgatewayrequest" yaml:"egressgatewayrequest"`
-	RelayAddrs              []string             `json:"relayaddrs" bson:"relayaddrs" yaml:"relayaddrs"`
-	FailoverNode            string               `json:"failovernode" bson:"failovernode" yaml:"failovernode"`
-	IngressGatewayRange     string               `json:"ingressgatewayrange" bson:"ingressgatewayrange" yaml:"ingressgatewayrange"`
-	IngressGatewayRange6    string               `json:"ingressgatewayrange6" bson:"ingressgatewayrange6" yaml:"ingressgatewayrange6"`
+	EgressGatewayRequest    EgressGatewayRequest `json:"egressgatewayrequest"    bson:"egressgatewayrequest"    yaml:"egressgatewayrequest"`
+	RelayAddrs              []string             `json:"relayaddrs"              bson:"relayaddrs"              yaml:"relayaddrs"`
+	FailoverNode            string               `json:"failovernode"            bson:"failovernode"            yaml:"failovernode"`
+	IngressGatewayRange     string               `json:"ingressgatewayrange"     bson:"ingressgatewayrange"     yaml:"ingressgatewayrange"`
+	IngressGatewayRange6    string               `json:"ingressgatewayrange6"    bson:"ingressgatewayrange6"    yaml:"ingressgatewayrange6"`
 	// IsStatic - refers to if the Endpoint is set manually or dynamically
-	IsStatic        string      `json:"isstatic" bson:"isstatic" yaml:"isstatic" validate:"checkyesorno"`
-	UDPHolePunch    string      `json:"udpholepunch" bson:"udpholepunch" yaml:"udpholepunch" validate:"checkyesorno"`
-	DNSOn           string      `json:"dnson" bson:"dnson" yaml:"dnson" validate:"checkyesorno"`
-	IsServer        string      `json:"isserver" bson:"isserver" yaml:"isserver" validate:"checkyesorno"`
-	Action          string      `json:"action" bson:"action" yaml:"action"`
-	IPForwarding    string      `json:"ipforwarding" bson:"ipforwarding" yaml:"ipforwarding" validate:"checkyesorno"`
-	OS              string      `json:"os" bson:"os" yaml:"os"`
-	MTU             int32       `json:"mtu" bson:"mtu" yaml:"mtu"`
-	Version         string      `json:"version" bson:"version" yaml:"version"`
-	Server          string      `json:"server" bson:"server" yaml:"server"`
-	TrafficKeys     TrafficKeys `json:"traffickeys" bson:"traffickeys" yaml:"traffickeys"`
-	FirewallInUse   string      `json:"firewallinuse" bson:"firewallinuse" yaml:"firewallinuse"`
-	InternetGateway string      `json:"internetgateway" bson:"internetgateway" yaml:"internetgateway"`
-	Connected       string      `json:"connected" bson:"connected" yaml:"connected" validate:"checkyesorno"`
+	IsStatic        string      `json:"isstatic"                bson:"isstatic"                yaml:"isstatic"                validate:"checkyesorno"`
+	UDPHolePunch    string      `json:"udpholepunch"            bson:"udpholepunch"            yaml:"udpholepunch"            validate:"checkyesorno"`
+	DNSOn           string      `json:"dnson"                   bson:"dnson"                   yaml:"dnson"                   validate:"checkyesorno"`
+	IsServer        string      `json:"isserver"                bson:"isserver"                yaml:"isserver"                validate:"checkyesorno"`
+	Action          string      `json:"action"                  bson:"action"                  yaml:"action"`
+	IPForwarding    string      `json:"ipforwarding"            bson:"ipforwarding"            yaml:"ipforwarding"            validate:"checkyesorno"`
+	OS              string      `json:"os"                      bson:"os"                      yaml:"os"`
+	MTU             int32       `json:"mtu"                     bson:"mtu"                     yaml:"mtu"`
+	Version         string      `json:"version"                 bson:"version"                 yaml:"version"`
+	Server          string      `json:"server"                  bson:"server"                  yaml:"server"`
+	TrafficKeys     TrafficKeys `json:"traffickeys"             bson:"traffickeys"             yaml:"traffickeys"`
+	FirewallInUse   string      `json:"firewallinuse"           bson:"firewallinuse"           yaml:"firewallinuse"`
+	InternetGateway string      `json:"internetgateway"         bson:"internetgateway"         yaml:"internetgateway"`
+	Connected       string      `json:"connected"               bson:"connected"               yaml:"connected"               validate:"checkyesorno"`
 	// == PRO ==
-	DefaultACL string `json:"defaultacl,omitempty" bson:"defaultacl,omitempty" yaml:"defaultacl,omitempty" validate:"checkyesornoorunset"`
-	OwnerID    string `json:"ownerid,omitempty" bson:"ownerid,omitempty" yaml:"ownerid,omitempty"`
-	Failover   string `json:"failover" bson:"failover" yaml:"failover" validate:"checkyesorno"`
+	DefaultACL string `json:"defaultacl,omitempty"    bson:"defaultacl,omitempty"    yaml:"defaultacl,omitempty"    validate:"checkyesornoorunset"`
+	OwnerID    string `json:"ownerid,omitempty"       bson:"ownerid,omitempty"       yaml:"ownerid,omitempty"`
+	Failover   string `json:"failover"                bson:"failover"                yaml:"failover"                validate:"checkyesorno"`
 }
 
 // NodesArray - used for node sorting
@@ -375,7 +375,10 @@ func (node *LegacyNode) SetDefaultFailover() {
 }
 
 // Node.Fill - fills other node data into calling node data if not set on calling node (skips DNSOn)
-func (newNode *Node) Fill(currentNode *Node, isPro bool) { // TODO add new field for nftables present
+func (newNode *Node) Fill(
+	currentNode *Node,
+	isPro bool,
+) { // TODO add new field for nftables present
 	newNode.ID = currentNode.ID
 	newNode.HostID = currentNode.HostID
 	// Revisit the logic for boolean values

+ 107 - 59
pro/controllers/failover.go

@@ -19,24 +19,25 @@ import (
 
 // FailOverHandlers - handlers for FailOver
 func FailOverHandlers(r *mux.Router) {
-	r.HandleFunc("/api/v1/node/{nodeid}/failover", http.HandlerFunc(getfailOver)).Methods(http.MethodGet)
-	r.HandleFunc("/api/v1/node/{nodeid}/failover", logic.SecurityCheck(true, http.HandlerFunc(createfailOver))).Methods(http.MethodPost)
-	r.HandleFunc("/api/v1/node/{nodeid}/failover", logic.SecurityCheck(true, http.HandlerFunc(deletefailOver))).Methods(http.MethodDelete)
-	r.HandleFunc("/api/v1/node/{network}/failover/reset", logic.SecurityCheck(true, http.HandlerFunc(resetFailOver))).Methods(http.MethodPost)
-	r.HandleFunc("/api/v1/node/{nodeid}/failover_me", controller.Authorize(true, false, "host", http.HandlerFunc(failOverME))).Methods(http.MethodPost)
+	r.HandleFunc("/api/v1/node/{nodeid}/failover", http.HandlerFunc(getfailOver)).
+		Methods(http.MethodGet)
+	r.HandleFunc("/api/v1/node/{nodeid}/failover", logic.SecurityCheck(true, http.HandlerFunc(createfailOver))).
+		Methods(http.MethodPost)
+	r.HandleFunc("/api/v1/node/{nodeid}/failover", logic.SecurityCheck(true, http.HandlerFunc(deletefailOver))).
+		Methods(http.MethodDelete)
+	r.HandleFunc("/api/v1/node/{network}/failover/reset", logic.SecurityCheck(true, http.HandlerFunc(resetFailOver))).
+		Methods(http.MethodPost)
+	r.HandleFunc("/api/v1/node/{nodeid}/failover_me", controller.Authorize(true, false, "host", http.HandlerFunc(failOverME))).
+		Methods(http.MethodPost)
 }
 
-// swagger:route GET /api/v1/node/failover node getfailOver
-//
-// get failover node.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: nodeResponse
+// @Summary     Get failover node
+// @Router      /api/v1/node/{nodeid}/failover [get]
+// @Tags        PRO
+// @Param       nodeid path string true "Node ID"
+// @Success     200 {object} models.Node
+// @Failure     400 {object} models.ErrorResponse
+// @Failure     404 {object} models.ErrorResponse
 func getfailOver(w http.ResponseWriter, r *http.Request) {
 	var params = mux.Vars(r)
 	nodeid := params["nodeid"]
@@ -50,24 +51,24 @@ func getfailOver(w http.ResponseWriter, r *http.Request) {
 
 	failOverNode, exists := proLogic.FailOverExists(node.Network)
 	if !exists {
-		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("failover node not found"), "notfound"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(errors.New("failover node not found"), "notfound"),
+		)
 		return
 	}
 	w.Header().Set("Content-Type", "application/json")
 	logic.ReturnSuccessResponseWithJson(w, r, failOverNode, "get failover node successfully")
 }
 
-// swagger:route POST /api/v1/node/failover node createfailOver
-//
-// Create a relay.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: nodeResponse
+// @Summary     Create failover node
+// @Router      /api/v1/node/{nodeid}/failover [post]
+// @Tags        PRO
+// @Param       nodeid path string true "Node ID"
+// @Success     200 {object} models.Node
+// @Failure     400 {object} models.ErrorResponse
+// @Failure     500 {object} models.ErrorResponse
 func createfailOver(w http.ResponseWriter, r *http.Request) {
 	var params = mux.Vars(r)
 	nodeid := params["nodeid"]
@@ -88,6 +89,12 @@ func createfailOver(w http.ResponseWriter, r *http.Request) {
 	logic.ReturnSuccessResponseWithJson(w, r, node, "created failover successfully")
 }
 
+// @Summary     Reset failover for a network
+// @Router      /api/v1/node/{network}/failover/reset [post]
+// @Tags        PRO
+// @Param       network path string true "Network ID"
+// @Success     200 {object} models.SuccessResponse
+// @Failure     500 {object} models.ErrorResponse
 func resetFailOver(w http.ResponseWriter, r *http.Request) {
 	var params = mux.Vars(r)
 	net := params["network"]
@@ -108,17 +115,13 @@ func resetFailOver(w http.ResponseWriter, r *http.Request) {
 	logic.ReturnSuccessResponse(w, r, "failover has been reset successfully")
 }
 
-// swagger:route DELETE /api/v1/node/failover node deletefailOver
-//
-// Create a relay.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: nodeResponse
+// @Summary     Delete failover node
+// @Router      /api/v1/node/{nodeid}/failover [delete]
+// @Tags        PRO
+// @Param       nodeid path string true "Node ID"
+// @Success     200 {object} models.Node
+// @Failure     400 {object} models.ErrorResponse
+// @Failure     500 {object} models.ErrorResponse
 func deletefailOver(w http.ResponseWriter, r *http.Request) {
 	var params = mux.Vars(r)
 	nodeid := params["nodeid"]
@@ -145,17 +148,15 @@ func deletefailOver(w http.ResponseWriter, r *http.Request) {
 	logic.ReturnSuccessResponseWithJson(w, r, node, "deleted failover successfully")
 }
 
-// swagger:route POST /api/node/{nodeid}/failOverME node failOver_me
-//
-// Create a relay.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: nodeResponse
+// @Summary     Failover me
+// @Router      /api/v1/node/{nodeid}/failover_me [post]
+// @Tags        PRO
+// @Param       nodeid path string true "Node ID"
+// @Accept      json
+// @Param       body body models.FailOverMeReq true "Failover request"
+// @Success     200 {object} models.SuccessResponse
+// @Failure     400 {object} models.ErrorResponse
+// @Failure     500 {object} models.ErrorResponse
 func failOverME(w http.ResponseWriter, r *http.Request) {
 	var params = mux.Vars(r)
 	nodeid := params["nodeid"]
@@ -174,7 +175,14 @@ func failOverME(w http.ResponseWriter, r *http.Request) {
 
 	failOverNode, exists := proLogic.FailOverExists(node.Network)
 	if !exists {
-		logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("req-from: %s, failover node doesn't exist in the network", host.Name), "badrequest"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(
+				fmt.Errorf("req-from: %s, failover node doesn't exist in the network", host.Name),
+				"badrequest",
+			),
+		)
 		return
 	}
 	var failOverReq models.FailOverMeReq
@@ -188,27 +196,57 @@ func failOverME(w http.ResponseWriter, r *http.Request) {
 	peerNode, err := logic.GetNodeByID(failOverReq.NodeID)
 	if err != nil {
 		slog.Error("peer not found: ", "nodeid", failOverReq.NodeID, "error", err)
-		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("peer not found"), "badrequest"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(errors.New("peer not found"), "badrequest"),
+		)
 		return
 	}
 	if node.IsFailOver {
-		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("node is acting as failover"), "badrequest"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(errors.New("node is acting as failover"), "badrequest"),
+		)
 		return
 	}
 	if node.IsRelayed && node.RelayedBy == peerNode.ID.String() {
-		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("node is relayed by peer node"), "badrequest"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(errors.New("node is relayed by peer node"), "badrequest"),
+		)
 		return
 	}
 	if node.IsRelay && peerNode.RelayedBy == node.ID.String() {
-		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("node acting as relay for the peer node"), "badrequest"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(errors.New("node acting as relay for the peer node"), "badrequest"),
+		)
 		return
 	}
 	if node.IsInternetGateway && peerNode.InternetGwID == node.ID.String() {
-		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("node acting as internet gw for the peer node"), "badrequest"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(
+				errors.New("node acting as internet gw for the peer node"),
+				"badrequest",
+			),
+		)
 		return
 	}
 	if node.InternetGwID != "" && node.InternetGwID == peerNode.ID.String() {
-		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("node using a internet gw by the peer node"), "badrequest"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(
+				errors.New("node using a internet gw by the peer node"),
+				"badrequest",
+			),
+		)
 		return
 	}
 
@@ -216,10 +254,20 @@ func failOverME(w http.ResponseWriter, r *http.Request) {
 	if err != nil {
 		slog.Error("failed to create failover", "id", node.ID.String(),
 			"network", node.Network, "error", err)
-		logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to create failover: %v", err), "internal"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(fmt.Errorf("failed to create failover: %v", err), "internal"),
+		)
 		return
 	}
-	slog.Info("[auto-relay] created relay on node", "node", node.ID.String(), "network", node.Network)
+	slog.Info(
+		"[auto-relay] created relay on node",
+		"node",
+		node.ID.String(),
+		"network",
+		node.Network,
+	)
 	sendPeerUpdate = true
 
 	if sendPeerUpdate {

+ 71 - 41
pro/controllers/inet_gws.go

@@ -16,22 +16,24 @@ import (
 
 // InetHandlers - handlers for internet gw
 func InetHandlers(r *mux.Router) {
-	r.HandleFunc("/api/nodes/{network}/{nodeid}/inet_gw", logic.SecurityCheck(true, http.HandlerFunc(createInternetGw))).Methods(http.MethodPost)
-	r.HandleFunc("/api/nodes/{network}/{nodeid}/inet_gw", logic.SecurityCheck(true, http.HandlerFunc(updateInternetGw))).Methods(http.MethodPut)
-	r.HandleFunc("/api/nodes/{network}/{nodeid}/inet_gw", logic.SecurityCheck(true, http.HandlerFunc(deleteInternetGw))).Methods(http.MethodDelete)
+	r.HandleFunc("/api/nodes/{network}/{nodeid}/inet_gw", logic.SecurityCheck(true, http.HandlerFunc(createInternetGw))).
+		Methods(http.MethodPost)
+	r.HandleFunc("/api/nodes/{network}/{nodeid}/inet_gw", logic.SecurityCheck(true, http.HandlerFunc(updateInternetGw))).
+		Methods(http.MethodPut)
+	r.HandleFunc("/api/nodes/{network}/{nodeid}/inet_gw", logic.SecurityCheck(true, http.HandlerFunc(deleteInternetGw))).
+		Methods(http.MethodDelete)
 }
 
-// swagger:route POST /api/nodes/{network}/{nodeid}/inet_gw nodes createInternetGw
-//
-// Create an inet node.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: nodeResponse
+// @Summary     Create an internet gateway
+// @Router      /api/nodes/{network}/{nodeid}/inet_gw [post]
+// @Tags        PRO
+// @Accept      json
+// @Param       network path string true "Network ID"
+// @Param       nodeid path string true "Node ID"
+// @Param       body body models.InetNodeReq true "Internet gateway request"
+// @Success     200 {object} models.Node
+// @Failure     400 {object} models.ErrorResponse
+// @Failure     500 {object} models.ErrorResponse
 func createInternetGw(w http.ResponseWriter, r *http.Request) {
 	var params = mux.Vars(r)
 	w.Header().Set("Content-Type", "application/json")
@@ -58,7 +60,14 @@ func createInternetGw(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 	if host.OS != models.OS_Types.Linux {
-		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("only linux nodes can be made internet gws"), "badrequest"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(
+				errors.New("only linux nodes can be made internet gws"),
+				"badrequest",
+			),
+		)
 		return
 	}
 	err = proLogic.ValidateInetGwReq(node, request, false)
@@ -81,23 +90,29 @@ func createInternetGw(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 	apiNode := node.ConvertToAPINode()
-	logger.Log(1, r.Header.Get("user"), "created ingress gateway on node", nodeid, "on network", netid)
+	logger.Log(
+		1,
+		r.Header.Get("user"),
+		"created ingress gateway on node",
+		nodeid,
+		"on network",
+		netid,
+	)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(apiNode)
 	go mq.PublishPeerUpdate(false)
 }
 
-// swagger:route PUT /api/nodes/{network}/{nodeid}/inet_gw nodes updateInternetGw
-//
-// update an inet node.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: nodeResponse
+// @Summary     Update an internet gateway
+// @Router      /api/nodes/{network}/{nodeid}/inet_gw [put]
+// @Tags        PRO
+// @Accept      json
+// @Param       network path string true "Network ID"
+// @Param       nodeid path string true "Node ID"
+// @Param       body body models.InetNodeReq true "Internet gateway request"
+// @Success     200 {object} models.Node
+// @Failure     400 {object} models.ErrorResponse
+// @Failure     500 {object} models.ErrorResponse
 func updateInternetGw(w http.ResponseWriter, r *http.Request) {
 	var params = mux.Vars(r)
 	w.Header().Set("Content-Type", "application/json")
@@ -115,7 +130,11 @@ func updateInternetGw(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 	if !node.IsInternetGateway {
-		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("node is not a internet gw"), "badrequest"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(errors.New("node is not a internet gw"), "badrequest"),
+		)
 		return
 	}
 	err = proLogic.ValidateInetGwReq(node, request, true)
@@ -131,23 +150,27 @@ func updateInternetGw(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 	apiNode := node.ConvertToAPINode()
-	logger.Log(1, r.Header.Get("user"), "created ingress gateway on node", nodeid, "on network", netid)
+	logger.Log(
+		1,
+		r.Header.Get("user"),
+		"created ingress gateway on node",
+		nodeid,
+		"on network",
+		netid,
+	)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(apiNode)
 	go mq.PublishPeerUpdate(false)
 }
 
-// swagger:route DELETE /api/nodes/{network}/{nodeid}/inet_gw nodes deleteInternetGw
-//
-// Delete an internet gw.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: nodeResponse
+// @Summary     Delete an internet gateway
+// @Router      /api/nodes/{network}/{nodeid}/inet_gw [delete]
+// @Tags        PRO
+// @Param       network path string true "Network ID"
+// @Param       nodeid path string true "Node ID"
+// @Success     200 {object} models.Node
+// @Failure     400 {object} models.ErrorResponse
+// @Failure     500 {object} models.ErrorResponse
 func deleteInternetGw(w http.ResponseWriter, r *http.Request) {
 	var params = mux.Vars(r)
 	w.Header().Set("Content-Type", "application/json")
@@ -166,7 +189,14 @@ func deleteInternetGw(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 	apiNode := node.ConvertToAPINode()
-	logger.Log(1, r.Header.Get("user"), "created ingress gateway on node", nodeid, "on network", netid)
+	logger.Log(
+		1,
+		r.Header.Get("user"),
+		"created ingress gateway on node",
+		nodeid,
+		"on network",
+		netid,
+	)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(apiNode)
 	go mq.PublishPeerUpdate(false)

+ 69 - 31
pro/controllers/relay.go

@@ -19,22 +19,25 @@ import (
 // RelayHandlers - handle Pro Relays
 func RelayHandlers(r *mux.Router) {
 
-	r.HandleFunc("/api/nodes/{network}/{nodeid}/createrelay", controller.Authorize(false, true, "user", http.HandlerFunc(createRelay))).Methods(http.MethodPost)
-	r.HandleFunc("/api/nodes/{network}/{nodeid}/deleterelay", controller.Authorize(false, true, "user", http.HandlerFunc(deleteRelay))).Methods(http.MethodDelete)
-	r.HandleFunc("/api/v1/host/{hostid}/failoverme", controller.Authorize(true, false, "host", http.HandlerFunc(failOverME))).Methods(http.MethodPost)
+	r.HandleFunc("/api/nodes/{network}/{nodeid}/createrelay", controller.Authorize(false, true, "user", http.HandlerFunc(createRelay))).
+		Methods(http.MethodPost)
+	r.HandleFunc("/api/nodes/{network}/{nodeid}/deleterelay", controller.Authorize(false, true, "user", http.HandlerFunc(deleteRelay))).
+		Methods(http.MethodDelete)
+	r.HandleFunc("/api/v1/host/{hostid}/failoverme", controller.Authorize(true, false, "host", http.HandlerFunc(failOverME))).
+		Methods(http.MethodPost)
 }
 
-// swagger:route POST /api/nodes/{network}/{nodeid}/createrelay nodes createRelay
-//
-// Create a relay.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: nodeResponse
+// @Summary     Create a relay
+// @Router      /api/nodes/{network}/{nodeid}/createrelay [post]
+// @Tags        PRO
+// @Accept      json
+// @Produce     json
+// @Param       network path string true "Network ID"
+// @Param       nodeid path string true "Node ID"
+// @Param       body body models.RelayRequest true "Relay request parameters"
+// @Success     200 {object} models.ApiNode
+// @Failure     400 {object} models.ErrorResponse
+// @Failure     500 {object} models.ErrorResponse
 func createRelay(w http.ResponseWriter, r *http.Request) {
 	var relayRequest models.RelayRequest
 	var params = mux.Vars(r)
@@ -49,8 +52,16 @@ func createRelay(w http.ResponseWriter, r *http.Request) {
 	relayRequest.NodeID = params["nodeid"]
 	_, relayNode, err := proLogic.CreateRelay(relayRequest)
 	if err != nil {
-		logger.Log(0, r.Header.Get("user"),
-			fmt.Sprintf("failed to create relay on node [%s] on network [%s]: %v", relayRequest.NodeID, relayRequest.NetID, err))
+		logger.Log(
+			0,
+			r.Header.Get("user"),
+			fmt.Sprintf(
+				"failed to create relay on node [%s] on network [%s]: %v",
+				relayRequest.NodeID,
+				relayRequest.NetID,
+				err,
+			),
+		)
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 		return
 	}
@@ -64,23 +75,29 @@ func createRelay(w http.ResponseWriter, r *http.Request) {
 		}
 	}
 	go mq.PublishPeerUpdate(false)
-	logger.Log(1, r.Header.Get("user"), "created relay on node", relayRequest.NodeID, "on network", relayRequest.NetID)
+	logger.Log(
+		1,
+		r.Header.Get("user"),
+		"created relay on node",
+		relayRequest.NodeID,
+		"on network",
+		relayRequest.NetID,
+	)
 	apiNode := relayNode.ConvertToAPINode()
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(apiNode)
 }
 
-// swagger:route DELETE /api/nodes/{network}/{nodeid}/deleterelay nodes deleteRelay
-//
-// Remove a relay.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: nodeResponse
+// @Summary     Remove a relay
+// @Router      /api/nodes/{network}/{nodeid}/deleterelay [delete]
+// @Tags        PRO
+// @Accept      json
+// @Produce     json
+// @Param       network path string true "Network ID"
+// @Param       nodeid path string true "Node ID"
+// @Success     200 {object} models.ApiNode
+// @Failure     400 {object} models.ErrorResponse
+// @Failure     500 {object} models.ErrorResponse
 func deleteRelay(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	var params = mux.Vars(r)
@@ -97,7 +114,15 @@ func deleteRelay(w http.ResponseWriter, r *http.Request) {
 		for _, relayedNode := range updateNodes {
 			err = mq.NodeUpdate(&relayedNode)
 			if err != nil {
-				logger.Log(1, "relayed node update ", relayedNode.ID.String(), "on network", relayedNode.Network, ": ", err.Error())
+				logger.Log(
+					1,
+					"relayed node update ",
+					relayedNode.ID.String(),
+					"on network",
+					relayedNode.Network,
+					": ",
+					err.Error(),
+				)
 
 			}
 			h, err := logic.GetHost(relayedNode.HostID.String())
@@ -109,14 +134,27 @@ func deleteRelay(w http.ResponseWriter, r *http.Request) {
 					}
 					node.IsRelay = true // for iot update to recognise that it has to delete relay peer
 					if err = mq.PublishSingleHostPeerUpdate(h, nodes, &node, nil, false); err != nil {
-						logger.Log(1, "failed to publish peer update to host", h.ID.String(), ": ", err.Error())
+						logger.Log(
+							1,
+							"failed to publish peer update to host",
+							h.ID.String(),
+							": ",
+							err.Error(),
+						)
 					}
 				}
 			}
 		}
 		mq.PublishPeerUpdate(false)
 	}()
-	logger.Log(1, r.Header.Get("user"), "deleted relay on node", node.ID.String(), "on network", node.Network)
+	logger.Log(
+		1,
+		r.Header.Get("user"),
+		"deleted relay on node",
+		node.ID.String(),
+		"on network",
+		node.Network,
+	)
 	apiNode := node.ConvertToAPINode()
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(apiNode)

+ 150 - 64
pro/controllers/users.go

@@ -17,27 +17,30 @@ import (
 )
 
 func UserHandlers(r *mux.Router) {
-	r.HandleFunc("/api/users/{username}/remote_access_gw/{remote_access_gateway_id}", logic.SecurityCheck(true, http.HandlerFunc(attachUserToRemoteAccessGw))).Methods(http.MethodPost)
-	r.HandleFunc("/api/users/{username}/remote_access_gw/{remote_access_gateway_id}", logic.SecurityCheck(true, http.HandlerFunc(removeUserFromRemoteAccessGW))).Methods(http.MethodDelete)
-	r.HandleFunc("/api/users/{username}/remote_access_gw", logic.SecurityCheck(false, logic.ContinueIfUserMatch(http.HandlerFunc(getUserRemoteAccessGws)))).Methods(http.MethodGet)
-	r.HandleFunc("/api/users/ingress/{ingress_id}", logic.SecurityCheck(true, http.HandlerFunc(ingressGatewayUsers))).Methods(http.MethodGet)
+	r.HandleFunc("/api/users/{username}/remote_access_gw/{remote_access_gateway_id}", logic.SecurityCheck(true, http.HandlerFunc(attachUserToRemoteAccessGw))).
+		Methods(http.MethodPost)
+	r.HandleFunc("/api/users/{username}/remote_access_gw/{remote_access_gateway_id}", logic.SecurityCheck(true, http.HandlerFunc(removeUserFromRemoteAccessGW))).
+		Methods(http.MethodDelete)
+	r.HandleFunc("/api/users/{username}/remote_access_gw", logic.SecurityCheck(false, logic.ContinueIfUserMatch(http.HandlerFunc(getUserRemoteAccessGws)))).
+		Methods(http.MethodGet)
+	r.HandleFunc("/api/users/ingress/{ingress_id}", logic.SecurityCheck(true, http.HandlerFunc(ingressGatewayUsers))).
+		Methods(http.MethodGet)
 	r.HandleFunc("/api/oauth/login", auth.HandleAuthLogin).Methods(http.MethodGet)
 	r.HandleFunc("/api/oauth/callback", auth.HandleAuthCallback).Methods(http.MethodGet)
 	r.HandleFunc("/api/oauth/headless", auth.HandleHeadlessSSO)
 	r.HandleFunc("/api/oauth/register/{regKey}", auth.RegisterHostSSO).Methods(http.MethodGet)
 }
 
-// swagger:route POST /api/users/{username}/remote_access_gw user attachUserToRemoteAccessGateway
-//
-// Attach User to a remote access gateway.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: userBodyResponse
+// @Summary     Attach user to a remote access gateway
+// @Router      /api/users/{username}/remote_access_gw/{remote_access_gateway_id} [post]
+// @Tags        PRO
+// @Accept      json
+// @Produce     json
+// @Param       username path string true "Username"
+// @Param       remote_access_gateway_id path string true "Remote Access Gateway ID"
+// @Success     200 {object} models.ReturnUser
+// @Failure     400 {object} models.ErrorResponse
+// @Failure     500 {object} models.ErrorResponse
 func attachUserToRemoteAccessGw(w http.ResponseWriter, r *http.Request) {
 	// set header.
 	w.Header().Set("Content-Type", "application/json")
@@ -46,27 +49,59 @@ func attachUserToRemoteAccessGw(w http.ResponseWriter, r *http.Request) {
 	username := params["username"]
 	remoteGwID := params["remote_access_gateway_id"]
 	if username == "" || remoteGwID == "" {
-		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("required params `username` and `remote_access_gateway_id`"), "badrequest"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(
+				errors.New("required params `username` and `remote_access_gateway_id`"),
+				"badrequest",
+			),
+		)
 		return
 	}
 	user, err := logic.GetUser(username)
 	if err != nil {
 		slog.Error("failed to fetch user: ", "username", username, "error", err.Error())
-		logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to fetch user %s, error: %v", username, err), "badrequest"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(
+				fmt.Errorf("failed to fetch user %s, error: %v", username, err),
+				"badrequest",
+			),
+		)
 		return
 	}
 	if user.IsAdmin || user.IsSuperAdmin {
-		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("superadmins/admins have access to all gateways"), "badrequest"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(
+				errors.New("superadmins/admins have access to all gateways"),
+				"badrequest",
+			),
+		)
 		return
 	}
 	node, err := logic.GetNodeByID(remoteGwID)
 	if err != nil {
 		slog.Error("failed to fetch gateway node", "nodeID", remoteGwID, "error", err)
-		logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to fetch remote access gateway node, error: %v", err), "badrequest"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(
+				fmt.Errorf("failed to fetch remote access gateway node, error: %v", err),
+				"badrequest",
+			),
+		)
 		return
 	}
 	if !node.IsIngressGateway {
-		logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("node is not a remote access gateway"), "badrequest"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(fmt.Errorf("node is not a remote access gateway"), "badrequest"),
+		)
 		return
 	}
 	if user.RemoteGwIDs == nil {
@@ -76,24 +111,30 @@ func attachUserToRemoteAccessGw(w http.ResponseWriter, r *http.Request) {
 	err = logic.UpsertUser(*user)
 	if err != nil {
 		slog.Error("failed to update user's gateways", "user", username, "error", err)
-		logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to fetch remote access gateway node,error: %v", err), "badrequest"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(
+				fmt.Errorf("failed to fetch remote access gateway node,error: %v", err),
+				"badrequest",
+			),
+		)
 		return
 	}
 
 	json.NewEncoder(w).Encode(logic.ToReturnUser(*user))
 }
 
-// swagger:route DELETE /api/users/{username}/remote_access_gw user removeUserFromRemoteAccessGW
-//
-// Delete User from a remote access gateway.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: userBodyResponse
+// @Summary     Remove user from a remote access gateway
+// @Router      /api/users/{username}/remote_access_gw/{remote_access_gateway_id} [delete]
+// @Tags        PRO
+// @Accept      json
+// @Produce     json
+// @Param       username path string true "Username"
+// @Param       remote_access_gateway_id path string true "Remote Access Gateway ID"
+// @Success     200 {object} models.ReturnUser
+// @Failure     400 {object} models.ErrorResponse
+// @Failure     500 {object} models.ErrorResponse
 func removeUserFromRemoteAccessGW(w http.ResponseWriter, r *http.Request) {
 	// set header.
 	w.Header().Set("Content-Type", "application/json")
@@ -102,13 +143,27 @@ func removeUserFromRemoteAccessGW(w http.ResponseWriter, r *http.Request) {
 	username := params["username"]
 	remoteGwID := params["remote_access_gateway_id"]
 	if username == "" || remoteGwID == "" {
-		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("required params `username` and `remote_access_gateway_id`"), "badrequest"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(
+				errors.New("required params `username` and `remote_access_gateway_id`"),
+				"badrequest",
+			),
+		)
 		return
 	}
 	user, err := logic.GetUser(username)
 	if err != nil {
 		logger.Log(0, username, "failed to fetch user: ", err.Error())
-		logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to fetch user %s, error: %v", username, err), "badrequest"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(
+				fmt.Errorf("failed to fetch user %s, error: %v", username, err),
+				"badrequest",
+			),
+		)
 		return
 	}
 	delete(user.RemoteGwIDs, remoteGwID)
@@ -139,23 +194,30 @@ func removeUserFromRemoteAccessGW(w http.ResponseWriter, r *http.Request) {
 	err = logic.UpsertUser(*user)
 	if err != nil {
 		slog.Error("failed to update user gateways", "user", username, "error", err)
-		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("failed to fetch remote access gaetway node "+err.Error()), "badrequest"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(
+				errors.New("failed to fetch remote access gaetway node "+err.Error()),
+				"badrequest",
+			),
+		)
 		return
 	}
 	json.NewEncoder(w).Encode(logic.ToReturnUser(*user))
 }
 
-// swagger:route GET "/api/users/{username}/remote_access_gw" nodes getUserRemoteAccessGws
-//
-// Get an individual node.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: nodeResponse
+// @Summary     Get user's remote access gateways
+// @Router      /api/users/{username}/remote_access_gw [get]
+// @Tags        PRO
+// @Accept      json
+// @Produce     json
+// @Param       username path string true "Username"
+// @Param       remote_access_clientid query string false "Remote Access Client ID"
+// @Param       from_mobile query boolean false "Request from mobile"
+// @Success     200 {array} models.UserRemoteGws
+// @Failure     400 {object} models.ErrorResponse
+// @Failure     500 {object} models.ErrorResponse
 func getUserRemoteAccessGws(w http.ResponseWriter, r *http.Request) {
 	// set header.
 	w.Header().Set("Content-Type", "application/json")
@@ -163,7 +225,11 @@ func getUserRemoteAccessGws(w http.ResponseWriter, r *http.Request) {
 	var params = mux.Vars(r)
 	username := params["username"]
 	if username == "" {
-		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("required params username"), "badrequest"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(errors.New("required params username"), "badrequest"),
+		)
 		return
 	}
 	remoteAccessClientID := r.URL.Query().Get("remote_access_clientid")
@@ -178,7 +244,11 @@ func getUserRemoteAccessGws(w http.ResponseWriter, r *http.Request) {
 	}
 	reqFromMobile := r.URL.Query().Get("from_mobile") == "true"
 	if req.RemoteAccessClientID == "" && remoteAccessClientID == "" {
-		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("remote access client id cannot be empty"), "badrequest"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(errors.New("remote access client id cannot be empty"), "badrequest"),
+		)
 		return
 	}
 	if req.RemoteAccessClientID == "" {
@@ -188,7 +258,14 @@ func getUserRemoteAccessGws(w http.ResponseWriter, r *http.Request) {
 	user, err := logic.GetUser(username)
 	if err != nil {
 		logger.Log(0, username, "failed to fetch user: ", err.Error())
-		logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to fetch user %s, error: %v", username, err), "badrequest"))
+		logic.ReturnErrorResponse(
+			w,
+			r,
+			logic.FormatError(
+				fmt.Errorf("failed to fetch user %s, error: %v", username, err),
+				"badrequest",
+			),
+		)
 		return
 	}
 	allextClients, err := logic.GetAllExtClients()
@@ -199,7 +276,8 @@ func getUserRemoteAccessGws(w http.ResponseWriter, r *http.Request) {
 
 	processedAdminNodeIds := make(map[string]struct{})
 	for _, extClient := range allextClients {
-		if extClient.RemoteAccessClientID == req.RemoteAccessClientID && extClient.OwnerID == username {
+		if extClient.RemoteAccessClientID == req.RemoteAccessClientID &&
+			extClient.OwnerID == username {
 			node, err := logic.GetNodeByID(extClient.IngressGatewayID)
 			if err != nil {
 				continue
@@ -219,7 +297,8 @@ func getUserRemoteAccessGws(w http.ResponseWriter, r *http.Request) {
 				slog.Error("failed to get node network", "error", err)
 			}
 
-			if _, ok := user.RemoteGwIDs[node.ID.String()]; (!user.IsAdmin && !user.IsSuperAdmin) && ok {
+			if _, ok := user.RemoteGwIDs[node.ID.String()]; (!user.IsAdmin && !user.IsSuperAdmin) &&
+				ok {
 				gws := userGws[node.Network]
 				extClient.AllowedIPs = logic.GetExtclientAllowedIPs(extClient)
 				gws = append(gws, models.UserRemoteGws{
@@ -345,17 +424,15 @@ func getUserRemoteAccessGws(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(userGws)
 }
 
-// swagger:route GET /api/nodes/{network}/{nodeid}/ingress/users users ingressGatewayUsers
-//
-// Lists all the users attached to an ingress gateway.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: nodeResponse
+// @Summary     List users attached to an remote access gateway
+// @Router      /api/nodes/{network}/{nodeid}/ingress/users [get]
+// @Tags        PRO
+// @Accept      json
+// @Produce     json
+// @Param       ingress_id path string true "Ingress Gateway ID"
+// @Success     200 {array} models.IngressGwUsers
+// @Failure     400 {object} models.ErrorResponse
+// @Failure     500 {object} models.ErrorResponse
 func ingressGatewayUsers(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	var params = mux.Vars(r)
@@ -368,8 +445,17 @@ func ingressGatewayUsers(w http.ResponseWriter, r *http.Request) {
 	}
 	gwUsers, err := logic.GetIngressGwUsers(node)
 	if err != nil {
-		slog.Error("failed to get users on ingress gateway", "nodeid", ingressID, "network", node.Network, "user", r.Header.Get("user"),
-			"error", err)
+		slog.Error(
+			"failed to get users on ingress gateway",
+			"nodeid",
+			ingressID,
+			"network",
+			node.Network,
+			"user",
+			r.Header.Get("user"),
+			"error",
+			err,
+		)
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 		return
 	}

+ 3105 - 0
swagger.yaml

@@ -0,0 +1,3105 @@
+definitions:
+  acls.ACL:
+    additionalProperties:
+      type: integer
+    type: object
+  acls.ACLContainer:
+    additionalProperties:
+      $ref: '#/definitions/acls.ACL'
+    type: object
+  config.ServerConfig:
+    properties:
+      IsEE:
+        type: string
+      allowedEmailDomains:
+        type: string
+      allowedOrigin:
+        type: string
+      apiconnString:
+        type: string
+      apihost:
+        type: string
+      apiport:
+        type: string
+      authProvider:
+        type: string
+      azureTenant:
+        type: string
+      basicAuth:
+        type: string
+      broker:
+        type: string
+      brokerType:
+        type: string
+      cacheEnabled:
+        type: string
+      clientID:
+        type: string
+      clientSecret:
+        type: string
+      coreDNSAddr:
+        type: string
+      database:
+        type: string
+      deployedByOperator:
+        type: boolean
+      disableRemoteIPCheck:
+        type: string
+      displayKeys:
+        type: string
+      dnskey:
+        type: string
+      dnsmode:
+        type: string
+      egressesLimit:
+        type: integer
+      emqxRestEndpoint:
+        type: string
+      endpoint_detection:
+        type: boolean
+      environment:
+        type: string
+      frontendURL:
+        type: string
+      hostNetwork:
+        type: string
+      ingressesLimit:
+        type: integer
+      jwtValidityDuration:
+        $ref: '#/definitions/time.Duration'
+      licenseValue:
+        type: string
+      machinesLimit:
+        type: integer
+      masterKey:
+        type: string
+      messageQueueBackend:
+        type: string
+      metricInterval:
+        type: string
+      metricsExporter:
+        type: string
+      mqpassword:
+        type: string
+      mquserName:
+        type: string
+      netclientAutoUpdate:
+        type: string
+      netclientEndpointDetection:
+        type: string
+      netmakerTenantID:
+        type: string
+      networksLimit:
+        type: integer
+      nodeID:
+        type: string
+      oidcissuer:
+        type: string
+      platform:
+        type: string
+      publicIPService:
+        type: string
+      racAutoDisable:
+        type: boolean
+      restBackend:
+        type: string
+      server:
+        type: string
+      serverBrokerEndpoint:
+        type: string
+      sqlconn:
+        type: string
+      stunList:
+        type: string
+      stunPort:
+        type: integer
+      telemetry:
+        type: string
+      turnApiServer:
+        type: string
+      turnPassword:
+        type: string
+      turnPort:
+        type: integer
+      turnServer:
+        type: string
+      turnUserName:
+        type: string
+      useTurn:
+        type: boolean
+      usersLimit:
+        type: integer
+      verbosity:
+        type: integer
+      version:
+        type: string
+    type: object
+  models.APIEnrollmentKey:
+    properties:
+      expiration:
+        type: integer
+      networks:
+        items:
+          type: string
+        type: array
+      relay:
+        type: string
+      tags:
+        items:
+          type: string
+        type: array
+      type:
+        $ref: '#/definitions/models.KeyType'
+      unlimited:
+        type: boolean
+      uses_remaining:
+        type: integer
+    required:
+    - tags
+    type: object
+  models.ApiHost:
+    properties:
+      autoupdate:
+        type: boolean
+      debug:
+        type: boolean
+      defaultinterface:
+        type: string
+      endpointip:
+        type: string
+      endpointipv6:
+        type: string
+      firewallinuse:
+        type: string
+      id:
+        type: string
+      interfaces:
+        items:
+          $ref: '#/definitions/models.ApiIface'
+        type: array
+      isdefault:
+        type: boolean
+      isstatic:
+        type: boolean
+      isstaticport:
+        type: boolean
+      listenport:
+        type: integer
+      macaddress:
+        type: string
+      mtu:
+        type: integer
+      name:
+        type: string
+      nat_type:
+        type: string
+      nodes:
+        items:
+          type: string
+        type: array
+      os:
+        type: string
+      persistentkeepalive:
+        type: integer
+      publickey:
+        type: string
+      verbosity:
+        type: integer
+      version:
+        type: string
+      wg_public_listen_port:
+        type: integer
+    type: object
+  models.ApiIface:
+    properties:
+      addressString:
+        type: string
+      name:
+        type: string
+    type: object
+  models.ApiNode:
+    properties:
+      additional_rag_ips:
+        items:
+          type: string
+        type: array
+      address:
+        type: string
+      address6:
+        type: string
+      allowedips:
+        items:
+          type: string
+        type: array
+      connected:
+        type: boolean
+      defaultacl:
+        description: == PRO ==
+        type: string
+      dnson:
+        type: boolean
+      egressgatewaynatenabled:
+        type: boolean
+      egressgatewayranges:
+        items:
+          type: string
+        type: array
+      expdatetime:
+        type: integer
+      fail_over_peers:
+        additionalProperties:
+          type: object
+        type: object
+      failed_over_by:
+        type: string
+      hostid:
+        minLength: 5
+        type: string
+      id:
+        minLength: 5
+        type: string
+      inet_node_req:
+        $ref: '#/definitions/models.InetNodeReq'
+      ingressdns:
+        type: string
+      internetgw_node_id:
+        type: string
+      is_fail_over:
+        type: boolean
+      isegressgateway:
+        type: boolean
+      isingressgateway:
+        type: boolean
+      isinternetgateway:
+        type: boolean
+      isrelay:
+        type: boolean
+      isrelayed:
+        type: boolean
+      lastcheckin:
+        type: integer
+      lastmodified:
+        type: integer
+      lastpeerupdate:
+        type: integer
+      localaddress:
+        type: string
+      metadata:
+        type: string
+      network:
+        type: string
+      networkrange:
+        type: string
+      networkrange6:
+        type: string
+      pendingdelete:
+        type: boolean
+      relayedby:
+        type: string
+      relaynodes:
+        items:
+          type: string
+        type: array
+      server:
+        type: string
+    required:
+    - hostid
+    - id
+    type: object
+  models.AuthParams:
+    properties:
+      id:
+        type: string
+      macaddress:
+        type: string
+      password:
+        type: string
+    type: object
+  models.DNSEntry:
+    properties:
+      address:
+        type: string
+      address6:
+        type: string
+      name:
+        maxLength: 192
+        minLength: 1
+        type: string
+      network:
+        type: string
+    required:
+    - name
+    type: object
+  models.EgressGatewayRequest:
+    properties:
+      natenabled:
+        type: string
+      netid:
+        type: string
+      nodeid:
+        type: string
+      ranges:
+        items:
+          type: string
+        type: array
+    type: object
+  models.EgressInfo:
+    properties:
+      egress_gateway_cfg:
+        $ref: '#/definitions/models.EgressGatewayRequest'
+      egress_gw_addr:
+        $ref: '#/definitions/net.IPNet'
+      egress_gw_addr6:
+        $ref: '#/definitions/net.IPNet'
+      egress_id:
+        type: string
+      network:
+        $ref: '#/definitions/net.IPNet'
+      network6:
+        $ref: '#/definitions/net.IPNet'
+    type: object
+  models.EgressNetworkRoutes:
+    properties:
+      egress_gw_addr:
+        $ref: '#/definitions/net.IPNet'
+      egress_gw_addr6:
+        $ref: '#/definitions/net.IPNet'
+      egress_ranges:
+        items:
+          type: string
+        type: array
+      node_addr:
+        $ref: '#/definitions/net.IPNet'
+      node_addr6:
+        $ref: '#/definitions/net.IPNet'
+    type: object
+  models.EnrollmentKey:
+    properties:
+      expiration:
+        type: string
+      networks:
+        items:
+          type: string
+        type: array
+      relay:
+        type: string
+      tags:
+        items:
+          type: string
+        type: array
+      token:
+        description: B64 value of EnrollmentToken
+        type: string
+      type:
+        $ref: '#/definitions/models.KeyType'
+      unlimited:
+        type: boolean
+      uses_remaining:
+        type: integer
+      value:
+        type: string
+    type: object
+  models.ErrorResponse:
+    properties:
+      code:
+        type: integer
+      message:
+        type: string
+    type: object
+  models.ExtClient:
+    properties:
+      address:
+        type: string
+      address6:
+        type: string
+      allowed_ips:
+        items:
+          type: string
+        type: array
+      clientid:
+        type: string
+      deniednodeacls:
+        additionalProperties:
+          type: object
+        type: object
+      dns:
+        type: string
+      enabled:
+        type: boolean
+      extraallowedips:
+        items:
+          type: string
+        type: array
+      ingressgatewayendpoint:
+        type: string
+      ingressgatewayid:
+        type: string
+      lastmodified:
+        type: integer
+      network:
+        type: string
+      ownerid:
+        type: string
+      postdown:
+        type: string
+      postup:
+        type: string
+      privatekey:
+        type: string
+      publickey:
+        type: string
+      remote_access_client_id:
+        description: unique ID (MAC address) of RAC machine
+        type: string
+    type: object
+  models.FailOverMeReq:
+    properties:
+      node_id:
+        type: string
+    type: object
+  models.FwUpdate:
+    properties:
+      egress_info:
+        additionalProperties:
+          $ref: '#/definitions/models.EgressInfo'
+        type: object
+      is_egress_gw:
+        type: boolean
+    type: object
+  models.Host:
+    properties:
+      autoupdate:
+        type: boolean
+      daemoninstalled:
+        type: boolean
+      debug:
+        type: boolean
+      defaultinterface:
+        type: string
+      endpointip:
+        items:
+          type: integer
+        type: array
+      endpointipv6:
+        items:
+          type: integer
+        type: array
+      firewallinuse:
+        type: string
+      hostpass:
+        type: string
+      id:
+        type: string
+      interface:
+        type: string
+      interfaces:
+        items:
+          $ref: '#/definitions/models.Iface'
+        type: array
+      ipforwarding:
+        type: boolean
+      isdefault:
+        type: boolean
+      isdocker:
+        type: boolean
+      isk8s:
+        type: boolean
+      isstatic:
+        type: boolean
+      isstaticport:
+        type: boolean
+      listenport:
+        type: integer
+      macaddress:
+        items:
+          type: integer
+        type: array
+      mtu:
+        type: integer
+      name:
+        type: string
+      nat_type:
+        type: string
+      nodes:
+        items:
+          type: string
+        type: array
+      os:
+        type: string
+      persistentkeepalive:
+        $ref: '#/definitions/time.Duration'
+      publickey:
+        items:
+          type: integer
+        type: array
+      traffickeypublic:
+        items:
+          type: integer
+        type: array
+      turn_endpoint:
+        $ref: '#/definitions/netip.AddrPort'
+      verbosity:
+        type: integer
+      version:
+        type: string
+      wg_public_listen_port:
+        type: integer
+    type: object
+  models.HostInfoMap:
+    additionalProperties:
+      $ref: '#/definitions/models.HostNetworkInfo'
+    type: object
+  models.HostMqAction:
+    enum:
+    - UPGRADE
+    - SIGNAL_HOST
+    - UPDATE_HOST
+    - DELETE_HOST
+    - JOIN_HOST_TO_NETWORK
+    - ACK
+    - REQ_ACK
+    - CHECK_IN
+    - UPDATE_KEYS
+    - REQ_PULL
+    - SIGNAL_PULL
+    - UPDATE_METRICS
+    type: string
+    x-enum-varnames:
+    - Upgrade
+    - SignalHost
+    - UpdateHost
+    - DeleteHost
+    - JoinHostToNetwork
+    - Acknowledgement
+    - RequestAck
+    - CheckIn
+    - UpdateKeys
+    - RequestPull
+    - SignalPull
+    - UpdateMetrics
+  models.HostNetworkInfo:
+    properties:
+      interfaces:
+        items:
+          $ref: '#/definitions/models.Iface'
+        type: array
+      is_static:
+        type: boolean
+      is_static_port:
+        type: boolean
+      listen_port:
+        type: integer
+    type: object
+  models.HostPull:
+    properties:
+      change_default_gw:
+        type: boolean
+      default_gw_ip:
+        items:
+          type: integer
+        type: array
+      egress_network_routes:
+        items:
+          $ref: '#/definitions/models.EgressNetworkRoutes'
+        type: array
+      endpoint_detection:
+        type: boolean
+      fw_update:
+        $ref: '#/definitions/models.FwUpdate'
+      host:
+        $ref: '#/definitions/models.Host'
+      host_network_info:
+        $ref: '#/definitions/models.HostInfoMap'
+      is_inet_gw:
+        type: boolean
+      nodes:
+        items:
+          $ref: '#/definitions/models.Node'
+        type: array
+      peer_ids:
+        $ref: '#/definitions/models.PeerMap'
+      peers:
+        items:
+          $ref: '#/definitions/wgtypes.PeerConfig'
+        type: array
+      server_config:
+        $ref: '#/definitions/models.ServerConfig'
+    type: object
+  models.HostUpdate:
+    properties:
+      action:
+        $ref: '#/definitions/models.HostMqAction'
+      host:
+        $ref: '#/definitions/models.Host'
+      newMetrics:
+        $ref: '#/definitions/models.Metrics'
+      node:
+        $ref: '#/definitions/models.Node'
+      signal:
+        $ref: '#/definitions/models.Signal'
+    type: object
+  models.IDandAddr:
+    properties:
+      address:
+        type: string
+      host_id:
+        type: string
+      id:
+        type: string
+      is_extclient:
+        type: boolean
+      isserver:
+        type: string
+      listen_port:
+        type: integer
+      name:
+        type: string
+      network:
+        type: string
+    type: object
+  models.Iface:
+    properties:
+      address:
+        $ref: '#/definitions/net.IPNet'
+      addressString:
+        type: string
+      name:
+        type: string
+    type: object
+  models.InetNodeReq:
+    properties:
+      inet_node_client_ids:
+        items:
+          type: string
+        type: array
+    type: object
+  models.IngressGwUsers:
+    properties:
+      network:
+        type: string
+      node_id:
+        type: string
+      users:
+        items:
+          $ref: '#/definitions/models.ReturnUser'
+        type: array
+    type: object
+  models.KeyType:
+    enum:
+    - 0
+    - 1
+    - 2
+    - 3
+    type: integer
+    x-enum-varnames:
+    - Undefined
+    - TimeExpiration
+    - Uses
+    - Unlimited
+  models.Metric:
+    properties:
+      actualuptime:
+        $ref: '#/definitions/time.Duration'
+      connected:
+        type: boolean
+      latency:
+        type: integer
+      node_name:
+        type: string
+      percentup:
+        type: number
+      totalreceived:
+        type: integer
+      totalsent:
+        type: integer
+      totaltime:
+        type: integer
+      uptime:
+        type: integer
+    type: object
+  models.Metrics:
+    properties:
+      connectivity:
+        additionalProperties:
+          $ref: '#/definitions/models.Metric'
+        type: object
+      network:
+        type: string
+      node_id:
+        type: string
+      node_name:
+        type: string
+    type: object
+  models.Network:
+    properties:
+      addressrange:
+        type: string
+      addressrange6:
+        type: string
+      allowmanualsignup:
+        type: string
+      defaultacl:
+        type: string
+      defaultinterface:
+        maxLength: 35
+        minLength: 1
+        type: string
+      defaultkeepalive:
+        maximum: 1000
+        type: integer
+      defaultlistenport:
+        maximum: 65535
+        minimum: 1024
+        type: integer
+      defaultmtu:
+        type: integer
+      defaultpostdown:
+        type: string
+      defaultudpholepunch:
+        type: string
+      isipv4:
+        type: string
+      isipv6:
+        type: string
+      netid:
+        maxLength: 32
+        minLength: 1
+        type: string
+      networklastmodified:
+        type: integer
+      nodelimit:
+        type: integer
+      nodeslastmodified:
+        type: integer
+    required:
+    - netid
+    type: object
+  models.Node:
+    properties:
+      action:
+        type: string
+      additional_rag_ips:
+        items:
+          type: number
+        type: array
+      address:
+        $ref: '#/definitions/net.IPNet'
+      address6:
+        $ref: '#/definitions/net.IPNet'
+      connected:
+        type: boolean
+      defaultacl:
+        description: == PRO ==
+        type: string
+      dnson:
+        type: boolean
+      egressgatewaynatenabled:
+        type: boolean
+      egressgatewayranges:
+        items:
+          type: string
+        type: array
+      egressgatewayrequest:
+        $ref: '#/definitions/models.EgressGatewayRequest'
+      expdatetime:
+        type: string
+      fail_over_peers:
+        additionalProperties:
+          type: object
+        type: object
+      failed_over_by:
+        type: string
+      hostid:
+        type: string
+      id:
+        type: string
+      inet_node_req:
+        $ref: '#/definitions/models.InetNodeReq'
+      ingressdns:
+        type: string
+      ingressgatewayrange:
+        type: string
+      ingressgatewayrange6:
+        type: string
+      internetgw_node_id:
+        type: string
+      is_fail_over:
+        type: boolean
+      isegressgateway:
+        type: boolean
+      isingressgateway:
+        type: boolean
+      isinternetgateway:
+        type: boolean
+      isrelay:
+        type: boolean
+      isrelayed:
+        type: boolean
+      lastcheckin:
+        type: string
+      lastmodified:
+        type: string
+      lastpeerupdate:
+        type: string
+      localaddress:
+        $ref: '#/definitions/net.IPNet'
+      metadata:
+        type: string
+      network:
+        type: string
+      networkrange:
+        type: integer
+      networkrange6:
+        type: number
+      ownerid:
+        type: string
+      pendingdelete:
+        type: boolean
+      relayedby:
+        type: string
+      relaynodes:
+        items:
+          type: string
+        type: array
+      server:
+        type: string
+    type: object
+  models.NodeGet:
+    properties:
+      host:
+        $ref: '#/definitions/models.Host'
+      host_peers:
+        items:
+          $ref: '#/definitions/wgtypes.PeerConfig'
+        type: array
+      node:
+        $ref: '#/definitions/models.Node'
+      peerids:
+        $ref: '#/definitions/models.PeerMap'
+      peers:
+        items:
+          $ref: '#/definitions/wgtypes.PeerConfig'
+        type: array
+      serverconfig:
+        $ref: '#/definitions/models.ServerConfig'
+    type: object
+  models.PeerMap:
+    additionalProperties:
+      $ref: '#/definitions/models.IDandAddr'
+    type: object
+  models.RegisterResponse:
+    properties:
+      requested_host:
+        $ref: '#/definitions/models.Host'
+      server_config:
+        $ref: '#/definitions/models.ServerConfig'
+    type: object
+  models.RelayRequest:
+    properties:
+      netid:
+        type: string
+      nodeid:
+        type: string
+      relayaddrs:
+        items:
+          type: string
+        type: array
+    type: object
+  models.ReturnUser:
+    properties:
+      isadmin:
+        type: boolean
+      issuperadmin:
+        type: boolean
+      last_login_time:
+        type: string
+      remote_gw_ids:
+        additionalProperties:
+          type: object
+        type: object
+      username:
+        type: string
+    type: object
+  models.ServerConfig:
+    properties:
+      Is_EE:
+        type: boolean
+      api:
+        type: string
+      apiport:
+        type: string
+      broker:
+        type: string
+      brokerType:
+        type: string
+      coreDNSAddr:
+        type: string
+      dnsmode:
+        type: string
+      metricInterval:
+        type: string
+      mqpassword:
+        type: string
+      mqport:
+        type: string
+      mquserName:
+        type: string
+      server:
+        type: string
+      trafficKey:
+        items:
+          type: integer
+        type: array
+      version:
+        type: string
+    type: object
+  models.Signal:
+    properties:
+      action:
+        $ref: '#/definitions/models.SignalAction'
+      from_host_id:
+        type: string
+      from_host_pubkey:
+        type: string
+      from_node_id:
+        type: string
+      is_pro:
+        type: boolean
+      reply:
+        type: boolean
+      server:
+        type: string
+      timestamp:
+        type: integer
+      to_host_id:
+        type: string
+      to_host_pubkey:
+        type: string
+      to_node_id:
+        type: string
+    type: object
+  models.SignalAction:
+    enum:
+    - CONNECTION_NEGOTIATION
+    - RELAY_ME
+    type: string
+    x-enum-varnames:
+    - ConnNegotiation
+    - RelayME
+  models.SuccessResponse:
+    properties:
+      code:
+        type: integer
+      message:
+        type: string
+      response: {}
+    type: object
+  models.User:
+    properties:
+      isadmin:
+        type: boolean
+      issuperadmin:
+        type: boolean
+      last_login_time:
+        type: string
+      password:
+        minLength: 5
+        type: string
+      remote_gw_ids:
+        additionalProperties:
+          type: object
+        type: object
+      username:
+        maxLength: 40
+        minLength: 3
+        type: string
+    required:
+    - password
+    type: object
+  models.UserAuthParams:
+    properties:
+      password:
+        type: string
+      username:
+        type: string
+    type: object
+  models.UserRemoteGws:
+    properties:
+      allowed_endpoints:
+        items:
+          type: string
+        type: array
+      connected:
+        type: boolean
+      gw_client:
+        $ref: '#/definitions/models.ExtClient'
+      gw_listen_port:
+        type: integer
+      gw_name:
+        type: string
+      gw_peer_public_key:
+        type: string
+      is_internet_gateway:
+        type: boolean
+      metadata:
+        type: string
+      network:
+        type: string
+      network_addresses:
+        items:
+          type: string
+        type: array
+      remote_access_gw_id:
+        type: string
+    type: object
+  net.IPNet:
+    properties:
+      ip:
+        description: network number
+        items:
+          type: integer
+        type: array
+      mask:
+        description: network mask
+        items:
+          type: integer
+        type: array
+    type: object
+  net.UDPAddr:
+    properties:
+      ip:
+        items:
+          type: integer
+        type: array
+      port:
+        type: integer
+      zone:
+        description: IPv6 scoped addressing zone
+        type: string
+    type: object
+  netip.AddrPort:
+    type: object
+  time.Duration:
+    enum:
+    - -9223372036854775808
+    - 9223372036854775807
+    - 1
+    - 1000
+    - 1000000
+    - 1000000000
+    - 60000000000
+    - 3600000000000
+    - -9223372036854775808
+    - 9223372036854775807
+    - 1
+    - 1000
+    - 1000000
+    - 1000000000
+    - 60000000000
+    - 3600000000000
+    type: integer
+    x-enum-varnames:
+    - minDuration
+    - maxDuration
+    - Nanosecond
+    - Microsecond
+    - Millisecond
+    - Second
+    - Minute
+    - Hour
+    - minDuration
+    - maxDuration
+    - Nanosecond
+    - Microsecond
+    - Millisecond
+    - Second
+    - Minute
+    - Hour
+  wgtypes.PeerConfig:
+    properties:
+      allowedIPs:
+        description: |-
+          AllowedIPs specifies a list of allowed IP addresses in CIDR notation
+          for this peer.
+        items:
+          $ref: '#/definitions/net.IPNet'
+        type: array
+      endpoint:
+        allOf:
+        - $ref: '#/definitions/net.UDPAddr'
+        description: Endpoint specifies the endpoint of this peer entry, if not nil.
+      persistentKeepaliveInterval:
+        allOf:
+        - $ref: '#/definitions/time.Duration'
+        description: |-
+          PersistentKeepaliveInterval specifies the persistent keepalive interval
+          for this peer, if not nil.
+
+          A non-nil value of 0 will clear the persistent keepalive interval.
+      presharedKey:
+        description: |-
+          PresharedKey specifies a peer's preshared key configuration, if not nil.
+
+          A non-nil, zero-value Key will clear the preshared key.
+        items:
+          type: integer
+        type: array
+      publicKey:
+        description: |-
+          PublicKey specifies the public key of this peer.  PublicKey is a
+          mandatory field for all PeerConfigs.
+        items:
+          type: integer
+        type: array
+      remove:
+        description: |-
+          Remove specifies if the peer with this public key should be removed
+          from a device's peer list.
+        type: boolean
+      replaceAllowedIPs:
+        description: |-
+          ReplaceAllowedIPs specifies if the allowed IPs specified in this peer
+          configuration should replace any existing ones, instead of appending them
+          to the allowed IPs list.
+        type: boolean
+      updateOnly:
+        description: |-
+          UpdateOnly specifies that an operation will only occur on this peer
+          if the peer already exists as part of the interface.
+        type: boolean
+    type: object
+host: api.demo.netmaker.io
+info:
+  contact: {}
+  description: NetMaker API Docs
+  title: NetMaker
+  version: 0.24.3
+paths:
+  /api/dns:
+    get:
+      consumes:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            items:
+              $ref: '#/definitions/models.DNSEntry'
+            type: array
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      summary: Get all DNS entries
+      tags:
+      - DNS
+  /api/dns/{network}:
+    get:
+      consumes:
+      - application/json
+      parameters:
+      - description: Network identifier
+        in: path
+        name: network
+        required: true
+        type: string
+      responses:
+        "200":
+          description: OK
+          schema:
+            items:
+              $ref: '#/definitions/models.DNSEntry'
+            type: array
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      summary: Gets node DNS entries associated with a network
+      tags:
+      - DNS
+  /api/dns/{network}/{domain}:
+    delete:
+      consumes:
+      - application/json
+      parameters:
+      - description: Network identifier
+        in: path
+        name: network
+        required: true
+        type: string
+      - description: Domain Name
+        in: path
+        name: domain
+        required: true
+        type: string
+      responses:
+        "200":
+          description: OK
+          schema:
+            items:
+              $ref: '#/definitions/models.DNSEntry'
+            type: array
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      summary: Delete a DNS entry
+      tags:
+      - DNS
+  /api/dns/adm/{network}:
+    get:
+      consumes:
+      - application/json
+      parameters:
+      - description: Network identifier
+        in: path
+        name: network
+        required: true
+        type: string
+      responses:
+        "200":
+          description: OK
+          schema:
+            items:
+              $ref: '#/definitions/models.DNSEntry'
+            type: array
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      summary: Get all DNS entries associated with the network
+      tags:
+      - DNS
+    post:
+      consumes:
+      - application/json
+      parameters:
+      - description: Network identifier
+        in: path
+        name: network
+        required: true
+        type: string
+      - description: DNS entry details
+        in: body
+        name: body
+        required: true
+        schema:
+          $ref: '#/definitions/models.DNSEntry'
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.DNSEntry'
+        "400":
+          description: Bad Request
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      summary: Create a new DNS entry
+      tags:
+      - DNS
+  /api/dns/adm/{network}/custom:
+    get:
+      consumes:
+      - application/json
+      parameters:
+      - description: Network identifier
+        in: path
+        name: network
+        required: true
+        type: string
+      responses:
+        "200":
+          description: OK
+          schema:
+            items:
+              $ref: '#/definitions/models.DNSEntry'
+            type: array
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      summary: Gets custom DNS entries associated with a network
+      tags:
+      - DNS
+  /api/dns/adm/pushdns:
+    post:
+      consumes:
+      - application/json
+      responses:
+        "200":
+          description: DNS Pushed to CoreDNS
+          schema:
+            type: string
+        "400":
+          description: Bad Request
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      summary: Push DNS entries to nameserver
+      tags:
+      - DNS
+  /api/emqx/hosts:
+    delete:
+      responses:
+        "200":
+          description: deleted hosts data on emqx
+          schema:
+            type: string
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      security:
+      - oauth: []
+      summary: Deletes all EMQX hosts
+      tags:
+      - Hosts
+  /api/extclients:
+    get:
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.ExtClient'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      security:
+      - oauth2: []
+      summary: Fetches All Remote Access Clients across all networks
+      tags:
+      - Remote Access Client
+  /api/extclients/{network}:
+    get:
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.ExtClient'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      security:
+      - oauth2: []
+      summary: Get all remote access client associated with network
+      tags:
+      - Remote Access Client
+  /api/extclients/{network}/{clientid}:
+    delete:
+      responses:
+        "200":
+          description: OK
+        "403":
+          description: Forbidden
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      security:
+      - oauth2: []
+      summary: Delete an individual remote access client
+      tags:
+      - Remote Access Client
+    get:
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.ExtClient'
+        "403":
+          description: Forbidden
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      security:
+      - oauth2: []
+      summary: Get an individual remote access client
+      tags:
+      - Remote Access Client
+    put:
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.ExtClient'
+        "400":
+          description: Bad Request
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+        "403":
+          description: Forbidden
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      security:
+      - oauth2: []
+      summary: Update an individual remote access client
+      tags:
+      - Remote Access Client
+  /api/extclients/{network}/{clientid}/{type}:
+    get:
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.ExtClient'
+        "403":
+          description: Forbidden
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      security:
+      - oauth2: []
+      summary: Get an individual remote access client
+      tags:
+      - Remote Access Client
+  /api/extclients/{network}/{nodeid}:
+    post:
+      responses:
+        "200":
+          description: OK
+          schema:
+            type: string
+        "400":
+          description: Bad Request
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+        "403":
+          description: Forbidden
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      security:
+      - oauth2: []
+      summary: Create an individual remote access client
+      tags:
+      - Remote Access Client
+  /api/getip:
+    get:
+      responses:
+        "200":
+          description: The public IP address.
+          schema:
+            type: string
+        "400":
+          description: Invalid IP address or no IP found.
+          schema:
+            type: string
+      security:
+      - oauth2: []
+      summary: Get the current public IP address.
+      tags:
+      - IP Service
+  /api/hosts:
+    get:
+      responses:
+        "200":
+          description: OK
+          schema:
+            items:
+              $ref: '#/definitions/models.ApiHost'
+            type: array
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      security:
+      - oauth: []
+      summary: List all hosts
+      tags:
+      - Hosts
+  /api/hosts/{hostid}:
+    delete:
+      parameters:
+      - description: Host ID
+        in: path
+        name: hostid
+        required: true
+        type: string
+      - description: Force delete
+        in: query
+        name: force
+        type: boolean
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.ApiHost'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      security:
+      - oauth: []
+      summary: Deletes a Netclient host from Netmaker server
+      tags:
+      - Hosts
+    put:
+      parameters:
+      - description: Host ID
+        in: path
+        name: hostid
+        required: true
+        type: string
+      - description: New host data
+        in: body
+        name: body
+        required: true
+        schema:
+          $ref: '#/definitions/models.ApiHost'
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.ApiHost'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      security:
+      - oauth: []
+      summary: Updates a Netclient host on Netmaker server
+      tags:
+      - Hosts
+  /api/hosts/{hostid}/keys:
+    put:
+      parameters:
+      - description: Host ID
+        in: path
+        name: hostid
+        required: true
+        type: string
+      responses:
+        "200":
+          description: OK
+          schema:
+            type: string
+        "400":
+          description: Bad Request
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      security:
+      - oauth: []
+      summary: Update keys for a host
+      tags:
+      - Hosts
+  /api/hosts/{hostid}/networks/{network}:
+    delete:
+      parameters:
+      - description: Host ID
+        in: path
+        name: hostid
+        required: true
+        type: string
+      - description: Network name
+        in: path
+        name: network
+        required: true
+        type: string
+      - description: Force delete
+        in: query
+        name: force
+        type: boolean
+      responses:
+        "200":
+          description: OK
+          schema:
+            type: string
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      security:
+      - oauth: []
+      summary: To Remove Host from Network
+      tags:
+      - Hosts
+    post:
+      parameters:
+      - description: Host ID
+        in: path
+        name: hostid
+        required: true
+        type: string
+      - description: Network name
+        in: path
+        name: network
+        required: true
+        type: string
+      responses:
+        "200":
+          description: OK
+          schema:
+            type: string
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      security:
+      - oauth: []
+      summary: To Add Host To Network
+      tags:
+      - Hosts
+  /api/hosts/{hostid}/sync:
+    post:
+      parameters:
+      - description: Host ID
+        in: path
+        name: hostid
+        required: true
+        type: string
+      responses:
+        "200":
+          description: OK
+          schema:
+            type: string
+        "400":
+          description: Bad Request
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      security:
+      - oauth: []
+      summary: Requests a host to pull
+      tags:
+      - Hosts
+  /api/hosts/{hostid}/upgrade:
+    put:
+      parameters:
+      - description: Host ID
+        in: path
+        name: hostid
+        required: true
+        type: string
+      responses:
+        "200":
+          description: passed message to upgrade host
+          schema:
+            type: string
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      security:
+      - oauth: []
+      summary: Upgrade a host
+      tags:
+      - Hosts
+  /api/hosts/adm/authenticate:
+    post:
+      consumes:
+      - application/json
+      parameters:
+      - description: Authentication parameters
+        in: body
+        name: body
+        required: true
+        schema:
+          $ref: '#/definitions/models.AuthParams'
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.SuccessResponse'
+        "400":
+          description: Bad Request
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+        "401":
+          description: Unauthorized
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      summary: To Fetch Auth Token for a Host
+      tags:
+      - Auth
+  /api/hosts/keys:
+    put:
+      responses:
+        "200":
+          description: OK
+          schema:
+            type: string
+        "400":
+          description: Bad Request
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      security:
+      - oauth: []
+      summary: Update keys for all hosts
+      tags:
+      - Hosts
+  /api/networks:
+    get:
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.Network'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      security:
+      - oauth: []
+      summary: Lists all networks
+      tags:
+      - Networks
+    post:
+      parameters:
+      - description: Network details
+        in: body
+        name: body
+        required: true
+        schema:
+          $ref: '#/definitions/models.Network'
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.Network'
+        "400":
+          description: Bad Request
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      security:
+      - oauth: []
+      summary: Create a network
+      tags:
+      - Networks
+  /api/networks/{networkname}:
+    delete:
+      parameters:
+      - description: Network name
+        in: path
+        name: networkname
+        required: true
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.SuccessResponse'
+        "400":
+          description: Bad Request
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+        "403":
+          description: Forbidden
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      security:
+      - oauth: []
+      summary: Delete a network
+      tags:
+      - Networks
+    get:
+      parameters:
+      - description: Network name
+        in: path
+        name: networkname
+        required: true
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.Network'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      security:
+      - oauth: []
+      summary: Get a network
+      tags:
+      - Networks
+    put:
+      parameters:
+      - description: Network name
+        in: path
+        name: networkname
+        required: true
+        type: string
+      - description: Network details
+        in: body
+        name: body
+        required: true
+        schema:
+          $ref: '#/definitions/models.Network'
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.Network'
+        "400":
+          description: Bad Request
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      security:
+      - oauth: []
+      summary: Update network settings
+      tags:
+      - Networks
+  /api/networks/{networkname}/acls:
+    get:
+      parameters:
+      - description: Network name
+        in: path
+        name: networkname
+        required: true
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/acls.ACLContainer'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      security:
+      - oauth: []
+      summary: Get a network ACL (Access Control List)
+      tags:
+      - Networks
+    put:
+      parameters:
+      - description: Network name
+        in: path
+        name: networkname
+        required: true
+        type: string
+      - description: ACL container
+        in: body
+        name: body
+        required: true
+        schema:
+          $ref: '#/definitions/acls.ACLContainer'
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/acls.ACLContainer'
+        "400":
+          description: Bad Request
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      security:
+      - oauth: []
+      summary: Update a network ACL (Access Control List)
+      tags:
+      - Networks
+  /api/networks/{networkname}/acls/v2:
+    put:
+      parameters:
+      - description: Network name
+        in: path
+        name: networkname
+        required: true
+        type: string
+      - description: ACL container
+        in: body
+        name: body
+        required: true
+        schema:
+          $ref: '#/definitions/acls.ACLContainer'
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/acls.ACLContainer'
+        "400":
+          description: Bad Request
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      security:
+      - oauth: []
+      summary: Update a network ACL (Access Control List)
+      tags:
+      - Networks
+  /api/nodes:
+    get:
+      responses:
+        "200":
+          description: OK
+          schema:
+            items:
+              $ref: '#/definitions/models.ApiNode'
+            type: array
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      summary: Get all nodes across all networks
+      tags:
+      - Nodes
+  /api/nodes/{network}/{nodeid}:
+    delete:
+      responses:
+        "200":
+          description: Node deleted.
+          schema:
+            type: string
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      security:
+      - oauth2: []
+      summary: Delete an individual node
+      tags:
+      - Nodes
+    get:
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.NodeGet'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      security:
+      - oauth2: []
+      summary: Get an individual node
+      tags:
+      - Nodes
+    put:
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.ApiNode'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      security:
+      - oauth2: []
+      summary: Update an individual node
+      tags:
+      - Nodes
+  /api/nodes/{network}/{nodeid}/creategateway:
+    post:
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.ApiNode'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      security:
+      - oauth2: []
+      summary: Create an egress gateway
+      tags:
+      - Nodes
+  /api/nodes/{network}/{nodeid}/createingress:
+    post:
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.ApiNode'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      security:
+      - oauth2: []
+      summary: Create an remote access gateway
+      tags:
+      - Nodes
+  /api/nodes/{network}/{nodeid}/createrelay:
+    post:
+      consumes:
+      - application/json
+      parameters:
+      - description: Network ID
+        in: path
+        name: network
+        required: true
+        type: string
+      - description: Node ID
+        in: path
+        name: nodeid
+        required: true
+        type: string
+      - description: Relay request parameters
+        in: body
+        name: body
+        required: true
+        schema:
+          $ref: '#/definitions/models.RelayRequest'
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.ApiNode'
+        "400":
+          description: Bad Request
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      summary: Create a relay
+      tags:
+      - PRO
+  /api/nodes/{network}/{nodeid}/deletegateway:
+    delete:
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.ApiNode'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      security:
+      - oauth2: []
+      summary: Delete an egress gateway
+      tags:
+      - Nodes
+  /api/nodes/{network}/{nodeid}/deleteingress:
+    delete:
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.ApiNode'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      security:
+      - oauth2: []
+      summary: Delete an remote access gateway
+      tags:
+      - Nodes
+  /api/nodes/{network}/{nodeid}/deleterelay:
+    delete:
+      consumes:
+      - application/json
+      parameters:
+      - description: Network ID
+        in: path
+        name: network
+        required: true
+        type: string
+      - description: Node ID
+        in: path
+        name: nodeid
+        required: true
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.ApiNode'
+        "400":
+          description: Bad Request
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      summary: Remove a relay
+      tags:
+      - PRO
+  /api/nodes/{network}/{nodeid}/inet_gw:
+    delete:
+      parameters:
+      - description: Network ID
+        in: path
+        name: network
+        required: true
+        type: string
+      - description: Node ID
+        in: path
+        name: nodeid
+        required: true
+        type: string
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.Node'
+        "400":
+          description: Bad Request
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      summary: Delete an internet gateway
+      tags:
+      - PRO
+    post:
+      consumes:
+      - application/json
+      parameters:
+      - description: Network ID
+        in: path
+        name: network
+        required: true
+        type: string
+      - description: Node ID
+        in: path
+        name: nodeid
+        required: true
+        type: string
+      - description: Internet gateway request
+        in: body
+        name: body
+        required: true
+        schema:
+          $ref: '#/definitions/models.InetNodeReq'
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.Node'
+        "400":
+          description: Bad Request
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      summary: Create an internet gateway
+      tags:
+      - PRO
+    put:
+      consumes:
+      - application/json
+      parameters:
+      - description: Network ID
+        in: path
+        name: network
+        required: true
+        type: string
+      - description: Node ID
+        in: path
+        name: nodeid
+        required: true
+        type: string
+      - description: Internet gateway request
+        in: body
+        name: body
+        required: true
+        schema:
+          $ref: '#/definitions/models.InetNodeReq'
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.Node'
+        "400":
+          description: Bad Request
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      summary: Update an internet gateway
+      tags:
+      - PRO
+  /api/nodes/{network}/{nodeid}/ingress/users:
+    get:
+      consumes:
+      - application/json
+      parameters:
+      - description: Ingress Gateway ID
+        in: path
+        name: ingress_id
+        required: true
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            items:
+              $ref: '#/definitions/models.IngressGwUsers'
+            type: array
+        "400":
+          description: Bad Request
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      summary: List users attached to an ingress gateway
+      tags:
+      - PRO
+  /api/nodes/adm/{network}:
+    get:
+      responses:
+        "200":
+          description: OK
+          schema:
+            items:
+              $ref: '#/definitions/models.Node'
+            type: array
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      summary: Gets all nodes associated with network including pending nodes
+      tags:
+      - Nodes
+  /api/server/getconfig:
+    get:
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/config.ServerConfig'
+      security:
+      - oauth2: []
+      summary: Get the server configuration
+      tags:
+      - Server
+  /api/server/getserverinfo:
+    get:
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.ServerConfig'
+      security:
+      - oauth2: []
+      summary: Get the server information
+      tags:
+      - Server
+  /api/server/status:
+    get:
+      responses: {}
+      security:
+      - oauth2: []
+      summary: Get the server status
+      tags:
+      - Server
+  /api/users:
+    get:
+      responses:
+        "200":
+          description: OK
+          schema:
+            items:
+              $ref: '#/definitions/models.User'
+            type: array
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      summary: Get all users
+      tags:
+      - Users
+  /api/users/{username}:
+    delete:
+      parameters:
+      - description: Username of the user to delete
+        in: path
+        name: username
+        required: true
+        type: string
+      responses:
+        "200":
+          description: OK
+          schema:
+            type: string
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      summary: Delete a user
+      tags:
+      - Users
+    get:
+      parameters:
+      - description: Username of the user to fetch
+        in: path
+        name: username
+        required: true
+        type: string
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.User'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      summary: Get an individual user
+      tags:
+      - Users
+    post:
+      parameters:
+      - description: Username of the user to create
+        in: path
+        name: username
+        required: true
+        type: string
+      - description: User details
+        in: body
+        name: body
+        required: true
+        schema:
+          $ref: '#/definitions/models.User'
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.User'
+        "400":
+          description: Bad Request
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+        "403":
+          description: Forbidden
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      summary: Create a user
+      tags:
+      - Users
+    put:
+      parameters:
+      - description: Username of the user to update
+        in: path
+        name: username
+        required: true
+        type: string
+      - description: User details
+        in: body
+        name: body
+        required: true
+        schema:
+          $ref: '#/definitions/models.User'
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.User'
+        "400":
+          description: Bad Request
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+        "403":
+          description: Forbidden
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      summary: Update a user
+      tags:
+      - Users
+  /api/users/{username}/remote_access_gw:
+    get:
+      consumes:
+      - application/json
+      parameters:
+      - description: Username
+        in: path
+        name: username
+        required: true
+        type: string
+      - description: Remote Access Client ID
+        in: query
+        name: remote_access_clientid
+        type: string
+      - description: Request from mobile
+        in: query
+        name: from_mobile
+        type: boolean
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            items:
+              $ref: '#/definitions/models.UserRemoteGws'
+            type: array
+        "400":
+          description: Bad Request
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      summary: Get user's remote access gateways
+      tags:
+      - PRO
+  /api/users/{username}/remote_access_gw/{remote_access_gateway_id}:
+    delete:
+      consumes:
+      - application/json
+      parameters:
+      - description: Username
+        in: path
+        name: username
+        required: true
+        type: string
+      - description: Remote Access Gateway ID
+        in: path
+        name: remote_access_gateway_id
+        required: true
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.ReturnUser'
+        "400":
+          description: Bad Request
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      summary: Remove user from a remote access gateway
+      tags:
+      - PRO
+    post:
+      consumes:
+      - application/json
+      parameters:
+      - description: Username
+        in: path
+        name: username
+        required: true
+        type: string
+      - description: Remote Access Gateway ID
+        in: path
+        name: remote_access_gateway_id
+        required: true
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.ReturnUser'
+        "400":
+          description: Bad Request
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      summary: Attach user to a remote access gateway
+      tags:
+      - PRO
+  /api/users/adm/authenticate:
+    post:
+      consumes:
+      - application/json
+      parameters:
+      - description: Authentication parameters
+        in: body
+        name: body
+        required: true
+        schema:
+          $ref: '#/definitions/models.UserAuthParams'
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.SuccessResponse'
+        "400":
+          description: Bad Request
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+        "401":
+          description: Unauthorized
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      summary: Authenticate a user to retrieve an authorization token
+      tags:
+      - Auth
+  /api/users/adm/createsuperadmin:
+    post:
+      parameters:
+      - description: User details
+        in: body
+        name: body
+        required: true
+        schema:
+          $ref: '#/definitions/models.User'
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.User'
+        "400":
+          description: Bad Request
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      summary: Create a super admin
+      tags:
+      - Users
+  /api/users/adm/hassuperadmin:
+    get:
+      responses:
+        "200":
+          description: OK
+          schema:
+            type: boolean
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      summary: Check if the server has a super admin
+      tags:
+      - Users
+  /api/users/adm/transfersuperadmin/{username}:
+    post:
+      parameters:
+      - description: Username of the user to transfer super admin role
+        in: path
+        name: username
+        required: true
+        type: string
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.User'
+        "403":
+          description: Forbidden
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      summary: Transfer super admin role to another admin user
+      tags:
+      - Users
+  /api/users_pending:
+    delete:
+      responses:
+        "200":
+          description: OK
+          schema:
+            type: string
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      summary: Delete all pending users
+      tags:
+      - Users
+    get:
+      responses:
+        "200":
+          description: OK
+          schema:
+            items:
+              $ref: '#/definitions/models.User'
+            type: array
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      summary: Get all pending users
+      tags:
+      - Users
+  /api/users_pending/user/{username}:
+    delete:
+      parameters:
+      - description: Username of the pending user to delete
+        in: path
+        name: username
+        required: true
+        type: string
+      responses:
+        "200":
+          description: OK
+          schema:
+            type: string
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      summary: Delete a pending user
+      tags:
+      - Users
+    post:
+      parameters:
+      - description: Username of the pending user to approve
+        in: path
+        name: username
+        required: true
+        type: string
+      responses:
+        "200":
+          description: OK
+          schema:
+            type: string
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      summary: Approve a pending user
+      tags:
+      - Users
+  /api/v1/enrollment-keys:
+    get:
+      responses:
+        "200":
+          description: OK
+          schema:
+            items:
+              $ref: '#/definitions/models.EnrollmentKey'
+            type: array
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      security:
+      - oauth: []
+      summary: Lists all EnrollmentKeys for admins
+      tags:
+      - EnrollmentKeys
+    post:
+      parameters:
+      - description: Enrollment Key parameters
+        in: body
+        name: body
+        required: true
+        schema:
+          $ref: '#/definitions/models.APIEnrollmentKey'
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.EnrollmentKey'
+        "400":
+          description: Bad Request
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      security:
+      - oauth: []
+      summary: Creates an EnrollmentKey for hosts to register with server and join
+        networks
+      tags:
+      - EnrollmentKeys
+  /api/v1/enrollment-keys/{keyid}:
+    delete:
+      parameters:
+      - description: Enrollment Key ID
+        in: path
+        name: keyid
+        required: true
+        type: string
+      responses:
+        "200":
+          description: OK
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      security:
+      - oauth: []
+      summary: Deletes an EnrollmentKey from Netmaker server
+      tags:
+      - EnrollmentKeys
+    put:
+      parameters:
+      - description: Enrollment Key ID
+        in: path
+        name: keyid
+        required: true
+        type: string
+      - description: Enrollment Key parameters
+        in: body
+        name: body
+        required: true
+        schema:
+          $ref: '#/definitions/models.APIEnrollmentKey'
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.EnrollmentKey'
+        "400":
+          description: Bad Request
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      security:
+      - oauth: []
+      summary: Updates an EnrollmentKey. Updates are only limited to the relay to
+        use
+      tags:
+      - EnrollmentKeys
+  /api/v1/fallback/host/{hostid}:
+    put:
+      parameters:
+      - description: Host ID
+        in: path
+        name: hostid
+        required: true
+        type: string
+      - description: Host update data
+        in: body
+        name: body
+        required: true
+        schema:
+          $ref: '#/definitions/models.HostUpdate'
+      responses:
+        "200":
+          description: updated host data
+          schema:
+            type: string
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      security:
+      - oauth: []
+      summary: Updates a Netclient host on Netmaker server
+      tags:
+      - Hosts
+  /api/v1/host:
+    get:
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.HostPull'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      security:
+      - oauth: []
+      summary: Used by clients for "pull" command
+      tags:
+      - Hosts
+  /api/v1/host/{hostid}/signalpeer:
+    post:
+      parameters:
+      - description: Host ID
+        in: path
+        name: hostid
+        required: true
+        type: string
+      - description: Signal data
+        in: body
+        name: body
+        required: true
+        schema:
+          $ref: '#/definitions/models.Signal'
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.Signal'
+        "400":
+          description: Bad Request
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      security:
+      - oauth: []
+      summary: Send signal to peer
+      tags:
+      - Hosts
+  /api/v1/host/register/{token}:
+    post:
+      parameters:
+      - description: Enrollment Key Token
+        in: path
+        name: token
+        required: true
+        type: string
+      - description: Host registration parameters
+        in: body
+        name: body
+        required: true
+        schema:
+          $ref: '#/definitions/models.Host'
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.RegisterResponse'
+        "400":
+          description: Bad Request
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      security:
+      - oauth: []
+      summary: Handles a Netclient registration with server and add nodes accordingly
+      tags:
+      - EnrollmentKeys
+  /api/v1/legacy/nodes:
+    delete:
+      responses:
+        "200":
+          description: Wiped all legacy nodes.
+          schema:
+            type: string
+        "400":
+          description: Bad Request
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      security:
+      - oauth2: []
+      summary: Delete all legacy nodes from DB.
+      tags:
+      - Nodes
+  /api/v1/node/{network}/failover/reset:
+    post:
+      parameters:
+      - description: Network ID
+        in: path
+        name: network
+        required: true
+        type: string
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.SuccessResponse'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      summary: Reset failover for a network
+      tags:
+      - PRO
+  /api/v1/node/{nodeid}/failover:
+    delete:
+      parameters:
+      - description: Node ID
+        in: path
+        name: nodeid
+        required: true
+        type: string
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.Node'
+        "400":
+          description: Bad Request
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      summary: Delete failover node
+      tags:
+      - PRO
+    get:
+      parameters:
+      - description: Node ID
+        in: path
+        name: nodeid
+        required: true
+        type: string
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.Node'
+        "400":
+          description: Bad Request
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+        "404":
+          description: Not Found
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      summary: Get failover node
+      tags:
+      - PRO
+    post:
+      parameters:
+      - description: Node ID
+        in: path
+        name: nodeid
+        required: true
+        type: string
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.Node'
+        "400":
+          description: Bad Request
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      summary: Create failover node
+      tags:
+      - PRO
+  /api/v1/node/{nodeid}/failover_me:
+    post:
+      consumes:
+      - application/json
+      parameters:
+      - description: Node ID
+        in: path
+        name: nodeid
+        required: true
+        type: string
+      - description: Failover request
+        in: body
+        name: body
+        required: true
+        schema:
+          $ref: '#/definitions/models.FailOverMeReq'
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/models.SuccessResponse'
+        "400":
+          description: Bad Request
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/models.ErrorResponse'
+      summary: Failover me
+      tags:
+      - PRO
+  /meshclient/files/{filename}:
+    get:
+      responses:
+        "200":
+          description: file
+          schema:
+            type: body
+        "404":
+          description: 404 not found
+          schema:
+            type: string
+      summary: Retrieve a file from the file server
+      tags:
+      - Meshclient
+swagger: "2.0"
+tags:
+- description: |
+    Most actions that can be performed via API can be performed via UI. We recommend managing your networks using the official netmaker-ui project. However, Netmaker can also be run without the UI, and all functions can be achieved via API calls. If your use case requires using Netmaker without the UI or you need to do some troubleshooting/advanced configuration, using the API directly may help.
+  name: APIUsage
+- description: |
+    API calls are primarily authenticated using a user authentication token. This token should be included in the header as follows:
+
+    -H "Authorization: Bearer <YOUR_AUTH_TOKEN>"
+
+    To obtain YOUR_AUTH_TOKEN:
+    Call the api/users/adm/authenticate endpoint (see documentation below for details).
+
+    Note: While a MasterKey exists (configurable via env var or config file), it should be considered a backup option, used only when server access is lost. By default, this key is "secret key," but it's crucial to change this and keep it secure in your instance.
+
+    For more information on configuration and security best practices, refer to the [Netmaker documentation](https://docs.netmaker.org/index.html).
+  name: Authentication
+- description: |
+    Check out our [Pricing](https://www.netmaker.io/pricing). And Feel Free to [Contact Us](https://www.netmaker.io/contact) if you have any questions or need some clarifications.
+  name: Pricing

+ 0 - 3006
swagger.yml

@@ -1,3006 +0,0 @@
-basePath: /
-consumes:
-    - application/json
-definitions:
-    ACL:
-        additionalProperties:
-            format: uint8
-            type: integer
-        description: ACL - the ACL of other nodes in a NetworkACL for a single unique node
-        type: object
-        x-go-package: github.com/gravitl/netmaker/logic/acls
-    ACLContainer:
-        additionalProperties:
-            $ref: '#/definitions/ACL'
-        description: ACLContainer - the total list of all node's ACL in a given network
-        type: object
-        x-go-package: github.com/gravitl/netmaker/logic/acls
-    APIEnrollmentKey:
-        description: APIEnrollmentKey - used to create enrollment keys via API
-        properties:
-            expiration:
-                format: int64
-                type: integer
-                x-go-name: Expiration
-            networks:
-                items:
-                    type: string
-                type: array
-                x-go-name: Networks
-            relay:
-                type: string
-                x-go-name: Relay
-            tags:
-                items:
-                    type: string
-                type: array
-                x-go-name: Tags
-            type:
-                $ref: '#/definitions/KeyType'
-            unlimited:
-                type: boolean
-                x-go-name: Unlimited
-            uses_remaining:
-                format: int64
-                type: integer
-                x-go-name: UsesRemaining
-        type: object
-        x-go-package: github.com/gravitl/netmaker/models
-    ApiHost:
-        description: ApiHost - the host struct for API usage
-        properties:
-            autoupdate:
-                type: boolean
-                x-go-name: AutoUpdate
-            debug:
-                type: boolean
-                x-go-name: Debug
-            defaultinterface:
-                type: string
-                x-go-name: DefaultInterface
-            endpointip:
-                type: string
-                x-go-name: EndpointIP
-            endpointipv6:
-                type: string
-                x-go-name: EndpointIPv6
-            firewallinuse:
-                type: string
-                x-go-name: FirewallInUse
-            id:
-                type: string
-                x-go-name: ID
-            interfaces:
-                items:
-                    $ref: '#/definitions/ApiIface'
-                type: array
-                x-go-name: Interfaces
-            isdefault:
-                type: boolean
-                x-go-name: IsDefault
-            isstatic:
-                type: boolean
-                x-go-name: IsStatic
-            listenport:
-                format: int64
-                type: integer
-                x-go-name: ListenPort
-            macaddress:
-                type: string
-                x-go-name: MacAddress
-            mtu:
-                format: int64
-                type: integer
-                x-go-name: MTU
-            name:
-                type: string
-                x-go-name: Name
-            nat_type:
-                type: string
-                x-go-name: NatType
-            nodes:
-                items:
-                    type: string
-                type: array
-                x-go-name: Nodes
-            os:
-                type: string
-                x-go-name: OS
-            persistentkeepalive:
-                format: int64
-                type: integer
-                x-go-name: PersistentKeepalive
-            publickey:
-                type: string
-                x-go-name: PublicKey
-            verbosity:
-                format: int64
-                type: integer
-                x-go-name: Verbosity
-            version:
-                type: string
-                x-go-name: Version
-            wg_public_listen_port:
-                format: int64
-                type: integer
-                x-go-name: WgPublicListenPort
-        type: object
-        x-go-package: github.com/gravitl/netmaker/models
-    ApiIface:
-        description: |-
-            ApiIface - the interface struct for API usage
-            The original Iface struct contains a net.Address, which does not get marshalled correctly
-        properties:
-            addressString:
-                type: string
-                x-go-name: AddressString
-            name:
-                type: string
-                x-go-name: Name
-        type: object
-        x-go-package: github.com/gravitl/netmaker/models
-    ApiNode:
-        description: ApiNode is a stripped down Node DTO that exposes only required fields to external systems
-        properties:
-            address:
-                type: string
-                x-go-name: Address
-            address6:
-                type: string
-                x-go-name: Address6
-            allowedips:
-                items:
-                    type: string
-                type: array
-                x-go-name: AllowedIPs
-            connected:
-                type: boolean
-                x-go-name: Connected
-            defaultacl:
-                description: == PRO ==
-                type: string
-                x-go-name: DefaultACL
-            dnson:
-                type: boolean
-                x-go-name: DNSOn
-            egressgatewaynatenabled:
-                type: boolean
-                x-go-name: EgressGatewayNatEnabled
-            egressgatewayranges:
-                items:
-                    type: string
-                type: array
-                x-go-name: EgressGatewayRanges
-            expdatetime:
-                format: int64
-                type: integer
-                x-go-name: ExpirationDateTime
-            fail_over_peers:
-                additionalProperties:
-                    type: object
-                type: object
-                x-go-name: FailOverPeers
-            failed_over_by:
-                format: uuid
-                type: string
-                x-go-name: FailedOverBy
-            hostid:
-                type: string
-                x-go-name: HostID
-            id:
-                type: string
-                x-go-name: ID
-            inet_node_req:
-                $ref: '#/definitions/InetNodeReq'
-            ingressdns:
-                type: string
-                x-go-name: IngressDns
-            internetgw_node_id:
-                type: string
-                x-go-name: InternetGwID
-            is_fail_over:
-                type: boolean
-                x-go-name: IsFailOver
-            isegressgateway:
-                type: boolean
-                x-go-name: IsEgressGateway
-            isingressgateway:
-                type: boolean
-                x-go-name: IsIngressGateway
-            isinternetgateway:
-                type: boolean
-                x-go-name: IsInternetGateway
-            isrelay:
-                type: boolean
-                x-go-name: IsRelay
-            isrelayed:
-                type: boolean
-                x-go-name: IsRelayed
-            lastcheckin:
-                format: int64
-                type: integer
-                x-go-name: LastCheckIn
-            lastmodified:
-                format: int64
-                type: integer
-                x-go-name: LastModified
-            lastpeerupdate:
-                format: int64
-                type: integer
-                x-go-name: LastPeerUpdate
-            localaddress:
-                type: string
-                x-go-name: LocalAddress
-            metadata:
-                type: string
-                x-go-name: Metadata
-            network:
-                type: string
-                x-go-name: Network
-            networkrange:
-                type: string
-                x-go-name: NetworkRange
-            networkrange6:
-                type: string
-                x-go-name: NetworkRange6
-            pendingdelete:
-                type: boolean
-                x-go-name: PendingDelete
-            relayedby:
-                type: string
-                x-go-name: RelayedBy
-            relaynodes:
-                items:
-                    type: string
-                type: array
-                x-go-name: RelayedNodes
-            server:
-                type: string
-                x-go-name: Server
-        type: object
-        x-go-package: github.com/gravitl/netmaker/models
-    AuthParams:
-        description: AuthParams - struct for auth params
-        properties:
-            id:
-                type: string
-                x-go-name: ID
-            macaddress:
-                type: string
-                x-go-name: MacAddress
-            password:
-                type: string
-                x-go-name: Password
-        type: object
-        x-go-package: github.com/gravitl/netmaker/models
-    CustomExtClient:
-        description: CustomExtClient - struct for CustomExtClient params
-        properties:
-            clientid:
-                type: string
-                x-go-name: ClientID
-            deniednodeacls:
-                additionalProperties:
-                    type: object
-                type: object
-                x-go-name: DeniedACLs
-            dns:
-                type: string
-                x-go-name: DNS
-            enabled:
-                type: boolean
-                x-go-name: Enabled
-            extraallowedips:
-                items:
-                    type: string
-                type: array
-                x-go-name: ExtraAllowedIPs
-            postdown:
-                type: string
-                x-go-name: PostDown
-            postup:
-                type: string
-                x-go-name: PostUp
-            publickey:
-                type: string
-                x-go-name: PublicKey
-            remote_access_client_id:
-                type: string
-                x-go-name: RemoteAccessClientID
-        type: object
-        x-go-package: github.com/gravitl/netmaker/models
-    DNSEntry:
-        description: DNSEntry - a DNS entry represented as struct
-        properties:
-            address:
-                type: string
-                x-go-name: Address
-            address6:
-                type: string
-                x-go-name: Address6
-            name:
-                type: string
-                x-go-name: Name
-            network:
-                type: string
-                x-go-name: Network
-        type: object
-        x-go-package: github.com/gravitl/netmaker/models
-    Duration:
-        description: |-
-            A Duration represents the elapsed time between two instants
-            as an int64 nanosecond count. The representation limits the
-            largest representable duration to approximately 290 years.
-        format: int64
-        type: integer
-        x-go-package: time
-    EgressGatewayRequest:
-        description: EgressGatewayRequest - egress gateway request
-        properties:
-            natenabled:
-                type: string
-                x-go-name: NatEnabled
-            netid:
-                type: string
-                x-go-name: NetID
-            nodeid:
-                type: string
-                x-go-name: NodeID
-            ranges:
-                items:
-                    type: string
-                type: array
-                x-go-name: Ranges
-        type: object
-        x-go-package: github.com/gravitl/netmaker/models
-    EgressInfo:
-        description: EgressInfo - struct for egress info
-        properties:
-            egress_gateway_cfg:
-                $ref: '#/definitions/EgressGatewayRequest'
-            egress_gw_addr:
-                $ref: '#/definitions/IPNet'
-            egress_id:
-                type: string
-                x-go-name: EgressID
-            network:
-                $ref: '#/definitions/IPNet'
-        type: object
-        x-go-package: github.com/gravitl/netmaker/models
-    EgressNetworkRoutes:
-        description: EgressNetworkRoutes - struct for egress network routes for adding routes to peer's interface
-        properties:
-            egress_ranges:
-                items:
-                    type: string
-                type: array
-                x-go-name: EgressRanges
-            node_addr:
-                $ref: '#/definitions/IPNet'
-            node_addr6:
-                $ref: '#/definitions/IPNet'
-        type: object
-        x-go-package: github.com/gravitl/netmaker/models
-    EnrollmentKey:
-        description: EnrollmentKey - the key used to register hosts and join them to specific networks
-        properties:
-            expiration:
-                format: date-time
-                type: string
-                x-go-name: Expiration
-            networks:
-                items:
-                    type: string
-                type: array
-                x-go-name: Networks
-            relay:
-                format: uuid
-                type: string
-                x-go-name: Relay
-            tags:
-                items:
-                    type: string
-                type: array
-                x-go-name: Tags
-            token:
-                type: string
-                x-go-name: Token
-            type:
-                $ref: '#/definitions/KeyType'
-            unlimited:
-                type: boolean
-                x-go-name: Unlimited
-            uses_remaining:
-                format: int64
-                type: integer
-                x-go-name: UsesRemaining
-            value:
-                type: string
-                x-go-name: Value
-        type: object
-        x-go-package: github.com/gravitl/netmaker/models
-    ExtClient:
-        description: ExtClient - struct for external clients
-        properties:
-            address:
-                type: string
-                x-go-name: Address
-            address6:
-                type: string
-                x-go-name: Address6
-            allowed_ips:
-                items:
-                    type: string
-                type: array
-                x-go-name: AllowedIPs
-            clientid:
-                type: string
-                x-go-name: ClientID
-            deniednodeacls:
-                additionalProperties:
-                    type: object
-                type: object
-                x-go-name: DeniedACLs
-            dns:
-                type: string
-                x-go-name: DNS
-            enabled:
-                type: boolean
-                x-go-name: Enabled
-            extraallowedips:
-                items:
-                    type: string
-                type: array
-                x-go-name: ExtraAllowedIPs
-            ingressgatewayendpoint:
-                type: string
-                x-go-name: IngressGatewayEndpoint
-            ingressgatewayid:
-                type: string
-                x-go-name: IngressGatewayID
-            lastmodified:
-                format: int64
-                type: integer
-                x-go-name: LastModified
-            network:
-                type: string
-                x-go-name: Network
-            ownerid:
-                type: string
-                x-go-name: OwnerID
-            postdown:
-                type: string
-                x-go-name: PostDown
-            postup:
-                type: string
-                x-go-name: PostUp
-            privatekey:
-                type: string
-                x-go-name: PrivateKey
-            publickey:
-                type: string
-                x-go-name: PublicKey
-            remote_access_client_id:
-                type: string
-                x-go-name: RemoteAccessClientID
-        type: object
-        x-go-package: github.com/gravitl/netmaker/models
-    File:
-        title: File represents an open file descriptor.
-        type: object
-        x-go-package: os
-    FwUpdate:
-        description: FwUpdate - struct for firewall updates
-        properties:
-            egress_info:
-                additionalProperties:
-                    $ref: '#/definitions/EgressInfo'
-                type: object
-                x-go-name: EgressInfo
-            is_egress_gw:
-                type: boolean
-                x-go-name: IsEgressGw
-        type: object
-        x-go-package: github.com/gravitl/netmaker/models
-    HardwareAddr:
-        items:
-            format: uint8
-            type: integer
-        title: A HardwareAddr represents a physical hardware address.
-        type: array
-        x-go-package: net
-    Host:
-        description: Host - represents a host on the network
-        properties:
-            autoupdate:
-                type: boolean
-                x-go-name: AutoUpdate
-            daemoninstalled:
-                type: boolean
-                x-go-name: DaemonInstalled
-            debug:
-                type: boolean
-                x-go-name: Debug
-            defaultinterface:
-                type: string
-                x-go-name: DefaultInterface
-            endpointip:
-                type: string
-                x-go-name: EndpointIP
-            endpointipv6:
-                type: string
-                x-go-name: EndpointIPv6
-            firewallinuse:
-                type: string
-                x-go-name: FirewallInUse
-            hostpass:
-                type: string
-                x-go-name: HostPass
-            id:
-                format: uuid
-                type: string
-                x-go-name: ID
-            interface:
-                type: string
-                x-go-name: Interface
-            interfaces:
-                items:
-                    $ref: '#/definitions/Iface'
-                type: array
-                x-go-name: Interfaces
-            ipforwarding:
-                type: boolean
-                x-go-name: IPForwarding
-            isdefault:
-                type: boolean
-                x-go-name: IsDefault
-            isdocker:
-                type: boolean
-                x-go-name: IsDocker
-            isk8s:
-                type: boolean
-                x-go-name: IsK8S
-            isstatic:
-                type: boolean
-                x-go-name: IsStatic
-            listenport:
-                format: int64
-                type: integer
-                x-go-name: ListenPort
-            macaddress:
-                $ref: '#/definitions/HardwareAddr'
-            mtu:
-                format: int64
-                type: integer
-                x-go-name: MTU
-            name:
-                type: string
-                x-go-name: Name
-            nat_type:
-                type: string
-                x-go-name: NatType
-            nodes:
-                items:
-                    type: string
-                type: array
-                x-go-name: Nodes
-            os:
-                type: string
-                x-go-name: OS
-            persistentkeepalive:
-                $ref: '#/definitions/Duration'
-            publickey:
-                $ref: '#/definitions/Key'
-            traffickeypublic:
-                items:
-                    format: uint8
-                    type: integer
-                type: array
-                x-go-name: TrafficKeyPublic
-            turn_endpoint:
-                type: string
-                x-go-name: TurnEndpoint
-            verbosity:
-                format: int64
-                type: integer
-                x-go-name: Verbosity
-            version:
-                type: string
-                x-go-name: Version
-            wg_public_listen_port:
-                format: int64
-                type: integer
-                x-go-name: WgPublicListenPort
-        type: object
-        x-go-package: github.com/gravitl/netmaker/models
-    HostInfoMap:
-        additionalProperties:
-            $ref: '#/definitions/HostNetworkInfo'
-        description: HostInfoMap - map of host public keys to host networking info
-        type: object
-        x-go-package: github.com/gravitl/netmaker/models
-    HostNetworkInfo:
-        description: HostNetworkInfo - holds info related to host networking (used for client side peer calculations)
-        properties:
-            interfaces:
-                items:
-                    $ref: '#/definitions/Iface'
-                type: array
-                x-go-name: Interfaces
-            is_static:
-                type: boolean
-                x-go-name: IsStatic
-            listen_port:
-                format: int64
-                type: integer
-                x-go-name: ListenPort
-        type: object
-        x-go-package: github.com/gravitl/netmaker/models
-    HostPull:
-        description: HostPull - response of a host's pull
-        properties:
-            change_default_gw:
-                type: boolean
-                x-go-name: ChangeDefaultGw
-            default_gw_ip:
-                type: string
-                x-go-name: DefaultGwIp
-            egress_network_routes:
-                items:
-                    $ref: '#/definitions/EgressNetworkRoutes'
-                type: array
-                x-go-name: EgressRoutes
-            endpoint_detection:
-                type: boolean
-                x-go-name: EndpointDetection
-            fw_update:
-                $ref: '#/definitions/FwUpdate'
-            host:
-                $ref: '#/definitions/Host'
-            host_network_info:
-                $ref: '#/definitions/HostInfoMap'
-            is_inet_gw:
-                type: boolean
-                x-go-name: IsInternetGw
-            nodes:
-                items:
-                    $ref: '#/definitions/Node'
-                type: array
-                x-go-name: Nodes
-            peer_ids:
-                $ref: '#/definitions/PeerMap'
-            peers:
-                items:
-                    $ref: '#/definitions/PeerConfig'
-                type: array
-                x-go-name: Peers
-            server_config:
-                $ref: '#/definitions/ServerConfig'
-        type: object
-        x-go-package: github.com/gravitl/netmaker/models
-    IDandAddr:
-        description: IDandAddr - struct to hold ID and primary Address
-        properties:
-            address:
-                type: string
-                x-go-name: Address
-            host_id:
-                type: string
-                x-go-name: HostID
-            id:
-                type: string
-                x-go-name: ID
-            is_extclient:
-                type: boolean
-                x-go-name: IsExtClient
-            isserver:
-                type: string
-                x-go-name: IsServer
-            listen_port:
-                format: int64
-                type: integer
-                x-go-name: ListenPort
-            name:
-                type: string
-                x-go-name: Name
-            network:
-                type: string
-                x-go-name: Network
-        type: object
-        x-go-package: github.com/gravitl/netmaker/models
-    IPMask:
-        description: See type IPNet and func ParseCIDR for details.
-        items:
-            format: uint8
-            type: integer
-        title: |-
-            An IPMask is a bitmask that can be used to manipulate
-            IP addresses for IP addressing and routing.
-        type: array
-        x-go-package: net
-    IPNet:
-        properties:
-            IP:
-                type: string
-            Mask:
-                $ref: '#/definitions/IPMask'
-        title: An IPNet represents an IP network.
-        type: object
-        x-go-package: net
-    Iface:
-        description: Iface struct for local interfaces of a node
-        properties:
-            address:
-                $ref: '#/definitions/IPNet'
-            addressString:
-                type: string
-                x-go-name: AddressString
-            name:
-                type: string
-                x-go-name: Name
-        type: object
-        x-go-package: github.com/gravitl/netmaker/models
-    InetNodeReq:
-        description: InetNodeReq - exit node request struct
-        properties:
-            inet_node_client_ids:
-                items:
-                    type: string
-                type: array
-                x-go-name: InetNodeClientIDs
-        type: object
-        x-go-package: github.com/gravitl/netmaker/models
-    Key:
-        description: |-
-            A Key is a public, private, or pre-shared secret key.  The Key constructor
-            functions in this package can be used to create Keys suitable for each of
-            these applications.
-        items:
-            format: uint8
-            type: integer
-        type: array
-        x-go-package: golang.zx2c4.com/wireguard/wgctrl/wgtypes
-    KeyType:
-        description: KeyType - the type of enrollment key
-        format: int64
-        type: integer
-        x-go-package: github.com/gravitl/netmaker/models
-    LegacyNode:
-        description: LegacyNode - legacy struct for node model
-        properties:
-            accesskey:
-                type: string
-                x-go-name: AccessKey
-            action:
-                type: string
-                x-go-name: Action
-            address:
-                type: string
-                x-go-name: Address
-            address6:
-                type: string
-                x-go-name: Address6
-            allowedips:
-                items:
-                    type: string
-                type: array
-                x-go-name: AllowedIPs
-            connected:
-                type: string
-                x-go-name: Connected
-            defaultacl:
-                description: == PRO ==
-                type: string
-                x-go-name: DefaultACL
-            dnson:
-                type: string
-                x-go-name: DNSOn
-            egressgatewaynatenabled:
-                type: string
-                x-go-name: EgressGatewayNatEnabled
-            egressgatewayranges:
-                items:
-                    type: string
-                type: array
-                x-go-name: EgressGatewayRanges
-            egressgatewayrequest:
-                $ref: '#/definitions/EgressGatewayRequest'
-            endpoint:
-                type: string
-                x-go-name: Endpoint
-            expdatetime:
-                format: int64
-                type: integer
-                x-go-name: ExpirationDateTime
-            failover:
-                type: string
-                x-go-name: Failover
-            failovernode:
-                type: string
-                x-go-name: FailoverNode
-            firewallinuse:
-                type: string
-                x-go-name: FirewallInUse
-            id:
-                type: string
-                x-go-name: ID
-            ingressgatewayrange:
-                type: string
-                x-go-name: IngressGatewayRange
-            ingressgatewayrange6:
-                type: string
-                x-go-name: IngressGatewayRange6
-            interface:
-                type: string
-                x-go-name: Interface
-            interfaces:
-                items:
-                    $ref: '#/definitions/Iface'
-                type: array
-                x-go-name: Interfaces
-            internetgateway:
-                type: string
-                x-go-name: InternetGateway
-            ipforwarding:
-                type: string
-                x-go-name: IPForwarding
-            isdocker:
-                type: string
-                x-go-name: IsDocker
-            isegressgateway:
-                type: string
-                x-go-name: IsEgressGateway
-            ishub:
-                type: string
-                x-go-name: IsHub
-            isingressgateway:
-                type: string
-                x-go-name: IsIngressGateway
-            isk8s:
-                type: string
-                x-go-name: IsK8S
-            ispending:
-                type: string
-                x-go-name: IsPending
-            isrelay:
-                type: string
-                x-go-name: IsRelay
-            isrelayed:
-                type: string
-                x-go-name: IsRelayed
-            isserver:
-                type: string
-                x-go-name: IsServer
-            isstatic:
-                description: IsStatic - refers to if the Endpoint is set manually or dynamically
-                type: string
-                x-go-name: IsStatic
-            lastcheckin:
-                format: int64
-                type: integer
-                x-go-name: LastCheckIn
-            lastmodified:
-                format: int64
-                type: integer
-                x-go-name: LastModified
-            lastpeerupdate:
-                format: int64
-                type: integer
-                x-go-name: LastPeerUpdate
-            listenport:
-                format: int32
-                type: integer
-                x-go-name: ListenPort
-            localaddress:
-                type: string
-                x-go-name: LocalAddress
-            locallistenport:
-                format: int32
-                type: integer
-                x-go-name: LocalListenPort
-            macaddress:
-                type: string
-                x-go-name: MacAddress
-            mtu:
-                format: int32
-                type: integer
-                x-go-name: MTU
-            name:
-                type: string
-                x-go-name: Name
-            network:
-                type: string
-                x-go-name: Network
-            networksettings:
-                $ref: '#/definitions/Network'
-            os:
-                type: string
-                x-go-name: OS
-            ownerid:
-                type: string
-                x-go-name: OwnerID
-            password:
-                type: string
-                x-go-name: Password
-            persistentkeepalive:
-                format: int32
-                type: integer
-                x-go-name: PersistentKeepalive
-            publickey:
-                type: string
-                x-go-name: PublicKey
-            relayaddrs:
-                items:
-                    type: string
-                type: array
-                x-go-name: RelayAddrs
-            server:
-                type: string
-                x-go-name: Server
-            traffickeys:
-                $ref: '#/definitions/TrafficKeys'
-            udpholepunch:
-                type: string
-                x-go-name: UDPHolePunch
-            version:
-                type: string
-                x-go-name: Version
-        type: object
-        x-go-package: github.com/gravitl/netmaker/models
-    Network:
-        description: |-
-            Network Struct - contains info for a given unique network
-            At  some point, need to replace all instances of Name with something else like  Identifier
-        properties:
-            addressrange:
-                type: string
-                x-go-name: AddressRange
-            addressrange6:
-                type: string
-                x-go-name: AddressRange6
-            allowmanualsignup:
-                type: string
-                x-go-name: AllowManualSignUp
-            defaultacl:
-                type: string
-                x-go-name: DefaultACL
-            defaultinterface:
-                type: string
-                x-go-name: DefaultInterface
-            defaultkeepalive:
-                format: int32
-                type: integer
-                x-go-name: DefaultKeepalive
-            defaultlistenport:
-                format: int32
-                type: integer
-                x-go-name: DefaultListenPort
-            defaultmtu:
-                format: int32
-                type: integer
-                x-go-name: DefaultMTU
-            defaultpostdown:
-                type: string
-                x-go-name: DefaultPostDown
-            defaultudpholepunch:
-                type: string
-                x-go-name: DefaultUDPHolePunch
-            isipv4:
-                type: string
-                x-go-name: IsIPv4
-            isipv6:
-                type: string
-                x-go-name: IsIPv6
-            netid:
-                type: string
-                x-go-name: NetID
-            networklastmodified:
-                format: int64
-                type: integer
-                x-go-name: NetworkLastModified
-            nodelimit:
-                format: int32
-                type: integer
-                x-go-name: NodeLimit
-            nodeslastmodified:
-                format: int64
-                type: integer
-                x-go-name: NodesLastModified
-        type: object
-        x-go-package: github.com/gravitl/netmaker/models
-    Node:
-        description: Node - a model of a network node
-        properties:
-            action:
-                type: string
-                x-go-name: Action
-            address:
-                $ref: '#/definitions/IPNet'
-            address6:
-                $ref: '#/definitions/IPNet'
-            connected:
-                type: boolean
-                x-go-name: Connected
-            defaultacl:
-                description: == PRO ==
-                type: string
-                x-go-name: DefaultACL
-            dnson:
-                type: boolean
-                x-go-name: DNSOn
-            egressgatewaynatenabled:
-                type: boolean
-                x-go-name: EgressGatewayNatEnabled
-            egressgatewayranges:
-                items:
-                    type: string
-                type: array
-                x-go-name: EgressGatewayRanges
-            egressgatewayrequest:
-                $ref: '#/definitions/EgressGatewayRequest'
-            expdatetime:
-                format: date-time
-                type: string
-                x-go-name: ExpirationDateTime
-            fail_over_peers:
-                additionalProperties:
-                    type: object
-                type: object
-                x-go-name: FailOverPeers
-            failed_over_by:
-                format: uuid
-                type: string
-                x-go-name: FailedOverBy
-            hostid:
-                format: uuid
-                type: string
-                x-go-name: HostID
-            id:
-                format: uuid
-                type: string
-                x-go-name: ID
-            inet_node_req:
-                $ref: '#/definitions/InetNodeReq'
-            ingressdns:
-                type: string
-                x-go-name: IngressDNS
-            ingressgatewayrange:
-                type: string
-                x-go-name: IngressGatewayRange
-            ingressgatewayrange6:
-                type: string
-                x-go-name: IngressGatewayRange6
-            internetgw_node_id:
-                type: string
-                x-go-name: InternetGwID
-            is_fail_over:
-                type: boolean
-                x-go-name: IsFailOver
-            isegressgateway:
-                type: boolean
-                x-go-name: IsEgressGateway
-            isingressgateway:
-                type: boolean
-                x-go-name: IsIngressGateway
-            isinternetgateway:
-                type: boolean
-                x-go-name: IsInternetGateway
-            isrelay:
-                type: boolean
-                x-go-name: IsRelay
-            isrelayed:
-                type: boolean
-                x-go-name: IsRelayed
-            lastcheckin:
-                format: date-time
-                type: string
-                x-go-name: LastCheckIn
-            lastmodified:
-                format: date-time
-                type: string
-                x-go-name: LastModified
-            lastpeerupdate:
-                format: date-time
-                type: string
-                x-go-name: LastPeerUpdate
-            localaddress:
-                $ref: '#/definitions/IPNet'
-            metadata:
-                type: string
-                x-go-name: Metadata
-            network:
-                type: string
-                x-go-name: Network
-            networkrange:
-                $ref: '#/definitions/IPNet'
-            networkrange6:
-                $ref: '#/definitions/IPNet'
-            ownerid:
-                type: string
-                x-go-name: OwnerID
-            pendingdelete:
-                type: boolean
-                x-go-name: PendingDelete
-            relayedby:
-                type: string
-                x-go-name: RelayedBy
-            relaynodes:
-                items:
-                    type: string
-                type: array
-                x-go-name: RelayedNodes
-            server:
-                type: string
-                x-go-name: Server
-        type: object
-        x-go-package: github.com/gravitl/netmaker/models
-    PeerConfig:
-        description: |-
-            Because the zero value of some Go types may be significant to WireGuard for
-            PeerConfig fields, pointer types are used for some of these fields. Only
-            pointer fields which are not nil will be applied when configuring a peer.
-        properties:
-            AllowedIPs:
-                description: |-
-                    AllowedIPs specifies a list of allowed IP addresses in CIDR notation
-                    for this peer.
-                items:
-                    $ref: '#/definitions/IPNet'
-                type: array
-            Endpoint:
-                $ref: '#/definitions/UDPAddr'
-            PersistentKeepaliveInterval:
-                $ref: '#/definitions/Duration'
-            PresharedKey:
-                $ref: '#/definitions/Key'
-            PublicKey:
-                $ref: '#/definitions/Key'
-            Remove:
-                description: |-
-                    Remove specifies if the peer with this public key should be removed
-                    from a device's peer list.
-                type: boolean
-            ReplaceAllowedIPs:
-                description: |-
-                    ReplaceAllowedIPs specifies if the allowed IPs specified in this peer
-                    configuration should replace any existing ones, instead of appending them
-                    to the allowed IPs list.
-                type: boolean
-            UpdateOnly:
-                description: |-
-                    UpdateOnly specifies that an operation will only occur on this peer
-                    if the peer already exists as part of the interface.
-                type: boolean
-        title: A PeerConfig is a WireGuard device peer configuration.
-        type: object
-        x-go-package: golang.zx2c4.com/wireguard/wgctrl/wgtypes
-    PeerMap:
-        additionalProperties:
-            $ref: '#/definitions/IDandAddr'
-        description: PeerMap - peer map for ids and addresses in metrics
-        type: object
-        x-go-package: github.com/gravitl/netmaker/models
-    RegisterResponse:
-        description: RegisterResponse - the response to a successful enrollment register
-        properties:
-            requested_host:
-                $ref: '#/definitions/Host'
-            server_config:
-                $ref: '#/definitions/ServerConfig'
-        type: object
-        x-go-package: github.com/gravitl/netmaker/models
-    RelayRequest:
-        description: RelayRequest - relay request struct
-        properties:
-            netid:
-                type: string
-                x-go-name: NetID
-            nodeid:
-                type: string
-                x-go-name: NodeID
-            relayaddrs:
-                items:
-                    type: string
-                type: array
-                x-go-name: RelayedNodes
-        type: object
-        x-go-package: github.com/gravitl/netmaker/models
-    ServerConfig:
-        description: ServerConfig - server conf struct
-        properties:
-            APIConnString:
-                type: string
-            APIHost:
-                type: string
-            APIPort:
-                type: string
-            AllowedEmailDomains:
-                type: string
-            AllowedOrigin:
-                type: string
-            AuthProvider:
-                type: string
-            AzureTenant:
-                type: string
-            BasicAuth:
-                type: string
-            Broker:
-                type: string
-            BrokerType:
-                type: string
-            CacheEnabled:
-                type: string
-            ClientID:
-                type: string
-            ClientSecret:
-                type: string
-            CoreDNSAddr:
-                type: string
-            DNSKey:
-                type: string
-            DNSMode:
-                type: string
-            Database:
-                type: string
-            DeployedByOperator:
-                type: boolean
-            DisableRemoteIPCheck:
-                type: string
-            DisplayKeys:
-                type: string
-            EgressesLimit:
-                format: int64
-                type: integer
-            EmqxRestEndpoint:
-                type: string
-            Environment:
-                type: string
-            FrontendURL:
-                type: string
-            HostNetwork:
-                type: string
-            IngressesLimit:
-                format: int64
-                type: integer
-            IsEE:
-                type: string
-                x-go-name: IsPro
-            JwtValidityDuration:
-                $ref: '#/definitions/Duration'
-            LicenseValue:
-                type: string
-            MQPassword:
-                type: string
-            MQUserName:
-                type: string
-            MachinesLimit:
-                format: int64
-                type: integer
-            MasterKey:
-                type: string
-            MessageQueueBackend:
-                type: string
-            MetricsExporter:
-                type: string
-            NetclientAutoUpdate:
-                type: string
-            NetclientEndpointDetection:
-                type: string
-            NetmakerTenantID:
-                type: string
-            NetworksLimit:
-                format: int64
-                type: integer
-            NodeID:
-                type: string
-            OIDCIssuer:
-                type: string
-            Platform:
-                type: string
-            PublicIPService:
-                type: string
-            RacAutoDisable:
-                type: boolean
-            RestBackend:
-                type: string
-            SQLConn:
-                type: string
-            Server:
-                type: string
-            ServerBrokerEndpoint:
-                type: string
-            StunList:
-                type: string
-            StunPort:
-                format: int64
-                type: integer
-            Telemetry:
-                type: string
-            TurnApiServer:
-                type: string
-            TurnPassword:
-                type: string
-            TurnPort:
-                format: int64
-                type: integer
-            TurnServer:
-                type: string
-            TurnUserName:
-                type: string
-            UseTurn:
-                type: boolean
-            UsersLimit:
-                format: int64
-                type: integer
-            Verbosity:
-                format: int32
-                type: integer
-            Version:
-                type: string
-            endpoint_detection:
-                type: boolean
-                x-go-name: EndpointDetection
-        type: object
-        x-go-package: github.com/gravitl/netmaker/config
-    Signal:
-        description: Signal - struct for signalling peer
-        properties:
-            action:
-                $ref: '#/definitions/SignalAction'
-            from_host_id:
-                type: string
-                x-go-name: FromHostID
-            from_host_pubkey:
-                type: string
-                x-go-name: FromHostPubKey
-            from_node_id:
-                type: string
-                x-go-name: FromNodeID
-            is_pro:
-                type: boolean
-                x-go-name: IsPro
-            reply:
-                type: boolean
-                x-go-name: Reply
-            server:
-                type: string
-                x-go-name: Server
-            timestamp:
-                format: int64
-                type: integer
-                x-go-name: TimeStamp
-            to_host_id:
-                type: string
-                x-go-name: ToHostID
-            to_host_pubkey:
-                type: string
-                x-go-name: ToHostPubKey
-            to_node_id:
-                type: string
-                x-go-name: ToNodeID
-        type: object
-        x-go-package: github.com/gravitl/netmaker/models
-    SignalAction:
-        description: SignalAction - turn peer signal action
-        type: string
-        x-go-package: github.com/gravitl/netmaker/models
-    SuccessResponse:
-        properties:
-            Code:
-                format: int64
-                type: integer
-            Message:
-                type: string
-            Response: {}
-        title: SuccessResponse is struct for sending error message with code.
-        type: object
-        x-go-package: github.com/gravitl/netmaker/models
-    TrafficKeys:
-        description: TrafficKeys - struct to hold public keys
-        properties:
-            mine:
-                items:
-                    format: uint8
-                    type: integer
-                type: array
-                x-go-name: Mine
-            server:
-                items:
-                    format: uint8
-                    type: integer
-                type: array
-                x-go-name: Server
-        type: object
-        x-go-package: github.com/gravitl/netmaker/models
-    UDPAddr:
-        properties:
-            IP:
-                type: string
-            Port:
-                format: int64
-                type: integer
-            Zone:
-                type: string
-        title: UDPAddr represents the address of a UDP end point.
-        type: object
-        x-go-package: net
-    User:
-        description: User struct - struct for Users
-        properties:
-            isadmin:
-                type: boolean
-                x-go-name: IsAdmin
-            issuperadmin:
-                type: boolean
-                x-go-name: IsSuperAdmin
-            last_login_time:
-                format: date-time
-                type: string
-                x-go-name: LastLoginTime
-            password:
-                type: string
-                x-go-name: Password
-            remote_gw_ids:
-                additionalProperties:
-                    type: object
-                type: object
-                x-go-name: RemoteGwIDs
-            username:
-                type: string
-                x-go-name: UserName
-        type: object
-        x-go-package: github.com/gravitl/netmaker/models
-    UserAuthParams:
-        description: UserAuthParams - user auth params struct
-        properties:
-            password:
-                type: string
-                x-go-name: Password
-            username:
-                type: string
-                x-go-name: UserName
-        type: object
-        x-go-package: github.com/gravitl/netmaker/models
-host: api.demo.netmaker.io
-info:
-    description: |-
-        # API Usage
-
-        Most actions that can be performed via API can be performed via UI. We recommend managing your networks using the official netmaker-ui project. However, Netmaker can also be run without the UI, and all functions can be achieved via API calls. If your use case requires using Netmaker without the UI or you need to do some troubleshooting/advanced configuration, using the API directly may help.
-
-        # Authentication
-
-        API calls must be authenticated via a header of the format -H “Authorization: Bearer <YOUR_SECRET_KEY>” There are two methods to obtain YOUR_SECRET_KEY: 1. Using the masterkey. By default, this value is “secret key,” but you should change this on your instance and keep it secure. This value can be set via env var at startup or in a config file (config/environments/< env >.yaml). See the [Netmaker](https://docs.netmaker.org/index.html) documentation for more details. 2. Using a JWT received for a node. This can be retrieved by calling the /api/nodes/<network>/authenticate endpoint, as documented below.
-    title: Netmaker
-    version: 0.25.0
-paths:
-    /api/dns:
-        get:
-            operationId: getAllDNS
-            responses:
-                "200":
-                    $ref: '#/responses/dnsResponse'
-            schemes:
-                - https
-            summary: Gets all DNS entries.
-            tags:
-                - dns
-    /api/dns/{network}:
-        post:
-            operationId: createDNS
-            parameters:
-                - description: Network
-                  in: path
-                  name: network
-                  required: true
-                  type: string
-                  x-go-name: Network
-                - description: DNS Entry
-                  in: body
-                  name: body
-                  schema:
-                    items:
-                        $ref: '#/definitions/DNSEntry'
-                    type: array
-                  x-go-name: Body
-            responses:
-                "200":
-                    $ref: '#/responses/dnsResponse'
-            schemes:
-                - https
-            summary: Create a DNS entry.
-            tags:
-                - dns
-    /api/dns/{network}/{domain}:
-        delete:
-            operationId: deleteDNS
-            parameters:
-                - description: Network
-                  in: path
-                  name: network
-                  required: true
-                  type: string
-                  x-go-name: Network
-                - description: Domain
-                  in: path
-                  name: domain
-                  required: true
-                  type: string
-                  x-go-name: Domain
-            responses:
-                "200":
-                    $ref: '#/responses/stringJSONResponse'
-            schemes:
-                - https
-            summary: Delete a DNS entry.
-            tags:
-                - dns
-    /api/dns/adm/{network}:
-        get:
-            operationId: getDNS
-            parameters:
-                - description: Network
-                  in: path
-                  name: network
-                  required: true
-                  type: string
-                  x-go-name: Network
-            responses:
-                "200":
-                    $ref: '#/responses/dnsResponse'
-            schemes:
-                - https
-            summary: Gets all DNS entries associated with the network.
-            tags:
-                - dns
-    /api/dns/adm/{network}/custom:
-        get:
-            operationId: getCustomDNS
-            parameters:
-                - description: Network
-                  in: path
-                  name: network
-                  required: true
-                  type: string
-                  x-go-name: Network
-            responses:
-                "200":
-                    $ref: '#/responses/dnsResponse'
-            schemes:
-                - https
-            summary: Gets custom DNS entries associated with a network.
-            tags:
-                - dns
-    /api/dns/adm/{network}/nodes:
-        get:
-            operationId: getNodeDNS
-            parameters:
-                - description: Network
-                  in: path
-                  name: network
-                  required: true
-                  type: string
-                  x-go-name: Network
-            responses:
-                "200":
-                    $ref: '#/responses/dnsResponse'
-            schemes:
-                - https
-            summary: Gets node DNS entries associated with a network.
-            tags:
-                - dns
-    /api/dns/adm/pushdns:
-        post:
-            operationId: pushDNS
-            responses:
-                "200":
-                    $ref: '#/responses/dnsResponse'
-            schemes:
-                - https
-            summary: Push DNS entries to nameserver.
-            tags:
-                - dns
-    /api/emqx/hosts:
-        delete:
-            operationId: delEmqxHosts
-            responses:
-                "200":
-                    $ref: '#/responses/apiHostResponse'
-            schemes:
-                - https
-            summary: Lists all hosts.
-            tags:
-                - hosts
-    /api/extclients:
-        get:
-            operationId: getAllExtClients
-            parameters:
-                - description: Networks
-                  in: body
-                  name: networks
-                  schema:
-                    items:
-                        type: string
-                    type: array
-                  x-go-name: Networks
-            responses:
-                "200":
-                    $ref: '#/responses/extClientSliceResponse'
-            schemes:
-                - https
-            summary: A separate function to get all extclients, not just extclients for a particular network.
-            tags:
-                - ext_client
-    /api/extclients/{network}:
-        get:
-            description: Gets all extclients associated with network, including pending extclients.
-            operationId: getNetworkExtClients
-            parameters:
-                - description: Network
-                  in: path
-                  name: network
-                  required: true
-                  type: string
-                  x-go-name: Network
-            responses:
-                "200":
-                    $ref: '#/responses/extClientSliceResponse'
-            schemes:
-                - https
-            summary: Get all extclients associated with network.
-            tags:
-                - ext_client
-    /api/extclients/{network}/{clientid}:
-        delete:
-            operationId: deleteExtClient
-            parameters:
-                - description: Client ID
-                  in: path
-                  name: clientid
-                  required: true
-                  type: string
-                  x-go-name: ClientID
-                - description: Network
-                  in: path
-                  name: network
-                  required: true
-                  type: string
-                  x-go-name: Network
-            responses:
-                "200":
-                    $ref: '#/responses/successResponse'
-            schemes:
-                - https
-            summary: Delete an individual extclient.
-            tags:
-                - ext_client
-        get:
-            operationId: getExtClient
-            parameters:
-                - description: Client ID
-                  in: path
-                  name: clientid
-                  required: true
-                  type: string
-                  x-go-name: ClientID
-                - description: Network
-                  in: path
-                  name: network
-                  required: true
-                  type: string
-                  x-go-name: Network
-            responses:
-                "200":
-                    $ref: '#/responses/extClientResponse'
-            schemes:
-                - https
-            summary: Get an individual extclient.
-            tags:
-                - ext_client
-        put:
-            operationId: updateExtClient
-            parameters:
-                - description: Client ID
-                  in: path
-                  name: clientid
-                  required: true
-                  type: string
-                  x-go-name: ClientID
-                - description: Network
-                  in: path
-                  name: network
-                  required: true
-                  type: string
-                  x-go-name: Network
-                - description: ExtClient
-                  in: body
-                  name: ext_client
-                  schema:
-                    $ref: '#/definitions/ExtClient'
-                  x-go-name: ExtClient
-            responses:
-                "200":
-                    $ref: '#/responses/extClientResponse'
-            schemes:
-                - https
-            summary: Update an individual extclient.
-            tags:
-                - ext_client
-    /api/extclients/{network}/{clientid}/{type}:
-        get:
-            operationId: getExtClientConf
-            parameters:
-                - description: Type
-                  in: path
-                  name: type
-                  required: true
-                  type: string
-                  x-go-name: Type
-                - description: Client ID
-                  in: path
-                  name: clientid
-                  required: true
-                  type: string
-                  x-go-name: ClientID
-                - description: Network
-                  in: path
-                  name: network
-                  required: true
-                  type: string
-                  x-go-name: Network
-            responses:
-                "200":
-                    $ref: '#/responses/extClientResponse'
-            schemes:
-                - https
-            summary: Get an individual extclient.
-            tags:
-                - ext_client
-    /api/extclients/{network}/{nodeid}:
-        post:
-            operationId: createExtClient
-            parameters:
-                - description: Network
-                  in: path
-                  name: network
-                  required: true
-                  type: string
-                  x-go-name: Network
-                - description: Node ID
-                  in: path
-                  name: nodeid
-                  required: true
-                  type: string
-                  x-go-name: NodeID
-                - description: Custom ExtClient
-                  in: body
-                  name: custom_ext_client
-                  schema:
-                    $ref: '#/definitions/CustomExtClient'
-                  x-go-name: CustomExtClient
-            responses:
-                "200":
-                    $ref: '#/responses/okResponse'
-            schemes:
-                - https
-            summary: Create an individual extclient.  Must have valid key and be unique.
-            tags:
-                - ext_client
-    /api/getip:
-        get:
-            operationId: getPublicIP
-            responses:
-                "200":
-                    $ref: '#/responses/byteArrayResponse'
-            schemes:
-                - https
-            summary: Get the current public IP address.
-            tags:
-                - ipservice
-    /api/hosts:
-        get:
-            operationId: getHosts
-            responses:
-                "200":
-                    $ref: '#/responses/apiHostSliceResponse'
-            schemes:
-                - https
-            summary: Lists all hosts.
-            tags:
-                - hosts
-    /api/hosts/{hostid}:
-        delete:
-            operationId: deleteHost
-            parameters:
-                - description: HostID
-                  in: path
-                  name: hostid
-                  required: true
-                  type: string
-                  x-go-name: HostID
-            responses:
-                "200":
-                    $ref: '#/responses/apiHostResponse'
-            schemes:
-                - https
-            summary: Deletes a Netclient host from Netmaker server.
-            tags:
-                - hosts
-        put:
-            operationId: updateHost
-            parameters:
-                - description: HostID
-                  in: path
-                  name: hostid
-                  required: true
-                  type: string
-                  x-go-name: HostID
-            responses:
-                "200":
-                    $ref: '#/responses/apiHostResponse'
-            schemes:
-                - https
-            summary: Updates a Netclient host on Netmaker server.
-            tags:
-                - hosts
-    /api/hosts/{hostid}/networks/{network}:
-        delete:
-            operationId: deleteHostFromNetwork
-            parameters:
-                - description: hostid to add or delete from network
-                  in: path
-                  name: hostid
-                  required: true
-                  type: string
-                  x-go-name: HostID
-                - description: network
-                  in: path
-                  name: network
-                  required: true
-                  type: string
-                  x-go-name: Network
-            responses:
-                "200":
-                    $ref: '#/responses/okResponse'
-            schemes:
-                - https
-            summary: Given a network, a host is removed from the network.
-            tags:
-                - hosts
-        post:
-            operationId: addHostToNetwork
-            parameters:
-                - description: hostid to add or delete from network
-                  in: path
-                  name: hostid
-                  required: true
-                  type: string
-                  x-go-name: HostID
-                - description: network
-                  in: path
-                  name: network
-                  required: true
-                  type: string
-                  x-go-name: Network
-            responses:
-                "200":
-                    $ref: '#/responses/okResponse'
-            schemes:
-                - https
-            summary: Given a network, a host is added to the network.
-            tags:
-                - hosts
-    /api/hosts/{hostid}/signalpeer:
-        post:
-            operationId: signalPeer
-            parameters:
-                - description: HostID
-                  in: path
-                  name: hostid
-                  required: true
-                  type: string
-                  x-go-name: HostID
-            responses:
-                "200":
-                    $ref: '#/responses/signal'
-            schemes:
-                - https
-            summary: send signal to peer.
-            tags:
-                - hosts
-    /api/hosts/{hostid}/sync:
-        post:
-            operationId: synchost
-            parameters:
-                - description: HostID
-                  in: path
-                  name: hostid
-                  required: true
-                  type: string
-                  x-go-name: HostID
-            responses:
-                "200":
-                    $ref: '#/responses/networkBodyResponse'
-            schemes:
-                - https
-            summary: Requests a host to pull.
-            tags:
-                - hosts
-    /api/hosts/{hostid}keys:
-        post:
-            operationId: updateKeys
-            parameters:
-                - description: HostID
-                  in: path
-                  name: hostid
-                  required: true
-                  type: string
-                  x-go-name: HostID
-            responses:
-                "200":
-                    $ref: '#/responses/networkBodyResponse'
-            schemes:
-                - https
-            summary: Update keys for a network.
-            tags:
-                - hosts
-    /api/hosts/adm/authenticate:
-        post:
-            operationId: authenticateHost
-            responses:
-                "200":
-                    $ref: '#/responses/successResponse'
-            schemes:
-                - https
-            summary: Host based authentication for making further API calls.
-            tags:
-                - authenticate
-    /api/hosts/keys:
-        post:
-            operationId: updateAllKeys
-            responses:
-                "200":
-                    $ref: '#/responses/networkBodyResponse'
-            schemes:
-                - https
-            summary: Update keys for a network.
-            tags:
-                - hosts
-    /api/networks:
-        get:
-            operationId: getNetworks
-            responses:
-                "200":
-                    $ref: '#/responses/getNetworksSliceResponse'
-            schemes:
-                - https
-            summary: Lists all networks.
-            tags:
-                - networks
-        post:
-            operationId: createNetwork
-            parameters:
-                - description: Network
-                  in: body
-                  name: network
-                  schema:
-                    $ref: '#/definitions/Network'
-                  x-go-name: Network
-            responses:
-                "200":
-                    $ref: '#/responses/networkBodyResponse'
-            schemes:
-                - https
-            summary: Create a network.
-            tags:
-                - networks
-    /api/networks/{networkname}:
-        delete:
-            operationId: deleteNetwork
-            parameters:
-                - description: 'name: network name'
-                  in: path
-                  name: networkname
-                  required: true
-                  type: string
-                  x-go-name: Networkname
-            responses:
-                "200":
-                    $ref: '#/responses/successResponse'
-            schemes:
-                - https
-            summary: Delete a network.  Will not delete if there are any nodes that belong to the network.
-            tags:
-                - networks
-        get:
-            operationId: getNetwork
-            parameters:
-                - description: 'name: network name'
-                  in: path
-                  name: networkname
-                  required: true
-                  type: string
-                  x-go-name: Networkname
-            responses:
-                "200":
-                    $ref: '#/responses/networkBodyResponse'
-            schemes:
-                - https
-            summary: Get a network.
-            tags:
-                - networks
-        put:
-            operationId: updateNetwork
-            parameters:
-                - description: 'name: network name'
-                  in: path
-                  name: networkname
-                  required: true
-                  type: string
-                  x-go-name: Networkname
-                - description: Network
-                  in: body
-                  name: network
-                  schema:
-                    $ref: '#/definitions/Network'
-                  x-go-name: Network
-            responses:
-                "200":
-                    $ref: '#/responses/networkBodyResponse'
-            schemes:
-                - https
-            summary: Update pro settings for a network.
-            tags:
-                - networks
-    /api/networks/{networkname}/acls:
-        get:
-            operationId: getNetworkACL
-            parameters:
-                - description: 'name: network name'
-                  in: path
-                  name: networkname
-                  required: true
-                  type: string
-                  x-go-name: Networkname
-            responses:
-                "200":
-                    $ref: '#/responses/aclContainerResponse'
-            schemes:
-                - https
-            summary: Get a network ACL (Access Control List).
-            tags:
-                - networks
-        put:
-            operationId: updateNetworkACL
-            parameters:
-                - description: 'name: network name'
-                  in: path
-                  name: networkname
-                  required: true
-                  type: string
-                  x-go-name: Networkname
-                - description: ACL Container
-                  in: body
-                  name: acl_container
-                  schema:
-                    $ref: '#/definitions/ACLContainer'
-                  x-go-name: ACLContainer
-            responses:
-                "200":
-                    $ref: '#/responses/aclContainerResponse'
-            schemes:
-                - https
-            summary: Update a network ACL (Access Control List).
-            tags:
-                - networks
-    /api/networks/{networkname}/acls/v2:
-        put:
-            operationId: updateNetworkACL
-            parameters:
-                - description: 'name: network name'
-                  in: path
-                  name: networkname
-                  required: true
-                  type: string
-                  x-go-name: Networkname
-                - description: ACL Container
-                  in: body
-                  name: acl_container
-                  schema:
-                    $ref: '#/definitions/ACLContainer'
-                  x-go-name: ACLContainer
-            responses:
-                "200":
-                    $ref: '#/responses/aclContainerResponse'
-            schemes:
-                - https
-            summary: Update a network ACL (Access Control List).
-            tags:
-                - networks
-    /api/node/{nodeid}/failOverME:
-        post:
-            operationId: failOver_me
-            responses:
-                "200":
-                    $ref: '#/responses/nodeResponse'
-            schemes:
-                - https
-            summary: Create a relay.
-            tags:
-                - node
-    /api/nodes:
-        get:
-            operationId: getAllNodes
-            responses:
-                "200":
-                    $ref: '#/responses/nodeSliceResponse'
-            schemes:
-                - https
-            summary: Get all nodes across all networks.
-            tags:
-                - nodes
-    /api/nodes/{network}:
-        get:
-            operationId: getNetworkNodes
-            parameters:
-                - description: Network
-                  in: path
-                  name: network
-                  required: true
-                  type: string
-                  x-go-name: Network
-            responses:
-                "200":
-                    $ref: '#/responses/nodeSliceResponse'
-            schemes:
-                - https
-            summary: Gets all nodes associated with network including pending nodes.
-            tags:
-                - nodes
-    /api/nodes/{network}/{nodeid}:
-        delete:
-            operationId: deleteNode
-            parameters:
-                - in: path
-                  name: network
-                  required: true
-                  type: string
-                  x-go-name: Network
-                - in: path
-                  name: nodeid
-                  required: true
-                  type: string
-                  x-go-name: NodeID
-                - description: Node
-                  in: body
-                  name: node
-                  schema:
-                    $ref: '#/definitions/LegacyNode'
-                  x-go-name: Node
-            responses:
-                "200":
-                    $ref: '#/responses/nodeResponse'
-            schemes:
-                - https
-            summary: Delete an individual node.
-            tags:
-                - nodes
-        get:
-            operationId: getNode
-            parameters:
-                - in: path
-                  name: network
-                  required: true
-                  type: string
-                  x-go-name: Network
-                - in: path
-                  name: nodeid
-                  required: true
-                  type: string
-                  x-go-name: NodeID
-            responses:
-                "200":
-                    $ref: '#/responses/nodeResponse'
-            schemes:
-                - https
-            summary: Get an individual node.
-            tags:
-                - nodes
-        put:
-            operationId: updateNode
-            parameters:
-                - in: path
-                  name: network
-                  required: true
-                  type: string
-                  x-go-name: Network
-                - in: path
-                  name: nodeid
-                  required: true
-                  type: string
-                  x-go-name: NodeID
-                - description: Node
-                  in: body
-                  name: node
-                  schema:
-                    $ref: '#/definitions/LegacyNode'
-                  x-go-name: Node
-            responses:
-                "200":
-                    $ref: '#/responses/nodeResponse'
-            schemes:
-                - https
-            summary: Update an individual node.
-            tags:
-                - nodes
-    /api/nodes/{network}/{nodeid}/creategateway:
-        post:
-            operationId: createEgressGateway
-            parameters:
-                - in: path
-                  name: network
-                  required: true
-                  type: string
-                  x-go-name: Network
-                - in: path
-                  name: nodeid
-                  required: true
-                  type: string
-                  x-go-name: NodeID
-                - description: Egress Gateway Request
-                  in: body
-                  name: egress_gateway_request
-                  schema:
-                    $ref: '#/definitions/EgressGatewayRequest'
-                  x-go-name: EgressGatewayRequest
-            responses:
-                "200":
-                    $ref: '#/responses/nodeResponse'
-            schemes:
-                - https
-            summary: Create an egress gateway.
-            tags:
-                - nodes
-    /api/nodes/{network}/{nodeid}/createingress:
-        post:
-            operationId: createIngressGateway
-            parameters:
-                - in: path
-                  name: network
-                  required: true
-                  type: string
-                  x-go-name: Network
-                - in: path
-                  name: nodeid
-                  required: true
-                  type: string
-                  x-go-name: NodeID
-            responses:
-                "200":
-                    $ref: '#/responses/nodeResponse'
-            schemes:
-                - https
-            summary: Create an ingress gateway.
-            tags:
-                - nodes
-    /api/nodes/{network}/{nodeid}/createrelay:
-        post:
-            operationId: createRelay
-            parameters:
-                - in: path
-                  name: network
-                  required: true
-                  type: string
-                  x-go-name: Network
-                - in: path
-                  name: nodeid
-                  required: true
-                  type: string
-                  x-go-name: NodeID
-                - description: Relay Request
-                  in: body
-                  name: relay_request
-                  schema:
-                    $ref: '#/definitions/RelayRequest'
-                  x-go-name: RelayRequest
-            responses:
-                "200":
-                    $ref: '#/responses/nodeResponse'
-            schemes:
-                - https
-            summary: Create a relay.
-            tags:
-                - nodes
-    /api/nodes/{network}/{nodeid}/deletegateway:
-        delete:
-            operationId: deleteEgressGateway
-            parameters:
-                - in: path
-                  name: network
-                  required: true
-                  type: string
-                  x-go-name: Network
-                - in: path
-                  name: nodeid
-                  required: true
-                  type: string
-                  x-go-name: NodeID
-            responses:
-                "200":
-                    $ref: '#/responses/nodeResponse'
-            schemes:
-                - https
-            summary: Delete an egress gateway.
-            tags:
-                - nodes
-    /api/nodes/{network}/{nodeid}/deleteingress:
-        delete:
-            operationId: deleteIngressGateway
-            parameters:
-                - in: path
-                  name: network
-                  required: true
-                  type: string
-                  x-go-name: Network
-                - in: path
-                  name: nodeid
-                  required: true
-                  type: string
-                  x-go-name: NodeID
-            responses:
-                "200":
-                    $ref: '#/responses/nodeResponse'
-            schemes:
-                - https
-            summary: Delete an ingress gateway.
-            tags:
-                - nodes
-    /api/nodes/{network}/{nodeid}/deleterelay:
-        delete:
-            operationId: deleteRelay
-            parameters:
-                - in: path
-                  name: network
-                  required: true
-                  type: string
-                  x-go-name: Network
-                - in: path
-                  name: nodeid
-                  required: true
-                  type: string
-                  x-go-name: NodeID
-            responses:
-                "200":
-                    $ref: '#/responses/nodeResponse'
-            schemes:
-                - https
-            summary: Remove a relay.
-            tags:
-                - nodes
-    /api/nodes/{network}/{nodeid}/inet_gw:
-        delete:
-            operationId: deleteInternetGw
-            responses:
-                "200":
-                    $ref: '#/responses/nodeResponse'
-            schemes:
-                - https
-            summary: Delete an internet gw.
-            tags:
-                - nodes
-        post:
-            operationId: createInternetGw
-            responses:
-                "200":
-                    $ref: '#/responses/nodeResponse'
-            schemes:
-                - https
-            summary: Create an inet node.
-            tags:
-                - nodes
-        put:
-            operationId: updateInternetGw
-            responses:
-                "200":
-                    $ref: '#/responses/nodeResponse'
-            schemes:
-                - https
-            summary: update an inet node.
-            tags:
-                - nodes
-    /api/nodes/{network}/{nodeid}/ingress/users:
-        get:
-            operationId: ingressGatewayUsers
-            parameters:
-                - in: path
-                  name: network
-                  required: true
-                  type: string
-                  x-go-name: Network
-                - in: path
-                  name: nodeid
-                  required: true
-                  type: string
-                  x-go-name: NodeID
-            responses:
-                "200":
-                    $ref: '#/responses/nodeResponse'
-            schemes:
-                - https
-            summary: Lists all the users attached to an ingress gateway.
-            tags:
-                - users
-    /api/nodes/adm/{network}/authenticate:
-        post:
-            operationId: authenticate
-            parameters:
-                - description: network
-                  in: path
-                  name: network
-                  required: true
-                  type: string
-                  x-go-name: Network
-                - description: AuthParams
-                  in: body
-                  name: auth_params
-                  schema:
-                    $ref: '#/definitions/AuthParams'
-                  x-go-name: AuthParams
-            responses:
-                "200":
-                    $ref: '#/responses/successResponse'
-            schemes:
-                - https
-            summary: Authenticate to make further API calls related to a network.
-            tags:
-                - authenticate
-    /api/oauth/login:
-        get:
-            operationId: HandleAuthLogin
-            responses:
-                "200":
-                    $ref: '#/responses/okResponse'
-            schemes:
-                - https
-            summary: Handles OAuth login.
-            tags:
-                - nodes
-    /api/server/getconfig:
-        get:
-            operationId: getConfig
-            responses:
-                "200":
-                    $ref: '#/responses/serverConfigResponse'
-            schemes:
-                - https
-            summary: Get the server configuration.
-            tags:
-                - server
-    /api/server/getserverinfo:
-        get:
-            operationId: getServerInfo
-            responses:
-                "200":
-                    $ref: '#/responses/serverConfigResponse'
-            schemes:
-                - https
-            summary: Get the server configuration.
-            tags:
-                - server
-    /api/server/status:
-        get:
-            operationId: getStatus
-            responses:
-                "200":
-                    $ref: '#/responses/serverConfigResponse'
-            schemes:
-                - https
-            summary: Get the server configuration.
-            tags:
-                - server
-    /api/users:
-        get:
-            operationId: getUsers
-            responses:
-                "200":
-                    $ref: '#/responses/userBodyResponse'
-            schemes:
-                - https
-            summary: Get all users.
-            tags:
-                - user
-    /api/users/{username}:
-        delete:
-            operationId: deleteUser
-            parameters:
-                - description: Username
-                  in: path
-                  name: username
-                  required: true
-                  type: string
-                  x-go-name: Username
-            responses:
-                "200":
-                    $ref: '#/responses/userBodyResponse'
-            schemes:
-                - https
-            summary: Delete a user.
-            tags:
-                - user
-        get:
-            operationId: getUser
-            parameters:
-                - description: Username
-                  in: path
-                  name: username
-                  required: true
-                  type: string
-                  x-go-name: Username
-            responses:
-                "200":
-                    $ref: '#/responses/userBodyResponse'
-            schemes:
-                - https
-            summary: Get an individual user.
-            tags:
-                - user
-        post:
-            operationId: createUser
-            parameters:
-                - description: User
-                  in: body
-                  name: user
-                  schema:
-                    $ref: '#/definitions/User'
-                  x-go-name: User
-                - description: Username
-                  in: path
-                  name: username
-                  required: true
-                  type: string
-                  x-go-name: Username
-            responses:
-                "200":
-                    $ref: '#/responses/userBodyResponse'
-            schemes:
-                - https
-            summary: Create a user.
-            tags:
-                - user
-        put:
-            operationId: updateUser
-            parameters:
-                - description: User
-                  in: body
-                  name: user
-                  schema:
-                    $ref: '#/definitions/User'
-                  x-go-name: User
-                - description: Username
-                  in: path
-                  name: username
-                  required: true
-                  type: string
-                  x-go-name: Username
-            responses:
-                "200":
-                    $ref: '#/responses/userBodyResponse'
-            schemes:
-                - https
-            summary: Update a user.
-            tags:
-                - user
-    /api/users/{username}/remote_access_gw:
-        delete:
-            operationId: removeUserFromRemoteAccessGW
-            parameters:
-                - in: path
-                  name: username
-                  required: true
-                  type: string
-                  x-go-name: Username
-            responses:
-                "200":
-                    $ref: '#/responses/userBodyResponse'
-            schemes:
-                - https
-            summary: Delete User from a remote access gateway.
-            tags:
-                - user
-        post:
-            operationId: attachUserToRemoteAccessGateway
-            parameters:
-                - in: path
-                  name: username
-                  required: true
-                  type: string
-                  x-go-name: Username
-            responses:
-                "200":
-                    $ref: '#/responses/userBodyResponse'
-            schemes:
-                - https
-            summary: Attach User to a remote access gateway.
-            tags:
-                - user
-    /api/users/adm/authenticate:
-        post:
-            operationId: authenticateUser
-            parameters:
-                - description: User Auth Params
-                  in: body
-                  name: user_auth_params
-                  schema:
-                    $ref: '#/definitions/UserAuthParams'
-                  x-go-name: UserAuthParams
-            responses:
-                "200":
-                    $ref: '#/responses/successResponse'
-            schemes:
-                - https
-            summary: User authenticates using its password and retrieves a JWT for authorization.
-            tags:
-                - authenticate
-    /api/users/adm/createsuperadmin:
-        post:
-            operationId: createAdmin
-            parameters:
-                - description: User
-                  in: body
-                  name: user
-                  schema:
-                    $ref: '#/definitions/User'
-                  x-go-name: User
-            responses:
-                "200":
-                    $ref: '#/responses/userBodyResponse'
-            schemes:
-                - https
-            summary: Make a user an admin.
-            tags:
-                - user
-    /api/users/adm/hassuperadmin:
-        get:
-            operationId: hasSuperAdmin
-            responses:
-                "200":
-                    $ref: '#/responses/hasAdmin'
-            schemes:
-                - https
-            summary: Checks whether the server has an admin.
-            tags:
-                - user
-    /api/users/adm/transfersuperadmin:
-        post:
-            operationId: transferSuperAdmin
-            responses:
-                "200":
-                    $ref: '#/responses/userBodyResponse'
-            schemes:
-                - https
-            summary: Transfers superadmin role to an admin user.
-            tags:
-                - user
-    /api/users_pending:
-        get:
-            operationId: getPendingUsers
-            responses:
-                "200":
-                    $ref: '#/responses/userBodyResponse'
-            schemes:
-                - https
-            summary: Get all pending users.
-            tags:
-                - user
-    /api/users_pending/{username}/pending:
-        delete:
-            operationId: deleteAllPendingUsers
-            responses:
-                "200":
-                    $ref: '#/responses/userBodyResponse'
-            schemes:
-                - https
-            summary: delete all pending users.
-            tags:
-                - user
-    /api/users_pending/user/{username}:
-        delete:
-            operationId: deletePendingUser
-            responses:
-                "200":
-                    $ref: '#/responses/userBodyResponse'
-            schemes:
-                - https
-            summary: delete pending user.
-            tags:
-                - user
-        post:
-            operationId: approvePendingUser
-            responses:
-                "200":
-                    $ref: '#/responses/userBodyResponse'
-            schemes:
-                - https
-            summary: approve pending user.
-            tags:
-                - user
-    /api/v1/enrollment-keys:
-        get:
-            operationId: getEnrollmentKeys
-            responses:
-                "200":
-                    $ref: '#/responses/EnrollmentKeys'
-            schemes:
-                - https
-            summary: Lists all EnrollmentKeys for admins.
-            tags:
-                - enrollmentKeys
-        post:
-            operationId: createEnrollmentKey
-            parameters:
-                - description: APIEnrollmentKey
-                  in: body
-                  name: body
-                  schema:
-                    $ref: '#/definitions/APIEnrollmentKey'
-                  x-go-name: Body
-            responses:
-                "200":
-                    $ref: '#/responses/EnrollmentKey'
-            schemes:
-                - https
-            summary: Creates an EnrollmentKey for hosts to use on Netmaker server.
-            tags:
-                - enrollmentKeys
-    /api/v1/enrollment-keys/{keyid}:
-        delete:
-            operationId: deleteEnrollmentKey
-            parameters:
-                - in: path
-                  name: keyid
-                  required: true
-                  type: string
-                  x-go-name: KeyID
-            responses:
-                "200":
-                    $ref: '#/responses/okResponse'
-            schemes:
-                - https
-            summary: Deletes an EnrollmentKey from Netmaker server.
-            tags:
-                - enrollmentKeys
-        put:
-            operationId: updateEnrollmentKey
-            parameters:
-                - description: KeyID
-                  in: path
-                  name: keyid
-                  required: true
-                  type: string
-                  x-go-name: KeyID
-                - description: APIEnrollmentKey
-                  in: body
-                  name: body
-                  schema:
-                    $ref: '#/definitions/APIEnrollmentKey'
-                  x-go-name: Body
-            responses:
-                "200":
-                    $ref: '#/responses/EnrollmentKey'
-            schemes:
-                - https
-            summary: Updates an EnrollmentKey for hosts to use on Netmaker server. Updates only the relay to use.
-            tags:
-                - enrollmentKeys
-    /api/v1/enrollment-keys/{token}:
-        post:
-            operationId: handleHostRegister
-            parameters:
-                - in: path
-                  name: token
-                  required: true
-                  type: string
-                  x-go-name: Token
-                - in: body
-                  name: host
-                  schema:
-                    $ref: '#/definitions/Host'
-                  x-go-name: Host
-            responses:
-                "200":
-                    $ref: '#/responses/RegisterResponse'
-            schemes:
-                - https
-            summary: Handles a Netclient registration with server and add nodes accordingly.
-            tags:
-                - enrollmentKeys
-    /api/v1/fallback/host/{hostid}:
-        put:
-            operationId: hostUpdateFallback
-            responses:
-                "200":
-                    $ref: '#/responses/apiHostResponse'
-            schemes:
-                - https
-            summary: Updates a Netclient host on Netmaker server.
-            tags:
-                - hosts
-    /api/v1/host:
-        get:
-            description: Used by clients for "pull" command
-            operationId: pullHost
-            responses:
-                "200":
-                    $ref: '#/responses/hostPull'
-            schemes:
-                - https
-            tags:
-                - hosts
-    /api/v1/legacy/nodes:
-        delete:
-            operationId: wipeLegacyNodes
-            responses:
-                "200":
-                    $ref: '#/responses/successResponse'
-            schemes:
-                - https
-            summary: Delete all legacy nodes from DB.
-            tags:
-                - nodes
-    /api/v1/node/failover:
-        delete:
-            operationId: deletefailOver
-            responses:
-                "200":
-                    $ref: '#/responses/nodeResponse'
-            schemes:
-                - https
-            summary: Create a relay.
-            tags:
-                - node
-        post:
-            operationId: createfailOver
-            responses:
-                "200":
-                    $ref: '#/responses/nodeResponse'
-            schemes:
-                - https
-            summary: Create a relay.
-            tags:
-                - node
-    /api/v1/nodes/migrate:
-        put:
-            operationId: migrateData
-            responses:
-                "200":
-                    $ref: '#/responses/hostPull'
-            schemes:
-                - https
-            summary: Used to migrate a legacy node.
-            tags:
-                - nodes
-    /meshclient/files/{filename}:
-        get:
-            operationId: getFile
-            parameters:
-                - description: Filename
-                  in: path
-                  name: filename
-                  required: true
-                  type: string
-                  x-go-name: Filename
-            responses:
-                "200":
-                    $ref: '#/responses/fileResponse'
-            schemes:
-                - https
-            summary: Retrieve a file from the file server.
-            tags:
-                - meshclient
-produces:
-    - application/json
-responses:
-    EnrollmentKey:
-        description: ""
-        schema:
-            $ref: '#/definitions/EnrollmentKey'
-    EnrollmentKeys:
-        description: ""
-        schema:
-            items:
-                $ref: '#/definitions/EnrollmentKey'
-            type: array
-    RegisterResponse:
-        description: ""
-        schema:
-            $ref: '#/definitions/RegisterResponse'
-    aclContainerResponse:
-        description: ""
-        schema:
-            $ref: '#/definitions/ACLContainer'
-    apiHostResponse:
-        description: ""
-        schema:
-            $ref: '#/definitions/ApiHost'
-    apiHostSliceResponse:
-        description: ""
-        schema:
-            items:
-                $ref: '#/definitions/ApiHost'
-            type: array
-    byteArrayResponse:
-        description: ""
-        schema:
-            items:
-                format: uint8
-                type: integer
-            type: array
-    dnsResponse:
-        description: Success
-        schema:
-            items:
-                $ref: '#/definitions/DNSEntry'
-            type: array
-    extClientResponse:
-        description: ""
-        schema:
-            $ref: '#/definitions/ExtClient'
-    extClientSliceResponse:
-        description: ""
-        schema:
-            items:
-                $ref: '#/definitions/ExtClient'
-            type: array
-    fileResponse:
-        description: ""
-        schema:
-            $ref: '#/definitions/File'
-    getNetworksSliceResponse:
-        description: ""
-        schema:
-            items:
-                $ref: '#/definitions/Network'
-            type: array
-    hasAdmin:
-        description: ""
-    hostPull:
-        description: ""
-        schema:
-            $ref: '#/definitions/HostPull'
-    networkBodyResponse:
-        description: ""
-        schema:
-            $ref: '#/definitions/Network'
-    nodeResponse:
-        description: ""
-        schema:
-            $ref: '#/definitions/LegacyNode'
-    nodeSliceResponse:
-        description: ""
-        schema:
-            items:
-                $ref: '#/definitions/ApiNode'
-            type: array
-    okResponse:
-        description: ""
-    serverConfigResponse:
-        description: ""
-        schema:
-            $ref: '#/definitions/ServerConfig'
-    signal:
-        description: ""
-        schema:
-            $ref: '#/definitions/Signal'
-    stringJSONResponse:
-        description: ""
-    successResponse:
-        description: ""
-        schema:
-            $ref: '#/definitions/SuccessResponse'
-    userBodyResponse:
-        description: ""
-        schema:
-            $ref: '#/definitions/User'
-schemes:
-    - https
-swagger: "2.0"