The following pull request was submitted through Github.
It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/7599

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) ===

From 6ca22a1973597afb2e5b27212489c90c69d7b7d4 Mon Sep 17 00:00:00 2001
From: Free Ekanayaka <free.ekanay...@canonical.com>
Date: Tue, 30 Jun 2020 08:47:13 +0200
Subject: [PATCH 1/2] lxd/db: Drop ClusterRoleDatabase records from the
 database

Signed-off-by: Free Ekanayaka <free.ekanay...@canonical.com>
---
 lxd/db/cluster/schema.go |  2 +-
 lxd/db/cluster/update.go | 11 +++++++++++
 lxd/db/node.go           |  8 +++++---
 3 files changed, 17 insertions(+), 4 deletions(-)

diff --git a/lxd/db/cluster/schema.go b/lxd/db/cluster/schema.go
index 201ed4e1eb..1d6e58c98d 100644
--- a/lxd/db/cluster/schema.go
+++ b/lxd/db/cluster/schema.go
@@ -565,5 +565,5 @@ CREATE TABLE storage_volumes_snapshots_config (
     UNIQUE (storage_volume_snapshot_id, key)
 );
 
-INSERT INTO schema (version, updated_at) VALUES (31, strftime("%s"))
+INSERT INTO schema (version, updated_at) VALUES (32, strftime("%s"))
 `
diff --git a/lxd/db/cluster/update.go b/lxd/db/cluster/update.go
index b6d5d4b1fe..c1ce123a16 100644
--- a/lxd/db/cluster/update.go
+++ b/lxd/db/cluster/update.go
@@ -68,6 +68,17 @@ var updates = map[int]schema.Update{
        29: updateFromV28,
        30: updateFromV29,
        31: updateFromV30,
+       32: updateFromV31,
+}
+
+// Drop database role from the nodes_roles table, since we now rely on the raft
+// log instead.
+func updateFromV31(tx *sql.Tx) error {
+       _, err := tx.Exec("DELETE FROM nodes_roles WHERE role = 0")
+       if err != nil {
+               return err
+       }
+       return nil
 }
 
 // Add content type field to storage volumes
diff --git a/lxd/db/node.go b/lxd/db/node.go
index 1e22920877..e0a2c30f41 100644
--- a/lxd/db/node.go
+++ b/lxd/db/node.go
@@ -25,9 +25,11 @@ type ClusterRole string
 const ClusterRoleDatabase = ClusterRole("database")
 
 // ClusterRoles maps role ids into human-readable names.
-var ClusterRoles = map[int]ClusterRole{
-       0: ClusterRoleDatabase,
-}
+//
+// Note: the database role is currently stored directly in the raft
+// configuration which acts as single source of truth for it. This map should
+// only contain LXD-specific cluster roles.
+var ClusterRoles = map[int]ClusterRole{}
 
 // NodeInfo holds information about a single LXD instance in a cluster.
 type NodeInfo struct {

From 60347fb5999eb0368c2277a1efd55e4f8120fe16 Mon Sep 17 00:00:00 2001
From: Free Ekanayaka <free.ekanay...@canonical.com>
Date: Tue, 30 Jun 2020 08:48:15 +0200
Subject: [PATCH 2/2] lxd/cluster: Fetch database role information directly
 from raft

Signed-off-by: Free Ekanayaka <free.ekanay...@canonical.com>
---
 lxd/api_cluster.go             |  4 +-
 lxd/cluster/membership.go      | 72 +++++++++++++++++-----------------
 lxd/cluster/membership_test.go |  2 +-
 lxd/patches.go                 | 48 -----------------------
 4 files changed, 39 insertions(+), 87 deletions(-)

diff --git a/lxd/api_cluster.go b/lxd/api_cluster.go
index 527da84e7b..fbc61dd979 100644
--- a/lxd/api_cluster.go
+++ b/lxd/api_cluster.go
@@ -840,7 +840,7 @@ func clusterAcceptMember(
 func clusterNodesGet(d *Daemon, r *http.Request) response.Response {
        recursion := util.IsRecursionRequest(r)
 
-       nodes, err := cluster.List(d.State())
+       nodes, err := cluster.List(d.State(), d.gateway)
        if err != nil {
                return response.SmartError(err)
        }
@@ -863,7 +863,7 @@ func clusterNodesGet(d *Daemon, r *http.Request) 
response.Response {
 func clusterNodeGet(d *Daemon, r *http.Request) response.Response {
        name := mux.Vars(r)["name"]
 
-       nodes, err := cluster.List(d.State())
+       nodes, err := cluster.List(d.State(), d.gateway)
        if err != nil {
                return response.SmartError(err)
        }
diff --git a/lxd/cluster/membership.go b/lxd/cluster/membership.go
index dff1e3f0ef..1d260d4295 100644
--- a/lxd/cluster/membership.go
+++ b/lxd/cluster/membership.go
@@ -81,12 +81,6 @@ func Bootstrap(state *state.State, gateway *Gateway, name 
string) error {
                        return errors.Wrap(err, "failed to update cluster node")
                }
 
-               // Update our role list.
-               err = tx.CreateNodeRole(1, db.ClusterRoleDatabase)
-               if err != nil {
-                       return errors.Wrapf(err, "Failed to add database role 
for the node")
-               }
-
                return nil
        })
        if err != nil {
@@ -446,14 +440,6 @@ func Join(state *state.State, gateway *Gateway, cert 
*shared.CertInfo, name stri
                        return errors.Wrapf(err, "failed to unmark the node as 
pending")
                }
 
-               // Update our role list if needed.
-               if info.Role == db.RaftVoter {
-                       err = tx.CreateNodeRole(node.ID, db.ClusterRoleDatabase)
-                       if err != nil {
-                               return errors.Wrapf(err, "Failed to add 
database role for the node")
-                       }
-               }
-
                // Generate partial heartbeat request containing just a raft 
node list.
                notifyNodesUpdate(raftNodes, info.ID, cert)
 
@@ -553,14 +539,6 @@ func Rebalance(state *state.State, gateway *Gateway) 
(string, []db.RaftNode, err
                                if err != nil {
                                        return "", nil, errors.Wrap(err, 
"Failed to demote offline node")
                                }
-                               if info.Role == db.RaftVoter {
-                                       err := 
state.Cluster.Transaction(func(tx *db.ClusterTx) error {
-                                               return 
tx.RemoveNodeRole(node.ID, db.ClusterRoleDatabase)
-                                       })
-                                       if err != nil {
-                                               return "", nil, 
errors.Wrap(err, "Failed to update node role")
-                                       }
-                               }
                                currentRaftNodes[i].Role = db.RaftSpare
                        }
                        continue
@@ -762,19 +740,9 @@ assign:
 
        gateway.info = info
 
-       // Unlock regular access to our cluster database and add the database 
role.
+       // Unlock regular access to our cluster database.
        err = transactor(func(tx *db.ClusterTx) error {
-               var f func(id int64, role db.ClusterRole) error
-               if info.Role == db.RaftVoter {
-                       f = tx.CreateNodeRole
-               } else {
-                       f = tx.RemoveNodeRole
-               }
-               err = f(state.Cluster.GetNodeID(), db.ClusterRoleDatabase)
-               if err != nil {
-                       return errors.Wrapf(err, "Failed to change role for the 
node")
-               }
-               return err
+               return nil
        })
        if err != nil {
                return errors.Wrap(err, "Cluster database initialization 
failed")
@@ -930,7 +898,7 @@ func Purge(cluster *db.Cluster, name string) error {
 }
 
 // List the nodes of the cluster.
-func List(state *state.State) ([]api.ClusterMember, error) {
+func List(state *state.State, gateway *Gateway) ([]api.ClusterMember, error) {
        var err error
        var nodes []db.NodeInfo
        var offlineThreshold time.Duration
@@ -952,14 +920,46 @@ func List(state *state.State) ([]api.ClusterMember, 
error) {
                return nil, err
        }
 
+       store := gateway.NodeStore()
+       dial := gateway.DialFunc()
+
+       ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
+       defer cancel()
+
+       cli, err := client.FindLeader(ctx, store, client.WithDialFunc(dial))
+       if err != nil {
+               return nil, err
+       }
+       defer cli.Close()
+
+       raftNodes, err := cli.Cluster(ctx)
+       if err != nil {
+               return nil, err
+       }
+       raftRoles := map[string]client.NodeRole{} // Address to role
+       for _, node := range raftNodes {
+               address := node.Address
+               if address == "1" {
+                       addr, err := gateway.raftAddress(1)
+                       if err != nil {
+                               return nil, err
+                       }
+                       address = string(addr)
+               }
+               raftRoles[address] = node.Role
+       }
+
        result := make([]api.ClusterMember, len(nodes))
        now := time.Now()
        version := nodes[0].Version()
        for i, node := range nodes {
                result[i].ServerName = node.Name
                result[i].URL = fmt.Sprintf("https://%s";, node.Address)
-               result[i].Database = 
shared.StringInSlice(string(db.ClusterRoleDatabase), node.Roles)
+               result[i].Database = raftRoles[node.Address] == db.RaftVoter
                result[i].Roles = node.Roles
+               if result[i].Database {
+                       result[i].Roles = append(result[i].Roles, 
string(db.ClusterRoleDatabase))
+               }
                result[i].Architecture, err = 
osarch.ArchitectureName(node.Architecture)
                if err != nil {
                        return nil, err
diff --git a/lxd/cluster/membership_test.go b/lxd/cluster/membership_test.go
index 63826b5f14..8013edba01 100644
--- a/lxd/cluster/membership_test.go
+++ b/lxd/cluster/membership_test.go
@@ -327,7 +327,7 @@ func TestJoin(t *testing.T) {
        assert.Equal(t, db.RaftStandBy, raftNodes[1].Role)
 
        // The List function returns all nodes in the cluster.
-       nodes, err := cluster.List(state)
+       nodes, err := cluster.List(state, gateway)
        require.NoError(t, err)
        assert.Len(t, nodes, 2)
        assert.Equal(t, "Online", nodes[0].Status)
diff --git a/lxd/patches.go b/lxd/patches.go
index 87ff3d8262..2cbf548307 100644
--- a/lxd/patches.go
+++ b/lxd/patches.go
@@ -3424,54 +3424,6 @@ func patchStorageApiUpdateContainerSnapshots(name 
string, d *Daemon) error {
 }
 
 func patchClusteringAddRoles(name string, d *Daemon) error {
-       addresses := []string{}
-       err := d.State().Node.Transaction(func(tx *db.NodeTx) error {
-               nodes, err := tx.GetRaftNodes()
-               if err != nil {
-                       return errors.Wrap(err, "Failed to fetch current raft 
nodes")
-               }
-
-               for _, node := range nodes {
-                       addresses = append(addresses, node.Address)
-               }
-
-               return nil
-       })
-       if err != nil {
-               return err
-       }
-
-       var nodes []db.NodeInfo
-       err = d.State().Cluster.Transaction(func(tx *db.ClusterTx) error {
-               nodes, err = tx.GetNodes()
-               if err != nil {
-                       return err
-               }
-
-               for _, node := range nodes {
-                       if node.Address == "0.0.0.0" {
-                               continue
-                       }
-
-                       if shared.StringInSlice(node.Address, addresses) && 
!shared.StringInSlice(string(db.ClusterRoleDatabase), node.Roles) {
-                               err = tx.CreateNodeRole(node.ID, 
db.ClusterRoleDatabase)
-                               if err != nil {
-                                       return err
-                               }
-                       } else if 
shared.StringInSlice(string(db.ClusterRoleDatabase), node.Roles) {
-                               err = tx.RemoveNodeRole(node.ID, 
db.ClusterRoleDatabase)
-                               if err != nil {
-                                       return err
-                               }
-                       }
-               }
-
-               return nil
-       })
-       if err != nil {
-               return err
-       }
-
        return nil
 }
 
_______________________________________________
lxc-devel mailing list
lxc-devel@lists.linuxcontainers.org
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to