[lxc-devel] [lxd/master] patches: fix upgrade when daemon got killed during migration

brauner on Github lxc-bot at linuxcontainers.org
Sun Mar 12 00:02:41 UTC 2017


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 398 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20170312/f3ca5d72/attachment.bin>
-------------- next part --------------
From 820f8ebed1ad379615d1f0c7e35b3c4afdff95d2 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Sun, 12 Mar 2017 00:25:20 +0100
Subject: [PATCH 1/2] daemon: skip StoragePoolCheck() broken patch

In case the daemon got killed during upgrade we will already have a valid
storage pool entry but it might have gotten messed up and so we cannot perform
StoragePoolCheck(). This case can be detected by looking at the patches db: If
we already have a storage pool defined but the upgrade somehow got messed up
then there will be no "storage_api" entry in the db.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 lxd/daemon.go | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/lxd/daemon.go b/lxd/daemon.go
index 76cbad4..e4b626e 100644
--- a/lxd/daemon.go
+++ b/lxd/daemon.go
@@ -366,6 +366,25 @@ func (d *Daemon) SetupStorageDriver() error {
 		return err
 	}
 
+	// In case the daemon got killed during upgrade we will already have a
+	// valid storage pool entry but it might have gotten messed up and so we
+	// cannot perform StoragePoolCheck(). This case can be detected by
+	// looking at the patches db: If we already have a storage pool defined
+	// but the upgrade somehow got messed up then there will be no
+	// "storage_api" entry in the db.
+	if len(pools) > 0 {
+		appliedPatches, err := dbPatches(d.db)
+		if err != nil {
+			return err
+		}
+
+		if !shared.StringInSlice("storage_api", appliedPatches) {
+			shared.LogWarnf("Incorrectly applied \"storage_api\" patch. Skipping storage pool initialization as it might be corrupt.")
+			return nil
+		}
+
+	}
+
 	for _, pool := range pools {
 		shared.LogDebugf("Initializing and checking storage pool \"%s\".", pool)
 		s, err := storagePoolInit(d, pool)

From e62bacb4f491b37934b0ffc4622a85c7ca2aa691 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Sun, 12 Mar 2017 00:26:43 +0100
Subject: [PATCH 2/2] patches: check if config is empty before update

We need to ensure that the current config is not overwritten, otherwise we
might clear an otherwise correct config when an update has to be rerun. For
example, when the daemon got killed mid-upgrade.

Fixes #2670.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 lxd/patches.go | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/lxd/patches.go b/lxd/patches.go
index 4105ebe..1fc7f89 100644
--- a/lxd/patches.go
+++ b/lxd/patches.go
@@ -1377,7 +1377,7 @@ func upgradeFromStorageTypeZfs(name string, d *Daemon, defaultPoolName string, d
 
 		// Get the pool ID as we need it for storage volume creation.
 		// (Use a tmp variable as Go's scoping is freaking me out.)
-		tmp, err := dbStoragePoolGetID(d.db, poolName)
+		tmp, pool, err := dbStoragePoolGet(d.db, poolName)
 		if err != nil {
 			shared.LogErrorf("Failed to query database: %s.", err)
 			return err
@@ -1387,7 +1387,10 @@ func upgradeFromStorageTypeZfs(name string, d *Daemon, defaultPoolName string, d
 		// Update the pool configuration on a post LXD 2.9.1 instance
 		// that still runs this upgrade code because of a partial
 		// upgrade.
-		err = dbStoragePoolUpdate(d.db, poolName, poolConfig)
+		if pool.Config == nil {
+			pool.Config = poolConfig
+		}
+		err = dbStoragePoolUpdate(d.db, poolName, pool.Config)
 		if err != nil {
 			return err
 		}


More information about the lxc-devel mailing list