Browse code

CLI flag for docker create(run) to change block device size.

Signed-off-by: Shishir Mahajan <shishir.mahajan@redhat.com>

Shishir Mahajan authored on 2016/03/20 13:42:58
Showing 30 changed files
... ...
@@ -137,7 +137,7 @@ func main() {
137 137
 			usage()
138 138
 		}
139 139
 
140
-		err := devices.AddDevice(args[1], args[2])
140
+		err := devices.AddDevice(args[1], args[2], nil)
141 141
 		if err != nil {
142 142
 			fmt.Println("Can't create snap device: ", err)
143 143
 			os.Exit(1)
... ...
@@ -84,6 +84,8 @@ func (daemon *Daemon) create(params types.ContainerCreateConfig) (retC *containe
84 84
 		return nil, err
85 85
 	}
86 86
 
87
+	container.HostConfig.StorageOpt = params.HostConfig.StorageOpt
88
+
87 89
 	// Set RWLayer for container after mount labels have been set
88 90
 	if err := daemon.setRWLayer(container); err != nil {
89 91
 		return nil, err
... ...
@@ -156,7 +158,7 @@ func (daemon *Daemon) setRWLayer(container *container.Container) error {
156 156
 		}
157 157
 		layerID = img.RootFS.ChainID()
158 158
 	}
159
-	rwLayer, err := daemon.layerStore.CreateRWLayer(container.ID, layerID, container.MountLabel, daemon.setupInitLayer)
159
+	rwLayer, err := daemon.layerStore.CreateRWLayer(container.ID, layerID, container.MountLabel, daemon.setupInitLayer, container.HostConfig.StorageOpt)
160 160
 	if err != nil {
161 161
 		return err
162 162
 	}
... ...
@@ -195,7 +195,12 @@ func (a *Driver) Exists(id string) bool {
195 195
 
196 196
 // Create three folders for each id
197 197
 // mnt, layers, and diff
198
-func (a *Driver) Create(id, parent, mountLabel string) error {
198
+func (a *Driver) Create(id, parent, mountLabel string, storageOpt map[string]string) error {
199
+
200
+	if len(storageOpt) != 0 {
201
+		return fmt.Errorf("--storage-opt is not supported for aufs")
202
+	}
203
+
199 204
 	if err := a.createDirsFor(id); err != nil {
200 205
 		return err
201 206
 	}
... ...
@@ -101,7 +101,7 @@ func TestCreateNewDir(t *testing.T) {
101 101
 	d := newDriver(t)
102 102
 	defer os.RemoveAll(tmp)
103 103
 
104
-	if err := d.Create("1", "", ""); err != nil {
104
+	if err := d.Create("1", "", "", nil); err != nil {
105 105
 		t.Fatal(err)
106 106
 	}
107 107
 }
... ...
@@ -110,7 +110,7 @@ func TestCreateNewDirStructure(t *testing.T) {
110 110
 	d := newDriver(t)
111 111
 	defer os.RemoveAll(tmp)
112 112
 
113
-	if err := d.Create("1", "", ""); err != nil {
113
+	if err := d.Create("1", "", "", nil); err != nil {
114 114
 		t.Fatal(err)
115 115
 	}
116 116
 
... ...
@@ -131,7 +131,7 @@ func TestRemoveImage(t *testing.T) {
131 131
 	d := newDriver(t)
132 132
 	defer os.RemoveAll(tmp)
133 133
 
134
-	if err := d.Create("1", "", ""); err != nil {
134
+	if err := d.Create("1", "", "", nil); err != nil {
135 135
 		t.Fatal(err)
136 136
 	}
137 137
 
... ...
@@ -156,7 +156,7 @@ func TestGetWithoutParent(t *testing.T) {
156 156
 	d := newDriver(t)
157 157
 	defer os.RemoveAll(tmp)
158 158
 
159
-	if err := d.Create("1", "", ""); err != nil {
159
+	if err := d.Create("1", "", "", nil); err != nil {
160 160
 		t.Fatal(err)
161 161
 	}
162 162
 
... ...
@@ -183,7 +183,7 @@ func TestCleanupWithDir(t *testing.T) {
183 183
 	d := newDriver(t)
184 184
 	defer os.RemoveAll(tmp)
185 185
 
186
-	if err := d.Create("1", "", ""); err != nil {
186
+	if err := d.Create("1", "", "", nil); err != nil {
187 187
 		t.Fatal(err)
188 188
 	}
189 189
 
... ...
@@ -196,7 +196,7 @@ func TestMountedFalseResponse(t *testing.T) {
196 196
 	d := newDriver(t)
197 197
 	defer os.RemoveAll(tmp)
198 198
 
199
-	if err := d.Create("1", "", ""); err != nil {
199
+	if err := d.Create("1", "", "", nil); err != nil {
200 200
 		t.Fatal(err)
201 201
 	}
202 202
 
... ...
@@ -215,10 +215,10 @@ func TestMountedTrueReponse(t *testing.T) {
215 215
 	defer os.RemoveAll(tmp)
216 216
 	defer d.Cleanup()
217 217
 
218
-	if err := d.Create("1", "", ""); err != nil {
218
+	if err := d.Create("1", "", "", nil); err != nil {
219 219
 		t.Fatal(err)
220 220
 	}
221
-	if err := d.Create("2", "1", ""); err != nil {
221
+	if err := d.Create("2", "1", "", nil); err != nil {
222 222
 		t.Fatal(err)
223 223
 	}
224 224
 
... ...
@@ -241,10 +241,10 @@ func TestMountWithParent(t *testing.T) {
241 241
 	d := newDriver(t)
242 242
 	defer os.RemoveAll(tmp)
243 243
 
244
-	if err := d.Create("1", "", ""); err != nil {
244
+	if err := d.Create("1", "", "", nil); err != nil {
245 245
 		t.Fatal(err)
246 246
 	}
247
-	if err := d.Create("2", "1", ""); err != nil {
247
+	if err := d.Create("2", "1", "", nil); err != nil {
248 248
 		t.Fatal(err)
249 249
 	}
250 250
 
... ...
@@ -272,10 +272,10 @@ func TestRemoveMountedDir(t *testing.T) {
272 272
 	d := newDriver(t)
273 273
 	defer os.RemoveAll(tmp)
274 274
 
275
-	if err := d.Create("1", "", ""); err != nil {
275
+	if err := d.Create("1", "", "", nil); err != nil {
276 276
 		t.Fatal(err)
277 277
 	}
278
-	if err := d.Create("2", "1", ""); err != nil {
278
+	if err := d.Create("2", "1", "", nil); err != nil {
279 279
 		t.Fatal(err)
280 280
 	}
281 281
 
... ...
@@ -311,7 +311,7 @@ func TestCreateWithInvalidParent(t *testing.T) {
311 311
 	d := newDriver(t)
312 312
 	defer os.RemoveAll(tmp)
313 313
 
314
-	if err := d.Create("1", "docker", ""); err == nil {
314
+	if err := d.Create("1", "docker", "", nil); err == nil {
315 315
 		t.Fatalf("Error should not be nil with parent does not exist")
316 316
 	}
317 317
 }
... ...
@@ -320,7 +320,7 @@ func TestGetDiff(t *testing.T) {
320 320
 	d := newDriver(t)
321 321
 	defer os.RemoveAll(tmp)
322 322
 
323
-	if err := d.Create("1", "", ""); err != nil {
323
+	if err := d.Create("1", "", "", nil); err != nil {
324 324
 		t.Fatal(err)
325 325
 	}
326 326
 
... ...
@@ -354,10 +354,10 @@ func TestChanges(t *testing.T) {
354 354
 	d := newDriver(t)
355 355
 	defer os.RemoveAll(tmp)
356 356
 
357
-	if err := d.Create("1", "", ""); err != nil {
357
+	if err := d.Create("1", "", "", nil); err != nil {
358 358
 		t.Fatal(err)
359 359
 	}
360
-	if err := d.Create("2", "1", ""); err != nil {
360
+	if err := d.Create("2", "1", "", nil); err != nil {
361 361
 		t.Fatal(err)
362 362
 	}
363 363
 
... ...
@@ -403,7 +403,7 @@ func TestChanges(t *testing.T) {
403 403
 		t.Fatalf("Change kind should be ChangeAdd got %s", change.Kind)
404 404
 	}
405 405
 
406
-	if err := d.Create("3", "2", ""); err != nil {
406
+	if err := d.Create("3", "2", "", nil); err != nil {
407 407
 		t.Fatal(err)
408 408
 	}
409 409
 	mntPoint, err = d.Get("3", "")
... ...
@@ -448,7 +448,7 @@ func TestDiffSize(t *testing.T) {
448 448
 	d := newDriver(t)
449 449
 	defer os.RemoveAll(tmp)
450 450
 
451
-	if err := d.Create("1", "", ""); err != nil {
451
+	if err := d.Create("1", "", "", nil); err != nil {
452 452
 		t.Fatal(err)
453 453
 	}
454 454
 
... ...
@@ -490,7 +490,7 @@ func TestChildDiffSize(t *testing.T) {
490 490
 	defer os.RemoveAll(tmp)
491 491
 	defer d.Cleanup()
492 492
 
493
-	if err := d.Create("1", "", ""); err != nil {
493
+	if err := d.Create("1", "", "", nil); err != nil {
494 494
 		t.Fatal(err)
495 495
 	}
496 496
 
... ...
@@ -526,7 +526,7 @@ func TestChildDiffSize(t *testing.T) {
526 526
 		t.Fatalf("Expected size to be %d got %d", size, diffSize)
527 527
 	}
528 528
 
529
-	if err := d.Create("2", "1", ""); err != nil {
529
+	if err := d.Create("2", "1", "", nil); err != nil {
530 530
 		t.Fatal(err)
531 531
 	}
532 532
 
... ...
@@ -545,7 +545,7 @@ func TestExists(t *testing.T) {
545 545
 	defer os.RemoveAll(tmp)
546 546
 	defer d.Cleanup()
547 547
 
548
-	if err := d.Create("1", "", ""); err != nil {
548
+	if err := d.Create("1", "", "", nil); err != nil {
549 549
 		t.Fatal(err)
550 550
 	}
551 551
 
... ...
@@ -563,7 +563,7 @@ func TestStatus(t *testing.T) {
563 563
 	defer os.RemoveAll(tmp)
564 564
 	defer d.Cleanup()
565 565
 
566
-	if err := d.Create("1", "", ""); err != nil {
566
+	if err := d.Create("1", "", "", nil); err != nil {
567 567
 		t.Fatal(err)
568 568
 	}
569 569
 
... ...
@@ -592,7 +592,7 @@ func TestApplyDiff(t *testing.T) {
592 592
 	defer os.RemoveAll(tmp)
593 593
 	defer d.Cleanup()
594 594
 
595
-	if err := d.Create("1", "", ""); err != nil {
595
+	if err := d.Create("1", "", "", nil); err != nil {
596 596
 		t.Fatal(err)
597 597
 	}
598 598
 
... ...
@@ -618,10 +618,10 @@ func TestApplyDiff(t *testing.T) {
618 618
 		t.Fatal(err)
619 619
 	}
620 620
 
621
-	if err := d.Create("2", "", ""); err != nil {
621
+	if err := d.Create("2", "", "", nil); err != nil {
622 622
 		t.Fatal(err)
623 623
 	}
624
-	if err := d.Create("3", "2", ""); err != nil {
624
+	if err := d.Create("3", "2", "", nil); err != nil {
625 625
 		t.Fatal(err)
626 626
 	}
627 627
 
... ...
@@ -671,7 +671,7 @@ func testMountMoreThan42Layers(t *testing.T, mountPath string) {
671 671
 		}
672 672
 		current = hash(current)
673 673
 
674
-		if err := d.Create(current, parent, ""); err != nil {
674
+		if err := d.Create(current, parent, "", nil); err != nil {
675 675
 			t.Logf("Current layer %d", i)
676 676
 			t.Error(err)
677 677
 		}
... ...
@@ -750,11 +750,11 @@ func BenchmarkConcurrentAccess(b *testing.B) {
750 750
 		ids = append(ids, stringid.GenerateNonCryptoID())
751 751
 	}
752 752
 
753
-	if err := d.Create(ids[0], "", ""); err != nil {
753
+	if err := d.Create(ids[0], "", "", nil); err != nil {
754 754
 		b.Fatal(err)
755 755
 	}
756 756
 
757
-	if err := d.Create(ids[1], ids[0], ""); err != nil {
757
+	if err := d.Create(ids[1], ids[0], "", nil); err != nil {
758 758
 		b.Fatal(err)
759 759
 	}
760 760
 
... ...
@@ -770,7 +770,7 @@ func BenchmarkConcurrentAccess(b *testing.B) {
770 770
 	for _, id := range ids {
771 771
 		go func(id string) {
772 772
 			defer outerGroup.Done()
773
-			if err := d.Create(id, parent, ""); err != nil {
773
+			if err := d.Create(id, parent, "", nil); err != nil {
774 774
 				b.Logf("Create %s failed", id)
775 775
 				chErr <- err
776 776
 				return
... ...
@@ -242,7 +242,12 @@ func (d *Driver) subvolumesDirID(id string) string {
242 242
 }
243 243
 
244 244
 // Create the filesystem with given id.
245
-func (d *Driver) Create(id, parent, mountLabel string) error {
245
+func (d *Driver) Create(id, parent, mountLabel string, storageOpt map[string]string) error {
246
+
247
+	if len(storageOpt) != 0 {
248
+		return fmt.Errorf("--storage-opt is not supported for btrfs")
249
+	}
250
+
246 251
 	subvolumes := path.Join(d.home, "subvolumes")
247 252
 	rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps)
248 253
 	if err != nil {
... ...
@@ -30,7 +30,7 @@ func TestBtrfsCreateSnap(t *testing.T) {
30 30
 
31 31
 func TestBtrfsSubvolDelete(t *testing.T) {
32 32
 	d := graphtest.GetDriver(t, "btrfs")
33
-	if err := d.Create("test", "", ""); err != nil {
33
+	if err := d.Create("test", "", "", nil); err != nil {
34 34
 		t.Fatal(err)
35 35
 	}
36 36
 	defer graphtest.PutDriver(t)
... ...
@@ -839,7 +839,7 @@ func (devices *DeviceSet) createRegisterDevice(hash string) (*devInfo, error) {
839 839
 	return info, nil
840 840
 }
841 841
 
842
-func (devices *DeviceSet) createRegisterSnapDevice(hash string, baseInfo *devInfo) error {
842
+func (devices *DeviceSet) createRegisterSnapDevice(hash string, baseInfo *devInfo, size uint64) error {
843 843
 	if err := devices.poolHasFreeSpace(); err != nil {
844 844
 		return err
845 845
 	}
... ...
@@ -878,7 +878,7 @@ func (devices *DeviceSet) createRegisterSnapDevice(hash string, baseInfo *devInf
878 878
 		break
879 879
 	}
880 880
 
881
-	if _, err := devices.registerDevice(deviceID, hash, baseInfo.Size, devices.OpenTransactionID); err != nil {
881
+	if _, err := devices.registerDevice(deviceID, hash, size, devices.OpenTransactionID); err != nil {
882 882
 		devicemapper.DeleteDevice(devices.getPoolDevName(), deviceID)
883 883
 		devices.markDeviceIDFree(deviceID)
884 884
 		logrus.Debugf("devmapper: Error registering device: %s", err)
... ...
@@ -1830,7 +1830,7 @@ func (devices *DeviceSet) initDevmapper(doInit bool) error {
1830 1830
 }
1831 1831
 
1832 1832
 // AddDevice adds a device and registers in the hash.
1833
-func (devices *DeviceSet) AddDevice(hash, baseHash string) error {
1833
+func (devices *DeviceSet) AddDevice(hash, baseHash string, storageOpt map[string]string) error {
1834 1834
 	logrus.Debugf("devmapper: AddDevice(hash=%s basehash=%s)", hash, baseHash)
1835 1835
 	defer logrus.Debugf("devmapper: AddDevice(hash=%s basehash=%s) END", hash, baseHash)
1836 1836
 
... ...
@@ -1856,10 +1856,56 @@ func (devices *DeviceSet) AddDevice(hash, baseHash string) error {
1856 1856
 		return fmt.Errorf("devmapper: device %s already exists. Deleted=%v", hash, info.Deleted)
1857 1857
 	}
1858 1858
 
1859
-	if err := devices.createRegisterSnapDevice(hash, baseInfo); err != nil {
1859
+	devinfo := &devInfo{}
1860
+
1861
+	if err := devices.parseStorageOpt(storageOpt, devinfo); err != nil {
1862
+		return err
1863
+	}
1864
+
1865
+	if devinfo.Size == 0 {
1866
+		devinfo.Size = baseInfo.Size
1867
+	}
1868
+
1869
+	if devinfo.Size < baseInfo.Size {
1870
+		return fmt.Errorf("devmapper: Container size cannot be smaller than %s", units.HumanSize(float64(baseInfo.Size)))
1871
+	}
1872
+
1873
+	if err := devices.createRegisterSnapDevice(hash, baseInfo, devinfo.Size); err != nil {
1860 1874
 		return err
1861 1875
 	}
1862 1876
 
1877
+	// Grow the container rootfs.
1878
+	if devinfo.Size > 0 {
1879
+		info, err := devices.lookupDevice(hash)
1880
+		if err != nil {
1881
+			return err
1882
+		}
1883
+
1884
+		if err := devices.growFS(info); err != nil {
1885
+			return err
1886
+		}
1887
+	}
1888
+
1889
+	return nil
1890
+}
1891
+
1892
+func (devices *DeviceSet) parseStorageOpt(storageOpt map[string]string, devinfo *devInfo) error {
1893
+
1894
+	// Read size to change the block device size per container.
1895
+	for key, val := range storageOpt {
1896
+		key := strings.ToLower(key)
1897
+		switch key {
1898
+		case "size":
1899
+			size, err := units.RAMInBytes(val)
1900
+			if err != nil {
1901
+				return err
1902
+			}
1903
+			devinfo.Size = uint64(size)
1904
+		default:
1905
+			return fmt.Errorf("Unknown option %s", key)
1906
+		}
1907
+	}
1908
+
1863 1909
 	return nil
1864 1910
 }
1865 1911
 
... ...
@@ -118,8 +118,8 @@ func (d *Driver) Cleanup() error {
118 118
 }
119 119
 
120 120
 // Create adds a device with a given id and the parent.
121
-func (d *Driver) Create(id, parent, mountLabel string) error {
122
-	if err := d.DeviceSet.AddDevice(id, parent); err != nil {
121
+func (d *Driver) Create(id, parent, mountLabel string, storageOpt map[string]string) error {
122
+	if err := d.DeviceSet.AddDevice(id, parent, storageOpt); err != nil {
123 123
 		return err
124 124
 	}
125 125
 
... ...
@@ -48,7 +48,7 @@ type ProtoDriver interface {
48 48
 	String() string
49 49
 	// Create creates a new, empty, filesystem layer with the
50 50
 	// specified id and parent and mountLabel. Parent and mountLabel may be "".
51
-	Create(id, parent, mountLabel string) error
51
+	Create(id, parent, mountLabel string, storageOpt map[string]string) error
52 52
 	// Remove attempts to remove the filesystem layer with this id.
53 53
 	Remove(id string) error
54 54
 	// Get returns the mountpoint for the layered filesystem referred
... ...
@@ -177,7 +177,7 @@ func DriverTestCreateEmpty(t *testing.T, drivername string) {
177 177
 	driver := GetDriver(t, drivername)
178 178
 	defer PutDriver(t)
179 179
 
180
-	if err := driver.Create("empty", "", ""); err != nil {
180
+	if err := driver.Create("empty", "", "", nil); err != nil {
181 181
 		t.Fatal(err)
182 182
 	}
183 183
 
... ...
@@ -215,7 +215,7 @@ func createBase(t *testing.T, driver graphdriver.Driver, name string) {
215 215
 	oldmask := syscall.Umask(0)
216 216
 	defer syscall.Umask(oldmask)
217 217
 
218
-	if err := driver.Create(name, "", ""); err != nil {
218
+	if err := driver.Create(name, "", "", nil); err != nil {
219 219
 		t.Fatal(err)
220 220
 	}
221 221
 
... ...
@@ -283,7 +283,7 @@ func DriverTestCreateSnap(t *testing.T, drivername string) {
283 283
 
284 284
 	createBase(t, driver, "Base")
285 285
 
286
-	if err := driver.Create("Snap", "Base", ""); err != nil {
286
+	if err := driver.Create("Snap", "Base", "", nil); err != nil {
287 287
 		t.Fatal(err)
288 288
 	}
289 289
 
... ...
@@ -222,7 +222,12 @@ func (d *Driver) Cleanup() error {
222 222
 
223 223
 // Create is used to create the upper, lower, and merge directories required for overlay fs for a given id.
224 224
 // The parent filesystem is used to configure these directories for the overlay.
225
-func (d *Driver) Create(id, parent, mountLabel string) (retErr error) {
225
+func (d *Driver) Create(id, parent, mountLabel string, storageOpt map[string]string) (retErr error) {
226
+
227
+	if len(storageOpt) != 0 {
228
+		return fmt.Errorf("--storage-opt is not supported for overlay")
229
+	}
230
+
226 231
 	dir := d.dir(id)
227 232
 
228 233
 	rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps)
... ...
@@ -54,7 +54,7 @@ func (d *graphDriverProxy) String() string {
54 54
 	return d.name
55 55
 }
56 56
 
57
-func (d *graphDriverProxy) Create(id, parent, mountLabel string) error {
57
+func (d *graphDriverProxy) Create(id, parent, mountLabel string, storageOpt map[string]string) error {
58 58
 	args := &graphDriverRequest{
59 59
 		ID:         id,
60 60
 		Parent:     parent,
... ...
@@ -69,7 +69,11 @@ func (d *Driver) Cleanup() error {
69 69
 }
70 70
 
71 71
 // Create prepares the filesystem for the VFS driver and copies the directory for the given id under the parent.
72
-func (d *Driver) Create(id, parent, mountLabel string) error {
72
+func (d *Driver) Create(id, parent, mountLabel string, storageOpt map[string]string) error {
73
+	if len(storageOpt) != 0 {
74
+		return fmt.Errorf("--storage-opt is not supported for vfs")
75
+	}
76
+
73 77
 	dir := d.dir(id)
74 78
 	rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps)
75 79
 	if err != nil {
... ...
@@ -107,7 +107,11 @@ func (d *Driver) Exists(id string) bool {
107 107
 }
108 108
 
109 109
 // Create creates a new layer with the given id.
110
-func (d *Driver) Create(id, parent, mountLabel string) error {
110
+func (d *Driver) Create(id, parent, mountLabel string, storageOpt map[string]string) error {
111
+	if len(storageOpt) != 0 {
112
+		return fmt.Errorf("--storage-opt is not supported for windows")
113
+	}
114
+
111 115
 	rPId, err := d.resolveID(parent)
112 116
 	if err != nil {
113 117
 		return err
... ...
@@ -432,7 +436,7 @@ func (d *Driver) GetCustomImageInfos() ([]CustomImageInfo, error) {
432 432
 		h := sha512.Sum384([]byte(folderName))
433 433
 		id := fmt.Sprintf("%x", h[:32])
434 434
 
435
-		if err := d.Create(id, "", ""); err != nil {
435
+		if err := d.Create(id, "", "", nil); err != nil {
436 436
 			return nil, err
437 437
 		}
438 438
 		// Create the alternate ID file.
... ...
@@ -241,7 +241,11 @@ func (d *Driver) mountPath(id string) string {
241 241
 }
242 242
 
243 243
 // Create prepares the dataset and filesystem for the ZFS driver for the given id under the parent.
244
-func (d *Driver) Create(id string, parent string, mountLabel string) error {
244
+func (d *Driver) Create(id string, parent string, mountLabel string, storageOpt map[string]string) error {
245
+	if len(storageOpt) != 0 {
246
+		return fmt.Errorf("--storage-opt is not supported for zfs")
247
+	}
248
+
245 249
 	err := d.create(id, parent)
246 250
 	if err == nil {
247 251
 		return nil
... ...
@@ -106,7 +106,7 @@ func (ls *mockLayerStore) Get(chainID layer.ChainID) (layer.Layer, error) {
106 106
 func (ls *mockLayerStore) Release(l layer.Layer) ([]layer.Metadata, error) {
107 107
 	return []layer.Metadata{}, nil
108 108
 }
109
-func (ls *mockLayerStore) CreateRWLayer(string, layer.ChainID, string, layer.MountInit) (layer.RWLayer, error) {
109
+func (ls *mockLayerStore) CreateRWLayer(string, layer.ChainID, string, layer.MountInit, map[string]string) (layer.RWLayer, error) {
110 110
 	return nil, errors.New("not implemented")
111 111
 }
112 112
 
... ...
@@ -116,6 +116,8 @@ This section lists each version from latest to oldest.  Each listing includes a
116 116
 
117 117
 [Docker Remote API v1.24](docker_remote_api_v1.24.md) documentation
118 118
 
119
+* `POST /containers/create` now takes `StorageOpt` field.
120
+
119 121
 ### v1.23 API changes
120 122
 
121 123
 [Docker Remote API v1.23](docker_remote_api_v1.23.md) documentation
... ...
@@ -325,6 +325,7 @@ Create a container
325 325
              "Ulimits": [{}],
326 326
              "LogConfig": { "Type": "json-file", "Config": {} },
327 327
              "SecurityOpt": [""],
328
+             "StorageOpt": {},
328 329
              "CgroupParent": "",
329 330
              "VolumeDriver": "",
330 331
              "ShmSize": 67108864
... ...
@@ -444,6 +445,8 @@ Json Parameters:
444 444
           `Ulimits: { "Name": "nofile", "Soft": 1024, "Hard": 2048 }`
445 445
     -   **SecurityOpt**: A list of string values to customize labels for MLS
446 446
         systems, such as SELinux.
447
+    -   **StorageOpt**: Storage driver options per container. Options can be passed in the form
448
+        `{"size":"120G"}`
447 449
     -   **LogConfig** - Log configuration for the container, specified as a JSON object in the form
448 450
           `{ "Type": "<driver_name>", "Config": {"key1": "val1"}}`.
449 451
           Available types: `json-file`, `syslog`, `journald`, `gelf`, `fluentd`, `awslogs`, `splunk`, `etwlogs`, `none`.
... ...
@@ -568,6 +571,7 @@ Return low-level information on the container `id`
568 568
 				"Type": "json-file"
569 569
 			},
570 570
 			"SecurityOpt": null,
571
+			"StorageOpt": null,
571 572
 			"VolumesFrom": null,
572 573
 			"Ulimits": [{}],
573 574
 			"VolumeDriver": "",
... ...
@@ -81,6 +81,7 @@ Creates a new container.
81 81
       --security-opt=[]             Security options
82 82
       --stop-signal="SIGTERM"       Signal to stop a container
83 83
       --shm-size=[]                 Size of `/dev/shm`. The format is `<number><unit>`. `number` must be greater than `0`.  Unit is optional and can be `b` (bytes), `k` (kilobytes), `m` (megabytes), or `g` (gigabytes). If you omit the unit, the system uses bytes. If you omit the size entirely, the system uses `64m`.
84
+      --storage-opt=[]              Set storage driver options per container
84 85
       -t, --tty                     Allocate a pseudo-TTY
85 86
       -u, --user=""                 Username or UID
86 87
       --userns=""                   Container user namespace
... ...
@@ -145,6 +146,13 @@ then be used from the subsequent container:
145 145
     drwx--S---  2 1000 staff  460 Dec  5 00:51 .ssh
146 146
     drwxr-xr-x 32 1000 staff 1140 Dec  5 04:01 docker
147 147
 
148
+Set storage driver options per container. 
149
+
150
+    $ docker create -it --storage-opt size=120G fedora /bin/bash
151
+
152
+This (size) will allow to set the container rootfs size to 120G at creation time. 
153
+User cannot pass a size less than the Default BaseFS Size. 
154
+
148 155
 ### Specify isolation technology for container (--isolation)
149 156
 
150 157
 This option is useful in situations where you are running Docker containers on
... ...
@@ -83,6 +83,7 @@ parent = "smn_cli"
83 83
       --security-opt=[]             Security Options
84 84
       --sig-proxy=true              Proxy received signals to the process
85 85
       --stop-signal="SIGTERM"       Signal to stop a container
86
+      --storage-opt=[]              Set storage driver options per container
86 87
       -t, --tty                     Allocate a pseudo-TTY
87 88
       -u, --user=""                 Username or UID (format: <name|uid>[:<group|gid>])
88 89
       --userns=""                   Container user namespace
... ...
@@ -167,6 +168,13 @@ flag exists to allow special use-cases, like running Docker within Docker.
167 167
 The `-w` lets the command being executed inside directory given, here
168 168
 `/path/to/dir/`. If the path does not exists it is created inside the container.
169 169
 
170
+### Set storage driver options per container
171
+
172
+    $ docker create -it --storage-opt size=120G fedora /bin/bash
173
+
174
+This (size) will allow to set the container rootfs size to 120G at creation time. 
175
+User cannot pass a size less than the Default BaseFS Size.
176
+
170 177
 ### Mount tmpfs (--tmpfs)
171 178
 
172 179
     $ docker run -d --tmpfs /run:rw,noexec,nosuid,size=65536k my_image
... ...
@@ -60,6 +60,27 @@ func (s *DockerSuite) TestCreateArgs(c *check.C) {
60 60
 
61 61
 }
62 62
 
63
+// Make sure we can grow the container's rootfs at creation time.
64
+func (s *DockerSuite) TestCreateGrowRootfs(c *check.C) {
65
+	testRequires(c, Devicemapper)
66
+	out, _ := dockerCmd(c, "create", "--storage-opt", "size=120G", "busybox")
67
+
68
+	cleanedContainerID := strings.TrimSpace(out)
69
+
70
+	inspectOut := inspectField(c, cleanedContainerID, "HostConfig.StorageOpt")
71
+	c.Assert(inspectOut, checker.Equals, "[size=120G]")
72
+}
73
+
74
+// Make sure we cannot shrink the container's rootfs at creation time.
75
+func (s *DockerSuite) TestCreateShrinkRootfs(c *check.C) {
76
+	testRequires(c, Devicemapper)
77
+
78
+	// Ensure this fails
79
+	out, _, err := dockerCmdWithError("create", "--storage-opt", "size=80G", "busybox")
80
+	c.Assert(err, check.NotNil, check.Commentf(out))
81
+	c.Assert(out, checker.Contains, "Container size cannot be smaller than")
82
+}
83
+
63 84
 // Make sure we can set hostconfig options too
64 85
 func (s *DockerSuite) TestCreateHostConfig(c *check.C) {
65 86
 	out, _ := dockerCmd(c, "create", "-P", "busybox", "echo")
... ...
@@ -122,7 +122,7 @@ func (s *DockerExternalGraphdriverSuite) SetUpSuite(c *check.C) {
122 122
 		if err := decReq(r.Body, &req, w); err != nil {
123 123
 			return
124 124
 		}
125
-		if err := driver.Create(req.ID, req.Parent, ""); err != nil {
125
+		if err := driver.Create(req.ID, req.Parent, "", nil); err != nil {
126 126
 			respond(w, err)
127 127
 			return
128 128
 		}
... ...
@@ -171,7 +171,7 @@ type Store interface {
171 171
 	Get(ChainID) (Layer, error)
172 172
 	Release(Layer) ([]Metadata, error)
173 173
 
174
-	CreateRWLayer(id string, parent ChainID, mountLabel string, initFunc MountInit) (RWLayer, error)
174
+	CreateRWLayer(id string, parent ChainID, mountLabel string, initFunc MountInit, storageOpt map[string]string) (RWLayer, error)
175 175
 	GetRWLayer(id string) (RWLayer, error)
176 176
 	GetMountID(id string) (string, error)
177 177
 	ReleaseRWLayer(RWLayer) ([]Metadata, error)
... ...
@@ -263,7 +263,7 @@ func (ls *layerStore) Register(ts io.Reader, parent ChainID) (Layer, error) {
263 263
 		references:     map[Layer]struct{}{},
264 264
 	}
265 265
 
266
-	if err = ls.driver.Create(layer.cacheID, pid, ""); err != nil {
266
+	if err = ls.driver.Create(layer.cacheID, pid, "", nil); err != nil {
267 267
 		return nil, err
268 268
 	}
269 269
 
... ...
@@ -414,7 +414,7 @@ func (ls *layerStore) Release(l Layer) ([]Metadata, error) {
414 414
 	return ls.releaseLayer(layer)
415 415
 }
416 416
 
417
-func (ls *layerStore) CreateRWLayer(name string, parent ChainID, mountLabel string, initFunc MountInit) (RWLayer, error) {
417
+func (ls *layerStore) CreateRWLayer(name string, parent ChainID, mountLabel string, initFunc MountInit, storageOpt map[string]string) (RWLayer, error) {
418 418
 	ls.mountL.Lock()
419 419
 	defer ls.mountL.Unlock()
420 420
 	m, ok := ls.mounts[name]
... ...
@@ -451,14 +451,14 @@ func (ls *layerStore) CreateRWLayer(name string, parent ChainID, mountLabel stri
451 451
 	}
452 452
 
453 453
 	if initFunc != nil {
454
-		pid, err = ls.initMount(m.mountID, pid, mountLabel, initFunc)
454
+		pid, err = ls.initMount(m.mountID, pid, mountLabel, initFunc, storageOpt)
455 455
 		if err != nil {
456 456
 			return nil, err
457 457
 		}
458 458
 		m.initID = pid
459 459
 	}
460 460
 
461
-	if err = ls.driver.Create(m.mountID, pid, ""); err != nil {
461
+	if err = ls.driver.Create(m.mountID, pid, "", storageOpt); err != nil {
462 462
 		return nil, err
463 463
 	}
464 464
 
... ...
@@ -561,14 +561,14 @@ func (ls *layerStore) saveMount(mount *mountedLayer) error {
561 561
 	return nil
562 562
 }
563 563
 
564
-func (ls *layerStore) initMount(graphID, parent, mountLabel string, initFunc MountInit) (string, error) {
564
+func (ls *layerStore) initMount(graphID, parent, mountLabel string, initFunc MountInit, storageOpt map[string]string) (string, error) {
565 565
 	// Use "<graph-id>-init" to maintain compatibility with graph drivers
566 566
 	// which are expecting this layer with this special name. If all
567 567
 	// graph drivers can be updated to not rely on knowing about this layer
568 568
 	// then the initID should be randomly generated.
569 569
 	initID := fmt.Sprintf("%s-init", graphID)
570 570
 
571
-	if err := ls.driver.Create(initID, parent, mountLabel); err != nil {
571
+	if err := ls.driver.Create(initID, parent, mountLabel, storageOpt); err != nil {
572 572
 		return "", err
573 573
 	}
574 574
 	p, err := ls.driver.Get(initID, "")
... ...
@@ -84,7 +84,7 @@ type layerInit func(root string) error
84 84
 
85 85
 func createLayer(ls Store, parent ChainID, layerFunc layerInit) (Layer, error) {
86 86
 	containerID := stringid.GenerateRandomID()
87
-	mount, err := ls.CreateRWLayer(containerID, parent, "", nil)
87
+	mount, err := ls.CreateRWLayer(containerID, parent, "", nil, nil)
88 88
 	if err != nil {
89 89
 		return nil, err
90 90
 	}
... ...
@@ -279,7 +279,7 @@ func TestMountAndRegister(t *testing.T) {
279 279
 	size, _ := layer.Size()
280 280
 	t.Logf("Layer size: %d", size)
281 281
 
282
-	mount2, err := ls.CreateRWLayer("new-test-mount", layer.ChainID(), "", nil)
282
+	mount2, err := ls.CreateRWLayer("new-test-mount", layer.ChainID(), "", nil, nil)
283 283
 	if err != nil {
284 284
 		t.Fatal(err)
285 285
 	}
... ...
@@ -387,7 +387,7 @@ func TestStoreRestore(t *testing.T) {
387 387
 		t.Fatal(err)
388 388
 	}
389 389
 
390
-	m, err := ls.CreateRWLayer("some-mount_name", layer3.ChainID(), "", nil)
390
+	m, err := ls.CreateRWLayer("some-mount_name", layer3.ChainID(), "", nil, nil)
391 391
 	if err != nil {
392 392
 		t.Fatal(err)
393 393
 	}
... ...
@@ -421,7 +421,7 @@ func TestStoreRestore(t *testing.T) {
421 421
 	assertLayerEqual(t, layer3b, layer3)
422 422
 
423 423
 	// Create again with same name, should return error
424
-	if _, err := ls2.CreateRWLayer("some-mount_name", layer3b.ChainID(), "", nil); err == nil {
424
+	if _, err := ls2.CreateRWLayer("some-mount_name", layer3b.ChainID(), "", nil, nil); err == nil {
425 425
 		t.Fatal("Expected error creating mount with same name")
426 426
 	} else if err != ErrMountNameConflict {
427 427
 		t.Fatal(err)
... ...
@@ -78,7 +78,7 @@ func TestLayerMigration(t *testing.T) {
78 78
 	}
79 79
 
80 80
 	graphID1 := stringid.GenerateRandomID()
81
-	if err := graph.Create(graphID1, "", ""); err != nil {
81
+	if err := graph.Create(graphID1, "", "", nil); err != nil {
82 82
 		t.Fatal(err)
83 83
 	}
84 84
 	if _, err := graph.ApplyDiff(graphID1, "", archive.Reader(bytes.NewReader(tar1))); err != nil {
... ...
@@ -123,7 +123,7 @@ func TestLayerMigration(t *testing.T) {
123 123
 	}
124 124
 
125 125
 	graphID2 := stringid.GenerateRandomID()
126
-	if err := graph.Create(graphID2, graphID1, ""); err != nil {
126
+	if err := graph.Create(graphID2, graphID1, "", nil); err != nil {
127 127
 		t.Fatal(err)
128 128
 	}
129 129
 	if _, err := graph.ApplyDiff(graphID2, graphID1, archive.Reader(bytes.NewReader(tar2))); err != nil {
... ...
@@ -165,7 +165,7 @@ func tarFromFilesInGraph(graph graphdriver.Driver, graphID, parentID string, fil
165 165
 		return nil, err
166 166
 	}
167 167
 
168
-	if err := graph.Create(graphID, parentID, ""); err != nil {
168
+	if err := graph.Create(graphID, parentID, "", nil); err != nil {
169 169
 		return nil, err
170 170
 	}
171 171
 	if _, err := graph.ApplyDiff(graphID, parentID, archive.Reader(bytes.NewReader(t))); err != nil {
... ...
@@ -320,14 +320,14 @@ func TestMountMigration(t *testing.T) {
320 320
 	containerID := stringid.GenerateRandomID()
321 321
 	containerInit := fmt.Sprintf("%s-init", containerID)
322 322
 
323
-	if err := graph.Create(containerInit, graphID1, ""); err != nil {
323
+	if err := graph.Create(containerInit, graphID1, "", nil); err != nil {
324 324
 		t.Fatal(err)
325 325
 	}
326 326
 	if _, err := graph.ApplyDiff(containerInit, graphID1, archive.Reader(bytes.NewReader(initTar))); err != nil {
327 327
 		t.Fatal(err)
328 328
 	}
329 329
 
330
-	if err := graph.Create(containerID, containerInit, ""); err != nil {
330
+	if err := graph.Create(containerID, containerInit, "", nil); err != nil {
331 331
 		t.Fatal(err)
332 332
 	}
333 333
 	if _, err := graph.ApplyDiff(containerID, containerInit, archive.Reader(bytes.NewReader(mountTar))); err != nil {
... ...
@@ -382,7 +382,7 @@ func TestMountMigration(t *testing.T) {
382 382
 
383 383
 	assertActivityCount(t, rwLayer1, 1)
384 384
 
385
-	if _, err := ls.CreateRWLayer("migration-mount", layer1.ChainID(), "", nil); err == nil {
385
+	if _, err := ls.CreateRWLayer("migration-mount", layer1.ChainID(), "", nil, nil); err == nil {
386 386
 		t.Fatal("Expected error creating mount with same name")
387 387
 	} else if err != ErrMountNameConflict {
388 388
 		t.Fatal(err)
... ...
@@ -32,7 +32,7 @@ func TestMountInit(t *testing.T) {
32 32
 		return initfile.ApplyFile(root)
33 33
 	}
34 34
 
35
-	m, err := ls.CreateRWLayer("fun-mount", layer.ChainID(), "", mountInit)
35
+	m, err := ls.CreateRWLayer("fun-mount", layer.ChainID(), "", mountInit, nil)
36 36
 	if err != nil {
37 37
 		t.Fatal(err)
38 38
 	}
... ...
@@ -89,7 +89,7 @@ func TestMountSize(t *testing.T) {
89 89
 		return newTestFile("file-init", contentInit, 0777).ApplyFile(root)
90 90
 	}
91 91
 
92
-	m, err := ls.CreateRWLayer("mount-size", layer.ChainID(), "", mountInit)
92
+	m, err := ls.CreateRWLayer("mount-size", layer.ChainID(), "", mountInit, nil)
93 93
 	if err != nil {
94 94
 		t.Fatal(err)
95 95
 	}
... ...
@@ -138,7 +138,7 @@ func TestMountChanges(t *testing.T) {
138 138
 		return initfile.ApplyFile(root)
139 139
 	}
140 140
 
141
-	m, err := ls.CreateRWLayer("mount-changes", layer.ChainID(), "", mountInit)
141
+	m, err := ls.CreateRWLayer("mount-changes", layer.ChainID(), "", mountInit, nil)
142 142
 	if err != nil {
143 143
 		t.Fatal(err)
144 144
 	}
... ...
@@ -64,6 +64,7 @@ docker-create - Create a new container
64 64
 [**--read-only**]
65 65
 [**--restart**[=*RESTART*]]
66 66
 [**--security-opt**[=*[]*]]
67
+[**--storage-opt**[=*[]*]]
67 68
 [**--stop-signal**[=*SIGNAL*]]
68 69
 [**--shm-size**[=*[]*]]
69 70
 [**-t**|**--tty**]
... ...
@@ -325,6 +326,13 @@ unit, `b` is used. Set LIMIT to `-1` to enable unlimited swap.
325 325
     "seccomp:unconfined" : Turn off seccomp confinement for the container
326 326
     "seccomp:profile.json :  White listed syscalls seccomp Json file to be used as a seccomp filter
327 327
 
328
+**--storage-opt**=[]
329
+   Storage driver options per container
330
+
331
+   $ docker create -it --storage-opt size=120G fedora /bin/bash
332
+
333
+   This (size) will allow to set the container rootfs size to 120G at creation time. User cannot pass a size less than the Default BaseFS Size.
334
+  
328 335
 **--stop-signal**=*SIGTERM*
329 336
   Signal to stop a container. Default is SIGTERM.
330 337
 
... ...
@@ -67,6 +67,7 @@ docker-run - Run a command in a new container
67 67
 [**--restart**[=*RESTART*]]
68 68
 [**--rm**]
69 69
 [**--security-opt**[=*[]*]]
70
+[**--storage-opt**[=*[]*]]
70 71
 [**--stop-signal**[=*SIGNAL*]]
71 72
 [**--shm-size**[=*[]*]]
72 73
 [**--sig-proxy**[=*true*]]
... ...
@@ -476,6 +477,13 @@ its root filesystem mounted as read only prohibiting any writes.
476 476
     "apparmor=unconfined" : Turn off apparmor confinement for the container
477 477
     "apparmor=your-profile" : Set the apparmor confinement profile for the container
478 478
 
479
+**--storage-opt**=[]
480
+   Storage driver options per container
481
+
482
+   $ docker run -it --storage-opt size=120G fedora /bin/bash
483
+
484
+   This (size) will allow to set the container rootfs size to 120G at creation time. User cannot pass a size less than the Default BaseFS Size.
485
+  
479 486
 **--stop-signal**=*SIGTERM*
480 487
   Signal to stop a container. Default is SIGTERM.
481 488
 
... ...
@@ -55,6 +55,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*container.Config, *container.Host
55 55
 		flCapDrop           = opts.NewListOpts(nil)
56 56
 		flGroupAdd          = opts.NewListOpts(nil)
57 57
 		flSecurityOpt       = opts.NewListOpts(nil)
58
+		flStorageOpt        = opts.NewListOpts(nil)
58 59
 		flLabelsFile        = opts.NewListOpts(nil)
59 60
 		flLoggingOpts       = opts.NewListOpts(nil)
60 61
 		flPrivileged        = cmd.Bool([]string{"-privileged"}, false, "Give extended privileges to this container")
... ...
@@ -124,6 +125,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*container.Config, *container.Host
124 124
 	cmd.Var(&flCapDrop, []string{"-cap-drop"}, "Drop Linux capabilities")
125 125
 	cmd.Var(&flGroupAdd, []string{"-group-add"}, "Add additional groups to join")
126 126
 	cmd.Var(&flSecurityOpt, []string{"-security-opt"}, "Security Options")
127
+	cmd.Var(&flStorageOpt, []string{"-storage-opt"}, "Set storage driver options per container")
127 128
 	cmd.Var(flUlimits, []string{"-ulimit"}, "Ulimit options")
128 129
 	cmd.Var(&flLoggingOpts, []string{"-log-opt"}, "Log driver options")
129 130
 
... ...
@@ -337,6 +339,11 @@ func Parse(cmd *flag.FlagSet, args []string) (*container.Config, *container.Host
337 337
 		return nil, nil, nil, cmd, err
338 338
 	}
339 339
 
340
+	storageOpts, err := parseStorageOpts(flStorageOpt.GetAll())
341
+	if err != nil {
342
+		return nil, nil, nil, cmd, err
343
+	}
344
+
340 345
 	resources := container.Resources{
341 346
 		CgroupParent:         *flCgroupParent,
342 347
 		Memory:               flMemory,
... ...
@@ -415,6 +422,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*container.Config, *container.Host
415 415
 		GroupAdd:       flGroupAdd.GetAll(),
416 416
 		RestartPolicy:  restartPolicy,
417 417
 		SecurityOpt:    securityOpts,
418
+		StorageOpt:     storageOpts,
418 419
 		ReadonlyRootfs: *flReadonlyRootfs,
419 420
 		LogConfig:      container.LogConfig{Type: *flLoggingDriver, Config: loggingOpts},
420 421
 		VolumeDriver:   *flVolumeDriver,
... ...
@@ -531,6 +539,20 @@ func parseSecurityOpts(securityOpts []string) ([]string, error) {
531 531
 	return securityOpts, nil
532 532
 }
533 533
 
534
+// parse storage options per container into a map
535
+func parseStorageOpts(storageOpts []string) (map[string]string, error) {
536
+	m := make(map[string]string)
537
+	for _, option := range storageOpts {
538
+		if strings.Contains(option, "=") {
539
+			opt := strings.SplitN(option, "=", 2)
540
+			m[opt[0]] = opt[1]
541
+		} else {
542
+			return nil, fmt.Errorf("Invalid storage option.")
543
+		}
544
+	}
545
+	return m, nil
546
+}
547
+
534 548
 // ParseRestartPolicy returns the parsed policy or an error indicating what is incorrect
535 549
 func ParseRestartPolicy(policy string) (container.RestartPolicy, error) {
536 550
 	p := container.RestartPolicy{}