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