[lxc-devel] [lxd/master] Network: Removes GetNetwork() and adds fixes errored networks from preventing LXD start

tomponline on Github lxc-bot at linuxcontainers.org
Mon Jul 20 13:55:44 UTC 2020


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 745 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20200720/e31a1823/attachment.bin>
-------------- next part --------------
From c6da02f90e41f3d1d12c4c11c337b5ab53630547 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 20 Jul 2020 12:32:33 +0100
Subject: [PATCH 01/16] shared/api/network: Adds network status constants

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 shared/api/network.go | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/shared/api/network.go b/shared/api/network.go
index c7280f59d3..12b126dc33 100644
--- a/shared/api/network.go
+++ b/shared/api/network.go
@@ -27,6 +27,18 @@ type NetworkPut struct {
 	Description string `json:"description" yaml:"description"`
 }
 
+// NetworkStatusPending network is pending creation on other cluster nodes.
+const NetworkStatusPending = "Pending"
+
+// NetworkStatusCreated network is fully created.
+const NetworkStatusCreated = "Created"
+
+// NetworkStatusErrored network is in error status.
+const NetworkStatusErrored = "Errored"
+
+// NetworkStatusUnknown network is in unknown status.
+const NetworkStatusUnknown = "Unknown"
+
 // Network represents a LXD network
 type Network struct {
 	NetworkPut `yaml:",inline"`

From 67d96396b4919b5da796220045f1975f792a99a6 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 20 Jul 2020 12:30:47 +0100
Subject: [PATCH 02/16] lxd/networks: API constant usage in networkDelete

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 4e114e2b41..7b8b7202cc 100644
--- a/lxd/networks.go
+++ b/lxd/networks.go
@@ -474,7 +474,7 @@ func networkDelete(d *Daemon, r *http.Request) response.Response {
 	if err != nil {
 		return response.SmartError(err)
 	}
-	if dbNetwork.Status == "Pending" {
+	if dbNetwork.Status == api.NetworkStatusPending {
 		err := d.cluster.DeleteNetwork(name)
 		if err != nil {
 			return response.SmartError(err)

From e30110322ef29ae21d7cc37ba641f144bdd548e7 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 20 Jul 2020 12:27:51 +0100
Subject: [PATCH 03/16] lxd/network/network/load: Adds status

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/network/network_load.go | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/lxd/network/network_load.go b/lxd/network/network_load.go
index 132e6933c5..6abb8430d4 100644
--- a/lxd/network/network_load.go
+++ b/lxd/network/network_load.go
@@ -11,7 +11,7 @@ var drivers = map[string]func() Network{
 
 // LoadByName loads the network info from the database by name.
 func LoadByName(s *state.State, name string) (Network, error) {
-	id, netInfo, err := s.Cluster.GetNetwork(name)
+	id, netInfo, err := s.Cluster.GetNetworkInAnyState(name)
 	if err != nil {
 		return nil, err
 	}
@@ -22,7 +22,7 @@ func LoadByName(s *state.State, name string) (Network, error) {
 	}
 
 	n := driverFunc()
-	n.init(s, id, name, netInfo.Type, netInfo.Description, netInfo.Config)
+	n.init(s, id, name, netInfo.Type, netInfo.Description, netInfo.Config, netInfo.Status)
 
 	return n, nil
 }
@@ -40,7 +40,7 @@ func Validate(name string, netType string, config map[string]string) error {
 	}
 
 	n := driverFunc()
-	n.init(nil, 0, name, netType, "", config)
+	n.init(nil, 0, name, netType, "", config, "Unknown")
 	return n.Validate(config)
 }
 
@@ -52,7 +52,7 @@ func FillConfig(req *api.NetworksPost) error {
 	}
 
 	n := driverFunc()
-	n.init(nil, 0, req.Name, req.Type, req.Description, req.Config)
+	n.init(nil, 0, req.Name, req.Type, req.Description, req.Config, "Unknown")
 
 	err := n.fillConfig(req)
 	if err != nil {

From 186f8efb00a9591fdbdc67e87c0f1bb7f0162114 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 20 Jul 2020 12:27:33 +0100
Subject: [PATCH 04/16] lxd/network/network/interface: Adds status function

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/network/network_interface.go | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/lxd/network/network_interface.go b/lxd/network/network_interface.go
index 9c2fd7424b..2691d424f9 100644
--- a/lxd/network/network_interface.go
+++ b/lxd/network/network_interface.go
@@ -9,13 +9,14 @@ import (
 // Network represents a LXD network.
 type Network interface {
 	// Load.
-	init(state *state.State, id int64, name string, netType string, description string, config map[string]string)
+	init(state *state.State, id int64, name string, netType string, description string, config map[string]string, status string)
 	fillConfig(*api.NetworksPost) error
 
 	// Config.
 	Validate(config map[string]string) error
 	Name() string
 	Type() string
+	Status() string
 	Config() map[string]string
 	IsUsed() bool
 	HasDHCPv4() bool

From 14235e71bcfe8a454b88b45c2d794843b59b639e Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 20 Jul 2020 12:26:57 +0100
Subject: [PATCH 05/16] lxd/network/driver/common: Adds status field and
 function

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/network/driver_common.go | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/lxd/network/driver_common.go b/lxd/network/driver_common.go
index 7b0c4e3c91..1cff49e438 100644
--- a/lxd/network/driver_common.go
+++ b/lxd/network/driver_common.go
@@ -34,10 +34,11 @@ type common struct {
 	netType     string
 	description string
 	config      map[string]string
+	status      string
 }
 
 // init initialise internal variables.
-func (n *common) init(state *state.State, id int64, name string, netType string, description string, config map[string]string) {
+func (n *common) init(state *state.State, id int64, name string, netType string, description string, config map[string]string, status string) {
 	n.logger = logging.AddContext(logger.Log, log.Ctx{"driver": netType, "network": name})
 	n.id = id
 	n.name = name
@@ -45,6 +46,7 @@ func (n *common) init(state *state.State, id int64, name string, netType string,
 	n.config = config
 	n.state = state
 	n.description = description
+	n.status = status
 }
 
 // fillConfig fills requested config with any default values, by default this is a no-op.
@@ -101,6 +103,11 @@ func (n *common) Name() string {
 	return n.name
 }
 
+// Status returns the network status.
+func (n *common) Status() string {
+	return n.status
+}
+
 // Type returns the network type.
 func (n *common) Type() string {
 	return n.netType
@@ -292,7 +299,7 @@ func (n *common) rename(newName string) error {
 	}
 
 	// Reinitialise internal name variable and logger context with new name.
-	n.init(n.state, n.id, newName, n.netType, n.description, n.config)
+	n.init(n.state, n.id, newName, n.netType, n.description, n.config, n.status)
 
 	return nil
 }

From b64ec9ad725c241699b8e73ae3f4b0166ffd88b7 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 20 Jul 2020 12:24:55 +0100
Subject: [PATCH 06/16] lxd/network/driver/bridge: Don't allow starting a
 pending network

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/network/driver_bridge.go | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/lxd/network/driver_bridge.go b/lxd/network/driver_bridge.go
index 3a1612029d..b302b3e79f 100644
--- a/lxd/network/driver_bridge.go
+++ b/lxd/network/driver_bridge.go
@@ -347,6 +347,10 @@ 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)

From f61ed2ca4c44513946bcdb71de6595ab34871c91 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 20 Jul 2020 12:23:42 +0100
Subject: [PATCH 07/16] lxd/device/nic/bridged: Usage of
 d.state.Cluster.GetNetworkInAnyState in rebuildDnsmasqEntry

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/device/nic_bridged.go | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/lxd/device/nic_bridged.go b/lxd/device/nic_bridged.go
index 622deda0ed..43fb8acb1f 100644
--- a/lxd/device/nic_bridged.go
+++ b/lxd/device/nic_bridged.go
@@ -456,8 +456,7 @@ func (d *nicBridged) Remove() error {
 	return nil
 }
 
-// rebuildDnsmasqEntry rebuilds the dnsmasq host entry if connected to an LXD managed network
-// and reloads dnsmasq.
+// rebuildDnsmasqEntry rebuilds the dnsmasq host entry if connected to an LXD managed network and reloads dnsmasq.
 func (d *nicBridged) rebuildDnsmasqEntry() error {
 	// Rebuild dnsmasq config if a bridged device has changed and parent is a managed network.
 	if !shared.PathExists(shared.VarPath("networks", d.config["parent"], "dnsmasq.pid")) {
@@ -467,7 +466,7 @@ func (d *nicBridged) rebuildDnsmasqEntry() error {
 	dnsmasq.ConfigMutex.Lock()
 	defer dnsmasq.ConfigMutex.Unlock()
 
-	_, dbInfo, err := d.state.Cluster.GetNetwork(d.config["parent"])
+	_, dbInfo, err := d.state.Cluster.GetNetworkInAnyState(d.config["parent"])
 	if err != nil {
 		return err
 	}

From 5fff6355cc39b652c4f69b7d70fdf679182f4ea8 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 20 Jul 2020 12:22:36 +0100
Subject: [PATCH 08/16] lxd/api/cluster: Usage of api.NetworkStatusPending

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/api_cluster.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lxd/api_cluster.go b/lxd/api_cluster.go
index d8cfb0a74c..15e2ed39b2 100644
--- a/lxd/api_cluster.go
+++ b/lxd/api_cluster.go
@@ -761,7 +761,7 @@ func clusterInitMember(d, client lxd.InstanceServer, memberConfig []api.ClusterM
 	// configs provided by the user.
 	for _, network := range networks {
 		// Skip not-managed or pending networks
-		if !network.Managed || network.Status == "Pending" {
+		if !network.Managed || network.Status == api.NetworkStatusPending {
 			continue
 		}
 

From 4e78f3859762531a611a76b42c1bdf58a7538538 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 20 Jul 2020 12:22:07 +0100
Subject: [PATCH 09/16] lxd/db/networks: Usage of api package's NetworkStatus
 constants in getNetwork

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 558c788f9b..1208fa23b4 100644
--- a/lxd/db/networks.go
+++ b/lxd/db/networks.go
@@ -357,13 +357,13 @@ func (c *Cluster) getNetwork(name string, onlyCreated bool) (int64, *api.Network
 
 	switch state {
 	case networkPending:
-		network.Status = "Pending"
+		network.Status = api.NetworkStatusPending
 	case networkCreated:
-		network.Status = "Created"
+		network.Status = api.NetworkStatusCreated
 	case networkErrored:
-		network.Status = "Errored"
+		network.Status = api.NetworkStatusErrored
 	default:
-		network.Status = "Unknown"
+		network.Status = api.NetworkStatusUnknown
 	}
 
 	switch netType {

From 08544a246ae9b0e967e7aef3644bfe4a0ed44d9b Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 20 Jul 2020 12:21:54 +0100
Subject: [PATCH 10/16] lxd/db/networks: Removes unused GetNetwork

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/db/networks.go | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/lxd/db/networks.go b/lxd/db/networks.go
index 1208fa23b4..8f941f9ee8 100644
--- a/lxd/db/networks.go
+++ b/lxd/db/networks.go
@@ -305,13 +305,6 @@ const (
 	NetworkTypeBridge NetworkType = iota // Network type bridge.
 )
 
-// GetNetwork returns the network with the given name.
-//
-// The network must be in the created stated, not pending.
-func (c *Cluster) GetNetwork(name string) (int64, *api.Network, error) {
-	return c.getNetwork(name, true)
-}
-
 // GetNetworkInAnyState returns the network with the given name.
 //
 // The network can be in any state.

From 2636beef7ed96820b4e8b2d2f049a78d826c5e8e Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 20 Jul 2020 12:21:44 +0100
Subject: [PATCH 11/16] lxd/db/networks: GetNonPendingNetworks comment

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/db/networks.go | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/lxd/db/networks.go b/lxd/db/networks.go
index 8f941f9ee8..a46be7af84 100644
--- a/lxd/db/networks.go
+++ b/lxd/db/networks.go
@@ -257,8 +257,7 @@ func (c *Cluster) GetNetworks() ([]string, error) {
 	return c.networks("")
 }
 
-// GetNonPendingNetworks returns the names of all networks that are not
-// pending.
+// GetNonPendingNetworks returns the names of all networks that are not pending.
 func (c *Cluster) GetNonPendingNetworks() ([]string, error) {
 	return c.networks("NOT state=?", networkPending)
 }

From 5d0e75954926d9ec950717a2c3791702fb231aaa Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 20 Jul 2020 12:20:54 +0100
Subject: [PATCH 12/16] lxd/db/networks: Allow pending nodes to be added to
 errored networks in CreatePendingNetwork

Allows potentially fixing the errored status.

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 a46be7af84..675e0f03b4 100644
--- a/lxd/db/networks.go
+++ b/lxd/db/networks.go
@@ -189,9 +189,9 @@ func (c *ClusterTx) CreatePendingNetwork(node, name string, netType NetworkType,
 			return err
 		}
 	} else {
-		// Check that the existing network  is in the pending state.
-		if network.state != networkPending {
-			return fmt.Errorf("network is not in pending state")
+		// Check that the existing network is in the pending state.
+		if network.state != networkPending && network.state != networkErrored {
+			return fmt.Errorf("Network is not in pending or errored state")
 		}
 	}
 

From 964d4da7ca6c56784f46f875beab9ec9d9be2699 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 20 Jul 2020 12:20:33 +0100
Subject: [PATCH 13/16] lxd/db/networks: CreatePendingNetwork comments and line
 spacing

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 675e0f03b4..5965f60e46 100644
--- a/lxd/db/networks.go
+++ b/lxd/db/networks.go
@@ -147,11 +147,9 @@ WHERE networks.id = ? AND networks.state = ?
 	return configs, nil
 }
 
-// CreatePendingNetwork creates a new pending network on the node with
-// the given name.
+// CreatePendingNetwork creates a new pending network on the node with the given name.
 func (c *ClusterTx) CreatePendingNetwork(node, name string, netType NetworkType, conf map[string]string) error {
-	// First check if a network with the given name exists, and, if
-	// so, that it's in the pending state.
+	// 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
@@ -161,27 +159,29 @@ func (c *ClusterTx) CreatePendingNetwork(node, name string, netType NetworkType,
 	dest := func(i int) []interface{} {
 		// Sanity check that there is at most one pool with the given name.
 		if i != 0 {
-			errConsistency = fmt.Errorf("more than one network exists with the given name")
+			errConsistency = fmt.Errorf("More than one network exists with the given name")
 		}
 		return []interface{}{&network.id, &network.state}
 	}
+
 	stmt, err := c.tx.Prepare("SELECT id, state FROM networks WHERE name=?")
 	if err != nil {
 		return err
 	}
 	defer stmt.Close()
+
 	err = query.SelectObjects(stmt, dest, name)
 	if err != nil {
 		return err
 	}
+
 	if errConsistency != nil {
 		return errConsistency
 	}
 
 	var networkID = network.id
 	if networkID == 0 {
-		// No existing network with the given name was found, let's create
-		// one.
+		// No existing network with the given name was found, let's create one.
 		columns := []string{"name", "type"}
 		values := []interface{}{name, netType}
 		networkID, err = query.UpsertObject(c.tx, "networks", columns, values)
@@ -202,8 +202,7 @@ func (c *ClusterTx) CreatePendingNetwork(node, name string, netType NetworkType,
 	}
 
 	// Check that no network entry for this node and network exists yet.
-	count, err := query.Count(
-		c.tx, "networks_nodes", "network_id=? AND node_id=?", networkID, nodeInfo.ID)
+	count, err := query.Count(c.tx, "networks_nodes", "network_id=? AND node_id=?", networkID, nodeInfo.ID)
 	if err != nil {
 		return err
 	}
@@ -218,6 +217,7 @@ func (c *ClusterTx) CreatePendingNetwork(node, name string, netType NetworkType,
 	if err != nil {
 		return err
 	}
+
 	err = c.CreateNetworkConfig(networkID, nodeInfo.ID, conf)
 	if err != nil {
 		return err

From c36366a87b69a38baa5b77fd10165e4d10e51ff2 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 20 Jul 2020 11:22:36 +0100
Subject: [PATCH 14/16] lxd/networks/utils: Skip network load error in
 networkUpdateForkdnsServersTask

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/networks_utils.go | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/lxd/networks_utils.go b/lxd/networks_utils.go
index 684abdc983..ecda29c599 100644
--- a/lxd/networks_utils.go
+++ b/lxd/networks_utils.go
@@ -14,6 +14,7 @@ import (
 	"github.com/lxc/lxd/lxd/state"
 	"github.com/lxc/lxd/shared"
 	"github.com/lxc/lxd/shared/api"
+	"github.com/lxc/lxd/shared/logger"
 )
 
 func readUint(path string) (uint64, error) {
@@ -77,7 +78,8 @@ func networkUpdateForkdnsServersTask(s *state.State, heartbeatData *cluster.APIH
 	for _, name := range networks {
 		n, err := network.LoadByName(s, name)
 		if err != nil {
-			return err
+			logger.Errorf("Failed to load network %q for heartbeat", name)
+			continue
 		}
 
 		if n.Type() == "bridge" && n.Config()["bridge.mode"] == "fan" {

From b89d1dd3046b8f8c8cdef6bf8aa568aa04302e32 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Fri, 17 Jul 2020 15:42:16 +0100
Subject: [PATCH 15/16] lxd/device/nic/bridged: Validates network is type
 bridge

Now that different NIC types support the "network" key.

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/device/nic_bridged.go | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/lxd/device/nic_bridged.go b/lxd/device/nic_bridged.go
index 43fb8acb1f..9024563756 100644
--- a/lxd/device/nic_bridged.go
+++ b/lxd/device/nic_bridged.go
@@ -82,6 +82,11 @@ func (d *nicBridged) validateConfig(instConf instance.ConfigReader) error {
 		if err != nil {
 			return errors.Wrapf(err, "Error loading network config for %q", d.config["network"])
 		}
+
+		if n.Type() != "bridge" {
+			return fmt.Errorf("Specified network must be of type bridge")
+		}
+
 		netConfig := n.Config()
 
 		if d.config["ipv4.address"] != "" {
@@ -128,6 +133,7 @@ func (d *nicBridged) validateConfig(instConf instance.ConfigReader) error {
 			d.config["mtu"] = netConfig["bridge.mtu"]
 		}
 
+		// Copy certain keys verbatim from the network's settings.
 		inheritKeys := []string{"maas.subnet.ipv4", "maas.subnet.ipv6"}
 		for _, inheritKey := range inheritKeys {
 			if _, found := netConfig[inheritKey]; found {

From 4c9c612389f56840ab3d25eeeb916511b05446be Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 20 Jul 2020 12:23:07 +0100
Subject: [PATCH 16/16] lxc/device/nic/bridged: Only allow using non-Pending
 networks

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/device/nic_bridged.go | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/lxd/device/nic_bridged.go b/lxd/device/nic_bridged.go
index 9024563756..eed02222de 100644
--- a/lxd/device/nic_bridged.go
+++ b/lxd/device/nic_bridged.go
@@ -28,6 +28,7 @@ import (
 	"github.com/lxc/lxd/lxd/revert"
 	"github.com/lxc/lxd/lxd/util"
 	"github.com/lxc/lxd/shared"
+	"github.com/lxc/lxd/shared/api"
 	log "github.com/lxc/lxd/shared/log15"
 	"github.com/lxc/lxd/shared/logger"
 )
@@ -83,6 +84,10 @@ func (d *nicBridged) validateConfig(instConf instance.ConfigReader) error {
 			return errors.Wrapf(err, "Error loading network config for %q", d.config["network"])
 		}
 
+		if n.Status() == api.NetworkStatusPending {
+			return fmt.Errorf("Specified network is not fully created")
+		}
+
 		if n.Type() != "bridge" {
 			return fmt.Errorf("Specified network must be of type bridge")
 		}


More information about the lxc-devel mailing list