finished initial crud for hosts, fixed stun server close bug

This commit is contained in:
0xdcarns
2022-12-19 14:55:24 -05:00
parent f267648286
commit cc529ab3bd
6 changed files with 325 additions and 93 deletions

View File

@@ -27,6 +27,7 @@ var HttpHandlers = []interface{}{
extClientHandlers, extClientHandlers,
ipHandlers, ipHandlers,
loggerHandlers, loggerHandlers,
hostHandlers,
} }
// HandleRESTRequests - handles the rest requests // HandleRESTRequests - handles the rest requests

114
controllers/hosts.go Normal file
View File

@@ -0,0 +1,114 @@
package controller
import (
"encoding/json"
"net/http"
"github.com/gorilla/mux"
"github.com/gravitl/netmaker/logger"
"github.com/gravitl/netmaker/logic"
"github.com/gravitl/netmaker/models"
)
func hostHandlers(r *mux.Router) {
r.HandleFunc("/api/hosts", logic.SecurityCheck(false, http.HandlerFunc(getHosts))).Methods("GET")
r.HandleFunc("/api/hosts", logic.SecurityCheck(true, http.HandlerFunc(updateHost))).Methods("PUT")
r.HandleFunc("/api/hosts/{hostid}", logic.SecurityCheck(true, http.HandlerFunc(deleteHost))).Methods("DELETE")
// r.HandleFunc("/api/hosts/{hostid}/{network}", logic.SecurityCheck(false, http.HandlerFunc(getHosts))).Methods("PUT")
}
// swagger:route GET /api/hosts hosts getHosts
//
// Lists all hosts.
//
// Schemes: https
//
// Security:
// oauth
//
// Responses:
// 200: getHostsSliceResponse
func getHosts(w http.ResponseWriter, r *http.Request) {
currentHosts, err := logic.GetAllHosts()
if err != nil {
logger.Log(0, r.Header.Get("user"), "failed to fetch hosts: ", err.Error())
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return
}
logger.Log(2, r.Header.Get("user"), "fetched all hosts")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(currentHosts)
}
// swagger:route PUT /api/hosts/{hostid} hosts updateHost
//
// Updates a Netclient host on Netmaker server.
//
// Schemes: https
//
// Security:
// oauth
//
// Responses:
// 200: updateHostResponse
func updateHost(w http.ResponseWriter, r *http.Request) {
var newHostData models.Host
err := json.NewDecoder(r.Body).Decode(&newHostData)
if err != nil {
logger.Log(0, r.Header.Get("user"), "failed to update a host:", err.Error())
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return
}
// confirm host exists
currHost, err := logic.GetHost(newHostData.ID.String())
if err != nil {
logger.Log(0, r.Header.Get("user"), "failed to update a host:", err.Error())
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return
}
logic.UpdateHost(&newHostData, currHost) // update the in memory struct values
if err = logic.UpsertHost(&newHostData); err != nil {
logger.Log(0, r.Header.Get("user"), "failed to update a host:", err.Error())
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return
}
logger.Log(2, r.Header.Get("user"), "updated host", newHostData.ID.String())
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(newHostData)
}
// swagger:route DELETE /api/hosts/{hostid} hosts deleteHost
//
// Deletes a Netclient host from Netmaker server.
//
// Schemes: https
//
// Security:
// oauth
//
// Responses:
// 200: deleteHostResponse
func deleteHost(w http.ResponseWriter, r *http.Request) {
var params = mux.Vars(r)
hostid := params["hostid"]
// confirm host exists
currHost, err := logic.GetHost(hostid)
if err != nil {
logger.Log(0, r.Header.Get("user"), "failed to delete a host:", err.Error())
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return
}
if err = logic.RemoveHost(currHost); err != nil {
logger.Log(0, r.Header.Get("user"), "failed to delete a host:", err.Error())
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return
}
logger.Log(2, r.Header.Get("user"), "removed host", currHost.Name)
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(currHost)
}

View File

