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  }