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