2016-03-18 14:53:27 -04:00
|
|
|
package daemon
|
|
|
|
|
|
|
|
import (
|
|
|
|
"syscall"
|
|
|
|
|
2016-09-08 00:23:56 -04:00
|
|
|
containertypes "github.com/docker/docker/api/types/container"
|
2016-03-18 14:53:27 -04:00
|
|
|
"github.com/docker/docker/container"
|
|
|
|
"github.com/docker/docker/oci"
|
2016-11-01 13:12:29 -04:00
|
|
|
"github.com/docker/docker/pkg/sysinfo"
|
2016-09-27 13:26:59 -04:00
|
|
|
"github.com/opencontainers/runtime-spec/specs-go"
|
2016-03-18 14:53:27 -04:00
|
|
|
)
|
|
|
|
|
2016-09-27 13:26:59 -04:00
|
|
|
func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) {
|
2016-03-18 14:53:27 -04:00
|
|
|
s := oci.DefaultSpec()
|
|
|
|
|
|
|
|
linkedEnv, err := daemon.setupLinkedContainers(c)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO Windows - this can be removed. Not used (UID/GID)
|
|
|
|
rootUID, rootGID := daemon.GetRemappedUIDGID()
|
|
|
|
if err := c.SetupWorkingDirectory(rootUID, rootGID); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// In base spec
|
|
|
|
s.Hostname = c.FullHostname()
|
|
|
|
|
|
|
|
// In s.Mounts
|
|
|
|
mounts, err := daemon.setupMounts(c)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
for _, mount := range mounts {
|
2016-09-27 13:26:59 -04:00
|
|
|
m := specs.Mount{
|
2016-03-18 14:53:27 -04:00
|
|
|
Source: mount.Source,
|
|
|
|
Destination: mount.Destination,
|
2016-09-14 14:35:31 -04:00
|
|
|
}
|
|
|
|
if !mount.Writable {
|
|
|
|
m.Options = append(m.Options, "ro")
|
|
|
|
}
|
|
|
|
s.Mounts = append(s.Mounts, m)
|
2016-03-18 14:53:27 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// In s.Process
|
2016-03-28 20:35:56 -04:00
|
|
|
s.Process.Args = append([]string{c.Path}, c.Args...)
|
|
|
|
if !c.Config.ArgsEscaped {
|
|
|
|
s.Process.Args = escapeArgs(s.Process.Args)
|
2016-03-18 14:53:27 -04:00
|
|
|
}
|
|
|
|
s.Process.Cwd = c.Config.WorkingDir
|
2016-04-18 13:11:37 -04:00
|
|
|
if len(s.Process.Cwd) == 0 {
|
|
|
|
// We default to C:\ to workaround the oddity of the case that the
|
|
|
|
// default directory for cmd running as LocalSystem (or
|
|
|
|
// ContainerAdministrator) is c:\windows\system32. Hence docker run
|
|
|
|
// <image> cmd will by default end in c:\windows\system32, rather
|
|
|
|
// than 'root' (/) on Linux. The oddity is that if you have a dockerfile
|
|
|
|
// which has no WORKDIR and has a COPY file ., . will be interpreted
|
|
|
|
// as c:\. Hence, setting it to default of c:\ makes for consistency.
|
|
|
|
s.Process.Cwd = `C:\`
|
|
|
|
}
|
2016-09-28 18:21:33 -04:00
|
|
|
s.Process.Env = c.CreateDaemonEnvironment(c.Config.Tty, linkedEnv)
|
2016-09-20 15:01:04 -04:00
|
|
|
s.Process.ConsoleSize.Height = c.HostConfig.ConsoleSize[0]
|
|
|
|
s.Process.ConsoleSize.Width = c.HostConfig.ConsoleSize[1]
|
2016-03-18 14:53:27 -04:00
|
|
|
s.Process.Terminal = c.Config.Tty
|
2016-09-14 14:46:18 -04:00
|
|
|
s.Process.User.Username = c.Config.User
|
2016-03-18 14:53:27 -04:00
|
|
|
|
2016-09-27 17:52:49 -04:00
|
|
|
// In spec.Root. This is not set for Hyper-V containers
|
|
|
|
isHyperV := false
|
|
|
|
if c.HostConfig.Isolation.IsDefault() {
|
|
|
|
// Container using default isolation, so take the default from the daemon configuration
|
|
|
|
isHyperV = daemon.defaultIsolation.IsHyperV()
|
|
|
|
} else {
|
|
|
|
// Container may be requesting an explicit isolation mode.
|
|
|
|
isHyperV = c.HostConfig.Isolation.IsHyperV()
|
|
|
|
}
|
|
|
|
if !isHyperV {
|
|
|
|
s.Root.Path = c.BaseFS
|
|
|
|
}
|
|
|
|
s.Root.Readonly = false // Windows does not support a read-only root filesystem
|
2016-03-18 14:53:27 -04:00
|
|
|
|
|
|
|
// In s.Windows.Resources
|
|
|
|
// @darrenstahlmsft implement these resources
|
2016-09-27 13:26:59 -04:00
|
|
|
cpuShares := uint16(c.HostConfig.CPUShares)
|
|
|
|
cpuPercent := uint8(c.HostConfig.CPUPercent)
|
2016-11-01 13:12:29 -04:00
|
|
|
if c.HostConfig.NanoCPUs > 0 {
|
|
|
|
cpuPercent = uint8(c.HostConfig.NanoCPUs * 100 / int64(sysinfo.NumCPU()) / 1e9)
|
|
|
|
}
|
2016-11-01 16:02:46 -04:00
|
|
|
cpuCount := uint64(c.HostConfig.CPUCount)
|
2016-09-27 13:26:59 -04:00
|
|
|
memoryLimit := uint64(c.HostConfig.Memory)
|
|
|
|
s.Windows.Resources = &specs.WindowsResources{
|
|
|
|
CPU: &specs.WindowsCPUResources{
|
|
|
|
Percent: &cpuPercent,
|
2016-03-04 20:24:09 -05:00
|
|
|
Shares: &cpuShares,
|
2016-11-01 16:02:46 -04:00
|
|
|
Count: &cpuCount,
|
2016-03-18 14:53:27 -04:00
|
|
|
},
|
2016-09-27 13:26:59 -04:00
|
|
|
Memory: &specs.WindowsMemoryResources{
|
|
|
|
Limit: &memoryLimit,
|
2016-06-09 15:37:17 -04:00
|
|
|
//TODO Reservation: ...,
|
2016-03-18 14:53:27 -04:00
|
|
|
},
|
2016-09-27 13:26:59 -04:00
|
|
|
Network: &specs.WindowsNetworkResources{
|
2016-03-18 14:53:27 -04:00
|
|
|
//TODO Bandwidth: ...,
|
|
|
|
},
|
2016-09-27 13:26:59 -04:00
|
|
|
Storage: &specs.WindowsStorageResources{
|
2016-02-24 20:51:46 -05:00
|
|
|
Bps: &c.HostConfig.IOMaximumBandwidth,
|
|
|
|
Iops: &c.HostConfig.IOMaximumIOps,
|
2016-03-18 14:53:27 -04:00
|
|
|
},
|
|
|
|
}
|
2016-09-27 13:26:59 -04:00
|
|
|
return (*specs.Spec)(&s), nil
|
2016-03-18 14:53:27 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
func escapeArgs(args []string) []string {
|
|
|
|
escapedArgs := make([]string, len(args))
|
|
|
|
for i, a := range args {
|
|
|
|
escapedArgs[i] = syscall.EscapeArg(a)
|
|
|
|
}
|
|
|
|
return escapedArgs
|
|
|
|
}
|
2016-09-08 00:23:56 -04:00
|
|
|
|
|
|
|
// mergeUlimits merge the Ulimits from HostConfig with daemon defaults, and update HostConfig
|
|
|
|
// It will do nothing on non-Linux platform
|
|
|
|
func (daemon *Daemon) mergeUlimits(c *containertypes.HostConfig) {
|
|
|
|
return
|
|
|
|
}
|