github.com/jiasir/docker@v1.3.3-0.20170609024000-252e610103e7/daemon/daemon_solaris.go (about) 1 // +build solaris,cgo 2 3 package daemon 4 5 import ( 6 "fmt" 7 "net" 8 "strconv" 9 10 "github.com/Sirupsen/logrus" 11 "github.com/docker/docker/api/types" 12 containertypes "github.com/docker/docker/api/types/container" 13 "github.com/docker/docker/container" 14 "github.com/docker/docker/image" 15 "github.com/docker/docker/layer" 16 "github.com/docker/docker/pkg/idtools" 17 "github.com/docker/docker/pkg/parsers/kernel" 18 "github.com/docker/docker/pkg/sysinfo" 19 refstore "github.com/docker/docker/reference" 20 "github.com/docker/libnetwork" 21 nwconfig "github.com/docker/libnetwork/config" 22 "github.com/docker/libnetwork/drivers/solaris/bridge" 23 "github.com/docker/libnetwork/netlabel" 24 "github.com/docker/libnetwork/netutils" 25 lntypes "github.com/docker/libnetwork/types" 26 "github.com/opencontainers/runtime-spec/specs-go" 27 "github.com/opencontainers/selinux/go-selinux/label" 28 "github.com/pkg/errors" 29 ) 30 31 //#include <zone.h> 32 import "C" 33 34 const ( 35 defaultVirtualSwitch = "Virtual Switch" 36 platformSupported = true 37 solarisMinCPUShares = 1 38 solarisMaxCPUShares = 65535 39 ) 40 41 func getMemoryResources(config containertypes.Resources) specs.CappedMemory { 42 memory := specs.CappedMemory{} 43 44 if config.Memory > 0 { 45 memory.Physical = strconv.FormatInt(config.Memory, 10) 46 } 47 48 if config.MemorySwap != 0 { 49 memory.Swap = strconv.FormatInt(config.MemorySwap, 10) 50 } 51 52 return memory 53 } 54 55 func getCPUResources(config containertypes.Resources) specs.CappedCPU { 56 cpu := specs.CappedCPU{} 57 58 if config.CpusetCpus != "" { 59 cpu.Ncpus = config.CpusetCpus 60 } 61 62 return cpu 63 } 64 65 func (daemon *Daemon) cleanupMountsByID(id string) error { 66 return nil 67 } 68 69 func (daemon *Daemon) parseSecurityOpt(container *container.Container, hostConfig *containertypes.HostConfig) error { 70 return parseSecurityOpt(container, hostConfig) 71 } 72 73 func parseSecurityOpt(container *container.Container, config *containertypes.HostConfig) error { 74 //Since config.SecurityOpt is specifically defined as a "List of string values to 75 //customize labels for MLs systems, such as SELinux" 76 //until we figure out how to map to Trusted Extensions 77 //this is being disabled for now on Solaris 78 var ( 79 labelOpts []string 80 err error 81 ) 82 83 if len(config.SecurityOpt) > 0 { 84 return errors.New("Security options are not supported on Solaris") 85 } 86 87 container.ProcessLabel, container.MountLabel, err = label.InitLabels(labelOpts) 88 return err 89 } 90 91 func setupRemappedRoot(config *Config) ([]idtools.IDMap, []idtools.IDMap, error) { 92 return nil, nil, nil 93 } 94 95 func setupDaemonRoot(config *Config, rootDir string, rootUID, rootGID int) error { 96 return nil 97 } 98 99 func (daemon *Daemon) getLayerInit() func(string) error { 100 return nil 101 } 102 103 func checkKernel() error { 104 // solaris can rely upon checkSystem() below, we don't skew kernel versions 105 return nil 106 } 107 108 func (daemon *Daemon) getCgroupDriver() string { 109 return "" 110 } 111 112 func (daemon *Daemon) adaptContainerSettings(hostConfig *containertypes.HostConfig, adjustCPUShares bool) error { 113 if hostConfig.CPUShares < 0 { 114 logrus.Warnf("Changing requested CPUShares of %d to minimum allowed of %d", hostConfig.CPUShares, solarisMinCPUShares) 115 hostConfig.CPUShares = solarisMinCPUShares 116 } else if hostConfig.CPUShares > solarisMaxCPUShares { 117 logrus.Warnf("Changing requested CPUShares of %d to maximum allowed of %d", hostConfig.CPUShares, solarisMaxCPUShares) 118 hostConfig.CPUShares = solarisMaxCPUShares 119 } 120 121 if hostConfig.Memory > 0 && hostConfig.MemorySwap == 0 { 122 // By default, MemorySwap is set to twice the size of Memory. 123 hostConfig.MemorySwap = hostConfig.Memory * 2 124 } 125 126 if hostConfig.ShmSize != 0 { 127 hostConfig.ShmSize = container.DefaultSHMSize 128 } 129 if hostConfig.OomKillDisable == nil { 130 defaultOomKillDisable := false 131 hostConfig.OomKillDisable = &defaultOomKillDisable 132 } 133 134 return nil 135 } 136 137 // UsingSystemd returns true if cli option includes native.cgroupdriver=systemd 138 func UsingSystemd(config *Config) bool { 139 return false 140 } 141 142 // verifyPlatformContainerSettings performs platform-specific validation of the 143 // hostconfig and config structures. 144 func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes.HostConfig, config *containertypes.Config, update bool) ([]string, error) { 145 warnings := []string{} 146 sysInfo := sysinfo.New(true) 147 // NOTE: We do not enforce a minimum value for swap limits for zones on Solaris and 148 // therefore we will not do that for Docker container either. 149 if hostConfig.Memory > 0 && !sysInfo.MemoryLimit { 150 warnings = append(warnings, "Your kernel does not support memory limit capabilities. Limitation discarded.") 151 logrus.Warnf("Your kernel does not support memory limit capabilities. Limitation discarded.") 152 hostConfig.Memory = 0 153 hostConfig.MemorySwap = -1 154 } 155 if hostConfig.Memory > 0 && hostConfig.MemorySwap != -1 && !sysInfo.SwapLimit { 156 warnings = append(warnings, "Your kernel does not support swap limit capabilities, memory limited without swap.") 157 logrus.Warnf("Your kernel does not support swap limit capabilities, memory limited without swap.") 158 hostConfig.MemorySwap = -1 159 } 160 if hostConfig.Memory > 0 && hostConfig.MemorySwap > 0 && hostConfig.MemorySwap < hostConfig.Memory { 161 return warnings, fmt.Errorf("Minimum memoryswap limit should be larger than memory limit, see usage.") 162 } 163 // Solaris NOTE: We allow and encourage setting the swap without setting the memory limit. 164 165 if hostConfig.MemorySwappiness != nil && *hostConfig.MemorySwappiness != -1 && !sysInfo.MemorySwappiness { 166 warnings = append(warnings, "Your kernel does not support memory swappiness capabilities, memory swappiness discarded.") 167 logrus.Warnf("Your kernel does not support memory swappiness capabilities, memory swappiness discarded.") 168 hostConfig.MemorySwappiness = nil 169 } 170 if hostConfig.MemoryReservation > 0 && !sysInfo.MemoryReservation { 171 warnings = append(warnings, "Your kernel does not support memory soft limit capabilities. Limitation discarded.") 172 logrus.Warnf("Your kernel does not support memory soft limit capabilities. Limitation discarded.") 173 hostConfig.MemoryReservation = 0 174 } 175 if hostConfig.Memory > 0 && hostConfig.MemoryReservation > 0 && hostConfig.Memory < hostConfig.MemoryReservation { 176 return warnings, fmt.Errorf("Minimum memory limit should be larger than memory reservation limit, see usage.") 177 } 178 if hostConfig.KernelMemory > 0 && !sysInfo.KernelMemory { 179 warnings = append(warnings, "Your kernel does not support kernel memory limit capabilities. Limitation discarded.") 180 logrus.Warnf("Your kernel does not support kernel memory limit capabilities. Limitation discarded.") 181 hostConfig.KernelMemory = 0 182 } 183 if hostConfig.CPUShares != 0 && !sysInfo.CPUShares { 184 warnings = append(warnings, "Your kernel does not support CPU shares. Shares discarded.") 185 logrus.Warnf("Your kernel does not support CPU shares. Shares discarded.") 186 hostConfig.CPUShares = 0 187 } 188 if hostConfig.CPUShares < 0 { 189 warnings = append(warnings, "Invalid CPUShares value. Must be positive. Discarding.") 190 logrus.Warnf("Invalid CPUShares value. Must be positive. Discarding.") 191 hostConfig.CPUQuota = 0 192 } 193 if hostConfig.CPUShares > 0 && !sysinfo.IsCPUSharesAvailable() { 194 warnings = append(warnings, "Global zone default scheduling class not FSS. Discarding shares.") 195 logrus.Warnf("Global zone default scheduling class not FSS. Discarding shares.") 196 hostConfig.CPUShares = 0 197 } 198 199 // Solaris NOTE: Linux does not do negative checking for CPUShares and Quota here. But it makes sense to. 200 if hostConfig.CPUPeriod > 0 && !sysInfo.CPUCfsPeriod { 201 warnings = append(warnings, "Your kernel does not support CPU cfs period. Period discarded.") 202 logrus.Warnf("Your kernel does not support CPU cfs period. Period discarded.") 203 if hostConfig.CPUQuota > 0 { 204 warnings = append(warnings, "Quota will be applied on default period, not period specified.") 205 logrus.Warnf("Quota will be applied on default period, not period specified.") 206 } 207 hostConfig.CPUPeriod = 0 208 } 209 if hostConfig.CPUQuota != 0 && !sysInfo.CPUCfsQuota { 210 warnings = append(warnings, "Your kernel does not support CPU cfs quota. Quota discarded.") 211 logrus.Warnf("Your kernel does not support CPU cfs quota. Quota discarded.") 212 hostConfig.CPUQuota = 0 213 } 214 if hostConfig.CPUQuota < 0 { 215 warnings = append(warnings, "Invalid CPUQuota value. Must be positive. Discarding.") 216 logrus.Warnf("Invalid CPUQuota value. Must be positive. Discarding.") 217 hostConfig.CPUQuota = 0 218 } 219 if (hostConfig.CpusetCpus != "" || hostConfig.CpusetMems != "") && !sysInfo.Cpuset { 220 warnings = append(warnings, "Your kernel does not support cpuset. Cpuset discarded.") 221 logrus.Warnf("Your kernel does not support cpuset. Cpuset discarded.") 222 hostConfig.CpusetCpus = "" 223 hostConfig.CpusetMems = "" 224 } 225 cpusAvailable, err := sysInfo.IsCpusetCpusAvailable(hostConfig.CpusetCpus) 226 if err != nil { 227 return warnings, fmt.Errorf("Invalid value %s for cpuset cpus.", hostConfig.CpusetCpus) 228 } 229 if !cpusAvailable { 230 return warnings, fmt.Errorf("Requested CPUs are not available - requested %s, available: %s.", hostConfig.CpusetCpus, sysInfo.Cpus) 231 } 232 memsAvailable, err := sysInfo.IsCpusetMemsAvailable(hostConfig.CpusetMems) 233 if err != nil { 234 return warnings, fmt.Errorf("Invalid value %s for cpuset mems.", hostConfig.CpusetMems) 235 } 236 if !memsAvailable { 237 return warnings, fmt.Errorf("Requested memory nodes are not available - requested %s, available: %s.", hostConfig.CpusetMems, sysInfo.Mems) 238 } 239 if hostConfig.BlkioWeight > 0 && !sysInfo.BlkioWeight { 240 warnings = append(warnings, "Your kernel does not support Block I/O weight. Weight discarded.") 241 logrus.Warnf("Your kernel does not support Block I/O weight. Weight discarded.") 242 hostConfig.BlkioWeight = 0 243 } 244 if hostConfig.OomKillDisable != nil && !sysInfo.OomKillDisable { 245 *hostConfig.OomKillDisable = false 246 // Don't warn; this is the default setting but only applicable to Linux 247 } 248 249 if sysInfo.IPv4ForwardingDisabled { 250 warnings = append(warnings, "IPv4 forwarding is disabled. Networking will not work.") 251 logrus.Warnf("IPv4 forwarding is disabled. Networking will not work") 252 } 253 254 // Solaris NOTE: We do not allow setting Linux specific options, so check and warn for all of them. 255 256 if hostConfig.CapAdd != nil || hostConfig.CapDrop != nil { 257 warnings = append(warnings, "Adding or dropping kernel capabilities unsupported on Solaris.Discarding capabilities lists.") 258 logrus.Warnf("Adding or dropping kernel capabilities unsupported on Solaris.Discarding capabilities lists.") 259 hostConfig.CapAdd = nil 260 hostConfig.CapDrop = nil 261 } 262 263 if hostConfig.GroupAdd != nil { 264 warnings = append(warnings, "Additional groups unsupported on Solaris.Discarding groups lists.") 265 logrus.Warnf("Additional groups unsupported on Solaris.Discarding groups lists.") 266 hostConfig.GroupAdd = nil 267 } 268 269 if hostConfig.IpcMode != "" { 270 warnings = append(warnings, "IPC namespace assignment unsupported on Solaris.Discarding IPC setting.") 271 logrus.Warnf("IPC namespace assignment unsupported on Solaris.Discarding IPC setting.") 272 hostConfig.IpcMode = "" 273 } 274 275 if hostConfig.PidMode != "" { 276 warnings = append(warnings, "PID namespace setting unsupported on Solaris. Running container in host PID namespace.") 277 logrus.Warnf("PID namespace setting unsupported on Solaris. Running container in host PID namespace.") 278 hostConfig.PidMode = "" 279 } 280 281 if hostConfig.Privileged { 282 warnings = append(warnings, "Privileged mode unsupported on Solaris. Discarding privileged mode setting.") 283 logrus.Warnf("Privileged mode unsupported on Solaris. Discarding privileged mode setting.") 284 hostConfig.Privileged = false 285 } 286 287 if hostConfig.UTSMode != "" { 288 warnings = append(warnings, "UTS namespace assignment unsupported on Solaris.Discarding UTS setting.") 289 logrus.Warnf("UTS namespace assignment unsupported on Solaris.Discarding UTS setting.") 290 hostConfig.UTSMode = "" 291 } 292 293 if hostConfig.CgroupParent != "" { 294 warnings = append(warnings, "Specifying Cgroup parent unsupported on Solaris. Discarding cgroup parent setting.") 295 logrus.Warnf("Specifying Cgroup parent unsupported on Solaris. Discarding cgroup parent setting.") 296 hostConfig.CgroupParent = "" 297 } 298 299 if hostConfig.Ulimits != nil { 300 warnings = append(warnings, "Specifying ulimits unsupported on Solaris. Discarding ulimits setting.") 301 logrus.Warnf("Specifying ulimits unsupported on Solaris. Discarding ulimits setting.") 302 hostConfig.Ulimits = nil 303 } 304 305 return warnings, nil 306 } 307 308 // reloadPlatform updates configuration with platform specific options 309 // and updates the passed attributes 310 func (daemon *Daemon) reloadPlatform(config *Config, attributes map[string]string) { 311 } 312 313 // verifyDaemonSettings performs validation of daemon config struct 314 func verifyDaemonSettings(config *Config) error { 315 316 if config.DefaultRuntime == "" { 317 config.DefaultRuntime = stockRuntimeName 318 } 319 if config.Runtimes == nil { 320 config.Runtimes = make(map[string]types.Runtime) 321 } 322 stockRuntimeOpts := []string{} 323 config.Runtimes[stockRuntimeName] = types.Runtime{Path: DefaultRuntimeBinary, Args: stockRuntimeOpts} 324 325 // checkSystem validates platform-specific requirements 326 return nil 327 } 328 329 func checkSystem() error { 330 // check OS version for compatibility, ensure running in global zone 331 var err error 332 var id C.zoneid_t 333 334 if id, err = C.getzoneid(); err != nil { 335 return fmt.Errorf("Exiting. Error getting zone id: %+v", err) 336 } 337 if int(id) != 0 { 338 return fmt.Errorf("Exiting because the Docker daemon is not running in the global zone") 339 } 340 341 v, err := kernel.GetKernelVersion() 342 if kernel.CompareKernelVersion(*v, kernel.VersionInfo{Kernel: 5, Major: 12, Minor: 0}) < 0 { 343 return fmt.Errorf("Your Solaris kernel version: %s doesn't support Docker. Please upgrade to 5.12.0", v.String()) 344 } 345 return err 346 } 347 348 // configureMaxThreads sets the Go runtime max threads threshold 349 // which is 90% of the kernel setting from /proc/sys/kernel/threads-max 350 func configureMaxThreads(config *Config) error { 351 return nil 352 } 353 354 // configureKernelSecuritySupport configures and validate security support for the kernel 355 func configureKernelSecuritySupport(config *Config, driverName string) error { 356 return nil 357 } 358 359 func (daemon *Daemon) initNetworkController(config *Config, activeSandboxes map[string]interface{}) (libnetwork.NetworkController, error) { 360 netOptions, err := daemon.networkOptions(config, daemon.PluginStore, activeSandboxes) 361 if err != nil { 362 return nil, err 363 } 364 365 controller, err := libnetwork.New(netOptions...) 366 if err != nil { 367 return nil, fmt.Errorf("error obtaining controller instance: %v", err) 368 } 369 370 // Initialize default network on "null" 371 if _, err := controller.NewNetwork("null", "none", "", libnetwork.NetworkOptionPersist(false)); err != nil { 372 return nil, fmt.Errorf("Error creating default 'null' network: %v", err) 373 } 374 375 if !config.DisableBridge { 376 // Initialize default driver "bridge" 377 if err := initBridgeDriver(controller, config); err != nil { 378 return nil, err 379 } 380 } 381 382 return controller, nil 383 } 384 385 func initBridgeDriver(controller libnetwork.NetworkController, config *Config) error { 386 if n, err := controller.NetworkByName("bridge"); err == nil { 387 if err = n.Delete(); err != nil { 388 return fmt.Errorf("could not delete the default bridge network: %v", err) 389 } 390 } 391 392 bridgeName := bridge.DefaultBridgeName 393 if config.bridgeConfig.Iface != "" { 394 bridgeName = config.bridgeConfig.Iface 395 } 396 netOption := map[string]string{ 397 bridge.BridgeName: bridgeName, 398 bridge.DefaultBridge: strconv.FormatBool(true), 399 netlabel.DriverMTU: strconv.Itoa(config.Mtu), 400 bridge.EnableICC: strconv.FormatBool(config.bridgeConfig.InterContainerCommunication), 401 } 402 403 // --ip processing 404 if config.bridgeConfig.DefaultIP != nil { 405 netOption[bridge.DefaultBindingIP] = config.bridgeConfig.DefaultIP.String() 406 } 407 408 var ipamV4Conf *libnetwork.IpamConf 409 410 ipamV4Conf = &libnetwork.IpamConf{AuxAddresses: make(map[string]string)} 411 412 nwList, _, err := netutils.ElectInterfaceAddresses(bridgeName) 413 if err != nil { 414 return errors.Wrap(err, "list bridge addresses failed") 415 } 416 417 nw := nwList[0] 418 if len(nwList) > 1 && config.bridgeConfig.FixedCIDR != "" { 419 _, fCIDR, err := net.ParseCIDR(config.bridgeConfig.FixedCIDR) 420 if err != nil { 421 return errors.Wrap(err, "parse CIDR failed") 422 } 423 // Iterate through in case there are multiple addresses for the bridge 424 for _, entry := range nwList { 425 if fCIDR.Contains(entry.IP) { 426 nw = entry 427 break 428 } 429 } 430 } 431 432 ipamV4Conf.PreferredPool = lntypes.GetIPNetCanonical(nw).String() 433 hip, _ := lntypes.GetHostPartIP(nw.IP, nw.Mask) 434 if hip.IsGlobalUnicast() { 435 ipamV4Conf.Gateway = nw.IP.String() 436 } 437 438 if config.bridgeConfig.IP != "" { 439 ipamV4Conf.PreferredPool = config.bridgeConfig.IP 440 ip, _, err := net.ParseCIDR(config.bridgeConfig.IP) 441 if err != nil { 442 return err 443 } 444 ipamV4Conf.Gateway = ip.String() 445 } else if bridgeName == bridge.DefaultBridgeName && ipamV4Conf.PreferredPool != "" { 446 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) 447 } 448 449 if config.bridgeConfig.FixedCIDR != "" { 450 _, fCIDR, err := net.ParseCIDR(config.bridgeConfig.FixedCIDR) 451 if err != nil { 452 return err 453 } 454 455 ipamV4Conf.SubPool = fCIDR.String() 456 } 457 458 if config.bridgeConfig.DefaultGatewayIPv4 != nil { 459 ipamV4Conf.AuxAddresses["DefaultGatewayIPv4"] = config.bridgeConfig.DefaultGatewayIPv4.String() 460 } 461 462 v4Conf := []*libnetwork.IpamConf{ipamV4Conf} 463 v6Conf := []*libnetwork.IpamConf{} 464 465 // Initialize default network on "bridge" with the same name 466 _, err = controller.NewNetwork("bridge", "bridge", "", 467 libnetwork.NetworkOptionDriverOpts(netOption), 468 libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf, nil), 469 libnetwork.NetworkOptionDeferIPv6Alloc(false)) 470 if err != nil { 471 return fmt.Errorf("Error creating default 'bridge' network: %v", err) 472 } 473 return nil 474 } 475 476 // registerLinks sets up links between containers and writes the 477 // configuration out for persistence. 478 func (daemon *Daemon) registerLinks(container *container.Container, hostConfig *containertypes.HostConfig) error { 479 return nil 480 } 481 482 func (daemon *Daemon) cleanupMounts() error { 483 return nil 484 } 485 486 // conditionalMountOnStart is a platform specific helper function during the 487 // container start to call mount. 488 func (daemon *Daemon) conditionalMountOnStart(container *container.Container) error { 489 return daemon.Mount(container) 490 } 491 492 // conditionalUnmountOnCleanup is a platform specific helper function called 493 // during the cleanup of a container to unmount. 494 func (daemon *Daemon) conditionalUnmountOnCleanup(container *container.Container) error { 495 return daemon.Unmount(container) 496 } 497 498 func restoreCustomImage(is image.Store, ls layer.Store, rs refstore.Store) error { 499 // Solaris has no custom images to register 500 return nil 501 } 502 503 func driverOptions(config *Config) []nwconfig.Option { 504 return []nwconfig.Option{} 505 } 506 507 func (daemon *Daemon) stats(c *container.Container) (*types.StatsJSON, error) { 508 return nil, nil 509 } 510 511 // setDefaultIsolation determine the default isolation mode for the 512 // daemon to run in. This is only applicable on Windows 513 func (daemon *Daemon) setDefaultIsolation() error { 514 return nil 515 } 516 517 func rootFSToAPIType(rootfs *image.RootFS) types.RootFS { 518 return types.RootFS{} 519 } 520 521 func setupDaemonProcess(config *Config) error { 522 return nil 523 } 524 525 func (daemon *Daemon) setupSeccompProfile() error { 526 return nil 527 }