1
0
mirror of https://github.com/lxc/incus.git synced 2026-02-05 09:46:19 +01:00

Automatically generate database schema from database updates

This change integrates the new Schema.Dump() method in the LXD
development process. From now one there's a single source of truth of
database schema, the database updates, and there's no need to keep
updates and CURRENT_SCHEMA declarations in sync, since CURRENT_SCHEMA
is generated automatically.

Signed-off-by: Free Ekanayaka <free.ekanayaka@canonical.com>
This commit is contained in:
Free Ekanayaka
2017-08-25 08:08:45 +00:00
parent c4f0af1717
commit 6c259c63ba
7 changed files with 384 additions and 219 deletions

View File

@@ -28,6 +28,11 @@ update:
go get -t -v -d -u ./...
@echo "Dependencies updated"
.PHONY: update
update-schema:
go run -v $(TAGS) ./lxd/schema.go
@echo "Schema source code updated"
.PHONY: debug
debug:
go get -t -v -d ./...

View File

@@ -1002,17 +1002,23 @@ func initializeDbObject(d *Daemon, path string) error {
// Apply any database update.
//
// NOTE: we use the postApply parameter to run a couple of
// legacy non-db updates that were introduced before the
// NOTE: we use the legacyPatches parameter to run a few
// legacy non-db updates that were in place before the
// patches mechanism was introduced in lxd/patches.go. The
// rest of non-db patches will be applied separately via
// patchesApplyAll. See PR #3322 for more details.
err = db.UpdatesApplyAll(d.db, true, func(version int) error {
if legacyPatch, ok := legacyPatches[version]; ok {
return legacyPatch(d)
legacy := map[int]*db.LegacyPatch{}
for i, patch := range legacyPatches {
legacy[i] = &db.LegacyPatch{
Hook: func() error {
return patch(d)
},
}
return nil
})
}
for _, i := range legacyPatchesNeedingDB {
legacy[i].NeedsDB = true
}
err = db.UpdatesApplyAll(d.db, true, legacy)
if err != nil {
return err
}

View File

@@ -25,196 +25,6 @@ var (
NoSuchObjectError = fmt.Errorf("No such object")
)
// CURRENT_SCHEMA contains the current SQLite SQL Schema.
const CURRENT_SCHEMA string = `
CREATE TABLE IF NOT EXISTS certificates (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
fingerprint VARCHAR(255) NOT NULL,
type INTEGER NOT NULL,
name VARCHAR(255) NOT NULL,
certificate TEXT NOT NULL,
UNIQUE (fingerprint)
);
CREATE TABLE IF NOT EXISTS config (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
key VARCHAR(255) NOT NULL,
value TEXT,
UNIQUE (key)
);
CREATE TABLE IF NOT EXISTS containers (
id INTEGER primary key AUTOINCREMENT NOT NULL,
name VARCHAR(255) NOT NULL,
description TEXT,
architecture INTEGER NOT NULL,
type INTEGER NOT NULL,
ephemeral INTEGER NOT NULL DEFAULT 0,
stateful INTEGER NOT NULL DEFAULT 0,
creation_date DATETIME,
last_use_date DATETIME,
UNIQUE (name)
);
CREATE TABLE IF NOT EXISTS containers_config (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
container_id INTEGER NOT NULL,
key VARCHAR(255) NOT NULL,
value TEXT,
FOREIGN KEY (container_id) REFERENCES containers (id) ON DELETE CASCADE,
UNIQUE (container_id, key)
);
CREATE TABLE IF NOT EXISTS containers_devices (
id INTEGER primary key AUTOINCREMENT NOT NULL,
container_id INTEGER NOT NULL,
name VARCHAR(255) NOT NULL,
type INTEGER NOT NULL default 0,
FOREIGN KEY (container_id) REFERENCES containers (id) ON DELETE CASCADE,
UNIQUE (container_id, name)
);
CREATE TABLE IF NOT EXISTS containers_devices_config (
id INTEGER primary key AUTOINCREMENT NOT NULL,
container_device_id INTEGER NOT NULL,
key VARCHAR(255) NOT NULL,
value TEXT,
FOREIGN KEY (container_device_id) REFERENCES containers_devices (id) ON DELETE CASCADE,
UNIQUE (container_device_id, key)
);
CREATE TABLE IF NOT EXISTS containers_profiles (
id INTEGER primary key AUTOINCREMENT NOT NULL,
container_id INTEGER NOT NULL,
profile_id INTEGER NOT NULL,
apply_order INTEGER NOT NULL default 0,
UNIQUE (container_id, profile_id),
FOREIGN KEY (container_id) REFERENCES containers(id) ON DELETE CASCADE,
FOREIGN KEY (profile_id) REFERENCES profiles(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS images (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
cached INTEGER NOT NULL DEFAULT 0,
fingerprint VARCHAR(255) NOT NULL,
filename VARCHAR(255) NOT NULL,
size INTEGER NOT NULL,
public INTEGER NOT NULL DEFAULT 0,
auto_update INTEGER NOT NULL DEFAULT 0,
architecture INTEGER NOT NULL,
creation_date DATETIME,
expiry_date DATETIME,
upload_date DATETIME NOT NULL,
last_use_date DATETIME,
UNIQUE (fingerprint)
);
CREATE TABLE IF NOT EXISTS images_aliases (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
name VARCHAR(255) NOT NULL,
image_id INTEGER NOT NULL,
description TEXT,
FOREIGN KEY (image_id) REFERENCES images (id) ON DELETE CASCADE,
UNIQUE (name)
);
CREATE TABLE IF NOT EXISTS images_properties (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
image_id INTEGER NOT NULL,
type INTEGER NOT NULL,
key VARCHAR(255) NOT NULL,
value TEXT,
FOREIGN KEY (image_id) REFERENCES images (id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS images_source (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
image_id INTEGER NOT NULL,
server TEXT NOT NULL,
protocol INTEGER NOT NULL,
certificate TEXT NOT NULL,
alias VARCHAR(255) NOT NULL,
FOREIGN KEY (image_id) REFERENCES images (id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS networks (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
name VARCHAR(255) NOT NULL,
description TEXT,
UNIQUE (name)
);
CREATE TABLE IF NOT EXISTS networks_config (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
network_id INTEGER NOT NULL,
key VARCHAR(255) NOT NULL,
value TEXT,
UNIQUE (network_id, key),
FOREIGN KEY (network_id) REFERENCES networks (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,
description TEXT,
UNIQUE (name)
);
CREATE TABLE IF NOT EXISTS profiles_config (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
profile_id INTEGER NOT NULL,
key VARCHAR(255) NOT NULL,
value VARCHAR(255),
UNIQUE (profile_id, key),
FOREIGN KEY (profile_id) REFERENCES profiles(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS profiles_devices (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
profile_id INTEGER NOT NULL,
name VARCHAR(255) NOT NULL,
type INTEGER NOT NULL default 0,
UNIQUE (profile_id, name),
FOREIGN KEY (profile_id) REFERENCES profiles (id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS profiles_devices_config (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
profile_device_id INTEGER NOT NULL,
key VARCHAR(255) NOT NULL,
value TEXT,
UNIQUE (profile_device_id, key),
FOREIGN KEY (profile_device_id) REFERENCES profiles_devices (id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS schema (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
version INTEGER NOT NULL,
updated_at DATETIME NOT NULL,
UNIQUE (version)
);
CREATE TABLE IF NOT EXISTS storage_pools (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
name VARCHAR(255) NOT NULL,
description TEXT,
driver VARCHAR(255) NOT NULL,
UNIQUE (name)
);
CREATE TABLE IF NOT EXISTS storage_pools_config (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
storage_pool_id INTEGER NOT NULL,
key VARCHAR(255) NOT NULL,
value TEXT,
UNIQUE (storage_pool_id, key),
FOREIGN KEY (storage_pool_id) REFERENCES storage_pools (id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS storage_volumes (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
name VARCHAR(255) NOT NULL,
description TEXT,
storage_pool_id INTEGER NOT NULL,
type INTEGER NOT NULL,
UNIQUE (storage_pool_id, name, type),
FOREIGN KEY (storage_pool_id) REFERENCES storage_pools (id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS storage_volumes_config (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
storage_volume_id INTEGER NOT NULL,
key VARCHAR(255) NOT NULL,
value TEXT,
UNIQUE (storage_volume_id, key),
FOREIGN KEY (storage_volume_id) REFERENCES storage_volumes (id) ON DELETE CASCADE
);`
func enableForeignKeys(conn *sqlite3.SQLiteConn) error {
_, err := conn.Exec("PRAGMA foreign_keys=ON;", nil)
return err
@@ -249,13 +59,6 @@ func CreateDb(db *sql.DB, patchNames []string) (err error) {
return err
}
// There isn't an entry for schema version, let's put it in.
insertStmt := `INSERT INTO schema (version, updated_at) values (?, strftime("%s"));`
_, err = db.Exec(insertStmt, GetLatestSchema())
if err != nil {
return err
}
// Mark all existing patches as applied
for _, patchName := range patchNames {
PatchesMarkApplied(db, patchName)

198
lxd/db/schema.go Normal file
View File

@@ -0,0 +1,198 @@
package db
// DO NOT EDIT BY HAND
//
// This code was generated by the UpdateSchemaDotGo function. If you need to
// modify the database schema, please add a new schema update to update.go
// and the run 'make update-schema'.
const CURRENT_SCHEMA = `
CREATE TABLE certificates (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
fingerprint VARCHAR(255) NOT NULL,
type INTEGER NOT NULL,
name VARCHAR(255) NOT NULL,
certificate TEXT NOT NULL,
UNIQUE (fingerprint)
);
CREATE TABLE config (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
key VARCHAR(255) NOT NULL,
value TEXT,
UNIQUE (key)
);
CREATE TABLE "containers" (
id INTEGER primary key AUTOINCREMENT NOT NULL,
name VARCHAR(255) NOT NULL,
architecture INTEGER NOT NULL,
type INTEGER NOT NULL,
ephemeral INTEGER NOT NULL DEFAULT 0,
creation_date DATETIME NOT NULL DEFAULT 0,
stateful INTEGER NOT NULL DEFAULT 0,
last_use_date DATETIME,
description TEXT,
UNIQUE (name)
);
CREATE TABLE containers_config (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
container_id INTEGER NOT NULL,
key VARCHAR(255) NOT NULL,
value TEXT,
FOREIGN KEY (container_id) REFERENCES containers (id) ON DELETE CASCADE,
UNIQUE (container_id, key)
);
CREATE TABLE containers_devices (
id INTEGER primary key AUTOINCREMENT NOT NULL,
container_id INTEGER NOT NULL,
name VARCHAR(255) NOT NULL,
type INTEGER NOT NULL default 0,
FOREIGN KEY (container_id) REFERENCES containers (id) ON DELETE CASCADE,
UNIQUE (container_id, name)
);
CREATE TABLE containers_devices_config (
id INTEGER primary key AUTOINCREMENT NOT NULL,
container_device_id INTEGER NOT NULL,
key VARCHAR(255) NOT NULL,
value TEXT,
FOREIGN KEY (container_device_id) REFERENCES containers_devices (id) ON DELETE CASCADE,
UNIQUE (container_device_id, key)
);
CREATE TABLE containers_profiles (
id INTEGER primary key AUTOINCREMENT NOT NULL,
container_id INTEGER NOT NULL,
profile_id INTEGER NOT NULL,
apply_order INTEGER NOT NULL default 0,
UNIQUE (container_id, profile_id),
FOREIGN KEY (container_id) REFERENCES containers(id) ON DELETE CASCADE,
FOREIGN KEY (profile_id) REFERENCES profiles(id) ON DELETE CASCADE
);
CREATE TABLE images (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
fingerprint VARCHAR(255) NOT NULL,
filename VARCHAR(255) NOT NULL,
size INTEGER NOT NULL,
public INTEGER NOT NULL DEFAULT 0,
architecture INTEGER NOT NULL,
creation_date DATETIME,
expiry_date DATETIME,
upload_date DATETIME NOT NULL,
cached INTEGER NOT NULL DEFAULT 0,
last_use_date DATETIME,
auto_update INTEGER NOT NULL DEFAULT 0,
UNIQUE (fingerprint)
);
CREATE TABLE "images_aliases" (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
name VARCHAR(255) NOT NULL,
image_id INTEGER NOT NULL,
description TEXT,
FOREIGN KEY (image_id) REFERENCES images (id) ON DELETE CASCADE,
UNIQUE (name)
);
CREATE TABLE images_properties (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
image_id INTEGER NOT NULL,
type INTEGER NOT NULL,
key VARCHAR(255) NOT NULL,
value TEXT,
FOREIGN KEY (image_id) REFERENCES images (id) ON DELETE CASCADE
);
CREATE TABLE images_source (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
image_id INTEGER NOT NULL,
server TEXT NOT NULL,
protocol INTEGER NOT NULL,
certificate TEXT NOT NULL,
alias VARCHAR(255) NOT NULL,
FOREIGN KEY (image_id) REFERENCES images (id) ON DELETE CASCADE
);
CREATE TABLE networks (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
name VARCHAR(255) NOT NULL,
description TEXT,
UNIQUE (name)
);
CREATE TABLE networks_config (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
network_id INTEGER NOT NULL,
key VARCHAR(255) NOT NULL,
value TEXT,
UNIQUE (network_id, key),
FOREIGN KEY (network_id) REFERENCES networks (id) ON DELETE CASCADE
);
CREATE TABLE patches (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
name VARCHAR(255) NOT NULL,
applied_at DATETIME NOT NULL,
UNIQUE (name)
);
CREATE TABLE profiles (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
name VARCHAR(255) NOT NULL,
description TEXT,
UNIQUE (name)
);
CREATE TABLE profiles_config (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
profile_id INTEGER NOT NULL,
key VARCHAR(255) NOT NULL,
value VARCHAR(255),
UNIQUE (profile_id, key),
FOREIGN KEY (profile_id) REFERENCES profiles(id) ON DELETE CASCADE
);
CREATE TABLE profiles_devices (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
profile_id INTEGER NOT NULL,
name VARCHAR(255) NOT NULL,
type INTEGER NOT NULL default 0,
UNIQUE (profile_id, name),
FOREIGN KEY (profile_id) REFERENCES profiles (id) ON DELETE CASCADE
);
CREATE TABLE profiles_devices_config (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
profile_device_id INTEGER NOT NULL,
key VARCHAR(255) NOT NULL,
value TEXT,
UNIQUE (profile_device_id, key),
FOREIGN KEY (profile_device_id) REFERENCES profiles_devices (id) ON DELETE CASCADE
);
CREATE TABLE schema (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
version INTEGER NOT NULL,
updated_at DATETIME NOT NULL,
UNIQUE (version)
);
CREATE TABLE storage_pools (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
name VARCHAR(255) NOT NULL,
driver VARCHAR(255) NOT NULL,
description TEXT,
UNIQUE (name)
);
CREATE TABLE storage_pools_config (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
storage_pool_id INTEGER NOT NULL,
key VARCHAR(255) NOT NULL,
value TEXT,
UNIQUE (storage_pool_id, key),
FOREIGN KEY (storage_pool_id) REFERENCES storage_pools (id) ON DELETE CASCADE
);
CREATE TABLE storage_volumes (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
name VARCHAR(255) NOT NULL,
storage_pool_id INTEGER NOT NULL,
type INTEGER NOT NULL,
description TEXT,
UNIQUE (storage_pool_id, name, type),
FOREIGN KEY (storage_pool_id) REFERENCES storage_pools (id) ON DELETE CASCADE
);
CREATE TABLE storage_volumes_config (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
storage_volume_id INTEGER NOT NULL,
key VARCHAR(255) NOT NULL,
value TEXT,
UNIQUE (storage_volume_id, key),
FOREIGN KEY (storage_volume_id) REFERENCES storage_volumes (id) ON DELETE CASCADE
);
INSERT INTO schema (version, updated_at) VALUES (36, strftime("%s"))
`

View File

@@ -5,6 +5,8 @@ import (
"encoding/hex"
"fmt"
"os"
"path"
"runtime"
"strconv"
"strings"
@@ -27,6 +29,10 @@ import (
DO NOT USE this mechanism for one-time actions which do not involve
changes to the database schema. Use patches instead (see lxd/patches.go).
REMEMBER to run "make update-schema" after you add a new update function to
this slice. That will refresh the schema declaration in lxd/db/schema.go and
include the effect of applying your patch as well.
Only append to the updates list, never remove entries and never re-order them.
*/
@@ -69,18 +75,25 @@ var updates = map[int]schema.Update{
36: updateFromV35,
}
// Apply all possible database patches. If "doBackup" is true, the
// sqlite file will be backed up before any update is applied. If
// "postApply" it's passed, it will be called after each database
// update gets successfully applied, and be passed the its version (as
// of now "postApply" is only used by the daemon as a mean to apply
// the legacy V10 and V15 non-db updates during the database upgrade
// sequence to, avoid changing semantics see PR #3322).
func UpdatesApplyAll(db *sql.DB, doBackup bool, postApply func(int) error) error {
// LegacyPatch is a "database" update that performs non-database work. They
// are needed for historical reasons, since there was a time were db updates
// could do non-db work and depend on functionality external to the db
// package. See UpdatesApplyAll below.
type LegacyPatch struct {
NeedsDB bool // Whether the patch does any DB-related work
Hook func() error // The actual patch logic
}
// UpdatesApplyAll applies all possible database patches. If "doBackup" is
// true, the sqlite file will be backed up before any update is applied. The
// legacyPatches parameter is used by the Daemon as a mean to apply the legacy
// V10, V11, V15, V29 and V30 non-db updates during the database upgrade
// sequence, to avoid any change in semantics wrt the old logic (see PR #3322).
func UpdatesApplyAll(db *sql.DB, doBackup bool, legacyPatches map[int]*LegacyPatch) error {
backup := false
schema := schema.NewFromMap(updates)
schema.Hook(func(version int) error {
schema.Hook(func(version int, tx *sql.Tx) error {
if doBackup && !backup {
logger.Infof("Updating the LXD database schema. Backup made as \"lxd.db.bak\"")
err := shared.FileCopy(shared.VarPath("lxd.db"), shared.VarPath("lxd.db.bak"))
@@ -91,14 +104,87 @@ func UpdatesApplyAll(db *sql.DB, doBackup bool, postApply func(int) error) error
backup = true
}
logger.Debugf("Updating DB schema from %d to %d", version, version+1)
if postApply != nil {
return postApply(version + 1)
legacyPatch, ok := legacyPatches[version]
if ok {
// FIXME We need to commit the transaction before the
// hook and then open it again afterwards because this
// legacy patch pokes with the database and would fail
// with a lock error otherwise.
if legacyPatch.NeedsDB {
_, err := tx.Exec("COMMIT")
if err != nil {
return err
}
}
err := legacyPatch.Hook()
if err != nil {
return err
}
if legacyPatch.NeedsDB {
_, err = tx.Exec("BEGIN")
}
return err
}
return nil
})
return schema.Ensure(db)
}
// UpdateSchemaDotGo rewrites the 'schema.go' source file in this package to
// match the current schema updates.
//
// The schema.go file contains a "flattened" render of all schema updates
// defined in this file, and it's used to initialize brand new databases.
func UpdateSchemaDotGo() error {
// Apply all the updates that we have on a pristine database and dump
// the resulting schema.
db, err := sql.Open("sqlite3", ":memory:")
if err != nil {
return fmt.Errorf("failed to open schema.go for writing: %v", err)
}
schema := schema.NewFromMap(updates)
err = schema.Ensure(db)
if err != nil {
return err
}
dump, err := schema.Dump(db)
if err != nil {
return err
}
// Passing 1 to runtime.Caller identifies the caller of runtime.Caller,
// that means us.
_, filename, _, _ := runtime.Caller(0)
file, err := os.Create(path.Join(path.Dir(filename), "schema.go"))
if err != nil {
return fmt.Errorf("failed to open schema.go for writing: %v", err)
}
_, err = file.Write([]byte(fmt.Sprintf(schemaDotGo, dump)))
if err != nil {
return fmt.Errorf("failed to write to schema.go: %v", err)
}
return nil
}
// Template for schema.go (can't use backticks since we need to use backticks
// inside the template itself).
const schemaDotGo = "package db\n\n" +
"// DO NOT EDIT BY HAND\n" +
"//\n" +
"// This code was generated by the UpdateSchemaDotGo function. If you need to\n" +
"// modify the database schema, please add a new schema update to update.go\n" +
"// and the run 'make update-schema'.\n" +
"const CURRENT_SCHEMA = `\n" +
"%s`\n"
// Schema updates begin here
func updateFromV35(tx *sql.Tx) error {
stmts := `
@@ -818,7 +904,51 @@ CREATE TABLE IF NOT EXISTS images_aliases (
}
func updateFromV0(tx *sql.Tx) error {
// v0..v1 is a noop. It used to add the schema table, but that's now
// done by Schema.Ensure().
return nil
// v0..v1 the dawn of containers
stmt := `
CREATE TABLE certificates (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
fingerprint VARCHAR(255) NOT NULL,
type INTEGER NOT NULL,
name VARCHAR(255) NOT NULL,
certificate TEXT NOT NULL,
UNIQUE (fingerprint)
);
CREATE TABLE containers (
id INTEGER primary key AUTOINCREMENT NOT NULL,
name VARCHAR(255) NOT NULL,
architecture INTEGER NOT NULL,
type INTEGER NOT NULL,
UNIQUE (name)
);
CREATE TABLE containers_config (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
container_id INTEGER NOT NULL,
key VARCHAR(255) NOT NULL,
value TEXT,
FOREIGN KEY (container_id) REFERENCES containers (id),
UNIQUE (container_id, key)
);
CREATE TABLE images (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
fingerprint VARCHAR(255) NOT NULL,
filename VARCHAR(255) NOT NULL,
size INTEGER NOT NULL,
public INTEGER NOT NULL DEFAULT 0,
architecture INTEGER NOT NULL,
creation_date DATETIME,
expiry_date DATETIME,
upload_date DATETIME NOT NULL,
UNIQUE (fingerprint)
);
CREATE TABLE images_properties (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
image_id INTEGER NOT NULL,
type INTEGER NOT NULL,
key VARCHAR(255) NOT NULL,
value TEXT,
FOREIGN KEY (image_id) REFERENCES images (id)
);`
_, err := tx.Exec(stmt)
return err
}

View File

@@ -2405,9 +2405,10 @@ var legacyPatches = map[int](func(d *Daemon) error){
11: patchUpdateFromV10,
12: patchUpdateFromV11,
16: patchUpdateFromV15,
31: patchUpdateFromV30,
30: patchUpdateFromV29,
31: patchUpdateFromV30,
}
var legacyPatchesNeedingDB = []int{11, 12, 16} // Legacy patches doing DB work
func patchUpdateFromV10(d *Daemon) error {
if shared.PathExists(shared.VarPath("lxc")) {

22
lxd/schema.go Normal file
View File

@@ -0,0 +1,22 @@
// +build never
//
// We use the tag 'never' because this utility shouldn't normally be built,
// unless you're running the 'update-schema' target of the Makefile.
package main
import (
"log"
"github.com/lxc/lxd/lxd/db"
)
// Entry point for the "schema" development utility, which updates the content
// of lxd/db/schema.go according to the current schema updates declared in
// updates.go in the same package.
func main() {
err := db.UpdateSchemaDotGo()
if err != nil {
log.Fatal(err)
}
}