The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/6706
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) === Supersedes #6380.
From f3bd7c13964ca90f8510fbff7eeb08e954a5501b Mon Sep 17 00:00:00 2001 From: Dinah Baum <dinahbaum...@gmail.com> Date: Fri, 6 Dec 2019 13:18:41 -0600 Subject: [PATCH 1/5] api: Add clustering_architecture extension Signed-off-by: Free Ekanayaka <free.ekanay...@canonical.com> --- doc/api-extensions.md | 4 ++++ shared/version/api.go | 1 + 2 files changed, 5 insertions(+) diff --git a/doc/api-extensions.md b/doc/api-extensions.md index 632ce186ac..f8daa82a8a 100644 --- a/doc/api-extensions.md +++ b/doc/api-extensions.md @@ -889,3 +889,7 @@ Add virtual machine support. ## image\_profiles Allows a list of profiles to be applied to an image when launching a new container. + +## clustering_architecture +This adds a new `architecture` attribute to cluster members which indicates a cluster +member's architecture. diff --git a/shared/version/api.go b/shared/version/api.go index 931606c8f0..ca419947db 100644 --- a/shared/version/api.go +++ b/shared/version/api.go @@ -180,6 +180,7 @@ var APIExtensions = []string{ "container_disk_ceph", "virtual-machines", "image_profiles", + "clustering_architecture", } // APIExtensionsCount returns the number of available API extensions. From 3ff31f78b584970ccb80624e4f35af0fd1e44374 Mon Sep 17 00:00:00 2001 From: Dinah Baum <dinahbaum...@gmail.com> Date: Thu, 5 Dec 2019 01:37:28 -0600 Subject: [PATCH 2/5] shared/api: Add Architecture to ClusterMember Signed-off-by: Free Ekanayaka <free.ekanay...@canonical.com> --- shared/api/cluster.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/shared/api/cluster.go b/shared/api/cluster.go index c773929c8d..94ac6a5016 100644 --- a/shared/api/cluster.go +++ b/shared/api/cluster.go @@ -60,4 +60,7 @@ type ClusterMember struct { // API extension: clustering_roles Roles []string `json:"roles" yaml:"roles"` + + // API extension: clustering_architecture + Architecture string `json:"architecture" yaml:"architecture"` } From 13670ca842939433d6a395cbf3ff18ed4e0c6175 Mon Sep 17 00:00:00 2001 From: Dinah Baum <dinahbaum...@gmail.com> Date: Thu, 5 Dec 2019 01:35:20 -0600 Subject: [PATCH 3/5] lxd/db: Add Architecture to NodeInfo Signed-off-by: Dinah Baum <dinahbaum...@gmail.com> --- lxd/db/node.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lxd/db/node.go b/lxd/db/node.go index 7bbf423f3a..b8dc908d32 100644 --- a/lxd/db/node.go +++ b/lxd/db/node.go @@ -37,6 +37,7 @@ type NodeInfo struct { APIExtensions int // Number of API extensions of the LXD code running on the node Heartbeat time.Time // Timestamp of the last heartbeat Roles []string // List of cluster roles + Architecture int // Node architecture } // IsOffline returns true if the last successful heartbeat time of the node is @@ -270,6 +271,7 @@ func (c *ClusterTx) nodes(pending bool, where string, args ...interface{}) ([]No &nodes[i].Schema, &nodes[i].APIExtensions, &nodes[i].Heartbeat, + &nodes[i].Architecture, } } if pending { @@ -279,7 +281,7 @@ func (c *ClusterTx) nodes(pending bool, where string, args ...interface{}) ([]No } // Get the node entries - sql = "SELECT id, name, address, description, schema, api_extensions, heartbeat FROM nodes WHERE pending=?" + sql = "SELECT id, name, address, description, schema, api_extensions, heartbeat, arch FROM nodes WHERE pending=?" if where != "" { sql += fmt.Sprintf("AND %s ", where) } @@ -584,6 +586,7 @@ func (c *ClusterTx) NodeWithLeastContainers() (string, error) { if err != nil { return "", errors.Wrap(err, "failed to get offline threshold") } + nodes, err := c.Nodes() if err != nil { return "", errors.Wrap(err, "failed to get current nodes") From 5862ac84f864bf43fba7709ae89c87389fb5b0cf Mon Sep 17 00:00:00 2001 From: Free Ekanayaka <free.ekanay...@canonical.com> Date: Tue, 14 Jan 2020 12:12:00 +0000 Subject: [PATCH 4/5] lxd/cluster: Track member architecture Signed-off-by: Free Ekanayaka <free.ekanay...@canonical.com> --- lxd/api_cluster.go | 10 +++++++++- lxd/cluster/heartbeat_test.go | 3 ++- lxd/cluster/membership.go | 9 +-------- lxd/cluster/membership_test.go | 7 ++++--- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/lxd/api_cluster.go b/lxd/api_cluster.go index bf96d39774..f37f8bf3ab 100644 --- a/lxd/api_cluster.go +++ b/lxd/api_cluster.go @@ -26,6 +26,7 @@ import ( "github.com/lxc/lxd/shared" "github.com/lxc/lxd/shared/api" "github.com/lxc/lxd/shared/logger" + "github.com/lxc/lxd/shared/osarch" "github.com/lxc/lxd/shared/version" ) @@ -807,6 +808,11 @@ func clusterAcceptMember( name, address string, schema, apiExt int, pools []api.StoragePool, networks []api.Network) (*internalClusterPostAcceptResponse, error) { + architecture, err := osarch.ArchitectureGetLocalID() + if err != nil { + return nil, err + } + req := internalClusterPostAcceptRequest{ Name: name, Address: address, @@ -814,6 +820,7 @@ func clusterAcceptMember( API: apiExt, StoragePools: pools, Networks: networks, + Architecture: architecture, } info := &internalClusterPostAcceptResponse{} resp, _, err := client.RawQuery("POST", "/internal/cluster/accept", req, "") @@ -1047,7 +1054,7 @@ func internalClusterPostAccept(d *Daemon, r *http.Request) response.Response { return response.SmartError(err) } - nodes, err := cluster.Accept(d.State(), d.gateway, req.Name, req.Address, req.Schema, req.API) + nodes, err := cluster.Accept(d.State(), d.gateway, req.Name, req.Address, req.Schema, req.API, req.Architecture) if err != nil { return response.BadRequest(err) } @@ -1070,6 +1077,7 @@ type internalClusterPostAcceptRequest struct { API int `json:"api" yaml:"api"` StoragePools []api.StoragePool `json:"storage_pools" yaml:"storage_pools"` Networks []api.Network `json:"networks" yaml:"networks"` + Architecture int `json:"architecture" yaml:"architecture"` } // A Response for the /internal/cluster/accept endpoint. diff --git a/lxd/cluster/heartbeat_test.go b/lxd/cluster/heartbeat_test.go index 4b4e247dc0..b310e71b18 100644 --- a/lxd/cluster/heartbeat_test.go +++ b/lxd/cluster/heartbeat_test.go @@ -12,6 +12,7 @@ import ( "github.com/lxc/lxd/lxd/db" "github.com/lxc/lxd/lxd/state" "github.com/lxc/lxd/shared" + "github.com/lxc/lxd/shared/osarch" "github.com/lxc/lxd/shared/version" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -144,7 +145,7 @@ func (f *heartbeatFixture) Grow() *cluster.Gateway { name := address nodes, err := cluster.Accept( - targetState, target, name, address, cluster.SchemaVersion, len(version.APIExtensions)) + targetState, target, name, address, cluster.SchemaVersion, len(version.APIExtensions), osarch.ARCH_64BIT_INTEL_X86) require.NoError(f.t, err) err = cluster.Join(state, gateway, target.Cert(), name, nodes) diff --git a/lxd/cluster/membership.go b/lxd/cluster/membership.go index f2bd48eb72..9f447e41e4 100644 --- a/lxd/cluster/membership.go +++ b/lxd/cluster/membership.go @@ -156,7 +156,7 @@ func Bootstrap(state *state.State, gateway *Gateway, name string) error { // // Return an updated list raft database nodes (possibly including the newly // accepted node). -func Accept(state *state.State, gateway *Gateway, name, address string, schema, api int) ([]db.RaftNode, error) { +func Accept(state *state.State, gateway *Gateway, name, address string, schema, api, arch int) ([]db.RaftNode, error) { // Check parameters if name == "" { return nil, fmt.Errorf("node name must not be empty") @@ -173,13 +173,6 @@ 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.NodeAddWithArch(name, address, arch) if err != nil { diff --git a/lxd/cluster/membership_test.go b/lxd/cluster/membership_test.go index 5462f7fc3e..bf7934b105 100644 --- a/lxd/cluster/membership_test.go +++ b/lxd/cluster/membership_test.go @@ -13,6 +13,7 @@ import ( "github.com/lxc/lxd/lxd/db" "github.com/lxc/lxd/lxd/state" "github.com/lxc/lxd/shared" + "github.com/lxc/lxd/shared/osarch" "github.com/lxc/lxd/shared/version" "github.com/mpvl/subtest" "github.com/stretchr/testify/assert" @@ -204,7 +205,7 @@ func TestAccept_UnmetPreconditions(t *testing.T) { c.setup(&membershipFixtures{t: t, state: state}) - _, err := cluster.Accept(state, gateway, c.name, c.address, c.schema, c.api) + _, err := cluster.Accept(state, gateway, c.name, c.address, c.schema, c.api, osarch.ARCH_64BIT_INTEL_X86) assert.EqualError(t, err, c.error) }) } @@ -224,7 +225,7 @@ func TestAccept(t *testing.T) { f.ClusterNode("1.2.3.4:666") nodes, err := cluster.Accept( - state, gateway, "buzz", "5.6.7.8:666", cluster.SchemaVersion, len(version.APIExtensions)) + state, gateway, "buzz", "5.6.7.8:666", cluster.SchemaVersion, len(version.APIExtensions), osarch.ARCH_64BIT_INTEL_X86) assert.NoError(t, err) assert.Len(t, nodes, 2) assert.Equal(t, int64(1), nodes[0].ID) @@ -306,7 +307,7 @@ func TestJoin(t *testing.T) { // Accept the joining node. raftNodes, err := cluster.Accept( - targetState, targetGateway, "rusp", address, cluster.SchemaVersion, len(version.APIExtensions)) + targetState, targetGateway, "rusp", address, cluster.SchemaVersion, len(version.APIExtensions), osarch.ARCH_64BIT_INTEL_X86) require.NoError(t, err) // Actually join the cluster. From 777660eb18b8aedd9aee6bc6600549716799ff15 Mon Sep 17 00:00:00 2001 From: Dinah Baum <dinahbaum...@gmail.com> Date: Thu, 5 Dec 2019 01:33:20 -0600 Subject: [PATCH 5/5] lxc/cluster: Add architecture column in list Signed-off-by: Free Ekanayaka <free.ekanay...@canonical.com> --- lxc/cluster.go | 3 ++- lxd/cluster/membership.go | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lxc/cluster.go b/lxc/cluster.go index 6b0b01d879..6d013ca54e 100644 --- a/lxc/cluster.go +++ b/lxc/cluster.go @@ -117,7 +117,7 @@ func (c *cmdClusterList) Run(cmd *cobra.Command, args []string) error { if member.Database { database = "YES" } - line := []string{member.ServerName, member.URL, database, strings.ToUpper(member.Status), member.Message} + line := []string{member.ServerName, member.URL, database, strings.ToUpper(member.Status), member.Message, member.Architecture} data = append(data, line) } sort.Sort(byName(data)) @@ -128,6 +128,7 @@ func (c *cmdClusterList) Run(cmd *cobra.Command, args []string) error { i18n.G("DATABASE"), i18n.G("STATE"), i18n.G("MESSAGE"), + i18n.G("ARCHITECTURE"), } return utils.RenderTable(c.flagFormat, header, data, members) diff --git a/lxd/cluster/membership.go b/lxd/cluster/membership.go index 9f447e41e4..c857bb7788 100644 --- a/lxd/cluster/membership.go +++ b/lxd/cluster/membership.go @@ -811,6 +811,11 @@ func List(state *state.State) ([]api.ClusterMember, error) { result[i].URL = fmt.Sprintf("https://%s", node.Address) result[i].Database = shared.StringInSlice(string(db.ClusterRoleDatabase), node.Roles) result[i].Roles = node.Roles + result[i].Architecture, err = osarch.ArchitectureName(node.Architecture) + if err != nil { + return nil, err + } + if node.IsOffline(offlineThreshold) { result[i].Status = "Offline" result[i].Message = fmt.Sprintf(
_______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel