[lxc-devel] [lxd/master] Implement patches mechanism

stgraber on Github lxc-bot at linuxcontainers.org
Fri Jun 3 05:23:30 UTC 2016


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 301 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20160603/0dddd375/attachment.bin>
-------------- next part --------------
From 5e831b86be5aa1b589b6de7f821cb26373fe3cc2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Thu, 2 Jun 2016 23:47:51 -0400
Subject: [PATCH 1/3] patches: Add new table and schema update
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxd/db.go        |  8 +++++++-
 lxd/db_update.go | 19 +++++++++++++++++++
 2 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/lxd/db.go b/lxd/db.go
index abd450f..17fc137 100644
--- a/lxd/db.go
+++ b/lxd/db.go
@@ -34,7 +34,7 @@ type Profile struct {
 // Profiles will contain a list of all Profiles.
 type Profiles []Profile
 
-const DB_CURRENT_VERSION int = 31
+const DB_CURRENT_VERSION int = 32
 
 // CURRENT_SCHEMA contains the current SQLite SQL Schema.
 const CURRENT_SCHEMA string = `
@@ -135,6 +135,12 @@ CREATE TABLE IF NOT EXISTS images_source (
     alias VARCHAR(255) NOT NULL,
     FOREIGN KEY (image_id) REFERENCES images (id) ON DELETE CASCADE
 );
+CREATE TABLE IF NOT EXISTS patches (
+    id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
+    name VARCHAR(255) NOT NULL,
+    applied_at DATETIME NOT NULL,
+    UNIQUE (name)
+);
 CREATE TABLE IF NOT EXISTS profiles (
     id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
     name VARCHAR(255) NOT NULL,
diff --git a/lxd/db_update.go b/lxd/db_update.go
index d8056d8..95ed4d3 100644
--- a/lxd/db_update.go
+++ b/lxd/db_update.go
@@ -17,6 +17,19 @@ import (
 	log "gopkg.in/inconshreveable/log15.v2"
 )
 
+func dbUpdateFromV31(db *sql.DB) error {
+	stmt := `
+CREATE TABLE IF NOT EXISTS patches (
+    id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
+    name VARCHAR(255) NOT NULL,
+    applied_at DATETIME NOT NULL,
+    UNIQUE (name)
+);
+INSERT INTO schema (version, updated_at) VALUES (?, strftime("%s"));`
+	_, err := db.Exec(stmt, 32)
+	return err
+}
+
 func dbUpdateFromV30(db *sql.DB, mockMode bool) error {
 	if mockMode {
 		stmt := `INSERT INTO schema (version, updated_at) VALUES (?, strftime("%s"));`
@@ -1072,6 +1085,12 @@ func dbUpdate(d *Daemon, prevVersion int) error {
 			return err
 		}
 	}
+	if prevVersion < 32 {
+		err = dbUpdateFromV31(db)
+		if err != nil {
+			return err
+		}
+	}
 
 	return nil
 }

From dc09db92ba6e3203755865630e10ad52e7893334 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Fri, 3 Jun 2016 00:57:06 -0400
Subject: [PATCH 2/3] patches: Initial implementation
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxd/daemon.go     |  8 ++++++-
 lxd/db_patches.go | 30 +++++++++++++++++++++++++
 lxd/patches.go    | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 102 insertions(+), 1 deletion(-)
 create mode 100644 lxd/db_patches.go
 create mode 100644 lxd/patches.go

diff --git a/lxd/daemon.go b/lxd/daemon.go
index d8bf79d..0215f0d 100644
--- a/lxd/daemon.go
+++ b/lxd/daemon.go
@@ -738,12 +738,18 @@ func (d *Daemon) Init() error {
 		return err
 	}
 
-	/* Setup the storage driver */
 	if !d.MockMode {
+		/* Setup the storage driver */
 		err = d.SetupStorageDriver()
 		if err != nil {
 			return fmt.Errorf("Failed to setup storage: %s", err)
 		}
+
+		/* Apply all patches */
+		err = patchesApplyAll(d)
+		if err != nil {
+			return err
+		}
 	}
 
 	/* Log expiry */
diff --git a/lxd/db_patches.go b/lxd/db_patches.go
new file mode 100644
index 0000000..cd2876a
--- /dev/null
+++ b/lxd/db_patches.go
@@ -0,0 +1,30 @@
+package main
+
+import (
+	"database/sql"
+	"fmt"
+)
+
+func dbPatches(db *sql.DB) ([]string, error) {
+	inargs := []interface{}{}
+	outfmt := []interface{}{""}
+
+	query := fmt.Sprintf("SELECT name FROM patches")
+	result, err := dbQueryScan(db, query, inargs, outfmt)
+	if err != nil {
+		return []string{}, err
+	}
+
+	response := []string{}
+	for _, r := range result {
+		response = append(response, r[0].(string))
+	}
+
+	return response, nil
+}
+
+func dbPatchesMarkApplied(db *sql.DB, patch string) error {
+	stmt := `INSERT INTO patches (name, applied_at) VALUES (?, strftime("%s"));`
+	_, err := db.Exec(stmt, patch)
+	return err
+}
diff --git a/lxd/patches.go b/lxd/patches.go
new file mode 100644
index 0000000..b0174c7
--- /dev/null
+++ b/lxd/patches.go
@@ -0,0 +1,65 @@
+package main
+
+import (
+	"github.com/lxc/lxd/shared"
+)
+
+/* Patches are one-time actions that are sometimes needed to update
+   existing container configuration or move things around on the
+   filesystem.
+
+   Those patches are applied at startup time after the database schema
+   has been fully updated. Patches can therefore assume a working database.
+
+   At the time the patches are applied, the containers aren't started
+   yet and the daemon isn't listening to requests.
+
+   DO NOT use this mechanism for database update. Schema updates must be
+   done through the separate schema update mechanism.
+
+
+   Only append to the patches list, never remove entries and never re-order them.
+*/
+
+var patches = []patch{}
+
+type patch struct {
+	name string
+	run  func(name string, d *Daemon) error
+}
+
+func (p *patch) apply(d *Daemon) error {
+	shared.Debugf("Applying patch: %s", p.name)
+
+	err := p.run(p.name, d)
+	if err != nil {
+		return err
+	}
+
+	err = dbPatchesMarkApplied(d.db, p.name)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func patchesApplyAll(d *Daemon) error {
+	appliedPatches, err := dbPatches(d.db)
+	if err != nil {
+		return err
+	}
+
+	for _, patch := range patches {
+		if shared.StringInSlice(patch.name, appliedPatches) {
+			continue
+		}
+
+		err := patch.apply(d)
+		if err != nil {
+			return err
+		}
+	}
+
+	return nil
+}

From 3d00e39f80698dc9c600453e831c4e3fdb75a6f2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Fri, 3 Jun 2016 01:03:05 -0400
Subject: [PATCH 3/3] Tiny optimization in db_update
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxd/db_update.go | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/lxd/db_update.go b/lxd/db_update.go
index 95ed4d3..73ec867 100644
--- a/lxd/db_update.go
+++ b/lxd/db_update.go
@@ -892,12 +892,14 @@ INSERT INTO schema (version, updated_at) VALUES (?, strftime("%s"));`
 func dbUpdate(d *Daemon, prevVersion int) error {
 	db := d.db
 
-	if prevVersion < 0 || prevVersion > DB_CURRENT_VERSION {
-		return fmt.Errorf("Bad database version: %d", prevVersion)
-	}
 	if prevVersion == DB_CURRENT_VERSION {
 		return nil
 	}
+
+	if prevVersion < 0 || prevVersion > DB_CURRENT_VERSION {
+		return fmt.Errorf("Bad database version: %d", prevVersion)
+	}
+
 	var err error
 	if prevVersion < 1 {
 		err = dbUpdateFromV0(db)


More information about the lxc-devel mailing list