[lxc-devel] [lxd/master] Introduce volatile.idmap.current

stgraber on Github lxc-bot at linuxcontainers.org
Thu Mar 28 02:09:42 UTC 2019


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 545 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20190327/d6cd433e/attachment.bin>
-------------- next part --------------
From d3f636a7eef8aaf3d0402bc1e84894ebdbf014e4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Wed, 27 Mar 2019 18:01:29 -0400
Subject: [PATCH 1/5] lxd/containers: Implement new idmap functions
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxd/container.go     |  6 ++++--
 lxd/container_lxc.go | 27 +++++++++++++++++++++++++++
 2 files changed, 31 insertions(+), 2 deletions(-)

diff --git a/lxd/container.go b/lxd/container.go
index 89c94e95ac..354aae4011 100644
--- a/lxd/container.go
+++ b/lxd/container.go
@@ -673,10 +673,12 @@ type container interface {
 	StorageStart() (bool, error)
 	StorageStop() (bool, error)
 	Storage() storage
-	IdmapSet() (*idmap.IdmapSet, error)
-	LastIdmapSet() (*idmap.IdmapSet, error)
 	TemplateApply(trigger string) error
 	DaemonState() *state.State
+
+	CurrentIdmap() (*idmap.IdmapSet, error)
+	DiskIdmap() (*idmap.IdmapSet, error)
+	NextIdmap() (*idmap.IdmapSet, error)
 }
 
 // Loader functions
diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index f3b8b5f8a0..5e383ae078 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -8735,6 +8735,33 @@ func (c *containerLXC) LastIdmapSet() (*idmap.IdmapSet, error) {
 	return c.idmapsetFromConfig("volatile.last_state.idmap")
 }
 
