The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/7905
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) === - Removes network loader helpers that don't require a DB record and replace it with a generic `LoadByType` that returns an interface that is safe to use without a DB record. - Adds `DBType()` and `Type()` functions to each network driver. - Adds `NodeSpecificConfig` flag to driver `Info` type indicating whether the network driver supports per-node cluster config. - Updates network creation to populate "pending" network node entries automatically when network driver doesn't support per-node cluster config, to avoid needing to specify `--target` when creating a network of that type. - Fixes dependent network start order, so that networks specifying another network always start after their parent.
From cbcd0da2fa9b5fdc43d114c97138d45e7f8a91c5 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Mon, 21 Sep 2020 10:34:19 +0100 Subject: [PATCH 01/22] lxd/network/network/interface: Adds Type interface and moves non-DB depedent functions into it Embeds Type interface into existing Network interface. Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/network/network_interface.go | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/lxd/network/network_interface.go b/lxd/network/network_interface.go index 2e3cefd4a1..1a095feb71 100644 --- a/lxd/network/network_interface.go +++ b/lxd/network/network_interface.go @@ -9,19 +9,25 @@ import ( "github.com/lxc/lxd/shared/api" ) -// Network represents a LXD network. +// Type represents an LXD network driver type. +type Type interface { + fillConfig(config map[string]string) error + Info() Info + ValidateName(name string) error + Type() string +} + +// Network represents an instantiated LXD network. 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) - fillConfig(config map[string]string) error - Info() Info // Config. - ValidateName(name string) error Validate(config map[string]string) error ID() int64 Name() string - Type() string Description() string Status() string Config() map[string]string From 4454e4c9a3fd5c9b04dacfdad6b4d2b6fa811410 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Mon, 21 Sep 2020 10:35:12 +0100 Subject: [PATCH 02/22] lxd/network/network/load: Adds LoadByType function and removes ValidateNameAndProject function As we add more driver type functionality that needs to occur before DB records are created, it makes sense to move these functions into their own interface, rather than relying on ever more helper functions at the package level. Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/network/network_load.go | 38 +++++++++++++------------------------ 1 file changed, 13 insertions(+), 25 deletions(-) diff --git a/lxd/network/network_load.go b/lxd/network/network_load.go index d3fe2cd50f..90f10c3649 100644 --- a/lxd/network/network_load.go +++ b/lxd/network/network_load.go @@ -1,8 +1,6 @@ package network import ( - "fmt" - "github.com/pkg/errors" "github.com/lxc/lxd/lxd/project" @@ -17,7 +15,19 @@ var drivers = map[string]func() Network{ "ovn": func() Network { return &ovn{} }, } -// LoadByName loads the network info from the database by name. +// LoadByType loads a network by driver type. +func LoadByType(driverType string) (Type, error) { + driverFunc, ok := drivers[driverType] + if !ok { + return nil, ErrUnknownDriver + } + + n := driverFunc() + + return n, nil +} + +// LoadByName loads an instantiated network from the database by name. func LoadByName(s *state.State, project string, name string) (Network, error) { id, netInfo, err := s.Cluster.GetNetworkInAnyState(project, name) if err != nil { @@ -35,28 +45,6 @@ func LoadByName(s *state.State, project string, name string) (Network, error) { return n, nil } -// ValidateNameAndProject validates the supplied network name and project support for the specified network type. -func ValidateNameAndProject(name string, networkProjectName string, netType string) error { - driverFunc, ok := drivers[netType] - if !ok { - return ErrUnknownDriver - } - - n := driverFunc() - n.init(nil, 0, networkProjectName, name, netType, "", nil, "Unknown") - - err := n.ValidateName(name) - if err != nil { - return errors.Wrapf(err, "Network name invalid") - } - - if networkProjectName != project.Default && !n.Info().Projects { - return fmt.Errorf("Network type does not support non-default projects") - } - - return nil -} - // Validate validates the supplied network name and configuration for the specified network type. func Validate(name string, netType string, config map[string]string) error { driverFunc, ok := drivers[netType] From 335ba9bdb20c22f0b278a2b3a05bfa15772bc652 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Mon, 21 Sep 2020 10:36:37 +0100 Subject: [PATCH 03/22] lxd/main/init/interactive: netType.ValidateName usage Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/main_init_interactive.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lxd/main_init_interactive.go b/lxd/main_init_interactive.go index 95679380b6..5fa8f755a6 100644 --- a/lxd/main_init_interactive.go +++ b/lxd/main_init_interactive.go @@ -365,7 +365,14 @@ func (c *cmdInit) askNetworking(config *cmdInitData, d lxd.InstanceServer) error net.Project = project.Default // Network name - net.Name = cli.AskString("What should the new bridge be called? [default=lxdbr0]: ", "lxdbr0", func(netName string) error { return network.ValidateNameAndProject(netName, project.Default, "bridge") }) + net.Name = cli.AskString("What should the new bridge be called? [default=lxdbr0]: ", "lxdbr0", func(netName string) error { + netType, err := network.LoadByType("bridge") + if err != nil { + return err + } + + return netType.ValidateName(netName) + }) _, _, err := d.GetNetwork(net.Name) if err == nil { fmt.Printf("The requested network bridge \"%s\" already exists. Please choose another name.\n", net.Name) From ceb500dd55671f4ec71fdb5cbdae82f5b3daa03d Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Mon, 21 Sep 2020 10:37:11 +0100 Subject: [PATCH 04/22] lxd/networks: Switch to network type validation in networksPost Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/networks.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lxd/networks.go b/lxd/networks.go index a294227cc0..a5d07c8566 100644 --- a/lxd/networks.go +++ b/lxd/networks.go @@ -151,11 +151,21 @@ func networksPost(d *Daemon, r *http.Request) response.Response { req.Config = map[string]string{} } - err = network.ValidateNameAndProject(req.Name, projectName, req.Type) + netType, err := network.LoadByType(req.Type) if err != nil { return response.BadRequest(err) } + err = netType.ValidateName(req.Name) + if err != nil { + return response.BadRequest(err) + } + + netTypeInfo := netType.Info() + if projectName != project.Default && !netTypeInfo.Projects { + return response.BadRequest(fmt.Errorf("Network type does not support non-default projects")) + } + // Check if project has limits.network and if so check we are allowed to create another network. if projectName != project.Default && projectConfig != nil && projectConfig["limits.networks"] != "" { networksLimit, err := strconv.Atoi(projectConfig["limits.networks"]) From e5f92170652d5e9349732da43b5a4be23997e190 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Mon, 21 Sep 2020 10:37:38 +0100 Subject: [PATCH 05/22] lxd/networks: Use ValidateName function on loaded DB network in networkPost Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/networks.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lxd/networks.go b/lxd/networks.go index a5d07c8566..a33b058eba 100644 --- a/lxd/networks.go +++ b/lxd/networks.go @@ -646,7 +646,7 @@ func networkPost(d *Daemon, r *http.Request) response.Response { return response.BadRequest(fmt.Errorf("New network name not provided")) } - err = network.ValidateNameAndProject(req.Name, projectName, n.Type()) + err = n.ValidateName(req.Name) if err != nil { return response.BadRequest(err) } From 77b5b0bded45befed01c10891a81c50e9498e1a3 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Mon, 21 Sep 2020 10:57:19 +0100 Subject: [PATCH 06/22] lxd/network/network/interface: Exports FillConfig Signed-off-by: Thomas Parrott <thomas.parr...@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 1a095feb71..0dc28b4184 100644 --- a/lxd/network/network_interface.go +++ b/lxd/network/network_interface.go @@ -11,7 +11,7 @@ import ( // Type represents an LXD network driver type. type Type interface { - fillConfig(config map[string]string) error + FillConfig(config map[string]string) error Info() Info ValidateName(name string) error Type() string From 2b77135298ef1f7cd6938171b24af452a473a040 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Mon, 21 Sep 2020 10:57:40 +0100 Subject: [PATCH 07/22] lxd/network/network/load: Removes FillConfig function Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/network/network_load.go | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/lxd/network/network_load.go b/lxd/network/network_load.go index 90f10c3649..862ba2831b 100644 --- a/lxd/network/network_load.go +++ b/lxd/network/network_load.go @@ -5,7 +5,6 @@ import ( "github.com/lxc/lxd/lxd/project" "github.com/lxc/lxd/lxd/state" - "github.com/lxc/lxd/shared/api" ) var drivers = map[string]func() Network{ @@ -62,21 +61,3 @@ func Validate(name string, netType string, config map[string]string) error { return n.Validate(config) } - -// FillConfig populates the supplied api.NetworkPost with automatically populated values. -func FillConfig(req *api.NetworksPost) error { - driverFunc, ok := drivers[req.Type] - if !ok { - return ErrUnknownDriver - } - - n := driverFunc() - n.init(nil, 0, project.Default, req.Name, req.Type, req.Description, req.Config, "Unknown") - - err := n.fillConfig(req.Config) - if err != nil { - return err - } - - return nil -} From b7e848b5b22851f05c0a405858bfa5636fefb65e Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Mon, 21 Sep 2020 10:58:14 +0100 Subject: [PATCH 08/22] lxd/networks: netType.FillConfig usage Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/networks.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lxd/networks.go b/lxd/networks.go index a33b058eba..cdcd5ce2c7 100644 --- a/lxd/networks.go +++ b/lxd/networks.go @@ -246,7 +246,7 @@ func networksPost(d *Daemon, r *http.Request) response.Response { } if count > 1 { - err = networksPostCluster(d, projectName, req, clientType) + err = networksPostCluster(d, projectName, req, clientType, netType) if err != nil { return response.SmartError(err) } @@ -255,7 +255,7 @@ func networksPost(d *Daemon, r *http.Request) response.Response { } // Non-clustered network creation. - err = network.FillConfig(&req) + err = netType.FillConfig(req.Config) if err != nil { return response.SmartError(err) } @@ -291,7 +291,7 @@ func networksPost(d *Daemon, r *http.Request) response.Response { return resp } -func networksPostCluster(d *Daemon, projectName string, req api.NetworksPost, clientType cluster.ClientType) error { +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 defined. for key := range req.Config { if shared.StringInSlice(key, db.NodeSpecificNetworkConfig) { @@ -311,7 +311,7 @@ func networksPostCluster(d *Daemon, projectName string, req api.NetworksPost, cl } // Add default values. - err = network.FillConfig(&req) + err = netType.FillConfig(req.Config) if err != nil { return err } From e3e07697081285cf4350a03012231071aad95483 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Mon, 21 Sep 2020 10:58:43 +0100 Subject: [PATCH 09/22] lxd/network/driver/common: Exports FillConfig Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/network/driver_common.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lxd/network/driver_common.go b/lxd/network/driver_common.go index 23e9f72d8b..6a4eda396d 100644 --- a/lxd/network/driver_common.go +++ b/lxd/network/driver_common.go @@ -44,15 +44,14 @@ func (n *common) init(state *state.State, id int64, projectName string, name str n.id = id n.project = projectName n.name = name - n.netType = netType 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. -func (n *common) fillConfig(config map[string]string) error { +// FillConfig fills requested config with any default values, by default this is a no-op. +func (n *common) FillConfig(config map[string]string) error { return nil } From 2f642388b57522921a7317d36b671e69b98e3ea0 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Mon, 21 Sep 2020 11:00:04 +0100 Subject: [PATCH 10/22] lxd/network/driver/bridge: FillConfig usage Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/network/driver_bridge.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lxd/network/driver_bridge.go b/lxd/network/driver_bridge.go index 42c10c9814..5cc54a38f0 100644 --- a/lxd/network/driver_bridge.go +++ b/lxd/network/driver_bridge.go @@ -71,8 +71,8 @@ func (n *bridge) checkClusterWideMACSafe(config map[string]string) error { return nil } -// fillConfig fills requested config with any default values. -func (n *bridge) fillConfig(config map[string]string) error { +// FillConfig fills requested config with any default values. +func (n *bridge) FillConfig(config map[string]string) error { // Set some default values where needed. if config["bridge.mode"] == "fan" { if config["fan.underlay_subnet"] == "" { @@ -1504,7 +1504,7 @@ func (n *bridge) Update(newNetwork api.NetworkPut, targetNode string, clientType n.logger.Debug("Update", log.Ctx{"clientType": clientType, "newNetwork": newNetwork}) // Populate default values if they are missing. - err := n.fillConfig(newNetwork.Config) + err := n.FillConfig(newNetwork.Config) if err != nil { return err } From 7f3b012ba2e67be527e890a64814f5a25f064c84 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Mon, 21 Sep 2020 11:00:27 +0100 Subject: [PATCH 11/22] lxd/network/driver/ovn: FillConfig usage Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/network/driver_ovn.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lxd/network/driver_ovn.go b/lxd/network/driver_ovn.go index d136d47c46..d79618d6d5 100644 --- a/lxd/network/driver_ovn.go +++ b/lxd/network/driver_ovn.go @@ -685,8 +685,8 @@ func (n *ovn) deleteParentPortBridge(parentNet Network) error { return nil } -// fillConfig fills requested config with any default values. -func (n *ovn) fillConfig(config map[string]string) error { +// FillConfig fills requested config with any default values. +func (n *ovn) FillConfig(config map[string]string) error { if config["ipv4.address"] == "" { config["ipv4.address"] = "auto" } @@ -1209,7 +1209,7 @@ func (n *ovn) Update(newNetwork api.NetworkPut, targetNode string, clientType cl n.logger.Debug("Update", log.Ctx{"clientType": clientType, "newNetwork": newNetwork}) // Populate default values if they are missing. - err := n.fillConfig(newNetwork.Config) + err := n.FillConfig(newNetwork.Config) if err != nil { return err } From a1a80fd6e884fc1fe2a629932745ec1ed68a74e6 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Mon, 21 Sep 2020 10:59:06 +0100 Subject: [PATCH 12/22] lxd/network/driver/common: Removes common Type() and netType Type() should be implemented by each driver. Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/network/driver_common.go | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/lxd/network/driver_common.go b/lxd/network/driver_common.go index 6a4eda396d..dae25bbaa1 100644 --- a/lxd/network/driver_common.go +++ b/lxd/network/driver_common.go @@ -32,7 +32,6 @@ type common struct { id int64 project string name string - netType string description string config map[string]string status string @@ -124,11 +123,6 @@ func (n *common) Status() string { return n.status } -// Type returns the network type. -func (n *common) Type() string { - return n.netType -} - // Config returns the network config. func (n *common) Config() map[string]string { return n.config @@ -205,7 +199,8 @@ func (n *common) DHCPv6Ranges() []shared.IPRange { func (n *common) update(applyNetwork api.NetworkPut, targetNode string, clientType cluster.ClientType) error { // Update internal config before database has been updated (so that if update is a notification we apply // the config being supplied and not that in the database). - n.init(n.state, n.id, n.project, n.name, n.netType, applyNetwork.Description, applyNetwork.Config, n.status) + n.description = applyNetwork.Description + n.config = applyNetwork.Config // If this update isn't coming via a cluster notification itself, then notify all nodes of change and then // update the database. @@ -316,7 +311,7 @@ func (n *common) rename(newName string) error { } // Reinitialise internal name variable and logger context with new name. - n.init(n.state, n.id, n.project, newName, n.netType, n.description, n.config, n.status) + n.name = newName return nil } From adadc6640b27bc7c0947b5435307f430d7487d01 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Mon, 21 Sep 2020 11:00:56 +0100 Subject: [PATCH 13/22] lxd/network: Adds Type() to each driver Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/network/driver_bridge.go | 5 +++++ lxd/network/driver_macvlan.go | 5 +++++ lxd/network/driver_ovn.go | 5 +++++ lxd/network/driver_sriov.go | 5 +++++ 4 files changed, 20 insertions(+) diff --git a/lxd/network/driver_bridge.go b/lxd/network/driver_bridge.go index 5cc54a38f0..100731cd61 100644 --- a/lxd/network/driver_bridge.go +++ b/lxd/network/driver_bridge.go @@ -48,6 +48,11 @@ type bridge struct { common } +// Type returns the network type. +func (n *bridge) Type() string { + return "bridge" +} + // checkClusterWideMACSafe returns whether it is safe to use the same MAC address for the bridge interface on all // cluster nodes. It is not suitable to use a static MAC address when "bridge.external_interfaces" is non-empty an // the bridge interface has no IPv4 or IPv6 address set. This is because in a clustered environment the same bridge diff --git a/lxd/network/driver_macvlan.go b/lxd/network/driver_macvlan.go index 7593eb82db..8b4369c20f 100644 --- a/lxd/network/driver_macvlan.go +++ b/lxd/network/driver_macvlan.go @@ -15,6 +15,11 @@ type macvlan struct { common } +// Type returns the network type. +func (n *macvlan) Type() string { + return "macvlan" +} + // Validate network config. func (n *macvlan) Validate(config map[string]string) error { rules := map[string]func(value string) error{ diff --git a/lxd/network/driver_ovn.go b/lxd/network/driver_ovn.go index d79618d6d5..7e09d6a0b2 100644 --- a/lxd/network/driver_ovn.go +++ b/lxd/network/driver_ovn.go @@ -63,6 +63,11 @@ type ovn struct { common } +// Type returns the network type. +func (n *ovn) Type() string { + return "ovn" +} + // Config returns the network driver info. func (n *ovn) Info() Info { return Info{ diff --git a/lxd/network/driver_sriov.go b/lxd/network/driver_sriov.go index 6bcbec7557..1ed0df6cdd 100644 --- a/lxd/network/driver_sriov.go +++ b/lxd/network/driver_sriov.go @@ -15,6 +15,11 @@ type sriov struct { common } +// Type returns the network type. +func (n *sriov) Type() string { + return "sriov" +} + // Validate network config. func (n *sriov) Validate(config map[string]string) error { rules := map[string]func(value string) error{ From 861ae0d937cb927b0a1a2911a837a228583485dd Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Mon, 21 Sep 2020 15:19:18 +0100 Subject: [PATCH 14/22] lxd/db/errors: Updates ErrAlreadyDefined text to be generic As is used in non-instance contexts. Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/db/errors.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lxd/db/errors.go b/lxd/db/errors.go index cdd4a2eee2..c1f046a7dc 100644 --- a/lxd/db/errors.go +++ b/lxd/db/errors.go @@ -7,7 +7,7 @@ import ( var ( // ErrAlreadyDefined hapens when the given entry already exists, // for example a container. - ErrAlreadyDefined = fmt.Errorf("The instance/snapshot already exists") + ErrAlreadyDefined = fmt.Errorf("The record already exists") // ErrNoSuchObject is in the case of joins (and probably other) queries, // we don't get back sql.ErrNoRows when no rows are returned, even though we do From 7a06fbc31b0a7a226a6fcf6c32c734a9b4891c07 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Mon, 21 Sep 2020 15:19:46 +0100 Subject: [PATCH 15/22] lxd/network/network/interface: Adds DBType function Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/network/network_interface.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lxd/network/network_interface.go b/lxd/network/network_interface.go index 0dc28b4184..b9ba1e89d1 100644 --- a/lxd/network/network_interface.go +++ b/lxd/network/network_interface.go @@ -4,6 +4,7 @@ import ( "net" "github.com/lxc/lxd/lxd/cluster" + "github.com/lxc/lxd/lxd/db" "github.com/lxc/lxd/lxd/state" "github.com/lxc/lxd/shared" "github.com/lxc/lxd/shared/api" @@ -15,6 +16,7 @@ type Type interface { Info() Info ValidateName(name string) error Type() string + DBType() db.NetworkType } // Network represents an instantiated LXD network. From cb5a4da6a6bd2ab19ce3369aeca8c2c75be0c8a1 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Mon, 21 Sep 2020 15:20:38 +0100 Subject: [PATCH 16/22] lxd/network/driver: Implements DBType() Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/network/driver_bridge.go | 6 ++++++ lxd/network/driver_macvlan.go | 6 ++++++ lxd/network/driver_ovn.go | 5 +++++ lxd/network/driver_sriov.go | 6 ++++++ 4 files changed, 23 insertions(+) diff --git a/lxd/network/driver_bridge.go b/lxd/network/driver_bridge.go index 100731cd61..cce5e1d245 100644 --- a/lxd/network/driver_bridge.go +++ b/lxd/network/driver_bridge.go @@ -21,6 +21,7 @@ import ( "github.com/lxc/lxd/lxd/apparmor" "github.com/lxc/lxd/lxd/cluster" "github.com/lxc/lxd/lxd/daemon" + "github.com/lxc/lxd/lxd/db" "github.com/lxc/lxd/lxd/dnsmasq" "github.com/lxc/lxd/lxd/dnsmasq/dhcpalloc" "github.com/lxc/lxd/lxd/network/openvswitch" @@ -53,6 +54,11 @@ func (n *bridge) Type() string { return "bridge" } +// DBType returns the network type DB ID. +func (n *bridge) DBType() db.NetworkType { + return db.NetworkTypeBridge +} + // checkClusterWideMACSafe returns whether it is safe to use the same MAC address for the bridge interface on all // cluster nodes. It is not suitable to use a static MAC address when "bridge.external_interfaces" is non-empty an // the bridge interface has no IPv4 or IPv6 address set. This is because in a clustered environment the same bridge diff --git a/lxd/network/driver_macvlan.go b/lxd/network/driver_macvlan.go index 8b4369c20f..8f82680e35 100644 --- a/lxd/network/driver_macvlan.go +++ b/lxd/network/driver_macvlan.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/lxc/lxd/lxd/cluster" + "github.com/lxc/lxd/lxd/db" "github.com/lxc/lxd/lxd/revert" "github.com/lxc/lxd/shared/api" log "github.com/lxc/lxd/shared/log15" @@ -20,6 +21,11 @@ func (n *macvlan) Type() string { return "macvlan" } +// DBType returns the network type DB ID. +func (n *macvlan) DBType() db.NetworkType { + return db.NetworkTypeMacvlan +} + // Validate network config. func (n *macvlan) Validate(config map[string]string) error { rules := map[string]func(value string) error{ diff --git a/lxd/network/driver_ovn.go b/lxd/network/driver_ovn.go index 7e09d6a0b2..fa68cf4e6d 100644 --- a/lxd/network/driver_ovn.go +++ b/lxd/network/driver_ovn.go @@ -68,6 +68,11 @@ func (n *ovn) Type() string { return "ovn" } +// DBType returns the network type DB ID. +func (n *ovn) DBType() db.NetworkType { + return db.NetworkTypeOVN +} + // Config returns the network driver info. func (n *ovn) Info() Info { return Info{ diff --git a/lxd/network/driver_sriov.go b/lxd/network/driver_sriov.go index 1ed0df6cdd..698242778f 100644 --- a/lxd/network/driver_sriov.go +++ b/lxd/network/driver_sriov.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/lxc/lxd/lxd/cluster" + "github.com/lxc/lxd/lxd/db" "github.com/lxc/lxd/lxd/revert" "github.com/lxc/lxd/shared/api" log "github.com/lxc/lxd/shared/log15" @@ -20,6 +21,11 @@ func (n *sriov) Type() string { return "sriov" } +// DBType returns the network type DB ID. +func (n *sriov) DBType() db.NetworkType { + return db.NetworkTypeSriov +} + // Validate network config. func (n *sriov) Validate(config map[string]string) error { rules := map[string]func(value string) error{ From a8c46bcfb5690b4b147290fda2e7e4bd690d3261 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Mon, 21 Sep 2020 15:21:00 +0100 Subject: [PATCH 17/22] lxd/network/driver: Adds NodeSpecificConfig Info var Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/network/driver_common.go | 6 ++++-- lxd/network/driver_ovn.go | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lxd/network/driver_common.go b/lxd/network/driver_common.go index dae25bbaa1..3c422c5a1a 100644 --- a/lxd/network/driver_common.go +++ b/lxd/network/driver_common.go @@ -22,7 +22,8 @@ import ( // Info represents information about a network driver. type Info struct { - Projects bool // Indicates if driver can be used in network enabled projects. + Projects bool // Indicates if driver can be used in network enabled projects. + NodeSpecificConfig bool // Whether driver has cluster node specific config as a prerequisite for creation. } // common represents a generic LXD network. @@ -131,7 +132,8 @@ func (n *common) Config() map[string]string { // Config returns the common network driver info. func (n *common) Info() Info { return Info{ - Projects: false, + Projects: false, + NodeSpecificConfig: true, } } diff --git a/lxd/network/driver_ovn.go b/lxd/network/driver_ovn.go index fa68cf4e6d..0f62cc7d4c 100644 --- a/lxd/network/driver_ovn.go +++ b/lxd/network/driver_ovn.go @@ -76,7 +76,8 @@ func (n *ovn) DBType() db.NetworkType { // Config returns the network driver info. func (n *ovn) Info() Info { return Info{ - Projects: true, + Projects: true, + NodeSpecificConfig: false, } } From d0ae93e802f66b9e7df9c53cd2a87f562b6d95a9 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Mon, 21 Sep 2020 15:24:23 +0100 Subject: [PATCH 18/22] lxd/networks: netType.DBType usage in networksPost Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/networks.go | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/lxd/networks.go b/lxd/networks.go index cdcd5ce2c7..e1b69e1fd4 100644 --- a/lxd/networks.go +++ b/lxd/networks.go @@ -186,21 +186,6 @@ func networksPost(d *Daemon, r *http.Request) response.Response { } } - // Convert requested network type to DB type code. - var dbNetType db.NetworkType - switch req.Type { - case "bridge": - dbNetType = db.NetworkTypeBridge - case "macvlan": - dbNetType = db.NetworkTypeMacvlan - case "sriov": - dbNetType = db.NetworkTypeSriov - case "ovn": - dbNetType = db.NetworkTypeOVN - default: - return response.BadRequest(fmt.Errorf("Unrecognised network type")) - } - url := fmt.Sprintf("/%s/networks/%s", version.APIVersion, req.Name) resp := response.SyncResponseLocation(true, nil, url) @@ -218,6 +203,10 @@ func networksPost(d *Daemon, r *http.Request) response.Response { targetNode := queryParam(r, "target") if targetNode != "" { + if !netTypeInfo.NodeSpecificConfig { + return response.BadRequest(fmt.Errorf("Network type %q does not support node specific config", netType.Type())) + } + // A targetNode was specified, let's just define the node's network without actually creating it. // Check that only NodeSpecificNetworkConfig keys are specified. for key := range req.Config { @@ -227,7 +216,7 @@ func networksPost(d *Daemon, r *http.Request) response.Response { } err = d.cluster.Transaction(func(tx *db.ClusterTx) error { - return tx.CreatePendingNetwork(targetNode, projectName, req.Name, dbNetType, req.Config) + return tx.CreatePendingNetwork(targetNode, projectName, req.Name, netType.DBType(), req.Config) }) if err != nil { if err == db.ErrAlreadyDefined { @@ -269,15 +258,20 @@ func networksPost(d *Daemon, r *http.Request) response.Response { return response.BadRequest(fmt.Errorf("The network already exists")) } + // Populate default config. + err = netType.FillConfig(req.Config) + if err != nil { + return response.SmartError(err) + } + revert := revert.New() defer revert.Fail() // Create the database entry. - _, err = d.cluster.CreateNetwork(projectName, req.Name, req.Description, dbNetType, req.Config) + _, err = d.cluster.CreateNetwork(projectName, req.Name, req.Description, netType.DBType(), req.Config) if err != nil { return response.SmartError(errors.Wrapf(err, "Error inserting %q into database", req.Name)) } - revert.Add(func() { d.cluster.DeleteNetwork(projectName, req.Name) }) From c1da0f64ee2bfa0e1b921ee86b6c4e5973e14e52 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Mon, 21 Sep 2020 15:25:54 +0100 Subject: [PATCH 19/22] lxd/networks: Create pending network node entries when network driver doesn't support per node config in networksPost Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/networks.go | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/lxd/networks.go b/lxd/networks.go index e1b69e1fd4..10903bcbe2 100644 --- a/lxd/networks.go +++ b/lxd/networks.go @@ -201,6 +201,9 @@ func networksPost(d *Daemon, r *http.Request) response.Response { return resp } + revert := revert.New() + defer revert.Fail() + targetNode := queryParam(r, "target") if targetNode != "" { if !netTypeInfo.NodeSpecificConfig { @@ -226,6 +229,31 @@ func networksPost(d *Daemon, r *http.Request) response.Response { } return resp + } else if !netTypeInfo.NodeSpecificConfig && clientType != cluster.ClientTypeJoiner { + // Simulate adding pending node network config when the driver doesn't support per-node config. + revert.Add(func() { + d.cluster.DeleteNetwork(projectName, req.Name) + }) + + // Create pending entry for each node. + err = d.cluster.Transaction(func(tx *db.ClusterTx) error { + nodes, err := tx.GetNodes() + if err != nil { + return err + } + + for _, node := range nodes { + err = tx.CreatePendingNetwork(node.Name, projectName, req.Name, netType.DBType(), req.Config) + if err != nil { + return errors.Wrapf(err, "Failed creating pending network for node %q", node.Name) + } + } + + return nil + }) + if err != nil { + return response.SmartError(err) + } } // Check if we're clustered. @@ -240,14 +268,11 @@ func networksPost(d *Daemon, r *http.Request) response.Response { return response.SmartError(err) } + revert.Success() return resp } // Non-clustered network creation. - err = netType.FillConfig(req.Config) - if err != nil { - return response.SmartError(err) - } networks, err := d.cluster.GetNetworks(projectName) if err != nil { @@ -264,9 +289,6 @@ func networksPost(d *Daemon, r *http.Request) response.Response { return response.SmartError(err) } - revert := revert.New() - defer revert.Fail() - // Create the database entry. _, err = d.cluster.CreateNetwork(projectName, req.Name, req.Description, netType.DBType(), req.Config) if err != nil { From 23f7b060e67e6ff36d2f078aeb664d4df6fcb54c Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Mon, 21 Sep 2020 15:26:58 +0100 Subject: [PATCH 20/22] lxd/networks: Comments in networksPostCluster Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/networks.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lxd/networks.go b/lxd/networks.go index 10903bcbe2..1269f2a95a 100644 --- a/lxd/networks.go +++ b/lxd/networks.go @@ -308,7 +308,7 @@ func networksPost(d *Daemon, r *http.Request) response.Response { } 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 defined. + // Check that no node-specific config key has been supplied in request. for key := range req.Config { if shared.StringInSlice(key, db.NodeSpecificNetworkConfig) { return fmt.Errorf("Config key %q is node-specific", key) @@ -368,6 +368,8 @@ func networksPostCluster(d *Daemon, projectName string, req api.NetworksPost, cl // 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 } From ea611ba00aefe90264aecf9a165e956d6a625b71 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Mon, 21 Sep 2020 15:27:10 +0100 Subject: [PATCH 21/22] lxd/networks: Comments in networkGet Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/networks.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lxd/networks.go b/lxd/networks.go index 1269f2a95a..87ed6ccd0b 100644 --- a/lxd/networks.go +++ b/lxd/networks.go @@ -483,8 +483,7 @@ func networkGet(d *Daemon, r *http.Request) response.Response { return response.SmartError(err) } - // If no target node is specified and the daemon is clustered, we omit - // the node-specific fields. + // If no target node is specified and the daemon is clustered, we omit the node-specific fields. if targetNode == "" && clustered { for _, key := range db.NodeSpecificNetworkConfig { delete(n.Config, key) From df23ec594d2c743657b702634b8f3f63a935f96a Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Mon, 21 Sep 2020 15:27:24 +0100 Subject: [PATCH 22/22] lxd/networks: Start parent networks before dependents in networkStartup Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/networks.go | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/lxd/networks.go b/lxd/networks.go index 87ed6ccd0b..e53e5bf088 100644 --- a/lxd/networks.go +++ b/lxd/networks.go @@ -1020,7 +1020,12 @@ func networkStartup(s *state.State) error { return errors.Wrapf(err, "Failed to load projects") } + // Record of networks that need to be started later keyed on project name. + deferredNetworks := make(map[string][]network.Network) + for _, projectName := range projectNames { + deferredNetworks[projectName] = make([]network.Network, 0) + // Get a list of managed networks. networks, err := s.Cluster.GetNonPendingNetworks(projectName) if err != nil { @@ -1034,13 +1039,20 @@ func networkStartup(s *state.State) error { return errors.Wrapf(err, "Failed to load network %q in project %q", name, projectName) } - err = n.Validate(n.Config()) + netConfig := n.Config() + err = n.Validate(netConfig) if err != nil { // Don't cause LXD to fail to start entirely on network start up failure. logger.Error("Failed to validate network", log.Ctx{"err": err, "project": projectName, "name": name}) continue } + // Defer network start until after non-dependent networks. + if netConfig["network"] != "" { + deferredNetworks[projectName] = append(deferredNetworks[projectName], n) + continue + } + err = n.Start() if err != nil { // Don't cause LXD to fail to start entirely on network start up failure. @@ -1050,6 +1062,18 @@ func networkStartup(s *state.State) error { } } + // Bring up deferred networks after non-dependent networks have been started. + for projectName, networks := range deferredNetworks { + for _, n := range networks { + err = n.Start() + if err != nil { + // Don't cause LXD to fail to start entirely on network start up failure. + logger.Error("Failed to bring up network", log.Ctx{"err": err, "project": projectName, "name": n.Name()}) + continue + } + } + } + return nil }
_______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel