[lxc-devel] [lxd/master] Trigger the upgrade script if we detect a dqlite client with higher version [WIP]

freeekanayaka on Github lxc-bot at linuxcontainers.org
Tue May 21 19:18:56 UTC 2019


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 363 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20190521/52433645/attachment.bin>
-------------- next part --------------
From 4bf0346d36c38295488da59813466d285c7664a7 Mon Sep 17 00:00:00 2001
From: Free Ekanayaka <free.ekanayaka at canonical.com>
Date: Tue, 21 May 2019 13:48:24 +0200
Subject: [PATCH] Trigger the upgrade script if we detect a dqlite client with
 higher version

Signed-off-by: Free Ekanayaka <free.ekanayaka at canonical.com>
---
 lxd/cluster/gateway.go | 30 ++++++++++++++++++++++++++++++
 lxd/cluster/upgrade.go | 11 ++++++++---
 2 files changed, 38 insertions(+), 3 deletions(-)

diff --git a/lxd/cluster/gateway.go b/lxd/cluster/gateway.go
index c34fdd1c0a..29d3337752 100644
--- a/lxd/cluster/gateway.go
+++ b/lxd/cluster/gateway.go
@@ -98,12 +98,19 @@ type Gateway struct {
 	// their version.
 	upgradeCh chan struct{}
 
+	// Used to track whether we already triggered an upgrade because we
+	// detected a peer with an higher version.
+	upgradeTriggered bool
+
 	// ServerStore wrapper.
 	store *dqliteServerStore
 
 	lock sync.RWMutex
 }
 
+// Current dqlite protocol version.
+const dqliteVersion = 0
+
 // HandlerFuncs returns the HTTP handlers that should be added to the REST API
 // endpoint in order to handle database-related requests.
 //
@@ -123,6 +130,29 @@ func (g *Gateway) HandlerFuncs() map[string]http.HandlerFunc {
 			return
 		}
 
+		// Compare the dqlite version of the connecting client
+		// with our own one.
+		versionHeader := r.Header.Get("X-Dqlite-Version")
+		if versionHeader == "" {
+			// No version header means an old pre dqlite 1.0 client.
+			versionHeader = "0"
+		}
+		version, err := strconv.Atoi(versionHeader)
+		if err != nil {
+			http.Error(w, "400 invalid dqlite version", http.StatusBadRequest)
+			return
+		}
+		if version != dqliteVersion {
+			if !g.upgradeTriggered && version > dqliteVersion {
+				err = triggerUpdate()
+				if err == nil {
+					g.upgradeTriggered = true
+				}
+			}
+			http.Error(w, "503 dqlite version mismatch", http.StatusServiceUnavailable)
+			return
+		}
+
 		// Handle heatbeats.
 		if r.Method == "PUT" {
 			var nodes []db.RaftNode
diff --git a/lxd/cluster/upgrade.go b/lxd/cluster/upgrade.go
index c4165343e4..df649da997 100644
--- a/lxd/cluster/upgrade.go
+++ b/lxd/cluster/upgrade.go
@@ -110,19 +110,24 @@ func maybeUpdate(state *state.State) {
 		return
 	}
 
+	triggerUpdate()
+}
+
+func triggerUpdate() error {
 	logger.Infof("Node is out-of-date with respect to other cluster nodes")
 
 	updateExecutable := os.Getenv("LXD_CLUSTER_UPDATE")
 	if updateExecutable == "" {
 		logger.Debug("No LXD_CLUSTER_UPDATE variable set, skipping auto-update")
-		return
+		return nil
 	}
 
 	logger.Infof("Triggering cluster update using: %s", updateExecutable)
 
-	_, err = shared.RunCommand(updateExecutable)
+	_, err := shared.RunCommand(updateExecutable)
 	if err != nil {
 		logger.Errorf("Cluster upgrade failed: '%v'", err.Error())
-		return
+		return err
 	}
+	return nil
 }


More information about the lxc-devel mailing list