| package container // import "github.com/docker/docker/container" | |
| import ( | |
| "context" | |
| "fmt" | |
| "os" | |
| "path/filepath" | |
| "github.com/docker/docker/api/types" | |
| containertypes "github.com/docker/docker/api/types/container" | |
| "github.com/docker/docker/api/types/events" | |
| swarmtypes "github.com/docker/docker/api/types/swarm" | |
| "github.com/docker/docker/pkg/system" | |
| ) | |
| const ( | |
| containerConfigMountPath = `C:\` | |
| containerSecretMountPath = `C:\ProgramData\Docker\secrets` | |
| containerInternalSecretMountPath = `C:\ProgramData\Docker\internal\secrets` | |
| containerInternalConfigsDirPath = `C:\ProgramData\Docker\internal\configs` | |
| // defaultStopSignal is the default syscall signal used to stop a container. | |
| defaultStopSignal = "SIGTERM" | |
| // defaultStopTimeout is the timeout (in seconds) for the shutdown call on a container | |
| defaultStopTimeout = 30 | |
| ) | |
| // UnmountIpcMount unmounts Ipc related mounts. | |
| // This is a NOOP on windows. | |
| func (container *Container) UnmountIpcMount() error { | |
| return nil | |
| } | |
| // IpcMounts returns the list of Ipc related mounts. | |
| func (container *Container) IpcMounts() []Mount { | |
| return nil | |
| } | |
| // CreateSecretSymlinks creates symlinks to files in the secret mount. | |
| func (container *Container) CreateSecretSymlinks() error { | |
| for _, r := range container.SecretReferences { | |
| if r.File == nil { | |
| continue | |
| } | |
| resolvedPath, _, err := container.ResolvePath(getSecretTargetPath(r)) | |
| if err != nil { | |
| return err | |
| } | |
| if err := system.MkdirAll(filepath.Dir(resolvedPath), 0); err != nil { | |
| return err | |
| } | |
| if err := os.Symlink(filepath.Join(containerInternalSecretMountPath, r.SecretID), resolvedPath); err != nil { | |
| return err | |
| } | |
| } | |
| return nil | |
| } | |
| // SecretMounts returns the mount for the secret path. | |
| // All secrets are stored in a single mount on Windows. Target symlinks are | |
| // created for each secret, pointing to the files in this mount. | |
| func (container *Container) SecretMounts() ([]Mount, error) { | |
| var mounts []Mount | |
| if len(container.SecretReferences) > 0 { | |
| src, err := container.SecretMountPath() | |
| if err != nil { | |
| return nil, err | |
| } | |
| mounts = append(mounts, Mount{ | |
| Source: src, | |
| Destination: containerInternalSecretMountPath, | |
| Writable: false, | |
| }) | |
| } | |
| return mounts, nil | |
| } | |
| // UnmountSecrets unmounts the fs for secrets | |
| func (container *Container) UnmountSecrets() error { | |
| p, err := container.SecretMountPath() | |
| if err != nil { | |
| return err | |
| } | |
| return os.RemoveAll(p) | |
| } | |
| // CreateConfigSymlinks creates symlinks to files in the config mount. | |
| func (container *Container) CreateConfigSymlinks() error { | |
| for _, configRef := range container.ConfigReferences { | |
| if configRef.File == nil { | |
| continue | |
| } | |
| resolvedPath, _, err := container.ResolvePath(getConfigTargetPath(configRef)) | |
| if err != nil { | |
| return err | |
| } | |
| if err := system.MkdirAll(filepath.Dir(resolvedPath), 0); err != nil { | |
| return err | |
| } | |
| if err := os.Symlink(filepath.Join(containerInternalConfigsDirPath, configRef.ConfigID), resolvedPath); err != nil { | |
| return err | |
| } | |
| } | |
| return nil | |
| } | |
| // ConfigMounts returns the mount for configs. | |
| // TODO: Right now Windows doesn't really have a "secure" storage for secrets, | |
| // however some configs may contain secrets. Once secure storage is worked out, | |
| // configs and secret handling should be merged. | |
| func (container *Container) ConfigMounts() []Mount { | |
| var mounts []Mount | |
| if len(container.ConfigReferences) > 0 { | |
| mounts = append(mounts, Mount{ | |
| Source: container.ConfigsDirPath(), | |
| Destination: containerInternalConfigsDirPath, | |
| Writable: false, | |
| }) | |
| } | |
| return mounts | |
| } | |
| // DetachAndUnmount unmounts all volumes. | |
| // On Windows it only delegates to `UnmountVolumes` since there is nothing to | |
| // force unmount. | |
| func (container *Container) DetachAndUnmount(volumeEventLog func(name string, action events.Action, attributes map[string]string)) error { | |
| return container.UnmountVolumes(context.TODO(), volumeEventLog) | |
| } | |
| // TmpfsMounts returns the list of tmpfs mounts | |
| func (container *Container) TmpfsMounts() ([]Mount, error) { | |
| var mounts []Mount | |
| return mounts, nil | |
| } | |
| // UpdateContainer updates configuration of a container. Callers must hold a Lock on the Container. | |
| func (container *Container) UpdateContainer(hostConfig *containertypes.HostConfig) error { | |
| resources := hostConfig.Resources | |
| if resources.CPUShares != 0 || | |
| resources.Memory != 0 || | |
| resources.NanoCPUs != 0 || | |
| resources.CgroupParent != "" || | |
| resources.BlkioWeight != 0 || | |
| len(resources.BlkioWeightDevice) != 0 || | |
| len(resources.BlkioDeviceReadBps) != 0 || | |
| len(resources.BlkioDeviceWriteBps) != 0 || | |
| len(resources.BlkioDeviceReadIOps) != 0 || | |
| len(resources.BlkioDeviceWriteIOps) != 0 || | |
| resources.CPUPeriod != 0 || | |
| resources.CPUQuota != 0 || | |
| resources.CPURealtimePeriod != 0 || | |
| resources.CPURealtimeRuntime != 0 || | |
| resources.CpusetCpus != "" || | |
| resources.CpusetMems != "" || | |
| len(resources.Devices) != 0 || | |
| len(resources.DeviceCgroupRules) != 0 || | |
| resources.KernelMemory != 0 || | |
| resources.MemoryReservation != 0 || | |
| resources.MemorySwap != 0 || | |
| resources.MemorySwappiness != nil || | |
| resources.OomKillDisable != nil || | |
| (resources.PidsLimit != nil && *resources.PidsLimit != 0) || | |
| len(resources.Ulimits) != 0 || | |
| resources.CPUCount != 0 || | |
| resources.CPUPercent != 0 || | |
| resources.IOMaximumIOps != 0 || | |
| resources.IOMaximumBandwidth != 0 { | |
| return fmt.Errorf("resource updating isn't supported on Windows") | |
| } | |
| // update HostConfig of container | |
| if hostConfig.RestartPolicy.Name != "" { | |
| if container.HostConfig.AutoRemove && !hostConfig.RestartPolicy.IsNone() { | |
| return fmt.Errorf("Restart policy cannot be updated because AutoRemove is enabled for the container") | |
| } | |
| container.HostConfig.RestartPolicy = hostConfig.RestartPolicy | |
| } | |
| return nil | |
| } | |
| // BuildHostnameFile writes the container's hostname file. | |
| func (container *Container) BuildHostnameFile() error { | |
| return nil | |
| } | |
| // GetMountPoints gives a platform specific transformation to types.MountPoint. Callers must hold a Container lock. | |
| func (container *Container) GetMountPoints() []types.MountPoint { | |
| mountPoints := make([]types.MountPoint, 0, len(container.MountPoints)) | |
| for _, m := range container.MountPoints { | |
| mountPoints = append(mountPoints, types.MountPoint{ | |
| Type: m.Type, | |
| Name: m.Name, | |
| Source: m.Path(), | |
| Destination: m.Destination, | |
| Driver: m.Driver, | |
| RW: m.RW, | |
| }) | |
| } | |
| return mountPoints | |
| } | |
| func (container *Container) ConfigsDirPath() string { | |
| return filepath.Join(container.Root, "configs") | |
| } | |
| // ConfigFilePath returns the path to the on-disk location of a config. | |
| func (container *Container) ConfigFilePath(configRef swarmtypes.ConfigReference) (string, error) { | |
| return filepath.Join(container.ConfigsDirPath(), configRef.ConfigID), nil | |
| } |