-
Notifications
You must be signed in to change notification settings - Fork 0
/
create_unix.go
129 lines (109 loc) · 4.14 KB
/
create_unix.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
//go:build !windows
package daemon // import "github.com/docker/docker/daemon"
import (
"context"
"fmt"
"os"
"path/filepath"
"github.com/containerd/log"
containertypes "github.com/docker/docker/api/types/container"
mounttypes "github.com/docker/docker/api/types/mount"
"github.com/docker/docker/container"
"github.com/docker/docker/errdefs"
"github.com/docker/docker/internal/compatcontext"
"github.com/docker/docker/oci"
volumemounts "github.com/docker/docker/volume/mounts"
volumeopts "github.com/docker/docker/volume/service/opts"
"github.com/opencontainers/selinux/go-selinux/label"
"github.com/pkg/errors"
)
// createContainerOSSpecificSettings performs host-OS specific container create functionality
func (daemon *Daemon) createContainerOSSpecificSettings(ctx context.Context, container *container.Container, config *containertypes.Config, hostConfig *containertypes.HostConfig) error {
if err := daemon.Mount(container); err != nil {
return err
}
defer daemon.Unmount(container)
rootIDs := daemon.idMapping.RootPair()
if err := container.SetupWorkingDirectory(rootIDs); err != nil {
return err
}
// Set the default masked and readonly paths with regard to the host config options if they are not set.
if hostConfig.MaskedPaths == nil && !hostConfig.Privileged {
hostConfig.MaskedPaths = oci.DefaultSpec().Linux.MaskedPaths // Set it to the default if nil
container.HostConfig.MaskedPaths = hostConfig.MaskedPaths
}
if hostConfig.ReadonlyPaths == nil && !hostConfig.Privileged {
hostConfig.ReadonlyPaths = oci.DefaultSpec().Linux.ReadonlyPaths // Set it to the default if nil
container.HostConfig.ReadonlyPaths = hostConfig.ReadonlyPaths
}
for spec := range config.Volumes {
destination := filepath.Clean(spec)
// Skip volumes for which we already have something mounted on that
// destination because of a --volume-from.
if container.HasMountFor(destination) {
log.G(ctx).WithField("container", container.ID).WithField("destination", spec).Debug("mountpoint already exists, skipping anonymous volume")
// Not an error, this could easily have come from the image config.
continue
}
path, err := container.GetResourcePath(destination)
if err != nil {
return err
}
stat, err := os.Stat(path)
if err == nil && !stat.IsDir() {
return fmt.Errorf("cannot mount volume over existing file, file exists %s", path)
}
v, err := daemon.volumes.Create(context.TODO(), "", hostConfig.VolumeDriver, volumeopts.WithCreateReference(container.ID))
if err != nil {
return err
}
if err := label.Relabel(v.Mountpoint, container.MountLabel, true); err != nil {
return err
}
container.AddMountPointWithVolume(destination, &volumeWrapper{v: v, s: daemon.volumes}, true)
}
return daemon.populateVolumes(ctx, container)
}
// populateVolumes copies data from the container's rootfs into the volume for non-binds.
// this is only called when the container is created.
func (daemon *Daemon) populateVolumes(ctx context.Context, c *container.Container) error {
for _, mnt := range c.MountPoints {
if mnt.Volume == nil {
continue
}
if mnt.Type != mounttypes.TypeVolume || !mnt.CopyData {
continue
}
if err := daemon.populateVolume(ctx, c, mnt); err != nil {
return err
}
}
return nil
}
func (daemon *Daemon) populateVolume(ctx context.Context, c *container.Container, mnt *volumemounts.MountPoint) error {
ctrDestPath, err := c.GetResourcePath(mnt.Destination)
if err != nil {
return err
}
if _, err := os.Stat(ctrDestPath); err != nil {
if os.IsNotExist(err) {
return nil
}
return err
}
volumePath, cleanup, err := mnt.Setup(ctx, c.MountLabel, daemon.idMapping.RootPair(), nil)
if err != nil {
if errdefs.IsNotFound(err) {
return nil
}
log.G(ctx).WithError(err).Debugf("can't copy data from %s:%s, to %s", c.ID, mnt.Destination, volumePath)
return errors.Wrapf(err, "failed to populate volume")
}
defer mnt.Cleanup(compatcontext.WithoutCancel(ctx))
defer cleanup(compatcontext.WithoutCancel(ctx))
log.G(ctx).Debugf("copying image data from %s:%s, to %s", c.ID, mnt.Destination, volumePath)
if err := c.CopyImagePathContent(volumePath, ctrDestPath); err != nil {
return err
}
return nil
}