1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Merge pull request #19367 from shishir-a412ed/rootfs_size_configurable_cli

CLI flag for docker create(run) to change block device size.
This commit is contained in:
Vincent Demeester 2016-03-29 08:52:54 +02:00
commit e6aa40a017
30 changed files with 228 additions and 72 deletions

View file

@ -137,7 +137,7 @@ func main() {
usage()
}
err := devices.AddDevice(args[1], args[2])
err := devices.AddDevice(args[1], args[2], nil)
if err != nil {
fmt.Println("Can't create snap device: ", err)
os.Exit(1)

View file

@ -84,6 +84,8 @@ func (daemon *Daemon) create(params types.ContainerCreateConfig) (retC *containe
return nil, err
}
container.HostConfig.StorageOpt = params.HostConfig.StorageOpt
// Set RWLayer for container after mount labels have been set
if err := daemon.setRWLayer(container); err != nil {
return nil, err
@ -156,7 +158,7 @@ func (daemon *Daemon) setRWLayer(container *container.Container) error {
}
layerID = img.RootFS.ChainID()
}
rwLayer, err := daemon.layerStore.CreateRWLayer(container.ID, layerID, container.MountLabel, daemon.setupInitLayer)
rwLayer, err := daemon.layerStore.CreateRWLayer(container.ID, layerID, container.MountLabel, daemon.setupInitLayer, container.HostConfig.StorageOpt)
if err != nil {
return err
}

View file

@ -196,7 +196,12 @@ func (a *Driver) Exists(id string) bool {
// Create three folders for each id
// mnt, layers, and diff
func (a *Driver) Create(id, parent, mountLabel string) error {
func (a *Driver) Create(id, parent, mountLabel string, storageOpt map[string]string) error {
if len(storageOpt) != 0 {
return fmt.Errorf("--storage-opt is not supported for aufs")
}
if err := a.createDirsFor(id); err != nil {
return err
}

View file

@ -101,7 +101,7 @@ func TestCreateNewDir(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
if err := d.Create("1", "", ""); err != nil {
if err := d.Create("1", "", "", nil); err != nil {
t.Fatal(err)
}
}
@ -110,7 +110,7 @@ func TestCreateNewDirStructure(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
if err := d.Create("1", "", ""); err != nil {
if err := d.Create("1", "", "", nil); err != nil {
t.Fatal(err)
}
@ -131,7 +131,7 @@ func TestRemoveImage(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
if err := d.Create("1", "", ""); err != nil {
if err := d.Create("1", "", "", nil); err != nil {
t.Fatal(err)
}
@ -156,7 +156,7 @@ func TestGetWithoutParent(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
if err := d.Create("1", "", ""); err != nil {
if err := d.Create("1", "", "", nil); err != nil {
t.Fatal(err)
}
@ -183,7 +183,7 @@ func TestCleanupWithDir(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
if err := d.Create("1", "", ""); err != nil {
if err := d.Create("1", "", "", nil); err != nil {
t.Fatal(err)
}
@ -196,7 +196,7 @@ func TestMountedFalseResponse(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
if err := d.Create("1", "", ""); err != nil {
if err := d.Create("1", "", "", nil); err != nil {
t.Fatal(err)
}
@ -215,10 +215,10 @@ func TestMountedTrueReponse(t *testing.T) {
defer os.RemoveAll(tmp)
defer d.Cleanup()
if err := d.Create("1", "", ""); err != nil {
if err := d.Create("1", "", "", nil); err != nil {
t.Fatal(err)
}
if err := d.Create("2", "1", ""); err != nil {
if err := d.Create("2", "1", "", nil); err != nil {
t.Fatal(err)
}
@ -241,10 +241,10 @@ func TestMountWithParent(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
if err := d.Create("1", "", ""); err != nil {
if err := d.Create("1", "", "", nil); err != nil {
t.Fatal(err)
}
if err := d.Create("2", "1", ""); err != nil {
if err := d.Create("2", "1", "", nil); err != nil {
t.Fatal(err)
}
@ -272,10 +272,10 @@ func TestRemoveMountedDir(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
if err := d.Create("1", "", ""); err != nil {
if err := d.Create("1", "", "", nil); err != nil {
t.Fatal(err)
}
if err := d.Create("2", "1", ""); err != nil {
if err := d.Create("2", "1", "", nil); err != nil {
t.Fatal(err)
}
@ -311,7 +311,7 @@ func TestCreateWithInvalidParent(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
if err := d.Create("1", "docker", ""); err == nil {
if err := d.Create("1", "docker", "", nil); err == nil {
t.Fatalf("Error should not be nil with parent does not exist")
}
}
@ -320,7 +320,7 @@ func TestGetDiff(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
if err := d.Create("1", "", ""); err != nil {
if err := d.Create("1", "", "", nil); err != nil {
t.Fatal(err)
}
@ -354,10 +354,10 @@ func TestChanges(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
if err := d.Create("1", "", ""); err != nil {
if err := d.Create("1", "", "", nil); err != nil {
t.Fatal(err)
}
if err := d.Create("2", "1", ""); err != nil {
if err := d.Create("2", "1", "", nil); err != nil {
t.Fatal(err)
}
@ -403,7 +403,7 @@ func TestChanges(t *testing.T) {
t.Fatalf("Change kind should be ChangeAdd got %s", change.Kind)
}
if err := d.Create("3", "2", ""); err != nil {
if err := d.Create("3", "2", "", nil); err != nil {
t.Fatal(err)
}
mntPoint, err = d.Get("3", "")
@ -448,7 +448,7 @@ func TestDiffSize(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
if err := d.Create("1", "", ""); err != nil {
if err := d.Create("1", "", "", nil); err != nil {
t.Fatal(err)
}
@ -490,7 +490,7 @@ func TestChildDiffSize(t *testing.T) {
defer os.RemoveAll(tmp)
defer d.Cleanup()
if err := d.Create("1", "", ""); err != nil {
if err := d.Create("1", "", "", nil); err != nil {
t.Fatal(err)
}
@ -526,7 +526,7 @@ func TestChildDiffSize(t *testing.T) {
t.Fatalf("Expected size to be %d got %d", size, diffSize)
}
if err := d.Create("2", "1", ""); err != nil {
if err := d.Create("2", "1", "", nil); err != nil {
t.Fatal(err)
}
@ -545,7 +545,7 @@ func TestExists(t *testing.T) {
defer os.RemoveAll(tmp)
defer d.Cleanup()
if err := d.Create("1", "", ""); err != nil {
if err := d.Create("1", "", "", nil); err != nil {
t.Fatal(err)
}
@ -563,7 +563,7 @@ func TestStatus(t *testing.T) {
defer os.RemoveAll(tmp)
defer d.Cleanup()
if err := d.Create("1", "", ""); err != nil {
if err := d.Create("1", "", "", nil); err != nil {
t.Fatal(err)
}
@ -592,7 +592,7 @@ func TestApplyDiff(t *testing.T) {
defer os.RemoveAll(tmp)
defer d.Cleanup()
if err := d.Create("1", "", ""); err != nil {
if err := d.Create("1", "", "", nil); err != nil {
t.Fatal(err)
}
@ -618,10 +618,10 @@ func TestApplyDiff(t *testing.T) {
t.Fatal(err)
}
if err := d.Create("2", "", ""); err != nil {
if err := d.Create("2", "", "", nil); err != nil {
t.Fatal(err)
}
if err := d.Create("3", "2", ""); err != nil {
if err := d.Create("3", "2", "", nil); err != nil {
t.Fatal(err)
}
@ -671,7 +671,7 @@ func testMountMoreThan42Layers(t *testing.T, mountPath string) {
}
current = hash(current)
if err := d.Create(current, parent, ""); err != nil {
if err := d.Create(current, parent, "", nil); err != nil {
t.Logf("Current layer %d", i)
t.Error(err)
}
@ -750,11 +750,11 @@ func BenchmarkConcurrentAccess(b *testing.B) {
ids = append(ids, stringid.GenerateNonCryptoID())
}
if err := d.Create(ids[0], "", ""); err != nil {
if err := d.Create(ids[0], "", "", nil); err != nil {
b.Fatal(err)
}
if err := d.Create(ids[1], ids[0], ""); err != nil {
if err := d.Create(ids[1], ids[0], "", nil); err != nil {
b.Fatal(err)
}
@ -770,7 +770,7 @@ func BenchmarkConcurrentAccess(b *testing.B) {
for _, id := range ids {
go func(id string) {
defer outerGroup.Done()
if err := d.Create(id, parent, ""); err != nil {
if err := d.Create(id, parent, "", nil); err != nil {
b.Logf("Create %s failed", id)
chErr <- err
return

View file

@ -242,7 +242,12 @@ func (d *Driver) subvolumesDirID(id string) string {
}
// Create the filesystem with given id.
func (d *Driver) Create(id, parent, mountLabel string) error {
func (d *Driver) Create(id, parent, mountLabel string, storageOpt map[string]string) error {
if len(storageOpt) != 0 {
return fmt.Errorf("--storage-opt is not supported for btrfs")
}
subvolumes := path.Join(d.home, "subvolumes")
rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps)
if err != nil {

View file

@ -30,7 +30,7 @@ func TestBtrfsCreateSnap(t *testing.T) {
func TestBtrfsSubvolDelete(t *testing.T) {
d := graphtest.GetDriver(t, "btrfs")
if err := d.Create("test", "", ""); err != nil {
if err := d.Create("test", "", "", nil); err != nil {
t.Fatal(err)
}
defer graphtest.PutDriver(t)

View file

@ -839,7 +839,7 @@ func (devices *DeviceSet) createRegisterDevice(hash string) (*devInfo, error) {
return info, nil
}
func (devices *DeviceSet) createRegisterSnapDevice(hash string, baseInfo *devInfo) error {
func (devices *DeviceSet) createRegisterSnapDevice(hash string, baseInfo *devInfo, size uint64) error {
if err := devices.poolHasFreeSpace(); err != nil {
return err
}
@ -878,7 +878,7 @@ func (devices *DeviceSet) createRegisterSnapDevice(hash string, baseInfo *devInf
break
}
if _, err := devices.registerDevice(deviceID, hash, baseInfo.Size, devices.OpenTransactionID); err != nil {
if _, err := devices.registerDevice(deviceID, hash, size, devices.OpenTransactionID); err != nil {
devicemapper.DeleteDevice(devices.getPoolDevName(), deviceID)
devices.markDeviceIDFree(deviceID)
logrus.Debugf("devmapper: Error registering device: %s", err)
@ -1830,7 +1830,7 @@ func (devices *DeviceSet) initDevmapper(doInit bool) error {
}
// AddDevice adds a device and registers in the hash.
func (devices *DeviceSet) AddDevice(hash, baseHash string) error {
func (devices *DeviceSet) AddDevice(hash, baseHash string, storageOpt map[string]string) error {
logrus.Debugf("devmapper: AddDevice(hash=%s basehash=%s)", hash, baseHash)
defer logrus.Debugf("devmapper: AddDevice(hash=%s basehash=%s) END", hash, baseHash)
@ -1856,10 +1856,56 @@ func (devices *DeviceSet) AddDevice(hash, baseHash string) error {
return fmt.Errorf("devmapper: device %s already exists. Deleted=%v", hash, info.Deleted)
}
if err := devices.createRegisterSnapDevice(hash, baseInfo); err != nil {
devinfo := &devInfo{}
if err := devices.parseStorageOpt(storageOpt, devinfo); err != nil {
return err
}
if devinfo.Size == 0 {
devinfo.Size = baseInfo.Size
}
if devinfo.Size < baseInfo.Size {
return fmt.Errorf("devmapper: Container size cannot be smaller than %s", units.HumanSize(float64(baseInfo.Size)))
}
if err := devices.createRegisterSnapDevice(hash, baseInfo, devinfo.Size); err != nil {
return err
}
// Grow the container rootfs.
if devinfo.Size > 0 {
info, err := devices.lookupDevice(hash)
if err != nil {
return err
}
if err := devices.growFS(info); err != nil {
return err
}
}
return nil
}
func (devices *DeviceSet) parseStorageOpt(storageOpt map[string]string, devinfo *devInfo) error {
// Read size to change the block device size per container.
for key, val := range storageOpt {
key := strings.ToLower(key)
switch key {
case "size":
size, err := units.RAMInBytes(val)
if err != nil {
return err
}
devinfo.Size = uint64(size)
default:
return fmt.Errorf("Unknown option %s", key)
}
}
return nil
}

View file

@ -118,8 +118,8 @@ func (d *Driver) Cleanup() error {
}
// Create adds a device with a given id and the parent.
func (d *Driver) Create(id, parent, mountLabel string) error {
if err := d.DeviceSet.AddDevice(id, parent); err != nil {
func (d *Driver) Create(id, parent, mountLabel string, storageOpt map[string]string) error {
if err := d.DeviceSet.AddDevice(id, parent, storageOpt); err != nil {
return err
}

View file

@ -48,7 +48,7 @@ type ProtoDriver interface {
String() string
// Create creates a new, empty, filesystem layer with the
// specified id and parent and mountLabel. Parent and mountLabel may be "".
Create(id, parent, mountLabel string) error
Create(id, parent, mountLabel string, storageOpt map[string]string) error
// Remove attempts to remove the filesystem layer with this id.
Remove(id string) error
// Get returns the mountpoint for the layered filesystem referred

View file

@ -177,7 +177,7 @@ func DriverTestCreateEmpty(t *testing.T, drivername string) {
driver := GetDriver(t, drivername)
defer PutDriver(t)
if err := driver.Create("empty", "", ""); err != nil {
if err := driver.Create("empty", "", "", nil); err != nil {
t.Fatal(err)
}
@ -215,7 +215,7 @@ func createBase(t *testing.T, driver graphdriver.Driver, name string) {
oldmask := syscall.Umask(0)
defer syscall.Umask(oldmask)
if err := driver.Create(name, "", ""); err != nil {
if err := driver.Create(name, "", "", nil); err != nil {
t.Fatal(err)
}
@ -283,7 +283,7 @@ func DriverTestCreateSnap(t *testing.T, drivername string) {
createBase(t, driver, "Base")
if err := driver.Create("Snap", "Base", ""); err != nil {
if err := driver.Create("Snap", "Base", "", nil); err != nil {
t.Fatal(err)
}

View file

@ -222,7 +222,12 @@ func (d *Driver) Cleanup() error {
// Create is used to create the upper, lower, and merge directories required for overlay fs for a given id.
// The parent filesystem is used to configure these directories for the overlay.
func (d *Driver) Create(id, parent, mountLabel string) (retErr error) {
func (d *Driver) Create(id, parent, mountLabel string, storageOpt map[string]string) (retErr error) {
if len(storageOpt) != 0 {
return fmt.Errorf("--storage-opt is not supported for overlay")
}
dir := d.dir(id)
rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps)

View file

@ -54,7 +54,7 @@ func (d *graphDriverProxy) String() string {
return d.name
}
func (d *graphDriverProxy) Create(id, parent, mountLabel string) error {
func (d *graphDriverProxy) Create(id, parent, mountLabel string, storageOpt map[string]string) error {
args := &graphDriverRequest{
ID: id,
Parent: parent,

View file

@ -69,7 +69,11 @@ func (d *Driver) Cleanup() error {
}
// Create prepares the filesystem for the VFS driver and copies the directory for the given id under the parent.
func (d *Driver) Create(id, parent, mountLabel string) error {
func (d *Driver) Create(id, parent, mountLabel string, storageOpt map[string]string) error {
if len(storageOpt) != 0 {
return fmt.Errorf("--storage-opt is not supported for vfs")
}
dir := d.dir(id)
rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps)
if err != nil {

View file

@ -107,7 +107,11 @@ func (d *Driver) Exists(id string) bool {
}
// Create creates a new layer with the given id.
func (d *Driver) Create(id, parent, mountLabel string) error {
func (d *Driver) Create(id, parent, mountLabel string, storageOpt map[string]string) error {
if len(storageOpt) != 0 {
return fmt.Errorf("--storage-opt is not supported for windows")
}
rPId, err := d.resolveID(parent)
if err != nil {
return err
@ -432,7 +436,7 @@ func (d *Driver) GetCustomImageInfos() ([]CustomImageInfo, error) {
h := sha512.Sum384([]byte(folderName))
id := fmt.Sprintf("%x", h[:32])
if err := d.Create(id, "", ""); err != nil {
if err := d.Create(id, "", "", nil); err != nil {
return nil, err
}
// Create the alternate ID file.

View file

@ -241,7 +241,11 @@ func (d *Driver) mountPath(id string) string {
}
// 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) 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)
if err == nil {
return nil

View file

@ -106,7 +106,7 @@ func (ls *mockLayerStore) Get(chainID layer.ChainID) (layer.Layer, error) {
func (ls *mockLayerStore) Release(l layer.Layer) ([]layer.Metadata, error) {
return []layer.Metadata{}, nil
}
func (ls *mockLayerStore) CreateRWLayer(string, layer.ChainID, string, layer.MountInit) (layer.RWLayer, error) {
func (ls *mockLayerStore) CreateRWLayer(string, layer.ChainID, string, layer.MountInit, map[string]string) (layer.RWLayer, error) {
return nil, errors.New("not implemented")
}

View file

@ -116,6 +116,8 @@ This section lists each version from latest to oldest. Each listing includes a
[Docker Remote API v1.24](docker_remote_api_v1.24.md) documentation
* `POST /containers/create` now takes `StorageOpt` field.
### v1.23 API changes
[Docker Remote API v1.23](docker_remote_api_v1.23.md) documentation

View file

@ -325,6 +325,7 @@ Create a container
"Ulimits": [{}],
"LogConfig": { "Type": "json-file", "Config": {} },
"SecurityOpt": [""],
"StorageOpt": {},
"CgroupParent": "",
"VolumeDriver": "",
"ShmSize": 67108864
@ -444,6 +445,8 @@ Json Parameters:
`Ulimits: { "Name": "nofile", "Soft": 1024, "Hard": 2048 }`
- **SecurityOpt**: A list of string values to customize labels for MLS
systems, such as SELinux.
- **StorageOpt**: Storage driver options per container. Options can be passed in the form
`{"size":"120G"}`
- **LogConfig** - Log configuration for the container, specified as a JSON object in the form
`{ "Type": "<driver_name>", "Config": {"key1": "val1"}}`.
Available types: `json-file`, `syslog`, `journald`, `gelf`, `fluentd`, `awslogs`, `splunk`, `etwlogs`, `none`.
@ -568,6 +571,7 @@ Return low-level information on the container `id`
"Type": "json-file"
},
"SecurityOpt": null,
"StorageOpt": null,
"VolumesFrom": null,
"Ulimits": [{}],
"VolumeDriver": "",

View file

@ -81,6 +81,7 @@ Creates a new container.
--security-opt=[] Security options
--stop-signal="SIGTERM" Signal to stop a container
--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`.
--storage-opt=[] Set storage driver options per container
-t, --tty Allocate a pseudo-TTY
-u, --user="" Username or UID
--userns="" Container user namespace
@ -145,6 +146,13 @@ then be used from the subsequent container:
drwx--S--- 2 1000 staff 460 Dec 5 00:51 .ssh
drwxr-xr-x 32 1000 staff 1140 Dec 5 04:01 docker
Set storage driver options per container.
$ docker create -it --storage-opt size=120G fedora /bin/bash
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.
### Specify isolation technology for container (--isolation)
This option is useful in situations where you are running Docker containers on

View file

@ -83,6 +83,7 @@ parent = "smn_cli"
--security-opt=[] Security Options
--sig-proxy=true Proxy received signals to the process
--stop-signal="SIGTERM" Signal to stop a container
--storage-opt=[] Set storage driver options per container
-t, --tty Allocate a pseudo-TTY
-u, --user="" Username or UID (format: <name|uid>[:<group|gid>])
--userns="" Container user namespace
@ -167,6 +168,13 @@ flag exists to allow special use-cases, like running Docker within Docker.
The `-w` lets the command being executed inside directory given, here
`/path/to/dir/`. If the path does not exists it is created inside the container.
### Set storage driver options per container
$ docker create -it --storage-opt size=120G fedora /bin/bash
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.
### Mount tmpfs (--tmpfs)
$ docker run -d --tmpfs /run:rw,noexec,nosuid,size=65536k my_image

View file

@ -60,6 +60,27 @@ func (s *DockerSuite) TestCreateArgs(c *check.C) {
}
// Make sure we can grow the container's rootfs at creation time.
func (s *DockerSuite) TestCreateGrowRootfs(c *check.C) {
testRequires(c, Devicemapper)
out, _ := dockerCmd(c, "create", "--storage-opt", "size=120G", "busybox")
cleanedContainerID := strings.TrimSpace(out)
inspectOut := inspectField(c, cleanedContainerID, "HostConfig.StorageOpt")
c.Assert(inspectOut, checker.Equals, "[size=120G]")
}
// Make sure we cannot shrink the container's rootfs at creation time.
func (s *DockerSuite) TestCreateShrinkRootfs(c *check.C) {
testRequires(c, Devicemapper)
// Ensure this fails
out, _, err := dockerCmdWithError("create", "--storage-opt", "size=80G", "busybox")
c.Assert(err, check.NotNil, check.Commentf(out))
c.Assert(out, checker.Contains, "Container size cannot be smaller than")
}
// Make sure we can set hostconfig options too
func (s *DockerSuite) TestCreateHostConfig(c *check.C) {
out, _ := dockerCmd(c, "create", "-P", "busybox", "echo")

View file

@ -122,7 +122,7 @@ func (s *DockerExternalGraphdriverSuite) SetUpSuite(c *check.C) {
if err := decReq(r.Body, &req, w); err != nil {
return
}
if err := driver.Create(req.ID, req.Parent, ""); err != nil {
if err := driver.Create(req.ID, req.Parent, "", nil); err != nil {
respond(w, err)
return
}

View file

@ -171,7 +171,7 @@ type Store interface {
Get(ChainID) (Layer, error)
Release(Layer) ([]Metadata, error)
CreateRWLayer(id string, parent ChainID, mountLabel string, initFunc MountInit) (RWLayer, error)
CreateRWLayer(id string, parent ChainID, mountLabel string, initFunc MountInit, storageOpt map[string]string) (RWLayer, error)
GetRWLayer(id string) (RWLayer, error)
GetMountID(id string) (string, error)
ReleaseRWLayer(RWLayer) ([]Metadata, error)

View file

@ -263,7 +263,7 @@ func (ls *layerStore) Register(ts io.Reader, parent ChainID) (Layer, error) {
references: map[Layer]struct{}{},
}
if err = ls.driver.Create(layer.cacheID, pid, ""); err != nil {
if err = ls.driver.Create(layer.cacheID, pid, "", nil); err != nil {
return nil, err
}
@ -414,7 +414,7 @@ func (ls *layerStore) Release(l Layer) ([]Metadata, error) {
return ls.releaseLayer(layer)
}
func (ls *layerStore) CreateRWLayer(name string, parent ChainID, mountLabel string, initFunc MountInit) (RWLayer, error) {
func (ls *layerStore) CreateRWLayer(name string, parent ChainID, mountLabel string, initFunc MountInit, storageOpt map[string]string) (RWLayer, error) {
ls.mountL.Lock()
defer ls.mountL.Unlock()
m, ok := ls.mounts[name]
@ -451,14 +451,14 @@ func (ls *layerStore) CreateRWLayer(name string, parent ChainID, mountLabel stri
}
if initFunc != nil {
pid, err = ls.initMount(m.mountID, pid, mountLabel, initFunc)
pid, err = ls.initMount(m.mountID, pid, mountLabel, initFunc, storageOpt)
if err != nil {
return nil, err
}
m.initID = pid
}
if err = ls.driver.Create(m.mountID, pid, ""); err != nil {
if err = ls.driver.Create(m.mountID, pid, "", storageOpt); err != nil {
return nil, err
}
@ -561,14 +561,14 @@ func (ls *layerStore) saveMount(mount *mountedLayer) error {
return nil
}
func (ls *layerStore) initMount(graphID, parent, mountLabel string, initFunc MountInit) (string, error) {
func (ls *layerStore) initMount(graphID, parent, mountLabel string, initFunc MountInit, storageOpt map[string]string) (string, error) {
// Use "<graph-id>-init" to maintain compatibility with graph drivers
// which are expecting this layer with this special name. If all
// graph drivers can be updated to not rely on knowing about this layer
// then the initID should be randomly generated.
initID := fmt.Sprintf("%s-init", graphID)
if err := ls.driver.Create(initID, parent, mountLabel); err != nil {
if err := ls.driver.Create(initID, parent, mountLabel, storageOpt); err != nil {
return "", err
}
p, err := ls.driver.Get(initID, "")

View file

@ -84,7 +84,7 @@ type layerInit func(root string) error
func createLayer(ls Store, parent ChainID, layerFunc layerInit) (Layer, error) {
containerID := stringid.GenerateRandomID()
mount, err := ls.CreateRWLayer(containerID, parent, "", nil)
mount, err := ls.CreateRWLayer(containerID, parent, "", nil, nil)
if err != nil {
return nil, err
}
@ -279,7 +279,7 @@ func TestMountAndRegister(t *testing.T) {
size, _ := layer.Size()
t.Logf("Layer size: %d", size)
mount2, err := ls.CreateRWLayer("new-test-mount", layer.ChainID(), "", nil)
mount2, err := ls.CreateRWLayer("new-test-mount", layer.ChainID(), "", nil, nil)
if err != nil {
t.Fatal(err)
}
@ -387,7 +387,7 @@ func TestStoreRestore(t *testing.T) {
t.Fatal(err)
}
m, err := ls.CreateRWLayer("some-mount_name", layer3.ChainID(), "", nil)
m, err := ls.CreateRWLayer("some-mount_name", layer3.ChainID(), "", nil, nil)
if err != nil {
t.Fatal(err)
}
@ -421,7 +421,7 @@ func TestStoreRestore(t *testing.T) {
assertLayerEqual(t, layer3b, layer3)
// Create again with same name, should return error
if _, err := ls2.CreateRWLayer("some-mount_name", layer3b.ChainID(), "", nil); err == nil {
if _, err := ls2.CreateRWLayer("some-mount_name", layer3b.ChainID(), "", nil, nil); err == nil {
t.Fatal("Expected error creating mount with same name")
} else if err != ErrMountNameConflict {
t.Fatal(err)

View file

@ -78,7 +78,7 @@ func TestLayerMigration(t *testing.T) {
}
graphID1 := stringid.GenerateRandomID()
if err := graph.Create(graphID1, "", ""); err != nil {
if err := graph.Create(graphID1, "", "", nil); err != nil {
t.Fatal(err)
}
if _, err := graph.ApplyDiff(graphID1, "", archive.Reader(bytes.NewReader(tar1))); err != nil {
@ -123,7 +123,7 @@ func TestLayerMigration(t *testing.T) {
}
graphID2 := stringid.GenerateRandomID()
if err := graph.Create(graphID2, graphID1, ""); err != nil {
if err := graph.Create(graphID2, graphID1, "", nil); err != nil {
t.Fatal(err)
}
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
return nil, err
}
if err := graph.Create(graphID, parentID, ""); err != nil {
if err := graph.Create(graphID, parentID, "", nil); err != nil {
return nil, err
}
if _, err := graph.ApplyDiff(graphID, parentID, archive.Reader(bytes.NewReader(t))); err != nil {
@ -320,14 +320,14 @@ func TestMountMigration(t *testing.T) {
containerID := stringid.GenerateRandomID()
containerInit := fmt.Sprintf("%s-init", containerID)
if err := graph.Create(containerInit, graphID1, ""); err != nil {
if err := graph.Create(containerInit, graphID1, "", nil); err != nil {
t.Fatal(err)
}
if _, err := graph.ApplyDiff(containerInit, graphID1, archive.Reader(bytes.NewReader(initTar))); err != nil {
t.Fatal(err)
}
if err := graph.Create(containerID, containerInit, ""); err != nil {
if err := graph.Create(containerID, containerInit, "", nil); err != nil {
t.Fatal(err)
}
if _, err := graph.ApplyDiff(containerID, containerInit, archive.Reader(bytes.NewReader(mountTar))); err != nil {
@ -382,7 +382,7 @@ func TestMountMigration(t *testing.T) {
assertActivityCount(t, rwLayer1, 1)
if _, err := ls.CreateRWLayer("migration-mount", layer1.ChainID(), "", nil); err == nil {
if _, err := ls.CreateRWLayer("migration-mount", layer1.ChainID(), "", nil, nil); err == nil {
t.Fatal("Expected error creating mount with same name")
} else if err != ErrMountNameConflict {
t.Fatal(err)

View file

@ -32,7 +32,7 @@ func TestMountInit(t *testing.T) {
return initfile.ApplyFile(root)
}
m, err := ls.CreateRWLayer("fun-mount", layer.ChainID(), "", mountInit)
m, err := ls.CreateRWLayer("fun-mount", layer.ChainID(), "", mountInit, nil)
if err != nil {
t.Fatal(err)
}
@ -89,7 +89,7 @@ func TestMountSize(t *testing.T) {
return newTestFile("file-init", contentInit, 0777).ApplyFile(root)
}
m, err := ls.CreateRWLayer("mount-size", layer.ChainID(), "", mountInit)
m, err := ls.CreateRWLayer("mount-size", layer.ChainID(), "", mountInit, nil)
if err != nil {
t.Fatal(err)
}
@ -138,7 +138,7 @@ func TestMountChanges(t *testing.T) {
return initfile.ApplyFile(root)
}
m, err := ls.CreateRWLayer("mount-changes", layer.ChainID(), "", mountInit)
m, err := ls.CreateRWLayer("mount-changes", layer.ChainID(), "", mountInit, nil)
if err != nil {
t.Fatal(err)
}

View file

@ -64,6 +64,7 @@ docker-create - Create a new container
[**--read-only**]
[**--restart**[=*RESTART*]]
[**--security-opt**[=*[]*]]
[**--storage-opt**[=*[]*]]
[**--stop-signal**[=*SIGNAL*]]
[**--shm-size**[=*[]*]]
[**-t**|**--tty**]
@ -325,6 +326,13 @@ unit, `b` is used. Set LIMIT to `-1` to enable unlimited swap.
"seccomp:unconfined" : Turn off seccomp confinement for the container
"seccomp:profile.json : White listed syscalls seccomp Json file to be used as a seccomp filter
**--storage-opt**=[]
Storage driver options per container
$ docker create -it --storage-opt size=120G fedora /bin/bash
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.
**--stop-signal**=*SIGTERM*
Signal to stop a container. Default is SIGTERM.

View file

@ -67,6 +67,7 @@ docker-run - Run a command in a new container
[**--restart**[=*RESTART*]]
[**--rm**]
[**--security-opt**[=*[]*]]
[**--storage-opt**[=*[]*]]
[**--stop-signal**[=*SIGNAL*]]
[**--shm-size**[=*[]*]]
[**--sig-proxy**[=*true*]]
@ -476,6 +477,13 @@ its root filesystem mounted as read only prohibiting any writes.
"apparmor=unconfined" : Turn off apparmor confinement for the container
"apparmor=your-profile" : Set the apparmor confinement profile for the container
**--storage-opt**=[]
Storage driver options per container
$ docker run -it --storage-opt size=120G fedora /bin/bash
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.
**--stop-signal**=*SIGTERM*
Signal to stop a container. Default is SIGTERM.

View file

@ -55,6 +55,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*container.Config, *container.Host
flCapDrop = opts.NewListOpts(nil)
flGroupAdd = opts.NewListOpts(nil)
flSecurityOpt = opts.NewListOpts(nil)
flStorageOpt = opts.NewListOpts(nil)
flLabelsFile = opts.NewListOpts(nil)
flLoggingOpts = opts.NewListOpts(nil)
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
cmd.Var(&flCapDrop, []string{"-cap-drop"}, "Drop Linux capabilities")
cmd.Var(&flGroupAdd, []string{"-group-add"}, "Add additional groups to join")
cmd.Var(&flSecurityOpt, []string{"-security-opt"}, "Security Options")
cmd.Var(&flStorageOpt, []string{"-storage-opt"}, "Set storage driver options per container")
cmd.Var(flUlimits, []string{"-ulimit"}, "Ulimit options")
cmd.Var(&flLoggingOpts, []string{"-log-opt"}, "Log driver options")
@ -337,6 +339,11 @@ func Parse(cmd *flag.FlagSet, args []string) (*container.Config, *container.Host
return nil, nil, nil, cmd, err
}
storageOpts, err := parseStorageOpts(flStorageOpt.GetAll())
if err != nil {
return nil, nil, nil, cmd, err
}
resources := container.Resources{
CgroupParent: *flCgroupParent,
Memory: flMemory,
@ -415,6 +422,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*container.Config, *container.Host
GroupAdd: flGroupAdd.GetAll(),
RestartPolicy: restartPolicy,
SecurityOpt: securityOpts,
StorageOpt: storageOpts,
ReadonlyRootfs: *flReadonlyRootfs,
LogConfig: container.LogConfig{Type: *flLoggingDriver, Config: loggingOpts},
VolumeDriver: *flVolumeDriver,
@ -531,6 +539,20 @@ func parseSecurityOpts(securityOpts []string) ([]string, error) {
return securityOpts, nil
}
// parse storage options per container into a map
func parseStorageOpts(storageOpts []string) (map[string]string, error) {
m := make(map[string]string)
for _, option := range storageOpts {
if strings.Contains(option, "=") {
opt := strings.SplitN(option, "=", 2)
m[opt[0]] = opt[1]
} else {
return nil, fmt.Errorf("Invalid storage option.")
}
}
return m, nil
}
// ParseRestartPolicy returns the parsed policy or an error indicating what is incorrect
func ParseRestartPolicy(policy string) (container.RestartPolicy, error) {
p := container.RestartPolicy{}