+func (c *containerLXC) CurrentIdmap() (*idmap.IdmapSet, error) {
+	jsonIdmap, ok := c.LocalConfig()["volatile.idmap.current"]
+	if !ok {
+		return c.DiskIdmap()
+	}
+
+	return idmapsetFromString(jsonIdmap)
+}
+
+func (c *containerLXC) DiskIdmap() (*idmap.IdmapSet, error) {
+	jsonIdmap, ok := c.LocalConfig()["volatile.last_state.idmap"]
+	if !ok {
+		return nil, nil
+	}
+
+	return idmapsetFromString(jsonIdmap)
+}
+
+func (c *containerLXC) NextIdmap() (*idmap.IdmapSet, error) {
+	jsonIdmap, ok := c.LocalConfig()["volatile.idmap.next"]
+	if !ok {
+		return c.CurrentIdmap()
+	}
+
+	return idmapsetFromString(jsonIdmap)
+}
+
 func (c *containerLXC) DaemonState() *state.State {
 	// FIXME: This function should go away, since the abstract container
 	//        interface should not be coupled with internal state details.

From 45a853a05b0165235c7c77683bbb6b98fa947be1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Wed, 27 Mar 2019 18:26:01 -0400
Subject: [PATCH 2/5] lxd: Port to new idmap functions
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxd/container_console.go |  2 +-
 lxd/container_exec.go    |  2 +-
 lxd/devlxd.go            |  2 +-
 lxd/migrate_container.go |  2 +-
 lxd/storage.go           | 20 +++++++++++++++-----
 5 files changed, 19 insertions(+), 9 deletions(-)

diff --git a/lxd/container_console.go b/lxd/container_console.go
index b12f060fe5..e2741bc8ca 100644
--- a/lxd/container_console.go
+++ b/lxd/container_console.go
@@ -303,7 +303,7 @@ func containerConsolePost(d *Daemon, r *http.Request) Response {
 	ws := &consoleWs{}
 	ws.fds = map[int]string{}
 
-	idmapset, err := c.IdmapSet()
+	idmapset, err := c.CurrentIdmap()
 	if err != nil {
 		return InternalError(err)
 	}
diff --git a/lxd/container_exec.go b/lxd/container_exec.go
index 71c694a06d..238b1df3a0 100644
--- a/lxd/container_exec.go
+++ b/lxd/container_exec.go
@@ -426,7 +426,7 @@ func containerExecPost(d *Daemon, r *http.Request) Response {
 		ws := &execWs{}
 		ws.fds = map[int]string{}
 
-		idmapset, err := c.IdmapSet()
+		idmapset, err := c.CurrentIdmap()
 		if err != nil {
 			return InternalError(err)
 		}
diff --git a/lxd/devlxd.go b/lxd/devlxd.go
index eb7735b215..a15fd2306c 100644
--- a/lxd/devlxd.go
+++ b/lxd/devlxd.go
@@ -231,7 +231,7 @@ func hoistReq(f func(*Daemon, container, http.ResponseWriter, *http.Request) *de
 		// Access control
 		rootUid := int64(0)
 
-		idmapset, err := c.LastIdmapSet()
+		idmapset, err := c.CurrentIdmap()
 		if err == nil && idmapset != nil {
 			uid, _ := idmapset.ShiftIntoNs(0, 0)
 			rootUid = int64(uid)
diff --git a/lxd/migrate_container.go b/lxd/migrate_container.go
index 69d3ec2eeb..ff4c476705 100644
--- a/lxd/migrate_container.go
+++ b/lxd/migrate_container.go
@@ -337,7 +337,7 @@ func (s *migrationSourceWs) Do(migrateOp *operation) error {
 
 	idmaps := make([]*migration.IDMapType, 0)
 
-	idmapset, err := s.container.LastIdmapSet()
+	idmapset, err := s.container.DiskIdmap()
 	if err != nil {
 		return err
 	}
diff --git a/lxd/storage.go b/lxd/storage.go
index 1f9438a05d..41ea2e09e3 100644
--- a/lxd/storage.go
+++ b/lxd/storage.go
@@ -411,7 +411,7 @@ func storagePoolVolumeAttachInit(s *state.State, poolName string, volumeName str
 		return st, nil
 	}
 
-	// get last idmapset
+	// Get the on-disk idmap for the volume
 	var lastIdmap *idmap.IdmapSet
 	if poolVolumePut.Config["volatile.idmap.last"] != "" {
 		lastIdmap, err = idmapsetFromString(poolVolumePut.Config["volatile.idmap.last"])
@@ -421,8 +421,13 @@ func storagePoolVolumeAttachInit(s *state.State, poolName string, volumeName str
 		}
 	}
 
-	// get next idmapset
-	nextIdmap, err := c.IdmapSet()
+	// Get the container's idmap
+	var nextIdmap *idmap.IdmapSet
+	if c.IsRunning() {
+		nextIdmap, err = c.CurrentIdmap()
+	} else {
+		nextIdmap, err = c.NextIdmap()
+	}
 	if err != nil {
 		return nil, err
 	}
@@ -460,7 +465,12 @@ func storagePoolVolumeAttachInit(s *state.State, poolName string, volumeName str
 					continue
 				}
 
-				ctNextIdmap, err := ct.IdmapSet()
+				var ctNextIdmap *idmap.IdmapSet
+				if ct.IsRunning() {
+					ctNextIdmap, err = ct.CurrentIdmap()
+				} else {
+					ctNextIdmap, err = ct.NextIdmap()
+				}
 				if err != nil {
 					return nil, fmt.Errorf("Failed to retrieve idmap of container")
 				}
@@ -745,7 +755,7 @@ func deleteSnapshotMountpoint(snapshotMountpoint string, snapshotsSymlinkTarget
 }
 
 func resetContainerDiskIdmap(container container, srcIdmap *idmap.IdmapSet) error {
-	dstIdmap, err := container.IdmapSet()
+	dstIdmap, err := container.DiskIdmap()
 	if err != nil {
 		return err
 	}

From 8075ed43f9f68eff0c3d5ad5a18024c3a1154213 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Wed, 27 Mar 2019 18:38:18 -0400
Subject: [PATCH 3/5] lxd/containers: Port to new idmap functions
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxd/container_lxc.go  | 74 ++++++++++---------------------------------
 lxd/container_test.go | 12 +++----
 2 files changed, 23 insertions(+), 63 deletions(-)

diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index 5e383ae078..98e08d4c3a 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -1225,7 +1225,7 @@ func (c *containerLXC) initLXC(config bool) error {
 	}
 
 	// Setup idmap
-	idmapset, err := c.IdmapSet()
+	idmapset, err := c.NextIdmap()
 	if err != nil {
 		return err
 	}
@@ -1976,12 +1976,12 @@ func (c *containerLXC) startCommon() (string, error) {
 	}
 
 	/* Deal with idmap changes */
-	idmap, err := c.IdmapSet()
+	idmap, err := c.NextIdmap()
 	if err != nil {
 		return "", errors.Wrap(err, "Set ID map")
 	}
 
-	lastIdmap, err := c.LastIdmapSet()
+	lastIdmap, err := c.DiskIdmap()
 	if err != nil {
 		return "", errors.Wrap(err, "Set last ID map")
 	}
@@ -2038,12 +2038,17 @@ func (c *containerLXC) startCommon() (string, error) {
 			}
 		}
 
+		err = c.ConfigKeySet("volatile.last_state.idmap", jsonIdmap)
+		if err != nil {
+			return "", errors.Wrapf(err, "Set volatile.last_state.idmap config key on container %q (id %d)", c.name, c.id)
+		}
+
 		c.updateProgress("")
 	}
 
-	err = c.ConfigKeySet("volatile.last_state.idmap", jsonIdmap)
+	err = c.ConfigKeySet("volatile.idmap.current", jsonIdmap)
 	if err != nil {
-		return "", errors.Wrapf(err, "Set volatile.last_state.idmap config key on container %q (id %d)", c.name, c.id)
+		return "", errors.Wrapf(err, "Set volatile.idmap.current config key on container %q (id %d)", c.name, c.id)
 	}
 
 	// Generate the Seccomp profile
@@ -5064,7 +5069,7 @@ func (c *containerLXC) Export(w io.Writer, properties map[string]string) error {
 	}
 
 	// Unshift the container
-	idmap, err := c.LastIdmapSet()
+	idmap, err := c.DiskIdmap()
 	if err != nil {
 		logger.Error("Failed exporting container", ctxMap)
 		return err
@@ -5392,7 +5397,7 @@ func (c *containerLXC) Migrate(args *CriuMigrationArgs) error {
 		 * namespace.
 		 */
 		if !c.IsPrivileged() {
-			idmapset, err := c.IdmapSet()
+			idmapset, err := c.CurrentIdmap()
 			if err != nil {
 				return err
 			}
@@ -5599,7 +5604,7 @@ func (c *containerLXC) templateApplyNow(trigger string) error {
 
 			// Get the right uid and gid for the container
 			if !c.IsPrivileged() {
-				idmapset, err := c.IdmapSet()
+				idmapset, err := c.DiskIdmap()
 				if err != nil {
 					return errors.Wrap(err, "Failed to set ID map")
 				}
@@ -5842,7 +5847,7 @@ func (c *containerLXC) FilePull(srcpath string, dstpath string) (int64, int64, o
 
 	// Unmap uid and gid if needed
 	if !c.IsRunning() {
-		idmapset, err := c.LastIdmapSet()
+		idmapset, err := c.DiskIdmap()
 		if err != nil {
 			return -1, -1, 0, "", nil, err
 		}
@@ -5862,7 +5867,7 @@ func (c *containerLXC) FilePush(type_ string, srcpath string, dstpath string, ui
 
 	// Map uid and gid if needed
 	if !c.IsRunning() {
-		idmapset, err := c.LastIdmapSet()
+		idmapset, err := c.DiskIdmap()
 		if err != nil {
 			return err
 		}
@@ -6368,7 +6373,7 @@ func (c *containerLXC) tarStoreFile(linkmap map[uint64]string, offset int, tw *t
 
 	// Unshift the id under /rootfs/ for unpriv containers
 	if !c.IsPrivileged() && strings.HasPrefix(hdr.Name, "/rootfs") {
-		idmapset, err := c.IdmapSet()
+		idmapset, err := c.DiskIdmap()
 		if err != nil {
 			return err
 		}
@@ -6719,7 +6724,7 @@ func (c *containerLXC) createUnixDevice(prefix string, m types.Device, defaultMo
 			return nil, fmt.Errorf("Failed to chmod device %s: %s", devPath, err)
 		}
 
-		idmapset, err := c.IdmapSet()
+		idmapset, err := c.CurrentIdmap()
 		if err != nil {
 			return nil, err
 		}
@@ -8672,25 +8677,6 @@ func (c *containerLXC) Id() int {
 	return c.id
 }
 
-func (c *containerLXC) IdmapSet() (*idmap.IdmapSet, error) {
-	var err error
-
-	if c.idmapset != nil {
-		return c.idmapset, nil
-	}
-
-	if c.IsPrivileged() {
-		return nil, nil
-	}
-
-	c.idmapset, err = c.NextIdmapSet()
-	if err != nil {
-		return nil, err
-	}
-
-	return c.idmapset, nil
-}
-
 func (c *containerLXC) InitPID() int {
 	// Load the go-lxc struct
 	err := c.initLXC(false)
@@ -8709,32 +8695,6 @@ func (c *containerLXC) LocalDevices() types.Devices {
 	return c.localDevices
 }
 
-func (c *containerLXC) idmapsetFromConfig(k string) (*idmap.IdmapSet, error) {
-	lastJsonIdmap := c.LocalConfig()[k]
-
-	if lastJsonIdmap == "" {
-		return c.IdmapSet()
-	}
-
-	return idmapsetFromString(lastJsonIdmap)
-}
-
-func (c *containerLXC) NextIdmapSet() (*idmap.IdmapSet, error) {
-	if c.localConfig["volatile.idmap.next"] != "" {
-		return c.idmapsetFromConfig("volatile.idmap.next")
-	} else if c.IsPrivileged() {
-		return nil, nil
-	} else if c.state.OS.IdmapSet != nil {
-		return c.state.OS.IdmapSet, nil
-	}
-
-	return nil, fmt.Errorf("Unable to determine the idmap")
-}
-
-func (c *containerLXC) LastIdmapSet() (*idmap.IdmapSet, error) {
-	return c.idmapsetFromConfig("volatile.last_state.idmap")
-}
-
 func (c *containerLXC) CurrentIdmap() (*idmap.IdmapSet, error) {
 	jsonIdmap, ok := c.LocalConfig()["volatile.idmap.current"]
 	if !ok {
diff --git a/lxd/container_test.go b/lxd/container_test.go
index 263412b787..caa3adebe0 100644
--- a/lxd/container_test.go
+++ b/lxd/container_test.go
@@ -264,9 +264,9 @@ func (suite *containerTestSuite) TestContainer_findIdmap_isolated() {
 	suite.Req.Nil(err)
 	defer c2.Delete()
 
-	map1, err := c1.(*containerLXC).NextIdmapSet()
+	map1, err := c1.(*containerLXC).NextIdmap()
 	suite.Req.Nil(err)
-	map2, err := c2.(*containerLXC).NextIdmapSet()
+	map2, err := c2.(*containerLXC).NextIdmap()
 	suite.Req.Nil(err)
 
 	host := suite.d.os.IdmapSet.Idmap[0]
@@ -305,9 +305,9 @@ func (suite *containerTestSuite) TestContainer_findIdmap_mixed() {
 	suite.Req.Nil(err)
 	defer c2.Delete()
 
-	map1, err := c1.(*containerLXC).NextIdmapSet()
+	map1, err := c1.(*containerLXC).NextIdmap()
 	suite.Req.Nil(err)
-	map2, err := c2.(*containerLXC).NextIdmapSet()
+	map2, err := c2.(*containerLXC).NextIdmap()
 	suite.Req.Nil(err)
 
 	host := suite.d.os.IdmapSet.Idmap[0]
@@ -337,7 +337,7 @@ func (suite *containerTestSuite) TestContainer_findIdmap_raw() {
 	suite.Req.Nil(err)
 	defer c1.Delete()
 
-	map1, err := c1.(*containerLXC).NextIdmapSet()
+	map1, err := c1.(*containerLXC).NextIdmap()
 	suite.Req.Nil(err)
 
 	host := suite.d.os.IdmapSet.Idmap[0]
@@ -383,7 +383,7 @@ func (suite *containerTestSuite) TestContainer_findIdmap_maxed() {
 
 		defer c.Delete()
 
-		m, err := c.(*containerLXC).NextIdmapSet()
+		m, err := c.(*containerLXC).NextIdmap()
 		suite.Req.Nil(err)
 
 		maps = append(maps, m)

From f7a5e23f978661ba10dae6f6d575cfd22b1b8b9c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Wed, 27 Mar 2019 18:42:07 -0400
Subject: [PATCH 4/5] doc: Introduce volatile.idmap.current
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 doc/containers.md       | 1 +
 scripts/bash/lxd-client | 6 +++---
 shared/container.go     | 3 ++-
 3 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/doc/containers.md b/doc/containers.md
index 2e853f59d3..b3949ff418 100644
--- a/doc/containers.md
+++ b/doc/containers.md
@@ -92,6 +92,7 @@ volatile.apply\_quota           | string    | -             | Disk quota to be a
 volatile.apply\_template        | string    | -             | The name of a template hook which should be triggered upon next startup
 volatile.base\_image            | string    | -             | The hash of the image the container was created from, if any.
 volatile.idmap.base             | integer   | -             | The first id in the container's primary idmap range
+volatile.idmap.current          | string    | -             | The idmap currently in use by the container
 volatile.idmap.next             | string    | -             | The idmap to use next time the container starts
 volatile.last\_state.idmap      | string    | -             | Serialized container uid/gid map
 volatile.last\_state.power      | string    | -             | Container state as of last host shutdown
diff --git a/scripts/bash/lxd-client b/scripts/bash/lxd-client
index c8e09f5793..41ee4f3ff1 100644
--- a/scripts/bash/lxd-client
+++ b/scripts/bash/lxd-client
@@ -92,9 +92,9 @@ _have lxc && {
       security.syscalls.blacklist_compat security.syscalls.blacklist_default \
       snapshots.schedule snapshots.schedule.stopped snapshots.pattern \
       volatile.apply_quota volatile.apply_template volatile.base_image \
-      volatile.idmap.base volatile.idmap.next volatile.last_state.idmap \
-      volatile.last_state.power user.meta-data user.network-config \
-      user.network_mode user.user-data user.vendor-data"
+      volatile.idmap.base volatile.idmap.current volatile.idmap.next \
+      volatile.last_state.idmap volatile.last_state.power user.meta-data \
+      user.network-config user.network_mode user.user-data user.vendor-data"
 
     networks_keys="bridge.driver bridge.external_interfaces bridge.mode \
       bridge.mtu bridge.hwaddr dns.domain dns.mode fan.overlay_subnet fan.type \
diff --git a/shared/container.go b/shared/container.go
index 824a142355..6e609959d0 100644
--- a/shared/container.go
+++ b/shared/container.go
@@ -302,8 +302,9 @@ var KnownContainerConfigKeys = map[string]func(value string) error{
 	"volatile.base_image":       IsAny,
 	"volatile.last_state.idmap": IsAny,
 	"volatile.last_state.power": IsAny,
-	"volatile.idmap.next":       IsAny,
 	"volatile.idmap.base":       IsAny,
+	"volatile.idmap.current":    IsAny,
+	"volatile.idmap.next":       IsAny,
 	"volatile.apply_quota":      IsAny,
 }
 

From e9f79646430c8513ed01b7efdcd5f0cfdce44f50 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Wed, 27 Mar 2019 22:08:30 -0400
Subject: [PATCH 5/5] api: Add id_map_current API extension
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 doc/api-extensions.md | 12 ++++++++++++
 shared/version/api.go |  1 +
 2 files changed, 13 insertions(+)

diff --git a/doc/api-extensions.md b/doc/api-extensions.md
index d30fc52cbd..20395ea9bf 100644
--- a/doc/api-extensions.md
+++ b/doc/api-extensions.md
@@ -710,3 +710,15 @@ Shows the NUMA node for all CPUs and GPUs.
 
 ## kernel\_features
 Exposes the state of optional kernel features through the server environment.
+
+## id\_map\_current
+This introduces a new internal `volatile.idmap.current` key which is
+used to track the current mapping for the container.
+
+This effectively gives us:
+ - `volatile.last\_state.idmap` => On-disk idmap
+ - `volatile.idmap.current` => Current kernel map
+ - `volatile.idmap.next` => Next on-disk idmap
+
+This is required to implement environments where the on-disk map isn't
+changed but the kernel map is (e.g. shiftfs).
diff --git a/shared/version/api.go b/shared/version/api.go
index 6481e4f786..6d056c5747 100644
--- a/shared/version/api.go
+++ b/shared/version/api.go
@@ -144,6 +144,7 @@ var APIExtensions = []string{
 	"resources_gpu",
 	"resources_numa",
 	"kernel_features",
+	"id_map_current",
 }
 
 // APIExtensionsCount returns the number of available API extensions.


More information about the lxc-devel mailing list