docker/docker

View on GitHub
container/container_windows.go

Summary

Maintainability
C
1 day
Test Coverage
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
}