[lxc-devel] [lxd/master] lxd/instances: Better use userRequested on Update

stgraber on Github lxc-bot at linuxcontainers.org
Wed Apr 15 00:56:15 UTC 2020


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 973 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20200414/9a2b664c/attachment.bin>
-------------- next part --------------
From b330cdf8ea0d99582cf67fd761ed60833fd4d282 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 14 Apr 2020 20:53:29 -0400
Subject: [PATCH] lxd/instances: Better use userRequested on Update
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This updates all calls to Update() to properly set userRequested to true
if the config change comes through a user request.

If it doesn't, then ignore validation issues as reverting will be just
as broken and there's nothing the user can do at that point anyway.

This also removes the logic checking if `volatile.` keys have been
modified since the check never actually applied to PUT/PATCH requests
due to us having to use that API when handling migrations.

So in practice userRequested was never set to true when a change was
actually requested by the user, making the check useless.

Closes #6661

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxd/instance/drivers/driver_lxc.go  | 85 ++++++++++++-----------------
 lxd/instance/drivers/driver_qemu.go | 66 ++++++++--------------
 lxd/instance_patch.go               |  2 +-
 lxd/instance_put.go                 |  3 +-
 lxd/instance_state.go               |  2 +-
 lxd/patches.go                      |  1 +
 6 files changed, 63 insertions(+), 96 deletions(-)

diff --git a/lxd/instance/drivers/driver_lxc.go b/lxd/instance/drivers/driver_lxc.go
index 41baeb283a..38e7265942 100644
--- a/lxd/instance/drivers/driver_lxc.go
+++ b/lxd/instance/drivers/driver_lxc.go
@@ -3289,7 +3289,7 @@ func (c *lxc) Restore(sourceContainer instance.Instance, stateful bool) error {
 			// On function return, set the flag back on.
 			defer func() {
 				args.Ephemeral = ephemeral
-				c.Update(args, true)
+				c.Update(args, false)
 			}()
 		}
 
@@ -3338,6 +3338,7 @@ func (c *lxc) Restore(sourceContainer instance.Instance, stateful bool) error {
 		Snapshot:     sourceContainer.IsSnapshot(),
 	}
 
+	// Don't pass as user-requested as there's no way to fix a bad config.
 	err = c.Update(args, false)
 	if err != nil {
 		logger.Error("Failed restoring container configuration", ctxMap)
@@ -3777,16 +3778,18 @@ func (c *lxc) Update(args db.InstanceArgs, userRequested bool) error {
 		args.Profiles = []string{}
 	}
 
-	// Validate the new config
-	err := instance.ValidConfig(c.state.OS, args.Config, false, false)
-	if err != nil {
-		return errors.Wrap(err, "Invalid config")
-	}
+	if userRequested {
+		// Validate the new config
+		err := instance.ValidConfig(c.state.OS, args.Config, false, false)
+		if err != nil {
+			return errors.Wrap(err, "Invalid config")
+		}
 
-	// Validate the new devices without using expanded devices validation (expensive checks disabled).
-	err = instance.ValidDevices(c.state, c.state.Cluster, c.Type(), args.Devices, false)
-	if err != nil {
-		return errors.Wrap(err, "Invalid devices")
+		// Validate the new devices without using expanded devices validation (expensive checks disabled).
+		err = instance.ValidDevices(c.state, c.state.Cluster, c.Type(), args.Devices, false)
+		if err != nil {
+			return errors.Wrap(err, "Invalid devices")
+		}
 	}
 
 	// Validate the new profiles
@@ -3816,29 +3819,6 @@ func (c *lxc) Update(args db.InstanceArgs, userRequested bool) error {
 		}
 	}
 
-	// Check that volatile and image keys weren't modified
-	if userRequested {
-		for k, v := range args.Config {
-			if strings.HasPrefix(k, "volatile.") && c.localConfig[k] != v {
-				return fmt.Errorf("Volatile keys are read-only")
-			}
-
-			if strings.HasPrefix(k, "image.") && c.localConfig[k] != v {
-				return fmt.Errorf("Image keys are read-only")
-			}
-		}
-
-		for k, v := range c.localConfig {
-			if strings.HasPrefix(k, "volatile.") && args.Config[k] != v {
-				return fmt.Errorf("Volatile keys are read-only")
-			}
-
-			if strings.HasPrefix(k, "image.") && args.Config[k] != v {
-				return fmt.Errorf("Image keys are read-only")
-			}
-		}
-	}
-
 	// Get a copy of the old configuration
 	oldDescription := c.Description()
 	oldArchitecture := 0
@@ -3968,27 +3948,32 @@ func (c *lxc) Update(args db.InstanceArgs, userRequested bool) error {
 		return updateFields
 	})
 
