Signed-off-by: Shishir Mahajan <shishir.mahajan@redhat.com>
| ... | ... |
@@ -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{}
|