The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/6519
This e-mail was sent by the LXC bot, direct replies will not reach the author unless they happen to be subscribed to this list. === Description (from pull-request) === This adds a new "arch" column to the "nodes" table, in preparation for putting in place multi-arch cluster support, see #6380.
From b7a1d3f1d7c50e591adac4a81be1be2121533d5a Mon Sep 17 00:00:00 2001 From: Free Ekanayaka <free.ekanay...@canonical.com> Date: Wed, 27 Nov 2019 11:02:00 +0000 Subject: [PATCH 1/2] Add arch column to nodes table Signed-off-by: Free Ekanayaka <free.ekanay...@canonical.com> --- lxd/db/cluster/open.go | 9 +++++++-- lxd/db/cluster/open_test.go | 5 +++-- lxd/db/cluster/schema.go | 3 ++- lxd/db/cluster/update.go | 27 +++++++++++++++++++++++++ lxd/db/cluster/update_test.go | 37 ++++++++++++++++++++++++++++++++++ shared/osarch/architectures.go | 13 ++++++++++++ 6 files changed, 89 insertions(+), 5 deletions(-) diff --git a/lxd/db/cluster/open.go b/lxd/db/cluster/open.go index cffb2b50c6..0ce55f6a0b 100644 --- a/lxd/db/cluster/open.go +++ b/lxd/db/cluster/open.go @@ -12,6 +12,7 @@ import ( "github.com/lxc/lxd/lxd/util" "github.com/lxc/lxd/shared" "github.com/lxc/lxd/shared/logger" + "github.com/lxc/lxd/shared/osarch" "github.com/lxc/lxd/shared/version" "github.com/pkg/errors" ) @@ -165,11 +166,15 @@ func EnsureSchema(db *sql.DB, address string, dir string) (bool, error) { // 1. This is needed for referential integrity with other tables. Also, // create a default profile. if initial == 0 { + arch, err := osarch.ArchitectureGetLocalID() + if err != nil { + return false, err + } err = query.Transaction(db, func(tx *sql.Tx) error { stmt := ` -INSERT INTO nodes(id, name, address, schema, api_extensions) VALUES(1, 'none', '0.0.0.0', ?, ?) +INSERT INTO nodes(id, name, address, schema, api_extensions, arch) VALUES(1, 'none', '0.0.0.0', ?, ?, ?) ` - _, err = tx.Exec(stmt, SchemaVersion, apiExtensions) + _, err = tx.Exec(stmt, SchemaVersion, apiExtensions, arch) if err != nil { return err } diff --git a/lxd/db/cluster/open_test.go b/lxd/db/cluster/open_test.go index bdf5505bc4..19c0b98ae5 100644 --- a/lxd/db/cluster/open_test.go +++ b/lxd/db/cluster/open_test.go @@ -10,6 +10,7 @@ import ( "github.com/lxc/lxd/lxd/db/cluster" "github.com/lxc/lxd/lxd/db/query" + "github.com/lxc/lxd/shared/osarch" "github.com/lxc/lxd/shared/version" "github.com/mpvl/subtest" "github.com/stretchr/testify/assert" @@ -165,10 +166,10 @@ CREATE TABLE schema ( func addNode(t *testing.T, db *sql.DB, address string, schema int, apiExtensions int) { err := query.Transaction(db, func(tx *sql.Tx) error { stmt := ` -INSERT INTO nodes(name, address, schema, api_extensions) VALUES (?, ?, ?, ?) +INSERT INTO nodes(name, address, schema, api_extensions, arch) VALUES (?, ?, ?, ?, ?) ` name := fmt.Sprintf("node at %s", address) - _, err := tx.Exec(stmt, name, address, schema, apiExtensions) + _, err := tx.Exec(stmt, name, address, schema, apiExtensions, osarch.ARCH_64BIT_INTEL_X86) return err }) require.NoError(t, err) diff --git a/lxd/db/cluster/schema.go b/lxd/db/cluster/schema.go index 03306ab770..fbe9bcabfd 100644 --- a/lxd/db/cluster/schema.go +++ b/lxd/db/cluster/schema.go @@ -303,6 +303,7 @@ CREATE TABLE nodes ( api_extensions INTEGER NOT NULL, heartbeat DATETIME DEFAULT CURRENT_TIMESTAMP, pending INTEGER NOT NULL DEFAULT 0, + arch INTEGER NOT NULL DEFAULT 0 CHECK (arch >= 1 AND arch <= 8), UNIQUE (name), UNIQUE (address) ); @@ -487,5 +488,5 @@ CREATE TABLE storage_volumes_config ( FOREIGN KEY (storage_volume_id) REFERENCES storage_volumes (id) ON DELETE CASCADE ); -INSERT INTO schema (version, updated_at) VALUES (19, strftime("%s")) +INSERT INTO schema (version, updated_at) VALUES (20, strftime("%s")) ` diff --git a/lxd/db/cluster/update.go b/lxd/db/cluster/update.go index c2f285cb2f..62e3e6b7b8 100644 --- a/lxd/db/cluster/update.go +++ b/lxd/db/cluster/update.go @@ -10,6 +10,7 @@ import ( "github.com/lxc/lxd/lxd/db/query" "github.com/lxc/lxd/lxd/db/schema" "github.com/lxc/lxd/shared" + "github.com/lxc/lxd/shared/osarch" "github.com/pkg/errors" ) @@ -54,6 +55,32 @@ var updates = map[int]schema.Update{ 17: updateFromV16, 18: updateFromV17, 19: updateFromV18, + 20: updateFromV19, +} + +// Add a new "arch" column to the "nodes" table. +func updateFromV19(tx *sql.Tx) error { + // The column has a not-null constraint and a default value of + // 0. However, leaving the 0 default won't effectively be accepted when + // creating a new, due to the check constraint, so we are sure to end + // up with a valid value. + stmt := fmt.Sprintf(` +ALTER TABLE nodes ADD COLUMN arch INTEGER NOT NULL DEFAULT 0 CHECK (arch >= %d AND arch <= %d) +`, + osarch.ARCH_32BIT_INTEL_X86, osarch.ARCH_64BIT_S390_BIG_ENDIAN) + _, err := tx.Exec(stmt) + if err != nil { + return err + } + arch, err := osarch.ArchitectureGetLocalID() + if err != nil { + return err + } + _, err = tx.Exec("UPDATE nodes SET arch = ?", arch) + if err != nil { + return err + } + return nil } // Rename 'containers' to 'instances' in *_used_by_ref views. diff --git a/lxd/db/cluster/update_test.go b/lxd/db/cluster/update_test.go index c620f2c56a..abc3bfac58 100644 --- a/lxd/db/cluster/update_test.go +++ b/lxd/db/cluster/update_test.go @@ -8,6 +8,8 @@ import ( "github.com/lxc/lxd/lxd/db/cluster" "github.com/lxc/lxd/lxd/db/query" + "github.com/lxc/lxd/shared/osarch" + "github.com/mattn/go-sqlite3" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -583,3 +585,38 @@ INSERT INTO instances VALUES (2, 1, 'eoan/snap', 2, 1, 0, ?, 0, ?, 'Eoan Ermine require.NoError(t, err) assert.Equal(t, config, map[string]string{"k": "v"}) } + +func TestUpdateFromV19(t *testing.T) { + schema := cluster.Schema() + db, err := schema.ExerciseUpdate(20, func(db *sql.DB) { + // Insert a node. + _, err := db.Exec( + "INSERT INTO nodes VALUES (1, 'n1', '', '1.2.3.4:666', 1, 32, ?, 0)", + time.Now()) + require.NoError(t, err) + }) + require.NoError(t, err) + defer db.Close() + + expectedArch, err := osarch.ArchitectureGetLocalID() + require.NoError(t, err) + + row := db.QueryRow("SELECT arch FROM nodes") + arch := 0 + err = row.Scan(&arch) + require.NoError(t, err) + + assert.Equal(t, expectedArch, arch) + + // Trying to create a row without specififying the architecture results + // in an error. + _, err = db.Exec(` +INSERT INTO nodes(id, name, description, address, schema, api_extensions, heartbeat, pending) +VALUES (2, 'n2', '', '2.2.3.4:666', 1, 32, ?, 0)`, time.Now()) + if err == nil { + t.Fatal("expected insertion to fail") + } + sqliteErr, ok := err.(sqlite3.Error) + require.True(t, ok) + assert.Equal(t, sqliteErr.Code, sqlite3.ErrConstraint) +} diff --git a/shared/osarch/architectures.go b/shared/osarch/architectures.go index 2956acfb0a..84d9f68568 100644 --- a/shared/osarch/architectures.go +++ b/shared/osarch/architectures.go @@ -105,3 +105,16 @@ func ArchitecturePersonalities(arch int) ([]int, error) { return []int{}, fmt.Errorf("Architecture isn't supported: %d", arch) } + +// ArchitectureGetLocalID returns the local hardware architecture ID +func ArchitectureGetLocalID() (int, error) { + name, err := ArchitectureGetLocal() + if err != nil { + return -1, err + } + id, err := ArchitectureId(name) + if err != nil { + return -1, err + } + return id, nil +} From 94b9c5f5623a22f446d72e78cc3ad0eb2d6eeec6 Mon Sep 17 00:00:00 2001 From: Free Ekanayaka <free.ekanay...@canonical.com> Date: Wed, 27 Nov 2019 11:03:18 +0000 Subject: [PATCH 2/2] Add NodeAddWithArch() method to add a node with a specific arch Signed-off-by: Free Ekanayaka <free.ekanay...@canonical.com> --- lxd/cluster/membership.go | 10 +++++++++- lxd/db/node.go | 18 +++++++++++++++--- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/lxd/cluster/membership.go b/lxd/cluster/membership.go index fe582040db..b572400553 100644 --- a/lxd/cluster/membership.go +++ b/lxd/cluster/membership.go @@ -18,6 +18,7 @@ import ( "github.com/lxc/lxd/shared/api" "github.com/lxc/lxd/shared/log15" "github.com/lxc/lxd/shared/logger" + "github.com/lxc/lxd/shared/osarch" "github.com/lxc/lxd/shared/version" "github.com/pkg/errors" ) @@ -172,8 +173,15 @@ func Accept(state *state.State, gateway *Gateway, name, address string, schema, return err } + // TODO: when fixing #6380 this should be replaced with the + // actual architecture of the foreign node. + arch, err := osarch.ArchitectureGetLocalID() + if err != nil { + return err + } + // Add the new node - id, err := tx.NodeAdd(name, address) + id, err := tx.NodeAddWithArch(name, address, arch) if err != nil { return errors.Wrap(err, "Failed to insert new node into the database") } diff --git a/lxd/db/node.go b/lxd/db/node.go index 7da9782955..b38d48d920 100644 --- a/lxd/db/node.go +++ b/lxd/db/node.go @@ -11,6 +11,7 @@ import ( "github.com/lxc/lxd/lxd/db/cluster" "github.com/lxc/lxd/lxd/db/query" "github.com/lxc/lxd/lxd/util" + "github.com/lxc/lxd/shared/osarch" "github.com/lxc/lxd/shared/version" "github.com/pkg/errors" ) @@ -307,10 +308,21 @@ func (c *ClusterTx) nodes(pending bool, where string, args ...interface{}) ([]No } // NodeAdd adds a node to the current list of LXD nodes that are part of the -// cluster. It returns the ID of the newly inserted row. +// cluster. The node's architecture will be the architecture of the machine the +// method is being run on. It returns the ID of the newly inserted row. func (c *ClusterTx) NodeAdd(name string, address string) (int64, error) { - columns := []string{"name", "address", "schema", "api_extensions"} - values := []interface{}{name, address, cluster.SchemaVersion, version.APIExtensionsCount()} + arch, err := osarch.ArchitectureGetLocalID() + if err != nil { + return -1, err + } + return c.NodeAddWithArch(name, address, arch) +} + +// NodeAddWithArch is the same as NodeAdd, but lets setting the node +// architecture explicitely. +func (c *ClusterTx) NodeAddWithArch(name string, address string, arch int) (int64, error) { + columns := []string{"name", "address", "schema", "api_extensions", "arch"} + values := []interface{}{name, address, cluster.SchemaVersion, version.APIExtensionsCount(), arch} return query.UpsertObject(c.tx, "nodes", columns, values) }
_______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel