github.com/jiasir/docker@v1.3.3-0.20170609024000-252e610103e7/daemon/oci_windows.go (about) 1 package daemon 2 3 import ( 4 "syscall" 5 6 containertypes "github.com/docker/docker/api/types/container" 7 "github.com/docker/docker/container" 8 "github.com/docker/docker/oci" 9 "github.com/docker/docker/pkg/sysinfo" 10 "github.com/opencontainers/runtime-spec/specs-go" 11 ) 12 13 func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) { 14 s := oci.DefaultSpec() 15 16 linkedEnv, err := daemon.setupLinkedContainers(c) 17 if err != nil { 18 return nil, err 19 } 20 21 // Note, unlike Unix, we do NOT call into SetupWorkingDirectory as 22 // this is done in VMCompute. Further, we couldn't do it for Hyper-V 23 // containers anyway. 24 25 // In base spec 26 s.Hostname = c.FullHostname() 27 28 if err := daemon.setupSecretDir(c); err != nil { 29 return nil, err 30 } 31 32 if err := daemon.setupConfigDir(c); err != nil { 33 return nil, err 34 } 35 36 // In s.Mounts 37 mounts, err := daemon.setupMounts(c) 38 if err != nil { 39 return nil, err 40 } 41 42 var isHyperV bool 43 if c.HostConfig.Isolation.IsDefault() { 44 // Container using default isolation, so take the default from the daemon configuration 45 isHyperV = daemon.defaultIsolation.IsHyperV() 46 } else { 47 // Container may be requesting an explicit isolation mode. 48 isHyperV = c.HostConfig.Isolation.IsHyperV() 49 } 50 51 // If the container has not been started, and has configs or secrets 52 // secrets, create symlinks to each confing and secret. If it has been 53 // started before, the symlinks should have already been created. Also, it 54 // is important to not mount a Hyper-V container that has been started 55 // before, to protect the host from the container; for example, from 56 // malicious mutation of NTFS data structures. 57 if !c.HasBeenStartedBefore && (len(c.SecretReferences) > 0 || len(c.ConfigReferences) > 0) { 58 // The container file system is mounted before this function is called, 59 // except for Hyper-V containers, so mount it here in that case. 60 if isHyperV { 61 if err := daemon.Mount(c); err != nil { 62 return nil, err 63 } 64 defer daemon.Unmount(c) 65 } 66 if err := c.CreateSecretSymlinks(); err != nil { 67 return nil, err 68 } 69 if err := c.CreateConfigSymlinks(); err != nil { 70 return nil, err 71 } 72 } 73 74 if m := c.SecretMounts(); m != nil { 75 mounts = append(mounts, m...) 76 } 77 78 if m := c.ConfigMounts(); m != nil { 79 mounts = append(mounts, m...) 80 } 81 82 for _, mount := range mounts { 83 m := specs.Mount{ 84 Source: mount.Source, 85 Destination: mount.Destination, 86 } 87 if !mount.Writable { 88 m.Options = append(m.Options, "ro") 89 } 90 s.Mounts = append(s.Mounts, m) 91 } 92 93 // In s.Process 94 s.Process.Args = append([]string{c.Path}, c.Args...) 95 if !c.Config.ArgsEscaped { 96 s.Process.Args = escapeArgs(s.Process.Args) 97 } 98 s.Process.Cwd = c.Config.WorkingDir 99 if len(s.Process.Cwd) == 0 { 100 // We default to C:\ to workaround the oddity of the case that the 101 // default directory for cmd running as LocalSystem (or 102 // ContainerAdministrator) is c:\windows\system32. Hence docker run 103 // <image> cmd will by default end in c:\windows\system32, rather 104 // than 'root' (/) on Linux. The oddity is that if you have a dockerfile 105 // which has no WORKDIR and has a COPY file ., . will be interpreted 106 // as c:\. Hence, setting it to default of c:\ makes for consistency. 107 s.Process.Cwd = `C:\` 108 } 109 s.Process.Env = c.CreateDaemonEnvironment(c.Config.Tty, linkedEnv) 110 s.Process.ConsoleSize.Height = c.HostConfig.ConsoleSize[0] 111 s.Process.ConsoleSize.Width = c.HostConfig.ConsoleSize[1] 112 s.Process.Terminal = c.Config.Tty 113 s.Process.User.Username = c.Config.User 114 115 // In spec.Root. This is not set for Hyper-V containers 116 if !isHyperV { 117 s.Root.Path = c.BaseFS 118 } 119 s.Root.Readonly = false // Windows does not support a read-only root filesystem 120 121 // In s.Windows.Resources 122 cpuShares := uint16(c.HostConfig.CPUShares) 123 cpuMaximum := uint16(c.HostConfig.CPUPercent) * 100 124 cpuCount := uint64(c.HostConfig.CPUCount) 125 if c.HostConfig.NanoCPUs > 0 { 126 if isHyperV { 127 cpuCount = uint64(c.HostConfig.NanoCPUs / 1e9) 128 leftoverNanoCPUs := c.HostConfig.NanoCPUs % 1e9 129 if leftoverNanoCPUs != 0 { 130 cpuCount++ 131 cpuMaximum = uint16(c.HostConfig.NanoCPUs / int64(cpuCount) / (1e9 / 10000)) 132 if cpuMaximum < 1 { 133 // The requested NanoCPUs is so small that we rounded to 0, use 1 instead 134 cpuMaximum = 1 135 } 136 } 137 } else { 138 cpuMaximum = uint16(c.HostConfig.NanoCPUs / int64(sysinfo.NumCPU()) / (1e9 / 10000)) 139 if cpuMaximum < 1 { 140 // The requested NanoCPUs is so small that we rounded to 0, use 1 instead 141 cpuMaximum = 1 142 } 143 } 144 } 145 memoryLimit := uint64(c.HostConfig.Memory) 146 s.Windows.Resources = &specs.WindowsResources{ 147 CPU: &specs.WindowsCPUResources{ 148 Maximum: &cpuMaximum, 149 Shares: &cpuShares, 150 Count: &cpuCount, 151 }, 152 Memory: &specs.WindowsMemoryResources{ 153 Limit: &memoryLimit, 154 }, 155 Storage: &specs.WindowsStorageResources{ 156 Bps: &c.HostConfig.IOMaximumBandwidth, 157 Iops: &c.HostConfig.IOMaximumIOps, 158 }, 159 } 160 return (*specs.Spec)(&s), nil 161 } 162 163 func escapeArgs(args []string) []string { 164 escapedArgs := make([]string, len(args)) 165 for i, a := range args { 166 escapedArgs[i] = syscall.EscapeArg(a) 167 } 168 return escapedArgs 169 } 170 171 // mergeUlimits merge the Ulimits from HostConfig with daemon defaults, and update HostConfig 172 // It will do nothing on non-Linux platform 173 func (daemon *Daemon) mergeUlimits(c *containertypes.HostConfig) { 174 return 175 }