mirror of
https://github.com/gravitl/netmaker.git
synced 2025-09-26 21:01:32 +08:00
NET-1933: option to force destroy network (#3311)
* option to force destroy network * fix network tests * fix network defaults func * fix network destroy action * delete network if node count is zero * push peer update network deletion * send node update
This commit is contained in:
@@ -594,7 +594,7 @@ func deleteHostFromNetwork(w http.ResponseWriter, r *http.Request) {
|
|||||||
w,
|
w,
|
||||||
r,
|
r,
|
||||||
logic.FormatError(
|
logic.FormatError(
|
||||||
fmt.Errorf("failed to force delete daemon node: "+err.Error()),
|
fmt.Errorf("failed to force delete daemon node: %s", err.Error()),
|
||||||
"internal",
|
"internal",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -634,7 +634,7 @@ func deleteHostFromNetwork(w http.ResponseWriter, r *http.Request) {
|
|||||||
w,
|
w,
|
||||||
r,
|
r,
|
||||||
logic.FormatError(
|
logic.FormatError(
|
||||||
fmt.Errorf("failed to force delete daemon node: "+err.Error()),
|
fmt.Errorf("failed to force delete daemon node: %s", err.Error()),
|
||||||
"internal",
|
"internal",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@@ -434,6 +434,7 @@ func getNetworkACL(w http.ResponseWriter, r *http.Request) {
|
|||||||
// @Tags Networks
|
// @Tags Networks
|
||||||
// @Security oauth
|
// @Security oauth
|
||||||
// @Param networkname path string true "Network name"
|
// @Param networkname path string true "Network name"
|
||||||
|
// @Param force query bool false "Force Delete"
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} models.SuccessResponse
|
// @Success 200 {object} models.SuccessResponse
|
||||||
// @Failure 400 {object} models.ErrorResponse
|
// @Failure 400 {object} models.ErrorResponse
|
||||||
@@ -441,10 +442,18 @@ func getNetworkACL(w http.ResponseWriter, r *http.Request) {
|
|||||||
func deleteNetwork(w http.ResponseWriter, r *http.Request) {
|
func deleteNetwork(w http.ResponseWriter, r *http.Request) {
|
||||||
// Set header
|
// Set header
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
force := r.URL.Query().Get("force") == "true"
|
||||||
var params = mux.Vars(r)
|
var params = mux.Vars(r)
|
||||||
network := params["networkname"]
|
network := params["networkname"]
|
||||||
err := logic.DeleteNetwork(network)
|
doneCh := make(chan struct{}, 1)
|
||||||
|
networkNodes, err := logic.GetNetworkNodes(network)
|
||||||
|
if err != nil {
|
||||||
|
logger.Log(0, r.Header.Get("user"),
|
||||||
|
fmt.Sprintf("failed to get network nodes [%s]: %v", network, err))
|
||||||
|
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = logic.DeleteNetwork(network, force, doneCh)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errtype := "badrequest"
|
errtype := "badrequest"
|
||||||
if strings.Contains(err.Error(), "Node check failed") {
|
if strings.Contains(err.Error(), "Node check failed") {
|
||||||
@@ -459,7 +468,22 @@ func deleteNetwork(w http.ResponseWriter, r *http.Request) {
|
|||||||
go logic.DeleteDefaultNetworkPolicies(models.NetworkID(network))
|
go logic.DeleteDefaultNetworkPolicies(models.NetworkID(network))
|
||||||
//delete network from allocated ip map
|
//delete network from allocated ip map
|
||||||
go logic.RemoveNetworkFromAllocatedIpMap(network)
|
go logic.RemoveNetworkFromAllocatedIpMap(network)
|
||||||
|
go func() {
|
||||||
|
<-doneCh
|
||||||
|
mq.PublishPeerUpdate(true)
|
||||||
|
// send node update to clean up locally
|
||||||
|
for _, node := range networkNodes {
|
||||||
|
node := node
|
||||||
|
node.PendingDelete = true
|
||||||
|
node.Action = models.NODE_DELETE
|
||||||
|
if err := mq.NodeUpdate(&node); err != nil {
|
||||||
|
slog.Error("error publishing node update to node", "node", node.ID, "error", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if servercfg.IsDNSMode() {
|
||||||
|
logic.SetDNS()
|
||||||
|
}
|
||||||
|
}()
|
||||||
logger.Log(1, r.Header.Get("user"), "deleted network", network)
|
logger.Log(1, r.Header.Get("user"), "deleted network", network)
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
json.NewEncoder(w).Encode("success")
|
json.NewEncoder(w).Encode("success")
|
||||||
|
@@ -75,11 +75,19 @@ func TestDeleteNetwork(t *testing.T) {
|
|||||||
t.Run("NetworkwithNodes", func(t *testing.T) {
|
t.Run("NetworkwithNodes", func(t *testing.T) {
|
||||||
})
|
})
|
||||||
t.Run("DeleteExistingNetwork", func(t *testing.T) {
|
t.Run("DeleteExistingNetwork", func(t *testing.T) {
|
||||||
err := logic.DeleteNetwork("skynet")
|
doneCh := make(chan struct{}, 1)
|
||||||
|
err := logic.DeleteNetwork("skynet", false, doneCh)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
})
|
})
|
||||||
t.Run("NonExistentNetwork", func(t *testing.T) {
|
t.Run("NonExistentNetwork", func(t *testing.T) {
|
||||||
err := logic.DeleteNetwork("skynet")
|
doneCh := make(chan struct{}, 1)
|
||||||
|
err := logic.DeleteNetwork("skynet", false, doneCh)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
})
|
||||||
|
createNetv1("test")
|
||||||
|
t.Run("ForceDeleteNetwork", func(t *testing.T) {
|
||||||
|
doneCh := make(chan struct{}, 1)
|
||||||
|
err := logic.DeleteNetwork("test", true, doneCh)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -214,6 +222,15 @@ func createNet() {
|
|||||||
logic.CreateNetwork(network)
|
logic.CreateNetwork(network)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
func createNetv1(netId string) {
|
||||||
|
var network models.Network
|
||||||
|
network.NetID = netId
|
||||||
|
network.AddressRange = "100.0.0.1/24"
|
||||||
|
_, err := logic.GetNetwork(netId)
|
||||||
|
if err != nil {
|
||||||
|
logic.CreateNetwork(network)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func createNetDualStack() {
|
func createNetDualStack() {
|
||||||
var network models.Network
|
var network models.Network
|
||||||
|
@@ -102,7 +102,7 @@ func RemoveIpFromAllocatedIpMap(networkName string, ip string) {
|
|||||||
// AddNetworkToAllocatedIpMap - add network to allocated ip map when network is added
|
// AddNetworkToAllocatedIpMap - add network to allocated ip map when network is added
|
||||||
func AddNetworkToAllocatedIpMap(networkName string) {
|
func AddNetworkToAllocatedIpMap(networkName string) {
|
||||||
networkCacheMutex.Lock()
|
networkCacheMutex.Lock()
|
||||||
allocatedIpMap[networkName] = map[string]net.IP{}
|
allocatedIpMap[networkName] = make(map[string]net.IP)
|
||||||
networkCacheMutex.Unlock()
|
networkCacheMutex.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,23 +171,8 @@ func GetNetworks() ([]models.Network, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DeleteNetwork - deletes a network
|
// DeleteNetwork - deletes a network
|
||||||
func DeleteNetwork(network string) error {
|
func DeleteNetwork(network string, force bool, done chan struct{}) error {
|
||||||
// remove ACL for network
|
|
||||||
err := nodeacls.DeleteACLContainer(nodeacls.NetworkID(network))
|
|
||||||
if err != nil {
|
|
||||||
logger.Log(1, "failed to remove the node acls during network delete for network,", network)
|
|
||||||
}
|
|
||||||
// Delete default network enrollment key
|
|
||||||
keys, _ := GetAllEnrollmentKeys()
|
|
||||||
for _, key := range keys {
|
|
||||||
if key.Tags[0] == network {
|
|
||||||
if key.Default {
|
|
||||||
DeleteEnrollmentKey(key.Value, true)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
nodeCount, err := GetNetworkNonServerNodeCount(network)
|
nodeCount, err := GetNetworkNonServerNodeCount(network)
|
||||||
if nodeCount == 0 || database.IsEmptyRecord(err) {
|
if nodeCount == 0 || database.IsEmptyRecord(err) {
|
||||||
// delete server nodes first then db records
|
// delete server nodes first then db records
|
||||||
@@ -200,7 +185,50 @@ func DeleteNetwork(network string) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return errors.New("node check failed. All nodes must be deleted before deleting network")
|
|
||||||
|
// Remove All Nodes
|
||||||
|
go func() {
|
||||||
|
nodes, err := GetNetworkNodes(network)
|
||||||
|
if err == nil {
|
||||||
|
for _, node := range nodes {
|
||||||
|
node := node
|
||||||
|
host, err := GetHost(node.HostID.String())
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
DissasociateNodeFromHost(&node, host)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// remove ACL for network
|
||||||
|
err = nodeacls.DeleteACLContainer(nodeacls.NetworkID(network))
|
||||||
|
if err != nil {
|
||||||
|
logger.Log(1, "failed to remove the node acls during network delete for network,", network)
|
||||||
|
}
|
||||||
|
// delete server nodes first then db records
|
||||||
|
err = database.DeleteRecord(database.NETWORKS_TABLE_NAME, network)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if servercfg.CacheEnabled() {
|
||||||
|
deleteNetworkFromCache(network)
|
||||||
|
}
|
||||||
|
done <- struct{}{}
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Delete default network enrollment key
|
||||||
|
keys, _ := GetAllEnrollmentKeys()
|
||||||
|
for _, key := range keys {
|
||||||
|
if key.Tags[0] == network {
|
||||||
|
if key.Default {
|
||||||
|
DeleteEnrollmentKey(key.Value, true)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateNetwork - creates a network in database
|
// CreateNetwork - creates a network in database
|
||||||
|
@@ -239,7 +239,7 @@ func UpdateNode(currentNode *models.Node, newNode *models.Node) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Errorf("failed to update node " + currentNode.ID.String() + ", cannot change ID.")
|
return fmt.Errorf("failed to update node %s, cannot change ID", currentNode.ID.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteNode - marks node for deletion (and adds to zombie list) if called by UI or deletes node if called by node
|
// DeleteNode - marks node for deletion (and adds to zombie list) if called by UI or deletes node if called by node
|
||||||
|
@@ -42,9 +42,10 @@ func (network *Network) SetNetworkLastModified() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Network.SetDefaults - sets default values for a network struct
|
// Network.SetDefaults - sets default values for a network struct
|
||||||
func (network *Network) SetDefaults() {
|
func (network *Network) SetDefaults() (upsert bool) {
|
||||||
if network.DefaultUDPHolePunch == "" {
|
if network.DefaultUDPHolePunch == "" {
|
||||||
network.DefaultUDPHolePunch = "no"
|
network.DefaultUDPHolePunch = "no"
|
||||||
|
upsert = true
|
||||||
}
|
}
|
||||||
if network.DefaultInterface == "" {
|
if network.DefaultInterface == "" {
|
||||||
if len(network.NetID) < 33 {
|
if len(network.NetID) < 33 {
|
||||||
@@ -52,35 +53,45 @@ func (network *Network) SetDefaults() {
|
|||||||
} else {
|
} else {
|
||||||
network.DefaultInterface = network.NetID
|
network.DefaultInterface = network.NetID
|
||||||
}
|
}
|
||||||
|
upsert = true
|
||||||
}
|
}
|
||||||
if network.DefaultListenPort == 0 {
|
if network.DefaultListenPort == 0 {
|
||||||
network.DefaultListenPort = 51821
|
network.DefaultListenPort = 51821
|
||||||
|
upsert = true
|
||||||
}
|
}
|
||||||
if network.NodeLimit == 0 {
|
if network.NodeLimit == 0 {
|
||||||
network.NodeLimit = 999999999
|
network.NodeLimit = 999999999
|
||||||
|
upsert = true
|
||||||
}
|
}
|
||||||
if network.DefaultKeepalive == 0 {
|
if network.DefaultKeepalive == 0 {
|
||||||
network.DefaultKeepalive = 20
|
network.DefaultKeepalive = 20
|
||||||
|
upsert = true
|
||||||
}
|
}
|
||||||
if network.AllowManualSignUp == "" {
|
if network.AllowManualSignUp == "" {
|
||||||
network.AllowManualSignUp = "no"
|
network.AllowManualSignUp = "no"
|
||||||
|
upsert = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if network.IsIPv4 == "" {
|
if network.IsIPv4 == "" {
|
||||||
network.IsIPv4 = "yes"
|
network.IsIPv4 = "yes"
|
||||||
|
upsert = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if network.IsIPv6 == "" {
|
if network.IsIPv6 == "" {
|
||||||
network.IsIPv6 = "no"
|
network.IsIPv6 = "no"
|
||||||
|
upsert = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if network.DefaultMTU == 0 {
|
if network.DefaultMTU == 0 {
|
||||||
network.DefaultMTU = 1280
|
network.DefaultMTU = 1280
|
||||||
|
upsert = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if network.DefaultACL == "" {
|
if network.DefaultACL == "" {
|
||||||
network.DefaultACL = "yes"
|
network.DefaultACL = "yes"
|
||||||
|
upsert = true
|
||||||
}
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (network *Network) GetNetworkNetworkCIDR4() *net.IPNet {
|
func (network *Network) GetNetworkNetworkCIDR4() *net.IPNet {
|
||||||
|
@@ -59,32 +59,8 @@ func setNetworkDefaults() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, network := range networks {
|
for _, network := range networks {
|
||||||
update := false
|
if network.SetDefaults() {
|
||||||
newNet := network
|
logic.SaveNetwork(&network)
|
||||||
if strings.Contains(network.NetID, ".") {
|
|
||||||
newNet.NetID = strings.ReplaceAll(network.NetID, ".", "")
|
|
||||||
newNet.DefaultInterface = strings.ReplaceAll(network.DefaultInterface, ".", "")
|
|
||||||
update = true
|
|
||||||
}
|
|
||||||
if strings.ContainsAny(network.NetID, "ABCDEFGHIJKLMNOPQRSTUVWXYZ") {
|
|
||||||
newNet.NetID = strings.ToLower(network.NetID)
|
|
||||||
newNet.DefaultInterface = strings.ToLower(network.DefaultInterface)
|
|
||||||
update = true
|
|
||||||
}
|
|
||||||
if update {
|
|
||||||
newNet.SetDefaults()
|
|
||||||
if err := logic.SaveNetwork(&newNet); err != nil {
|
|
||||||
logger.Log(0, "error saving networks during initial update:", err.Error())
|
|
||||||
}
|
|
||||||
if err := logic.DeleteNetwork(network.NetID); err != nil {
|
|
||||||
logger.Log(0, "error deleting old network:", err.Error())
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
network.SetDefaults()
|
|
||||||
_, _, _, err = logic.UpdateNetwork(&network, &network)
|
|
||||||
if err != nil {
|
|
||||||
logger.Log(0, "could not set defaults on network", network.NetID)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
Reference in New Issue
Block a user