github.com/Ilhicas/nomad@v1.0.4-0.20210304152020-e86851182bc3/drivers/docker/config.go (about) 1 package docker 2 3 import ( 4 "context" 5 "fmt" 6 "runtime" 7 "strconv" 8 "strings" 9 "time" 10 11 docker "github.com/fsouza/go-dockerclient" 12 "github.com/hashicorp/go-hclog" 13 "github.com/hashicorp/nomad/helper/pluginutils/hclutils" 14 "github.com/hashicorp/nomad/helper/pluginutils/loader" 15 "github.com/hashicorp/nomad/plugins/base" 16 "github.com/hashicorp/nomad/plugins/drivers" 17 "github.com/hashicorp/nomad/plugins/shared/hclspec" 18 ) 19 20 const ( 21 // NoSuchContainerError is returned by the docker daemon if the container 22 // does not exist. 23 NoSuchContainerError = "No such container" 24 25 // ContainerNotRunningError is returned by the docker daemon if the container 26 // is not running, yet we requested it to stop 27 ContainerNotRunningError = "Container not running" 28 29 // pluginName is the name of the plugin 30 pluginName = "docker" 31 32 // fingerprintPeriod is the interval at which the driver will send fingerprint responses 33 fingerprintPeriod = 30 * time.Second 34 35 // dockerTimeout is the length of time a request can be outstanding before 36 // it is timed out. 37 dockerTimeout = 5 * time.Minute 38 39 // dockerBasicCaps is comma-separated list of Linux capabilities that are 40 // allowed by docker by default, as documented in 41 // https://docs.docker.com/engine/reference/run/#block-io-bandwidth-blkio-constraint 42 dockerBasicCaps = "CHOWN,DAC_OVERRIDE,FSETID,FOWNER,MKNOD,NET_RAW,SETGID," + 43 "SETUID,SETFCAP,SETPCAP,NET_BIND_SERVICE,SYS_CHROOT,KILL,AUDIT_WRITE" 44 45 // dockerAuthHelperPrefix is the prefix to attach to the credential helper 46 // and should be found in the $PATH. Example: ${prefix-}${helper-name} 47 dockerAuthHelperPrefix = "docker-credential-" 48 ) 49 50 func PluginLoader(opts map[string]string) (map[string]interface{}, error) { 51 conf := map[string]interface{}{} 52 if v, ok := opts["docker.endpoint"]; ok { 53 conf["endpoint"] = v 54 } 55 56 // dockerd auth 57 authConf := map[string]interface{}{} 58 if v, ok := opts["docker.auth.config"]; ok { 59 authConf["config"] = v 60 } 61 if v, ok := opts["docker.auth.helper"]; ok { 62 authConf["helper"] = v 63 } 64 conf["auth"] = authConf 65 66 // dockerd tls 67 if _, ok := opts["docker.tls.cert"]; ok { 68 conf["tls"] = map[string]interface{}{ 69 "cert": opts["docker.tls.cert"], 70 "key": opts["docker.tls.key"], 71 "ca": opts["docker.tls.ca"], 72 } 73 } 74 75 // garbage collection 76 gcConf := map[string]interface{}{} 77 if v, err := strconv.ParseBool(opts["docker.cleanup.image"]); err == nil { 78 gcConf["image"] = v 79 } 80 if v, ok := opts["docker.cleanup.image.delay"]; ok { 81 gcConf["image_delay"] = v 82 } 83 if v, err := strconv.ParseBool(opts["docker.cleanup.container"]); err == nil { 84 gcConf["container"] = v 85 } 86 conf["gc"] = gcConf 87 88 // volume options 89 volConf := map[string]interface{}{} 90 if v, err := strconv.ParseBool(opts["docker.volumes.enabled"]); err == nil { 91 volConf["enabled"] = v 92 } 93 if v, ok := opts["docker.volumes.selinuxlabel"]; ok { 94 volConf["selinuxlabel"] = v 95 } 96 conf["volumes"] = volConf 97 98 // capabilities 99 // COMPAT(1.0) uses inclusive language. whitelist is used for backward compatibility. 100 if v, ok := opts["docker.caps.allowlist"]; ok { 101 conf["allow_caps"] = strings.Split(v, ",") 102 } else if v, ok := opts["docker.caps.whitelist"]; ok { 103 conf["allow_caps"] = strings.Split(v, ",") 104 } 105 106 // privileged containers 107 if v, err := strconv.ParseBool(opts["docker.privileged.enabled"]); err == nil { 108 conf["allow_privileged"] = v 109 } 110 111 // nvidia_runtime 112 if v, ok := opts["docker.nvidia_runtime"]; ok { 113 conf["nvidia_runtime"] = v 114 } 115 116 return conf, nil 117 } 118 119 var ( 120 // PluginID is the rawexec plugin metadata registered in the plugin 121 // catalog. 122 PluginID = loader.PluginID{ 123 Name: pluginName, 124 PluginType: base.PluginTypeDriver, 125 } 126 127 // PluginConfig is the rawexec factory function registered in the 128 // plugin catalog. 129 PluginConfig = &loader.InternalPluginConfig{ 130 Config: map[string]interface{}{}, 131 Factory: func(ctx context.Context, l hclog.Logger) interface{} { return NewDockerDriver(ctx, l) }, 132 } 133 134 // pluginInfo is the response returned for the PluginInfo RPC 135 pluginInfo = &base.PluginInfoResponse{ 136 Type: base.PluginTypeDriver, 137 PluginApiVersions: []string{drivers.ApiVersion010}, 138 PluginVersion: "0.1.0", 139 Name: pluginName, 140 } 141 142 danglingContainersBlock = hclspec.NewObject(map[string]*hclspec.Spec{ 143 "enabled": hclspec.NewDefault( 144 hclspec.NewAttr("enabled", "bool", false), 145 hclspec.NewLiteral(`true`), 146 ), 147 "period": hclspec.NewDefault( 148 hclspec.NewAttr("period", "string", false), 149 hclspec.NewLiteral(`"5m"`), 150 ), 151 "creation_grace": hclspec.NewDefault( 152 hclspec.NewAttr("creation_grace", "string", false), 153 hclspec.NewLiteral(`"5m"`), 154 ), 155 "dry_run": hclspec.NewDefault( 156 hclspec.NewAttr("dry_run", "bool", false), 157 hclspec.NewLiteral(`false`), 158 ), 159 }) 160 161 // configSpec is the hcl specification returned by the ConfigSchema RPC 162 // and is used to parse the contents of the 'plugin "docker" {...}' block. 163 // Example: 164 // plugin "docker" { 165 // config { 166 // endpoint = "unix:///var/run/docker.sock" 167 // auth { 168 // config = "/etc/docker-auth.json" 169 // helper = "docker-credential-aws" 170 // } 171 // tls { 172 // cert = "/etc/nomad/nomad.pub" 173 // key = "/etc/nomad/nomad.pem" 174 // ca = "/etc/nomad/nomad.cert" 175 // } 176 // gc { 177 // image = true 178 // image_delay = "5m" 179 // container = false 180 // } 181 // volumes { 182 // enabled = true 183 // selinuxlabel = "z" 184 // } 185 // allow_privileged = false 186 // allow_caps = ["CHOWN", "NET_RAW" ... ] 187 // nvidia_runtime = "nvidia" 188 // } 189 // } 190 configSpec = hclspec.NewObject(map[string]*hclspec.Spec{ 191 "endpoint": hclspec.NewAttr("endpoint", "string", false), 192 193 // docker daemon auth option for image registry 194 "auth": hclspec.NewBlock("auth", false, hclspec.NewObject(map[string]*hclspec.Spec{ 195 "config": hclspec.NewAttr("config", "string", false), 196 "helper": hclspec.NewAttr("helper", "string", false), 197 })), 198 199 // client tls options 200 "tls": hclspec.NewBlock("tls", false, hclspec.NewObject(map[string]*hclspec.Spec{ 201 "cert": hclspec.NewAttr("cert", "string", false), 202 "key": hclspec.NewAttr("key", "string", false), 203 "ca": hclspec.NewAttr("ca", "string", false), 204 })), 205 206 // garbage collection options 207 // default needed for both if the gc {...} block is not set and 208 // if the default fields are missing 209 "gc": hclspec.NewDefault(hclspec.NewBlock("gc", false, hclspec.NewObject(map[string]*hclspec.Spec{ 210 "image": hclspec.NewDefault( 211 hclspec.NewAttr("image", "bool", false), 212 hclspec.NewLiteral("true"), 213 ), 214 "image_delay": hclspec.NewDefault( 215 hclspec.NewAttr("image_delay", "string", false), 216 hclspec.NewLiteral("\"3m\""), 217 ), 218 "container": hclspec.NewDefault( 219 hclspec.NewAttr("container", "bool", false), 220 hclspec.NewLiteral("true"), 221 ), 222 "dangling_containers": hclspec.NewDefault( 223 hclspec.NewBlock("dangling_containers", false, danglingContainersBlock), 224 hclspec.NewLiteral(`{ 225 enabled = true 226 period = "5m" 227 creation_grace = "5m" 228 }`), 229 ), 230 })), hclspec.NewLiteral(`{ 231 image = true 232 image_delay = "3m" 233 container = true 234 dangling_containers = { 235 enabled = true 236 period = "5m" 237 creation_grace = "5m" 238 } 239 }`)), 240 241 // docker volume options 242 // defaulted needed for both if the volumes {...} block is not set and 243 // if the default fields are missing 244 "volumes": hclspec.NewDefault(hclspec.NewBlock("volumes", false, hclspec.NewObject(map[string]*hclspec.Spec{ 245 "enabled": hclspec.NewAttr("enabled", "bool", false), 246 "selinuxlabel": hclspec.NewAttr("selinuxlabel", "string", false), 247 })), hclspec.NewLiteral("{ enabled = false }")), 248 "allow_privileged": hclspec.NewAttr("allow_privileged", "bool", false), 249 "allow_caps": hclspec.NewDefault( 250 hclspec.NewAttr("allow_caps", "list(string)", false), 251 hclspec.NewLiteral(`["CHOWN","DAC_OVERRIDE","FSETID","FOWNER","MKNOD","NET_RAW","SETGID","SETUID","SETFCAP","SETPCAP","NET_BIND_SERVICE","SYS_CHROOT","KILL","AUDIT_WRITE"]`), 252 ), 253 "nvidia_runtime": hclspec.NewDefault( 254 hclspec.NewAttr("nvidia_runtime", "string", false), 255 hclspec.NewLiteral(`"nvidia"`), 256 ), 257 // list of docker runtimes allowed to be used 258 "allow_runtimes": hclspec.NewDefault( 259 hclspec.NewAttr("allow_runtimes", "list(string)", false), 260 hclspec.NewLiteral(`["runc", "nvidia"]`), 261 ), 262 // image to use when creating a network namespace parent container 263 "infra_image": hclspec.NewDefault( 264 hclspec.NewAttr("infra_image", "string", false), 265 hclspec.NewLiteral(fmt.Sprintf( 266 `"gcr.io/google_containers/pause-%s:3.1"`, 267 runtime.GOARCH, 268 )), 269 ), 270 // timeout to use when pulling the infra image. 271 "infra_image_pull_timeout": hclspec.NewDefault( 272 hclspec.NewAttr("infra_image_pull_timeout", "string", false), 273 hclspec.NewLiteral(`"5m"`), 274 ), 275 276 // the duration that the driver will wait for activity from the Docker engine during an image pull 277 // before canceling the request 278 "pull_activity_timeout": hclspec.NewDefault( 279 hclspec.NewAttr("pull_activity_timeout", "string", false), 280 hclspec.NewLiteral(`"2m"`), 281 ), 282 // disable_log_collection indicates whether docker driver should collect logs of docker 283 // task containers. If true, nomad doesn't start docker_logger/logmon processes 284 "disable_log_collection": hclspec.NewAttr("disable_log_collection", "bool", false), 285 }) 286 287 // mountBodySpec is the hcl specification for the `mount` block 288 mountBodySpec = hclspec.NewObject(map[string]*hclspec.Spec{ 289 "type": hclspec.NewDefault( 290 hclspec.NewAttr("type", "string", false), 291 hclspec.NewLiteral("\"volume\""), 292 ), 293 "target": hclspec.NewAttr("target", "string", false), 294 "source": hclspec.NewAttr("source", "string", false), 295 "readonly": hclspec.NewAttr("readonly", "bool", false), 296 "bind_options": hclspec.NewBlock("bind_options", false, hclspec.NewObject(map[string]*hclspec.Spec{ 297 "propagation": hclspec.NewAttr("propagation", "string", false), 298 })), 299 "tmpfs_options": hclspec.NewBlock("tmpfs_options", false, hclspec.NewObject(map[string]*hclspec.Spec{ 300 "size": hclspec.NewAttr("size", "number", false), 301 "mode": hclspec.NewAttr("mode", "number", false), 302 })), 303 "volume_options": hclspec.NewBlock("volume_options", false, hclspec.NewObject(map[string]*hclspec.Spec{ 304 "no_copy": hclspec.NewAttr("no_copy", "bool", false), 305 "labels": hclspec.NewAttr("labels", "list(map(string))", false), 306 "driver_config": hclspec.NewBlock("driver_config", false, hclspec.NewObject(map[string]*hclspec.Spec{ 307 "name": hclspec.NewAttr("name", "string", false), 308 "options": hclspec.NewAttr("options", "list(map(string))", false), 309 })), 310 })), 311 }) 312 313 // taskConfigSpec is the hcl specification for the driver config section of 314 // a task within a job. It is returned in the TaskConfigSchema RPC 315 taskConfigSpec = hclspec.NewObject(map[string]*hclspec.Spec{ 316 "image": hclspec.NewAttr("image", "string", true), 317 "advertise_ipv6_address": hclspec.NewAttr("advertise_ipv6_address", "bool", false), 318 "args": hclspec.NewAttr("args", "list(string)", false), 319 "auth": hclspec.NewBlock("auth", false, hclspec.NewObject(map[string]*hclspec.Spec{ 320 "username": hclspec.NewAttr("username", "string", false), 321 "password": hclspec.NewAttr("password", "string", false), 322 "email": hclspec.NewAttr("email", "string", false), 323 "server_address": hclspec.NewAttr("server_address", "string", false), 324 })), 325 "auth_soft_fail": hclspec.NewAttr("auth_soft_fail", "bool", false), 326 "cap_add": hclspec.NewAttr("cap_add", "list(string)", false), 327 "cap_drop": hclspec.NewAttr("cap_drop", "list(string)", false), 328 "command": hclspec.NewAttr("command", "string", false), 329 "cpuset_cpus": hclspec.NewAttr("cpuset_cpus", "string", false), 330 "cpu_hard_limit": hclspec.NewAttr("cpu_hard_limit", "bool", false), 331 "cpu_cfs_period": hclspec.NewDefault( 332 hclspec.NewAttr("cpu_cfs_period", "number", false), 333 hclspec.NewLiteral(`100000`), 334 ), 335 "devices": hclspec.NewBlockList("devices", hclspec.NewObject(map[string]*hclspec.Spec{ 336 "host_path": hclspec.NewAttr("host_path", "string", false), 337 "container_path": hclspec.NewAttr("container_path", "string", false), 338 "cgroup_permissions": hclspec.NewAttr("cgroup_permissions", "string", false), 339 })), 340 "dns_search_domains": hclspec.NewAttr("dns_search_domains", "list(string)", false), 341 "dns_options": hclspec.NewAttr("dns_options", "list(string)", false), 342 "dns_servers": hclspec.NewAttr("dns_servers", "list(string)", false), 343 "entrypoint": hclspec.NewAttr("entrypoint", "list(string)", false), 344 "extra_hosts": hclspec.NewAttr("extra_hosts", "list(string)", false), 345 "force_pull": hclspec.NewAttr("force_pull", "bool", false), 346 "hostname": hclspec.NewAttr("hostname", "string", false), 347 "interactive": hclspec.NewAttr("interactive", "bool", false), 348 "ipc_mode": hclspec.NewAttr("ipc_mode", "string", false), 349 "ipv4_address": hclspec.NewAttr("ipv4_address", "string", false), 350 "ipv6_address": hclspec.NewAttr("ipv6_address", "string", false), 351 "labels": hclspec.NewAttr("labels", "list(map(string))", false), 352 "load": hclspec.NewAttr("load", "string", false), 353 "logging": hclspec.NewBlock("logging", false, hclspec.NewObject(map[string]*hclspec.Spec{ 354 "type": hclspec.NewAttr("type", "string", false), 355 "driver": hclspec.NewAttr("driver", "string", false), 356 "config": hclspec.NewAttr("config", "list(map(string))", false), 357 })), 358 "mac_address": hclspec.NewAttr("mac_address", "string", false), 359 "memory_hard_limit": hclspec.NewAttr("memory_hard_limit", "number", false), 360 // mount and mounts are effectively aliases, but `mounts` is meant for pre-1.0 361 // assignment syntax `mounts = [{type="..." ..."}]` while 362 // `mount` is 1.0 repeated block syntax `mount { type = "..." }` 363 "mount": hclspec.NewBlockList("mount", mountBodySpec), 364 "mounts": hclspec.NewBlockList("mounts", mountBodySpec), 365 "network_aliases": hclspec.NewAttr("network_aliases", "list(string)", false), 366 "network_mode": hclspec.NewAttr("network_mode", "string", false), 367 "runtime": hclspec.NewAttr("runtime", "string", false), 368 "pids_limit": hclspec.NewAttr("pids_limit", "number", false), 369 "pid_mode": hclspec.NewAttr("pid_mode", "string", false), 370 "ports": hclspec.NewAttr("ports", "list(string)", false), 371 "port_map": hclspec.NewAttr("port_map", "list(map(number))", false), 372 "privileged": hclspec.NewAttr("privileged", "bool", false), 373 "image_pull_timeout": hclspec.NewDefault( 374 hclspec.NewAttr("image_pull_timeout", "string", false), 375 hclspec.NewLiteral(`"5m"`), 376 ), 377 "readonly_rootfs": hclspec.NewAttr("readonly_rootfs", "bool", false), 378 "security_opt": hclspec.NewAttr("security_opt", "list(string)", false), 379 "shm_size": hclspec.NewAttr("shm_size", "number", false), 380 "storage_opt": hclspec.NewBlockAttrs("storage_opt", "string", false), 381 "sysctl": hclspec.NewAttr("sysctl", "list(map(string))", false), 382 "tty": hclspec.NewAttr("tty", "bool", false), 383 "ulimit": hclspec.NewAttr("ulimit", "list(map(string))", false), 384 "uts_mode": hclspec.NewAttr("uts_mode", "string", false), 385 "userns_mode": hclspec.NewAttr("userns_mode", "string", false), 386 "volumes": hclspec.NewAttr("volumes", "list(string)", false), 387 "volume_driver": hclspec.NewAttr("volume_driver", "string", false), 388 "work_dir": hclspec.NewAttr("work_dir", "string", false), 389 }) 390 391 // capabilities is returned by the Capabilities RPC and indicates what 392 // optional features this driver supports 393 capabilities = &drivers.Capabilities{ 394 SendSignals: true, 395 Exec: true, 396 FSIsolation: drivers.FSIsolationImage, 397 NetIsolationModes: []drivers.NetIsolationMode{ 398 drivers.NetIsolationModeHost, 399 drivers.NetIsolationModeGroup, 400 drivers.NetIsolationModeTask, 401 }, 402 MustInitiateNetwork: true, 403 MountConfigs: drivers.MountConfigSupportAll, 404 } 405 ) 406 407 type TaskConfig struct { 408 Image string `codec:"image"` 409 AdvertiseIPv6Addr bool `codec:"advertise_ipv6_address"` 410 Args []string `codec:"args"` 411 Auth DockerAuth `codec:"auth"` 412 AuthSoftFail bool `codec:"auth_soft_fail"` 413 CapAdd []string `codec:"cap_add"` 414 CapDrop []string `codec:"cap_drop"` 415 Command string `codec:"command"` 416 CPUCFSPeriod int64 `codec:"cpu_cfs_period"` 417 CPUHardLimit bool `codec:"cpu_hard_limit"` 418 CPUSetCPUs string `codec:"cpuset_cpus"` 419 Devices []DockerDevice `codec:"devices"` 420 DNSSearchDomains []string `codec:"dns_search_domains"` 421 DNSOptions []string `codec:"dns_options"` 422 DNSServers []string `codec:"dns_servers"` 423 Entrypoint []string `codec:"entrypoint"` 424 ExtraHosts []string `codec:"extra_hosts"` 425 ForcePull bool `codec:"force_pull"` 426 Hostname string `codec:"hostname"` 427 Interactive bool `codec:"interactive"` 428 IPCMode string `codec:"ipc_mode"` 429 IPv4Address string `codec:"ipv4_address"` 430 IPv6Address string `codec:"ipv6_address"` 431 Labels hclutils.MapStrStr `codec:"labels"` 432 LoadImage string `codec:"load"` 433 Logging DockerLogging `codec:"logging"` 434 MacAddress string `codec:"mac_address"` 435 MemoryHardLimit int64 `codec:"memory_hard_limit"` 436 Mounts []DockerMount `codec:"mount"` 437 NetworkAliases []string `codec:"network_aliases"` 438 NetworkMode string `codec:"network_mode"` 439 Runtime string `codec:"runtime"` 440 PidsLimit int64 `codec:"pids_limit"` 441 PidMode string `codec:"pid_mode"` 442 Ports []string `codec:"ports"` 443 PortMap hclutils.MapStrInt `codec:"port_map"` 444 Privileged bool `codec:"privileged"` 445 ImagePullTimeout string `codec:"image_pull_timeout"` 446 ReadonlyRootfs bool `codec:"readonly_rootfs"` 447 SecurityOpt []string `codec:"security_opt"` 448 ShmSize int64 `codec:"shm_size"` 449 StorageOpt map[string]string `codec:"storage_opt"` 450 Sysctl hclutils.MapStrStr `codec:"sysctl"` 451 TTY bool `codec:"tty"` 452 Ulimit hclutils.MapStrStr `codec:"ulimit"` 453 UTSMode string `codec:"uts_mode"` 454 UsernsMode string `codec:"userns_mode"` 455 Volumes []string `codec:"volumes"` 456 VolumeDriver string `codec:"volume_driver"` 457 WorkDir string `codec:"work_dir"` 458 459 // MountsList supports the pre-1.0 mounts array syntax 460 MountsList []DockerMount `codec:"mounts"` 461 } 462 463 type DockerAuth struct { 464 Username string `codec:"username"` 465 Password string `codec:"password"` 466 Email string `codec:"email"` 467 ServerAddr string `codec:"server_address"` 468 } 469 470 type DockerDevice struct { 471 HostPath string `codec:"host_path"` 472 ContainerPath string `codec:"container_path"` 473 CgroupPermissions string `codec:"cgroup_permissions"` 474 } 475 476 func (d DockerDevice) toDockerDevice() (docker.Device, error) { 477 dd := docker.Device{ 478 PathOnHost: d.HostPath, 479 PathInContainer: d.ContainerPath, 480 CgroupPermissions: d.CgroupPermissions, 481 } 482 483 if d.HostPath == "" { 484 return dd, fmt.Errorf("host path must be set in configuration for devices") 485 } 486 487 if dd.CgroupPermissions == "" { 488 dd.CgroupPermissions = "rwm" 489 } 490 491 if !validateCgroupPermission(dd.CgroupPermissions) { 492 return dd, fmt.Errorf("invalid cgroup permission string: %q", dd.CgroupPermissions) 493 } 494 495 return dd, nil 496 } 497 498 type DockerLogging struct { 499 Type string `codec:"type"` 500 Driver string `codec:"driver"` 501 Config hclutils.MapStrStr `codec:"config"` 502 } 503 504 type DockerMount struct { 505 Type string `codec:"type"` 506 Target string `codec:"target"` 507 Source string `codec:"source"` 508 ReadOnly bool `codec:"readonly"` 509 BindOptions DockerBindOptions `codec:"bind_options"` 510 VolumeOptions DockerVolumeOptions `codec:"volume_options"` 511 TmpfsOptions DockerTmpfsOptions `codec:"tmpfs_options"` 512 } 513 514 func (m DockerMount) toDockerHostMount() (docker.HostMount, error) { 515 if m.Type == "" { 516 // for backward compatibility, as type is optional 517 m.Type = "volume" 518 } 519 520 hm := docker.HostMount{ 521 Target: m.Target, 522 Source: m.Source, 523 Type: m.Type, 524 ReadOnly: m.ReadOnly, 525 } 526 527 switch m.Type { 528 case "volume": 529 vo := m.VolumeOptions 530 hm.VolumeOptions = &docker.VolumeOptions{ 531 NoCopy: vo.NoCopy, 532 Labels: vo.Labels, 533 DriverConfig: docker.VolumeDriverConfig{ 534 Name: vo.DriverConfig.Name, 535 Options: vo.DriverConfig.Options, 536 }, 537 } 538 case "bind": 539 hm.BindOptions = &docker.BindOptions{ 540 Propagation: m.BindOptions.Propagation, 541 } 542 case "tmpfs": 543 if m.Source != "" { 544 return hm, fmt.Errorf(`invalid source, must be "" for tmpfs`) 545 } 546 hm.TempfsOptions = &docker.TempfsOptions{ 547 SizeBytes: m.TmpfsOptions.SizeBytes, 548 Mode: m.TmpfsOptions.Mode, 549 } 550 default: 551 return hm, fmt.Errorf(`invalid mount type, must be "bind", "volume", "tmpfs": %q`, m.Type) 552 } 553 554 return hm, nil 555 } 556 557 type DockerVolumeOptions struct { 558 NoCopy bool `codec:"no_copy"` 559 Labels hclutils.MapStrStr `codec:"labels"` 560 DriverConfig DockerVolumeDriverConfig `codec:"driver_config"` 561 } 562 563 type DockerBindOptions struct { 564 Propagation string `codec:"propagation"` 565 } 566 567 type DockerTmpfsOptions struct { 568 SizeBytes int64 `codec:"size"` 569 Mode int `codec:"mode"` 570 } 571 572 // DockerVolumeDriverConfig holds a map of volume driver specific options 573 type DockerVolumeDriverConfig struct { 574 Name string `codec:"name"` 575 Options hclutils.MapStrStr `codec:"options"` 576 } 577 578 // ContainerGCConfig controls the behavior of the GC reconciler to detects 579 // dangling nomad containers that aren't tracked due to docker/nomad bugs 580 type ContainerGCConfig struct { 581 // Enabled controls whether container reconciler is enabled 582 Enabled bool `codec:"enabled"` 583 584 // DryRun indicates that reconciler should log unexpectedly running containers 585 // if found without actually killing them 586 DryRun bool `codec:"dry_run"` 587 588 // PeriodStr controls the frequency of scanning containers 589 PeriodStr string `codec:"period"` 590 period time.Duration `codec:"-"` 591 592 // CreationGraceStr is the duration allowed for a newly created container 593 // to live without being registered as a running task in nomad. 594 // A container is treated as leaked if it lived more than grace duration 595 // and haven't been registered in tasks. 596 CreationGraceStr string `codec:"creation_grace"` 597 CreationGrace time.Duration `codec:"-"` 598 } 599 600 type DriverConfig struct { 601 Endpoint string `codec:"endpoint"` 602 Auth AuthConfig `codec:"auth"` 603 TLS TLSConfig `codec:"tls"` 604 GC GCConfig `codec:"gc"` 605 Volumes VolumeConfig `codec:"volumes"` 606 AllowPrivileged bool `codec:"allow_privileged"` 607 AllowCaps []string `codec:"allow_caps"` 608 GPURuntimeName string `codec:"nvidia_runtime"` 609 InfraImage string `codec:"infra_image"` 610 InfraImagePullTimeout string `codec:"infra_image_pull_timeout"` 611 infraImagePullTimeoutDuration time.Duration `codec:"-"` 612 DisableLogCollection bool `codec:"disable_log_collection"` 613 PullActivityTimeout string `codec:"pull_activity_timeout"` 614 pullActivityTimeoutDuration time.Duration `codec:"-"` 615 616 AllowRuntimesList []string `codec:"allow_runtimes"` 617 allowRuntimes map[string]struct{} `codec:"-"` 618 } 619 620 type AuthConfig struct { 621 Config string `codec:"config"` 622 Helper string `codec:"helper"` 623 } 624 625 type TLSConfig struct { 626 Cert string `codec:"cert"` 627 Key string `codec:"key"` 628 CA string `codec:"ca"` 629 } 630 631 type GCConfig struct { 632 Image bool `codec:"image"` 633 ImageDelay string `codec:"image_delay"` 634 imageDelayDuration time.Duration `codec:"-"` 635 Container bool `codec:"container"` 636 637 DanglingContainers ContainerGCConfig `codec:"dangling_containers"` 638 } 639 640 type VolumeConfig struct { 641 Enabled bool `codec:"enabled"` 642 SelinuxLabel string `codec:"selinuxlabel"` 643 } 644 645 func (d *Driver) PluginInfo() (*base.PluginInfoResponse, error) { 646 return pluginInfo, nil 647 } 648 649 func (d *Driver) ConfigSchema() (*hclspec.Spec, error) { 650 return configSpec, nil 651 } 652 653 const danglingContainersCreationGraceMinimum = 1 * time.Minute 654 const pullActivityTimeoutMinimum = 1 * time.Minute 655 656 func (d *Driver) SetConfig(c *base.Config) error { 657 var config DriverConfig 658 if len(c.PluginConfig) != 0 { 659 if err := base.MsgPackDecode(c.PluginConfig, &config); err != nil { 660 return err 661 } 662 } 663 664 d.config = &config 665 d.config.InfraImage = strings.TrimPrefix(d.config.InfraImage, "https://") 666 667 if len(d.config.GC.ImageDelay) > 0 { 668 dur, err := time.ParseDuration(d.config.GC.ImageDelay) 669 if err != nil { 670 return fmt.Errorf("failed to parse 'image_delay' duration: %v", err) 671 } 672 d.config.GC.imageDelayDuration = dur 673 } 674 675 if len(d.config.GC.DanglingContainers.PeriodStr) > 0 { 676 dur, err := time.ParseDuration(d.config.GC.DanglingContainers.PeriodStr) 677 if err != nil { 678 return fmt.Errorf("failed to parse 'period' duration: %v", err) 679 } 680 d.config.GC.DanglingContainers.period = dur 681 } 682 683 if len(d.config.GC.DanglingContainers.CreationGraceStr) > 0 { 684 dur, err := time.ParseDuration(d.config.GC.DanglingContainers.CreationGraceStr) 685 if err != nil { 686 return fmt.Errorf("failed to parse 'creation_grace' duration: %v", err) 687 } 688 if dur < danglingContainersCreationGraceMinimum { 689 return fmt.Errorf("creation_grace is less than minimum, %v", danglingContainersCreationGraceMinimum) 690 } 691 d.config.GC.DanglingContainers.CreationGrace = dur 692 } 693 694 if len(d.config.PullActivityTimeout) > 0 { 695 dur, err := time.ParseDuration(d.config.PullActivityTimeout) 696 if err != nil { 697 return fmt.Errorf("failed to parse 'pull_activity_timeout' duaration: %v", err) 698 } 699 if dur < pullActivityTimeoutMinimum { 700 return fmt.Errorf("pull_activity_timeout is less than minimum, %v", pullActivityTimeoutMinimum) 701 } 702 d.config.pullActivityTimeoutDuration = dur 703 } 704 705 if d.config.InfraImagePullTimeout != "" { 706 dur, err := time.ParseDuration(d.config.InfraImagePullTimeout) 707 if err != nil { 708 return fmt.Errorf("failed to parse 'infra_image_pull_timeout' duaration: %v", err) 709 } 710 d.config.infraImagePullTimeoutDuration = dur 711 } 712 713 d.config.allowRuntimes = make(map[string]struct{}, len(d.config.AllowRuntimesList)) 714 for _, r := range d.config.AllowRuntimesList { 715 d.config.allowRuntimes[r] = struct{}{} 716 } 717 718 if c.AgentConfig != nil { 719 d.clientConfig = c.AgentConfig.Driver 720 } 721 722 dockerClient, _, err := d.dockerClients() 723 if err != nil { 724 return fmt.Errorf("failed to get docker client: %v", err) 725 } 726 coordinatorConfig := &dockerCoordinatorConfig{ 727 ctx: d.ctx, 728 client: dockerClient, 729 cleanup: d.config.GC.Image, 730 logger: d.logger, 731 removeDelay: d.config.GC.imageDelayDuration, 732 } 733 734 d.coordinator = newDockerCoordinator(coordinatorConfig) 735 736 d.reconciler = newReconciler(d) 737 738 return nil 739 } 740 741 func (d *Driver) TaskConfigSchema() (*hclspec.Spec, error) { 742 return taskConfigSpec, nil 743 } 744 745 func (d *Driver) Capabilities() (*drivers.Capabilities, error) { 746 return capabilities, nil 747 } 748 749 var _ drivers.InternalCapabilitiesDriver = (*Driver)(nil) 750 751 func (d *Driver) InternalCapabilities() drivers.InternalCapabilities { 752 return drivers.InternalCapabilities{ 753 DisableLogCollection: d.config != nil && d.config.DisableLogCollection, 754 } 755 }