[lxc-devel] [lxd/master] [RFC] zfs: Set canmount=noauto on all mountable datasets

stgraber on Github lxc-bot at linuxcontainers.org
Sat Jul 8 05:08:00 UTC 2017


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 447 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20170708/82e6df84/attachment.bin>
-------------- next part --------------
From abae8e083e4f25d228aa55ba994ae619904f3d8b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Fri, 7 Jul 2017 17:41:24 -0400
Subject: [PATCH] zfs: Set canmount=noauto on all mountable datasets
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

We don't want the container host to randomly mount stuff behind our back.

Closes #3437

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxd/patches.go           | 58 ++++++++++++++++++++++++++++++++++++++++++++++++
 lxd/storage_zfs.go       | 49 +++++++++++++++++++++++++++++++++++++---
 lxd/storage_zfs_utils.go | 12 +++++++---
 test/suites/snapshots.sh |  2 +-
 4 files changed, 114 insertions(+), 7 deletions(-)

diff --git a/lxd/patches.go b/lxd/patches.go
index 9c3786799..ce2f54989 100644
--- a/lxd/patches.go
+++ b/lxd/patches.go
@@ -44,6 +44,7 @@ var patches = []patch{
 	{name: "storage_api_lxd_on_btrfs", run: patchStorageApiLxdOnBtrfs},
 	{name: "storage_api_lvm_detect_lv_size", run: patchStorageApiDetectLVSize},
 	{name: "storage_api_insert_zfs_driver", run: patchStorageApiInsertZfsDriver},
+	{name: "storage_zfs_noauto", run: patchStorageZFSnoauto},
 }
 
 type patch struct {
@@ -2247,6 +2248,63 @@ func patchStorageApiInsertZfsDriver(name string, d *Daemon) error {
 	return nil
 }
 
+func patchStorageZFSnoauto(name string, d *Daemon) error {
+	pools, err := dbStoragePools(d.db)
+	if err != nil {
+		if err == NoSuchObjectError {
+			return nil
+		}
+		logger.Errorf("Failed to query database: %s", err)
+		return err
+	}
+
+	for _, poolName := range pools {
+		_, pool, err := dbStoragePoolGet(d.db, poolName)
+		if err != nil {
+			logger.Errorf("Failed to query database: %s", err)
+			return err
+		}
+
+		if pool.Driver != "zfs" {
+			continue
+		}
+
+		zpool := pool.Config["zfs.pool_name"]
+		if zpool == "" {
+			continue
+		}
+		path := fmt.Sprintf("%s/containers", zpool)
+
+		output, err := shared.RunCommand(
+			"zfs",
+			"list",
+			"-t", "filesystem",
+			"-o", "name",
+			"-H",
+			"-r", path)
+		if err != nil {
+			return fmt.Errorf("Unable to list containers on zpool: %s", zpool)
+		}
+
+		for _, entry := range strings.Split(output, "\n") {
+			if entry == "" {
+				continue
+			}
+
+			if entry == path {
+				continue
+			}
+
+			_, err := shared.RunCommand("zfs", "set", "canmount=noauto", entry)
+			if err != nil {
+				return fmt.Errorf("Unable to set canmount=noauto on: %s", entry)
+			}
+		}
+	}
+
+	return nil
+}
+
 // Patches end here
 
 // Here are a couple of legacy patches that were originally in
diff --git a/lxd/storage_zfs.go b/lxd/storage_zfs.go
index 5d6b3fb2e..6e6eac9be 100644
--- a/lxd/storage_zfs.go
+++ b/lxd/storage_zfs.go
@@ -192,7 +192,7 @@ func (s *storageZfs) StoragePoolVolumeCreate() error {
 	dataset := fmt.Sprintf("%s/%s", poolName, fs)
 	customPoolVolumeMntPoint := getStoragePoolVolumeMountPoint(s.pool.Name, s.volume.Name)
 
-	msg, err := zfsPoolVolumeCreate(dataset, "mountpoint=none")
+	msg, err := zfsPoolVolumeCreate(dataset, "mountpoint=none", "canmount=noauto")
 	if err != nil {
 		logger.Errorf("failed to create ZFS storage volume \"%s\" on storage pool \"%s\": %s", s.volume.Name, s.pool.Name, msg)
 		return err
@@ -535,11 +535,12 @@ func (s *storageZfs) ContainerCreate(container container) error {
 	containerPoolVolumeMntPoint := getContainerMountPoint(s.pool.Name, containerName)
 
 	// Create volume.
-	msg, err := zfsPoolVolumeCreate(dataset, "mountpoint=none")
+	msg, err := zfsPoolVolumeCreate(dataset, "mountpoint=none", "canmount=noauto")
 	if err != nil {
 		logger.Errorf("failed to create ZFS storage volume for container \"%s\" on storage pool \"%s\": %s", s.volume.Name, s.pool.Name, msg)
 		return err
 	}
+
 	revert := true
 	defer func() {
 		if !revert {
@@ -554,6 +555,14 @@ func (s *storageZfs) ContainerCreate(container container) error {
 		return err
 	}
 
+	ourMount, err := s.ContainerMount(container)
+	if err != nil {
+		return err
+	}
+	if ourMount {
+		defer s.ContainerUmount(containerName, containerPath)
+	}
+
 	err = createContainerMountpoint(containerPoolVolumeMntPoint, containerPath, container.IsPrivileged())
 	if err != nil {
 		return err
@@ -620,6 +629,14 @@ func (s *storageZfs) ContainerCreateFromImage(container container, fingerprint s
 		s.ContainerDelete(container)
 	}()
 
+	ourMount, err := s.ContainerMount(container)
+	if err != nil {
+		return err
+	}
+	if ourMount {
+		defer s.ContainerUmount(containerName, containerPath)
+	}
+
 	privileged := container.IsPrivileged()
 	err = createContainerMountpoint(containerPoolVolumeMntPoint, containerPath, privileged)
 	if err != nil {
@@ -922,6 +939,12 @@ func (s *storageZfs) copyWithoutSnapshotFull(target container, source container)
 
 	targetContainerMountPoint := getContainerMountPoint(s.pool.Name, targetName)
 	targetfs := fmt.Sprintf("containers/%s", targetName)
+
+	err = s.zfsPoolVolumeSet(targetfs, "canmount", "noauto")
+	if err != nil {
+		return err
+	}
+
 	err = s.zfsPoolVolumeSet(targetfs, "mountpoint", targetContainerMountPoint)
 	if err != nil {
 		return err
@@ -932,6 +955,14 @@ func (s *storageZfs) copyWithoutSnapshotFull(target container, source container)
 		return err
 	}
 
+	ourMount, err := s.ContainerMount(target)
+	if err != nil {
+		return err
+	}
+	if ourMount {
+		defer s.ContainerUmount(targetName, targetContainerMountPoint)
+	}
+
 	err = createContainerMountpoint(targetContainerMountPoint, target.Path(), target.IsPrivileged())
 	if err != nil {
 		return err
@@ -1093,11 +1124,16 @@ func (s *storageZfs) ContainerCopy(target container, source container, container
 		s.zfsPoolVolumeSnapshotDestroy(fmt.Sprintf("containers/%s", target.Name()), tmpSnapshotName)
 
 		fs := fmt.Sprintf("containers/%s", target.Name())
-		err = s.zfsPoolVolumeSet(fs, "mountpoint", targetContainerMountPoint)
+
+		err = s.zfsPoolVolumeSet(fs, "canmount", "noauto")
 		if err != nil {
 			return err
 		}
 
+		err = s.zfsPoolVolumeSet(fs, "mountpoint", targetContainerMountPoint)
+		if err != nil {
+			return err
+		}
 	}
 
 	logger.Debugf("Copied ZFS container storage %s -> %s.", source.Name(), target.Name())
@@ -1501,6 +1537,11 @@ func (s *storageZfs) ContainerSnapshotStart(container container) (bool, error) {
 		return false, err
 	}
 
+	err = s.zfsPoolVolumeMount(destFs)
+	if err != nil {
+		return false, err
+	}
+
 	logger.Debugf("Initialized ZFS storage volume for snapshot \"%s\" on storage pool \"%s\".", s.volume.Name, s.pool.Name)
 	return true, nil
 }
@@ -1947,6 +1988,7 @@ func (s *storageZfs) zfsPoolVolumeClone(source string, name string, dest string,
 		"clone",
 		"-p",
 		"-o", fmt.Sprintf("mountpoint=%s", mountpoint),
+		"-o", "canmount=noauto",
 		fmt.Sprintf("%s/%s@%s", poolName, source, name),
 		fmt.Sprintf("%s/%s", poolName, dest))
 	if err != nil {
@@ -1977,6 +2019,7 @@ func (s *storageZfs) zfsPoolVolumeClone(source string, name string, dest string,
 			"clone",
 			"-p",
 			"-o", fmt.Sprintf("mountpoint=%s", snapshotMntPoint),
+			"-o", "canmount=noauto",
 			fmt.Sprintf("%s/%s@%s", poolName, sub, name),
 			fmt.Sprintf("%s/%s", poolName, destSubvol))
 		if err != nil {
diff --git a/lxd/storage_zfs_utils.go b/lxd/storage_zfs_utils.go
index c13229543..599a37a6e 100644
--- a/lxd/storage_zfs_utils.go
+++ b/lxd/storage_zfs_utils.go
@@ -2,15 +2,21 @@ package main
 
 import (
 	"fmt"
-	"strings"
 
 	"github.com/lxc/lxd/shared"
 )
 
 // zfsPoolVolumeCreate creates a ZFS dataset with a set of given properties.
 func zfsPoolVolumeCreate(dataset string, properties ...string) (string, error) {
-	p := strings.Join(properties, ",")
-	return shared.RunCommand("zfs", "create", "-o", p, "-p", dataset)
+	cmd := []string{"zfs", "create"}
+
+	for _, prop := range properties {
+		cmd = append(cmd, []string{"-o", prop}...)
+	}
+
+	cmd = append(cmd, []string{"-p", dataset}...)
+
+	return shared.RunCommand(cmd[0], cmd[1:]...)
 }
 
 func zfsPoolVolumeSet(dataset string, key string, value string) (string, error) {
diff --git a/test/suites/snapshots.sh b/test/suites/snapshots.sh
index d3f8c598b..bf188f18c 100644
--- a/test/suites/snapshots.sh
+++ b/test/suites/snapshots.sh
@@ -44,7 +44,7 @@ snapshots() {
 
   lxc copy foo/tester foosnap1
   # FIXME: make this backend agnostic
-  if [ "$lxd_backend" != "lvm" ]; then
+  if [ "$lxd_backend" != "lvm" ] && [ "${lxd_backend}" != "zfs" ]; then
     [ -d "${LXD_DIR}/containers/foosnap1/rootfs" ]
   fi
 


More information about the lxc-devel mailing list