Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
| ... | ... |
@@ -514,14 +514,14 @@ func (container *Container) AddMountPointWithVolume(destination string, vol volu |
| 514 | 514 |
} |
| 515 | 515 |
|
| 516 | 516 |
// UnmountVolumes unmounts all volumes |
| 517 |
-func (container *Container) UnmountVolumes(volumeEventLog func(name string, action events.Action, attributes map[string]string)) error {
|
|
| 517 |
+func (container *Container) UnmountVolumes(ctx context.Context, volumeEventLog func(name string, action events.Action, attributes map[string]string)) error {
|
|
| 518 | 518 |
var errs []string |
| 519 | 519 |
for _, volumeMount := range container.MountPoints {
|
| 520 | 520 |
if volumeMount.Volume == nil {
|
| 521 | 521 |
continue |
| 522 | 522 |
} |
| 523 | 523 |
|
| 524 |
- if err := volumeMount.Cleanup(); err != nil {
|
|
| 524 |
+ if err := volumeMount.Cleanup(ctx); err != nil {
|
|
| 525 | 525 |
errs = append(errs, err.Error()) |
| 526 | 526 |
continue |
| 527 | 527 |
} |
| ... | ... |
@@ -371,7 +371,7 @@ func (container *Container) DetachAndUnmount(volumeEventLog func(name string, ac |
| 371 | 371 |
Warn("Unable to unmount")
|
| 372 | 372 |
} |
| 373 | 373 |
} |
| 374 |
- return container.UnmountVolumes(volumeEventLog) |
|
| 374 |
+ return container.UnmountVolumes(ctx, volumeEventLog) |
|
| 375 | 375 |
} |
| 376 | 376 |
|
| 377 | 377 |
// ignoreUnsupportedXAttrs ignores errors when extended attributes |
| ... | ... |
@@ -1,6 +1,7 @@ |
| 1 | 1 |
package container // import "github.com/docker/docker/container" |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "context" |
|
| 4 | 5 |
"fmt" |
| 5 | 6 |
"os" |
| 6 | 7 |
"path/filepath" |
| ... | ... |
@@ -128,7 +129,7 @@ func (container *Container) ConfigMounts() []Mount {
|
| 128 | 128 |
// On Windows it only delegates to `UnmountVolumes` since there is nothing to |
| 129 | 129 |
// force unmount. |
| 130 | 130 |
func (container *Container) DetachAndUnmount(volumeEventLog func(name string, action events.Action, attributes map[string]string)) error {
|
| 131 |
- return container.UnmountVolumes(volumeEventLog) |
|
| 131 |
+ return container.UnmountVolumes(context.TODO(), volumeEventLog) |
|
| 132 | 132 |
} |
| 133 | 133 |
|
| 134 | 134 |
// TmpfsMounts returns the list of tmpfs mounts |
| ... | ... |
@@ -17,6 +17,7 @@ import ( |
| 17 | 17 |
|
| 18 | 18 |
"github.com/docker/docker/api/types" |
| 19 | 19 |
"github.com/docker/docker/container" |
| 20 |
+ "github.com/docker/docker/internal/compatcontext" |
|
| 20 | 21 |
"github.com/docker/docker/internal/mounttree" |
| 21 | 22 |
"github.com/docker/docker/internal/unshare" |
| 22 | 23 |
"github.com/docker/docker/pkg/fileutils" |
| ... | ... |
@@ -54,6 +55,8 @@ type containerFSView struct {
|
| 54 | 54 |
|
| 55 | 55 |
// openContainerFS opens a new view of the container's filesystem. |
| 56 | 56 |
func (daemon *Daemon) openContainerFS(container *container.Container) (_ *containerFSView, err error) {
|
| 57 |
+ ctx := context.TODO() |
|
| 58 |
+ |
|
| 57 | 59 |
if err := daemon.Mount(container); err != nil {
|
| 58 | 60 |
return nil, err |
| 59 | 61 |
} |
| ... | ... |
@@ -63,14 +66,15 @@ func (daemon *Daemon) openContainerFS(container *container.Container) (_ *contai |
| 63 | 63 |
} |
| 64 | 64 |
}() |
| 65 | 65 |
|
| 66 |
- mounts, cleanup, err := daemon.setupMounts(container) |
|
| 66 |
+ mounts, cleanup, err := daemon.setupMounts(ctx, container) |
|
| 67 | 67 |
if err != nil {
|
| 68 | 68 |
return nil, err |
| 69 | 69 |
} |
| 70 | 70 |
defer func() {
|
| 71 |
- cleanup() |
|
| 71 |
+ ctx := compatcontext.WithoutCancel(ctx) |
|
| 72 |
+ cleanup(ctx) |
|
| 72 | 73 |
if err != nil {
|
| 73 |
- _ = container.UnmountVolumes(daemon.LogVolumeEvent) |
|
| 74 |
+ _ = container.UnmountVolumes(ctx, daemon.LogVolumeEvent) |
|
| 74 | 75 |
} |
| 75 | 76 |
}() |
| 76 | 77 |
|
| ... | ... |
@@ -208,7 +212,7 @@ func (vw *containerFSView) Close() error {
|
| 208 | 208 |
runtime.SetFinalizer(vw, nil) |
| 209 | 209 |
close(vw.todo) |
| 210 | 210 |
err := multierror.Append(nil, <-vw.done) |
| 211 |
- err = multierror.Append(err, vw.ctr.UnmountVolumes(vw.d.LogVolumeEvent)) |
|
| 211 |
+ err = multierror.Append(err, vw.ctr.UnmountVolumes(context.TODO(), vw.d.LogVolumeEvent)) |
|
| 212 | 212 |
err = multierror.Append(err, vw.d.Unmount(vw.ctr)) |
| 213 | 213 |
return err.ErrorOrNil() |
| 214 | 214 |
} |
| ... | ... |
@@ -222,7 +222,7 @@ func (daemon *Daemon) create(ctx context.Context, daemonCfg *config.Config, opts |
| 222 | 222 |
return nil, err |
| 223 | 223 |
} |
| 224 | 224 |
|
| 225 |
- if err := daemon.createContainerOSSpecificSettings(ctr, opts.params.Config, opts.params.HostConfig); err != nil {
|
|
| 225 |
+ if err := daemon.createContainerOSSpecificSettings(ctx, ctr, opts.params.Config, opts.params.HostConfig); err != nil {
|
|
| 226 | 226 |
return nil, err |
| 227 | 227 |
} |
| 228 | 228 |
|
| ... | ... |
@@ -13,6 +13,7 @@ import ( |
| 13 | 13 |
mounttypes "github.com/docker/docker/api/types/mount" |
| 14 | 14 |
"github.com/docker/docker/container" |
| 15 | 15 |
"github.com/docker/docker/errdefs" |
| 16 |
+ "github.com/docker/docker/internal/compatcontext" |
|
| 16 | 17 |
"github.com/docker/docker/oci" |
| 17 | 18 |
volumemounts "github.com/docker/docker/volume/mounts" |
| 18 | 19 |
volumeopts "github.com/docker/docker/volume/service/opts" |
| ... | ... |
@@ -21,7 +22,7 @@ import ( |
| 21 | 21 |
) |
| 22 | 22 |
|
| 23 | 23 |
// createContainerOSSpecificSettings performs host-OS specific container create functionality |
| 24 |
-func (daemon *Daemon) createContainerOSSpecificSettings(container *container.Container, config *containertypes.Config, hostConfig *containertypes.HostConfig) error {
|
|
| 24 |
+func (daemon *Daemon) createContainerOSSpecificSettings(ctx context.Context, container *container.Container, config *containertypes.Config, hostConfig *containertypes.HostConfig) error {
|
|
| 25 | 25 |
if err := daemon.Mount(container); err != nil {
|
| 26 | 26 |
return err |
| 27 | 27 |
} |
| ... | ... |
@@ -48,7 +49,7 @@ func (daemon *Daemon) createContainerOSSpecificSettings(container *container.Con |
| 48 | 48 |
// Skip volumes for which we already have something mounted on that |
| 49 | 49 |
// destination because of a --volume-from. |
| 50 | 50 |
if container.HasMountFor(destination) {
|
| 51 |
- log.G(context.TODO()).WithField("container", container.ID).WithField("destination", spec).Debug("mountpoint already exists, skipping anonymous volume")
|
|
| 51 |
+ log.G(ctx).WithField("container", container.ID).WithField("destination", spec).Debug("mountpoint already exists, skipping anonymous volume")
|
|
| 52 | 52 |
// Not an error, this could easily have come from the image config. |
| 53 | 53 |
continue |
| 54 | 54 |
} |
| ... | ... |
@@ -73,12 +74,12 @@ func (daemon *Daemon) createContainerOSSpecificSettings(container *container.Con |
| 73 | 73 |
|
| 74 | 74 |
container.AddMountPointWithVolume(destination, &volumeWrapper{v: v, s: daemon.volumes}, true)
|
| 75 | 75 |
} |
| 76 |
- return daemon.populateVolumes(container) |
|
| 76 |
+ return daemon.populateVolumes(ctx, container) |
|
| 77 | 77 |
} |
| 78 | 78 |
|
| 79 | 79 |
// populateVolumes copies data from the container's rootfs into the volume for non-binds. |
| 80 | 80 |
// this is only called when the container is created. |
| 81 |
-func (daemon *Daemon) populateVolumes(c *container.Container) error {
|
|
| 81 |
+func (daemon *Daemon) populateVolumes(ctx context.Context, c *container.Container) error {
|
|
| 82 | 82 |
for _, mnt := range c.MountPoints {
|
| 83 | 83 |
if mnt.Volume == nil {
|
| 84 | 84 |
continue |
| ... | ... |
@@ -88,14 +89,14 @@ func (daemon *Daemon) populateVolumes(c *container.Container) error {
|
| 88 | 88 |
continue |
| 89 | 89 |
} |
| 90 | 90 |
|
| 91 |
- if err := daemon.populateVolume(c, mnt); err != nil {
|
|
| 91 |
+ if err := daemon.populateVolume(ctx, c, mnt); err != nil {
|
|
| 92 | 92 |
return err |
| 93 | 93 |
} |
| 94 | 94 |
} |
| 95 | 95 |
return nil |
| 96 | 96 |
} |
| 97 | 97 |
|
| 98 |
-func (daemon *Daemon) populateVolume(c *container.Container, mnt *volumemounts.MountPoint) error {
|
|
| 98 |
+func (daemon *Daemon) populateVolume(ctx context.Context, c *container.Container, mnt *volumemounts.MountPoint) error {
|
|
| 99 | 99 |
ctrDestPath, err := c.GetResourcePath(mnt.Destination) |
| 100 | 100 |
if err != nil {
|
| 101 | 101 |
return err |
| ... | ... |
@@ -108,18 +109,18 @@ func (daemon *Daemon) populateVolume(c *container.Container, mnt *volumemounts.M |
| 108 | 108 |
return err |
| 109 | 109 |
} |
| 110 | 110 |
|
| 111 |
- volumePath, cleanup, err := mnt.Setup(c.MountLabel, daemon.idMapping.RootPair(), nil) |
|
| 111 |
+ volumePath, cleanup, err := mnt.Setup(ctx, c.MountLabel, daemon.idMapping.RootPair(), nil) |
|
| 112 | 112 |
if err != nil {
|
| 113 | 113 |
if errdefs.IsNotFound(err) {
|
| 114 | 114 |
return nil |
| 115 | 115 |
} |
| 116 |
- log.G(context.TODO()).WithError(err).Debugf("can't copy data from %s:%s, to %s", c.ID, mnt.Destination, volumePath)
|
|
| 116 |
+ log.G(ctx).WithError(err).Debugf("can't copy data from %s:%s, to %s", c.ID, mnt.Destination, volumePath)
|
|
| 117 | 117 |
return errors.Wrapf(err, "failed to populate volume") |
| 118 | 118 |
} |
| 119 |
- defer mnt.Cleanup() |
|
| 120 |
- defer cleanup() |
|
| 119 |
+ defer mnt.Cleanup(compatcontext.WithoutCancel(ctx)) |
|
| 120 |
+ defer cleanup(compatcontext.WithoutCancel(ctx)) |
|
| 121 | 121 |
|
| 122 |
- log.G(context.TODO()).Debugf("copying image data from %s:%s, to %s", c.ID, mnt.Destination, volumePath)
|
|
| 122 |
+ log.G(ctx).Debugf("copying image data from %s:%s, to %s", c.ID, mnt.Destination, volumePath)
|
|
| 123 | 123 |
if err := c.CopyImagePathContent(volumePath, ctrDestPath); err != nil {
|
| 124 | 124 |
return err |
| 125 | 125 |
} |
| ... | ... |
@@ -11,7 +11,7 @@ import ( |
| 11 | 11 |
) |
| 12 | 12 |
|
| 13 | 13 |
// createContainerOSSpecificSettings performs host-OS specific container create functionality |
| 14 |
-func (daemon *Daemon) createContainerOSSpecificSettings(container *container.Container, config *containertypes.Config, hostConfig *containertypes.HostConfig) error {
|
|
| 14 |
+func (daemon *Daemon) createContainerOSSpecificSettings(ctx context.Context, container *container.Container, config *containertypes.Config, hostConfig *containertypes.HostConfig) error {
|
|
| 15 | 15 |
if containertypes.Isolation.IsDefault(hostConfig.Isolation) {
|
| 16 | 16 |
// Make sure the host config has the default daemon isolation if not specified by caller. |
| 17 | 17 |
hostConfig.Isolation = daemon.defaultIsolation |
| ... | ... |
@@ -34,7 +34,7 @@ func (daemon *Daemon) createContainerOSSpecificSettings(container *container.Con |
| 34 | 34 |
|
| 35 | 35 |
// Create the volume in the volume driver. If it doesn't exist, |
| 36 | 36 |
// a new one will be created. |
| 37 |
- v, err := daemon.volumes.Create(context.TODO(), "", volumeDriver, volumeopts.WithCreateReference(container.ID)) |
|
| 37 |
+ v, err := daemon.volumes.Create(ctx, "", volumeDriver, volumeopts.WithCreateReference(container.ID)) |
|
| 38 | 38 |
if err != nil {
|
| 39 | 39 |
return err |
| 40 | 40 |
} |
| ... | ... |
@@ -466,7 +466,7 @@ func (daemon *Daemon) restore(cfg *configStore) error {
|
| 466 | 466 |
ces.ExitCode = 255 |
| 467 | 467 |
} |
| 468 | 468 |
c.SetStopped(&ces) |
| 469 |
- daemon.Cleanup(c) |
|
| 469 |
+ daemon.Cleanup(context.TODO(), c) |
|
| 470 | 470 |
if err := c.CheckpointTo(daemon.containersReplica); err != nil {
|
| 471 | 471 |
baseLogger.WithError(err).Error("failed to update stopped container state")
|
| 472 | 472 |
} |
| ... | ... |
@@ -89,7 +89,7 @@ func (daemon *Daemon) handleContainerExit(c *container.Container, e *libcontaine |
| 89 | 89 |
"exitCode": strconv.Itoa(exitStatus.ExitCode), |
| 90 | 90 |
"execDuration": strconv.Itoa(int(execDuration.Seconds())), |
| 91 | 91 |
} |
| 92 |
- daemon.Cleanup(c) |
|
| 92 |
+ daemon.Cleanup(context.TODO(), c) |
|
| 93 | 93 |
|
| 94 | 94 |
if restart {
|
| 95 | 95 |
c.RestartCount++ |
| ... | ... |
@@ -139,7 +139,7 @@ func (daemon *Daemon) containerStart(ctx context.Context, daemonCfg *configStore |
| 139 | 139 |
} |
| 140 | 140 |
container.Reset(false) |
| 141 | 141 |
|
| 142 |
- daemon.Cleanup(container) |
|
| 142 |
+ daemon.Cleanup(compatcontext.WithoutCancel(ctx), container) |
|
| 143 | 143 |
// if containers AutoRemove flag is set, remove it after clean up |
| 144 | 144 |
if container.HostConfig.AutoRemove {
|
| 145 | 145 |
container.Unlock() |
| ... | ... |
@@ -164,12 +164,12 @@ func (daemon *Daemon) containerStart(ctx context.Context, daemonCfg *configStore |
| 164 | 164 |
return err |
| 165 | 165 |
} |
| 166 | 166 |
|
| 167 |
- m, cleanup, err := daemon.setupMounts(container) |
|
| 167 |
+ m, cleanup, err := daemon.setupMounts(ctx, container) |
|
| 168 | 168 |
if err != nil {
|
| 169 | 169 |
return err |
| 170 | 170 |
} |
| 171 | 171 |
mnts = append(mnts, m...) |
| 172 |
- defer cleanup() |
|
| 172 |
+ defer cleanup(compatcontext.WithoutCancel(ctx)) |
|
| 173 | 173 |
|
| 174 | 174 |
spec, err := daemon.createSpec(ctx, daemonCfg, container, mnts) |
| 175 | 175 |
if err != nil {
|
| ... | ... |
@@ -260,19 +260,19 @@ func (daemon *Daemon) containerStart(ctx context.Context, daemonCfg *configStore |
| 260 | 260 |
|
| 261 | 261 |
// Cleanup releases any network resources allocated to the container along with any rules |
| 262 | 262 |
// around how containers are linked together. It also unmounts the container's root filesystem. |
| 263 |
-func (daemon *Daemon) Cleanup(container *container.Container) {
|
|
| 263 |
+func (daemon *Daemon) Cleanup(ctx context.Context, container *container.Container) {
|
|
| 264 | 264 |
// Microsoft HCS containers get in a bad state if host resources are |
| 265 | 265 |
// released while the container still exists. |
| 266 | 266 |
if ctr, ok := container.C8dContainer(); ok {
|
| 267 | 267 |
if err := ctr.Delete(context.Background()); err != nil {
|
| 268 |
- log.G(context.TODO()).Errorf("%s cleanup: failed to delete container from containerd: %v", container.ID, err)
|
|
| 268 |
+ log.G(ctx).Errorf("%s cleanup: failed to delete container from containerd: %v", container.ID, err)
|
|
| 269 | 269 |
} |
| 270 | 270 |
} |
| 271 | 271 |
|
| 272 | 272 |
daemon.releaseNetwork(container) |
| 273 | 273 |
|
| 274 | 274 |
if err := container.UnmountIpcMount(); err != nil {
|
| 275 |
- log.G(context.TODO()).Warnf("%s cleanup: failed to unmount IPC: %s", container.ID, err)
|
|
| 275 |
+ log.G(ctx).Warnf("%s cleanup: failed to unmount IPC: %s", container.ID, err)
|
|
| 276 | 276 |
} |
| 277 | 277 |
|
| 278 | 278 |
if err := daemon.conditionalUnmountOnCleanup(container); err != nil {
|
| ... | ... |
@@ -284,11 +284,11 @@ func (daemon *Daemon) Cleanup(container *container.Container) {
|
| 284 | 284 |
} |
| 285 | 285 |
|
| 286 | 286 |
if err := container.UnmountSecrets(); err != nil {
|
| 287 |
- log.G(context.TODO()).Warnf("%s cleanup: failed to unmount secrets: %s", container.ID, err)
|
|
| 287 |
+ log.G(ctx).Warnf("%s cleanup: failed to unmount secrets: %s", container.ID, err)
|
|
| 288 | 288 |
} |
| 289 | 289 |
|
| 290 | 290 |
if err := recursiveUnmount(container.Root); err != nil {
|
| 291 |
- log.G(context.TODO()).WithError(err).WithField("container", container.ID).Warn("Error while cleaning up container resource mounts.")
|
|
| 291 |
+ log.G(ctx).WithError(err).WithField("container", container.ID).Warn("Error while cleaning up container resource mounts.")
|
|
| 292 | 292 |
} |
| 293 | 293 |
|
| 294 | 294 |
for _, eConfig := range container.ExecCommands.Commands() {
|
| ... | ... |
@@ -296,8 +296,8 @@ func (daemon *Daemon) Cleanup(container *container.Container) {
|
| 296 | 296 |
} |
| 297 | 297 |
|
| 298 | 298 |
if container.BaseFS != "" {
|
| 299 |
- if err := container.UnmountVolumes(daemon.LogVolumeEvent); err != nil {
|
|
| 300 |
- log.G(context.TODO()).Warnf("%s cleanup: Failed to umount volumes: %v", container.ID, err)
|
|
| 299 |
+ if err := container.UnmountVolumes(ctx, daemon.LogVolumeEvent); err != nil {
|
|
| 300 |
+ log.G(ctx).Warnf("%s cleanup: Failed to umount volumes: %v", container.ID, err)
|
|
| 301 | 301 |
} |
| 302 | 302 |
} |
| 303 | 303 |
|
| ... | ... |
@@ -15,6 +15,7 @@ import ( |
| 15 | 15 |
mounttypes "github.com/docker/docker/api/types/mount" |
| 16 | 16 |
"github.com/docker/docker/container" |
| 17 | 17 |
"github.com/docker/docker/internal/cleanups" |
| 18 |
+ "github.com/docker/docker/internal/compatcontext" |
|
| 18 | 19 |
volumemounts "github.com/docker/docker/volume/mounts" |
| 19 | 20 |
"github.com/pkg/errors" |
| 20 | 21 |
) |
| ... | ... |
@@ -25,7 +26,7 @@ import ( |
| 25 | 25 |
// |
| 26 | 26 |
// The cleanup function should be called as soon as the container has been |
| 27 | 27 |
// started. |
| 28 |
-func (daemon *Daemon) setupMounts(c *container.Container) ([]container.Mount, func() error, error) {
|
|
| 28 |
+func (daemon *Daemon) setupMounts(ctx context.Context, c *container.Container) ([]container.Mount, func(context.Context) error, error) {
|
|
| 29 | 29 |
var mounts []container.Mount |
| 30 | 30 |
// TODO: tmpfs mounts should be part of Mountpoints |
| 31 | 31 |
tmpfsMounts := make(map[string]bool) |
| ... | ... |
@@ -39,8 +40,8 @@ func (daemon *Daemon) setupMounts(c *container.Container) ([]container.Mount, fu |
| 39 | 39 |
|
| 40 | 40 |
cleanups := cleanups.Composite{}
|
| 41 | 41 |
defer func() {
|
| 42 |
- if err := cleanups.Call(); err != nil {
|
|
| 43 |
- log.G(context.TODO()).WithError(err).Warn("failed to cleanup temporary mounts created by MountPoint.Setup")
|
|
| 42 |
+ if err := cleanups.Call(compatcontext.WithoutCancel(ctx)); err != nil {
|
|
| 43 |
+ log.G(ctx).WithError(err).Warn("failed to cleanup temporary mounts created by MountPoint.Setup")
|
|
| 44 | 44 |
} |
| 45 | 45 |
}() |
| 46 | 46 |
|
| ... | ... |
@@ -62,7 +63,7 @@ func (daemon *Daemon) setupMounts(c *container.Container) ([]container.Mount, fu |
| 62 | 62 |
return nil |
| 63 | 63 |
} |
| 64 | 64 |
|
| 65 |
- path, clean, err := m.Setup(c.MountLabel, daemon.idMapping.RootPair(), checkfunc) |
|
| 65 |
+ path, clean, err := m.Setup(ctx, c.MountLabel, daemon.idMapping.RootPair(), checkfunc) |
|
| 66 | 66 |
if err != nil {
|
| 67 | 67 |
return nil, nil, err |
| 68 | 68 |
} |
| ... | ... |
@@ -8,6 +8,7 @@ import ( |
| 8 | 8 |
"github.com/docker/docker/api/types/mount" |
| 9 | 9 |
"github.com/docker/docker/container" |
| 10 | 10 |
"github.com/docker/docker/internal/cleanups" |
| 11 |
+ "github.com/docker/docker/internal/compatcontext" |
|
| 11 | 12 |
"github.com/docker/docker/pkg/idtools" |
| 12 | 13 |
volumemounts "github.com/docker/docker/volume/mounts" |
| 13 | 14 |
) |
| ... | ... |
@@ -23,11 +24,11 @@ import ( |
| 23 | 23 |
// BUGBUG TODO Windows containerd. This would be much better if it returned |
| 24 | 24 |
// an array of runtime spec mounts, not container mounts. Then no need to |
| 25 | 25 |
// do multiple transitions. |
| 26 |
-func (daemon *Daemon) setupMounts(c *container.Container) ([]container.Mount, func() error, error) {
|
|
| 26 |
+func (daemon *Daemon) setupMounts(ctx context.Context, c *container.Container) ([]container.Mount, func(context.Context) error, error) {
|
|
| 27 | 27 |
cleanups := cleanups.Composite{}
|
| 28 | 28 |
defer func() {
|
| 29 |
- if err := cleanups.Call(); err != nil {
|
|
| 30 |
- log.G(context.TODO()).WithError(err).Warn("failed to cleanup temporary mounts created by MountPoint.Setup")
|
|
| 29 |
+ if err := cleanups.Call(compatcontext.WithoutCancel(ctx)); err != nil {
|
|
| 30 |
+ log.G(ctx).WithError(err).Warn("failed to cleanup temporary mounts created by MountPoint.Setup")
|
|
| 31 | 31 |
} |
| 32 | 32 |
}() |
| 33 | 33 |
|
| ... | ... |
@@ -36,7 +37,7 @@ func (daemon *Daemon) setupMounts(c *container.Container) ([]container.Mount, fu |
| 36 | 36 |
if err := daemon.lazyInitializeVolume(c.ID, mount); err != nil {
|
| 37 | 37 |
return nil, nil, err |
| 38 | 38 |
} |
| 39 |
- s, c, err := mount.Setup(c.MountLabel, idtools.Identity{}, nil)
|
|
| 39 |
+ s, c, err := mount.Setup(ctx, c.MountLabel, idtools.Identity{}, nil)
|
|
| 40 | 40 |
if err != nil {
|
| 41 | 41 |
return nil, nil, err |
| 42 | 42 |
} |
| ... | ... |
@@ -1,22 +1,24 @@ |
| 1 | 1 |
package cleanups |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "context" |
|
| 5 |
+ |
|
| 4 | 6 |
"github.com/docker/docker/internal/multierror" |
| 5 | 7 |
) |
| 6 | 8 |
|
| 7 | 9 |
type Composite struct {
|
| 8 |
- cleanups []func() error |
|
| 10 |
+ cleanups []func(context.Context) error |
|
| 9 | 11 |
} |
| 10 | 12 |
|
| 11 | 13 |
// Add adds a cleanup to be called. |
| 12 |
-func (c *Composite) Add(f func() error) {
|
|
| 14 |
+func (c *Composite) Add(f func(context.Context) error) {
|
|
| 13 | 15 |
c.cleanups = append(c.cleanups, f) |
| 14 | 16 |
} |
| 15 | 17 |
|
| 16 | 18 |
// Call calls all cleanups in reverse order and returns an error combining all |
| 17 | 19 |
// non-nil errors. |
| 18 |
-func (c *Composite) Call() error {
|
|
| 19 |
- err := call(c.cleanups) |
|
| 20 |
+func (c *Composite) Call(ctx context.Context) error {
|
|
| 21 |
+ err := call(ctx, c.cleanups) |
|
| 20 | 22 |
c.cleanups = nil |
| 21 | 23 |
return err |
| 22 | 24 |
} |
| ... | ... |
@@ -24,19 +26,19 @@ func (c *Composite) Call() error {
|
| 24 | 24 |
// Release removes all cleanups, turning Call into a no-op. |
| 25 | 25 |
// Caller still can call the cleanups by calling the returned function |
| 26 | 26 |
// which is equivalent to calling the Call before Release was called. |
| 27 |
-func (c *Composite) Release() func() error {
|
|
| 27 |
+func (c *Composite) Release() func(context.Context) error {
|
|
| 28 | 28 |
cleanups := c.cleanups |
| 29 | 29 |
c.cleanups = nil |
| 30 |
- return func() error {
|
|
| 31 |
- return call(cleanups) |
|
| 30 |
+ return func(ctx context.Context) error {
|
|
| 31 |
+ return call(ctx, cleanups) |
|
| 32 | 32 |
} |
| 33 | 33 |
} |
| 34 | 34 |
|
| 35 |
-func call(cleanups []func() error) error {
|
|
| 35 |
+func call(ctx context.Context, cleanups []func(context.Context) error) error {
|
|
| 36 | 36 |
var errs []error |
| 37 | 37 |
for idx := len(cleanups) - 1; idx >= 0; idx-- {
|
| 38 | 38 |
c := cleanups[idx] |
| 39 |
- errs = append(errs, c()) |
|
| 39 |
+ errs = append(errs, c(ctx)) |
|
| 40 | 40 |
} |
| 41 | 41 |
return multierror.Join(errs...) |
| 42 | 42 |
} |
| ... | ... |
@@ -1,6 +1,7 @@ |
| 1 | 1 |
package cleanups |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "context" |
|
| 4 | 5 |
"errors" |
| 5 | 6 |
"fmt" |
| 6 | 7 |
"testing" |
| ... | ... |
@@ -18,20 +19,20 @@ func TestCall(t *testing.T) {
|
| 18 | 18 |
var errZ = errors.New("errorZ")
|
| 19 | 19 |
var errYZ = errors.Join(errY, errZ) |
| 20 | 20 |
|
| 21 |
- c.Add(func() error {
|
|
| 21 |
+ c.Add(func(ctx context.Context) error {
|
|
| 22 | 22 |
return err1 |
| 23 | 23 |
}) |
| 24 |
- c.Add(func() error {
|
|
| 24 |
+ c.Add(func(ctx context.Context) error {
|
|
| 25 | 25 |
return nil |
| 26 | 26 |
}) |
| 27 |
- c.Add(func() error {
|
|
| 27 |
+ c.Add(func(ctx context.Context) error {
|
|
| 28 | 28 |
return fmt.Errorf("something happened: %w", err2)
|
| 29 | 29 |
}) |
| 30 |
- c.Add(func() error {
|
|
| 30 |
+ c.Add(func(ctx context.Context) error {
|
|
| 31 | 31 |
return errors.Join(errX, fmt.Errorf("joined: %w", errYZ))
|
| 32 | 32 |
}) |
| 33 | 33 |
|
| 34 |
- err := c.Call() |
|
| 34 |
+ err := c.Call(context.Background()) |
|
| 35 | 35 |
|
| 36 | 36 |
errs := err.(interface{ Unwrap() []error }).Unwrap()
|
| 37 | 37 |
|
| ... | ... |
@@ -20,7 +20,7 @@ import ( |
| 20 | 20 |
// After use, it is the caller's responsibility to call Close on the returned |
| 21 | 21 |
// SafePath object, which will unmount the temporary file/directory |
| 22 | 22 |
// and remove it. |
| 23 |
-func Join(path, subpath string) (*SafePath, error) {
|
|
| 23 |
+func Join(_ context.Context, path, subpath string) (*SafePath, error) {
|
|
| 24 | 24 |
base, subpart, err := evaluatePath(path, subpath) |
| 25 | 25 |
if err != nil {
|
| 26 | 26 |
return nil, err |
| ... | ... |
@@ -126,20 +126,20 @@ func tempMountPoint(sourceFd int) (string, error) {
|
| 126 | 126 |
|
| 127 | 127 |
// cleanupSafePaths returns a function that unmounts the path and removes the |
| 128 | 128 |
// mountpoint. |
| 129 |
-func cleanupSafePath(path string) func() error {
|
|
| 130 |
- return func() error {
|
|
| 131 |
- log.G(context.TODO()).WithField("path", path).Debug("removing safe temp mount")
|
|
| 129 |
+func cleanupSafePath(path string) func(context.Context) error {
|
|
| 130 |
+ return func(ctx context.Context) error {
|
|
| 131 |
+ log.G(ctx).WithField("path", path).Debug("removing safe temp mount")
|
|
| 132 | 132 |
|
| 133 | 133 |
if err := unix_noeintr.Unmount(path, unix.MNT_DETACH); err != nil {
|
| 134 | 134 |
if errors.Is(err, unix.EINVAL) {
|
| 135 |
- log.G(context.TODO()).WithField("path", path).Warn("safe temp mount no longer exists?")
|
|
| 135 |
+ log.G(ctx).WithField("path", path).Warn("safe temp mount no longer exists?")
|
|
| 136 | 136 |
return nil |
| 137 | 137 |
} |
| 138 | 138 |
return errors.Wrapf(err, "error unmounting safe mount %s", path) |
| 139 | 139 |
} |
| 140 | 140 |
if err := os.Remove(path); err != nil {
|
| 141 | 141 |
if errors.Is(err, os.ErrNotExist) {
|
| 142 |
- log.G(context.TODO()).WithField("path", path).Warn("safe temp mount no longer exists?")
|
|
| 142 |
+ log.G(ctx).WithField("path", path).Warn("safe temp mount no longer exists?")
|
|
| 143 | 143 |
return nil |
| 144 | 144 |
} |
| 145 | 145 |
return errors.Wrapf(err, "failed to delete temporary safe mount") |
| ... | ... |
@@ -1,6 +1,7 @@ |
| 1 | 1 |
package safepath |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "context" |
|
| 4 | 5 |
"os" |
| 5 | 6 |
"path/filepath" |
| 6 | 7 |
"runtime" |
| ... | ... |
@@ -40,9 +41,9 @@ func TestJoinEscapingSymlink(t *testing.T) {
|
| 40 | 40 |
err = os.Symlink(tc.target, filepath.Join(dir, "link")) |
| 41 | 41 |
assert.NilError(t, err, "failed to create symlink to %s", tc.target) |
| 42 | 42 |
|
| 43 |
- safe, err := Join(dir, "link") |
|
| 43 |
+ safe, err := Join(context.Background(), dir, "link") |
|
| 44 | 44 |
if err == nil {
|
| 45 |
- safe.Close() |
|
| 45 |
+ safe.Close(context.Background()) |
|
| 46 | 46 |
} |
| 47 | 47 |
assert.ErrorType(t, err, &ErrEscapesBase{})
|
| 48 | 48 |
}) |
| ... | ... |
@@ -70,10 +71,10 @@ func TestJoinGoodSymlink(t *testing.T) {
|
| 70 | 70 |
"subdir_link_relative", "foo_link_relative", |
| 71 | 71 |
} {
|
| 72 | 72 |
t.Run(target, func(t *testing.T) {
|
| 73 |
- safe, err := Join(dir, target) |
|
| 73 |
+ safe, err := Join(context.Background(), dir, target) |
|
| 74 | 74 |
assert.NilError(t, err) |
| 75 | 75 |
|
| 76 |
- defer safe.Close() |
|
| 76 |
+ defer safe.Close(context.Background()) |
|
| 77 | 77 |
if strings.HasPrefix(target, "subdir") {
|
| 78 | 78 |
data, err := os.ReadFile(filepath.Join(safe.Path(), "hello.txt")) |
| 79 | 79 |
assert.NilError(t, err) |
| ... | ... |
@@ -97,10 +98,10 @@ func TestJoinWithSymlinkReplace(t *testing.T) {
|
| 97 | 97 |
err = os.Symlink(target, link) |
| 98 | 98 |
assert.Check(t, err, "failed to create symlink to foo") |
| 99 | 99 |
|
| 100 |
- safe, err := Join(dir, "link") |
|
| 100 |
+ safe, err := Join(context.Background(), dir, "link") |
|
| 101 | 101 |
assert.NilError(t, err) |
| 102 | 102 |
|
| 103 |
- defer safe.Close() |
|
| 103 |
+ defer safe.Close(context.Background()) |
|
| 104 | 104 |
|
| 105 | 105 |
// Delete the link target. |
| 106 | 106 |
err = os.Remove(target) |
| ... | ... |
@@ -133,12 +134,12 @@ func TestJoinCloseInvalidates(t *testing.T) {
|
| 133 | 133 |
err = os.WriteFile(foo, []byte("bar"), 0o744)
|
| 134 | 134 |
assert.NilError(t, err, "failed to create test file") |
| 135 | 135 |
|
| 136 |
- safe, err := Join(dir, "foo") |
|
| 136 |
+ safe, err := Join(context.Background(), dir, "foo") |
|
| 137 | 137 |
assert.NilError(t, err) |
| 138 | 138 |
|
| 139 | 139 |
assert.Check(t, safe.IsValid()) |
| 140 | 140 |
|
| 141 |
- assert.NilError(t, safe.Close()) |
|
| 141 |
+ assert.NilError(t, safe.Close(context.Background())) |
|
| 142 | 142 |
|
| 143 | 143 |
assert.Check(t, !safe.IsValid()) |
| 144 | 144 |
} |
| ... | ... |
@@ -8,6 +8,7 @@ import ( |
| 8 | 8 |
|
| 9 | 9 |
"github.com/containerd/log" |
| 10 | 10 |
"github.com/docker/docker/internal/cleanups" |
| 11 |
+ "github.com/docker/docker/internal/compatcontext" |
|
| 11 | 12 |
"github.com/pkg/errors" |
| 12 | 13 |
"golang.org/x/sys/windows" |
| 13 | 14 |
) |
| ... | ... |
@@ -19,7 +20,7 @@ import ( |
| 19 | 19 |
// The path is safe (the path target won't change) until the returned SafePath |
| 20 | 20 |
// is Closed. |
| 21 | 21 |
// Caller is responsible for calling the Close function which unlocks the path. |
| 22 |
-func Join(path, subpath string) (*SafePath, error) {
|
|
| 22 |
+func Join(ctx context.Context, path, subpath string) (*SafePath, error) {
|
|
| 23 | 23 |
base, subpart, err := evaluatePath(path, subpath) |
| 24 | 24 |
if err != nil {
|
| 25 | 25 |
return nil, err |
| ... | ... |
@@ -28,8 +29,8 @@ func Join(path, subpath string) (*SafePath, error) {
|
| 28 | 28 |
|
| 29 | 29 |
cleanups := cleanups.Composite{}
|
| 30 | 30 |
defer func() {
|
| 31 |
- if cErr := cleanups.Call(); cErr != nil {
|
|
| 32 |
- log.G(context.TODO()).WithError(cErr).Warn("failed to close handles after error")
|
|
| 31 |
+ if cErr := cleanups.Call(compatcontext.WithoutCancel(ctx)); cErr != nil {
|
|
| 32 |
+ log.G(ctx).WithError(cErr).Warn("failed to close handles after error")
|
|
| 33 | 33 |
} |
| 34 | 34 |
}() |
| 35 | 35 |
|
| ... | ... |
@@ -44,7 +45,7 @@ func Join(path, subpath string) (*SafePath, error) {
|
| 44 | 44 |
} |
| 45 | 45 |
return nil, errors.Wrapf(err, "failed to lock file %s", fullPath) |
| 46 | 46 |
} |
| 47 |
- cleanups.Add(func() error {
|
|
| 47 |
+ cleanups.Add(func(context.Context) error {
|
|
| 48 | 48 |
if err := windows.CloseHandle(handle); err != nil {
|
| 49 | 49 |
return &os.PathError{Op: "CloseHandle", Path: fullPath, Err: err}
|
| 50 | 50 |
} |
| ... | ... |
@@ -10,7 +10,7 @@ import ( |
| 10 | 10 |
|
| 11 | 11 |
type SafePath struct {
|
| 12 | 12 |
path string |
| 13 |
- cleanup func() error |
|
| 13 |
+ cleanup func(ctx context.Context) error |
|
| 14 | 14 |
mutex sync.Mutex |
| 15 | 15 |
|
| 16 | 16 |
// Immutable fields |
| ... | ... |
@@ -18,13 +18,13 @@ type SafePath struct {
|
| 18 | 18 |
} |
| 19 | 19 |
|
| 20 | 20 |
// Close releases the resources used by the path. |
| 21 |
-func (s *SafePath) Close() error {
|
|
| 21 |
+func (s *SafePath) Close(ctx context.Context) error {
|
|
| 22 | 22 |
s.mutex.Lock() |
| 23 | 23 |
defer s.mutex.Unlock() |
| 24 | 24 |
|
| 25 | 25 |
if s.path == "" {
|
| 26 | 26 |
base, sub := s.SourcePath() |
| 27 |
- log.G(context.TODO()).WithFields(log.Fields{
|
|
| 27 |
+ log.G(ctx).WithFields(log.Fields{
|
|
| 28 | 28 |
"path": s.Path(), |
| 29 | 29 |
"sourceBase": base, |
| 30 | 30 |
"sourceSubpath": sub, |
| ... | ... |
@@ -34,7 +34,7 @@ func (s *SafePath) Close() error {
|
| 34 | 34 |
|
| 35 | 35 |
s.path = "" |
| 36 | 36 |
if s.cleanup != nil {
|
| 37 |
- return s.cleanup() |
|
| 37 |
+ return s.cleanup(ctx) |
|
| 38 | 38 |
} |
| 39 | 39 |
return nil |
| 40 | 40 |
} |
| ... | ... |
@@ -83,7 +83,7 @@ type MountPoint struct {
|
| 83 | 83 |
|
| 84 | 84 |
// Cleanup frees resources used by the mountpoint and cleans up all the paths |
| 85 | 85 |
// returned by Setup that hasn't been cleaned up by the caller. |
| 86 |
-func (m *MountPoint) Cleanup() error {
|
|
| 86 |
+func (m *MountPoint) Cleanup(ctx context.Context) error {
|
|
| 87 | 87 |
if m.Volume == nil || m.ID == "" {
|
| 88 | 88 |
return nil |
| 89 | 89 |
} |
| ... | ... |
@@ -93,9 +93,9 @@ func (m *MountPoint) Cleanup() error {
|
| 93 | 93 |
continue |
| 94 | 94 |
} |
| 95 | 95 |
|
| 96 |
- err := p.Close() |
|
| 96 |
+ err := p.Close(ctx) |
|
| 97 | 97 |
base, sub := p.SourcePath() |
| 98 |
- log.G(context.TODO()).WithFields(log.Fields{
|
|
| 98 |
+ log.G(ctx).WithFields(log.Fields{
|
|
| 99 | 99 |
"error": err, |
| 100 | 100 |
"path": p.Path(), |
| 101 | 101 |
"sourceBase": base, |
| ... | ... |
@@ -126,7 +126,7 @@ func (m *MountPoint) Cleanup() error {
|
| 126 | 126 |
// still points to the same target (to avoid TOCTOU attack). |
| 127 | 127 |
// |
| 128 | 128 |
// Cleanup function doesn't need to be called when error is returned. |
| 129 |
-func (m *MountPoint) Setup(mountLabel string, rootIDs idtools.Identity, checkFun func(m *MountPoint) error) (path string, cleanup func() error, retErr error) {
|
|
| 129 |
+func (m *MountPoint) Setup(ctx context.Context, mountLabel string, rootIDs idtools.Identity, checkFun func(m *MountPoint) error) (path string, cleanup func(context.Context) error, retErr error) {
|
|
| 130 | 130 |
if m.SkipMountpointCreation {
|
| 131 | 131 |
return m.Source, noCleanup, nil |
| 132 | 132 |
} |
| ... | ... |
@@ -140,8 +140,8 @@ func (m *MountPoint) Setup(mountLabel string, rootIDs idtools.Identity, checkFun |
| 140 | 140 |
if err != nil {
|
| 141 | 141 |
path = "" |
| 142 | 142 |
retErr = errors.Wrapf(err, "error evaluating symlinks from mount source %q", m.Source) |
| 143 |
- if cleanupErr := cleanup(); cleanupErr != nil {
|
|
| 144 |
- log.G(context.TODO()).WithError(cleanupErr).Warn("failed to cleanup after error")
|
|
| 143 |
+ if cleanupErr := cleanup(ctx); cleanupErr != nil {
|
|
| 144 |
+ log.G(ctx).WithError(cleanupErr).Warn("failed to cleanup after error")
|
|
| 145 | 145 |
} |
| 146 | 146 |
cleanup = noCleanup |
| 147 | 147 |
return |
| ... | ... |
@@ -150,8 +150,8 @@ func (m *MountPoint) Setup(mountLabel string, rootIDs idtools.Identity, checkFun |
| 150 | 150 |
if err != nil && !errors.Is(err, syscall.ENOTSUP) {
|
| 151 | 151 |
path = "" |
| 152 | 152 |
retErr = errors.Wrapf(err, "error setting label on mount source '%s'", sourcePath) |
| 153 |
- if cleanupErr := cleanup(); cleanupErr != nil {
|
|
| 154 |
- log.G(context.TODO()).WithError(cleanupErr).Warn("failed to cleanup after error")
|
|
| 153 |
+ if cleanupErr := cleanup(ctx); cleanupErr != nil {
|
|
| 154 |
+ log.G(ctx).WithError(cleanupErr).Warn("failed to cleanup after error")
|
|
| 155 | 155 |
} |
| 156 | 156 |
cleanup = noCleanup |
| 157 | 157 |
} |
| ... | ... |
@@ -172,15 +172,15 @@ func (m *MountPoint) Setup(mountLabel string, rootIDs idtools.Identity, checkFun |
| 172 | 172 |
if m.Spec.VolumeOptions != nil && m.Spec.VolumeOptions.Subpath != "" {
|
| 173 | 173 |
subpath := m.Spec.VolumeOptions.Subpath |
| 174 | 174 |
|
| 175 |
- safePath, err := safepath.Join(volumePath, subpath) |
|
| 175 |
+ safePath, err := safepath.Join(ctx, volumePath, subpath) |
|
| 176 | 176 |
if err != nil {
|
| 177 | 177 |
if err := m.Volume.Unmount(id); err != nil {
|
| 178 |
- log.G(context.TODO()).WithError(err).Error("failed to unmount after safepath.Join failed")
|
|
| 178 |
+ log.G(ctx).WithError(err).Error("failed to unmount after safepath.Join failed")
|
|
| 179 | 179 |
} |
| 180 | 180 |
return "", noCleanup, err |
| 181 | 181 |
} |
| 182 | 182 |
m.safePaths = append(m.safePaths, safePath) |
| 183 |
- log.G(context.TODO()).Debugf("mounting (%s|%s) via %s", volumePath, subpath, safePath.Path())
|
|
| 183 |
+ log.G(ctx).Debugf("mounting (%s|%s) via %s", volumePath, subpath, safePath.Path())
|
|
| 184 | 184 |
|
| 185 | 185 |
clean = safePath.Close |
| 186 | 186 |
volumePath = safePath.Path() |
| ... | ... |
@@ -260,6 +260,6 @@ func errInvalidSpec(spec string) error {
|
| 260 | 260 |
} |
| 261 | 261 |
|
| 262 | 262 |
// noCleanup is a no-op cleanup function. |
| 263 |
-func noCleanup() error {
|
|
| 263 |
+func noCleanup(_ context.Context) error {
|
|
| 264 | 264 |
return nil |
| 265 | 265 |
} |