refactor node deletion

This commit is contained in:
Matthew R. Kasun 2022-11-15 09:52:17 -05:00
parent b453897e65
commit 4df672de68
7 changed files with 100 additions and 67 deletions

View file

@ -665,7 +665,7 @@ func createNode(w http.ResponseWriter, r *http.Request) {
}
if !updatedUserNode { // user was found but not updated, so delete node
logger.Log(0, "failed to add node to user", keyName)
logic.DeleteNodeByID(&node, true)
logic.DeleteNode(&node, true)
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return
}
@ -1049,22 +1049,11 @@ func deleteNode(w http.ResponseWriter, r *http.Request) {
var params = mux.Vars(r)
var nodeid = params["nodeid"]
fromNode := r.Header.Get("requestfrom") == "node"
var node, err = logic.GetNodeByID(nodeid)
node, err := logic.GetNodeByID(nodeid)
if err != nil {
if fromNode {
node, err = logic.GetDeletedNodeByID(nodeid)
if err != nil {
logger.Log(0, r.Header.Get("user"),
fmt.Sprintf("error fetching node from deleted nodes [ %s ] info: %v", nodeid, err))
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
return
}
} else {
logger.Log(0, r.Header.Get("user"),
fmt.Sprintf("error fetching node [ %s ] info: %v", nodeid, err))
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
return
}
logger.Log(0, "error retrieving node to delete", err.Error())
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
return
}
if isServer(&node) {
err := fmt.Errorf("cannot delete server node")
@ -1080,34 +1069,35 @@ func deleteNode(w http.ResponseWriter, r *http.Request) {
return
}
}
//send update to node to be deleted before deleting on server otherwise message cannot be sent
node.Action = models.NODE_DELETE
err = logic.DeleteNodeByID(&node, fromNode)
if err != nil {
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
if err := logic.DeleteNode(&node, fromNode); err != nil {
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to delete node"), "internal"))
return
}
if fromNode {
// deletes node related role and client
event := mq.MqDynsecPayload{
Commands: []mq.MqDynSecCmd{
{
Command: mq.DeleteClientCmd,
Username: nodeid,
//check if server should be removed from mq
found := false
// err is irrelevent
nodes, _ := logic.GetAllNodes()
for _, nodetocheck := range nodes {
if nodetocheck.HostID == node.HostID {
found = true
break
}
}
if !found {
// deletes node related role and client
event := mq.MqDynsecPayload{
Commands: []mq.MqDynSecCmd{
{
Command: mq.DeleteClientCmd,
Username: node.HostID,
},
},
},
}
if err := mq.PublishEventToDynSecTopic(event); err != nil {
logger.Log(0, fmt.Sprintf("failed to send DynSec command [%v]: %v",
event.Commands, err.Error()))
}
}
if servercfg.Is_EE {
if err = logic.EnterpriseResetAllPeersFailovers(node.ID, node.Network); err != nil {
logger.Log(0, "failed to reset failover lists during node delete for node", node.Name, node.Network)
}
if err := mq.PublishEventToDynSecTopic(event); err != nil {
logger.Log(0, fmt.Sprintf("failed to send DynSec command [%v]: %v",
event.Commands, err.Error()))
}
}
}

View file

@ -54,7 +54,7 @@ func DeleteNetwork(network string) error {
servers, err := GetSortedNetworkServerNodes(network)
if err == nil {
for _, s := range servers {
if err = DeleteNodeByID(&s, true); err != nil {
if err = DeleteNode(&s, true); err != nil {
logger.Log(2, "could not removed server", s.Name, "before deleting network", network)
} else {
logger.Log(2, "removed server", s.Name, "before deleting network", network)

View file

@ -1,6 +1,7 @@
package logic
import (
"context"
"encoding/json"
"errors"
"fmt"
@ -22,8 +23,14 @@ import (
"golang.org/x/crypto/bcrypt"
)
// RELAY_NODE_ERR - error to return if relay node is unfound
const RELAY_NODE_ERR = "could not find relay for node"
const (
// RELAY_NODE_ERR - error to return if relay node is unfound
RELAY_NODE_ERR = "could not find relay for node"
// NodePurgeTime time to wait for node to response to a NODE_DELETE actions
NodePurgeTime = time.Second * 10
// NodePurgeCheckTime is how often to check nodes for Pending Delete
NodePurgeCheckTime = time.Second * 30
)
// GetNetworkNodes - gets the nodes of a network
func GetNetworkNodes(network string) ([]models.Node, error) {
@ -160,8 +167,31 @@ func UpdateNode(currentNode *models.Node, newNode *models.Node) error {
return fmt.Errorf("failed to update node " + currentNode.ID + ", cannot change ID.")
}
// DeleteNodeByID - deletes a node from database or moves into delete nodes table
func DeleteNodeByID(node *models.Node, exterminate bool) error {
// DeleteNode - marks node for deletion if called by UI or deletes node if called by node
func DeleteNode(node *models.Node, purge bool) error {
if !purge {
newnode := node
newnode.PendingDelete = true
newnode.Action = models.NODE_DELETE
if err := UpdateNode(node, newnode); err != nil {
return err
}
return nil
}
if err := DeleteNodeByID(node); err != nil {
return err
}
if servercfg.Is_EE {
if err := EnterpriseResetAllPeersFailovers(node.ID, node.Network); err != nil {
logger.Log(0, "failed to reset failover lists during node delete for node", node.Name, node.Network)
}
}
return nil
}
// DeleteNodeByID - deletes a node from database
func DeleteNodeByID(node *models.Node) error {
var err error
var key = node.ID
//delete any ext clients as required
@ -170,27 +200,11 @@ func DeleteNodeByID(node *models.Node, exterminate bool) error {
logger.Log(0, "failed to deleted ext clients", err.Error())
}
}
if !exterminate {
node.Action = models.NODE_DELETE
nodedata, err := json.Marshal(&node)
if err != nil {
return err
}
err = database.Insert(key, string(nodedata), database.DELETED_NODES_TABLE_NAME)
if err != nil {
return err
}
} else {
if err := database.DeleteRecord(database.DELETED_NODES_TABLE_NAME, key); err != nil {
logger.Log(2, err.Error())
}
}
if err = database.DeleteRecord(database.NODES_TABLE_NAME, key); err != nil {
if !database.IsEmptyRecord(err) {
return err
}
}
if servercfg.IsDNSMode() {
SetDNS()
}
@ -200,7 +214,6 @@ func DeleteNodeByID(node *models.Node, exterminate bool) error {
logger.Log(0, "failed to dissasociate", node.OwnerID, "from node", node.ID, ":", err.Error())
}
}
_, err = nodeacls.RemoveNodeACL(nodeacls.NetworkID(node.Network), nodeacls.NodeID(node.ID))
if err != nil {
// ignoring for now, could hit a nil pointer if delete called twice
@ -210,11 +223,9 @@ func DeleteNodeByID(node *models.Node, exterminate bool) error {
if err = DeleteMetrics(node.ID); err != nil {
logger.Log(1, "unable to remove metrics from DB for node", node.ID, err.Error())
}
if node.IsServer == "yes" {
return removeLocalServer(node)
}
return nil
}
@ -773,4 +784,34 @@ func updateProNodeACLS(node *models.Node) error {
return nil
}
func PurgePendingNodes(ctx context.Context) {
ticker := time.NewTicker(NodePurgeCheckTime)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
nodes, err := GetAllNodes()
if err != nil {
logger.Log(0, "PurgePendingNodes failed to retrieve nodes", err.Error())
continue
}
for _, node := range nodes {
if node.PendingDelete {
modified := time.Unix(node.LastModified, 0)
if time.Since(modified) > NodePurgeTime {
if err := DeleteNode(&node, true); err != nil {
logger.Log(0, "failed to purge node", node.ID, err.Error())
} else {
logger.Log(0, "purged node ", node.ID)
}
}
}
}
}
}
}
// == END PRO ==

View file

@ -193,7 +193,7 @@ func ServerUpdate(serverNode *models.Node, ifaceDelta bool) error {
var err = ServerPull(serverNode, ifaceDelta)
if isDeleteError(err) {
return DeleteNodeByID(serverNode, true)
return DeleteNode(serverNode, true)
} else if err != nil && !ifaceDelta {
err = ServerPull(serverNode, true)
if err != nil {
@ -224,7 +224,7 @@ func checkNodeActions(node *models.Node) string {
}
}
if node.Action == models.NODE_DELETE {
err := DeleteNodeByID(node, true)
err := DeleteNode(node, true)
if err != nil {
logger.Log(1, "error deleting locally:", err.Error())
}

View file

@ -74,7 +74,7 @@ func ManageZombies(ctx context.Context) {
continue
}
if time.Since(time.Unix(node.LastCheckIn, 0)) > time.Minute*ZOMBIE_DELETE_TIME {
if err := DeleteNodeByID(&node, true); err != nil {
if err := DeleteNode(&node, true); err != nil {
logger.Log(1, "error deleting zombie node", zombies[i], err.Error())
continue
}

View file

@ -184,6 +184,7 @@ func runMessageQueue(wg *sync.WaitGroup) {
ctx, cancel := context.WithCancel(context.Background())
go mq.Keepalive(ctx)
go logic.ManageZombies(ctx)
go logic.PurgePendingNodes(ctx)
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGTERM, os.Interrupt)
<-quit

View file

@ -103,6 +103,7 @@ type Node struct {
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"`
PendingDelete bool `json:"pendingdelete" bson:"pendingdelete" yaml:"pendingdelete"`
// == 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"`