-	// Do some validation of the config diff
-	err = instance.ValidConfig(c.state.OS, c.expandedConfig, false, true)
-	if err != nil {
-		return errors.Wrap(err, "Invalid expanded config")
-	}
+	if userRequested {
+		// Do some validation of the config diff
+		err = instance.ValidConfig(c.state.OS, c.expandedConfig, false, true)
+		if err != nil {
+			return errors.Wrap(err, "Invalid expanded config")
+		}
 
-	// Do full expanded validation of the devices diff.
-	err = instance.ValidDevices(c.state, c.state.Cluster, c.Type(), c.expandedDevices, true)
-	if err != nil {
-		return errors.Wrap(err, "Invalid expanded devices")
+		// Do full expanded validation of the devices diff.
+		err = instance.ValidDevices(c.state, c.state.Cluster, c.Type(), c.expandedDevices, true)
+		if err != nil {
+			return errors.Wrap(err, "Invalid expanded devices")
+		}
 	}
 
 	// Run through initLXC to catch anything we missed
-	if c.c != nil {
-		c.c.Release()
-		c.c = nil
-	}
-	c.cConfig = false
-	err = c.initLXC(true)
-	if err != nil {
-		return errors.Wrap(err, "Initialize LXC")
+	if userRequested {
+		if c.c != nil {
+			c.c.Release()
+			c.c = nil
+		}
+
+		c.cConfig = false
+		err = c.initLXC(true)
+		if err != nil {
+			return errors.Wrap(err, "Initialize LXC")
+		}
 	}
 
 	cg, err := c.cgroup(nil)
diff --git a/lxd/instance/drivers/driver_qemu.go b/lxd/instance/drivers/driver_qemu.go
index 58835eea4d..0b83a30380 100644
--- a/lxd/instance/drivers/driver_qemu.go
+++ b/lxd/instance/drivers/driver_qemu.go
@@ -2047,7 +2047,7 @@ func (vm *qemu) Restore(source instance.Instance, stateful bool) error {
 			// On function return, set the flag back on.
 			defer func() {
 				args.Ephemeral = ephemeral
-				vm.Update(args, true)
+				vm.Update(args, false)
 			}()
 		}
 
@@ -2087,6 +2087,7 @@ func (vm *qemu) Restore(source instance.Instance, stateful bool) error {
 		Snapshot:     source.IsSnapshot(),
 	}
 
+	// Don't pass as user-requested as there's no way to fix a bad config.
 	err = vm.Update(args, false)
 	if err != nil {
 		logger.Error("Failed restoring instance configuration", ctxMap)
@@ -2328,16 +2329,18 @@ func (vm *qemu) Update(args db.InstanceArgs, userRequested bool) error {
 		args.Profiles = []string{}
 	}
 
-	// Validate the new config.
-	err := instance.ValidConfig(vm.state.OS, args.Config, false, false)
-	if err != nil {
-		return errors.Wrap(err, "Invalid config")
-	}
+	if userRequested {
+		// Validate the new config.
+		err := instance.ValidConfig(vm.state.OS, args.Config, false, false)
+		if err != nil {
+			return errors.Wrap(err, "Invalid config")
+		}
 
-	// Validate the new devices without using expanded devices validation (expensive checks disabled).
-	err = instance.ValidDevices(vm.state, vm.state.Cluster, vm.Type(), args.Devices, false)
-	if err != nil {
-		return errors.Wrap(err, "Invalid devices")
+		// Validate the new devices without using expanded devices validation (expensive checks disabled).
+		err = instance.ValidDevices(vm.state, vm.state.Cluster, vm.Type(), args.Devices, false)
+		if err != nil {
+			return errors.Wrap(err, "Invalid devices")
+		}
 	}
 
 	// Validate the new profiles.
@@ -2367,29 +2370,6 @@ func (vm *qemu) Update(args db.InstanceArgs, userRequested bool) error {
 		}
 	}
 
-	// Check that volatile and image keys weren't modified.
-	if userRequested {
-		for k, v := range args.Config {
-			if strings.HasPrefix(k, "volatile.") && vm.localConfig[k] != v {
-				return fmt.Errorf("Volatile keys are read-only")
-			}
-
-			if strings.HasPrefix(k, "image.") && vm.localConfig[k] != v {
-				return fmt.Errorf("Image keys are read-only")
-			}
-		}
-
-		for k, v := range vm.localConfig {
-			if strings.HasPrefix(k, "volatile.") && args.Config[k] != v {
-				return fmt.Errorf("Volatile keys are read-only")
-			}
-
-			if strings.HasPrefix(k, "image.") && args.Config[k] != v {
-				return fmt.Errorf("Image keys are read-only")
-			}
-		}
-	}
-
 	// Get a copy of the old configuration.
 	oldDescription := vm.Description()
 	oldArchitecture := 0
@@ -2512,16 +2492,18 @@ func (vm *qemu) Update(args db.InstanceArgs, userRequested bool) error {
 		return updateFields
 	})
 
-	// Do some validation of the config diff.
-	err = instance.ValidConfig(vm.state.OS, vm.expandedConfig, false, true)
-	if err != nil {
-		return errors.Wrap(err, "Invalid expanded config")
-	}
+	if userRequested {
+		// Do some validation of the config diff.
+		err = instance.ValidConfig(vm.state.OS, vm.expandedConfig, false, true)
+		if err != nil {
+			return errors.Wrap(err, "Invalid expanded config")
+		}
 
-	// Do full expanded validation of the devices diff.
-	err = instance.ValidDevices(vm.state, vm.state.Cluster, vm.Type(), vm.expandedDevices, true)
-	if err != nil {
-		return errors.Wrap(err, "Invalid expanded devices")
+		// Do full expanded validation of the devices diff.
+		err = instance.ValidDevices(vm.state, vm.state.Cluster, vm.Type(), vm.expandedDevices, true)
+		if err != nil {
+			return errors.Wrap(err, "Invalid expanded devices")
+		}
 	}
 
 	// Use the device interface to apply update changes.
diff --git a/lxd/instance_patch.go b/lxd/instance_patch.go
index 13a856f127..af4cacf31a 100644
--- a/lxd/instance_patch.go
+++ b/lxd/instance_patch.go
@@ -140,7 +140,7 @@ func containerPatch(d *Daemon, r *http.Request) response.Response {
 		Project:      project,
 	}
 
-	err = c.Update(args, false)
+	err = c.Update(args, true)
 	if err != nil {
 		return response.SmartError(err)
 	}
diff --git a/lxd/instance_put.go b/lxd/instance_put.go
index df8b9a813a..5390756615 100644
--- a/lxd/instance_put.go
+++ b/lxd/instance_put.go
@@ -89,8 +89,7 @@ func containerPut(d *Daemon, r *http.Request) response.Response {
 				Project:      project,
 			}
 
-			// FIXME: should set to true when not migrating
-			err = c.Update(args, false)
+			err = c.Update(args, true)
 			if err != nil {
 				return err
 			}
diff --git a/lxd/instance_state.go b/lxd/instance_state.go
index e1b55e9754..b0fab52b0b 100644
--- a/lxd/instance_state.go
+++ b/lxd/instance_state.go
@@ -163,7 +163,7 @@ func containerStatePut(d *Daemon, r *http.Request) response.Response {
 				// On function return, set the flag back on
 				defer func() {
 					args.Ephemeral = ephemeral
-					c.Update(args, true)
+					c.Update(args, false)
 				}()
 			}
 
diff --git a/lxd/patches.go b/lxd/patches.go
index 52f26a9e11..64a8663bef 100644
--- a/lxd/patches.go
+++ b/lxd/patches.go
@@ -2038,6 +2038,7 @@ func updatePoolPropertyForAllObjects(d *Daemon, poolName string, allcontainers [
 
 		err = c.Update(args, false)
 		if err != nil {
+			logger.Warnf("Unable to add pool name to '%s': %v", c.Name(), err)
 			continue
 		}
 	}


More information about the lxc-devel mailing list