github.com/kobeld/docker@v1.12.0-rc1/daemon/oci_windows.go (about) 1 package daemon 2 3 import ( 4 "errors" 5 "fmt" 6 "os" 7 "path/filepath" 8 "syscall" 9 10 "github.com/docker/docker/container" 11 "github.com/docker/docker/image" 12 "github.com/docker/docker/layer" 13 "github.com/docker/docker/libcontainerd" 14 "github.com/docker/docker/libcontainerd/windowsoci" 15 "github.com/docker/docker/oci" 16 ) 17 18 func (daemon *Daemon) createSpec(c *container.Container) (*libcontainerd.Spec, error) { 19 s := oci.DefaultSpec() 20 21 linkedEnv, err := daemon.setupLinkedContainers(c) 22 if err != nil { 23 return nil, err 24 } 25 26 // TODO Windows - this can be removed. Not used (UID/GID) 27 rootUID, rootGID := daemon.GetRemappedUIDGID() 28 if err := c.SetupWorkingDirectory(rootUID, rootGID); err != nil { 29 return nil, err 30 } 31 32 img, err := daemon.imageStore.Get(c.ImageID) 33 if err != nil { 34 return nil, fmt.Errorf("Failed to graph.Get on ImageID %s - %s", c.ImageID, err) 35 } 36 37 s.Platform.OSVersion = img.OSVersion 38 39 // In base spec 40 s.Hostname = c.FullHostname() 41 42 // In s.Mounts 43 mounts, err := daemon.setupMounts(c) 44 if err != nil { 45 return nil, err 46 } 47 for _, mount := range mounts { 48 s.Mounts = append(s.Mounts, windowsoci.Mount{ 49 Source: mount.Source, 50 Destination: mount.Destination, 51 Readonly: !mount.Writable, 52 }) 53 } 54 55 // In s.Process 56 s.Process.Args = append([]string{c.Path}, c.Args...) 57 if !c.Config.ArgsEscaped { 58 s.Process.Args = escapeArgs(s.Process.Args) 59 } 60 s.Process.Cwd = c.Config.WorkingDir 61 if len(s.Process.Cwd) == 0 { 62 // We default to C:\ to workaround the oddity of the case that the 63 // default directory for cmd running as LocalSystem (or 64 // ContainerAdministrator) is c:\windows\system32. Hence docker run 65 // <image> cmd will by default end in c:\windows\system32, rather 66 // than 'root' (/) on Linux. The oddity is that if you have a dockerfile 67 // which has no WORKDIR and has a COPY file ., . will be interpreted 68 // as c:\. Hence, setting it to default of c:\ makes for consistency. 69 s.Process.Cwd = `C:\` 70 } 71 s.Process.Env = c.CreateDaemonEnvironment(linkedEnv) 72 s.Process.InitialConsoleSize = c.HostConfig.ConsoleSize 73 s.Process.Terminal = c.Config.Tty 74 s.Process.User.User = c.Config.User 75 76 // In spec.Root 77 s.Root.Path = c.BaseFS 78 s.Root.Readonly = c.HostConfig.ReadonlyRootfs 79 80 // In s.Windows 81 s.Windows.FirstStart = !c.HasBeenStartedBefore 82 83 // s.Windows.LayerFolder. 84 m, err := c.RWLayer.Metadata() 85 if err != nil { 86 return nil, fmt.Errorf("Failed to get layer metadata - %s", err) 87 } 88 s.Windows.LayerFolder = m["dir"] 89 90 // s.Windows.LayerPaths 91 var layerPaths []string 92 if img.RootFS != nil && (img.RootFS.Type == image.TypeLayers || img.RootFS.Type == image.TypeLayersWithBase) { 93 // Get the layer path for each layer. 94 start := 1 95 if img.RootFS.Type == image.TypeLayersWithBase { 96 // Include an empty slice to get the base layer ID. 97 start = 0 98 } 99 max := len(img.RootFS.DiffIDs) 100 for i := start; i <= max; i++ { 101 img.RootFS.DiffIDs = img.RootFS.DiffIDs[:i] 102 path, err := layer.GetLayerPath(daemon.layerStore, img.RootFS.ChainID()) 103 if err != nil { 104 return nil, fmt.Errorf("Failed to get layer path from graphdriver %s for ImageID %s - %s", daemon.layerStore, img.RootFS.ChainID(), err) 105 } 106 // Reverse order, expecting parent most first 107 layerPaths = append([]string{path}, layerPaths...) 108 } 109 } 110 s.Windows.LayerPaths = layerPaths 111 112 // Are we going to run as a Hyper-V container? 113 hv := false 114 if c.HostConfig.Isolation.IsDefault() { 115 // Container is set to use the default, so take the default from the daemon configuration 116 hv = daemon.defaultIsolation.IsHyperV() 117 } else { 118 // Container is requesting an isolation mode. Honour it. 119 hv = c.HostConfig.Isolation.IsHyperV() 120 } 121 if hv { 122 hvr := &windowsoci.HvRuntime{} 123 if img.RootFS != nil && img.RootFS.Type == image.TypeLayers { 124 // For TP5, the utility VM is part of the base layer. 125 // TODO-jstarks: Add support for separate utility VM images 126 // once it is decided how they can be stored. 127 uvmpath := filepath.Join(layerPaths[len(layerPaths)-1], "UtilityVM") 128 _, err = os.Stat(uvmpath) 129 if err != nil { 130 if os.IsNotExist(err) { 131 err = errors.New("container image does not contain a utility VM") 132 } 133 return nil, err 134 } 135 136 hvr.ImagePath = uvmpath 137 } 138 139 s.Windows.HvRuntime = hvr 140 } 141 142 // In s.Windows.Networking 143 // Connect all the libnetwork allocated networks to the container 144 var epList []string 145 if c.NetworkSettings != nil { 146 for n := range c.NetworkSettings.Networks { 147 sn, err := daemon.FindNetwork(n) 148 if err != nil { 149 continue 150 } 151 152 ep, err := c.GetEndpointInNetwork(sn) 153 if err != nil { 154 continue 155 } 156 157 data, err := ep.DriverInfo() 158 if err != nil { 159 continue 160 } 161 if data["hnsid"] != nil { 162 epList = append(epList, data["hnsid"].(string)) 163 } 164 } 165 } 166 s.Windows.Networking = &windowsoci.Networking{ 167 EndpointList: epList, 168 } 169 170 // In s.Windows.Resources 171 // @darrenstahlmsft implement these resources 172 cpuShares := uint64(c.HostConfig.CPUShares) 173 s.Windows.Resources = &windowsoci.Resources{ 174 CPU: &windowsoci.CPU{ 175 Percent: &c.HostConfig.CPUPercent, 176 Shares: &cpuShares, 177 }, 178 Memory: &windowsoci.Memory{ 179 //TODO Limit: ..., 180 //TODO Reservation: ..., 181 }, 182 Network: &windowsoci.Network{ 183 //TODO Bandwidth: ..., 184 }, 185 Storage: &windowsoci.Storage{ 186 Bps: &c.HostConfig.IOMaximumBandwidth, 187 Iops: &c.HostConfig.IOMaximumIOps, 188 //TODO SandboxSize: ..., 189 }, 190 } 191 return (*libcontainerd.Spec)(&s), nil 192 } 193 194 func escapeArgs(args []string) []string { 195 escapedArgs := make([]string, len(args)) 196 for i, a := range args { 197 escapedArgs[i] = syscall.EscapeArg(a) 198 } 199 return escapedArgs 200 }