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:
commit
e6aa40a017
30 changed files with 228 additions and 72 deletions
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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": "",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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, "")
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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{}
|
||||
|
|
Loading…
Reference in a new issue