[lxc-devel] [lxd/master] Network: Adds network node state to improve clustered network creation process
tomponline on Github
lxc-bot at linuxcontainers.org
Tue Nov 24 09:08:34 UTC 2020
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 552 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20201124/005a8189/attachment-0001.bin>
-------------- next part --------------
From 94f106b017fbb3c22805898981cbeace5d67b4fe Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Fri, 20 Nov 2020 11:44:34 +0000
Subject: [PATCH 01/37] lxd/storage/pools/utils: Updates comment and error for
storagePoolCreateLocal
Makes more accurate.
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/storage_pools_utils.go | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/lxd/storage_pools_utils.go b/lxd/storage_pools_utils.go
index 57cc08b74f..6ea29eb5c2 100644
--- a/lxd/storage_pools_utils.go
+++ b/lxd/storage_pools_utils.go
@@ -3,6 +3,8 @@ package main
import (
"fmt"
+ "github.com/pkg/errors"
+
"github.com/lxc/lxd/lxd/state"
storagePools "github.com/lxc/lxd/lxd/storage"
"github.com/lxc/lxd/shared"
@@ -95,7 +97,7 @@ func storagePoolCreateGlobal(state *state.State, req api.StoragePoolsPost) error
return nil
}
-// This performs all non-db related work needed to create the pool.
+// This performs local pool setup and updates DB record if config was changed during pool setup.
func storagePoolCreateLocal(state *state.State, id int64, req api.StoragePoolsPost, isNotification bool) (map[string]string, error) {
tryUndo := true
@@ -145,7 +147,7 @@ func storagePoolCreateLocal(state *state.State, id int64, req api.StoragePoolsPo
// Create the database entry for the storage pool.
err = state.Cluster.UpdateStoragePool(req.Name, req.Description, updatedConfig)
if err != nil {
- return nil, fmt.Errorf("Error inserting %s into database: %s", req.Name, err)
+ return nil, errors.Wrapf(err, "Error updating storage pool config after local create for %q", req.Name)
}
}
From ecc1cdb3022219c536aba6b02b2191e0fcf059a5 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Fri, 20 Nov 2020 11:46:21 +0000
Subject: [PATCH 02/37] lxd/storage/pools: Error quoting
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/storage_pools.go | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/lxd/storage_pools.go b/lxd/storage_pools.go
index c631d7cbc7..2e3631e676 100644
--- a/lxd/storage_pools.go
+++ b/lxd/storage_pools.go
@@ -182,7 +182,7 @@ func storagePoolsPost(d *Daemon, r *http.Request) response.Response {
// storage config are the ones in StoragePoolNodeConfigKeys.
for key := range req.Config {
if !shared.StringInSlice(key, db.StoragePoolNodeConfigKeys) {
- return response.SmartError(fmt.Errorf("Config key '%s' may not be used as node-specific key", key))
+ return response.SmartError(fmt.Errorf("Config key %q may not be used as node-specific key", key))
}
}
@@ -196,7 +196,7 @@ func storagePoolsPost(d *Daemon, r *http.Request) response.Response {
})
if err != nil {
if err == db.ErrAlreadyDefined {
- return response.BadRequest(fmt.Errorf("The storage pool already defined on node %s", targetNode))
+ return response.BadRequest(fmt.Errorf("The storage pool already defined on node %q", targetNode))
}
return response.SmartError(err)
@@ -209,7 +209,7 @@ func storagePoolsPostCluster(d *Daemon, req api.StoragePoolsPost) error {
// Check that no node-specific config key has been defined.
for key := range req.Config {
if shared.StringInSlice(key, db.StoragePoolNodeConfigKeys) {
- return fmt.Errorf("Config key '%s' is node-specific", key)
+ return fmt.Errorf("Config key %q is node-specific", key)
}
}
@@ -525,7 +525,7 @@ func storagePoolPatch(d *Daemon, r *http.Request) response.Response {
func storagePoolValidateClusterConfig(reqConfig map[string]string) error {
for key := range reqConfig {
if shared.StringInSlice(key, db.StoragePoolNodeConfigKeys) {
- return fmt.Errorf("node-specific config key %s can't be changed", key)
+ return fmt.Errorf("Node-specific config key %q can't be changed", key)
}
}
return nil
From 43d0cba9443e07e7f828b9495e94ae5684db4e7a Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Fri, 20 Nov 2020 14:37:47 +0000
Subject: [PATCH 03/37] lxd/db/cluster: Adds state column to
storage_pools_nodes and networks_nodes table and set existing rows to state=1
(created)
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/db/cluster/schema.go | 4 +++-
lxd/db/cluster/update.go | 13 +++++++++++++
2 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/lxd/db/cluster/schema.go b/lxd/db/cluster/schema.go
index 3e9227899b..8d0c38bdb8 100644
--- a/lxd/db/cluster/schema.go
+++ b/lxd/db/cluster/schema.go
@@ -299,6 +299,7 @@ CREATE TABLE "networks_nodes" (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
network_id INTEGER NOT NULL,
node_id INTEGER NOT NULL,
+ state INTEGER NOT NULL DEFAULT 0,
UNIQUE (network_id, node_id),
FOREIGN KEY (network_id) REFERENCES "networks" (id) ON DELETE CASCADE,
FOREIGN KEY (node_id) REFERENCES nodes (id) ON DELETE CASCADE
@@ -489,6 +490,7 @@ CREATE TABLE storage_pools_nodes (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
storage_pool_id INTEGER NOT NULL,
node_id INTEGER NOT NULL,
+ state INTEGER NOT NULL DEFAULT 0,
UNIQUE (storage_pool_id, node_id),
FOREIGN KEY (storage_pool_id) REFERENCES storage_pools (id) ON DELETE CASCADE,
FOREIGN KEY (node_id) REFERENCES nodes (id) ON DELETE CASCADE
@@ -589,5 +591,5 @@ CREATE TABLE storage_volumes_snapshots_config (
UNIQUE (storage_volume_snapshot_id, key)
);
-INSERT INTO schema (version, updated_at) VALUES (39, strftime("%s"))
+INSERT INTO schema (version, updated_at) VALUES (40, strftime("%s"))
`
diff --git a/lxd/db/cluster/update.go b/lxd/db/cluster/update.go
index 750097c693..cfb300b95d 100644
--- a/lxd/db/cluster/update.go
+++ b/lxd/db/cluster/update.go
@@ -76,6 +76,19 @@ var updates = map[int]schema.Update{
37: updateFromV36,
38: updateFromV37,
39: updateFromV38,
+ 40: updateFromV39,
+}
+
+// Add state column to storage_pools_nodes and networks_nodes tables. Set existing row's state to 1 ("created").
+func updateFromV39(tx *sql.Tx) error {
+ stmt := `
+ ALTER TABLE storage_pools_nodes ADD COLUMN state INTEGER NOT NULL DEFAULT 0;
+ UPDATE storage_pools_nodes SET state = 1;
+ ALTER TABLE networks_nodes ADD COLUMN state INTEGER NOT NULL DEFAULT 0;
+ UPDATE networks_nodes SET state = 1;
+ `
+ _, err := tx.Exec(stmt)
+ return err
}
// Add storage_volumes_backups table.
From 20283679c22da495d2090fa7806c193a49016c31 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 23 Nov 2020 11:17:12 +0000
Subject: [PATCH 04/37] lxd/db/networks: Populate node state column in
NetworkNodeJoin
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/db/networks.go | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/lxd/db/networks.go b/lxd/db/networks.go
index b2549cabd5..c0fecfc5ce 100644
--- a/lxd/db/networks.go
+++ b/lxd/db/networks.go
@@ -171,8 +171,9 @@ func (c *ClusterTx) CreateNetworkConfig(networkID, nodeID int64, config map[stri
// assume that the relevant network has already been created on the joining node,
// and we just need to track it.
func (c *ClusterTx) NetworkNodeJoin(networkID, nodeID int64) error {
- columns := []string{"network_id", "node_id"}
- values := []interface{}{networkID, nodeID}
+ columns := []string{"network_id", "node_id", "state"}
+ // Create network node with "created" state as we expect the network to already be setup.
+ values := []interface{}{networkID, nodeID, networkCreated}
_, err := query.UpsertObject(c.tx, "networks_nodes", columns, values)
return err
}
From cd243854421b89c79611273020235a28139c49bf Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 23 Nov 2020 11:17:36 +0000
Subject: [PATCH 05/37] lxd/db/networks: Populate node state column in
CreatePendingNetwork
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/db/networks.go | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/lxd/db/networks.go b/lxd/db/networks.go
index c0fecfc5ce..f4964a99da 100644
--- a/lxd/db/networks.go
+++ b/lxd/db/networks.go
@@ -299,9 +299,9 @@ func (c *ClusterTx) CreatePendingNetwork(node string, projectName string, name s
return ErrAlreadyDefined
}
- // Insert the node-specific configuration.
- columns := []string{"network_id", "node_id"}
- values := []interface{}{networkID, nodeInfo.ID}
+ // Insert the node-specific configuration with state "pending".
+ columns := []string{"network_id", "node_id", "state"}
+ values := []interface{}{networkID, nodeInfo.ID, networkPending}
_, err = query.UpsertObject(c.tx, "networks_nodes", columns, values)
if err != nil {
return err
From 726620ad3e975a8c458914effb3361ef8f1eedfb Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 23 Nov 2020 11:18:01 +0000
Subject: [PATCH 06/37] lxd/db/networks: Adds networkNodeState and
NetworkNodeCreated functiond
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/db/networks.go | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/lxd/db/networks.go b/lxd/db/networks.go
index f4964a99da..ba74ef7d72 100644
--- a/lxd/db/networks.go
+++ b/lxd/db/networks.go
@@ -341,6 +341,29 @@ func (c *ClusterTx) networkState(project string, name string, state int) error {
return nil
}
+// NetworkNodeCreated sets the state of the given network for the local member to "Created".
+func (c *ClusterTx) NetworkNodeCreated(networkID int64) error {
+ return c.networkNodeState(networkID, networkCreated)
+}
+
+// networkNodeState updates the network member state for the local member and specified network ID.
+func (c *ClusterTx) networkNodeState(networkID int64, state int) error {
+ stmt := "UPDATE networks_nodes SET state=? WHERE network_id = ? and node_id = ?"
+ result, err := c.tx.Exec(stmt, state, networkID, c.nodeID)
+ if err != nil {
+ return err
+ }
+ n, err := result.RowsAffected()
+ if err != nil {
+ return err
+ }
+ if n != 1 {
+ return ErrNoSuchObject
+ }
+
+ return nil
+}
+
// UpdateNetwork updates the network with the given ID.
func (c *ClusterTx) UpdateNetwork(id int64, description string, config map[string]string) error {
err := updateNetworkDescription(c.tx, id, description)
From 0973a46ecabb4d5a83612624940e0f2fde9852f6 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 23 Nov 2020 11:18:37 +0000
Subject: [PATCH 07/37] lxd/db/networks: Comments
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/db/networks.go | 11 ++++-------
1 file changed, 4 insertions(+), 7 deletions(-)
diff --git a/lxd/db/networks.go b/lxd/db/networks.go
index ba74ef7d72..b06411e610 100644
--- a/lxd/db/networks.go
+++ b/lxd/db/networks.go
@@ -456,15 +456,12 @@ const (
NetworkTypePhysical // Network type physical.
)
-// GetNetworkInAnyState returns the network with the given name.
-//
-// The network can be in any state.
+// GetNetworkInAnyState returns the network with the given name. The network can be in any state.
func (c *Cluster) GetNetworkInAnyState(project string, name string) (int64, *api.Network, error) {
return c.getNetwork(project, name, false)
}
-// Get the network with the given name. If onlyCreated is true, only return
-// networks in the created state.
+// Get the network with the given name. If onlyCreated is true, only return networks in the created state.
func (c *Cluster) getNetwork(project string, name string, onlyCreated bool) (int64, *api.Network, error) {
description := sql.NullString{}
id := int64(-1)
@@ -562,8 +559,7 @@ func (c *Cluster) networkNodes(networkID int64) ([]string, error) {
return nodes, nil
}
-// GetNetworkWithInterface returns the network associated with the interface with
-// the given name.
+// GetNetworkWithInterface returns the network associated with the interface with the given name.
func (c *Cluster) GetNetworkWithInterface(devName string) (int64, *api.Network, error) {
id := int64(-1)
name := ""
@@ -656,6 +652,7 @@ func (c *Cluster) getNetworkConfig(id int64) (map[string]string, error) {
func (c *Cluster) CreateNetwork(projectName string, name string, description string, netType NetworkType, config map[string]string) (int64, error) {
var id int64
err := c.Transaction(func(tx *ClusterTx) error {
+ // Insert a new network record with state "created".
result, err := tx.tx.Exec("INSERT INTO networks (project_id, name, description, state, type) VALUES ((SELECT id FROM projects WHERE name = ?), ?, ?, ?, ?)",
projectName, name, description, networkCreated, netType)
if err != nil {
From e8c987b6ffea5e0c2296701ae71e4b6fd28b32b6 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 23 Nov 2020 11:18:49 +0000
Subject: [PATCH 08/37] lxd/db/networks: Populate node state column in
CreateNetwork
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/db/networks.go | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/lxd/db/networks.go b/lxd/db/networks.go
index b06411e610..a879a23728 100644
--- a/lxd/db/networks.go
+++ b/lxd/db/networks.go
@@ -664,9 +664,9 @@ func (c *Cluster) CreateNetwork(projectName string, name string, description str
return err
}
- // Insert a node-specific entry pointing to ourselves.
- columns := []string{"network_id", "node_id"}
- values := []interface{}{id, c.nodeID}
+ // Insert a node-specific entry pointing to ourselves with state "pending".
+ columns := []string{"network_id", "node_id", "state"}
+ values := []interface{}{id, c.nodeID, networkPending}
_, err = query.UpsertObject(tx.tx, "networks_nodes", columns, values)
if err != nil {
return err
From c9d06cbfc278966704a801cea8016858d9e6a537 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 23 Nov 2020 11:19:31 +0000
Subject: [PATCH 09/37] lxd/network/driver: Remove check that prevents starting
network in pending state
This is needed as we now need to check if the network can start OK before marking the network created.
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/network/driver_bridge.go | 4 ----
lxd/network/driver_macvlan.go | 6 ------
lxd/network/driver_ovn.go | 4 ----
lxd/network/driver_physical.go | 4 ----
lxd/network/driver_sriov.go | 6 ------
5 files changed, 24 deletions(-)
diff --git a/lxd/network/driver_bridge.go b/lxd/network/driver_bridge.go
index ec30df98ca..8014bdb256 100644
--- a/lxd/network/driver_bridge.go
+++ b/lxd/network/driver_bridge.go
@@ -487,10 +487,6 @@ func (n *bridge) setup(oldConfig map[string]string) error {
n.logger.Debug("Setting up network")
- if n.status == api.NetworkStatusPending {
- return fmt.Errorf("Cannot start pending network")
- }
-
// Create directory.
if !shared.PathExists(shared.VarPath("networks", n.name)) {
err := os.MkdirAll(shared.VarPath("networks", n.name), 0711)
diff --git a/lxd/network/driver_macvlan.go b/lxd/network/driver_macvlan.go
index 09c15a174f..9c9a159cc5 100644
--- a/lxd/network/driver_macvlan.go
+++ b/lxd/network/driver_macvlan.go
@@ -1,8 +1,6 @@
package network
import (
- "fmt"
-
"github.com/lxc/lxd/lxd/cluster"
"github.com/lxc/lxd/lxd/db"
"github.com/lxc/lxd/lxd/revert"
@@ -67,10 +65,6 @@ func (n *macvlan) Rename(newName string) error {
func (n *macvlan) Start() error {
n.logger.Debug("Start")
- if n.status == api.NetworkStatusPending {
- return fmt.Errorf("Cannot start pending network")
- }
-
return nil
}
diff --git a/lxd/network/driver_ovn.go b/lxd/network/driver_ovn.go
index 03dd522eb7..097aaeb011 100644
--- a/lxd/network/driver_ovn.go
+++ b/lxd/network/driver_ovn.go
@@ -1836,10 +1836,6 @@ func (n *ovn) Rename(newName string) error {
func (n *ovn) Start() error {
n.logger.Debug("Start")
- if n.status == api.NetworkStatusPending {
- return fmt.Errorf("Cannot start pending network")
- }
-
// Add local node's OVS chassis ID to logical chassis group.
err := n.addChassisGroupEntry()
if err != nil {
diff --git a/lxd/network/driver_physical.go b/lxd/network/driver_physical.go
index 3d24584924..4ee105c8f2 100644
--- a/lxd/network/driver_physical.go
+++ b/lxd/network/driver_physical.go
@@ -143,10 +143,6 @@ func (n *physical) Rename(newName string) error {
func (n *physical) Start() error {
n.logger.Debug("Start")
- if n.status == api.NetworkStatusPending {
- return fmt.Errorf("Cannot start pending network")
- }
-
revert := revert.New()
defer revert.Fail()
diff --git a/lxd/network/driver_sriov.go b/lxd/network/driver_sriov.go
index 299e2dd2df..6a745cbb18 100644
--- a/lxd/network/driver_sriov.go
+++ b/lxd/network/driver_sriov.go
@@ -1,8 +1,6 @@
package network
import (
- "fmt"
-
"github.com/lxc/lxd/lxd/cluster"
"github.com/lxc/lxd/lxd/db"
"github.com/lxc/lxd/lxd/revert"
@@ -67,10 +65,6 @@ func (n *sriov) Rename(newName string) error {
func (n *sriov) Start() error {
n.logger.Debug("Start")
- if n.status == api.NetworkStatusPending {
- return fmt.Errorf("Cannot start pending network")
- }
-
return nil
}
From cc6f8548c20af0bb9112ec1daab8ee04080206f0 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 23 Nov 2020 11:20:38 +0000
Subject: [PATCH 10/37] lxd/networks: Whitespace
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/networks.go | 1 -
1 file changed, 1 deletion(-)
diff --git a/lxd/networks.go b/lxd/networks.go
index 09ea358629..a4fec44216 100644
--- a/lxd/networks.go
+++ b/lxd/networks.go
@@ -279,7 +279,6 @@ func networksPost(d *Daemon, r *http.Request) response.Response {
}
// Non-clustered network creation.
-
networks, err := d.cluster.GetNetworks(projectName)
if err != nil {
return response.InternalError(err)
From 8fe254d8c90b9b8cabc58bd88572e07dabf83ce4 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 23 Nov 2020 17:02:25 +0000
Subject: [PATCH 11/37] lxd/network/network/interface: Updates init to take
api.Network and network nodes map
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/network/network_interface.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lxd/network/network_interface.go b/lxd/network/network_interface.go
index b9ba1e89d1..1df3fe001c 100644
--- a/lxd/network/network_interface.go
+++ b/lxd/network/network_interface.go
@@ -24,7 +24,7 @@ type Network interface {
Type
// Load.
- init(state *state.State, id int64, projectName string, name string, netType string, description string, config map[string]string, status string)
+ init(state *state.State, id int64, projectName string, netInfo *api.Network, netNodes map[int64]db.NetworkNode)
// Config.
Validate(config map[string]string) error
From 1bf2a21a6d885274a1a173d91cad1d924814a0c1 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 23 Nov 2020 17:02:57 +0000
Subject: [PATCH 12/37] lxd/network/network/interface: Adds LocalStatus
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/network/network_interface.go | 1 +
1 file changed, 1 insertion(+)
diff --git a/lxd/network/network_interface.go b/lxd/network/network_interface.go
index 1df3fe001c..c5f60ca4ca 100644
--- a/lxd/network/network_interface.go
+++ b/lxd/network/network_interface.go
@@ -32,6 +32,7 @@ type Network interface {
Name() string
Description() string
Status() string
+ LocalStatus() string
Config() map[string]string
IsUsed() (bool, error)
DHCPv4Subnet() *net.IPNet
From 3e8161904004bc8af61cd70e9c330b3423c9e584 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 23 Nov 2020 17:03:26 +0000
Subject: [PATCH 13/37] lxd/network/network/load: Updates LoadByName to pass
network nodes from s.Cluster.GetNetworkInAnyState to init()
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/network/network_load.go | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lxd/network/network_load.go b/lxd/network/network_load.go
index 7098181a57..0b165b63cc 100644
--- a/lxd/network/network_load.go
+++ b/lxd/network/network_load.go
@@ -26,7 +26,7 @@ func LoadByType(driverType string) (Type, error) {
// LoadByName loads an instantiated network from the database by project and name.
func LoadByName(s *state.State, projectName string, name string) (Network, error) {
- id, netInfo, err := s.Cluster.GetNetworkInAnyState(projectName, name)
+ id, netInfo, netNodes, err := s.Cluster.GetNetworkInAnyState(projectName, name)
if err != nil {
return nil, err
}
@@ -37,7 +37,7 @@ func LoadByName(s *state.State, projectName string, name string) (Network, error
}
n := driverFunc()
- n.init(s, id, projectName, name, netInfo.Type, netInfo.Description, netInfo.Config, netInfo.Status)
+ n.init(s, id, projectName, netInfo, netNodes)
return n, nil
}
From 2a10a295e9dad218cc0ab0a0defc21aab48fd771 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 23 Nov 2020 17:05:56 +0000
Subject: [PATCH 14/37] lxd/db/networks: Adds NetworkState type and uses it in
place of int
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/db/networks.go | 19 +++++++++++--------
1 file changed, 11 insertions(+), 8 deletions(-)
diff --git a/lxd/db/networks.go b/lxd/db/networks.go
index a879a23728..66e57968d2 100644
--- a/lxd/db/networks.go
+++ b/lxd/db/networks.go
@@ -94,7 +94,7 @@ func (c *ClusterTx) GetNonPendingNetworks() (map[string]map[int64]api.Network, e
var projectName string
var networkID int64
var networkType NetworkType
- var networkState int
+ var networkState NetworkState
var network api.Network
err := rows.Scan(&projectName, &networkID, &network.Name, &network.Description, &networkType, &networkState)
@@ -230,7 +230,7 @@ func (c *ClusterTx) CreatePendingNetwork(node string, projectName string, name s
// First check if a network with the given name exists, and, if so, that it's in the pending state.
network := struct {
id int64
- state int
+ state NetworkState
netType NetworkType
}{}
@@ -325,7 +325,7 @@ func (c *ClusterTx) NetworkErrored(project string, name string) error {
return c.networkState(project, name, networkErrored)
}
-func (c *ClusterTx) networkState(project string, name string, state int) error {
+func (c *ClusterTx) networkState(project string, name string, state NetworkState) error {
stmt := "UPDATE networks SET state=? WHERE project_id = (SELECT id FROM projects WHERE name = ?) AND name=?"
result, err := c.tx.Exec(stmt, state, project, name)
if err != nil {
@@ -347,7 +347,7 @@ func (c *ClusterTx) NetworkNodeCreated(networkID int64) error {
}
// networkNodeState updates the network member state for the local member and specified network ID.
-func (c *ClusterTx) networkNodeState(networkID int64, state int) error {
+func (c *ClusterTx) networkNodeState(networkID int64, state NetworkState) error {
stmt := "UPDATE networks_nodes SET state=? WHERE network_id = ? and node_id = ?"
result, err := c.tx.Exec(stmt, state, networkID, c.nodeID)
if err != nil {
@@ -437,11 +437,14 @@ func (c *Cluster) networks(project string, where string, args ...interface{}) ([
return response, nil
}
+// NetworkState indicates the state of the network or network node.
+type NetworkState int
+
// Network state.
const (
- networkPending int = iota // Network defined but not yet created.
- networkCreated // Network created on all nodes.
- networkErrored // Network creation failed on some nodes
+ networkPending NetworkState = iota // Network defined but not yet created.
+ networkCreated // Network created on all nodes.
+ networkErrored // Network creation failed on some nodes
)
// NetworkType indicates type of network.
@@ -465,7 +468,7 @@ func (c *Cluster) GetNetworkInAnyState(project string, name string) (int64, *api
func (c *Cluster) getNetwork(project string, name string, onlyCreated bool) (int64, *api.Network, error) {
description := sql.NullString{}
id := int64(-1)
- state := 0
+ var state NetworkState
var netType NetworkType
q := "SELECT id, description, state, type FROM networks WHERE project_id = (SELECT id FROM projects WHERE name = ?) AND name=?"
From 10c53771be5eace214e35282964b81f43a821b2b Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 23 Nov 2020 17:07:37 +0000
Subject: [PATCH 15/37] lxd/db/networks: Renames networkFillStatus to
NetworkStateToAPIStatus
And updates usage.
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/db/networks.go | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/lxd/db/networks.go b/lxd/db/networks.go
index 66e57968d2..9fe91ec9f7 100644
--- a/lxd/db/networks.go
+++ b/lxd/db/networks.go
@@ -103,7 +103,7 @@ func (c *ClusterTx) GetNonPendingNetworks() (map[string]map[int64]api.Network, e
}
// Populate Status and Type fields by converting from DB values.
- networkFillStatus(&network, networkState)
+ network.Status = NetworkStateToAPIStatus(networkState)
networkFillType(&network, networkType)
if projectNetworks[projectName] != nil {
@@ -500,7 +500,7 @@ func (c *Cluster) getNetwork(project string, name string, onlyCreated bool) (int
network.Config = config
// Populate Status and Type fields by converting from DB values.
- networkFillStatus(&network, state)
+ network.Status = NetworkStateToAPIStatus(state)
networkFillType(&network, netType)
nodes, err := c.networkNodes(id)
@@ -512,16 +512,17 @@ func (c *Cluster) getNetwork(project string, name string, onlyCreated bool) (int
return id, &network, nil
}
-func networkFillStatus(network *api.Network, state int) {
+// NetworkStateToAPIStatus converts DB NetworkState to API status string.
+func NetworkStateToAPIStatus(state NetworkState) string {
switch state {
case networkPending:
- network.Status = api.NetworkStatusPending
+ return api.NetworkStatusPending
case networkCreated:
- network.Status = api.NetworkStatusCreated
+ return api.NetworkStatusCreated
case networkErrored:
- network.Status = api.NetworkStatusErrored
+ return api.NetworkStatusErrored
default:
- network.Status = api.NetworkStatusUnknown
+ return api.NetworkStatusUnknown
}
}
From 31ace3f2ed6d2c3860a058fb992c4ff12d398635 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 23 Nov 2020 17:09:45 +0000
Subject: [PATCH 16/37] lxd/db/networks: Adds NetworkNode type
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/db/networks.go | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/lxd/db/networks.go b/lxd/db/networks.go
index 9fe91ec9f7..4b1e5d3158 100644
--- a/lxd/db/networks.go
+++ b/lxd/db/networks.go
@@ -459,6 +459,13 @@ const (
NetworkTypePhysical // Network type physical.
)
+// NetworkNode represents a network node.
+type NetworkNode struct {
+ ID int64
+ Name string
+ State NetworkState
+}
+
// GetNetworkInAnyState returns the network with the given name. The network can be in any state.
func (c *Cluster) GetNetworkInAnyState(project string, name string) (int64, *api.Network, error) {
return c.getNetwork(project, name, false)
From 52140c740a8e3f4ce5ba59a03e0bdae92e57012f Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 23 Nov 2020 17:10:11 +0000
Subject: [PATCH 17/37] lxd/db/networks: Exports NetworkNodes and updates to
return map of NetworkNodes
Including node ID, name and state.
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/db/networks.go | 35 +++++++++++++++++++++++++----------
1 file changed, 25 insertions(+), 10 deletions(-)
diff --git a/lxd/db/networks.go b/lxd/db/networks.go
index 4b1e5d3158..5ff4322ed5 100644
--- a/lxd/db/networks.go
+++ b/lxd/db/networks.go
@@ -384,20 +384,35 @@ func (c *ClusterTx) UpdateNetwork(id int64, description string, config map[strin
return nil
}
-// Return the names of the nodes the given network is defined on.
-func (c *ClusterTx) networkNodes(networkID int64) ([]string, error) {
- var err error
- stmt := `
- SELECT nodes.name FROM nodes
- JOIN networks_nodes ON networks_nodes.node_id = nodes.id
- WHERE networks_nodes.network_id = ?
- `
- nodes, err := query.SelectStrings(c.tx, stmt, networkID)
+// NetworkNodes returns the nodes keyed by node ID that the given network is defined on.
+func (c *ClusterTx) NetworkNodes(networkID int64) (map[int64]NetworkNode, error) {
+ nodes := []NetworkNode{}
+ dest := func(i int) []interface{} {
+ nodes = append(nodes, NetworkNode{})
+ return []interface{}{&nodes[i].ID, &nodes[i].Name, &nodes[i].State}
+ }
+
+ stmt, err := c.tx.Prepare(`
+ SELECT nodes.id, nodes.name, networks_nodes.state FROM nodes
+ JOIN networks_nodes ON networks_nodes.node_id = nodes.id
+ WHERE networks_nodes.network_id = ?
+ `)
+ if err != nil {
+ return nil, err
+ }
+ defer stmt.Close()
+
+ err = query.SelectObjects(stmt, dest, networkID)
if err != nil {
return nil, err
}
- return nodes, nil
+ netNodes := map[int64]NetworkNode{}
+ for _, node := range nodes {
+ netNodes[node.ID] = node
+ }
+
+ return netNodes, nil
}
// GetNetworks returns the names of existing networks.
From bc3108c16910af7a46274e50b52a0734afd673f6 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 23 Nov 2020 17:11:41 +0000
Subject: [PATCH 18/37] lxd/db/networks: Updates GetNonPendingNetworks usage of
NetworkNodes()
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/db/networks.go | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/lxd/db/networks.go b/lxd/db/networks.go
index 5ff4322ed5..ddeee25093 100644
--- a/lxd/db/networks.go
+++ b/lxd/db/networks.go
@@ -130,11 +130,14 @@ func (c *ClusterTx) GetNonPendingNetworks() (map[string]map[int64]api.Network, e
network.Config = networkConfig
- nodes, err := c.networkNodes(networkID)
+ nodes, err := c.NetworkNodes(networkID)
if err != nil {
return nil, err
}
- network.Locations = nodes
+
+ for _, node := range nodes {
+ network.Locations = append(network.Locations, node.Name)
+ }
projectNetworks[projectName][networkID] = network
}
From a0f20b9a19926fec4033572c6d4af887f4423650 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 23 Nov 2020 17:12:10 +0000
Subject: [PATCH 19/37] lxd/db/networks: Modifies getNetwork and
GetNetworkInAnyState to return map of NetworkNodes for network
We run the query anyway to populate Network's Location field so cheap to return at same time.
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/db/networks.go | 24 ++++++++++++++----------
1 file changed, 14 insertions(+), 10 deletions(-)
diff --git a/lxd/db/networks.go b/lxd/db/networks.go
index ddeee25093..9c086d0f37 100644
--- a/lxd/db/networks.go
+++ b/lxd/db/networks.go
@@ -485,12 +485,13 @@ type NetworkNode struct {
}
// GetNetworkInAnyState returns the network with the given name. The network can be in any state.
-func (c *Cluster) GetNetworkInAnyState(project string, name string) (int64, *api.Network, error) {
+func (c *Cluster) GetNetworkInAnyState(project string, name string) (int64, *api.Network, map[int64]NetworkNode, error) {
return c.getNetwork(project, name, false)
}
-// Get the network with the given name. If onlyCreated is true, only return networks in the created state.
-func (c *Cluster) getNetwork(project string, name string, onlyCreated bool) (int64, *api.Network, error) {
+// Get the network with the given name. If onlyCreated is true, only return networks in the networkCreated state.
+// Also returns a map of the network's nodes keyed by node ID.
+func (c *Cluster) getNetwork(project string, name string, onlyCreated bool) (int64, *api.Network, map[int64]NetworkNode, error) {
description := sql.NullString{}
id := int64(-1)
var state NetworkState
@@ -506,15 +507,15 @@ func (c *Cluster) getNetwork(project string, name string, onlyCreated bool) (int
err := dbQueryRowScan(c, q, arg1, arg2)
if err != nil {
if err == sql.ErrNoRows {
- return -1, nil, ErrNoSuchObject
+ return -1, nil, nil, ErrNoSuchObject
}
- return -1, nil, err
+ return -1, nil, nil, err
}
config, err := c.getNetworkConfig(id)
if err != nil {
- return -1, nil, err
+ return -1, nil, nil, err
}
network := api.Network{
@@ -528,13 +529,16 @@ func (c *Cluster) getNetwork(project string, name string, onlyCreated bool) (int
network.Status = NetworkStateToAPIStatus(state)
networkFillType(&network, netType)
- nodes, err := c.networkNodes(id)
+ nodes, err := c.NetworkNodes(id)
if err != nil {
- return -1, nil, err
+ return -1, nil, nil, err
}
- network.Locations = nodes
- return id, &network, nil
+ for _, node := range nodes {
+ network.Locations = append(network.Locations, node.Name)
+ }
+
+ return id, &network, nodes, nil
}
// NetworkStateToAPIStatus converts DB NetworkState to API status string.
From 36f25d841d4245cf5ab37dcc4ca7d9e019e79647 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 23 Nov 2020 17:13:07 +0000
Subject: [PATCH 20/37] lxd/db/networks: Exports NetworkNodes
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/db/networks.go | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/lxd/db/networks.go b/lxd/db/networks.go
index 9c086d0f37..d0fd2a14b1 100644
--- a/lxd/db/networks.go
+++ b/lxd/db/networks.go
@@ -572,13 +572,13 @@ func networkFillType(network *api.Network, netType NetworkType) {
}
}
-// Return the names of the nodes the given network is defined on.
-func (c *Cluster) networkNodes(networkID int64) ([]string, error) {
- var nodes []string
+// NetworkNodes returns the nodes keyed by node ID that the given network is defined on.
+func (c *Cluster) NetworkNodes(networkID int64) (map[int64]NetworkNode, error) {
+ var nodes map[int64]NetworkNode
var err error
err = c.Transaction(func(tx *ClusterTx) error {
- nodes, err = tx.networkNodes(networkID)
+ nodes, err = tx.NetworkNodes(networkID)
if err != nil {
return err
}
From 0daa38e09bff9b01b6725586229828355766803a Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 23 Nov 2020 17:13:49 +0000
Subject: [PATCH 21/37] lxd/db/networks: c.GetNetworkInAnyState usage
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/db/networks.go | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/lxd/db/networks.go b/lxd/db/networks.go
index d0fd2a14b1..12866e0344 100644
--- a/lxd/db/networks.go
+++ b/lxd/db/networks.go
@@ -720,7 +720,7 @@ func (c *Cluster) CreateNetwork(projectName string, name string, description str
// UpdateNetwork updates the network with the given name.
func (c *Cluster) UpdateNetwork(project string, name, description string, config map[string]string) error {
- id, netInfo, err := c.GetNetworkInAnyState(project, name)
+ id, netInfo, _, err := c.GetNetworkInAnyState(project, name)
if err != nil {
return err
}
@@ -794,7 +794,7 @@ func clearNetworkConfig(tx *sql.Tx, networkID, nodeID int64) error {
// DeleteNetwork deletes the network with the given name.
func (c *Cluster) DeleteNetwork(project string, name string) error {
- id, _, err := c.GetNetworkInAnyState(project, name)
+ id, _, _, err := c.GetNetworkInAnyState(project, name)
if err != nil {
return err
}
@@ -809,7 +809,7 @@ func (c *Cluster) DeleteNetwork(project string, name string) error {
// RenameNetwork renames a network.
func (c *Cluster) RenameNetwork(project string, oldName string, newName string) error {
- id, _, err := c.GetNetworkInAnyState(project, oldName)
+ id, _, _, err := c.GetNetworkInAnyState(project, oldName)
if err != nil {
return err
}
From b914b831e65e35ed3ce8b81dbbff14accf10bf3f Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 23 Nov 2020 17:14:07 +0000
Subject: [PATCH 22/37] lxd/db/networks: Updates comments to reference state
constants
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/db/networks.go | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/lxd/db/networks.go b/lxd/db/networks.go
index 12866e0344..34a75003a6 100644
--- a/lxd/db/networks.go
+++ b/lxd/db/networks.go
@@ -175,7 +175,7 @@ func (c *ClusterTx) CreateNetworkConfig(networkID, nodeID int64, config map[stri
// and we just need to track it.
func (c *ClusterTx) NetworkNodeJoin(networkID, nodeID int64) error {
columns := []string{"network_id", "node_id", "state"}
- // Create network node with "created" state as we expect the network to already be setup.
+ // Create network node with networkCreated state as we expect the network to already be setup.
values := []interface{}{networkID, nodeID, networkCreated}
_, err := query.UpsertObject(c.tx, "networks_nodes", columns, values)
return err
@@ -276,7 +276,7 @@ func (c *ClusterTx) CreatePendingNetwork(node string, projectName string, name s
return err
}
} else {
- // Check that the existing network is in the pending state.
+ // Check that the existing network is in the networkPending or networkErrored state.
if network.state != networkPending && network.state != networkErrored {
return fmt.Errorf("Network is not in pending or errored state")
}
@@ -302,7 +302,7 @@ func (c *ClusterTx) CreatePendingNetwork(node string, projectName string, name s
return ErrAlreadyDefined
}
- // Insert the node-specific configuration with state "pending".
+ // Insert the node-specific configuration with state networkPending.
columns := []string{"network_id", "node_id", "state"}
values := []interface{}{networkID, nodeInfo.ID, networkPending}
_, err = query.UpsertObject(c.tx, "networks_nodes", columns, values)
@@ -318,12 +318,12 @@ func (c *ClusterTx) CreatePendingNetwork(node string, projectName string, name s
return nil
}
-// NetworkCreated sets the state of the given network to "Created".
+// NetworkCreated sets the state of the given network to networkCreated.
func (c *ClusterTx) NetworkCreated(project string, name string) error {
return c.networkState(project, name, networkCreated)
}
-// NetworkErrored sets the state of the given network to "Errored".
+// NetworkErrored sets the state of the given network to networkErrored.
func (c *ClusterTx) NetworkErrored(project string, name string) error {
return c.networkState(project, name, networkErrored)
}
@@ -344,7 +344,7 @@ func (c *ClusterTx) networkState(project string, name string, state NetworkState
return nil
}
-// NetworkNodeCreated sets the state of the given network for the local member to "Created".
+// NetworkNodeCreated sets the state of the given network for the local member to networkCreated.
func (c *ClusterTx) NetworkNodeCreated(networkID int64) error {
return c.networkNodeState(networkID, networkCreated)
}
@@ -423,7 +423,7 @@ func (c *Cluster) GetNetworks(project string) ([]string, error) {
return c.networks(project, "")
}
-// GetNonPendingNetworks returns the names of all networks that are not pending.
+// GetNonPendingNetworks returns the names of all networks that are not in state networkPending.
func (c *Cluster) GetNonPendingNetworks(project string) ([]string, error) {
return c.networks(project, "NOT state=?", networkPending)
}
@@ -685,7 +685,7 @@ func (c *Cluster) getNetworkConfig(id int64) (map[string]string, error) {
func (c *Cluster) CreateNetwork(projectName string, name string, description string, netType NetworkType, config map[string]string) (int64, error) {
var id int64
err := c.Transaction(func(tx *ClusterTx) error {
- // Insert a new network record with state "created".
+ // Insert a new network record with state networkCreated.
result, err := tx.tx.Exec("INSERT INTO networks (project_id, name, description, state, type) VALUES ((SELECT id FROM projects WHERE name = ?), ?, ?, ?, ?)",
projectName, name, description, networkCreated, netType)
if err != nil {
@@ -697,7 +697,7 @@ func (c *Cluster) CreateNetwork(projectName string, name string, description str
return err
}
- // Insert a node-specific entry pointing to ourselves with state "pending".
+ // Insert a node-specific entry pointing to ourselves with state networkPending.
columns := []string{"network_id", "node_id", "state"}
values := []interface{}{id, c.nodeID, networkPending}
_, err = query.UpsertObject(tx.tx, "networks_nodes", columns, values)
From c0ce479baf45772ff367e66892a50238c3a1b38c Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 23 Nov 2020 17:14:44 +0000
Subject: [PATCH 23/37] lxd/patches: d.cluster.GetNetworkInAnyState usage
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/patches.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lxd/patches.go b/lxd/patches.go
index 194a5695c9..1e6fa8183c 100644
--- a/lxd/patches.go
+++ b/lxd/patches.go
@@ -3787,7 +3787,7 @@ func patchNetworkCearBridgeVolatileHwaddr(name string, d *Daemon) error {
}
for _, networkName := range networks {
- _, net, err := d.cluster.GetNetworkInAnyState(projectName, networkName)
+ _, net, _, err := d.cluster.GetNetworkInAnyState(projectName, networkName)
if err != nil {
return errors.Wrapf(err, "Failed loading network %q for network_clear_bridge_volatile_hwaddr patch", networkName)
}
From a059aee307388e5c18ecc3b1a82fa8d268064a84 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 23 Nov 2020 17:16:31 +0000
Subject: [PATCH 24/37] lxd/api/cluster: d.cluster.GetNetworkInAnyState usage
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/api_cluster.go | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lxd/api_cluster.go b/lxd/api_cluster.go
index 7e88bcce2f..3167c0d83f 100644
--- a/lxd/api_cluster.go
+++ b/lxd/api_cluster.go
@@ -436,7 +436,7 @@ func clusterPutJoin(d *Daemon, req api.ClusterPut) response.Response {
}
for _, name := range networkNames {
- _, network, err := d.cluster.GetNetworkInAnyState(p.Name, name)
+ _, network, _, err := d.cluster.GetNetworkInAnyState(p.Name, name)
if err != nil {
return err
}
@@ -1628,7 +1628,7 @@ func clusterCheckNetworksMatch(cluster *db.Cluster, reqNetworks []internalCluste
found = true
- _, network, err := cluster.GetNetworkInAnyState(networkProjectName, networkName)
+ _, network, _, err := cluster.GetNetworkInAnyState(networkProjectName, networkName)
if err != nil {
return err
}
From 55e5ce01af334a72e9784bd37ceff3cd4f3774cf Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 23 Nov 2020 17:16:43 +0000
Subject: [PATCH 25/37] lxd/api/project: s.Cluster.GetNetworkInAnyState usage
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/api_project.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lxd/api_project.go b/lxd/api_project.go
index 85de1f61b2..cbb088cb85 100644
--- a/lxd/api_project.go
+++ b/lxd/api_project.go
@@ -624,7 +624,7 @@ func projectValidateRestrictedSubnets(s *state.State, value string) error {
}
// Check uplink exists and load config to compare subnets.
- _, uplink, err := s.Cluster.GetNetworkInAnyState(project.Default, uplinkName)
+ _, uplink, _, err := s.Cluster.GetNetworkInAnyState(project.Default, uplinkName)
if err != nil {
return errors.Wrapf(err, "Invalid uplink network %q", uplinkName)
}
From e89c92f2f969ff910edda33b2a8d12d6427c94aa Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 23 Nov 2020 17:16:53 +0000
Subject: [PATCH 26/37] lxd/device/nic: d.state.Cluster.GetNetworkInAnyState
usage
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/device/nic_bridged.go | 2 +-
lxd/device/nictype/nictype.go | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/lxd/device/nic_bridged.go b/lxd/device/nic_bridged.go
index f79fd3549c..83e78ed092 100644
--- a/lxd/device/nic_bridged.go
+++ b/lxd/device/nic_bridged.go
@@ -492,7 +492,7 @@ func (d *nicBridged) rebuildDnsmasqEntry() error {
defer dnsmasq.ConfigMutex.Unlock()
// Use project.Default here as bridge networks don't support projects.
- _, dbInfo, err := d.state.Cluster.GetNetworkInAnyState(project.Default, d.config["parent"])
+ _, dbInfo, _, err := d.state.Cluster.GetNetworkInAnyState(project.Default, d.config["parent"])
if err != nil {
return err
}
diff --git a/lxd/device/nictype/nictype.go b/lxd/device/nictype/nictype.go
index 5c8ef08209..3848864855 100644
--- a/lxd/device/nictype/nictype.go
+++ b/lxd/device/nictype/nictype.go
@@ -26,7 +26,7 @@ func NICType(s *state.State, deviceProjectName string, d deviceConfig.Device) (s
return "", errors.Wrapf(err, "Failed to translate device project %q into network project", deviceProjectName)
}
- _, netInfo, err := s.Cluster.GetNetworkInAnyState(networkProjectName, d["network"])
+ _, netInfo, _, err := s.Cluster.GetNetworkInAnyState(networkProjectName, d["network"])
if err != nil {
return "", errors.Wrapf(err, "Failed to load network %q for project %q", d["network"], networkProjectName)
}
From 5223624dea787970919240a11791347ba49d6787 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 23 Nov 2020 17:18:19 +0000
Subject: [PATCH 27/37] lxd/network/driver/ovn:
n.state.Cluster.GetNetworkInAnyState usage
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/network/driver_ovn.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lxd/network/driver_ovn.go b/lxd/network/driver_ovn.go
index 097aaeb011..6c855330b3 100644
--- a/lxd/network/driver_ovn.go
+++ b/lxd/network/driver_ovn.go
@@ -82,7 +82,7 @@ func (n *ovn) Info() Info {
// uplinkRoutes parses ipv4.routes and ipv6.routes settings for a named uplink network into a slice of *net.IPNet.
func (n *ovn) uplinkRoutes(uplinkNetworkName string) ([]*net.IPNet, error) {
- _, uplink, err := n.state.Cluster.GetNetworkInAnyState(project.Default, uplinkNetworkName)
+ _, uplink, _, err := n.state.Cluster.GetNetworkInAnyState(project.Default, uplinkNetworkName)
if err != nil {
return nil, err
}
From 9079c21409a0f4b361682fbb8e8fcab60f38817e Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 23 Nov 2020 17:19:29 +0000
Subject: [PATCH 28/37] lxd/network/driver/common: Adds LocalStatus function
and store node info inside network via init()
Updates init() to accept api.Network and map of NetworkNodes.
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/network/driver_common.go | 24 ++++++++++++++++++------
1 file changed, 18 insertions(+), 6 deletions(-)
diff --git a/lxd/network/driver_common.go b/lxd/network/driver_common.go
index 23cff9a58c..6c39a6d7b2 100644
--- a/lxd/network/driver_common.go
+++ b/lxd/network/driver_common.go
@@ -36,18 +36,20 @@ type common struct {
description string
config map[string]string
status string
+ nodes map[int64]db.NetworkNode
}
// init initialise internal variables.
-func (n *common) init(state *state.State, id int64, projectName string, name string, netType string, description string, config map[string]string, status string) {
- n.logger = logging.AddContext(logger.Log, log.Ctx{"project": projectName, "driver": netType, "network": name})
+func (n *common) init(state *state.State, id int64, projectName string, netInfo *api.Network, netNodes map[int64]db.NetworkNode) {
+ n.logger = logging.AddContext(logger.Log, log.Ctx{"project": projectName, "driver": netInfo.Type, "network": netInfo.Name})
n.id = id
n.project = projectName
- n.name = name
- n.config = config
+ n.name = netInfo.Name
+ n.config = netInfo.Config
n.state = state
- n.description = description
- n.status = status
+ n.description = netInfo.Description
+ n.status = netInfo.Status
+ n.nodes = netNodes
}
// FillConfig fills requested config with any default values, by default this is a no-op.
@@ -133,6 +135,16 @@ func (n *common) Status() string {
return n.status
}
+// LocalStatus returns network status of the local cluster member.
+func (n *common) LocalStatus() string {
+ node, exists := n.nodes[n.state.Cluster.GetNodeID()]
+ if !exists {
+ return api.NetworkStatusUnknown
+ }
+
+ return db.NetworkStateToAPIStatus(node.State)
+}
+
// Config returns the network config.
func (n *common) Config() map[string]string {
return n.config
From 1fed7bc2c9f5142c53910a14b94b8eea8d0bd41f Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 23 Nov 2020 17:17:32 +0000
Subject: [PATCH 29/37] lxd/network/driver/bridge: Only perform local date if
local status is api.NetworkStatusCreated
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/network/driver_bridge.go | 20 +++++++++++---------
1 file changed, 11 insertions(+), 9 deletions(-)
diff --git a/lxd/network/driver_bridge.go b/lxd/network/driver_bridge.go
index 8014bdb256..0175e930e3 100644
--- a/lxd/network/driver_bridge.go
+++ b/lxd/network/driver_bridge.go
@@ -414,20 +414,22 @@ func (n *bridge) isRunning() bool {
func (n *bridge) Delete(clientType cluster.ClientType) error {
n.logger.Debug("Delete", log.Ctx{"clientType": clientType})
- // Bring the network down.
- if n.isRunning() {
- err := n.Stop()
+ // Bring the local network down if created on this node.
+ if n.LocalStatus() == api.NetworkStatusCreated {
+ if n.isRunning() {
+ err := n.Stop()
+ if err != nil {
+ return err
+ }
+ }
+
+ // Delete apparmor profiles.
+ err := apparmor.NetworkDelete(n.state, n)
if err != nil {
return err
}
}
- // Delete apparmor profiles.
- err := apparmor.NetworkDelete(n.state, n)
- if err != nil {
- return err
- }
-
return n.common.delete(clientType)
}
From d0b90906fdb44bc612bd739eeb7deb79da51a552 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 23 Nov 2020 17:18:11 +0000
Subject: [PATCH 30/37] lxd/network/driver/ovn: Only perform local date if
local status is api.NetworkStatusCreated
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/network/driver_ovn.go | 88 ++++++++++++++++++++-------------------
1 file changed, 45 insertions(+), 43 deletions(-)
diff --git a/lxd/network/driver_ovn.go b/lxd/network/driver_ovn.go
index 6c855330b3..370104179c 100644
--- a/lxd/network/driver_ovn.go
+++ b/lxd/network/driver_ovn.go
@@ -1758,61 +1758,63 @@ func (n *ovn) deleteChassisGroupEntry() error {
func (n *ovn) Delete(clientType cluster.ClientType) error {
n.logger.Debug("Delete", log.Ctx{"clientType": clientType})
- err := n.Stop()
- if err != nil {
- return err
- }
-
- if clientType == cluster.ClientTypeNormal {
- client, err := n.getClient()
+ if n.LocalStatus() == api.NetworkStatusCreated {
+ err := n.Stop()
if err != nil {
return err
}
- err = client.LogicalRouterDelete(n.getRouterName())
- if err != nil {
- return err
- }
+ if clientType == cluster.ClientTypeNormal {
+ client, err := n.getClient()
+ if err != nil {
+ return err
+ }
- err = client.LogicalSwitchDelete(n.getExtSwitchName())
- if err != nil {
- return err
- }
+ err = client.LogicalRouterDelete(n.getRouterName())
+ if err != nil {
+ return err
+ }
- err = client.LogicalSwitchDelete(n.getIntSwitchName())
- if err != nil {
- return err
- }
+ err = client.LogicalSwitchDelete(n.getExtSwitchName())
+ if err != nil {
+ return err
+ }
- err = client.LogicalRouterPortDelete(n.getRouterExtPortName())
- if err != nil {
- return err
- }
+ err = client.LogicalSwitchDelete(n.getIntSwitchName())
+ if err != nil {
+ return err
+ }
- err = client.LogicalRouterPortDelete(n.getRouterIntPortName())
- if err != nil {
- return err
- }
+ err = client.LogicalRouterPortDelete(n.getRouterExtPortName())
+ if err != nil {
+ return err
+ }
- err = client.LogicalSwitchPortDelete(n.getExtSwitchRouterPortName())
- if err != nil {
- return err
- }
+ err = client.LogicalRouterPortDelete(n.getRouterIntPortName())
+ if err != nil {
+ return err
+ }
- err = client.LogicalSwitchPortDelete(n.getExtSwitchProviderPortName())
- if err != nil {
- return err
- }
+ err = client.LogicalSwitchPortDelete(n.getExtSwitchRouterPortName())
+ if err != nil {
+ return err
+ }
- err = client.LogicalSwitchPortDelete(n.getIntSwitchRouterPortName())
- if err != nil {
- return err
- }
+ err = client.LogicalSwitchPortDelete(n.getExtSwitchProviderPortName())
+ if err != nil {
+ return err
+ }
- // Must be done after logical router removal.
- err = client.ChassisGroupDelete(n.getChassisGroupName())
- if err != nil {
- return err
+ err = client.LogicalSwitchPortDelete(n.getIntSwitchRouterPortName())
+ if err != nil {
+ return err
+ }
+
+ // Must be done after logical router removal.
+ err = client.ChassisGroupDelete(n.getChassisGroupName())
+ if err != nil {
+ return err
+ }
}
}
From 3aa894b481e1c14fe778a5964eea4e17c123c5f5 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 23 Nov 2020 17:20:08 +0000
Subject: [PATCH 31/37] lxd/network/driver/physical: Only perform local date if
local status is api.NetworkStatusCreated
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/network/driver_physical.go | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/lxd/network/driver_physical.go b/lxd/network/driver_physical.go
index 4ee105c8f2..09d94f59a4 100644
--- a/lxd/network/driver_physical.go
+++ b/lxd/network/driver_physical.go
@@ -118,9 +118,11 @@ func (n *physical) Create(clientType cluster.ClientType) error {
func (n *physical) Delete(clientType cluster.ClientType) error {
n.logger.Debug("Delete", log.Ctx{"clientType": clientType})
- err := n.Stop()
- if err != nil {
- return err
+ if n.LocalStatus() == api.NetworkStatusCreated {
+ err := n.Stop()
+ if err != nil {
+ return err
+ }
}
return n.common.delete(clientType)
From a8e123c0337bb67fa9f5fc9a4ccf618ecbfe1f79 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 23 Nov 2020 17:24:48 +0000
Subject: [PATCH 32/37] lxd/networks: Updates doNetworksCreate to skip creation
if node is already marked created
Updates node status to created on successful create.
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/networks.go | 20 +++++++++++++++++++-
1 file changed, 19 insertions(+), 1 deletion(-)
diff --git a/lxd/networks.go b/lxd/networks.go
index a4fec44216..4a1205edca 100644
--- a/lxd/networks.go
+++ b/lxd/networks.go
@@ -444,6 +444,11 @@ func doNetworksCreate(d *Daemon, projectName string, req api.NetworksPost, clien
return err
}
+ if n.LocalStatus() == api.NetworkStatusCreated {
+ logger.Debug("Skipping network create as already created locally", log.Ctx{"project": projectName, "network": n.Name()})
+ return nil
+ }
+
// Run initial creation setup for the network driver.
err = n.Create(clientType)
if err != nil {
@@ -457,13 +462,26 @@ func doNetworksCreate(d *Daemon, projectName string, req api.NetworksPost, clien
if err != nil {
delErr := n.Delete(clientType)
if delErr != nil {
- logger.Errorf("Failed clearing up network %q after failed create: %v", n.Name(), delErr)
+ logger.Error("Failed clearing up network after failed create", log.Ctx{"project": projectName, "network": n.Name(), "err": delErr})
}
return err
}
}
+ // Mark local as status as networkCreated.
+ err = d.cluster.Transaction(func(tx *db.ClusterTx) error {
+ return tx.NetworkNodeCreated(n.ID())
+ })
+ if err != nil {
+ delErr := n.Delete(clientType)
+ if delErr != nil {
+ logger.Error("Failed clearing up network after failed local status update", log.Ctx{"project": projectName, "network": n.Name(), "err": delErr})
+ }
+ return err
+ }
+ logger.Debug("Marked network local status as created", log.Ctx{"project": projectName, "network": req.Name})
+
return nil
}
From 0338b87c317db87c77e0ce0c82c68f7a20f9327a Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 23 Nov 2020 17:25:32 +0000
Subject: [PATCH 33/37] lxd/networks: d.cluster.GetNetworkInAnyState usage
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/networks.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lxd/networks.go b/lxd/networks.go
index 4a1205edca..866d6e4125 100644
--- a/lxd/networks.go
+++ b/lxd/networks.go
@@ -529,7 +529,7 @@ func doNetworkGet(d *Daemon, projectName string, name string) (api.Network, erro
}
// Get some information.
- _, dbInfo, _ := d.cluster.GetNetworkInAnyState(projectName, name)
+ _, dbInfo, _, _ := d.cluster.GetNetworkInAnyState(projectName, name)
// Don't allow retrieving info about the local node interfaces when not using default project.
if projectName != project.Default && dbInfo == nil {
From 7863bf7fee38f547e2f32f552fa2502c22819fb0 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 23 Nov 2020 17:26:00 +0000
Subject: [PATCH 34/37] lxd/networks: Don't skip network clean up if network is
pending in networkDelete()
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/networks.go | 15 +--------------
1 file changed, 1 insertion(+), 14 deletions(-)
diff --git a/lxd/networks.go b/lxd/networks.go
index 866d6e4125..fd8a82ef35 100644
--- a/lxd/networks.go
+++ b/lxd/networks.go
@@ -601,19 +601,6 @@ func networkDelete(d *Daemon, r *http.Request) response.Response {
name := mux.Vars(r)["name"]
state := d.State()
- // Check if the network is pending, if so we just need to delete it from the database.
- _, dbNetwork, err := d.cluster.GetNetworkInAnyState(projectName, name)
- if err != nil {
- return response.SmartError(err)
- }
- if dbNetwork.Status == api.NetworkStatusPending {
- err := d.cluster.DeleteNetwork(projectName, name)
- if err != nil {
- return response.SmartError(err)
- }
- return response.EmptySyncResponse
- }
-
// Get the existing network.
n, err := network.LoadByName(state, projectName, name)
if err != nil {
@@ -635,7 +622,7 @@ func networkDelete(d *Daemon, r *http.Request) response.Response {
}
}
- // Delete the network.
+ // Delete the network from each member.
err = n.Delete(clientType)
if err != nil {
return response.SmartError(err)
From 5e551c15a2533b0f2db5c6e7cb5b879e87f26b4e Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 23 Nov 2020 17:26:34 +0000
Subject: [PATCH 35/37] lxd/networks: d.cluster.GetNetworkInAnyState usage
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/networks.go | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lxd/networks.go b/lxd/networks.go
index fd8a82ef35..6207073172 100644
--- a/lxd/networks.go
+++ b/lxd/networks.go
@@ -322,7 +322,7 @@ func networksPostCluster(d *Daemon, projectName string, req api.NetworksPost, cl
// Check that the requested network type matches the type created when adding the local node config.
// If network doesn't exist yet, ignore not found error, as this will be checked by NetworkNodeConfigs().
- _, netInfo, err := d.cluster.GetNetworkInAnyState(projectName, req.Name)
+ _, netInfo, _, err := d.cluster.GetNetworkInAnyState(projectName, req.Name)
if err != nil && err != db.ErrNoSuchObject {
return err
}
@@ -726,7 +726,7 @@ func networkPut(d *Daemon, r *http.Request) response.Response {
name := mux.Vars(r)["name"]
// Get the existing network.
- _, dbInfo, err := d.cluster.GetNetworkInAnyState(projectName, name)
+ _, dbInfo, _, err := d.cluster.GetNetworkInAnyState(projectName, name)
if err != nil {
return response.SmartError(err)
}
From 421d5d40291ba03bddf5f87157c6201e1b1e5116 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 23 Nov 2020 17:41:56 +0000
Subject: [PATCH 36/37] lxd/networks: Updates networksPostCluster to only mark
global network states as created once all nodes created
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/networks.go | 52 ++++++++++++++++++++++++-------------------------
1 file changed, 26 insertions(+), 26 deletions(-)
diff --git a/lxd/networks.go b/lxd/networks.go
index 6207073172..4896f116f8 100644
--- a/lxd/networks.go
+++ b/lxd/networks.go
@@ -312,6 +312,8 @@ func networksPost(d *Daemon, r *http.Request) response.Response {
return resp
}
+// networksPostCluster checks that there is a pending network in the database and then attempts to setup the
+// network on each node. If all nodes are successfully setup then the network's state is set to created.
func networksPostCluster(d *Daemon, projectName string, req api.NetworksPost, clientType cluster.ClientType, netType network.Type) error {
// Check that no node-specific config key has been supplied in request.
for key := range req.Config {
@@ -371,43 +373,27 @@ func networksPostCluster(d *Daemon, projectName string, req api.NetworksPost, cl
return err
}
- // Create the network on this node.
- nodeReq := req
-
- // Merge node specific config items into global config.
- for key, value := range configs[nodeName] {
- nodeReq.Config[key] = value
- }
-
- // Notify all other nodes to create the network.
+ // Create notifier for other nodes to create the network.
notifier, err := cluster.NewNotifier(d.State(), d.endpoints.NetworkCert(), cluster.NotifyAll)
if err != nil {
return err
}
- revert := revert.New()
- defer revert.Fail()
-
- revert.Add(func() {
- d.cluster.Transaction(func(tx *db.ClusterTx) error {
- return tx.NetworkErrored(projectName, req.Name)
- })
- })
+ // Create the network on this node.
+ nodeReq := req
- // We need to mark the network as created now, because the network.LoadByName call invoked by
- // doNetworksCreate would fail with not-found otherwise.
- err = d.cluster.Transaction(func(tx *db.ClusterTx) error {
- return tx.NetworkCreated(projectName, req.Name)
- })
- if err != nil {
- return err
+ // Merge node specific config items into global config.
+ for key, value := range configs[nodeName] {
+ nodeReq.Config[key] = value
}
err = doNetworksCreate(d, projectName, nodeReq, clientType)
if err != nil {
return err
}
+ logger.Error("Created network on local cluster member", log.Ctx{"project": projectName, "network": req.Name})
+ // Notify other nodes to create the network.
err = notifier(func(client lxd.InstanceServer) error {
server, _, err := client.GetServer()
if err != nil {
@@ -419,13 +405,27 @@ func networksPostCluster(d *Daemon, projectName string, req api.NetworksPost, cl
nodeReq.Config[key] = value
}
- return client.UseProject(projectName).CreateNetwork(nodeReq)
+ err = client.UseProject(projectName).CreateNetwork(nodeReq)
+ if err != nil {
+ return err
+ }
+ logger.Error("Created network on cluster member", log.Ctx{"project": projectName, "network": req.Name, "member": server.Environment.ServerName})
+
+ return nil
})
if err != nil {
return err
}
- revert.Success()
+ // Mark network global status as networkCreated now that all nodes have succeeded.
+ err = d.cluster.Transaction(func(tx *db.ClusterTx) error {
+ return tx.NetworkCreated(projectName, req.Name)
+ })
+ if err != nil {
+ return err
+ }
+ logger.Debug("Marked network global status as created", log.Ctx{"project": projectName, "network": req.Name})
+
return nil
}
From 10fe44e00eb6bfbc72f582dfaac80f42069f593f Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 23 Nov 2020 17:51:11 +0000
Subject: [PATCH 37/37] lxd/db/migration/test: cluster.GetNetworkInAnyState
usage
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/db/migration_test.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lxd/db/migration_test.go b/lxd/db/migration_test.go
index fb2c07d16c..1986c355c2 100644
--- a/lxd/db/migration_test.go
+++ b/lxd/db/migration_test.go
@@ -90,7 +90,7 @@ func TestImportPreClusteringData(t *testing.T) {
networks, err := cluster.GetNetworks(project.Default)
require.NoError(t, err)
assert.Equal(t, []string{"lxcbr0"}, networks)
- id, network, err := cluster.GetNetworkInAnyState(project.Default, "lxcbr0")
+ id, network, _, err := cluster.GetNetworkInAnyState(project.Default, "lxcbr0")
require.NoError(t, err)
assert.Equal(t, int64(1), id)
assert.Equal(t, "true", network.Config["ipv4.nat"])
More information about the lxc-devel
mailing list