github.com/ojongerius/docker@v1.11.2/daemon/oci_windows.go (about) 1 package daemon 2 3 import ( 4 "fmt" 5 "strings" 6 "syscall" 7 8 "github.com/docker/docker/container" 9 "github.com/docker/docker/layer" 10 "github.com/docker/docker/libcontainerd" 11 "github.com/docker/docker/libcontainerd/windowsoci" 12 "github.com/docker/docker/oci" 13 ) 14 15 func (daemon *Daemon) createSpec(c *container.Container) (*libcontainerd.Spec, error) { 16 s := oci.DefaultSpec() 17 18 linkedEnv, err := daemon.setupLinkedContainers(c) 19 if err != nil { 20 return nil, err 21 } 22 23 // TODO Windows - this can be removed. Not used (UID/GID) 24 rootUID, rootGID := daemon.GetRemappedUIDGID() 25 if err := c.SetupWorkingDirectory(rootUID, rootGID); err != nil { 26 return nil, err 27 } 28 29 img, err := daemon.imageStore.Get(c.ImageID) 30 if err != nil { 31 return nil, fmt.Errorf("Failed to graph.Get on ImageID %s - %s", c.ImageID, err) 32 } 33 34 // In base spec 35 s.Hostname = c.FullHostname() 36 37 // In s.Mounts 38 mounts, err := daemon.setupMounts(c) 39 if err != nil { 40 return nil, err 41 } 42 for _, mount := range mounts { 43 s.Mounts = append(s.Mounts, windowsoci.Mount{ 44 Source: mount.Source, 45 Destination: mount.Destination, 46 Readonly: !mount.Writable, 47 }) 48 } 49 50 // Are we going to run as a Hyper-V container? 51 hv := false 52 if c.HostConfig.Isolation.IsDefault() { 53 // Container is set to use the default, so take the default from the daemon configuration 54 hv = daemon.defaultIsolation.IsHyperV() 55 } else { 56 // Container is requesting an isolation mode. Honour it. 57 hv = c.HostConfig.Isolation.IsHyperV() 58 } 59 if hv { 60 // TODO We don't yet have the ImagePath hooked up. But set to 61 // something non-nil to pickup in libcontainerd. 62 s.Windows.HvRuntime = &windowsoci.HvRuntime{} 63 } 64 65 // In s.Process 66 if c.Config.ArgsEscaped { 67 s.Process.Args = append([]string{c.Path}, c.Args...) 68 } else { 69 // TODO (jstarks): escape the entrypoint too once the tests are fixed to not rely on this behavior 70 s.Process.Args = append([]string{c.Path}, escapeArgs(c.Args)...) 71 } 72 s.Process.Cwd = c.Config.WorkingDir 73 s.Process.Env = c.CreateDaemonEnvironment(linkedEnv) 74 s.Process.InitialConsoleSize = c.HostConfig.ConsoleSize 75 s.Process.Terminal = c.Config.Tty 76 s.Process.User.User = c.Config.User 77 78 // In spec.Root 79 s.Root.Path = c.BaseFS 80 s.Root.Readonly = c.HostConfig.ReadonlyRootfs 81 82 // In s.Windows 83 s.Windows.FirstStart = !c.HasBeenStartedBefore 84 85 // s.Windows.LayerFolder. 86 m, err := c.RWLayer.Metadata() 87 if err != nil { 88 return nil, fmt.Errorf("Failed to get layer metadata - %s", err) 89 } 90 s.Windows.LayerFolder = m["dir"] 91 92 // s.Windows.LayerPaths 93 var layerPaths []string 94 if img.RootFS != nil && img.RootFS.Type == "layers+base" { 95 max := len(img.RootFS.DiffIDs) 96 for i := 0; i <= max; i++ { 97 img.RootFS.DiffIDs = img.RootFS.DiffIDs[:i] 98 path, err := layer.GetLayerPath(daemon.layerStore, img.RootFS.ChainID()) 99 if err != nil { 100 return nil, fmt.Errorf("Failed to get layer path from graphdriver %s for ImageID %s - %s", daemon.layerStore, img.RootFS.ChainID(), err) 101 } 102 // Reverse order, expecting parent most first 103 layerPaths = append([]string{path}, layerPaths...) 104 } 105 } 106 s.Windows.LayerPaths = layerPaths 107 108 // In s.Windows.Networking (TP5+ libnetwork way of doing things) 109 // Connect all the libnetwork allocated networks to the container 110 var epList []string 111 if c.NetworkSettings != nil { 112 for n := range c.NetworkSettings.Networks { 113 sn, err := daemon.FindNetwork(n) 114 if err != nil { 115 continue 116 } 117 118 ep, err := c.GetEndpointInNetwork(sn) 119 if err != nil { 120 continue 121 } 122 123 data, err := ep.DriverInfo() 124 if err != nil { 125 continue 126 } 127 if data["hnsid"] != nil { 128 epList = append(epList, data["hnsid"].(string)) 129 } 130 } 131 } 132 s.Windows.Networking = &windowsoci.Networking{ 133 EndpointList: epList, 134 } 135 136 // In s.Windows.Networking (TP4 back compat) 137 // TODO Windows: Post TP4 - Remove this along with definitions from spec 138 // and changes to libcontainerd to not read these fields. 139 if daemon.netController == nil { 140 parts := strings.SplitN(string(c.HostConfig.NetworkMode), ":", 2) 141 switch parts[0] { 142 case "none": 143 case "default", "": // empty string to support existing containers 144 if !c.Config.NetworkDisabled { 145 s.Windows.Networking = &windowsoci.Networking{ 146 MacAddress: c.Config.MacAddress, 147 Bridge: daemon.configStore.bridgeConfig.Iface, 148 PortBindings: c.HostConfig.PortBindings, 149 } 150 } 151 default: 152 return nil, fmt.Errorf("invalid network mode: %s", c.HostConfig.NetworkMode) 153 } 154 } 155 156 // In s.Windows.Resources 157 // @darrenstahlmsft implement these resources 158 cpuShares := uint64(c.HostConfig.CPUShares) 159 s.Windows.Resources = &windowsoci.Resources{ 160 CPU: &windowsoci.CPU{ 161 //TODO Count: ..., 162 //TODO Percent: ..., 163 Shares: &cpuShares, 164 }, 165 Memory: &windowsoci.Memory{ 166 //TODO Limit: ..., 167 //TODO Reservation: ..., 168 }, 169 Network: &windowsoci.Network{ 170 //TODO Bandwidth: ..., 171 }, 172 Storage: &windowsoci.Storage{ 173 //TODO Bps: ..., 174 //TODO Iops: ..., 175 //TODO SandboxSize: ..., 176 }, 177 } 178 return (*libcontainerd.Spec)(&s), nil 179 } 180 181 func escapeArgs(args []string) []string { 182 escapedArgs := make([]string, len(args)) 183 for i, a := range args { 184 escapedArgs[i] = syscall.EscapeArg(a) 185 } 186 return escapedArgs 187 }