package daemon // import "github.com/docker/docker/daemon" import ( "context" "fmt" "runtime" containertypes "github.com/docker/docker/api/types/container" "github.com/docker/docker/container" "github.com/docker/docker/pkg/stringid" volumemounts "github.com/docker/docker/volume/mounts" volumeopts "github.com/docker/docker/volume/service/opts" ) // createContainerOSSpecificSettings performs host-OS specific container create functionality func (daemon *Daemon) createContainerOSSpecificSettings(container *container.Container, config *containertypes.Config, hostConfig *containertypes.HostConfig) error { if container.OS == runtime.GOOS { // Make sure the host config has the default daemon isolation if not specified by caller. if containertypes.Isolation.IsDefault(containertypes.Isolation(hostConfig.Isolation)) { hostConfig.Isolation = daemon.defaultIsolation } } else { // LCOW must be a Hyper-V container as you can't run a shared kernel when one // is a Windows kernel, the other is a Linux kernel. if containertypes.Isolation.IsProcess(containertypes.Isolation(hostConfig.Isolation)) { return fmt.Errorf("process isolation is invalid for Linux containers on Windows") } hostConfig.Isolation = "hyperv" } parser := volumemounts.NewParser(container.OS) for spec := range config.Volumes { mp, err := parser.ParseMountRaw(spec, hostConfig.VolumeDriver) if err != nil { return fmt.Errorf("Unrecognised volume spec: %v", err) } // If the mountpoint doesn't have a name, generate one. if len(mp.Name) == 0 { mp.Name = stringid.GenerateNonCryptoID() } // Skip volumes for which we already have something mounted on that // destination because of a --volume-from. if container.IsDestinationMounted(mp.Destination) { continue } volumeDriver := hostConfig.VolumeDriver // Create the volume in the volume driver. If it doesn't exist, // a new one will be created. v, err := daemon.volumes.Create(context.TODO(), mp.Name, volumeDriver, volumeopts.WithCreateReference(container.ID)) if err != nil { return err } // FIXME Windows: This code block is present in the Linux version and // allows the contents to be copied to the container FS prior to it // being started. However, the function utilizes the FollowSymLinkInScope // path which does not cope with Windows volume-style file paths. There // is a separate effort to resolve this (@swernli), so this processing // is deferred for now. A case where this would be useful is when // a dockerfile includes a VOLUME statement, but something is created // in that directory during the dockerfile processing. What this means // on Windows for TP5 is that in that scenario, the contents will not // copied, but that's (somewhat) OK as HCS will bomb out soon after // at it doesn't support mapped directories which have contents in the // destination path anyway. // // Example for repro later: // FROM windowsservercore // RUN mkdir c:\myvol // RUN copy c:\windows\system32\ntdll.dll c:\myvol // VOLUME "c:\myvol" // // Then // docker build -t vol . // docker run -it --rm vol cmd <-- This is where HCS will error out. // // // never attempt to copy existing content in a container FS to a shared volume // if v.DriverName() == volume.DefaultDriverName { // if err := container.CopyImagePathContent(v, mp.Destination); err != nil { // return err // } // } // Add it to container.MountPoints container.AddMountPointWithVolume(mp.Destination, &volumeWrapper{v: v, s: daemon.volumes}, mp.RW) } return nil }