github.com/ilhicas/nomad@v0.11.8/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.NewAttr("enabled", "bool", false), 241 "selinuxlabel": hclspec.NewAttr("selinuxlabel", "string", false), 242 })), hclspec.NewLiteral("{ enabled = true }")), 243 "allow_privileged": hclspec.NewAttr("allow_privileged", "bool", false), 244 "allow_caps": hclspec.NewDefault( 245 hclspec.NewAttr("allow_caps", "list(string)", false), 246 hclspec.NewLiteral(`["CHOWN","DAC_OVERRIDE","FSETID","FOWNER","MKNOD","NET_RAW","SETGID","SETUID","SETFCAP","SETPCAP","NET_BIND_SERVICE","SYS_CHROOT","KILL","AUDIT_WRITE"]`), 247 ), 248 "nvidia_runtime": hclspec.NewDefault( 249 hclspec.NewAttr("nvidia_runtime", "string", false), 250 hclspec.NewLiteral(`"nvidia"`), 251 ), 252 // list of docker runtimes allowed to be used 253 "allow_runtimes": hclspec.NewDefault( 254 hclspec.NewAttr("allow_runtimes", "list(string)", false), 255 hclspec.NewLiteral(`["runc", "nvidia"]`), 256 ), 257 // image to use when creating a network namespace parent container 258 "infra_image": hclspec.NewDefault( 259 hclspec.NewAttr("infra_image", "string", false), 260 hclspec.NewLiteral(`"gcr.io/google_containers/pause-amd64:3.0"`), 261 ), 262 263 // the duration that the driver will wait for activity from the Docker engine during an image pull 264 // before canceling the request 265 "pull_activity_timeout": hclspec.NewDefault( 266 hclspec.NewAttr("pull_activity_timeout", "string", false), 267 hclspec.NewLiteral(`"2m"`), 268 ), 269 270 // disable_log_collection indicates whether docker driver should collect logs of docker 271 // task containers. If true, nomad doesn't start docker_logger/logmon processes 272 "disable_log_collection": hclspec.NewAttr("disable_log_collection", "bool", false), 273 }) 274 275 // taskConfigSpec is the hcl specification for the driver config section of 276 // a task within a job. It is returned in the TaskConfigSchema RPC 277 taskConfigSpec = hclspec.NewObject(map[string]*hclspec.Spec{ 278 "image": hclspec.NewAttr("image", "string", true), 279 "advertise_ipv6_address": hclspec.NewAttr("advertise_ipv6_address", "bool", false), 280 "args": hclspec.NewAttr("args", "list(string)", false), 281 "auth": hclspec.NewBlock("auth", false, hclspec.NewObject(map[string]*hclspec.Spec{ 282 "username": hclspec.NewAttr("username", "string", false), 283 "password": hclspec.NewAttr("password", "string", false), 284 "email": hclspec.NewAttr("email", "string", false), 285 "server_address": hclspec.NewAttr("server_address", "string", false), 286 })), 287 "auth_soft_fail": hclspec.NewAttr("auth_soft_fail", "bool", false), 288 "cap_add": hclspec.NewAttr("cap_add", "list(string)", false), 289 "cap_drop": hclspec.NewAttr("cap_drop", "list(string)", false), 290 "command": hclspec.NewAttr("command", "string", false), 291 "cpu_hard_limit": hclspec.NewAttr("cpu_hard_limit", "bool", false), 292 "cpu_cfs_period": hclspec.NewDefault( 293 hclspec.NewAttr("cpu_cfs_period", "number", false), 294 hclspec.NewLiteral(`100000`), 295 ), 296 "devices": hclspec.NewBlockList("devices", hclspec.NewObject(map[string]*hclspec.Spec{ 297 "host_path": hclspec.NewAttr("host_path", "string", false), 298 "container_path": hclspec.NewAttr("container_path", "string", false), 299 "cgroup_permissions": hclspec.NewAttr("cgroup_permissions", "string", false), 300 })), 301 "dns_search_domains": hclspec.NewAttr("dns_search_domains", "list(string)", false), 302 "dns_options": hclspec.NewAttr("dns_options", "list(string)", false), 303 "dns_servers": hclspec.NewAttr("dns_servers", "list(string)", false), 304 "entrypoint": hclspec.NewAttr("entrypoint", "list(string)", false), 305 "extra_hosts": hclspec.NewAttr("extra_hosts", "list(string)", false), 306 "force_pull": hclspec.NewAttr("force_pull", "bool", false), 307 "hostname": hclspec.NewAttr("hostname", "string", false), 308 "interactive": hclspec.NewAttr("interactive", "bool", false), 309 "ipc_mode": hclspec.NewAttr("ipc_mode", "string", false), 310 "ipv4_address": hclspec.NewAttr("ipv4_address", "string", false), 311 "ipv6_address": hclspec.NewAttr("ipv6_address", "string", false), 312 "labels": hclspec.NewAttr("labels", "list(map(string))", false), 313 "load": hclspec.NewAttr("load", "string", false), 314 "logging": hclspec.NewBlock("logging", false, hclspec.NewObject(map[string]*hclspec.Spec{ 315 "type": hclspec.NewAttr("type", "string", false), 316 "driver": hclspec.NewAttr("driver", "string", false), 317 "config": hclspec.NewAttr("config", "list(map(string))", false), 318 })), 319 "mac_address": hclspec.NewAttr("mac_address", "string", false), 320 "memory_hard_limit": hclspec.NewAttr("memory_hard_limit", "number", false), 321 "mounts": hclspec.NewBlockList("mounts", hclspec.NewObject(map[string]*hclspec.Spec{ 322 "type": hclspec.NewDefault( 323 hclspec.NewAttr("type", "string", false), 324 hclspec.NewLiteral("\"volume\""), 325 ), 326 "target": hclspec.NewAttr("target", "string", false), 327 "source": hclspec.NewAttr("source", "string", false), 328 "readonly": hclspec.NewAttr("readonly", "bool", false), 329 "bind_options": hclspec.NewBlock("bind_options", false, hclspec.NewObject(map[string]*hclspec.Spec{ 330 "propagation": hclspec.NewAttr("propagation", "string", false), 331 })), 332 "tmpfs_options": hclspec.NewBlock("tmpfs_options", false, hclspec.NewObject(map[string]*hclspec.Spec{ 333 "size": hclspec.NewAttr("size", "number", false), 334 "mode": hclspec.NewAttr("mode", "number", false), 335 })), 336 "volume_options": hclspec.NewBlock("volume_options", false, hclspec.NewObject(map[string]*hclspec.Spec{ 337 "no_copy": hclspec.NewAttr("no_copy", "bool", false), 338 "labels": hclspec.NewAttr("labels", "list(map(string))", false), 339 "driver_config": hclspec.NewBlock("driver_config", false, hclspec.NewObject(map[string]*hclspec.Spec{ 340 "name": hclspec.NewAttr("name", "string", false), 341 "options": hclspec.NewAttr("options", "list(map(string))", false), 342 })), 343 })), 344 })), 345 "network_aliases": hclspec.NewAttr("network_aliases", "list(string)", false), 346 "network_mode": hclspec.NewAttr("network_mode", "string", false), 347 "runtime": hclspec.NewAttr("runtime", "string", false), 348 "pids_limit": hclspec.NewAttr("pids_limit", "number", false), 349 "pid_mode": hclspec.NewAttr("pid_mode", "string", false), 350 "port_map": hclspec.NewAttr("port_map", "list(map(number))", false), 351 "privileged": hclspec.NewAttr("privileged", "bool", false), 352 "readonly_rootfs": hclspec.NewAttr("readonly_rootfs", "bool", false), 353 "security_opt": hclspec.NewAttr("security_opt", "list(string)", false), 354 "shm_size": hclspec.NewAttr("shm_size", "number", false), 355 "storage_opt": hclspec.NewBlockAttrs("storage_opt", "string", false), 356 "sysctl": hclspec.NewAttr("sysctl", "list(map(string))", false), 357 "tty": hclspec.NewAttr("tty", "bool", false), 358 "ulimit": hclspec.NewAttr("ulimit", "list(map(string))", false), 359 "uts_mode": hclspec.NewAttr("uts_mode", "string", false), 360 "userns_mode": hclspec.NewAttr("userns_mode", "string", false), 361 "volumes": hclspec.NewAttr("volumes", "list(string)", false), 362 "volume_driver": hclspec.NewAttr("volume_driver", "string", false), 363 "work_dir": hclspec.NewAttr("work_dir", "string", false), 364 }) 365 366 // capabilities is returned by the Capabilities RPC and indicates what 367 // optional features this driver supports 368 capabilities = &drivers.Capabilities{ 369 SendSignals: true, 370 Exec: true, 371 FSIsolation: drivers.FSIsolationImage, 372 NetIsolationModes: []drivers.NetIsolationMode{ 373 drivers.NetIsolationModeHost, 374 drivers.NetIsolationModeGroup, 375 drivers.NetIsolationModeTask, 376 }, 377 MustInitiateNetwork: true, 378 MountConfigs: drivers.MountConfigSupportAll, 379 } 380 ) 381 382 type TaskConfig struct { 383 Image string `codec:"image"` 384 AdvertiseIPv6Addr bool `codec:"advertise_ipv6_address"` 385 Args []string `codec:"args"` 386 Auth DockerAuth `codec:"auth"` 387 AuthSoftFail bool `codec:"auth_soft_fail"` 388 CapAdd []string `codec:"cap_add"` 389 CapDrop []string `codec:"cap_drop"` 390 Command string `codec:"command"` 391 CPUCFSPeriod int64 `codec:"cpu_cfs_period"` 392 CPUHardLimit bool `codec:"cpu_hard_limit"` 393 Devices []DockerDevice `codec:"devices"` 394 DNSSearchDomains []string `codec:"dns_search_domains"` 395 DNSOptions []string `codec:"dns_options"` 396 DNSServers []string `codec:"dns_servers"` 397 Entrypoint []string `codec:"entrypoint"` 398 ExtraHosts []string `codec:"extra_hosts"` 399 ForcePull bool `codec:"force_pull"` 400 Hostname string `codec:"hostname"` 401 Interactive bool `codec:"interactive"` 402 IPCMode string `codec:"ipc_mode"` 403 IPv4Address string `codec:"ipv4_address"` 404 IPv6Address string `codec:"ipv6_address"` 405 Labels hclutils.MapStrStr `codec:"labels"` 406 LoadImage string `codec:"load"` 407 Logging DockerLogging `codec:"logging"` 408 MacAddress string `codec:"mac_address"` 409 MemoryHardLimit int64 `codec:"memory_hard_limit"` 410 Mounts []DockerMount `codec:"mounts"` 411 NetworkAliases []string `codec:"network_aliases"` 412 NetworkMode string `codec:"network_mode"` 413 Runtime string `codec:"runtime"` 414 PidsLimit int64 `codec:"pids_limit"` 415 PidMode string `codec:"pid_mode"` 416 PortMap hclutils.MapStrInt `codec:"port_map"` 417 Privileged bool `codec:"privileged"` 418 ReadonlyRootfs bool `codec:"readonly_rootfs"` 419 SecurityOpt []string `codec:"security_opt"` 420 ShmSize int64 `codec:"shm_size"` 421 StorageOpt map[string]string `codec:"storage_opt"` 422 Sysctl hclutils.MapStrStr `codec:"sysctl"` 423 TTY bool `codec:"tty"` 424 Ulimit hclutils.MapStrStr `codec:"ulimit"` 425 UTSMode string `codec:"uts_mode"` 426 UsernsMode string `codec:"userns_mode"` 427 Volumes []string `codec:"volumes"` 428 VolumeDriver string `codec:"volume_driver"` 429 WorkDir string `codec:"work_dir"` 430 } 431 432 type DockerAuth struct { 433 Username string `codec:"username"` 434 Password string `codec:"password"` 435 Email string `codec:"email"` 436 ServerAddr string `codec:"server_address"` 437 } 438 439 type DockerDevice struct { 440 HostPath string `codec:"host_path"` 441 ContainerPath string `codec:"container_path"` 442 CgroupPermissions string `codec:"cgroup_permissions"` 443 } 444 445 func (d DockerDevice) toDockerDevice() (docker.Device, error) { 446 dd := docker.Device{ 447 PathOnHost: d.HostPath, 448 PathInContainer: d.ContainerPath, 449 CgroupPermissions: d.CgroupPermissions, 450 } 451 452 if d.HostPath == "" { 453 return dd, fmt.Errorf("host path must be set in configuration for devices") 454 } 455 456 if dd.CgroupPermissions == "" { 457 dd.CgroupPermissions = "rwm" 458 } 459 460 if !validateCgroupPermission(dd.CgroupPermissions) { 461 return dd, fmt.Errorf("invalid cgroup permission string: %q", dd.CgroupPermissions) 462 } 463 464 return dd, nil 465 } 466 467 type DockerLogging struct { 468 Type string `codec:"type"` 469 Driver string `codec:"driver"` 470 Config hclutils.MapStrStr `codec:"config"` 471 } 472 473 type DockerMount struct { 474 Type string `codec:"type"` 475 Target string `codec:"target"` 476 Source string `codec:"source"` 477 ReadOnly bool `codec:"readonly"` 478 BindOptions DockerBindOptions `codec:"bind_options"` 479 VolumeOptions DockerVolumeOptions `codec:"volume_options"` 480 TmpfsOptions DockerTmpfsOptions `codec:"tmpfs_options"` 481 } 482 483 func (m DockerMount) toDockerHostMount() (docker.HostMount, error) { 484 if m.Type == "" { 485 // for backward compatbility, as type is optional 486 m.Type = "volume" 487 } 488 489 hm := docker.HostMount{ 490 Target: m.Target, 491 Source: m.Source, 492 Type: m.Type, 493 ReadOnly: m.ReadOnly, 494 } 495 496 switch m.Type { 497 case "volume": 498 vo := m.VolumeOptions 499 hm.VolumeOptions = &docker.VolumeOptions{ 500 NoCopy: vo.NoCopy, 501 Labels: vo.Labels, 502 DriverConfig: docker.VolumeDriverConfig{ 503 Name: vo.DriverConfig.Name, 504 Options: vo.DriverConfig.Options, 505 }, 506 } 507 case "bind": 508 hm.BindOptions = &docker.BindOptions{ 509 Propagation: m.BindOptions.Propagation, 510 } 511 case "tmpfs": 512 if m.Source != "" { 513 return hm, fmt.Errorf(`invalid source, must be "" for tmpfs`) 514 } 515 hm.TempfsOptions = &docker.TempfsOptions{ 516 SizeBytes: m.TmpfsOptions.SizeBytes, 517 Mode: m.TmpfsOptions.Mode, 518 } 519 default: 520 return hm, fmt.Errorf(`invalid mount type, must be "bind", "volume", "tmpfs": %q`, m.Type) 521 } 522 523 return hm, nil 524 } 525 526 type DockerVolumeOptions struct { 527 NoCopy bool `codec:"no_copy"` 528 Labels hclutils.MapStrStr `codec:"labels"` 529 DriverConfig DockerVolumeDriverConfig `codec:"driver_config"` 530 } 531 532 type DockerBindOptions struct { 533 Propagation string `codec:"propagation"` 534 } 535 536 type DockerTmpfsOptions struct { 537 SizeBytes int64 `codec:"size"` 538 Mode int `codec:"mode"` 539 } 540 541 // DockerVolumeDriverConfig holds a map of volume driver specific options 542 type DockerVolumeDriverConfig struct { 543 Name string `codec:"name"` 544 Options hclutils.MapStrStr `codec:"options"` 545 } 546 547 // ContainerGCConfig controls the behavior of the GC reconciler to detects 548 // dangling nomad containers that aren't tracked due to docker/nomad bugs 549 type ContainerGCConfig struct { 550 // Enabled controls whether container reconciler is enabled 551 Enabled bool `codec:"enabled"` 552 553 // DryRun indicates that reconciler should log unexpectedly running containers 554 // if found without actually killing them 555 DryRun bool `codec:"dry_run"` 556 557 // PeriodStr controls the frequency of scanning containers 558 PeriodStr string `codec:"period"` 559 period time.Duration `codec:"-"` 560 561 // CreationGraceStr is the duration allowed for a newly created container 562 // to live without being registered as a running task in nomad. 563 // A container is treated as leaked if it lived more than grace duration 564 // and haven't been registered in tasks. 565 CreationGraceStr string `codec:"creation_grace"` 566 CreationGrace time.Duration `codec:"-"` 567 } 568 569 type DriverConfig struct { 570 Endpoint string `codec:"endpoint"` 571 Auth AuthConfig `codec:"auth"` 572 TLS TLSConfig `codec:"tls"` 573 GC GCConfig `codec:"gc"` 574 Volumes VolumeConfig `codec:"volumes"` 575 AllowPrivileged bool `codec:"allow_privileged"` 576 AllowCaps []string `codec:"allow_caps"` 577 GPURuntimeName string `codec:"nvidia_runtime"` 578 InfraImage string `codec:"infra_image"` 579 DisableLogCollection bool `codec:"disable_log_collection"` 580 PullActivityTimeout string `codec:"pull_activity_timeout"` 581 pullActivityTimeoutDuration time.Duration `codec:"-"` 582 583 AllowRuntimesList []string `codec:"allow_runtimes"` 584 allowRuntimes map[string]struct{} `codec:"-"` 585 } 586 587 type AuthConfig struct { 588 Config string `codec:"config"` 589 Helper string `codec:"helper"` 590 } 591 592 type TLSConfig struct { 593 Cert string `codec:"cert"` 594 Key string `codec:"key"` 595 CA string `codec:"ca"` 596 } 597 598 type GCConfig struct { 599 Image bool `codec:"image"` 600 ImageDelay string `codec:"image_delay"` 601 imageDelayDuration time.Duration `codec:"-"` 602 Container bool `codec:"container"` 603 604 DanglingContainers ContainerGCConfig `codec:"dangling_containers"` 605 } 606 607 type VolumeConfig struct { 608 Enabled bool `codec:"enabled"` 609 SelinuxLabel string `codec:"selinuxlabel"` 610 } 611 612 func (d *Driver) PluginInfo() (*base.PluginInfoResponse, error) { 613 return pluginInfo, nil 614 } 615 616 func (d *Driver) ConfigSchema() (*hclspec.Spec, error) { 617 return configSpec, nil 618 } 619 620 const danglingContainersCreationGraceMinimum = 1 * time.Minute 621 const pullActivityTimeoutMinimum = 1 * time.Minute 622 623 func (d *Driver) SetConfig(c *base.Config) error { 624 var config DriverConfig 625 if len(c.PluginConfig) != 0 { 626 if err := base.MsgPackDecode(c.PluginConfig, &config); err != nil { 627 return err 628 } 629 } 630 631 d.config = &config 632 if len(d.config.GC.ImageDelay) > 0 { 633 dur, err := time.ParseDuration(d.config.GC.ImageDelay) 634 if err != nil { 635 return fmt.Errorf("failed to parse 'image_delay' duration: %v", err) 636 } 637 d.config.GC.imageDelayDuration = dur 638 } 639 640 if len(d.config.GC.DanglingContainers.PeriodStr) > 0 { 641 dur, err := time.ParseDuration(d.config.GC.DanglingContainers.PeriodStr) 642 if err != nil { 643 return fmt.Errorf("failed to parse 'period' duration: %v", err) 644 } 645 d.config.GC.DanglingContainers.period = dur 646 } 647 648 if len(d.config.GC.DanglingContainers.CreationGraceStr) > 0 { 649 dur, err := time.ParseDuration(d.config.GC.DanglingContainers.CreationGraceStr) 650 if err != nil { 651 return fmt.Errorf("failed to parse 'creation_grace' duration: %v", err) 652 } 653 if dur < danglingContainersCreationGraceMinimum { 654 return fmt.Errorf("creation_grace is less than minimum, %v", danglingContainersCreationGraceMinimum) 655 } 656 d.config.GC.DanglingContainers.CreationGrace = dur 657 } 658 659 if len(d.config.PullActivityTimeout) > 0 { 660 dur, err := time.ParseDuration(d.config.PullActivityTimeout) 661 if err != nil { 662 return fmt.Errorf("failed to parse 'pull_activity_timeout' duaration: %v", err) 663 } 664 if dur < pullActivityTimeoutMinimum { 665 return fmt.Errorf("pull_activity_timeout is less than minimum, %v", pullActivityTimeoutMinimum) 666 } 667 d.config.pullActivityTimeoutDuration = dur 668 } 669 670 d.config.allowRuntimes = make(map[string]struct{}, len(d.config.AllowRuntimesList)) 671 for _, r := range d.config.AllowRuntimesList { 672 d.config.allowRuntimes[r] = struct{}{} 673 } 674 675 if c.AgentConfig != nil { 676 d.clientConfig = c.AgentConfig.Driver 677 } 678 679 dockerClient, _, err := d.dockerClients() 680 if err != nil { 681 return fmt.Errorf("failed to get docker client: %v", err) 682 } 683 coordinatorConfig := &dockerCoordinatorConfig{ 684 ctx: d.ctx, 685 client: dockerClient, 686 cleanup: d.config.GC.Image, 687 logger: d.logger, 688 removeDelay: d.config.GC.imageDelayDuration, 689 } 690 691 d.coordinator = newDockerCoordinator(coordinatorConfig) 692 693 d.reconciler = newReconciler(d) 694 695 return nil 696 } 697 698 func (d *Driver) TaskConfigSchema() (*hclspec.Spec, error) { 699 return taskConfigSpec, nil 700 } 701 702 func (d *Driver) Capabilities() (*drivers.Capabilities, error) { 703 return capabilities, nil 704 } 705 706 var _ drivers.InternalCapabilitiesDriver = (*Driver)(nil) 707 708 func (d *Driver) InternalCapabilities() drivers.InternalCapabilities { 709 return drivers.InternalCapabilities{ 710 DisableLogCollection: d.config != nil && d.config.DisableLogCollection, 711 } 712 }