[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