github.com/brahmaroutu/docker@v1.2.1-0.20160809185609-eb28dde01f16/daemon/daemon_unix.go (about) 1 // +build linux freebsd 2 3 package daemon 4 5 import ( 6 "bytes" 7 "fmt" 8 "io/ioutil" 9 "net" 10 "os" 11 "path/filepath" 12 "runtime" 13 "runtime/debug" 14 "strconv" 15 "strings" 16 "syscall" 17 18 "github.com/Sirupsen/logrus" 19 "github.com/docker/docker/container" 20 "github.com/docker/docker/image" 21 "github.com/docker/docker/pkg/idtools" 22 "github.com/docker/docker/pkg/parsers" 23 "github.com/docker/docker/pkg/parsers/kernel" 24 "github.com/docker/docker/pkg/sysinfo" 25 "github.com/docker/docker/runconfig" 26 runconfigopts "github.com/docker/docker/runconfig/opts" 27 "github.com/docker/engine-api/types" 28 "github.com/docker/engine-api/types/blkiodev" 29 pblkiodev "github.com/docker/engine-api/types/blkiodev" 30 containertypes "github.com/docker/engine-api/types/container" 31 "github.com/docker/libnetwork" 32 nwconfig "github.com/docker/libnetwork/config" 33 "github.com/docker/libnetwork/drivers/bridge" 34 "github.com/docker/libnetwork/netlabel" 35 "github.com/docker/libnetwork/netutils" 36 "github.com/docker/libnetwork/options" 37 lntypes "github.com/docker/libnetwork/types" 38 "github.com/golang/protobuf/ptypes" 39 "github.com/opencontainers/runc/libcontainer/label" 40 "github.com/opencontainers/runc/libcontainer/user" 41 "github.com/opencontainers/specs/specs-go" 42 ) 43 44 const ( 45 // See https://git.kernel.org/cgit/linux/kernel/git/tip/tip.git/tree/kernel/sched/sched.h?id=8cd9234c64c584432f6992fe944ca9e46ca8ea76#n269 46 linuxMinCPUShares = 2 47 linuxMaxCPUShares = 262144 48 platformSupported = true 49 // It's not kernel limit, we want this 4M limit to supply a reasonable functional container 50 linuxMinMemory = 4194304 51 // constants for remapped root settings 52 defaultIDSpecifier string = "default" 53 defaultRemappedID string = "dockremap" 54 55 // constant for cgroup drivers 56 cgroupFsDriver = "cgroupfs" 57 cgroupSystemdDriver = "systemd" 58 ) 59 60 func getMemoryResources(config containertypes.Resources) *specs.Memory { 61 memory := specs.Memory{} 62 63 if config.Memory > 0 { 64 limit := uint64(config.Memory) 65 memory.Limit = &limit 66 } 67 68 if config.MemoryReservation > 0 { 69 reservation := uint64(config.MemoryReservation) 70 memory.Reservation = &reservation 71 } 72 73 if config.MemorySwap != 0 { 74 swap := uint64(config.MemorySwap) 75 memory.Swap = &swap 76 } 77 78 if config.MemorySwappiness != nil { 79 swappiness := uint64(*config.MemorySwappiness) 80 memory.Swappiness = &swappiness 81 } 82 83 if config.KernelMemory != 0 { 84 kernelMemory := uint64(config.KernelMemory) 85 memory.Kernel = &kernelMemory 86 } 87 88 return &memory 89 } 90 91 func getCPUResources(config containertypes.Resources) *specs.CPU { 92 cpu := specs.CPU{} 93 94 if config.CPUShares != 0 { 95 shares := uint64(config.CPUShares) 96 cpu.Shares = &shares 97 } 98 99 if config.CpusetCpus != "" { 100 cpuset := config.CpusetCpus 101 cpu.Cpus = &cpuset 102 } 103 104 if config.CpusetMems != "" { 105 cpuset := config.CpusetMems 106 cpu.Mems = &cpuset 107 } 108 109 if config.CPUPeriod != 0 { 110 period := uint64(config.CPUPeriod) 111 cpu.Period = &period 112 } 113 114 if config.CPUQuota != 0 { 115 quota := uint64(config.CPUQuota) 116 cpu.Quota = "a 117 } 118 119 return &cpu 120 } 121 122 func getBlkioWeightDevices(config containertypes.Resources) ([]specs.WeightDevice, error) { 123 var stat syscall.Stat_t 124 var blkioWeightDevices []specs.WeightDevice 125 126 for _, weightDevice := range config.BlkioWeightDevice { 127 if err := syscall.Stat(weightDevice.Path, &stat); err != nil { 128 return nil, err 129 } 130 weight := weightDevice.Weight 131 d := specs.WeightDevice{Weight: &weight} 132 d.Major = int64(stat.Rdev / 256) 133 d.Minor = int64(stat.Rdev % 256) 134 blkioWeightDevices = append(blkioWeightDevices, d) 135 } 136 137 return blkioWeightDevices, nil 138 } 139 140 func parseSecurityOpt(container *container.Container, config *containertypes.HostConfig) error { 141 var ( 142 labelOpts []string 143 err error 144 ) 145 146 for _, opt := range config.SecurityOpt { 147 if opt == "no-new-privileges" { 148 container.NoNewPrivileges = true 149 } else { 150 var con []string 151 if strings.Contains(opt, "=") { 152 con = strings.SplitN(opt, "=", 2) 153 } else if strings.Contains(opt, ":") { 154 con = strings.SplitN(opt, ":", 2) 155 logrus.Warn("Security options with `:` as a separator are deprecated and will be completely unsupported in 1.13, use `=` instead.") 156 } 157 158 if len(con) != 2 { 159 return fmt.Errorf("Invalid --security-opt 1: %q", opt) 160 } 161 162 switch con[0] { 163 case "label": 164 labelOpts = append(labelOpts, con[1]) 165 case "apparmor": 166 container.AppArmorProfile = con[1] 167 case "seccomp": 168 container.SeccompProfile = con[1] 169 default: 170 return fmt.Errorf("Invalid --security-opt 2: %q", opt) 171 } 172 } 173 } 174 175 container.ProcessLabel, container.MountLabel, err = label.InitLabels(labelOpts) 176 return err 177 } 178 179 func getBlkioThrottleDevices(devs []*blkiodev.ThrottleDevice) ([]specs.ThrottleDevice, error) { 180 var throttleDevices []specs.ThrottleDevice 181 var stat syscall.Stat_t 182 183 for _, d := range devs { 184 if err := syscall.Stat(d.Path, &stat); err != nil { 185 return nil, err 186 } 187 rate := d.Rate 188 d := specs.ThrottleDevice{Rate: &rate} 189 d.Major = int64(stat.Rdev / 256) 190 d.Minor = int64(stat.Rdev % 256) 191 throttleDevices = append(throttleDevices, d) 192 } 193 194 return throttleDevices, nil 195 } 196 197 func checkKernel() error { 198 // Check for unsupported kernel versions 199 // FIXME: it would be cleaner to not test for specific versions, but rather 200 // test for specific functionalities. 201 // Unfortunately we can't test for the feature "does not cause a kernel panic" 202 // without actually causing a kernel panic, so we need this workaround until 203 // the circumstances of pre-3.10 crashes are clearer. 204 // For details see https://github.com/docker/docker/issues/407 205 // Docker 1.11 and above doesn't actually run on kernels older than 3.4, 206 // due to containerd-shim usage of PR_SET_CHILD_SUBREAPER (introduced in 3.4). 207 if !kernel.CheckKernelVersion(3, 10, 0) { 208 v, _ := kernel.GetKernelVersion() 209 if os.Getenv("DOCKER_NOWARN_KERNEL_VERSION") == "" { 210 logrus.Fatalf("Your Linux kernel version %s is not supported for running docker. Please upgrade your kernel to 3.10.0 or newer.", v.String()) 211 } 212 } 213 return nil 214 } 215 216 // adaptContainerSettings is called during container creation to modify any 217 // settings necessary in the HostConfig structure. 218 func (daemon *Daemon) adaptContainerSettings(hostConfig *containertypes.HostConfig, adjustCPUShares bool) error { 219 if adjustCPUShares && hostConfig.CPUShares > 0 { 220 // Handle unsupported CPUShares 221 if hostConfig.CPUShares < linuxMinCPUShares { 222 logrus.Warnf("Changing requested CPUShares of %d to minimum allowed of %d", hostConfig.CPUShares, linuxMinCPUShares) 223 hostConfig.CPUShares = linuxMinCPUShares 224 } else if hostConfig.CPUShares > linuxMaxCPUShares { 225 logrus.Warnf("Changing requested CPUShares of %d to maximum allowed of %d", hostConfig.CPUShares, linuxMaxCPUShares) 226 hostConfig.CPUShares = linuxMaxCPUShares 227 } 228 } 229 if hostConfig.Memory > 0 && hostConfig.MemorySwap == 0 { 230 // By default, MemorySwap is set to twice the size of Memory. 231 hostConfig.MemorySwap = hostConfig.Memory * 2 232 } 233 if hostConfig.ShmSize == 0 { 234 hostConfig.ShmSize = container.DefaultSHMSize 235 } 236 var err error 237 if hostConfig.SecurityOpt == nil { 238 hostConfig.SecurityOpt, err = daemon.generateSecurityOpt(hostConfig.IpcMode, hostConfig.PidMode, hostConfig.Privileged) 239 if err != nil { 240 return err 241 } 242 } 243 if hostConfig.MemorySwappiness == nil { 244 defaultSwappiness := int64(-1) 245 hostConfig.MemorySwappiness = &defaultSwappiness 246 } 247 if hostConfig.OomKillDisable == nil { 248 defaultOomKillDisable := false 249 hostConfig.OomKillDisable = &defaultOomKillDisable 250 } 251 252 return nil 253 } 254 255 func verifyContainerResources(resources *containertypes.Resources, sysInfo *sysinfo.SysInfo, update bool) ([]string, error) { 256 warnings := []string{} 257 258 // memory subsystem checks and adjustments 259 if resources.Memory != 0 && resources.Memory < linuxMinMemory { 260 return warnings, fmt.Errorf("Minimum memory limit allowed is 4MB") 261 } 262 if resources.Memory > 0 && !sysInfo.MemoryLimit { 263 warnings = append(warnings, "Your kernel does not support memory limit capabilities or the cgroup is not mounted. Limitation discarded.") 264 logrus.Warn("Your kernel does not support memory limit capabilities or the cgroup is not mounted. Limitation discarded.") 265 resources.Memory = 0 266 resources.MemorySwap = -1 267 } 268 if resources.Memory > 0 && resources.MemorySwap != -1 && !sysInfo.SwapLimit { 269 warnings = append(warnings, "Your kernel does not support swap limit capabilities or the cgroup is not mounted. Memory limited without swap.") 270 logrus.Warn("Your kernel does not support swap limit capabilities,or the cgroup is not mounted. Memory limited without swap.") 271 resources.MemorySwap = -1 272 } 273 if resources.Memory > 0 && resources.MemorySwap > 0 && resources.MemorySwap < resources.Memory { 274 return warnings, fmt.Errorf("Minimum memoryswap limit should be larger than memory limit, see usage") 275 } 276 if resources.Memory == 0 && resources.MemorySwap > 0 && !update { 277 return warnings, fmt.Errorf("You should always set the Memory limit when using Memoryswap limit, see usage") 278 } 279 if resources.MemorySwappiness != nil && *resources.MemorySwappiness != -1 && !sysInfo.MemorySwappiness { 280 warnings = append(warnings, "Your kernel does not support memory swappiness capabilities or the cgroup is not mounted. Memory swappiness discarded.") 281 logrus.Warn("Your kernel does not support memory swappiness capabilities, or the cgroup is not mounted. Memory swappiness discarded.") 282 resources.MemorySwappiness = nil 283 } 284 if resources.MemorySwappiness != nil { 285 swappiness := *resources.MemorySwappiness 286 if swappiness < -1 || swappiness > 100 { 287 return warnings, fmt.Errorf("Invalid value: %v, valid memory swappiness range is 0-100", swappiness) 288 } 289 } 290 if resources.MemoryReservation > 0 && !sysInfo.MemoryReservation { 291 warnings = append(warnings, "Your kernel does not support memory soft limit capabilities or the cgroup is not mounted. Limitation discarded.") 292 logrus.Warn("Your kernel does not support memory soft limit capabilities or the cgroup is not mounted. Limitation discarded.") 293 resources.MemoryReservation = 0 294 } 295 if resources.MemoryReservation > 0 && resources.MemoryReservation < linuxMinMemory { 296 return warnings, fmt.Errorf("Minimum memory reservation allowed is 4MB") 297 } 298 if resources.Memory > 0 && resources.MemoryReservation > 0 && resources.Memory < resources.MemoryReservation { 299 return warnings, fmt.Errorf("Minimum memory limit can not be less than memory reservation limit, see usage") 300 } 301 if resources.KernelMemory > 0 && !sysInfo.KernelMemory { 302 warnings = append(warnings, "Your kernel does not support kernel memory limit capabilities or the cgroup is not mounted. Limitation discarded.") 303 logrus.Warn("Your kernel does not support kernel memory limit capabilities or the cgroup is not mounted. Limitation discarded.") 304 resources.KernelMemory = 0 305 } 306 if resources.KernelMemory > 0 && resources.KernelMemory < linuxMinMemory { 307 return warnings, fmt.Errorf("Minimum kernel memory limit allowed is 4MB") 308 } 309 if resources.KernelMemory > 0 && !kernel.CheckKernelVersion(4, 0, 0) { 310 warnings = append(warnings, "You specified a kernel memory limit on a kernel older than 4.0. Kernel memory limits are experimental on older kernels, it won't work as expected and can cause your system to be unstable.") 311 logrus.Warn("You specified a kernel memory limit on a kernel older than 4.0. Kernel memory limits are experimental on older kernels, it won't work as expected and can cause your system to be unstable.") 312 } 313 if resources.OomKillDisable != nil && !sysInfo.OomKillDisable { 314 // only produce warnings if the setting wasn't to *disable* the OOM Kill; no point 315 // warning the caller if they already wanted the feature to be off 316 if *resources.OomKillDisable { 317 warnings = append(warnings, "Your kernel does not support OomKillDisable. OomKillDisable discarded.") 318 logrus.Warn("Your kernel does not support OomKillDisable. OomKillDisable discarded.") 319 } 320 resources.OomKillDisable = nil 321 } 322 323 if resources.PidsLimit != 0 && !sysInfo.PidsLimit { 324 warnings = append(warnings, "Your kernel does not support pids limit capabilities or the cgroup is not mounted. PIDs limit discarded.") 325 logrus.Warn("Your kernel does not support pids limit capabilities or the cgroup is not mounted. PIDs limit discarded.") 326 resources.PidsLimit = 0 327 } 328 329 // cpu subsystem checks and adjustments 330 if resources.CPUShares > 0 && !sysInfo.CPUShares { 331 warnings = append(warnings, "Your kernel does not support CPU shares or the cgroup is not mounted. Shares discarded.") 332 logrus.Warn("Your kernel does not support CPU shares or the cgroup is not mounted. Shares discarded.") 333 resources.CPUShares = 0 334 } 335 if resources.CPUPeriod > 0 && !sysInfo.CPUCfsPeriod { 336 warnings = append(warnings, "Your kernel does not support CPU cfs period or the cgroup is not mounted. Period discarded.") 337 logrus.Warn("Your kernel does not support CPU cfs period or the cgroup is not mounted. Period discarded.") 338 resources.CPUPeriod = 0 339 } 340 if resources.CPUPeriod != 0 && (resources.CPUPeriod < 1000 || resources.CPUPeriod > 1000000) { 341 return warnings, fmt.Errorf("CPU cfs period can not be less than 1ms (i.e. 1000) or larger than 1s (i.e. 1000000)") 342 } 343 if resources.CPUQuota > 0 && !sysInfo.CPUCfsQuota { 344 warnings = append(warnings, "Your kernel does not support CPU cfs quota or the cgroup is not mounted. Quota discarded.") 345 logrus.Warn("Your kernel does not support CPU cfs quota or the cgroup is not mounted. Quota discarded.") 346 resources.CPUQuota = 0 347 } 348 if resources.CPUQuota > 0 && resources.CPUQuota < 1000 { 349 return warnings, fmt.Errorf("CPU cfs quota can not be less than 1ms (i.e. 1000)") 350 } 351 if resources.CPUPercent > 0 { 352 warnings = append(warnings, "%s does not support CPU percent. Percent discarded.", runtime.GOOS) 353 logrus.Warnf("%s does not support CPU percent. Percent discarded.", runtime.GOOS) 354 resources.CPUPercent = 0 355 } 356 357 // cpuset subsystem checks and adjustments 358 if (resources.CpusetCpus != "" || resources.CpusetMems != "") && !sysInfo.Cpuset { 359 warnings = append(warnings, "Your kernel does not support cpuset or the cgroup is not mounted. Cpuset discarded.") 360 logrus.Warn("Your kernel does not support cpuset or the cgroup is not mounted. Cpuset discarded.") 361 resources.CpusetCpus = "" 362 resources.CpusetMems = "" 363 } 364 cpusAvailable, err := sysInfo.IsCpusetCpusAvailable(resources.CpusetCpus) 365 if err != nil { 366 return warnings, fmt.Errorf("Invalid value %s for cpuset cpus", resources.CpusetCpus) 367 } 368 if !cpusAvailable { 369 return warnings, fmt.Errorf("Requested CPUs are not available - requested %s, available: %s", resources.CpusetCpus, sysInfo.Cpus) 370 } 371 memsAvailable, err := sysInfo.IsCpusetMemsAvailable(resources.CpusetMems) 372 if err != nil { 373 return warnings, fmt.Errorf("Invalid value %s for cpuset mems", resources.CpusetMems) 374 } 375 if !memsAvailable { 376 return warnings, fmt.Errorf("Requested memory nodes are not available - requested %s, available: %s", resources.CpusetMems, sysInfo.Mems) 377 } 378 379 // blkio subsystem checks and adjustments 380 if resources.BlkioWeight > 0 && !sysInfo.BlkioWeight { 381 warnings = append(warnings, "Your kernel does not support Block I/O weight or the cgroup is not mounted. Weight discarded.") 382 logrus.Warn("Your kernel does not support Block I/O weight or the cgroup is not mounted. Weight discarded.") 383 resources.BlkioWeight = 0 384 } 385 if resources.BlkioWeight > 0 && (resources.BlkioWeight < 10 || resources.BlkioWeight > 1000) { 386 return warnings, fmt.Errorf("Range of blkio weight is from 10 to 1000") 387 } 388 if resources.IOMaximumBandwidth != 0 || resources.IOMaximumIOps != 0 { 389 return warnings, fmt.Errorf("Invalid QoS settings: %s does not support Maximum IO Bandwidth or Maximum IO IOps", runtime.GOOS) 390 } 391 if len(resources.BlkioWeightDevice) > 0 && !sysInfo.BlkioWeightDevice { 392 warnings = append(warnings, "Your kernel does not support Block I/O weight_device or the cgroup is not mounted. Weight-device discarded.") 393 logrus.Warn("Your kernel does not support Block I/O weight_device or the cgroup is not mounted. Weight-device discarded.") 394 resources.BlkioWeightDevice = []*pblkiodev.WeightDevice{} 395 } 396 if len(resources.BlkioDeviceReadBps) > 0 && !sysInfo.BlkioReadBpsDevice { 397 warnings = append(warnings, "Your kernel does not support BPS Block I/O read limit or the cgroup is not mounted. Block I/O BPS read limit discarded.") 398 logrus.Warn("Your kernel does not support BPS Block I/O read limit or the cgroup is not mounted. Block I/O BPS read limit discarded") 399 resources.BlkioDeviceReadBps = []*pblkiodev.ThrottleDevice{} 400 } 401 if len(resources.BlkioDeviceWriteBps) > 0 && !sysInfo.BlkioWriteBpsDevice { 402 warnings = append(warnings, "Your kernel does not support BPS Block I/O write limit or the cgroup is not mounted. Block I/O BPS write limit discarded.") 403 logrus.Warn("Your kernel does not support BPS Block I/O write limit or the cgroup is not mounted. Block I/O BPS write limit discarded.") 404 resources.BlkioDeviceWriteBps = []*pblkiodev.ThrottleDevice{} 405 } 406 if len(resources.BlkioDeviceReadIOps) > 0 && !sysInfo.BlkioReadIOpsDevice { 407 warnings = append(warnings, "Your kernel does not support IOPS Block read limit or the cgroup is not mounted. Block I/O IOPS read limit discarded.") 408 logrus.Warn("Your kernel does not support IOPS Block I/O read limit in IO or the cgroup is not mounted. Block I/O IOPS read limit discarded.") 409 resources.BlkioDeviceReadIOps = []*pblkiodev.ThrottleDevice{} 410 } 411 if len(resources.BlkioDeviceWriteIOps) > 0 && !sysInfo.BlkioWriteIOpsDevice { 412 warnings = append(warnings, "Your kernel does not support IOPS Block write limit or the cgroup is not mounted. Block I/O IOPS write limit discarded.") 413 logrus.Warn("Your kernel does not support IOPS Block I/O write limit or the cgroup is not mounted. Block I/O IOPS write limit discarded.") 414 resources.BlkioDeviceWriteIOps = []*pblkiodev.ThrottleDevice{} 415 } 416 417 return warnings, nil 418 } 419 420 func (daemon *Daemon) getCgroupDriver() string { 421 cgroupDriver := cgroupFsDriver 422 423 if UsingSystemd(daemon.configStore) { 424 cgroupDriver = cgroupSystemdDriver 425 } 426 return cgroupDriver 427 } 428 429 // getCD gets the raw value of the native.cgroupdriver option, if set. 430 func getCD(config *Config) string { 431 for _, option := range config.ExecOptions { 432 key, val, err := parsers.ParseKeyValueOpt(option) 433 if err != nil || !strings.EqualFold(key, "native.cgroupdriver") { 434 continue 435 } 436 return val 437 } 438 return "" 439 } 440 441 // VerifyCgroupDriver validates native.cgroupdriver 442 func VerifyCgroupDriver(config *Config) error { 443 cd := getCD(config) 444 if cd == "" || cd == cgroupFsDriver || cd == cgroupSystemdDriver { 445 return nil 446 } 447 return fmt.Errorf("native.cgroupdriver option %s not supported", cd) 448 } 449 450 // UsingSystemd returns true if cli option includes native.cgroupdriver=systemd 451 func UsingSystemd(config *Config) bool { 452 return getCD(config) == cgroupSystemdDriver 453 } 454 455 // verifyPlatformContainerSettings performs platform-specific validation of the 456 // hostconfig and config structures. 457 func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes.HostConfig, config *containertypes.Config, update bool) ([]string, error) { 458 warnings := []string{} 459 sysInfo := sysinfo.New(true) 460 461 warnings, err := daemon.verifyExperimentalContainerSettings(hostConfig, config) 462 if err != nil { 463 return warnings, err 464 } 465 466 w, err := verifyContainerResources(&hostConfig.Resources, sysInfo, update) 467 if err != nil { 468 return warnings, err 469 } 470 warnings = append(warnings, w...) 471 472 if hostConfig.ShmSize < 0 { 473 return warnings, fmt.Errorf("SHM size can not be less than 0") 474 } 475 476 if hostConfig.OomScoreAdj < -1000 || hostConfig.OomScoreAdj > 1000 { 477 return warnings, fmt.Errorf("Invalid value %d, range for oom score adj is [-1000, 1000]", hostConfig.OomScoreAdj) 478 } 479 480 // ip-forwarding does not affect container with '--net=host' (or '--net=none') 481 if sysInfo.IPv4ForwardingDisabled && !(hostConfig.NetworkMode.IsHost() || hostConfig.NetworkMode.IsNone()) { 482 warnings = append(warnings, "IPv4 forwarding is disabled. Networking will not work.") 483 logrus.Warn("IPv4 forwarding is disabled. Networking will not work") 484 } 485 // check for various conflicting options with user namespaces 486 if daemon.configStore.RemappedRoot != "" && hostConfig.UsernsMode.IsPrivate() { 487 if hostConfig.Privileged { 488 return warnings, fmt.Errorf("Privileged mode is incompatible with user namespaces") 489 } 490 if hostConfig.NetworkMode.IsHost() { 491 return warnings, fmt.Errorf("Cannot share the host's network namespace when user namespaces are enabled") 492 } 493 if hostConfig.PidMode.IsHost() { 494 return warnings, fmt.Errorf("Cannot share the host PID namespace when user namespaces are enabled") 495 } 496 if hostConfig.ReadonlyRootfs { 497 return warnings, fmt.Errorf("Cannot use the --read-only option when user namespaces are enabled") 498 } 499 } 500 if hostConfig.CgroupParent != "" && UsingSystemd(daemon.configStore) { 501 // CgroupParent for systemd cgroup should be named as "xxx.slice" 502 if len(hostConfig.CgroupParent) <= 6 || !strings.HasSuffix(hostConfig.CgroupParent, ".slice") { 503 return warnings, fmt.Errorf("cgroup-parent for systemd cgroup should be a valid slice named as \"xxx.slice\"") 504 } 505 } 506 if hostConfig.Runtime == "" { 507 hostConfig.Runtime = daemon.configStore.GetDefaultRuntimeName() 508 } 509 510 if rt := daemon.configStore.GetRuntime(hostConfig.Runtime); rt == nil { 511 return warnings, fmt.Errorf("Unknown runtime specified %s", hostConfig.Runtime) 512 } 513 514 return warnings, nil 515 } 516 517 // platformReload update configuration with platform specific options 518 func (daemon *Daemon) platformReload(config *Config, attributes *map[string]string) { 519 if config.IsValueSet("runtimes") { 520 daemon.configStore.Runtimes = config.Runtimes 521 // Always set the default one 522 daemon.configStore.Runtimes[stockRuntimeName] = types.Runtime{Path: DefaultRuntimeBinary} 523 } 524 525 if config.DefaultRuntime != "" { 526 daemon.configStore.DefaultRuntime = config.DefaultRuntime 527 } 528 529 // Update attributes 530 var runtimeList bytes.Buffer 531 for name, rt := range daemon.configStore.Runtimes { 532 if runtimeList.Len() > 0 { 533 runtimeList.WriteRune(' ') 534 } 535 runtimeList.WriteString(fmt.Sprintf("%s:%s", name, rt)) 536 } 537 538 (*attributes)["runtimes"] = runtimeList.String() 539 (*attributes)["default-runtime"] = daemon.configStore.DefaultRuntime 540 } 541 542 // verifyDaemonSettings performs validation of daemon config struct 543 func verifyDaemonSettings(config *Config) error { 544 // Check for mutually incompatible config options 545 if config.bridgeConfig.Iface != "" && config.bridgeConfig.IP != "" { 546 return fmt.Errorf("You specified -b & --bip, mutually exclusive options. Please specify only one") 547 } 548 if !config.bridgeConfig.EnableIPTables && !config.bridgeConfig.InterContainerCommunication { 549 return fmt.Errorf("You specified --iptables=false with --icc=false. ICC=false uses iptables to function. Please set --icc or --iptables to true") 550 } 551 if !config.bridgeConfig.EnableIPTables && config.bridgeConfig.EnableIPMasq { 552 config.bridgeConfig.EnableIPMasq = false 553 } 554 if err := VerifyCgroupDriver(config); err != nil { 555 return err 556 } 557 if config.CgroupParent != "" && UsingSystemd(config) { 558 if len(config.CgroupParent) <= 6 || !strings.HasSuffix(config.CgroupParent, ".slice") { 559 return fmt.Errorf("cgroup-parent for systemd cgroup should be a valid slice named as \"xxx.slice\"") 560 } 561 } 562 563 if config.DefaultRuntime == "" { 564 config.DefaultRuntime = stockRuntimeName 565 } 566 if config.Runtimes == nil { 567 config.Runtimes = make(map[string]types.Runtime) 568 } 569 stockRuntimeOpts := []string{} 570 if UsingSystemd(config) { 571 stockRuntimeOpts = append(stockRuntimeOpts, "--systemd-cgroup=true") 572 } 573 config.Runtimes[stockRuntimeName] = types.Runtime{Path: DefaultRuntimeBinary, Args: stockRuntimeOpts} 574 575 return nil 576 } 577 578 // checkSystem validates platform-specific requirements 579 func checkSystem() error { 580 if os.Geteuid() != 0 { 581 return fmt.Errorf("The Docker daemon needs to be run as root") 582 } 583 return checkKernel() 584 } 585 586 // configureMaxThreads sets the Go runtime max threads threshold 587 // which is 90% of the kernel setting from /proc/sys/kernel/threads-max 588 func configureMaxThreads(config *Config) error { 589 mt, err := ioutil.ReadFile("/proc/sys/kernel/threads-max") 590 if err != nil { 591 return err 592 } 593 mtint, err := strconv.Atoi(strings.TrimSpace(string(mt))) 594 if err != nil { 595 return err 596 } 597 maxThreads := (mtint / 100) * 90 598 debug.SetMaxThreads(maxThreads) 599 logrus.Debugf("Golang's threads limit set to %d", maxThreads) 600 return nil 601 } 602 603 // configureKernelSecuritySupport configures and validates security support for the kernel 604 func configureKernelSecuritySupport(config *Config, driverName string) error { 605 if config.EnableSelinuxSupport { 606 if selinuxEnabled() { 607 // As Docker on overlayFS and SELinux are incompatible at present, error on overlayfs being enabled 608 if driverName == "overlay" { 609 return fmt.Errorf("SELinux is not supported with the %s graph driver", driverName) 610 } 611 logrus.Debug("SELinux enabled successfully") 612 } else { 613 logrus.Warn("Docker could not enable SELinux on the host system") 614 } 615 } else { 616 selinuxSetDisabled() 617 } 618 return nil 619 } 620 621 func (daemon *Daemon) initNetworkController(config *Config, activeSandboxes map[string]interface{}) (libnetwork.NetworkController, error) { 622 netOptions, err := daemon.networkOptions(config, activeSandboxes) 623 if err != nil { 624 return nil, err 625 } 626 627 controller, err := libnetwork.New(netOptions...) 628 if err != nil { 629 return nil, fmt.Errorf("error obtaining controller instance: %v", err) 630 } 631 632 if len(activeSandboxes) > 0 { 633 logrus.Infof("There are old running containers, the network config will not take affect") 634 return controller, nil 635 } 636 637 // Initialize default network on "null" 638 if n, _ := controller.NetworkByName("none"); n == nil { 639 if _, err := controller.NewNetwork("null", "none", "", libnetwork.NetworkOptionPersist(true)); err != nil { 640 return nil, fmt.Errorf("Error creating default \"null\" network: %v", err) 641 } 642 } 643 644 // Initialize default network on "host" 645 if n, _ := controller.NetworkByName("host"); n == nil { 646 if _, err := controller.NewNetwork("host", "host", "", libnetwork.NetworkOptionPersist(true)); err != nil { 647 return nil, fmt.Errorf("Error creating default \"host\" network: %v", err) 648 } 649 } 650 if !config.DisableBridge { 651 // Initialize default driver "bridge" 652 if err := initBridgeDriver(controller, config); err != nil { 653 return nil, err 654 } 655 } 656 657 return controller, nil 658 } 659 660 func driverOptions(config *Config) []nwconfig.Option { 661 bridgeConfig := options.Generic{ 662 "EnableIPForwarding": config.bridgeConfig.EnableIPForward, 663 "EnableIPTables": config.bridgeConfig.EnableIPTables, 664 "EnableUserlandProxy": config.bridgeConfig.EnableUserlandProxy} 665 bridgeOption := options.Generic{netlabel.GenericData: bridgeConfig} 666 667 dOptions := []nwconfig.Option{} 668 dOptions = append(dOptions, nwconfig.OptionDriverConfig("bridge", bridgeOption)) 669 return dOptions 670 } 671 672 func initBridgeDriver(controller libnetwork.NetworkController, config *Config) error { 673 if n, err := controller.NetworkByName("bridge"); err == nil { 674 if err = n.Delete(); err != nil { 675 return fmt.Errorf("could not delete the default bridge network: %v", err) 676 } 677 } 678 679 bridgeName := bridge.DefaultBridgeName 680 if config.bridgeConfig.Iface != "" { 681 bridgeName = config.bridgeConfig.Iface 682 } 683 netOption := map[string]string{ 684 bridge.BridgeName: bridgeName, 685 bridge.DefaultBridge: strconv.FormatBool(true), 686 netlabel.DriverMTU: strconv.Itoa(config.Mtu), 687 bridge.EnableIPMasquerade: strconv.FormatBool(config.bridgeConfig.EnableIPMasq), 688 bridge.EnableICC: strconv.FormatBool(config.bridgeConfig.InterContainerCommunication), 689 } 690 691 // --ip processing 692 if config.bridgeConfig.DefaultIP != nil { 693 netOption[bridge.DefaultBindingIP] = config.bridgeConfig.DefaultIP.String() 694 } 695 696 var ( 697 ipamV4Conf *libnetwork.IpamConf 698 ipamV6Conf *libnetwork.IpamConf 699 ) 700 701 ipamV4Conf = &libnetwork.IpamConf{AuxAddresses: make(map[string]string)} 702 703 nw, nw6List, err := netutils.ElectInterfaceAddresses(bridgeName) 704 if err == nil { 705 ipamV4Conf.PreferredPool = lntypes.GetIPNetCanonical(nw).String() 706 hip, _ := lntypes.GetHostPartIP(nw.IP, nw.Mask) 707 if hip.IsGlobalUnicast() { 708 ipamV4Conf.Gateway = nw.IP.String() 709 } 710 } 711 712 if config.bridgeConfig.IP != "" { 713 ipamV4Conf.PreferredPool = config.bridgeConfig.IP 714 ip, _, err := net.ParseCIDR(config.bridgeConfig.IP) 715 if err != nil { 716 return err 717 } 718 ipamV4Conf.Gateway = ip.String() 719 } else if bridgeName == bridge.DefaultBridgeName && ipamV4Conf.PreferredPool != "" { 720 logrus.Infof("Default bridge (%s) is assigned with an IP address %s. Daemon option --bip can be used to set a preferred IP address", bridgeName, ipamV4Conf.PreferredPool) 721 } 722 723 if config.bridgeConfig.FixedCIDR != "" { 724 _, fCIDR, err := net.ParseCIDR(config.bridgeConfig.FixedCIDR) 725 if err != nil { 726 return err 727 } 728 729 ipamV4Conf.SubPool = fCIDR.String() 730 } 731 732 if config.bridgeConfig.DefaultGatewayIPv4 != nil { 733 ipamV4Conf.AuxAddresses["DefaultGatewayIPv4"] = config.bridgeConfig.DefaultGatewayIPv4.String() 734 } 735 736 var deferIPv6Alloc bool 737 if config.bridgeConfig.FixedCIDRv6 != "" { 738 _, fCIDRv6, err := net.ParseCIDR(config.bridgeConfig.FixedCIDRv6) 739 if err != nil { 740 return err 741 } 742 743 // In case user has specified the daemon flag --fixed-cidr-v6 and the passed network has 744 // at least 48 host bits, we need to guarantee the current behavior where the containers' 745 // IPv6 addresses will be constructed based on the containers' interface MAC address. 746 // We do so by telling libnetwork to defer the IPv6 address allocation for the endpoints 747 // on this network until after the driver has created the endpoint and returned the 748 // constructed address. Libnetwork will then reserve this address with the ipam driver. 749 ones, _ := fCIDRv6.Mask.Size() 750 deferIPv6Alloc = ones <= 80 751 752 if ipamV6Conf == nil { 753 ipamV6Conf = &libnetwork.IpamConf{AuxAddresses: make(map[string]string)} 754 } 755 ipamV6Conf.PreferredPool = fCIDRv6.String() 756 757 // In case the --fixed-cidr-v6 is specified and the current docker0 bridge IPv6 758 // address belongs to the same network, we need to inform libnetwork about it, so 759 // that it can be reserved with IPAM and it will not be given away to somebody else 760 for _, nw6 := range nw6List { 761 if fCIDRv6.Contains(nw6.IP) { 762 ipamV6Conf.Gateway = nw6.IP.String() 763 break 764 } 765 } 766 } 767 768 if config.bridgeConfig.DefaultGatewayIPv6 != nil { 769 if ipamV6Conf == nil { 770 ipamV6Conf = &libnetwork.IpamConf{AuxAddresses: make(map[string]string)} 771 } 772 ipamV6Conf.AuxAddresses["DefaultGatewayIPv6"] = config.bridgeConfig.DefaultGatewayIPv6.String() 773 } 774 775 v4Conf := []*libnetwork.IpamConf{ipamV4Conf} 776 v6Conf := []*libnetwork.IpamConf{} 777 if ipamV6Conf != nil { 778 v6Conf = append(v6Conf, ipamV6Conf) 779 } 780 // Initialize default network on "bridge" with the same name 781 _, err = controller.NewNetwork("bridge", "bridge", "", 782 libnetwork.NetworkOptionEnableIPv6(config.bridgeConfig.EnableIPv6), 783 libnetwork.NetworkOptionDriverOpts(netOption), 784 libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf, nil), 785 libnetwork.NetworkOptionDeferIPv6Alloc(deferIPv6Alloc)) 786 if err != nil { 787 return fmt.Errorf("Error creating default \"bridge\" network: %v", err) 788 } 789 return nil 790 } 791 792 // setupInitLayer populates a directory with mountpoints suitable 793 // for bind-mounting things into the container. 794 // 795 // This extra layer is used by all containers as the top-most ro layer. It protects 796 // the container from unwanted side-effects on the rw layer. 797 func setupInitLayer(initLayer string, rootUID, rootGID int) error { 798 for pth, typ := range map[string]string{ 799 "/dev/pts": "dir", 800 "/dev/shm": "dir", 801 "/proc": "dir", 802 "/sys": "dir", 803 "/.dockerenv": "file", 804 "/etc/resolv.conf": "file", 805 "/etc/hosts": "file", 806 "/etc/hostname": "file", 807 "/dev/console": "file", 808 "/etc/mtab": "/proc/mounts", 809 } { 810 parts := strings.Split(pth, "/") 811 prev := "/" 812 for _, p := range parts[1:] { 813 prev = filepath.Join(prev, p) 814 syscall.Unlink(filepath.Join(initLayer, prev)) 815 } 816 817 if _, err := os.Stat(filepath.Join(initLayer, pth)); err != nil { 818 if os.IsNotExist(err) { 819 if err := idtools.MkdirAllNewAs(filepath.Join(initLayer, filepath.Dir(pth)), 0755, rootUID, rootGID); err != nil { 820 return err 821 } 822 switch typ { 823 case "dir": 824 if err := idtools.MkdirAllNewAs(filepath.Join(initLayer, pth), 0755, rootUID, rootGID); err != nil { 825 return err 826 } 827 case "file": 828 f, err := os.OpenFile(filepath.Join(initLayer, pth), os.O_CREATE, 0755) 829 if err != nil { 830 return err 831 } 832 f.Chown(rootUID, rootGID) 833 f.Close() 834 default: 835 if err := os.Symlink(typ, filepath.Join(initLayer, pth)); err != nil { 836 return err 837 } 838 } 839 } else { 840 return err 841 } 842 } 843 } 844 845 // Layer is ready to use, if it wasn't before. 846 return nil 847 } 848 849 // Parse the remapped root (user namespace) option, which can be one of: 850 // username - valid username from /etc/passwd 851 // username:groupname - valid username; valid groupname from /etc/group 852 // uid - 32-bit unsigned int valid Linux UID value 853 // uid:gid - uid value; 32-bit unsigned int Linux GID value 854 // 855 // If no groupname is specified, and a username is specified, an attempt 856 // will be made to lookup a gid for that username as a groupname 857 // 858 // If names are used, they are verified to exist in passwd/group 859 func parseRemappedRoot(usergrp string) (string, string, error) { 860 861 var ( 862 userID, groupID int 863 username, groupname string 864 ) 865 866 idparts := strings.Split(usergrp, ":") 867 if len(idparts) > 2 { 868 return "", "", fmt.Errorf("Invalid user/group specification in --userns-remap: %q", usergrp) 869 } 870 871 if uid, err := strconv.ParseInt(idparts[0], 10, 32); err == nil { 872 // must be a uid; take it as valid 873 userID = int(uid) 874 luser, err := user.LookupUid(userID) 875 if err != nil { 876 return "", "", fmt.Errorf("Uid %d has no entry in /etc/passwd: %v", userID, err) 877 } 878 username = luser.Name 879 if len(idparts) == 1 { 880 // if the uid was numeric and no gid was specified, take the uid as the gid 881 groupID = userID 882 lgrp, err := user.LookupGid(groupID) 883 if err != nil { 884 return "", "", fmt.Errorf("Gid %d has no entry in /etc/group: %v", groupID, err) 885 } 886 groupname = lgrp.Name 887 } 888 } else { 889 lookupName := idparts[0] 890 // special case: if the user specified "default", they want Docker to create or 891 // use (after creation) the "dockremap" user/group for root remapping 892 if lookupName == defaultIDSpecifier { 893 lookupName = defaultRemappedID 894 } 895 luser, err := user.LookupUser(lookupName) 896 if err != nil && idparts[0] != defaultIDSpecifier { 897 // error if the name requested isn't the special "dockremap" ID 898 return "", "", fmt.Errorf("Error during uid lookup for %q: %v", lookupName, err) 899 } else if err != nil { 900 // special case-- if the username == "default", then we have been asked 901 // to create a new entry pair in /etc/{passwd,group} for which the /etc/sub{uid,gid} 902 // ranges will be used for the user and group mappings in user namespaced containers 903 _, _, err := idtools.AddNamespaceRangesUser(defaultRemappedID) 904 if err == nil { 905 return defaultRemappedID, defaultRemappedID, nil 906 } 907 return "", "", fmt.Errorf("Error during %q user creation: %v", defaultRemappedID, err) 908 } 909 username = luser.Name 910 if len(idparts) == 1 { 911 // we only have a string username, and no group specified; look up gid from username as group 912 group, err := user.LookupGroup(lookupName) 913 if err != nil { 914 return "", "", fmt.Errorf("Error during gid lookup for %q: %v", lookupName, err) 915 } 916 groupID = group.Gid 917 groupname = group.Name 918 } 919 } 920 921 if len(idparts) == 2 { 922 // groupname or gid is separately specified and must be resolved 923 // to an unsigned 32-bit gid 924 if gid, err := strconv.ParseInt(idparts[1], 10, 32); err == nil { 925 // must be a gid, take it as valid 926 groupID = int(gid) 927 lgrp, err := user.LookupGid(groupID) 928 if err != nil { 929 return "", "", fmt.Errorf("Gid %d has no entry in /etc/passwd: %v", groupID, err) 930 } 931 groupname = lgrp.Name 932 } else { 933 // not a number; attempt a lookup 934 if _, err := user.LookupGroup(idparts[1]); err != nil { 935 return "", "", fmt.Errorf("Error during groupname lookup for %q: %v", idparts[1], err) 936 } 937 groupname = idparts[1] 938 } 939 } 940 return username, groupname, nil 941 } 942 943 func setupRemappedRoot(config *Config) ([]idtools.IDMap, []idtools.IDMap, error) { 944 if runtime.GOOS != "linux" && config.RemappedRoot != "" { 945 return nil, nil, fmt.Errorf("User namespaces are only supported on Linux") 946 } 947 948 // if the daemon was started with remapped root option, parse 949 // the config option to the int uid,gid values 950 var ( 951 uidMaps, gidMaps []idtools.IDMap 952 ) 953 if config.RemappedRoot != "" { 954 username, groupname, err := parseRemappedRoot(config.RemappedRoot) 955 if err != nil { 956 return nil, nil, err 957 } 958 if username == "root" { 959 // Cannot setup user namespaces with a 1-to-1 mapping; "--root=0:0" is a no-op 960 // effectively 961 logrus.Warn("User namespaces: root cannot be remapped with itself; user namespaces are OFF") 962 return uidMaps, gidMaps, nil 963 } 964 logrus.Infof("User namespaces: ID ranges will be mapped to subuid/subgid ranges of: %s:%s", username, groupname) 965 // update remapped root setting now that we have resolved them to actual names 966 config.RemappedRoot = fmt.Sprintf("%s:%s", username, groupname) 967 968 uidMaps, gidMaps, err = idtools.CreateIDMappings(username, groupname) 969 if err != nil { 970 return nil, nil, fmt.Errorf("Can't create ID mappings: %v", err) 971 } 972 } 973 return uidMaps, gidMaps, nil 974 } 975 976 func setupDaemonRoot(config *Config, rootDir string, rootUID, rootGID int) error { 977 config.Root = rootDir 978 // the docker root metadata directory needs to have execute permissions for all users (g+x,o+x) 979 // so that syscalls executing as non-root, operating on subdirectories of the graph root 980 // (e.g. mounted layers of a container) can traverse this path. 981 // The user namespace support will create subdirectories for the remapped root host uid:gid 982 // pair owned by that same uid:gid pair for proper write access to those needed metadata and 983 // layer content subtrees. 984 if _, err := os.Stat(rootDir); err == nil { 985 // root current exists; verify the access bits are correct by setting them 986 if err = os.Chmod(rootDir, 0711); err != nil { 987 return err 988 } 989 } else if os.IsNotExist(err) { 990 // no root exists yet, create it 0711 with root:root ownership 991 if err := os.MkdirAll(rootDir, 0711); err != nil { 992 return err 993 } 994 } 995 996 // if user namespaces are enabled we will create a subtree underneath the specified root 997 // with any/all specified remapped root uid/gid options on the daemon creating 998 // a new subdirectory with ownership set to the remapped uid/gid (so as to allow 999 // `chdir()` to work for containers namespaced to that uid/gid) 1000 if config.RemappedRoot != "" { 1001 config.Root = filepath.Join(rootDir, fmt.Sprintf("%d.%d", rootUID, rootGID)) 1002 logrus.Debugf("Creating user namespaced daemon root: %s", config.Root) 1003 // Create the root directory if it doesn't exist 1004 if err := idtools.MkdirAllAs(config.Root, 0700, rootUID, rootGID); err != nil { 1005 return fmt.Errorf("Cannot create daemon root: %s: %v", config.Root, err) 1006 } 1007 } 1008 return nil 1009 } 1010 1011 // registerLinks writes the links to a file. 1012 func (daemon *Daemon) registerLinks(container *container.Container, hostConfig *containertypes.HostConfig) error { 1013 if hostConfig == nil || hostConfig.NetworkMode.IsUserDefined() { 1014 return nil 1015 } 1016 1017 for _, l := range hostConfig.Links { 1018 name, alias, err := runconfigopts.ParseLink(l) 1019 if err != nil { 1020 return err 1021 } 1022 child, err := daemon.GetContainer(name) 1023 if err != nil { 1024 return fmt.Errorf("Could not get container for %s", name) 1025 } 1026 for child.HostConfig.NetworkMode.IsContainer() { 1027 parts := strings.SplitN(string(child.HostConfig.NetworkMode), ":", 2) 1028 child, err = daemon.GetContainer(parts[1]) 1029 if err != nil { 1030 return fmt.Errorf("Could not get container for %s", parts[1]) 1031 } 1032 } 1033 if child.HostConfig.NetworkMode.IsHost() { 1034 return runconfig.ErrConflictHostNetworkAndLinks 1035 } 1036 if err := daemon.registerLink(container, child, alias); err != nil { 1037 return err 1038 } 1039 } 1040 1041 // After we load all the links into the daemon 1042 // set them to nil on the hostconfig 1043 return container.WriteHostConfig() 1044 } 1045 1046 // conditionalMountOnStart is a platform specific helper function during the 1047 // container start to call mount. 1048 func (daemon *Daemon) conditionalMountOnStart(container *container.Container) error { 1049 return daemon.Mount(container) 1050 } 1051 1052 // conditionalUnmountOnCleanup is a platform specific helper function called 1053 // during the cleanup of a container to unmount. 1054 func (daemon *Daemon) conditionalUnmountOnCleanup(container *container.Container) error { 1055 return daemon.Unmount(container) 1056 } 1057 1058 func (daemon *Daemon) stats(c *container.Container) (*types.StatsJSON, error) { 1059 if !c.IsRunning() { 1060 return nil, errNotRunning{c.ID} 1061 } 1062 stats, err := daemon.containerd.Stats(c.ID) 1063 if err != nil { 1064 return nil, err 1065 } 1066 s := &types.StatsJSON{} 1067 cgs := stats.CgroupStats 1068 if cgs != nil { 1069 s.BlkioStats = types.BlkioStats{ 1070 IoServiceBytesRecursive: copyBlkioEntry(cgs.BlkioStats.IoServiceBytesRecursive), 1071 IoServicedRecursive: copyBlkioEntry(cgs.BlkioStats.IoServicedRecursive), 1072 IoQueuedRecursive: copyBlkioEntry(cgs.BlkioStats.IoQueuedRecursive), 1073 IoServiceTimeRecursive: copyBlkioEntry(cgs.BlkioStats.IoServiceTimeRecursive), 1074 IoWaitTimeRecursive: copyBlkioEntry(cgs.BlkioStats.IoWaitTimeRecursive), 1075 IoMergedRecursive: copyBlkioEntry(cgs.BlkioStats.IoMergedRecursive), 1076 IoTimeRecursive: copyBlkioEntry(cgs.BlkioStats.IoTimeRecursive), 1077 SectorsRecursive: copyBlkioEntry(cgs.BlkioStats.SectorsRecursive), 1078 } 1079 cpu := cgs.CpuStats 1080 s.CPUStats = types.CPUStats{ 1081 CPUUsage: types.CPUUsage{ 1082 TotalUsage: cpu.CpuUsage.TotalUsage, 1083 PercpuUsage: cpu.CpuUsage.PercpuUsage, 1084 UsageInKernelmode: cpu.CpuUsage.UsageInKernelmode, 1085 UsageInUsermode: cpu.CpuUsage.UsageInUsermode, 1086 }, 1087 ThrottlingData: types.ThrottlingData{ 1088 Periods: cpu.ThrottlingData.Periods, 1089 ThrottledPeriods: cpu.ThrottlingData.ThrottledPeriods, 1090 ThrottledTime: cpu.ThrottlingData.ThrottledTime, 1091 }, 1092 } 1093 mem := cgs.MemoryStats.Usage 1094 s.MemoryStats = types.MemoryStats{ 1095 Usage: mem.Usage, 1096 MaxUsage: mem.MaxUsage, 1097 Stats: cgs.MemoryStats.Stats, 1098 Failcnt: mem.Failcnt, 1099 Limit: mem.Limit, 1100 } 1101 // if the container does not set memory limit, use the machineMemory 1102 if mem.Limit > daemon.statsCollector.machineMemory && daemon.statsCollector.machineMemory > 0 { 1103 s.MemoryStats.Limit = daemon.statsCollector.machineMemory 1104 } 1105 if cgs.PidsStats != nil { 1106 s.PidsStats = types.PidsStats{ 1107 Current: cgs.PidsStats.Current, 1108 } 1109 } 1110 } 1111 s.Read, err = ptypes.Timestamp(stats.Timestamp) 1112 if err != nil { 1113 return nil, err 1114 } 1115 return s, nil 1116 } 1117 1118 // setDefaultIsolation determines the default isolation mode for the 1119 // daemon to run in. This is only applicable on Windows 1120 func (daemon *Daemon) setDefaultIsolation() error { 1121 return nil 1122 } 1123 1124 func rootFSToAPIType(rootfs *image.RootFS) types.RootFS { 1125 var layers []string 1126 for _, l := range rootfs.DiffIDs { 1127 layers = append(layers, l.String()) 1128 } 1129 return types.RootFS{ 1130 Type: rootfs.Type, 1131 Layers: layers, 1132 } 1133 } 1134 1135 // setupDaemonProcess sets various settings for the daemon's process 1136 func setupDaemonProcess(config *Config) error { 1137 // setup the daemons oom_score_adj 1138 return setupOOMScoreAdj(config.OOMScoreAdjust) 1139 } 1140 1141 func setupOOMScoreAdj(score int) error { 1142 f, err := os.OpenFile("/proc/self/oom_score_adj", os.O_WRONLY, 0) 1143 if err != nil { 1144 return err 1145 } 1146 _, err = f.WriteString(strconv.Itoa(score)) 1147 f.Close() 1148 return err 1149 }