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  }