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,
|
||||
RW: rw,
|
||||
Volume: vol,
|
||||
CopyData: volume.DefaultCopyMode,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -185,12 +185,8 @@ func (container *Container) CopyImagePathContent(v volume.Volume, destination st
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := copyExistingContents(rootfs, path); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return v.Unmount()
|
||||
defer v.Unmount()
|
||||
return copyExistingContents(rootfs, path)
|
||||
}
|
||||
|
||||
// ShmResourcePath returns path to shm
|
||||
|
|
|
@ -63,8 +63,7 @@ func (daemon *Daemon) createContainerPlatformSpecificSettings(container *contain
|
|||
// this is only called when the container is created.
|
||||
func (daemon *Daemon) populateVolumes(c *container.Container) error {
|
||||
for _, mnt := range c.MountPoints {
|
||||
// skip binds and volumes referenced by other containers (ie, volumes-from)
|
||||
if mnt.Driver == "" || mnt.Volume == nil || len(daemon.volumes.Refs(mnt.Volume)) > 1 {
|
||||
if !mnt.CopyData || mnt.Volume == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
|
@ -131,6 +131,7 @@ func (daemon *Daemon) registerMountPoints(container *container.Container, hostCo
|
|||
bind = setBindModeIfNull(bind)
|
||||
}
|
||||
}
|
||||
|
||||
if label.RelabelNeeded(bind.Mode) {
|
||||
if err := label.Relabel(bind.Source, container.MountLabel, label.IsShared(bind.Mode)); err != nil {
|
||||
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.
|
||||
* `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 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 /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
|
||||
-v, --volume=[host-src:]container-dest[:<options>]
|
||||
Bind mount a volume. The comma-delimited
|
||||
`options` are [rw|ro], [z|Z], or
|
||||
[[r]shared|[r]slave|[r]private]. The
|
||||
'host-src' is an absolute path or a name
|
||||
value.
|
||||
`options` are [rw|ro], [z|Z],
|
||||
[[r]shared|[r]slave|[r]private], and
|
||||
[nocopy]. The 'host-src' is an absolute path
|
||||
or a name value.
|
||||
--volume-driver="" Container's volume driver
|
||||
--volumes-from=[] Mount volumes from the specified container(s)
|
||||
-w, --workdir="" Working directory inside the container
|
||||
|
|
|
@ -92,10 +92,10 @@ parent = "smn_cli"
|
|||
--uts="" UTS namespace to use
|
||||
-v, --volume=[host-src:]container-dest[:<options>]
|
||||
Bind mount a volume. The comma-delimited
|
||||
`options` are [rw|ro], [z|Z], or
|
||||
[[r]shared|[r]slave|[r]private]. The
|
||||
'host-src' is an absolute path or a name
|
||||
value.
|
||||
`options` are [rw|ro], [z|Z],
|
||||
[[r]shared|[r]slave|[r]private], and
|
||||
[nocopy]. The 'host-src' is an absolute path
|
||||
or a name value.
|
||||
--volume-driver="" Container's volume driver
|
||||
--volumes-from=[] Mount volumes from the specified container(s)
|
||||
-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)
|
||||
|
||||
-v, --volume=[host-src:]container-dest[:<options>]: Bind mount a volume.
|
||||
The comma-delimited `options` are [rw|ro], [z|Z], or
|
||||
[[r]shared|[r]slave|[r]private]. The 'host-src' is an absolute path or a
|
||||
name value.
|
||||
The comma-delimited `options` are [rw|ro], [z|Z],
|
||||
[[r]shared|[r]slave|[r]private], and [nocopy].
|
||||
The 'host-src' is an absolute path or a name value.
|
||||
|
||||
If neither 'rw' or 'ro' is specified then the volume is mounted in
|
||||
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)
|
||||
|
||||
> **Note**:
|
||||
|
|
|
@ -4249,6 +4249,44 @@ func (s *DockerSuite) TestRunVolumeWithOneCharacter(c *check.C) {
|
|||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
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")
|
||||
}
|
||||
|
||||
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
|
||||
> 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**=""
|
||||
Container's volume driver. This driver creates volumes specified either from
|
||||
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]
|
||||
* [z|Z]
|
||||
* [`[r]shared`|`[r]slave`|`[r]private`]
|
||||
* [nocopy]
|
||||
|
||||
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
|
||||
|
@ -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
|
||||
> 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**=""
|
||||
Container's volume driver. This driver creates volumes specified either from
|
||||
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
|
||||
Propagation string // Mount propagation string
|
||||
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
|
||||
|
@ -115,6 +120,10 @@ func ParseVolumesFrom(spec string) (string, string, error) {
|
|||
if HasPropagation(mode) {
|
||||
return "", "", errInvalidMode(mode)
|
||||
}
|
||||
// Do not allow copy modes on volumes-from
|
||||
if _, isSet := getCopyMode(mode); isSet {
|
||||
return "", "", errInvalidMode(mode)
|
||||
}
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
return mp, nil
|
||||
|
@ -137,23 +144,25 @@ func ValidMountMode(mode string) bool {
|
|||
rwModeCount := 0
|
||||
labelModeCount := 0
|
||||
propagationModeCount := 0
|
||||
copyModeCount := 0
|
||||
|
||||
for _, o := range strings.Split(mode, ",") {
|
||||
if rwModes[o] {
|
||||
switch {
|
||||
case rwModes[o]:
|
||||
rwModeCount++
|
||||
continue
|
||||
} else if labelModes[o] {
|
||||
case labelModes[o]:
|
||||
labelModeCount++
|
||||
continue
|
||||
} else if propagationModes[o] {
|
||||
case propagationModes[o]:
|
||||
propagationModeCount++
|
||||
continue
|
||||
}
|
||||
case copyModeExists(o):
|
||||
copyModeCount++
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// 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 true
|
||||
|
|
Loading…
Add table
Reference in a new issue