github.com/portworx/docker@v1.12.1/daemon/daemon_windows.go (about) 1 package daemon 2 3 import ( 4 "encoding/json" 5 "errors" 6 "fmt" 7 "os" 8 "path/filepath" 9 "runtime" 10 "strings" 11 12 "github.com/Microsoft/hcsshim" 13 "github.com/Sirupsen/logrus" 14 "github.com/docker/docker/container" 15 "github.com/docker/docker/daemon/graphdriver" 16 "github.com/docker/docker/daemon/graphdriver/windows" // register the windows graph driver 17 "github.com/docker/docker/dockerversion" 18 "github.com/docker/docker/image" 19 "github.com/docker/docker/layer" 20 "github.com/docker/docker/pkg/idtools" 21 "github.com/docker/docker/pkg/parsers" 22 "github.com/docker/docker/pkg/sysinfo" 23 "github.com/docker/docker/pkg/system" 24 "github.com/docker/docker/reference" 25 "github.com/docker/docker/runconfig" 26 "github.com/docker/engine-api/types" 27 pblkiodev "github.com/docker/engine-api/types/blkiodev" 28 containertypes "github.com/docker/engine-api/types/container" 29 "github.com/docker/libnetwork" 30 nwconfig "github.com/docker/libnetwork/config" 31 winlibnetwork "github.com/docker/libnetwork/drivers/windows" 32 "github.com/docker/libnetwork/netlabel" 33 "github.com/docker/libnetwork/options" 34 blkiodev "github.com/opencontainers/runc/libcontainer/configs" 35 ) 36 37 const ( 38 defaultNetworkSpace = "172.16.0.0/12" 39 platformSupported = true 40 windowsMinCPUShares = 1 41 windowsMaxCPUShares = 10000 42 ) 43 44 func getBlkioWeightDevices(config *containertypes.HostConfig) ([]blkiodev.WeightDevice, error) { 45 return nil, nil 46 } 47 48 func parseSecurityOpt(container *container.Container, config *containertypes.HostConfig) error { 49 return nil 50 } 51 52 func getBlkioReadIOpsDevices(config *containertypes.HostConfig) ([]blkiodev.ThrottleDevice, error) { 53 return nil, nil 54 } 55 56 func getBlkioWriteIOpsDevices(config *containertypes.HostConfig) ([]blkiodev.ThrottleDevice, error) { 57 return nil, nil 58 } 59 60 func getBlkioReadBpsDevices(config *containertypes.HostConfig) ([]blkiodev.ThrottleDevice, error) { 61 return nil, nil 62 } 63 64 func getBlkioWriteBpsDevices(config *containertypes.HostConfig) ([]blkiodev.ThrottleDevice, error) { 65 return nil, nil 66 } 67 68 func setupInitLayer(initLayer string, rootUID, rootGID int) error { 69 return nil 70 } 71 72 func checkKernel() error { 73 return nil 74 } 75 76 func (daemon *Daemon) getCgroupDriver() string { 77 return "" 78 } 79 80 // adaptContainerSettings is called during container creation to modify any 81 // settings necessary in the HostConfig structure. 82 func (daemon *Daemon) adaptContainerSettings(hostConfig *containertypes.HostConfig, adjustCPUShares bool) error { 83 if hostConfig == nil { 84 return nil 85 } 86 87 if hostConfig.CPUShares < 0 { 88 logrus.Warnf("Changing requested CPUShares of %d to minimum allowed of %d", hostConfig.CPUShares, windowsMinCPUShares) 89 hostConfig.CPUShares = windowsMinCPUShares 90 } else if hostConfig.CPUShares > windowsMaxCPUShares { 91 logrus.Warnf("Changing requested CPUShares of %d to maximum allowed of %d", hostConfig.CPUShares, windowsMaxCPUShares) 92 hostConfig.CPUShares = windowsMaxCPUShares 93 } 94 95 return nil 96 } 97 98 func verifyContainerResources(resources *containertypes.Resources, sysInfo *sysinfo.SysInfo) ([]string, error) { 99 warnings := []string{} 100 101 // cpu subsystem checks and adjustments 102 if resources.CPUPercent < 0 || resources.CPUPercent > 100 { 103 return warnings, fmt.Errorf("Range of CPU percent is from 1 to 100") 104 } 105 106 if resources.CPUPercent > 0 && resources.CPUShares > 0 { 107 return warnings, fmt.Errorf("Conflicting options: CPU Shares and CPU Percent cannot both be set") 108 } 109 110 // TODO Windows: Add more validation of resource settings not supported on Windows 111 112 if resources.BlkioWeight > 0 { 113 warnings = append(warnings, "Windows does not support Block I/O weight. Weight discarded.") 114 logrus.Warn("Windows does not support Block I/O weight. --blkio-weight discarded.") 115 resources.BlkioWeight = 0 116 } 117 if len(resources.BlkioWeightDevice) > 0 { 118 warnings = append(warnings, "Windows does not support Block I/O weight_device.") 119 logrus.Warn("Windows does not support Block I/O weight_device. --blkio-weight-device discarded.") 120 resources.BlkioWeightDevice = []*pblkiodev.WeightDevice{} 121 } 122 if len(resources.BlkioDeviceReadBps) > 0 { 123 warnings = append(warnings, "Windows does not support Block read limit in bytes per second.") 124 logrus.Warn("Windows does not support Block I/O read limit in bytes per second. --device-read-bps discarded.") 125 resources.BlkioDeviceReadBps = []*pblkiodev.ThrottleDevice{} 126 } 127 if len(resources.BlkioDeviceWriteBps) > 0 { 128 warnings = append(warnings, "Windows does not support Block write limit in bytes per second.") 129 logrus.Warn("Windows does not support Block I/O write limit in bytes per second. --device-write-bps discarded.") 130 resources.BlkioDeviceWriteBps = []*pblkiodev.ThrottleDevice{} 131 } 132 if len(resources.BlkioDeviceReadIOps) > 0 { 133 warnings = append(warnings, "Windows does not support Block read limit in IO per second.") 134 logrus.Warn("Windows does not support Block I/O read limit in IO per second. -device-read-iops discarded.") 135 resources.BlkioDeviceReadIOps = []*pblkiodev.ThrottleDevice{} 136 } 137 if len(resources.BlkioDeviceWriteIOps) > 0 { 138 warnings = append(warnings, "Windows does not support Block write limit in IO per second.") 139 logrus.Warn("Windows does not support Block I/O write limit in IO per second. --device-write-iops discarded.") 140 resources.BlkioDeviceWriteIOps = []*pblkiodev.ThrottleDevice{} 141 } 142 return warnings, nil 143 } 144 145 // verifyPlatformContainerSettings performs platform-specific validation of the 146 // hostconfig and config structures. 147 func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes.HostConfig, config *containertypes.Config, update bool) ([]string, error) { 148 warnings := []string{} 149 150 w, err := verifyContainerResources(&hostConfig.Resources, nil) 151 warnings = append(warnings, w...) 152 if err != nil { 153 return warnings, err 154 } 155 156 return warnings, nil 157 } 158 159 // platformReload update configuration with platform specific options 160 func (daemon *Daemon) platformReload(config *Config, attributes *map[string]string) { 161 } 162 163 // verifyDaemonSettings performs validation of daemon config struct 164 func verifyDaemonSettings(config *Config) error { 165 return nil 166 } 167 168 // checkSystem validates platform-specific requirements 169 func checkSystem() error { 170 // Validate the OS version. Note that docker.exe must be manifested for this 171 // call to return the correct version. 172 osv := system.GetOSVersion() 173 if osv.MajorVersion < 10 { 174 return fmt.Errorf("This version of Windows does not support the docker daemon") 175 } 176 if osv.Build < 14300 { 177 return fmt.Errorf("The Windows daemon requires Windows Server 2016 Technical Preview 5 build 14300 or later") 178 } 179 return nil 180 } 181 182 // configureKernelSecuritySupport configures and validate security support for the kernel 183 func configureKernelSecuritySupport(config *Config, driverName string) error { 184 return nil 185 } 186 187 // configureMaxThreads sets the Go runtime max threads threshold 188 func configureMaxThreads(config *Config) error { 189 return nil 190 } 191 192 func (daemon *Daemon) initNetworkController(config *Config, activeSandboxes map[string]interface{}) (libnetwork.NetworkController, error) { 193 netOptions, err := daemon.networkOptions(config, nil) 194 if err != nil { 195 return nil, err 196 } 197 controller, err := libnetwork.New(netOptions...) 198 if err != nil { 199 return nil, fmt.Errorf("error obtaining controller instance: %v", err) 200 } 201 202 hnsresponse, err := hcsshim.HNSListNetworkRequest("GET", "", "") 203 if err != nil { 204 return nil, err 205 } 206 207 // Remove networks not present in HNS 208 for _, v := range controller.Networks() { 209 options := v.Info().DriverOptions() 210 hnsid := options[winlibnetwork.HNSID] 211 found := false 212 213 for _, v := range hnsresponse { 214 if v.Id == hnsid { 215 found = true 216 break 217 } 218 } 219 220 if !found { 221 err = v.Delete() 222 if err != nil { 223 return nil, err 224 } 225 } 226 } 227 228 _, err = controller.NewNetwork("null", "none", "", libnetwork.NetworkOptionPersist(false)) 229 if err != nil { 230 return nil, err 231 } 232 233 // discover and add HNS networks to windows 234 // network that exist are removed and added again 235 for _, v := range hnsresponse { 236 var n libnetwork.Network 237 s := func(current libnetwork.Network) bool { 238 options := current.Info().DriverOptions() 239 if options[winlibnetwork.HNSID] == v.Id { 240 n = current 241 return true 242 } 243 return false 244 } 245 246 controller.WalkNetworks(s) 247 if n != nil { 248 v.Name = n.Name() 249 n.Delete() 250 } 251 252 netOption := map[string]string{ 253 winlibnetwork.NetworkName: v.Name, 254 winlibnetwork.HNSID: v.Id, 255 } 256 257 v4Conf := []*libnetwork.IpamConf{} 258 for _, subnet := range v.Subnets { 259 ipamV4Conf := libnetwork.IpamConf{} 260 ipamV4Conf.PreferredPool = subnet.AddressPrefix 261 ipamV4Conf.Gateway = subnet.GatewayAddress 262 v4Conf = append(v4Conf, &ipamV4Conf) 263 } 264 265 name := v.Name 266 // There is only one nat network supported in windows. 267 // If it exists with a different name add it as the default name 268 if runconfig.DefaultDaemonNetworkMode() == containertypes.NetworkMode(strings.ToLower(v.Type)) { 269 name = runconfig.DefaultDaemonNetworkMode().NetworkName() 270 } 271 272 v6Conf := []*libnetwork.IpamConf{} 273 _, err := controller.NewNetwork(strings.ToLower(v.Type), name, "", 274 libnetwork.NetworkOptionGeneric(options.Generic{ 275 netlabel.GenericData: netOption, 276 }), 277 libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf, nil), 278 ) 279 280 if err != nil { 281 logrus.Errorf("Error occurred when creating network %v", err) 282 } 283 } 284 285 if !config.DisableBridge { 286 // Initialize default driver "bridge" 287 if err := initBridgeDriver(controller, config); err != nil { 288 return nil, err 289 } 290 } 291 292 return controller, nil 293 } 294 295 func initBridgeDriver(controller libnetwork.NetworkController, config *Config) error { 296 if _, err := controller.NetworkByName(runconfig.DefaultDaemonNetworkMode().NetworkName()); err == nil { 297 return nil 298 } 299 300 netOption := map[string]string{ 301 winlibnetwork.NetworkName: runconfig.DefaultDaemonNetworkMode().NetworkName(), 302 } 303 304 ipamV4Conf := libnetwork.IpamConf{} 305 if config.bridgeConfig.FixedCIDR == "" { 306 ipamV4Conf.PreferredPool = defaultNetworkSpace 307 } else { 308 ipamV4Conf.PreferredPool = config.bridgeConfig.FixedCIDR 309 } 310 311 v4Conf := []*libnetwork.IpamConf{&ipamV4Conf} 312 v6Conf := []*libnetwork.IpamConf{} 313 314 _, err := controller.NewNetwork(string(runconfig.DefaultDaemonNetworkMode()), runconfig.DefaultDaemonNetworkMode().NetworkName(), "", 315 libnetwork.NetworkOptionGeneric(options.Generic{ 316 netlabel.GenericData: netOption, 317 }), 318 libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf, nil), 319 ) 320 321 if err != nil { 322 return fmt.Errorf("Error creating default network: %v", err) 323 } 324 return nil 325 } 326 327 // registerLinks sets up links between containers and writes the 328 // configuration out for persistence. As of Windows TP4, links are not supported. 329 func (daemon *Daemon) registerLinks(container *container.Container, hostConfig *containertypes.HostConfig) error { 330 return nil 331 } 332 333 func (daemon *Daemon) cleanupMountsByID(in string) error { 334 return nil 335 } 336 337 func (daemon *Daemon) cleanupMounts() error { 338 return nil 339 } 340 341 func setupRemappedRoot(config *Config) ([]idtools.IDMap, []idtools.IDMap, error) { 342 return nil, nil, nil 343 } 344 345 func setupDaemonRoot(config *Config, rootDir string, rootUID, rootGID int) error { 346 config.Root = rootDir 347 // Create the root directory if it doesn't exists 348 if err := system.MkdirAll(config.Root, 0700); err != nil && !os.IsExist(err) { 349 return err 350 } 351 return nil 352 } 353 354 // runasHyperVContainer returns true if we are going to run as a Hyper-V container 355 func (daemon *Daemon) runAsHyperVContainer(container *container.Container) bool { 356 if container.HostConfig.Isolation.IsDefault() { 357 // Container is set to use the default, so take the default from the daemon configuration 358 return daemon.defaultIsolation.IsHyperV() 359 } 360 361 // Container is requesting an isolation mode. Honour it. 362 return container.HostConfig.Isolation.IsHyperV() 363 364 } 365 366 // conditionalMountOnStart is a platform specific helper function during the 367 // container start to call mount. 368 func (daemon *Daemon) conditionalMountOnStart(container *container.Container) error { 369 // We do not mount if a Hyper-V container 370 if !daemon.runAsHyperVContainer(container) { 371 return daemon.Mount(container) 372 } 373 return nil 374 } 375 376 // conditionalUnmountOnCleanup is a platform specific helper function called 377 // during the cleanup of a container to unmount. 378 func (daemon *Daemon) conditionalUnmountOnCleanup(container *container.Container) error { 379 // We do not unmount if a Hyper-V container 380 if !daemon.runAsHyperVContainer(container) { 381 return daemon.Unmount(container) 382 } 383 return nil 384 } 385 386 func restoreCustomImage(is image.Store, ls layer.Store, rs reference.Store) error { 387 type graphDriverStore interface { 388 GraphDriver() graphdriver.Driver 389 } 390 391 gds, ok := ls.(graphDriverStore) 392 if !ok { 393 return nil 394 } 395 396 driver := gds.GraphDriver() 397 wd, ok := driver.(*windows.Driver) 398 if !ok { 399 return nil 400 } 401 402 imageInfos, err := wd.GetCustomImageInfos() 403 if err != nil { 404 return err 405 } 406 407 // Convert imageData to valid image configuration 408 for _, info := range imageInfos { 409 name := strings.ToLower(info.Name) 410 411 type registrar interface { 412 RegisterDiffID(graphID string, size int64) (layer.Layer, error) 413 } 414 r, ok := ls.(registrar) 415 if !ok { 416 return errors.New("Layerstore doesn't support RegisterDiffID") 417 } 418 if _, err := r.RegisterDiffID(info.ID, info.Size); err != nil { 419 return err 420 } 421 // layer is intentionally not released 422 423 rootFS := image.NewRootFSWithBaseLayer(filepath.Base(info.Path)) 424 425 // Create history for base layer 426 config, err := json.Marshal(&image.Image{ 427 V1Image: image.V1Image{ 428 DockerVersion: dockerversion.Version, 429 Architecture: runtime.GOARCH, 430 OS: runtime.GOOS, 431 Created: info.CreatedTime, 432 }, 433 RootFS: rootFS, 434 History: []image.History{}, 435 OSVersion: info.OSVersion, 436 OSFeatures: info.OSFeatures, 437 }) 438 439 named, err := reference.ParseNamed(name) 440 if err != nil { 441 return err 442 } 443 444 ref, err := reference.WithTag(named, info.Version) 445 if err != nil { 446 return err 447 } 448 449 id, err := is.Create(config) 450 if err != nil { 451 logrus.Warnf("Failed to restore custom image %s with error: %s.", name, err) 452 logrus.Warnf("Skipping image %s...", name) 453 continue 454 } 455 456 if err := rs.AddTag(ref, id, true); err != nil { 457 return err 458 } 459 460 logrus.Debugf("Registered base layer %s as %s", ref, id) 461 } 462 return nil 463 } 464 465 func driverOptions(config *Config) []nwconfig.Option { 466 return []nwconfig.Option{} 467 } 468 469 func (daemon *Daemon) stats(c *container.Container) (*types.StatsJSON, error) { 470 return nil, nil 471 } 472 473 // setDefaultIsolation determine the default isolation mode for the 474 // daemon to run in. This is only applicable on Windows 475 func (daemon *Daemon) setDefaultIsolation() error { 476 daemon.defaultIsolation = containertypes.Isolation("process") 477 // On client SKUs, default to Hyper-V 478 if system.IsWindowsClient() { 479 daemon.defaultIsolation = containertypes.Isolation("hyperv") 480 } 481 for _, option := range daemon.configStore.ExecOptions { 482 key, val, err := parsers.ParseKeyValueOpt(option) 483 if err != nil { 484 return err 485 } 486 key = strings.ToLower(key) 487 switch key { 488 489 case "isolation": 490 if !containertypes.Isolation(val).IsValid() { 491 return fmt.Errorf("Invalid exec-opt value for 'isolation':'%s'", val) 492 } 493 if containertypes.Isolation(val).IsHyperV() { 494 daemon.defaultIsolation = containertypes.Isolation("hyperv") 495 } 496 if containertypes.Isolation(val).IsProcess() { 497 if system.IsWindowsClient() { 498 return fmt.Errorf("Windows client operating systems only support Hyper-V containers") 499 } 500 daemon.defaultIsolation = containertypes.Isolation("process") 501 } 502 default: 503 return fmt.Errorf("Unrecognised exec-opt '%s'\n", key) 504 } 505 } 506 507 logrus.Infof("Windows default isolation mode: %s", daemon.defaultIsolation) 508 return nil 509 } 510 511 func rootFSToAPIType(rootfs *image.RootFS) types.RootFS { 512 var layers []string 513 for _, l := range rootfs.DiffIDs { 514 layers = append(layers, l.String()) 515 } 516 return types.RootFS{ 517 Type: rootfs.Type, 518 Layers: layers, 519 BaseLayer: rootfs.BaseLayer, 520 } 521 } 522 523 func setupDaemonProcess(config *Config) error { 524 return nil 525 }