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