Преглед изворни кода

Add support for setting storage size on zfs containers

Now supports setting a containers storage size when using zfs as the
storage engine.  By passing in `--storage-opt size=<size>`, the created
container's storage size will be limited to the given size.  Note that
the way zfs works, the given specified storage size will be given in
addition to the base container size.

Example:

The node image reports a size of `671M` from `df -h` when started.
Setting `--storage-opt size=2G` will result in a drive the size of
`671M` + `2G`, `2.7G` in total.  Available space will be `2.0G`.

The storage size is achieved by setting the zfs option `quota` to the
given size on the zfs volume.

Signed-off-by: Ken Herner <kherner@progress.com>
Ken Herner пре 9 година
родитељ
комит
e918340431
1 измењених фајлова са 40 додато и 11 уклоњено
  1. 40 11
      daemon/graphdriver/zfs/zfs.go

+ 40 - 11
daemon/graphdriver/zfs/zfs.go

@@ -250,11 +250,7 @@ func (d *Driver) CreateReadWrite(id, parent, mountLabel string, storageOpt map[s
 
 
 // Create prepares the dataset and filesystem for the ZFS driver for the given id under the parent.
 // Create prepares the dataset and filesystem for the ZFS driver for the given id under the parent.
 func (d *Driver) Create(id string, parent string, mountLabel string, storageOpt map[string]string) error {
 func (d *Driver) Create(id string, parent string, mountLabel string, storageOpt map[string]string) error {
-	if len(storageOpt) != 0 {
-		return fmt.Errorf("--storage-opt is not supported for zfs")
-	}
-
-	err := d.create(id, parent)
+	err := d.create(id, parent, storageOpt)
 	if err == nil {
 	if err == nil {
 		return nil
 		return nil
 	}
 	}
@@ -273,22 +269,55 @@ func (d *Driver) Create(id string, parent string, mountLabel string, storageOpt
 	}
 	}
 
 
 	// retry
 	// retry
-	return d.create(id, parent)
+	return d.create(id, parent, storageOpt)
 }
 }
 
 
-func (d *Driver) create(id, parent string) error {
+func (d *Driver) create(id, parent string, storageOpt map[string]string) error {
 	name := d.zfsPath(id)
 	name := d.zfsPath(id)
+	quota, err := parseStorageOpt(storageOpt)
 	if parent == "" {
 	if parent == "" {
 		mountoptions := map[string]string{"mountpoint": "legacy"}
 		mountoptions := map[string]string{"mountpoint": "legacy"}
 		fs, err := zfs.CreateFilesystem(name, mountoptions)
 		fs, err := zfs.CreateFilesystem(name, mountoptions)
 		if err == nil {
 		if err == nil {
-			d.Lock()
-			d.filesystemsCache[fs.Name] = true
-			d.Unlock()
+			err = setQuota(name, quota)
+			if err == nil {
+				d.Lock()
+				d.filesystemsCache[fs.Name] = true
+				d.Unlock()
+			}
+		}
+		return err
+	}
+	err = d.cloneFilesystem(name, d.zfsPath(parent))
+	if err == nil {
+		err = setQuota(name, quota)
+	}
+	return err
+}
+
+func parseStorageOpt(storageOpt map[string]string) (string, error) {
+	// Read size to change the disk quota per container
+	for k, v := range storageOpt {
+		key := strings.ToLower(k)
+		switch key {
+		case "size":
+			return v, nil
+		default:
+			return "0", fmt.Errorf("Unknown option %s", key)
 		}
 		}
+	}
+	return "0", nil
+}
+
+func setQuota(name string, quota string) error {
+	if quota == "0" {
+		return nil
+	}
+	fs, err := zfs.GetDataset(name)
+	if err != nil {
 		return err
 		return err
 	}
 	}
-	return d.cloneFilesystem(name, d.zfsPath(parent))
+	return fs.SetProperty("quota", quota)
 }
 }
 
 
 // Remove deletes the dataset, filesystem and the cache for the given id.
 // Remove deletes the dataset, filesystem and the cache for the given id.