[lxc-devel] [lxd/master] Network: Adds support adding nodes to clusters that have OVN networks

tomponline on Github lxc-bot at linuxcontainers.org
Wed Aug 26 13:56:08 UTC 2020


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 2709 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20200826/8443b8b6/attachment-0001.bin>
-------------- next part --------------
From 4a1c3e61f862aef59c59baaae9f63faee5f4d176 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 26 Aug 2020 14:29:42 +0100
Subject: [PATCH 01/15] lxd/network/driver/ovn: Makes ping test in
 startParentPortBridge async

No need to delay LXD startup.

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/network/driver_ovn.go | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/lxd/network/driver_ovn.go b/lxd/network/driver_ovn.go
index 1c6d914674..29174efff7 100644
--- a/lxd/network/driver_ovn.go
+++ b/lxd/network/driver_ovn.go
@@ -591,7 +591,7 @@ func (n *ovn) startParentPortBridge(parentNet Network) error {
 		// wouldn't work until the next router advertisement was sent (which could be several minutes).
 		// By pinging the OVN router's external IP this will trigger an NDP request from the parent bridge
 		// which will cause the OVN router to learn its MAC address.
-		func() {
+		go func() {
 			// Try several attempts as it can take a few seconds for the network to come up.
 			for i := 0; i < 5; i++ {
 				if pingIP(routerExtPortIPv6) {
@@ -602,7 +602,9 @@ func (n *ovn) startParentPortBridge(parentNet Network) error {
 				time.Sleep(time.Second)
 			}
 
-			n.logger.Warn("OVN router external IPv6 address unreachable", log.Ctx{"ip": routerExtPortIPv6.String()})
+			// We would expect this on a chassis node that isn't the active router gateway, it doesn't
+			// always indicate a problem.
+			n.logger.Debug("OVN router external IPv6 address unreachable", log.Ctx{"ip": routerExtPortIPv6.String()})
 		}()
 	}
 

From 8313ca2000d1b28eab17a06ed7e4fa1e2483e67f Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 26 Aug 2020 11:41:20 +0100
Subject: [PATCH 02/15] lxd/init: Updates initDataNodeApply to use revert
 package and to revert itself on error

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/init.go | 74 +++++++++++++++++++----------------------------------
 1 file changed, 27 insertions(+), 47 deletions(-)

diff --git a/lxd/init.go b/lxd/init.go
index ba961a5b85..ca599d459d 100644
--- a/lxd/init.go
+++ b/lxd/init.go
@@ -3,10 +3,12 @@ package main
 import (
 	"fmt"
 
+	"github.com/pkg/errors"
+
 	lxd "github.com/lxc/lxd/client"
+	"github.com/lxc/lxd/lxd/revert"
 	"github.com/lxc/lxd/shared"
 	"github.com/lxc/lxd/shared/api"
-	"github.com/pkg/errors"
 )
 
 type initDataNode struct {
@@ -26,34 +28,26 @@ type initDataCluster struct {
 // It's used both by the 'lxd init' command and by the PUT /1.0/cluster API.
 //
 // In case of error, the returned function can be used to revert the changes.
-func initDataNodeApply(d lxd.InstanceServer, config initDataNode) (func(), error) {
-	// Handle reverts
-	reverts := []func(){}
-	revert := func() {
-		// Lets undo things in reverse order
-		for i := len(reverts) - 1; i >= 0; i-- {
-			reverts[i]()
-		}
-	}
+func initDataNodeApply(d lxd.InstanceServer, config initDataNode) error {
+	revert := revert.New()
+	defer revert.Fail()
 
 	// Apply server configuration
 	if config.Config != nil && len(config.Config) > 0 {
 		// Get current config
 		currentServer, etag, err := d.GetServer()
 		if err != nil {
-			return revert, errors.Wrap(err, "Failed to retrieve current server configuration")
+			return errors.Wrap(err, "Failed to retrieve current server configuration")
 		}
 
 		// Setup reverter
-		reverts = append(reverts, func() {
-			d.UpdateServer(currentServer.Writable(), "")
-		})
+		revert.Add(func() { d.UpdateServer(currentServer.Writable(), "") })
 
 		// Prepare the update
 		newServer := api.ServerPut{}
 		err = shared.DeepCopy(currentServer.Writable(), &newServer)
 		if err != nil {
-			return revert, errors.Wrap(err, "Failed to copy server configuration")
+			return errors.Wrap(err, "Failed to copy server configuration")
 		}
 
 		for k, v := range config.Config {
@@ -63,7 +57,7 @@ func initDataNodeApply(d lxd.InstanceServer, config initDataNode) (func(), error
 		// Apply it
 		err = d.UpdateServer(newServer, etag)
 		if err != nil {
-			return revert, errors.Wrap(err, "Failed to update server configuration")
+			return errors.Wrap(err, "Failed to update server configuration")
 		}
 	}
 
@@ -72,7 +66,7 @@ func initDataNodeApply(d lxd.InstanceServer, config initDataNode) (func(), error
 		// Get the list of networks
 		networkNames, err := d.GetNetworkNames()
 		if err != nil {
-			return revert, errors.Wrap(err, "Failed to retrieve list of networks")
+			return errors.Wrap(err, "Failed to retrieve list of networks")
 		}
 
 		// Network creator
@@ -84,10 +78,7 @@ func initDataNodeApply(d lxd.InstanceServer, config initDataNode) (func(), error
 			}
 
 			// Setup reverter
-			reverts = append(reverts, func() {
-				d.DeleteNetwork(network.Name)
-			})
-
+			revert.Add(func() { d.DeleteNetwork(network.Name) })
 			return nil
 		}
 
@@ -100,9 +91,7 @@ func initDataNodeApply(d lxd.InstanceServer, config initDataNode) (func(), error
 			}
 
 			// Setup reverter
-			reverts = append(reverts, func() {
-				d.UpdateNetwork(currentNetwork.Name, currentNetwork.Writable(), "")
-			})
+			revert.Add(func() { d.UpdateNetwork(currentNetwork.Name, currentNetwork.Writable(), "") })
 
 			// Prepare the update
 			newNetwork := api.NetworkPut{}
@@ -135,7 +124,7 @@ func initDataNodeApply(d lxd.InstanceServer, config initDataNode) (func(), error
 			if !shared.StringInSlice(network.Name, networkNames) {
 				err := createNetwork(network)
 				if err != nil {
-					return revert, err
+					return err
 				}
 
 				continue
@@ -144,7 +133,7 @@ func initDataNodeApply(d lxd.InstanceServer, config initDataNode) (func(), error
 			// Existing network
 			err := updateNetwork(network)
 			if err != nil {
-				return revert, err
+				return err
 			}
 		}
 	}
@@ -154,7 +143,7 @@ func initDataNodeApply(d lxd.InstanceServer, config initDataNode) (func(), error
 		// Get the list of storagePools
 		storagePoolNames, err := d.GetStoragePoolNames()
 		if err != nil {
-			return revert, errors.Wrap(err, "Failed to retrieve list of storage pools")
+			return errors.Wrap(err, "Failed to retrieve list of storage pools")
 		}
 
 		// StoragePool creator
@@ -166,10 +155,7 @@ func initDataNodeApply(d lxd.InstanceServer, config initDataNode) (func(), error
 			}
 
 			// Setup reverter
-			reverts = append(reverts, func() {
-				d.DeleteStoragePool(storagePool.Name)
-			})
-
+			revert.Add(func() { d.DeleteStoragePool(storagePool.Name) })
 			return nil
 		}
 
@@ -187,9 +173,7 @@ func initDataNodeApply(d lxd.InstanceServer, config initDataNode) (func(), error
 			}
 
 			// Setup reverter
-			reverts = append(reverts, func() {
-				d.UpdateStoragePool(currentStoragePool.Name, currentStoragePool.Writable(), "")
-			})
+			revert.Add(func() { d.UpdateStoragePool(currentStoragePool.Name, currentStoragePool.Writable(), "") })
 
 			// Prepare the update
 			newStoragePool := api.StoragePoolPut{}
@@ -222,7 +206,7 @@ func initDataNodeApply(d lxd.InstanceServer, config initDataNode) (func(), error
 			if !shared.StringInSlice(storagePool.Name, storagePoolNames) {
 				err := createStoragePool(storagePool)
 				if err != nil {
-					return revert, err
+					return err
 				}
 
 				continue
@@ -231,7 +215,7 @@ func initDataNodeApply(d lxd.InstanceServer, config initDataNode) (func(), error
 			// Existing storagePool
 			err := updateStoragePool(storagePool)
 			if err != nil {
-				return revert, err
+				return err
 			}
 		}
 	}
@@ -241,7 +225,7 @@ func initDataNodeApply(d lxd.InstanceServer, config initDataNode) (func(), error
 		// Get the list of profiles
 		profileNames, err := d.GetProfileNames()
 		if err != nil {
-			return revert, errors.Wrap(err, "Failed to retrieve list of profiles")
+			return errors.Wrap(err, "Failed to retrieve list of profiles")
 		}
 
 		// Profile creator
@@ -253,10 +237,7 @@ func initDataNodeApply(d lxd.InstanceServer, config initDataNode) (func(), error
 			}
 
 			// Setup reverter
-			reverts = append(reverts, func() {
-				d.DeleteProfile(profile.Name)
-			})
-
+			revert.Add(func() { d.DeleteProfile(profile.Name) })
 			return nil
 		}
 
@@ -269,9 +250,7 @@ func initDataNodeApply(d lxd.InstanceServer, config initDataNode) (func(), error
 			}
 
 			// Setup reverter
-			reverts = append(reverts, func() {
-				d.UpdateProfile(currentProfile.Name, currentProfile.Writable(), "")
-			})
+			revert.Add(func() { d.UpdateProfile(currentProfile.Name, currentProfile.Writable(), "") })
 
 			// Prepare the update
 			newProfile := api.ProfilePut{}
@@ -319,7 +298,7 @@ func initDataNodeApply(d lxd.InstanceServer, config initDataNode) (func(), error
 			if !shared.StringInSlice(profile.Name, profileNames) {
 				err := createProfile(profile)
 				if err != nil {
-					return revert, err
+					return err
 				}
 
 				continue
@@ -328,12 +307,13 @@ func initDataNodeApply(d lxd.InstanceServer, config initDataNode) (func(), error
 			// Existing profile
 			err := updateProfile(profile)
 			if err != nil {
-				return revert, err
+				return err
 			}
 		}
 	}
 
-	return nil, nil
+	revert.Success()
+	return nil
 }
 
 // Helper to initialize LXD clustering.

From 6127ed7e543590e5ffaa00d431010c7a49851c28 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 26 Aug 2020 11:40:19 +0100
Subject: [PATCH 03/15] lxd/cluster/connect: Adds UserAgentNotifier constant

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/cluster/connect.go | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/lxd/cluster/connect.go b/lxd/cluster/connect.go
index 4773d7e354..bce7206595 100644
--- a/lxd/cluster/connect.go
+++ b/lxd/cluster/connect.go
@@ -18,11 +18,15 @@ import (
 	"github.com/lxc/lxd/shared/version"
 )
 
+// UserAgentNotifier used to distinguish between a regular client request and an internal cluster request when
+// notifying other nodes of a cluster change.
+const UserAgentNotifier = "lxd-cluster-notifier"
+
 // Connect is a convenience around lxd.ConnectLXD that configures the client
 // with the correct parameters for node-to-node communication.
 //
 // If 'notify' switch is true, then the user agent will be set to the special
-// value 'lxd-cluster-notifier', which can be used in some cases to distinguish
+// to the UserAgentNotifier value, which can be used in some cases to distinguish
 // between a regular client request and an internal cluster request.
 func Connect(address string, cert *shared.CertInfo, notify bool) (lxd.InstanceServer, error) {
 	// Wait for a connection to the events API first for non-notify connections.
@@ -54,7 +58,7 @@ func Connect(address string, cert *shared.CertInfo, notify bool) (lxd.InstanceSe
 		UserAgent:     version.UserAgent,
 	}
 	if notify {
-		args.UserAgent = "lxd-cluster-notifier"
+		args.UserAgent = UserAgentNotifier
 	}
 
 	url := fmt.Sprintf("https://%s", address)

From 6f2c50c072fadea92baf8be2cb72f2f95bf645cb Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 26 Aug 2020 11:44:18 +0100
Subject: [PATCH 04/15] lxd/cluster/connect: Adds UserAgentJoiner constant

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/cluster/connect.go | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/lxd/cluster/connect.go b/lxd/cluster/connect.go
index bce7206595..523264bb6b 100644
--- a/lxd/cluster/connect.go
+++ b/lxd/cluster/connect.go
@@ -22,6 +22,10 @@ import (
 // notifying other nodes of a cluster change.
 const UserAgentNotifier = "lxd-cluster-notifier"
 
+// UserAgentJoiner used to distinguish between a regular client request and an internal cluster request when
+// joining a node to a cluster.
+const UserAgentJoiner = "lxd-cluster-joiner"
+
 // Connect is a convenience around lxd.ConnectLXD that configures the client
 // with the correct parameters for node-to-node communication.
 //

From ac1dffda59deba257c4ca6daee47314cca1d27d9 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 26 Aug 2020 14:25:53 +0100
Subject: [PATCH 05/15] lxd/cluster/connect: Adds ClientType type and
 UserAgentClientType function

 - Defines client type constants for normal, notifier and joiner types.
 - Adds a function UserAgentClientType for converting client user agent to client type.

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/cluster/connect.go | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/lxd/cluster/connect.go b/lxd/cluster/connect.go
index 523264bb6b..7ed1dd0773 100644
--- a/lxd/cluster/connect.go
+++ b/lxd/cluster/connect.go
@@ -26,6 +26,30 @@ const UserAgentNotifier = "lxd-cluster-notifier"
 // joining a node to a cluster.
 const UserAgentJoiner = "lxd-cluster-joiner"
 
+// ClientType indicates which sort of client type is being used.
+type ClientType string
+
+// ClientTypeNotifier cluster notification client.
+const ClientTypeNotifier ClientType = "notifier"
+
+// ClientTypeJoiner cluster joiner client.
+const ClientTypeJoiner ClientType = "joiner"
+
+// ClientTypeNormal normal client.
+const ClientTypeNormal ClientType = "normal"
+
+// UserAgentClientType converts user agent to client type.
+func UserAgentClientType(userAgent string) ClientType {
+	switch userAgent {
+	case UserAgentNotifier:
+		return ClientTypeNotifier
+	case UserAgentJoiner:
+		return ClientTypeJoiner
+	}
+
+	return ClientTypeNormal
+}
+
 // Connect is a convenience around lxd.ConnectLXD that configures the client
 // with the correct parameters for node-to-node communication.
 //

From 5c29460f2af4edf8f91c3a4ece1c7bafe04addb5 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 26 Aug 2020 11:40:47 +0100
Subject: [PATCH 06/15] lxd/api: Updates isClusterNotification to use
 cluster.UserAgentNotifier

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/api.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lxd/api.go b/lxd/api.go
index faa0e4ab58..2bdcba49d2 100644
--- a/lxd/api.go
+++ b/lxd/api.go
@@ -118,7 +118,7 @@ func setCORSHeaders(rw http.ResponseWriter, req *http.Request, config *cluster.C
 // notifying us of some user-initiated API request that needs some action to be
 // taken on this node as well.
 func isClusterNotification(r *http.Request) bool {
-	return r.Header.Get("User-Agent") == "lxd-cluster-notifier"
+	return r.Header.Get("User-Agent") == cluster.UserAgentNotifier
 }
 
 // projectParam returns the project query parameter from the given request or "default" if parameter is not set.

From 8292a901f97e5807cfefe86bf1b0e8b794b19597 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 26 Aug 2020 11:42:20 +0100
Subject: [PATCH 07/15] lxd/api/cluster: clusterInitMember comments

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/api_cluster.go | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/lxd/api_cluster.go b/lxd/api_cluster.go
index 32d3e5ac1a..471aaa04e0 100644
--- a/lxd/api_cluster.go
+++ b/lxd/api_cluster.go
@@ -686,11 +686,9 @@ func clusterPutDisable(d *Daemon) response.Response {
 	return response.EmptySyncResponse
 }
 
-// Initialize storage pools and networks on this node.
-//
-// We pass to LXD client instances, one connected to ourselves (the joining
-// node) and one connected to the target cluster node to join.
-func clusterInitMember(d, client lxd.InstanceServer, memberConfig []api.ClusterMemberConfigKey) error {
+// clusterInitMember initialises storage pools and networks on this node. We pass two LXD client instances, one
+// connected to ourselves (the joining node) and one connected to the target cluster node to join.
+func clusterInitMember(d lxd.InstanceServer, client lxd.InstanceServer, memberConfig []api.ClusterMemberConfigKey) error {
 	data := initDataNode{}
 
 	// Fetch all pools currently defined in the cluster.

From cffeed2766216e11a0764a354a3e588fd3fe6052 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 26 Aug 2020 11:42:32 +0100
Subject: [PATCH 08/15] lxd/api/cluster: initDataNodeApply usage

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/api_cluster.go | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/lxd/api_cluster.go b/lxd/api_cluster.go
index 471aaa04e0..55a70d059c 100644
--- a/lxd/api_cluster.go
+++ b/lxd/api_cluster.go
@@ -785,9 +785,8 @@ func clusterInitMember(d lxd.InstanceServer, client lxd.InstanceServer, memberCo
 		data.Networks = append(data.Networks, post)
 	}
 
-	revert, err := initDataNodeApply(d, data)
+	err = initDataNodeApply(d, data)
 	if err != nil {
-		revert()
 		return errors.Wrap(err, "Failed to initialize storage pools and networks")
 	}
 

From 913140ecdbc5de420e841fe19b8e20459bbba2ec Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 26 Aug 2020 11:42:47 +0100
Subject: [PATCH 09/15] lxd/main/init: initDataNodeApply usage

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/main_init.go | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/lxd/main_init.go b/lxd/main_init.go
index 62047c8f91..eef6d370bc 100644
--- a/lxd/main_init.go
+++ b/lxd/main_init.go
@@ -149,9 +149,8 @@ func (c *cmdInit) Run(cmd *cobra.Command, args []string) error {
 		return nil
 	}
 
-	revert, err := initDataNodeApply(d, config.Node)
+	err = initDataNodeApply(d, config.Node)
 	if err != nil {
-		revert()
 		return err
 	}
 

From df86ab953d8e03735ccc40607d0131d6224166ed Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 26 Aug 2020 11:44:40 +0100
Subject: [PATCH 10/15] lxd/api/cluster: Updates clusterPutJoin to use
 cluster.UserAgentJoiner when sending requests to local node

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/api_cluster.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lxd/api_cluster.go b/lxd/api_cluster.go
index 55a70d059c..a9345985c4 100644
--- a/lxd/api_cluster.go
+++ b/lxd/api_cluster.go
@@ -386,7 +386,7 @@ func clusterPutJoin(d *Daemon, req api.ClusterPut) response.Response {
 		// As ServerAddress field is required to be set it means that we're using the new join API
 		// introduced with the 'clustering_join' extension.
 		// Connect to ourselves to initialize storage pools and networks using the API.
-		localClient, err := lxd.ConnectLXDUnix(d.UnixSocket(), nil)
+		localClient, err := lxd.ConnectLXDUnix(d.UnixSocket(), &lxd.ConnectionArgs{UserAgent: cluster.UserAgentJoiner})
 		if err != nil {
 			return errors.Wrap(err, "Failed to connect to local LXD")
 		}

From 585095fb70407f3dff2f1ffacd8d89dfdd025ff4 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 26 Aug 2020 14:27:18 +0100
Subject: [PATCH 11/15] lxd/network/network/interfaces: Replaces
 clusterNotification bool with cluster.ClientType

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/network/network_interface.go | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/lxd/network/network_interface.go b/lxd/network/network_interface.go
index dfb9e3b470..69e787a14a 100644
--- a/lxd/network/network_interface.go
+++ b/lxd/network/network_interface.go
@@ -30,11 +30,11 @@ type Network interface {
 	DHCPv6Ranges() []shared.IPRange
 
 	// Actions.
-	Create(clusterNotification bool) error
+	Create(clientType cluster.ClientType) error
 	Start() error
 	Stop() error
 	Rename(name string) error
-	Update(newNetwork api.NetworkPut, targetNode string, clusterNotification bool) error
+	Update(newNetwork api.NetworkPut, targetNode string, clientType cluster.ClientType) error
 	HandleHeartbeat(heartbeatData *cluster.APIHeartbeat) error
-	Delete(clusterNotification bool) error
+	Delete(clientType cluster.ClientType) error
 }

From be3d1bb5426bf73a6bf7dfbf4fec105e39e518ed Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 26 Aug 2020 14:27:53 +0100
Subject: [PATCH 12/15] lxd/network/driver/common: cluster.ClientType usage

And improved logging.

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/network/driver_common.go | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/lxd/network/driver_common.go b/lxd/network/driver_common.go
index 296106b82d..41197225f6 100644
--- a/lxd/network/driver_common.go
+++ b/lxd/network/driver_common.go
@@ -222,14 +222,14 @@ func (n *common) DHCPv6Ranges() []shared.IPRange {
 }
 
 // update the internal config variables, and if not cluster notification, notifies all nodes and updates database.
-func (n *common) update(applyNetwork api.NetworkPut, targetNode string, clusterNotification bool) error {
+func (n *common) update(applyNetwork api.NetworkPut, targetNode string, clientType cluster.ClientType) error {
 	// Update internal config before database has been updated (so that if update is a notification we apply
 	// the config being supplied and not that in the database).
 	n.init(n.state, n.id, n.name, n.netType, applyNetwork.Description, applyNetwork.Config, n.status)
 
 	// If this update isn't coming via a cluster notification itself, then notify all nodes of change and then
 	// update the database.
-	if !clusterNotification {
+	if clientType != cluster.ClientTypeNotifier {
 		if targetNode == "" {
 			// Notify all other nodes to update the network if no target specified.
 			notifier, err := cluster.NewNotifier(n.state, n.state.Endpoints.NetworkCert(), cluster.NotifyAll)
@@ -342,9 +342,9 @@ func (n *common) rename(newName string) error {
 }
 
 // delete the network from the database if clusterNotification is false.
-func (n *common) delete(clusterNotification bool) error {
+func (n *common) delete(clientType cluster.ClientType) error {
 	// Only delete database record if not cluster notification.
-	if !clusterNotification {
+	if clientType != cluster.ClientTypeNotifier {
 		// Notify all other nodes. If any node is down, an error will be returned.
 		notifier, err := cluster.NewNotifier(n.state, n.state.Endpoints.NetworkCert(), cluster.NotifyAll)
 		if err != nil {
@@ -373,7 +373,9 @@ func (n *common) delete(clusterNotification bool) error {
 }
 
 // Create is a no-op.
-func (n *common) Create(clusterNotification bool) error {
+func (n *common) Create(clientType cluster.ClientType) error {
+	n.logger.Debug("Create", log.Ctx{"clientType": clientType, "config": n.config})
+
 	return nil
 }
 

From 03cd073e7d48cbd30445bb1ab1c6fd022074abdb Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 26 Aug 2020 14:28:38 +0100
Subject: [PATCH 13/15] lxd/network/driver: cluster.ClientType usage

And improved logging.

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/network/driver_bridge.go  | 18 +++++++++++-------
 lxd/network/driver_macvlan.go | 19 ++++++++++++-------
 lxd/network/driver_sriov.go   | 19 ++++++++++++-------
 3 files changed, 35 insertions(+), 21 deletions(-)

diff --git a/lxd/network/driver_bridge.go b/lxd/network/driver_bridge.go
index 562fe48280..8ef1e612e4 100644
--- a/lxd/network/driver_bridge.go
+++ b/lxd/network/driver_bridge.go
@@ -384,8 +384,8 @@ func (n *bridge) isRunning() bool {
 }
 
 // Delete deletes a network.
-func (n *bridge) Delete(clusterNotification bool) error {
-	n.logger.Debug("Delete", log.Ctx{"clusterNotification": clusterNotification})
+func (n *bridge) Delete(clientType cluster.ClientType) error {
+	n.logger.Debug("Delete", log.Ctx{"clientType": clientType})
 
 	// Bring the network down.
 	if n.isRunning() {
@@ -401,7 +401,7 @@ func (n *bridge) Delete(clusterNotification bool) error {
 		return err
 	}
 
-	return n.common.delete(clusterNotification)
+	return n.common.delete(clientType)
 }
 
 // Rename renames a network.
@@ -452,6 +452,8 @@ func (n *bridge) Rename(newName string) error {
 
 // Start starts the network.
 func (n *bridge) Start() error {
+	n.logger.Debug("Start")
+
 	return n.setup(nil)
 }
 
@@ -1420,6 +1422,8 @@ func (n *bridge) setup(oldConfig map[string]string) error {
 
 // Stop stops the network.
 func (n *bridge) Stop() error {
+	n.logger.Debug("Stop")
+
 	if !n.isRunning() {
 		return nil
 	}
@@ -1491,8 +1495,8 @@ func (n *bridge) Stop() error {
 
 // Update updates the network. Accepts notification boolean indicating if this update request is coming from a
 // cluster notification, in which case do not update the database, just apply local changes needed.
-func (n *bridge) Update(newNetwork api.NetworkPut, targetNode string, clusterNotification bool) error {
-	n.logger.Debug("Update", log.Ctx{"clusterNotification": clusterNotification, "newNetwork": newNetwork})
+func (n *bridge) Update(newNetwork api.NetworkPut, targetNode string, clientType cluster.ClientType) error {
+	n.logger.Debug("Update", log.Ctx{"clientType": clientType, "newNetwork": newNetwork})
 
 	// Populate default values if they are missing.
 	err := n.fillConfig(newNetwork.Config)
@@ -1515,7 +1519,7 @@ func (n *bridge) Update(newNetwork api.NetworkPut, targetNode string, clusterNot
 	// Define a function which reverts everything.
 	revert.Add(func() {
 		// Reset changes to all nodes and database.
-		n.common.update(oldNetwork, targetNode, clusterNotification)
+		n.common.update(oldNetwork, targetNode, clientType)
 
 		// Reset any change that was made to local bridge.
 		n.setup(newNetwork.Config)
@@ -1553,7 +1557,7 @@ func (n *bridge) Update(newNetwork api.NetworkPut, targetNode string, clusterNot
 	}
 
 	// Apply changes to database.
-	err = n.common.update(newNetwork, targetNode, clusterNotification)
+	err = n.common.update(newNetwork, targetNode, clientType)
 	if err != nil {
 		return err
 	}
diff --git a/lxd/network/driver_macvlan.go b/lxd/network/driver_macvlan.go
index 6195c6c9f0..5798f06c65 100644
--- a/lxd/network/driver_macvlan.go
+++ b/lxd/network/driver_macvlan.go
@@ -3,6 +3,7 @@ package network
 import (
 	"fmt"
 
+	"github.com/lxc/lxd/lxd/cluster"
 	"github.com/lxc/lxd/lxd/revert"
 	"github.com/lxc/lxd/shared/api"
 	log "github.com/lxc/lxd/shared/log15"
@@ -33,9 +34,9 @@ func (n *macvlan) Validate(config map[string]string) error {
 }
 
 // Delete deletes a network.
-func (n *macvlan) Delete(clusterNotification bool) error {
-	n.logger.Debug("Delete", log.Ctx{"clusterNotification": clusterNotification})
-	return n.common.delete(clusterNotification)
+func (n *macvlan) Delete(clientType cluster.ClientType) error {
+	n.logger.Debug("Delete", log.Ctx{"clientType": clientType})
+	return n.common.delete(clientType)
 }
 
 // Rename renames a network.
@@ -63,6 +64,8 @@ func (n *macvlan) Rename(newName string) error {
 
 // Start starts is a no-op.
 func (n *macvlan) Start() error {
+	n.logger.Debug("Start")
+
 	if n.status == api.NetworkStatusPending {
 		return fmt.Errorf("Cannot start pending network")
 	}
@@ -72,13 +75,15 @@ func (n *macvlan) Start() error {
 
 // Stop stops is a no-op.
 func (n *macvlan) Stop() error {
+	n.logger.Debug("Stop")
+
 	return nil
 }
 
 // Update updates the network. Accepts notification boolean indicating if this update request is coming from a
 // cluster notification, in which case do not update the database, just apply local changes needed.
-func (n *macvlan) Update(newNetwork api.NetworkPut, targetNode string, clusterNotification bool) error {
-	n.logger.Debug("Update", log.Ctx{"clusterNotification": clusterNotification, "newNetwork": newNetwork})
+func (n *macvlan) Update(newNetwork api.NetworkPut, targetNode string, clientType cluster.ClientType) error {
+	n.logger.Debug("Update", log.Ctx{"clientType": clientType, "newNetwork": newNetwork})
 
 	dbUpdateNeeeded, _, oldNetwork, err := n.common.configChanged(newNetwork)
 	if err != nil {
@@ -95,11 +100,11 @@ func (n *macvlan) Update(newNetwork api.NetworkPut, targetNode string, clusterNo
 	// Define a function which reverts everything.
 	revert.Add(func() {
 		// Reset changes to all nodes and database.
-		n.common.update(oldNetwork, targetNode, clusterNotification)
+		n.common.update(oldNetwork, targetNode, clientType)
 	})
 
 	// Apply changes to database.
-	err = n.common.update(newNetwork, targetNode, clusterNotification)
+	err = n.common.update(newNetwork, targetNode, clientType)
 	if err != nil {
 		return err
 	}
diff --git a/lxd/network/driver_sriov.go b/lxd/network/driver_sriov.go
index 2f3483ed75..034ede797a 100644
--- a/lxd/network/driver_sriov.go
+++ b/lxd/network/driver_sriov.go
@@ -3,6 +3,7 @@ package network
 import (
 	"fmt"
 
+	"github.com/lxc/lxd/lxd/cluster"
 	"github.com/lxc/lxd/lxd/revert"
 	"github.com/lxc/lxd/shared/api"
 	log "github.com/lxc/lxd/shared/log15"
@@ -33,9 +34,9 @@ func (n *sriov) Validate(config map[string]string) error {
 }
 
 // Delete deletes a network.
-func (n *sriov) Delete(clusterNotification bool) error {
-	n.logger.Debug("Delete", log.Ctx{"clusterNotification": clusterNotification})
-	return n.common.delete(clusterNotification)
+func (n *sriov) Delete(clientType cluster.ClientType) error {
+	n.logger.Debug("Delete", log.Ctx{"clientType": clientType})
+	return n.common.delete(clientType)
 }
 
 // Rename renames a network.
@@ -63,6 +64,8 @@ func (n *sriov) Rename(newName string) error {
 
 // Start starts is a no-op.
 func (n *sriov) Start() error {
+	n.logger.Debug("Start")
+
 	if n.status == api.NetworkStatusPending {
 		return fmt.Errorf("Cannot start pending network")
 	}
@@ -72,13 +75,15 @@ func (n *sriov) Start() error {
 
 // Stop stops is a no-op.
 func (n *sriov) Stop() error {
+	n.logger.Debug("Stop")
+
 	return nil
 }
 
 // Update updates the network. Accepts notification boolean indicating if this update request is coming from a
 // cluster notification, in which case do not update the database, just apply local changes needed.
-func (n *sriov) Update(newNetwork api.NetworkPut, targetNode string, clusterNotification bool) error {
-	n.logger.Debug("Update", log.Ctx{"clusterNotification": clusterNotification, "newNetwork": newNetwork})
+func (n *sriov) Update(newNetwork api.NetworkPut, targetNode string, clientType cluster.ClientType) error {
+	n.logger.Debug("Update", log.Ctx{"clientType": clientType, "newNetwork": newNetwork})
 
 	dbUpdateNeeeded, _, oldNetwork, err := n.common.configChanged(newNetwork)
 	if err != nil {
@@ -95,11 +100,11 @@ func (n *sriov) Update(newNetwork api.NetworkPut, targetNode string, clusterNoti
 	// Define a function which reverts everything.
 	revert.Add(func() {
 		// Reset changes to all nodes and database.
-		n.common.update(oldNetwork, targetNode, clusterNotification)
+		n.common.update(oldNetwork, targetNode, clientType)
 	})
 
 	// Apply changes to database.
-	err = n.common.update(newNetwork, targetNode, clusterNotification)
+	err = n.common.update(newNetwork, targetNode, clientType)
 	if err != nil {
 		return err
 	}

From 0d245ffd733f9ff10adc97d843398dff13a1a7b9 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 26 Aug 2020 14:30:42 +0100
Subject: [PATCH 14/15] lxd/network/driver/ovn: cluster.ClientType usage

 - Differentiates between normal and cluster joiner client type requests and only sets up logical network on normal requests.
 - And improved logging.

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/network/driver_ovn.go | 32 ++++++++++++++++++--------------
 1 file changed, 18 insertions(+), 14 deletions(-)

diff --git a/lxd/network/driver_ovn.go b/lxd/network/driver_ovn.go
index 29174efff7..4066ee366c 100644
--- a/lxd/network/driver_ovn.go
+++ b/lxd/network/driver_ovn.go
@@ -728,11 +728,11 @@ func (n *ovn) fillConfig(config map[string]string) error {
 }
 
 // Create sets up network in OVN Northbound database.
-func (n *ovn) Create(clusterNotification bool) error {
-	n.logger.Debug("Create", log.Ctx{"clusterNotification": clusterNotification, "config": n.config})
+func (n *ovn) Create(clientType cluster.ClientType) error {
+	n.logger.Debug("Create", log.Ctx{"clientType": clientType, "config": n.config})
 
 	// We only need to setup the OVN Northbound database once, not on every clustered node.
-	if !clusterNotification {
+	if clientType == cluster.ClientTypeNormal {
 		err := n.setup(false)
 		if err != nil {
 			return err
@@ -1054,10 +1054,10 @@ func (n *ovn) setup(update bool) error {
 }
 
 // Delete deletes a network.
-func (n *ovn) Delete(clusterNotification bool) error {
-	n.logger.Debug("Delete", log.Ctx{"clusterNotification": clusterNotification})
+func (n *ovn) Delete(clientType cluster.ClientType) error {
+	n.logger.Debug("Delete", log.Ctx{"clientType": clientType})
 
-	if !clusterNotification {
+	if clientType == cluster.ClientTypeNormal {
 		client, err := n.getClient()
 		if err != nil {
 			return err
@@ -1116,7 +1116,7 @@ func (n *ovn) Delete(clusterNotification bool) error {
 		return err
 	}
 
-	return n.common.delete(clusterNotification)
+	return n.common.delete(clientType)
 }
 
 // Rename renames a network.
@@ -1144,6 +1144,8 @@ func (n *ovn) Rename(newName string) error {
 
 // Start starts configures the local OVS parent uplink port.
 func (n *ovn) Start() error {
+	n.logger.Debug("Start")
+
 	if n.status == api.NetworkStatusPending {
 		return fmt.Errorf("Cannot start pending network")
 	}
@@ -1158,13 +1160,15 @@ func (n *ovn) Start() error {
 
 // Stop stops is a no-op.
 func (n *ovn) Stop() error {
+	n.logger.Debug("Stop")
+
 	return nil
 }
 
 // Update updates the network. Accepts notification boolean indicating if this update request is coming from a
 // cluster notification, in which case do not update the database, just apply local changes needed.
-func (n *ovn) Update(newNetwork api.NetworkPut, targetNode string, clusterNotification bool) error {
-	n.logger.Debug("Update", log.Ctx{"clusterNotification": clusterNotification, "newNetwork": newNetwork})
+func (n *ovn) Update(newNetwork api.NetworkPut, targetNode string, clientType cluster.ClientType) error {
+	n.logger.Debug("Update", log.Ctx{"clientType": clientType, "newNetwork": newNetwork})
 
 	// Populate default values if they are missing.
 	err := n.fillConfig(newNetwork.Config)
@@ -1187,22 +1191,22 @@ func (n *ovn) Update(newNetwork api.NetworkPut, targetNode string, clusterNotifi
 	// Define a function which reverts everything.
 	revert.Add(func() {
 		// Reset changes to all nodes and database.
-		n.common.update(oldNetwork, targetNode, clusterNotification)
+		n.common.update(oldNetwork, targetNode, clientType)
 
 		// Reset any change that was made to logical network.
-		if !clusterNotification {
+		if clientType == cluster.ClientTypeNormal {
 			n.setup(true)
 		}
 	})
 
 	// Apply changes to database.
-	err = n.common.update(newNetwork, targetNode, clusterNotification)
+	err = n.common.update(newNetwork, targetNode, clientType)
 	if err != nil {
 		return err
 	}
 
-	// Restart the logical network if needed.
-	if len(changedKeys) > 0 && !clusterNotification {
+	// Re-setup the logical network if needed.
+	if len(changedKeys) > 0 && clientType == cluster.ClientTypeNormal {
 		err = n.setup(true)
 		if err != nil {
 			return err

From 1a2375d6e54d2dfb4fed0ac32fc718e57107621c Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 26 Aug 2020 14:32:54 +0100
Subject: [PATCH 15/15] lxd/networks: cluster.ClientType usage

Replaces cluster notification concept.

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/networks.go | 31 ++++++++++++++++++-------------
 1 file changed, 18 insertions(+), 13 deletions(-)

diff --git a/lxd/networks.go b/lxd/networks.go
index 60bd4a8642..df4f027f33 100644
--- a/lxd/networks.go
+++ b/lxd/networks.go
@@ -142,10 +142,12 @@ func networksPost(d *Daemon, r *http.Request) response.Response {
 	url := fmt.Sprintf("/%s/networks/%s", version.APIVersion, req.Name)
 	resp := response.SyncResponseLocation(true, nil, url)
 
+	clientType := cluster.UserAgentClientType(r.Header.Get("User-Agent"))
+
 	if isClusterNotification(r) {
 		// This is an internal request which triggers the actual creation of the network across all nodes
 		// after they have been previously defined.
-		err = doNetworksCreate(d, req, true)
+		err = doNetworksCreate(d, req, clientType)
 		if err != nil {
 			return response.SmartError(err)
 		}
@@ -181,7 +183,7 @@ func networksPost(d *Daemon, r *http.Request) response.Response {
 	}
 
 	if count > 1 {
-		err = networksPostCluster(d, req)
+		err = networksPostCluster(d, req, clientType)
 		if err != nil {
 			return response.SmartError(err)
 		}
@@ -217,8 +219,7 @@ func networksPost(d *Daemon, r *http.Request) response.Response {
 		d.cluster.DeleteNetwork(req.Name)
 	})
 
-	// Create network and pass false to clusterNotification so the database record is removed on error.
-	err = doNetworksCreate(d, req, false)
+	err = doNetworksCreate(d, req, clientType)
 	if err != nil {
 		return response.SmartError(err)
 	}
@@ -227,7 +228,7 @@ func networksPost(d *Daemon, r *http.Request) response.Response {
 	return resp
 }
 
-func networksPostCluster(d *Daemon, req api.NetworksPost) error {
+func networksPostCluster(d *Daemon, req api.NetworksPost, clientType cluster.ClientType) error {
 	// Check that no node-specific config key has been defined.
 	for key := range req.Config {
 		if shared.StringInSlice(key, db.NodeSpecificNetworkConfig) {
@@ -316,7 +317,7 @@ func networksPostCluster(d *Daemon, req api.NetworksPost) error {
 		return err
 	}
 
-	err = doNetworksCreate(d, nodeReq, false)
+	err = doNetworksCreate(d, nodeReq, clientType)
 	if err != nil {
 		return err
 	}
@@ -344,7 +345,7 @@ func networksPostCluster(d *Daemon, req api.NetworksPost) error {
 
 // Create the network on the system. The clusterNotification flag is used to indicate whether creation request
 // is coming from a cluster notification (and if so we should not delete the database record on error).
-func doNetworksCreate(d *Daemon, req api.NetworksPost, clusterNotification bool) error {
+func doNetworksCreate(d *Daemon, req api.NetworksPost, clientType cluster.ClientType) error {
 	// Start the network.
 	n, err := network.LoadByName(d.State(), req.Name)
 	if err != nil {
@@ -358,14 +359,14 @@ func doNetworksCreate(d *Daemon, req api.NetworksPost, clusterNotification bool)
 	}
 
 	// Run initial creation setup for the network driver.
-	err = n.Create(clusterNotification)
+	err = n.Create(clientType)
 	if err != nil {
 		return err
 	}
 
 	err = n.Start()
 	if err != nil {
-		n.Delete(clusterNotification)
+		n.Delete(clientType)
 		return err
 	}
 
@@ -535,6 +536,8 @@ func networkDelete(d *Daemon, r *http.Request) response.Response {
 		return response.NotFound(err)
 	}
 
+	clientType := cluster.UserAgentClientType(r.Header.Get("User-Agent"))
+
 	clusterNotification := isClusterNotification(r)
 	if !clusterNotification {
 		// Sanity checks.
@@ -549,7 +552,7 @@ func networkDelete(d *Daemon, r *http.Request) response.Response {
 	}
 
 	// Delete the network.
-	err = n.Delete(clusterNotification)
+	err = n.Delete(clientType)
 	if err != nil {
 		return response.SmartError(err)
 	}
@@ -681,7 +684,9 @@ func networkPut(d *Daemon, r *http.Request) response.Response {
 		}
 	}
 
-	return doNetworkUpdate(d, name, req, targetNode, isClusterNotification(r), r.Method, clustered)
+	clientType := cluster.UserAgentClientType(r.Header.Get("User-Agent"))
+
+	return doNetworkUpdate(d, name, req, targetNode, clientType, r.Method, clustered)
 }
 
 func networkPatch(d *Daemon, r *http.Request) response.Response {
@@ -690,7 +695,7 @@ func networkPatch(d *Daemon, r *http.Request) response.Response {
 
 // doNetworkUpdate loads the current local network config, merges with the requested network config, validates
 // and applies the changes. Will also notify other cluster nodes of non-node specific config if needed.
-func doNetworkUpdate(d *Daemon, name string, req api.NetworkPut, targetNode string, clusterNotification bool, httpMethod string, clustered bool) response.Response {
+func doNetworkUpdate(d *Daemon, name string, req api.NetworkPut, targetNode string, clientType cluster.ClientType, httpMethod string, clustered bool) response.Response {
 	// Load the local node-specific network.
 	n, err := network.LoadByName(d.State(), name)
 	if err != nil {
@@ -730,7 +735,7 @@ func doNetworkUpdate(d *Daemon, name string, req api.NetworkPut, targetNode stri
 	}
 
 	// Apply the new configuration (will also notify other cluster nodes if needed).
-	err = n.Update(req, targetNode, clusterNotification)
+	err = n.Update(req, targetNode, clientType)
 	if err != nil {
 		return response.SmartError(err)
 	}


More information about the lxc-devel mailing list