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

This e-mail was sent by the LXC bot, direct replies will not reach the author
unless they happen to be subscribed to this list.

=== Description (from pull-request) ===

From 8ca190120f9461048bb38537a7ba1f1883e11a41 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Wed, 23 Sep 2020 09:20:04 +0100
Subject: [PATCH 01/10] lxd/network: Removes client side default network type
 when creating network

Let server decide the appropriate network type to use when not specified by 
user.

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxc/network.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lxc/network.go b/lxc/network.go
index 17980f40c2..41c2f6e549 100644
--- a/lxc/network.go
+++ b/lxc/network.go
@@ -255,7 +255,7 @@ func (c *cmdNetworkCreate) Command() *cobra.Command {
        cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(`Create new 
networks`))
 
        cmd.Flags().StringVar(&c.network.flagTarget, "target", "", 
i18n.G("Cluster member name")+"``")
-       cmd.Flags().StringVarP(&c.network.flagType, "type", "t", "bridge", 
i18n.G("Network type"))
+       cmd.Flags().StringVarP(&c.network.flagType, "type", "t", "", 
i18n.G("Network type"))
 
        cmd.RunE = c.Run
 

From c896c22ae8c97cfb93ebf4112b6e6ecaa291bd48 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Wed, 23 Sep 2020 09:20:43 +0100
Subject: [PATCH 02/10] lxd/networks: Default to ovn network type when creating
 non-default network project

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/networks.go | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/lxd/networks.go b/lxd/networks.go
index 32a58f7043..3e399350c0 100644
--- a/lxd/networks.go
+++ b/lxd/networks.go
@@ -144,7 +144,11 @@ func networksPost(d *Daemon, r *http.Request) 
response.Response {
        }
 
        if req.Type == "" {
-               req.Type = "bridge"
+               if projectName != project.Default {
+                       req.Type = "ovn" // Only OVN networks are allowed 
inside network enabled projects.
+               } else {
+                       req.Type = "bridge" // Default to bridge for 
non-network enabled projects.
+               }
        }
 
        if req.Config == nil {

From e115d907ebd313a280b9fd80f1688a950d679d41 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Tue, 22 Sep 2020 14:42:36 +0100
Subject: [PATCH 03/10] api: Adds projects_networks_restricted_uplinks
 extension

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 doc/api-extensions.md | 4 ++++
 shared/version/api.go | 1 +
 2 files changed, 5 insertions(+)

diff --git a/doc/api-extensions.md b/doc/api-extensions.md
index 615a8c047f..f5377108b8 100644
--- a/doc/api-extensions.md
+++ b/doc/api-extensions.md
@@ -1154,3 +1154,7 @@ Also introduces two new global config keys that apply to 
all `ovn` networks and
 
 ## projects\_networks
 Adds the `features.networks` config key to projects and the ability for a 
project to hold networks.
+
+## projects\_networks\_restricted\_uplinks
+Adds the `restricted.networks.uplinks` project config key to indicate (as a 
comma delimited list) which networks
+the networks created inside the project can use as their uplink parent network.
diff --git a/shared/version/api.go b/shared/version/api.go
index 85da3b0a87..6e2603d3c1 100644
--- a/shared/version/api.go
+++ b/shared/version/api.go
@@ -225,6 +225,7 @@ var APIExtensions = []string{
        "container_syscall_intercept_bpf_devices",
        "network_type_ovn",
        "projects_networks",
+       "projects_networks_restricted_uplinks",
 }
 
 // APIExtensionsCount returns the number of available API extensions.

From 6b195c1fbfc7ca448dd0666128212aaae88c3a55 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Tue, 22 Sep 2020 14:55:22 +0100
Subject: [PATCH 04/10] doc/projects: Adds restricted.networks.uplinks

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 doc/projects.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/doc/projects.md b/doc/projects.md
index e8c1142e8d..b7fa5d8961 100644
--- a/doc/projects.md
+++ b/doc/projects.md
@@ -40,6 +40,7 @@ restricted.devices.unix-block        | string    | -          
           | block
 restricted.devices.unix-char         | string    | -                     | 
block                     | Prevents use of devices of type "unix-char"
 restricted.devices.unix-hotplug      | string    | -                     | 
block                     | Prevents use of devices of type "unix-hotplug"
 restricted.devices.usb               | string    | -                     | 
block                     | Prevents use of devices of type "usb"
+restricted.networks.uplinks          | string    | -                     | 
block                     | Comma delimited list of network names that can be 
used as uplinks for networks in this project.
 restricted.virtual-machines.lowlevel | string    | -                     | 
block                     | Prevents use of low-level virtual-machine options 
like raw.qemu, volatile, etc.
 
 Those keys can be set using the lxc tool with:

From 7b6f82e7355b3da0f02a73c75698636c0ee7ec73 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Tue, 22 Sep 2020 15:08:19 +0100
Subject: [PATCH 05/10] lxd/networks: Updates doNetworkUpdate to use n.Validate
 so that project is available to validator

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 3e399350c0..ae67d059a8 100644
--- a/lxd/networks.go
+++ b/lxd/networks.go
@@ -816,7 +816,7 @@ func doNetworkUpdate(d *Daemon, projectName string, name 
string, req api.Network
        }
 
        // Validate the merged configuration.
-       err = network.Validate(name, n.Type(), req.Config)
+       err = n.Validate(req.Config)
        if err != nil {
                return response.BadRequest(err)
        }

From 172478a726796e33efea75c89ae32dd7cbde70fa Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Tue, 22 Sep 2020 15:07:33 +0100
Subject: [PATCH 06/10] lxd/network/network/load: Removes unused Validate

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/network/network_load.go | 21 ---------------------
 1 file changed, 21 deletions(-)

diff --git a/lxd/network/network_load.go b/lxd/network/network_load.go
index 862ba2831b..ed098ef3d9 100644
--- a/lxd/network/network_load.go
+++ b/lxd/network/network_load.go
@@ -1,9 +1,6 @@
 package network
 
 import (
-       "github.com/pkg/errors"
-
-       "github.com/lxc/lxd/lxd/project"
        "github.com/lxc/lxd/lxd/state"
 )
 
@@ -43,21 +40,3 @@ func LoadByName(s *state.State, project string, name string) 
(Network, error) {
 
        return n, 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]
-       if !ok {
-               return ErrUnknownDriver
-       }
-
-       n := driverFunc()
-       n.init(nil, 0, project.Default, name, netType, "", config, "Unknown")
-
-       err := n.ValidateName(name)
-       if err != nil {
-               return errors.Wrapf(err, "Network name invalid")
-       }
-
-       return n.Validate(config)
-}

