mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Merge pull request #21223 from cpuguy83/add_nocp_to_vols
Add explicit flags for volume cp/no-cp
This commit is contained in:
commit
de9ff4bdc0
14 changed files with 123 additions and 28 deletions
|
@ -552,6 +552,7 @@ func (container *Container) AddMountPointWithVolume(destination string, vol volu
|
||||||
Destination: destination,
|
Destination: destination,
|
||||||
RW: rw,
|
RW: rw,
|
||||||
Volume: vol,
|
Volume: vol,
|
||||||
|
CopyData: volume.DefaultCopyMode,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -185,12 +185,8 @@ func (container *Container) CopyImagePathContent(v volume.Volume, destination st
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
defer v.Unmount()
|
||||||
if err := copyExistingContents(rootfs, path); err != nil {
|
return copyExistingContents(rootfs, path)
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return v.Unmount()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ShmResourcePath returns path to shm
|
// ShmResourcePath returns path to shm
|
||||||
|
|
|
@ -63,8 +63,7 @@ func (daemon *Daemon) createContainerPlatformSpecificSettings(container *contain
|
||||||
// this is only called when the container is created.
|
// this is only called when the container is created.
|
||||||
func (daemon *Daemon) populateVolumes(c *container.Container) error {
|
func (daemon *Daemon) populateVolumes(c *container.Container) error {
|
||||||
for _, mnt := range c.MountPoints {
|
for _, mnt := range c.MountPoints {
|
||||||
// skip binds and volumes referenced by other containers (ie, volumes-from)
|
if !mnt.CopyData || mnt.Volume == nil {
|
||||||
if mnt.Driver == "" || mnt.Volume == nil || len(daemon.volumes.Refs(mnt.Volume)) > 1 {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -131,6 +131,7 @@ func (daemon *Daemon) registerMountPoints(container *container.Container, hostCo
|
||||||
bind = setBindModeIfNull(bind)
|
bind = setBindModeIfNull(bind)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if label.RelabelNeeded(bind.Mode) {
|
if label.RelabelNeeded(bind.Mode) {
|
||||||
if err := label.Relabel(bind.Source, container.MountLabel, label.IsShared(bind.Mode)); err != nil {
|
if err := label.Relabel(bind.Source, container.MountLabel, label.IsShared(bind.Mode)); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -126,6 +126,7 @@ This section lists each version from latest to oldest. Each listing includes a
|
||||||
* `POST /containers/create` now takes `PidsLimit` field, if the kernel is >= 4.3 and the pids cgroup is supported.
|
* `POST /containers/create` now takes `PidsLimit` field, if the kernel is >= 4.3 and the pids cgroup is supported.
|
||||||
* `GET /containers/(id or name)/stats` now returns `pids_stats`, if the kernel is >= 4.3 and the pids cgroup is supported.
|
* `GET /containers/(id or name)/stats` now returns `pids_stats`, if the kernel is >= 4.3 and the pids cgroup is supported.
|
||||||
* `POST /containers/create` now allows you to override usernamespaces remapping and use privileged options for the container.
|
* `POST /containers/create` now allows you to override usernamespaces remapping and use privileged options for the container.
|
||||||
|
* `POST /containers/create` now allows specifying `nocopy` for named volumes, which disables automatic copying from the container path to the volume.
|
||||||
* `POST /auth` now returns an `IdentityToken` when supported by a registry.
|
* `POST /auth` now returns an `IdentityToken` when supported by a registry.
|
||||||
* `POST /containers/create` with both `Hostname` and `Domainname` fields specified will result in the container's hostname being set to `Hostname`, rather than `Hostname.Domainname`.
|
* `POST /containers/create` with both `Hostname` and `Domainname` fields specified will result in the container's hostname being set to `Hostname`, rather than `Hostname.Domainname`.
|
||||||
|
|
||||||
|
|
|
@ -90,10 +90,10 @@ Creates a new container.
|
||||||
--uts="" UTS namespace to use
|
--uts="" UTS namespace to use
|
||||||
-v, --volume=[host-src:]container-dest[:<options>]
|
-v, --volume=[host-src:]container-dest[:<options>]
|
||||||
Bind mount a volume. The comma-delimited
|
Bind mount a volume. The comma-delimited
|
||||||
`options` are [rw|ro], [z|Z], or
|
`options` are [rw|ro], [z|Z],
|
||||||
[[r]shared|[r]slave|[r]private]. The
|
[[r]shared|[r]slave|[r]private], and
|
||||||
'host-src' is an absolute path or a name
|
[nocopy]. The 'host-src' is an absolute path
|
||||||
value.
|
or a name value.
|
||||||
--volume-driver="" Container's volume driver
|
--volume-driver="" Container's volume driver
|
||||||
--volumes-from=[] Mount volumes from the specified container(s)
|
--volumes-from=[] Mount volumes from the specified container(s)
|
||||||
-w, --workdir="" Working directory inside the container
|
-w, --workdir="" Working directory inside the container
|
||||||
|
|
|
@ -92,10 +92,10 @@ parent = "smn_cli"
|
||||||
--uts="" UTS namespace to use
|
--uts="" UTS namespace to use
|
||||||
-v, --volume=[host-src:]container-dest[:<options>]
|
-v, --volume=[host-src:]container-dest[:<options>]
|
||||||
Bind mount a volume. The comma-delimited
|
Bind mount a volume. The comma-delimited
|
||||||
`options` are [rw|ro], [z|Z], or
|
`options` are [rw|ro], [z|Z],
|
||||||
[[r]shared|[r]slave|[r]private]. The
|
[[r]shared|[r]slave|[r]private], and
|
||||||
'host-src' is an absolute path or a name
|
[nocopy]. The 'host-src' is an absolute path
|
||||||
value.
|
or a name value.
|
||||||
--volume-driver="" Container's volume driver
|
--volume-driver="" Container's volume driver
|
||||||
--volumes-from=[] Mount volumes from the specified container(s)
|
--volumes-from=[] Mount volumes from the specified container(s)
|
||||||
-w, --workdir="" Working directory inside the container
|
-w, --workdir="" Working directory inside the container
|
||||||
|
|
|
@ -1400,13 +1400,18 @@ The example below mounts an empty tmpfs into the container with the `rw`,
|
||||||
### VOLUME (shared filesystems)
|
### VOLUME (shared filesystems)
|
||||||
|
|
||||||
-v, --volume=[host-src:]container-dest[:<options>]: Bind mount a volume.
|
-v, --volume=[host-src:]container-dest[:<options>]: Bind mount a volume.
|
||||||
The comma-delimited `options` are [rw|ro], [z|Z], or
|
The comma-delimited `options` are [rw|ro], [z|Z],
|
||||||
[[r]shared|[r]slave|[r]private]. The 'host-src' is an absolute path or a
|
[[r]shared|[r]slave|[r]private], and [nocopy].
|
||||||
name value.
|
The 'host-src' is an absolute path or a name value.
|
||||||
|
|
||||||
If neither 'rw' or 'ro' is specified then the volume is mounted in
|
If neither 'rw' or 'ro' is specified then the volume is mounted in
|
||||||
read-write mode.
|
read-write mode.
|
||||||
|
|
||||||
|
The `nocopy` modes is used to disable automatic copying requested volume
|
||||||
|
path in the container to the volume storage location.
|
||||||
|
For named volumes, `copy` is the default mode. Copy modes are not supported
|
||||||
|
for bind-mounted volumes.
|
||||||
|
|
||||||
--volumes-from="": Mount all volumes from the given container(s)
|
--volumes-from="": Mount all volumes from the given container(s)
|
||||||
|
|
||||||
> **Note**:
|
> **Note**:
|
||||||
|
|
|
@ -4249,6 +4249,44 @@ func (s *DockerSuite) TestRunVolumeWithOneCharacter(c *check.C) {
|
||||||
testRequires(c, DaemonIsLinux)
|
testRequires(c, DaemonIsLinux)
|
||||||
|
|
||||||
out, _ := dockerCmd(c, "run", "-v", "/tmp/q:/foo", "busybox", "sh", "-c", "find /foo")
|
out, _ := dockerCmd(c, "run", "-v", "/tmp/q:/foo", "busybox", "sh", "-c", "find /foo")
|
||||||
fmt.Printf("OUTPUT: %+v", out)
|
|
||||||
c.Assert(strings.TrimSpace(out), checker.Equals, "/foo")
|
c.Assert(strings.TrimSpace(out), checker.Equals, "/foo")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *DockerSuite) TestRunVolumeCopyFlag(c *check.C) {
|
||||||
|
testRequires(c, DaemonIsLinux) // Windows does not support copying data from image to the volume
|
||||||
|
_, err := buildImage("volumecopy",
|
||||||
|
`FROM busybox
|
||||||
|
RUN mkdir /foo && echo hello > /foo/bar
|
||||||
|
CMD cat /foo/bar`,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
|
||||||
|
dockerCmd(c, "volume", "create", "--name=test")
|
||||||
|
|
||||||
|
// test with the nocopy flag
|
||||||
|
out, _, err := dockerCmdWithError("run", "-v", "test:/foo:nocopy", "volumecopy")
|
||||||
|
c.Assert(err, checker.NotNil, check.Commentf(out))
|
||||||
|
// test default behavior which is to copy for non-binds
|
||||||
|
out, _ = dockerCmd(c, "run", "-v", "test:/foo", "volumecopy")
|
||||||
|
c.Assert(strings.TrimSpace(out), checker.Equals, "hello")
|
||||||
|
// error out when the volume is already populated
|
||||||
|
out, _, err = dockerCmdWithError("run", "-v", "test:/foo:copy", "volumecopy")
|
||||||
|
c.Assert(err, checker.NotNil, check.Commentf(out))
|
||||||
|
// do not error out when copy isn't explicitly set even though it's already populated
|
||||||
|
out, _ = dockerCmd(c, "run", "-v", "test:/foo", "volumecopy")
|
||||||
|
c.Assert(strings.TrimSpace(out), checker.Equals, "hello")
|
||||||
|
|
||||||
|
// do not allow copy modes on volumes-from
|
||||||
|
dockerCmd(c, "run", "--name=test", "-v", "/foo", "busybox", "true")
|
||||||
|
out, _, err = dockerCmdWithError("run", "--volumes-from=test:copy", "busybox", "true")
|
||||||
|
c.Assert(err, checker.NotNil, check.Commentf(out))
|
||||||
|
out, _, err = dockerCmdWithError("run", "--volumes-from=test:nocopy", "busybox", "true")
|
||||||
|
c.Assert(err, checker.NotNil, check.Commentf(out))
|
||||||
|
|
||||||
|
// do not allow copy modes on binds
|
||||||
|
out, _, err = dockerCmdWithError("run", "-v", "/foo:/bar:copy", "busybox", "true")
|
||||||
|
c.Assert(err, checker.NotNil, check.Commentf(out))
|
||||||
|
out, _, err = dockerCmdWithError("run", "-v", "/foo:/bar:nocopy", "busybox", "true")
|
||||||
|
c.Assert(err, checker.NotNil, check.Commentf(out))
|
||||||
|
}
|
||||||
|
|
|
@ -434,6 +434,10 @@ change propagation properties of source mount. Say `/` is source mount for
|
||||||
> is `slave`, you may not be able to use the `shared` or `rshared` propagation on
|
> is `slave`, you may not be able to use the `shared` or `rshared` propagation on
|
||||||
> a volume.
|
> a volume.
|
||||||
|
|
||||||
|
|
||||||
|
To disable automatic copying of data from the container path to the volume, use
|
||||||
|
the `nocopy` flag. The `nocopy` flag can be set on bind mounts and named volumes.
|
||||||
|
|
||||||
**--volume-driver**=""
|
**--volume-driver**=""
|
||||||
Container's volume driver. This driver creates volumes specified either from
|
Container's volume driver. This driver creates volumes specified either from
|
||||||
a Dockerfile's `VOLUME` instruction or from the `docker run -v` flag.
|
a Dockerfile's `VOLUME` instruction or from the `docker run -v` flag.
|
||||||
|
|
|
@ -531,6 +531,7 @@ any options, the systems uses the following options:
|
||||||
* [rw|ro]
|
* [rw|ro]
|
||||||
* [z|Z]
|
* [z|Z]
|
||||||
* [`[r]shared`|`[r]slave`|`[r]private`]
|
* [`[r]shared`|`[r]slave`|`[r]private`]
|
||||||
|
* [nocopy]
|
||||||
|
|
||||||
The `CONTAINER-DIR` must be an absolute path such as `/src/docs`. The `HOST-DIR`
|
The `CONTAINER-DIR` must be an absolute path such as `/src/docs`. The `HOST-DIR`
|
||||||
can be an absolute path or a `name` value. A `name` value must start with an
|
can be an absolute path or a `name` value. A `name` value must start with an
|
||||||
|
@ -603,6 +604,9 @@ change propagation properties of source mount. Say `/` is source mount for
|
||||||
> is `slave`, you may not be able to use the `shared` or `rshared` propagation on
|
> is `slave`, you may not be able to use the `shared` or `rshared` propagation on
|
||||||
> a volume.
|
> a volume.
|
||||||
|
|
||||||
|
To disable automatic copying of data from the container path to the volume, use
|
||||||
|
the `nocopy` flag. The `nocopy` flag can be set on bind mounts and named volumes.
|
||||||
|
|
||||||
**--volume-driver**=""
|
**--volume-driver**=""
|
||||||
Container's volume driver. This driver creates volumes specified either from
|
Container's volume driver. This driver creates volumes specified either from
|
||||||
a Dockerfile's `VOLUME` instruction or from the `docker run -v` flag.
|
a Dockerfile's `VOLUME` instruction or from the `docker run -v` flag.
|
||||||
|
|
|
@ -60,6 +60,11 @@ type MountPoint struct {
|
||||||
// Note Propagation is not used on Windows
|
// Note Propagation is not used on Windows
|
||||||
Propagation string // Mount propagation string
|
Propagation string // Mount propagation string
|
||||||
Named bool // specifies if the mountpoint was specified by name
|
Named bool // specifies if the mountpoint was specified by name
|
||||||
|
|
||||||
|
// Specifies if data should be copied from the container before the first mount
|
||||||
|
// Use a pointer here so we can tell if the user set this value explicitly
|
||||||
|
// This allows us to error out when the user explicitly enabled copy but we can't copy due to the volume being populated
|
||||||
|
CopyData bool `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup sets up a mount point by either mounting the volume if it is
|
// Setup sets up a mount point by either mounting the volume if it is
|
||||||
|
@ -115,6 +120,10 @@ func ParseVolumesFrom(spec string) (string, string, error) {
|
||||||
if HasPropagation(mode) {
|
if HasPropagation(mode) {
|
||||||
return "", "", errInvalidMode(mode)
|
return "", "", errInvalidMode(mode)
|
||||||
}
|
}
|
||||||
|
// Do not allow copy modes on volumes-from
|
||||||
|
if _, isSet := getCopyMode(mode); isSet {
|
||||||
|
return "", "", errInvalidMode(mode)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return id, mode, nil
|
return id, mode, nil
|
||||||
}
|
}
|
||||||
|
|
28
volume/volume_copy.go
Normal file
28
volume/volume_copy.go
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
package volume
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
const (
|
||||||
|
// DefaultCopyMode is the copy mode used by default for normal/named volumes
|
||||||
|
DefaultCopyMode = true
|
||||||
|
)
|
||||||
|
|
||||||
|
// {<copy mode>=isEnabled}
|
||||||
|
var copyModes = map[string]bool{
|
||||||
|
"nocopy": false,
|
||||||
|
}
|
||||||
|
|
||||||
|
func copyModeExists(mode string) bool {
|
||||||
|
_, exists := copyModes[mode]
|
||||||
|
return exists
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCopyMode gets the copy mode from the mode string for mounts
|
||||||
|
func getCopyMode(mode string) (bool, bool) {
|
||||||
|
for _, o := range strings.Split(mode, ",") {
|
||||||
|
if isEnabled, exists := copyModes[o]; exists {
|
||||||
|
return isEnabled, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return DefaultCopyMode, false
|
||||||
|
}
|
|
@ -110,6 +110,13 @@ func ParseMountSpec(spec, volumeDriver string) (*MountPoint, error) {
|
||||||
mp.Source = filepath.Clean(source)
|
mp.Source = filepath.Clean(source)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
copyData, isSet := getCopyMode(mp.Mode)
|
||||||
|
// do not allow copy modes on binds
|
||||||
|
if len(name) == 0 && isSet {
|
||||||
|
return nil, errInvalidMode(mp.Mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
mp.CopyData = copyData
|
||||||
mp.Name = name
|
mp.Name = name
|
||||||
|
|
||||||
return mp, nil
|
return mp, nil
|
||||||
|
@ -137,23 +144,25 @@ func ValidMountMode(mode string) bool {
|
||||||
rwModeCount := 0
|
rwModeCount := 0
|
||||||
labelModeCount := 0
|
labelModeCount := 0
|
||||||
propagationModeCount := 0
|
propagationModeCount := 0
|
||||||
|
copyModeCount := 0
|
||||||
|
|
||||||
for _, o := range strings.Split(mode, ",") {
|
for _, o := range strings.Split(mode, ",") {
|
||||||
if rwModes[o] {
|
switch {
|
||||||
|
case rwModes[o]:
|
||||||
rwModeCount++
|
rwModeCount++
|
||||||
continue
|
case labelModes[o]:
|
||||||
} else if labelModes[o] {
|
|
||||||
labelModeCount++
|
labelModeCount++
|
||||||
continue
|
case propagationModes[o]:
|
||||||
} else if propagationModes[o] {
|
|
||||||
propagationModeCount++
|
propagationModeCount++
|
||||||
continue
|
case copyModeExists(o):
|
||||||
}
|
copyModeCount++
|
||||||
|
default:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Only one string for each mode is allowed.
|
// Only one string for each mode is allowed.
|
||||||
if rwModeCount > 1 || labelModeCount > 1 || propagationModeCount > 1 {
|
if rwModeCount > 1 || labelModeCount > 1 || propagationModeCount > 1 || copyModeCount > 1 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
|
Loading…
Add table
Reference in a new issue