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  }