From df9d197962f5d09b540d36966c51fb745e2f1152 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Tue, 22 Sep 2020 15:07:46 +0100
Subject: [PATCH 07/10] lxd/network/network/load: Renames project arg to
 projectName for clarity

Improves comments.

Signed-off-by: Thomas Parrott <thomas.parr...@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 ed098ef3d9..cf59074663 100644
--- a/lxd/network/network_load.go
+++ b/lxd/network/network_load.go
@@ -23,9 +23,9 @@ func LoadByType(driverType string) (Type, error) {
        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)
+// 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)
        if err != nil {
                return nil, err
        }
@@ -36,7 +36,7 @@ func LoadByName(s *state.State, project string, name string) 
(Network, error) {
        }
 
        n := driverFunc()
-       n.init(s, id, project, name, netInfo.Type, netInfo.Description, 
netInfo.Config, netInfo.Status)
+       n.init(s, id, projectName, name, netInfo.Type, netInfo.Description, 
netInfo.Config, netInfo.Status)
 
        return n, nil
 }

From f0b69275081b4dd8384bdc38cece224c32327f6f Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Tue, 22 Sep 2020 15:08:45 +0100
Subject: [PATCH 08/10] lxd/api/project: Adds restricted.networks.uplinks to
 validation

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/api_project.go | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lxd/api_project.go b/lxd/api_project.go
index cb9d79ca58..770e9abf65 100644
--- a/lxd/api_project.go
+++ b/lxd/api_project.go
@@ -555,6 +555,7 @@ var projectConfigKeys = map[string]func(value string) error{
        "restricted.devices.usb":               isEitherAllowOrBlock,
        "restricted.devices.nic":               isEitherAllowOrBlockOrManaged,
        "restricted.devices.disk":              isEitherAllowOrBlockOrManaged,
+       "restricted.networks.uplinks":          validate.IsAny,
 }
 
 func projectValidateConfig(config map[string]string) error {

From 78b66cd9e3e336797afca1479459c352811b081f Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Wed, 23 Sep 2020 11:17:48 +0100
Subject: [PATCH 09/10] lxd/network/driver/ovn: Adds allowedUplinkNetworks
 function

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/network/driver_ovn.go | 61 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 61 insertions(+)

diff --git a/lxd/network/driver_ovn.go b/lxd/network/driver_ovn.go
index 5d8f142c9b..fd43146ca1 100644
--- a/lxd/network/driver_ovn.go
+++ b/lxd/network/driver_ovn.go
@@ -825,6 +825,67 @@ func (n *ovn) Create(clientType cluster.ClientType) error {
        return nil
 }
 
+// allowedUplinkNetworks returns a list of allowed networks to use as uplinks 
based on project restrictions.
+func (n *ovn) allowedUplinkNetworks() ([]string, error) {
+       // Uplink networks are always from the default project.
+       networks, err := n.state.Cluster.GetNetworks(project.Default)
+       if err != nil {
+               return nil, errors.Wrapf(err, "Failed getting uplink networks")
+       }
+
+       // Remove ourselves from the networks list if we are in the default 
project.
+       if n.project == project.Default {
+               allNets := networks
+               networks = make([]string, 0, len(allNets)-1)
+               for _, network := range allNets {
+                       if network == n.name {
+                               continue
+                       }
+
+                       networks = append(networks, network)
+               }
+       }
+
+       // Load the project to get uplink network restrictions.
+       var project *api.Project
+       err = n.state.Cluster.Transaction(func(tx *db.ClusterTx) error {
+               project, err = tx.GetProject(n.project)
+               if err != nil {
+                       return err
+               }
+
+               return nil
+       })
+       if err != nil {
+               return nil, errors.Wrapf(err, "Failed to load restrictions for 
project %q", n.project)
+       }
+
+       // If project is not restricted, return full network list.
+       if !shared.IsTrue(project.Config["restricted"]) {
+               return networks, nil
+       }
+
+       allowedNetworks := []string{}
+
+       // There are no allowed networks if restricted.networks.uplinks is not 
set.
+       if project.Config["restricted.networks.uplinks"] == "" {
+               return allowedNetworks, nil
+       }
+
+       // Parse the allowed uplinks and return any that are present in the 
actual defined networks.
+       allowedRestrictedUplinks := 
strings.Split(project.Config["restricted.networks.uplinks"], ",")
+
+       for _, allowedRestrictedUplink := range allowedRestrictedUplinks {
+               allowedRestrictedUplink = 
strings.TrimSpace(allowedRestrictedUplink)
+
+               if shared.StringInSlice(allowedRestrictedUplink, networks) {
+                       allowedNetworks = append(allowedNetworks, 
allowedRestrictedUplink)
+               }
+       }
+
+       return allowedNetworks, nil
+}
+
 func (n *ovn) setup(update bool) error {
        // If we are in mock mode, just no-op.
        if n.state.OS.MockMode {

From 99bc3f4f5a31e201c884235a46a7525d5e23cc9b Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Wed, 23 Sep 2020 11:18:08 +0100
Subject: [PATCH 10/10] lxd/network/driver/ovn: Enforce project
 restricted.networks.uplinks setting

And auto set the `network` property when not specified and when only one 
possible uplink network available.

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/network/driver_ovn.go | 37 +++++++++++++++++++++++++++++++++++--
 1 file changed, 35 insertions(+), 2 deletions(-)

diff --git a/lxd/network/driver_ovn.go b/lxd/network/driver_ovn.go
index fd43146ca1..40a3cdb524 100644
--- a/lxd/network/driver_ovn.go
+++ b/lxd/network/driver_ovn.go
@@ -81,7 +81,7 @@ func (n *ovn) Info() Info {
 // Validate network config.
 func (n *ovn) Validate(config map[string]string) error {
        rules := map[string]func(value string) error{
-               "network":       validate.IsNotEmpty,
+               "network":       validate.IsAny, // Is validated during setup.
                "bridge.hwaddr": validate.Optional(validate.IsNetworkMAC),
                "bridge.mtu":    validate.Optional(validate.IsNetworkMTU),
                "ipv4.address": func(value string) error {
@@ -905,6 +905,31 @@ func (n *ovn) setup(update bool) error {
        var routerExtPortIPv4, routerIntPortIPv4, routerExtPortIPv6, 
routerIntPortIPv6 net.IP
        var routerExtPortIPv4Net, routerIntPortIPv4Net, routerExtPortIPv6Net, 
routerIntPortIPv6Net *net.IPNet
 
+       // Record updated config so we can store back into DB and n.config 
variable.
+       updatedConfig := make(map[string]string)
+
+       // Check project restrictions.
+       allowedUplinkNetworks, err := n.allowedUplinkNetworks()
+       if err != nil {
+               return err
+       }
+
+       if n.config["network"] != "" {
+               if !shared.StringInSlice(n.config["network"], 
allowedUplinkNetworks) {
+                       return fmt.Errorf(`Option "network" value %q is not one 
of the allowed uplink networks in project`, n.config["network"])
+               }
+       } else {
+               allowedNetworkCount := len(allowedUplinkNetworks)
+               if allowedNetworkCount == 0 {
+                       return fmt.Errorf(`No allowed uplink networks in 
project`)
+               } else if allowedNetworkCount == 1 {
+                       // If there is only one allowed uplink network then use 
it if not specified by user.
+                       updatedConfig["network"] = allowedUplinkNetworks[0]
+               } else {
+                       return fmt.Errorf(`Option "network" is required`)
+               }
+       }
+
        // Get bridge MTU to use.
        bridgeMTU := n.getBridgeMTU()
        if bridgeMTU == 0 {
@@ -915,7 +940,15 @@ func (n *ovn) setup(update bool) error {
                }
 
                // Save to config so the value can be read by instances 
connecting to network.
-               n.config["bridge.mtu"] = fmt.Sprintf("%d", bridgeMTU)
+               updatedConfig["bridge.mtu"] = fmt.Sprintf("%d", bridgeMTU)
+       }
+
+       // Apply any config dynamically generated to the current config and 
store back to DB in single transaction.
+       if len(updatedConfig) > 0 {
+               for k, v := range updatedConfig {
+                       n.config[k] = v
+               }
+
                err := n.state.Cluster.Transaction(func(tx *db.ClusterTx) error 
{
                        err = tx.UpdateNetwork(n.id, n.description, n.config)
                        if err != nil {
_______________________________________________
lxc-devel mailing list
lxc-devel@lists.linuxcontainers.org
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to