@@ -14,96 +14,73 @@ import (
"golang.org/x/crypto/nacl/box" "golang.org/x/crypto/nacl/box"
) )
const (
// == Table Names ==
// NETWORKS_TABLE_NAME - networks table // NETWORKS_TABLE_NAME - networks table
const NETWORKS_TABLE_NAME = "networks" NETWORKS_TABLE_NAME = "networks"
// NODES_TABLE_NAME - nodes table // NODES_TABLE_NAME - nodes table
const NODES_TABLE_NAME = "nodes" NODES_TABLE_NAME = "nodes"
// DELETED_NODES_TABLE_NAME - deleted nodes table // DELETED_NODES_TABLE_NAME - deleted nodes table
const DELETED_NODES_TABLE_NAME = "deletednodes" DELETED_NODES_TABLE_NAME = "deletednodes"
// USERS_TABLE_NAME - users table // USERS_TABLE_NAME - users table
const USERS_TABLE_NAME = "users" USERS_TABLE_NAME = "users"
// CERTS_TABLE_NAME - certificates table // CERTS_TABLE_NAME - certificates table
const CERTS_TABLE_NAME = "certs" CERTS_TABLE_NAME = "certs"
// DNS_TABLE_NAME - dns table // DNS_TABLE_NAME - dns table
const DNS_TABLE_NAME = "dns" DNS_TABLE_NAME = "dns"
// EXT_CLIENT_TABLE_NAME - ext client table // EXT_CLIENT_TABLE_NAME - ext client table
const EXT_CLIENT_TABLE_NAME = "extclients" EXT_CLIENT_TABLE_NAME = "extclients"
// PEERS_TABLE_NAME - peers table // PEERS_TABLE_NAME - peers table
const PEERS_TABLE_NAME = "peers" PEERS_TABLE_NAME = "peers"
// SERVERCONF_TABLE_NAME - stores server conf // SERVERCONF_TABLE_NAME - stores server conf
const SERVERCONF_TABLE_NAME = "serverconf" SERVERCONF_TABLE_NAME = "serverconf"
// SERVER_UUID_TABLE_NAME - stores unique netmaker server data // SERVER_UUID_TABLE_NAME - stores unique netmaker server data
const SERVER_UUID_TABLE_NAME = "serveruuid" SERVER_UUID_TABLE_NAME = "serveruuid"
// SERVER_UUID_RECORD_KEY - telemetry thing // SERVER_UUID_RECORD_KEY - telemetry thing
const SERVER_UUID_RECORD_KEY = "serveruuid" SERVER_UUID_RECORD_KEY = "serveruuid"
// DATABASE_FILENAME - database file name // DATABASE_FILENAME - database file name
const DATABASE_FILENAME = "netmaker.db" DATABASE_FILENAME = "netmaker.db"
// GENERATED_TABLE_NAME - stores server generated k/v // GENERATED_TABLE_NAME - stores server generated k/v
const GENERATED_TABLE_NAME = "generated" GENERATED_TABLE_NAME = "generated"
// NODE_ACLS_TABLE_NAME - stores the node ACL rules // NODE_ACLS_TABLE_NAME - stores the node ACL rules
const NODE_ACLS_TABLE_NAME = "nodeacls" NODE_ACLS_TABLE_NAME = "nodeacls"
// SSO_STATE_CACHE - holds sso session information for OAuth2 sign-ins // SSO_STATE_CACHE - holds sso session information for OAuth2 sign-ins
const SSO_STATE_CACHE = "ssostatecache" SSO_STATE_CACHE = "ssostatecache"
// METRICS_TABLE_NAME - stores network metrics // METRICS_TABLE_NAME - stores network metrics
const METRICS_TABLE_NAME = "metrics" METRICS_TABLE_NAME = "metrics"
// NETWORK_USER_TABLE_NAME - network user table tracks stats for a network user per network // NETWORK_USER_TABLE_NAME - network user table tracks stats for a network user per network
const NETWORK_USER_TABLE_NAME = "networkusers" NETWORK_USER_TABLE_NAME = "networkusers"
// USER_GROUPS_TABLE_NAME - table for storing usergroups // USER_GROUPS_TABLE_NAME - table for storing usergroups
const USER_GROUPS_TABLE_NAME = "usergroups" USER_GROUPS_TABLE_NAME = "usergroups"
// CACHE_TABLE_NAME - caching table // CACHE_TABLE_NAME - caching table
const CACHE_TABLE_NAME = "cache" CACHE_TABLE_NAME = "cache"
// HOSTS_TABLE_NAME - the table name for hosts
HOSTS_TABLE_NAME = "hosts"
// == ERROR CONSTS == // == ERROR CONSTS ==
// NO_RECORD - no singular result found // NO_RECORD - no singular result found
const NO_RECORD = "no result found" NO_RECORD = "no result found"
// NO_RECORDS - no results found // NO_RECORDS - no results found
const NO_RECORDS = "could not find any records" NO_RECORDS = "could not find any records"
// == Constants ==
// == DB Constants ==
// INIT_DB - initialize db // INIT_DB - initialize db
const INIT_DB = "init" INIT_DB = "init"
// CREATE_TABLE - create table const // CREATE_TABLE - create table const
const CREATE_TABLE = "createtable" CREATE_TABLE = "createtable"
// INSERT - insert into db const // INSERT - insert into db const
const INSERT = "insert" INSERT = "insert"
// INSERT_PEER - insert peer into db const // INSERT_PEER - insert peer into db const
const INSERT_PEER = "insertpeer" INSERT_PEER = "insertpeer"
// DELETE - delete db record const // DELETE - delete db record const
const DELETE = "delete" DELETE = "delete"
// DELETE_ALL - delete a table const // DELETE_ALL - delete a table const
const DELETE_ALL = "deleteall" DELETE_ALL = "deleteall"
// FETCH_ALL - fetch table contents const // FETCH_ALL - fetch table contents const
const FETCH_ALL = "fetchall" FETCH_ALL = "fetchall"
// CLOSE_DB - graceful close of db const // CLOSE_DB - graceful close of db const
const CLOSE_DB = "closedb" CLOSE_DB = "closedb"
)
func getCurrentDB() map[string]interface{} { func getCurrentDB() map[string]interface{} {
switch servercfg.GetDB() { switch servercfg.GetDB() {
@@ -155,6 +132,7 @@ func createTables() {
createTable(NETWORK_USER_TABLE_NAME) createTable(NETWORK_USER_TABLE_NAME)
createTable(USER_GROUPS_TABLE_NAME) createTable(USER_GROUPS_TABLE_NAME)
createTable(CACHE_TABLE_NAME) createTable(CACHE_TABLE_NAME)
createTable(HOSTS_TABLE_NAME)
} }
func createTable(tableName string) error { func createTable(tableName string) error {

139
logic/hosts.go Normal file
View File

@@ -0,0 +1,139 @@
package logic
import (
"encoding/json"
"fmt"
"github.com/gravitl/netmaker/database"
"github.com/gravitl/netmaker/models"
)
// GetAllHosts - returns all hosts in flat list or error
func GetAllHosts() ([]models.Host, error) {
currHostMap, err := GetHostsMap()
if err != nil {
return nil, err
}
var currentHosts = []models.Host{}
for k := range currHostMap {
var h = *currHostMap[k]
currentHosts = append(currentHosts, h)
}
return currentHosts, nil
}
// GetHostsMap - gets all the current hosts on machine in a map
func GetHostsMap() (map[string]*models.Host, error) {
records, err := database.FetchRecords(database.HOSTS_TABLE_NAME)
if err != nil && !database.IsEmptyRecord(err) {
return nil, err
}
currHostMap := make(map[string]*models.Host)
for k := range records {
var h models.Host
err = json.Unmarshal([]byte(records[k]), &h)
if err != nil {
return nil, err
}
currHostMap[h.ID.String()] = &h
}
return currHostMap, nil
}
// GetHost - gets a host from db given id
func GetHost(hostid string) (*models.Host, error) {
record, err := database.FetchRecord(database.HOSTS_TABLE_NAME, hostid)
if err != nil {
return nil, err
}
var h models.Host
if err = json.Unmarshal([]byte(record), &h); err != nil {
return nil, err
}
return &h, nil
}
// CreateHost - creates a host if not exist
func CreateHost(h *models.Host) error {
_, err := GetHost(h.ID.String())
if (err != nil && !database.IsEmptyRecord(err)) || (err == nil) {
return fmt.Errorf("host already exists")
}
return UpsertHost(h)
}
// UpdateHost - updates host data by field
func UpdateHost(newHost, currentHost *models.Host) {
// unchangeable fields via API here
newHost.DaemonInstalled = currentHost.DaemonInstalled
newHost.OS = currentHost.OS
newHost.IPForwarding = currentHost.IPForwarding
newHost.HostPass = currentHost.HostPass
newHost.NodePassword = currentHost.NodePassword
newHost.MacAddress = currentHost.MacAddress
newHost.Debug = currentHost.Debug
newHost.Nodes = currentHost.Nodes
newHost.PublicKey = currentHost.PublicKey
newHost.InternetGateway = currentHost.InternetGateway
newHost.TrafficKeyPublic = currentHost.TrafficKeyPublic
// changeable fields
if len(newHost.Version) == 0 {
newHost.Version = currentHost.Version
}
if len(newHost.Name) == 0 {
newHost.Name = currentHost.Name
}
if newHost.LocalAddress.String() != currentHost.LocalAddress.String() {
newHost.LocalAddress = currentHost.LocalAddress
}
if newHost.LocalRange.String() != currentHost.LocalRange.String() {
newHost.LocalRange = currentHost.LocalRange
}
if newHost.MTU == 0 {
newHost.MTU = currentHost.MTU
}
if newHost.ListenPort == 0 {
newHost.ListenPort = currentHost.ListenPort
}
if newHost.ProxyListenPort == 0 {
newHost.ProxyListenPort = currentHost.ProxyListenPort
}
}
// UpsertHost - upserts into DB a given host model, does not check for existence*
func UpsertHost(h *models.Host) error {
data, err := json.Marshal(h)
if err != nil {
return err
}
return database.Insert(h.ID.String(), string(data), database.HOSTS_TABLE_NAME)
}
// RemoveHost - removes a given host from server
func RemoveHost(h *models.Host) error {
if len(h.Nodes) > 0 {
for i := range h.Nodes {
id := h.Nodes[i]
n, err := GetNodeByID(id)
if err == nil {
if err = DeleteNodeByID(&n); err != nil {
return err // must remove associated nodes before removing a host
}
}
}
}
return database.DeleteRecord(database.HOSTS_TABLE_NAME, h.ID.String())
}

View File

@@ -30,5 +30,5 @@ type Host struct {
MacAddress net.HardwareAddr `json:"macaddress" yaml:"macaddress"` MacAddress net.HardwareAddr `json:"macaddress" yaml:"macaddress"`
TrafficKeyPublic []byte `json:"traffickeypublic" yaml:"trafficekeypublic"` TrafficKeyPublic []byte `json:"traffickeypublic" yaml:"trafficekeypublic"`
InternetGateway net.UDPAddr `json:"internetgateway" yaml:"internetgateway"` InternetGateway net.UDPAddr `json:"internetgateway" yaml:"internetgateway"`
Nodes []Node `json:"nodes" yaml:"nodes"` Nodes []string `json:"nodes" yaml:"nodes"`
} }

View File

@@ -144,20 +144,20 @@ func normalize(address string) string {
return address return address
} }
// Start - starts the stun server
func Start(wg *sync.WaitGroup) { func Start(wg *sync.WaitGroup) {
defer wg.Done()
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
go func() { go func(wg *sync.WaitGroup) {
defer wg.Done()
quit := make(chan os.Signal, 1) quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGTERM, os.Interrupt) signal.Notify(quit, syscall.SIGTERM, os.Interrupt)
<-quit <-quit
cancel() cancel()
}() }(wg)
normalized := normalize(fmt.Sprintf("0.0.0.0:%d", servercfg.GetStunPort())) normalized := normalize(fmt.Sprintf("0.0.0.0:%d", servercfg.GetStunPort()))
logger.Log(0, "netmaker-stun listening on", normalized, "via udp") logger.Log(0, "netmaker-stun listening on", normalized, "via udp")
err := listenUDPAndServe(ctx, "udp", normalized) err := listenUDPAndServe(ctx, "udp", normalized)
if err != nil { if err != nil {
logger.Log(0, "failed to start stun server: ", err.Error()) logger.Log(0, "failed to start stun server: ", err.Error())
} }
} }