github.com/bigcommerce/nomad@v0.9.3-bc/drivers/docker/config.go (about)

     1  package docker
     2  
     3  import (
     4  	"fmt"
     5  	"strconv"
     6  	"strings"
     7  	"time"
     8  
     9  	docker "github.com/fsouza/go-dockerclient"
    10  	hclog "github.com/hashicorp/go-hclog"
    11  	"github.com/hashicorp/nomad/helper/pluginutils/hclutils"
    12  	"github.com/hashicorp/nomad/helper/pluginutils/loader"
    13  	"github.com/hashicorp/nomad/plugins/base"
    14  	"github.com/hashicorp/nomad/plugins/drivers"
    15  	"github.com/hashicorp/nomad/plugins/shared/hclspec"
    16  )
    17  
    18  const (
    19  	// NoSuchContainerError is returned by the docker daemon if the container
    20  	// does not exist.
    21  	NoSuchContainerError = "No such container"
    22  
    23  	// ContainerNotRunningError is returned by the docker daemon if the container
    24  	// is not running, yet we requested it to stop
    25  	ContainerNotRunningError = "Container not running"
    26  
    27  	// pluginName is the name of the plugin
    28  	pluginName = "docker"
    29  
    30  	// fingerprintPeriod is the interval at which the driver will send fingerprint responses
    31  	fingerprintPeriod = 30 * time.Second
    32  
    33  	// dockerTimeout is the length of time a request can be outstanding before
    34  	// it is timed out.
    35  	dockerTimeout = 5 * time.Minute
    36  
    37  	// dockerBasicCaps is comma-separated list of Linux capabilities that are
    38  	// allowed by docker by default, as documented in
    39  	// https://docs.docker.com/engine/reference/run/#block-io-bandwidth-blkio-constraint
    40  	dockerBasicCaps = "CHOWN,DAC_OVERRIDE,FSETID,FOWNER,MKNOD,NET_RAW,SETGID," +
    41  		"SETUID,SETFCAP,SETPCAP,NET_BIND_SERVICE,SYS_CHROOT,KILL,AUDIT_WRITE"
    42  
    43  	// dockerAuthHelperPrefix is the prefix to attach to the credential helper
    44  	// and should be found in the $PATH. Example: ${prefix-}${helper-name}
    45  	dockerAuthHelperPrefix = "docker-credential-"
    46  )
    47  
    48  func PluginLoader(opts map[string]string) (map[string]interface{}, error) {
    49  	conf := map[string]interface{}{}
    50  	if v, ok := opts["docker.endpoint"]; ok {
    51  		conf["endpoint"] = v
    52  	}
    53  
    54  	// dockerd auth
    55  	authConf := map[string]interface{}{}
    56  	if v, ok := opts["docker.auth.config"]; ok {
    57  		authConf["config"] = v
    58  	}
    59  	if v, ok := opts["docker.auth.helper"]; ok {
    60  		authConf["helper"] = v
    61  	}
    62  	conf["auth"] = authConf
    63  
    64  	// dockerd tls
    65  	if _, ok := opts["docker.tls.cert"]; ok {
    66  		conf["tls"] = map[string]interface{}{
    67  			"cert": opts["docker.tls.cert"],
    68  			"key":  opts["docker.tls.key"],
    69  			"ca":   opts["docker.tls.ca"],
    70  		}
    71  	}
    72  
    73  	// garbage collection
    74  	gcConf := map[string]interface{}{}
    75  	if v, err := strconv.ParseBool(opts["docker.cleanup.image"]); err == nil {
    76  		gcConf["image"] = v
    77  	}
    78  	if v, ok := opts["docker.cleanup.image.delay"]; ok {
    79  		gcConf["image_delay"] = v
    80  	}
    81  	if v, err := strconv.ParseBool(opts["docker.cleanup.container"]); err == nil {
    82  		gcConf["container"] = v
    83  	}
    84  	conf["gc"] = gcConf
    85  
    86  	// volume options
    87  	volConf := map[string]interface{}{}
    88  	if v, err := strconv.ParseBool(opts["docker.volumes.enabled"]); err == nil {
    89  		volConf["enabled"] = v
    90  	}
    91  	if v, ok := opts["docker.volumes.selinuxlabel"]; ok {
    92  		volConf["selinuxlabel"] = v
    93  	}
    94  	conf["volumes"] = volConf
    95  
    96  	// capabilities
    97  	if v, ok := opts["docker.caps.whitelist"]; ok {
    98  		conf["allow_caps"] = strings.Split(v, ",")
    99  	}
   100  
   101  	// privileged containers
   102  	if v, err := strconv.ParseBool(opts["docker.privileged.enabled"]); err == nil {
   103  		conf["allow_privileged"] = v
   104  	}
   105  
   106  	// nvidia_runtime
   107  	if v, ok := opts["docker.nvidia_runtime"]; ok {
   108  		conf["nvidia_runtime"] = v
   109  	}
   110  
   111  	return conf, nil
   112  }
   113  
   114  var (
   115  	// PluginID is the rawexec plugin metadata registered in the plugin
   116  	// catalog.
   117  	PluginID = loader.PluginID{
   118  		Name:       pluginName,
   119  		PluginType: base.PluginTypeDriver,
   120  	}
   121  
   122  	// PluginConfig is the rawexec factory function registered in the
   123  	// plugin catalog.
   124  	PluginConfig = &loader.InternalPluginConfig{
   125  		Config:  map[string]interface{}{},
   126  		Factory: func(l hclog.Logger) interface{} { return NewDockerDriver(l) },
   127  	}
   128  
   129  	// pluginInfo is the response returned for the PluginInfo RPC
   130  	pluginInfo = &base.PluginInfoResponse{
   131  		Type:              base.PluginTypeDriver,
   132  		PluginApiVersions: []string{drivers.ApiVersion010},
   133  		PluginVersion:     "0.1.0",
   134  		Name:              pluginName,
   135  	}
   136  
   137  	// configSpec is the hcl specification returned by the ConfigSchema RPC
   138  	// and is used to parse the contents of the 'plugin "docker" {...}' block.
   139  	// Example:
   140  	//	plugin "docker" {
   141  	//		config {
   142  	//		endpoint = "unix:///var/run/docker.sock"
   143  	//		auth {
   144  	//			config = "/etc/docker-auth.json"
   145  	//			helper = "docker-credential-aws"
   146  	//		}
   147  	//		tls {
   148  	//			cert = "/etc/nomad/nomad.pub"
   149  	//			key = "/etc/nomad/nomad.pem"
   150  	//			ca = "/etc/nomad/nomad.cert"
   151  	//		}
   152  	//		gc {
   153  	//			image = true
   154  	//			image_delay = "5m"
   155  	//			container = false
   156  	//		}
   157  	//		volumes {
   158  	//			enabled = true
   159  	//			selinuxlabel = "z"
   160  	//		}
   161  	//		allow_privileged = false
   162  	//		allow_caps = ["CHOWN", "NET_RAW" ... ]
   163  	//		nvidia_runtime = "nvidia"
   164  	//		}
   165  	//	}
   166  	configSpec = hclspec.NewObject(map[string]*hclspec.Spec{
   167  		"endpoint": hclspec.NewAttr("endpoint", "string", false),
   168  
   169  		// docker daemon auth option for image registry
   170  		"auth": hclspec.NewBlock("auth", false, hclspec.NewObject(map[string]*hclspec.Spec{
   171  			"config": hclspec.NewAttr("config", "string", false),
   172  			"helper": hclspec.NewAttr("helper", "string", false),
   173  		})),
   174  
   175  		// client tls options
   176  		"tls": hclspec.NewBlock("tls", false, hclspec.NewObject(map[string]*hclspec.Spec{
   177  			"cert": hclspec.NewAttr("cert", "string", false),
   178  			"key":  hclspec.NewAttr("key", "string", false),
   179  			"ca":   hclspec.NewAttr("ca", "string", false),
   180  		})),
   181  
   182  		// garbage collection options
   183  		// default needed for both if the gc {...} block is not set and
   184  		// if the default fields are missing
   185  		"gc": hclspec.NewDefault(hclspec.NewBlock("gc", false, hclspec.NewObject(map[string]*hclspec.Spec{
   186  			"image": hclspec.NewDefault(
   187  				hclspec.NewAttr("image", "bool", false),
   188  				hclspec.NewLiteral("true"),
   189  			),
   190  			"image_delay": hclspec.NewAttr("image_delay", "string", false),
   191  			"container": hclspec.NewDefault(
   192  				hclspec.NewAttr("container", "bool", false),
   193  				hclspec.NewLiteral("true"),
   194  			),
   195  		})), hclspec.NewLiteral(`{
   196  			image = true
   197  			container = true
   198  		}`)),
   199  
   200  		// docker volume options
   201  		// defaulted needed for both if the volumes {...} block is not set and
   202  		// if the default fields are missing
   203  		"volumes": hclspec.NewDefault(hclspec.NewBlock("volumes", false, hclspec.NewObject(map[string]*hclspec.Spec{
   204  			"enabled": hclspec.NewDefault(
   205  				hclspec.NewAttr("enabled", "bool", false),
   206  				hclspec.NewLiteral("true"),
   207  			),
   208  			"selinuxlabel": hclspec.NewAttr("selinuxlabel", "string", false),
   209  		})), hclspec.NewLiteral("{ enabled = true }")),
   210  		"allow_privileged": hclspec.NewAttr("allow_privileged", "bool", false),
   211  		"allow_caps": hclspec.NewDefault(
   212  			hclspec.NewAttr("allow_caps", "list(string)", false),
   213  			hclspec.NewLiteral(`["CHOWN","DAC_OVERRIDE","FSETID","FOWNER","MKNOD","NET_RAW","SETGID","SETUID","SETFCAP","SETPCAP","NET_BIND_SERVICE","SYS_CHROOT","KILL","AUDIT_WRITE"]`),
   214  		),
   215  		"nvidia_runtime": hclspec.NewDefault(
   216  			hclspec.NewAttr("nvidia_runtime", "string", false),
   217  			hclspec.NewLiteral(`"nvidia"`),
   218  		),
   219  	})
   220  
   221  	// taskConfigSpec is the hcl specification for the driver config section of
   222  	// a task within a job. It is returned in the TaskConfigSchema RPC
   223  	taskConfigSpec = hclspec.NewObject(map[string]*hclspec.Spec{
   224  		"image":                  hclspec.NewAttr("image", "string", true),
   225  		"advertise_ipv6_address": hclspec.NewAttr("advertise_ipv6_address", "bool", false),
   226  		"args":                   hclspec.NewAttr("args", "list(string)", false),
   227  		"auth": hclspec.NewBlock("auth", false, hclspec.NewObject(map[string]*hclspec.Spec{
   228  			"username":       hclspec.NewAttr("username", "string", false),
   229  			"password":       hclspec.NewAttr("password", "string", false),
   230  			"email":          hclspec.NewAttr("email", "string", false),
   231  			"server_address": hclspec.NewAttr("server_address", "string", false),
   232  		})),
   233  		"auth_soft_fail": hclspec.NewAttr("auth_soft_fail", "bool", false),
   234  		"cap_add":        hclspec.NewAttr("cap_add", "list(string)", false),
   235  		"cap_drop":       hclspec.NewAttr("cap_drop", "list(string)", false),
   236  		"command":        hclspec.NewAttr("command", "string", false),
   237  		"cpu_hard_limit": hclspec.NewAttr("cpu_hard_limit", "bool", false),
   238  		"cpu_cfs_period": hclspec.NewAttr("cpu_cfs_period", "number", false),
   239  		"devices": hclspec.NewBlockList("devices", hclspec.NewObject(map[string]*hclspec.Spec{
   240  			"host_path":          hclspec.NewAttr("host_path", "string", false),
   241  			"container_path":     hclspec.NewAttr("container_path", "string", false),
   242  			"cgroup_permissions": hclspec.NewAttr("cgroup_permissions", "string", false),
   243  		})),
   244  		"dns_search_domains": hclspec.NewAttr("dns_search_domains", "list(string)", false),
   245  		"dns_options":        hclspec.NewAttr("dns_options", "list(string)", false),
   246  		"dns_servers":        hclspec.NewAttr("dns_servers", "list(string)", false),
   247  		"entrypoint":         hclspec.NewAttr("entrypoint", "list(string)", false),
   248  		"extra_hosts":        hclspec.NewAttr("extra_hosts", "list(string)", false),
   249  		"force_pull":         hclspec.NewAttr("force_pull", "bool", false),
   250  		"hostname":           hclspec.NewAttr("hostname", "string", false),
   251  		"interactive":        hclspec.NewAttr("interactive", "bool", false),
   252  		"ipc_mode":           hclspec.NewAttr("ipc_mode", "string", false),
   253  		"ipv4_address":       hclspec.NewAttr("ipv4_address", "string", false),
   254  		"ipv6_address":       hclspec.NewAttr("ipv6_address", "string", false),
   255  		"labels":             hclspec.NewAttr("labels", "list(map(string))", false),
   256  		"load":               hclspec.NewAttr("load", "string", false),
   257  		"logging": hclspec.NewBlock("logging", false, hclspec.NewObject(map[string]*hclspec.Spec{
   258  			"type":   hclspec.NewAttr("type", "string", false),
   259  			"driver": hclspec.NewAttr("driver", "string", false),
   260  			"config": hclspec.NewAttr("config", "list(map(string))", false),
   261  		})),
   262  		"mac_address": hclspec.NewAttr("mac_address", "string", false),
   263  		"mounts": hclspec.NewBlockList("mounts", hclspec.NewObject(map[string]*hclspec.Spec{
   264  			"type": hclspec.NewDefault(
   265  				hclspec.NewAttr("type", "string", false),
   266  				hclspec.NewLiteral("\"volume\""),
   267  			),
   268  			"target":   hclspec.NewAttr("target", "string", false),
   269  			"source":   hclspec.NewAttr("source", "string", false),
   270  			"readonly": hclspec.NewAttr("readonly", "bool", false),
   271  			"bind_options": hclspec.NewBlock("bind_options", false, hclspec.NewObject(map[string]*hclspec.Spec{
   272  				"propagation": hclspec.NewAttr("propagation", "string", false),
   273  			})),
   274  			"tmpfs_options": hclspec.NewBlock("tmpfs_options", false, hclspec.NewObject(map[string]*hclspec.Spec{
   275  				"size": hclspec.NewAttr("size", "number", false),
   276  				"mode": hclspec.NewAttr("mode", "number", false),
   277  			})),
   278  			"volume_options": hclspec.NewBlock("volume_options", false, hclspec.NewObject(map[string]*hclspec.Spec{
   279  				"no_copy": hclspec.NewAttr("no_copy", "bool", false),
   280  				"labels":  hclspec.NewAttr("labels", "list(map(string))", false),
   281  				"driver_config": hclspec.NewBlock("driver_config", false, hclspec.NewObject(map[string]*hclspec.Spec{
   282  					"name":    hclspec.NewAttr("name", "string", false),
   283  					"options": hclspec.NewAttr("options", "list(map(string))", false),
   284  				})),
   285  			})),
   286  		})),
   287  		"network_aliases": hclspec.NewAttr("network_aliases", "list(string)", false),
   288  		"network_mode":    hclspec.NewAttr("network_mode", "string", false),
   289  		"pids_limit":      hclspec.NewAttr("pids_limit", "number", false),
   290  		"pid_mode":        hclspec.NewAttr("pid_mode", "string", false),
   291  		"port_map":        hclspec.NewAttr("port_map", "list(map(number))", false),
   292  		"privileged":      hclspec.NewAttr("privileged", "bool", false),
   293  		"readonly_rootfs": hclspec.NewAttr("readonly_rootfs", "bool", false),
   294  		"security_opt":    hclspec.NewAttr("security_opt", "list(string)", false),
   295  		"shm_size":        hclspec.NewAttr("shm_size", "number", false),
   296  		"storage_opt":     hclspec.NewBlockAttrs("storage_opt", "string", false),
   297  		"sysctl":          hclspec.NewAttr("sysctl", "list(map(string))", false),
   298  		"tty":             hclspec.NewAttr("tty", "bool", false),
   299  		"ulimit":          hclspec.NewAttr("ulimit", "list(map(string))", false),
   300  		"uts_mode":        hclspec.NewAttr("uts_mode", "string", false),
   301  		"userns_mode":     hclspec.NewAttr("userns_mode", "string", false),
   302  		"volumes":         hclspec.NewAttr("volumes", "list(string)", false),
   303  		"volume_driver":   hclspec.NewAttr("volume_driver", "string", false),
   304  		"work_dir":        hclspec.NewAttr("work_dir", "string", false),
   305  	})
   306  
   307  	// capabilities is returned by the Capabilities RPC and indicates what
   308  	// optional features this driver supports
   309  	capabilities = &drivers.Capabilities{
   310  		SendSignals: true,
   311  		Exec:        true,
   312  		FSIsolation: drivers.FSIsolationImage,
   313  	}
   314  )
   315  
   316  type TaskConfig struct {
   317  	Image             string             `codec:"image"`
   318  	AdvertiseIPv6Addr bool               `codec:"advertise_ipv6_address"`
   319  	Args              []string           `codec:"args"`
   320  	Auth              DockerAuth         `codec:"auth"`
   321  	AuthSoftFail      bool               `codec:"auth_soft_fail"`
   322  	CapAdd            []string           `codec:"cap_add"`
   323  	CapDrop           []string           `codec:"cap_drop"`
   324  	Command           string             `codec:"command"`
   325  	CPUCFSPeriod      int64              `codec:"cpu_cfs_period"`
   326  	CPUHardLimit      bool               `codec:"cpu_hard_limit"`
   327  	Devices           []DockerDevice     `codec:"devices"`
   328  	DNSSearchDomains  []string           `codec:"dns_search_domains"`
   329  	DNSOptions        []string           `codec:"dns_options"`
   330  	DNSServers        []string           `codec:"dns_servers"`
   331  	Entrypoint        []string           `codec:"entrypoint"`
   332  	ExtraHosts        []string           `codec:"extra_hosts"`
   333  	ForcePull         bool               `codec:"force_pull"`
   334  	Hostname          string             `codec:"hostname"`
   335  	Interactive       bool               `codec:"interactive"`
   336  	IPCMode           string             `codec:"ipc_mode"`
   337  	IPv4Address       string             `codec:"ipv4_address"`
   338  	IPv6Address       string             `codec:"ipv6_address"`
   339  	Labels            hclutils.MapStrStr `codec:"labels"`
   340  	LoadImage         string             `codec:"load"`
   341  	Logging           DockerLogging      `codec:"logging"`
   342  	MacAddress        string             `codec:"mac_address"`
   343  	Mounts            []DockerMount      `codec:"mounts"`
   344  	NetworkAliases    []string           `codec:"network_aliases"`
   345  	NetworkMode       string             `codec:"network_mode"`
   346  	PidsLimit         int64              `codec:"pids_limit"`
   347  	PidMode           string             `codec:"pid_mode"`
   348  	PortMap           hclutils.MapStrInt `codec:"port_map"`
   349  	Privileged        bool               `codec:"privileged"`
   350  	ReadonlyRootfs    bool               `codec:"readonly_rootfs"`
   351  	SecurityOpt       []string           `codec:"security_opt"`
   352  	ShmSize           int64              `codec:"shm_size"`
   353  	StorageOpt        map[string]string  `codec:"storage_opt"`
   354  	Sysctl            hclutils.MapStrStr `codec:"sysctl"`
   355  	TTY               bool               `codec:"tty"`
   356  	Ulimit            hclutils.MapStrStr `codec:"ulimit"`
   357  	UTSMode           string             `codec:"uts_mode"`
   358  	UsernsMode        string             `codec:"userns_mode"`
   359  	Volumes           []string           `codec:"volumes"`
   360  	VolumeDriver      string             `codec:"volume_driver"`
   361  	WorkDir           string             `codec:"work_dir"`
   362  }
   363  
   364  type DockerAuth struct {
   365  	Username   string `codec:"username"`
   366  	Password   string `codec:"password"`
   367  	Email      string `codec:"email"`
   368  	ServerAddr string `codec:"server_address"`
   369  }
   370  
   371  type DockerDevice struct {
   372  	HostPath          string `codec:"host_path"`
   373  	ContainerPath     string `codec:"container_path"`
   374  	CgroupPermissions string `codec:"cgroup_permissions"`
   375  }
   376  
   377  func (d DockerDevice) toDockerDevice() (docker.Device, error) {
   378  	dd := docker.Device{
   379  		PathOnHost:        d.HostPath,
   380  		PathInContainer:   d.ContainerPath,
   381  		CgroupPermissions: d.CgroupPermissions,
   382  	}
   383  
   384  	if d.HostPath == "" {
   385  		return dd, fmt.Errorf("host path must be set in configuration for devices")
   386  	}
   387  
   388  	if dd.CgroupPermissions == "" {
   389  		dd.CgroupPermissions = "rwm"
   390  	}
   391  
   392  	if !validateCgroupPermission(dd.CgroupPermissions) {
   393  		return dd, fmt.Errorf("invalid cgroup permission string: %q", dd.CgroupPermissions)
   394  	}
   395  
   396  	return dd, nil
   397  }
   398  
   399  type DockerLogging struct {
   400  	Type   string             `codec:"type"`
   401  	Driver string             `codec:"driver"`
   402  	Config hclutils.MapStrStr `codec:"config"`
   403  }
   404  
   405  type DockerMount struct {
   406  	Type          string              `codec:"type"`
   407  	Target        string              `codec:"target"`
   408  	Source        string              `codec:"source"`
   409  	ReadOnly      bool                `codec:"readonly"`
   410  	BindOptions   DockerBindOptions   `codec:"bind_options"`
   411  	VolumeOptions DockerVolumeOptions `codec:"volume_options"`
   412  	TmpfsOptions  DockerTmpfsOptions  `codec:"tmpfs_options"`
   413  }
   414  
   415  func (m DockerMount) toDockerHostMount() (docker.HostMount, error) {
   416  	if m.Type == "" {
   417  		// for backward compatbility, as type is optional
   418  		m.Type = "volume"
   419  	}
   420  
   421  	hm := docker.HostMount{
   422  		Target:   m.Target,
   423  		Source:   m.Source,
   424  		Type:     m.Type,
   425  		ReadOnly: m.ReadOnly,
   426  	}
   427  
   428  	switch m.Type {
   429  	case "volume":
   430  		vo := m.VolumeOptions
   431  		hm.VolumeOptions = &docker.VolumeOptions{
   432  			NoCopy: vo.NoCopy,
   433  			Labels: vo.Labels,
   434  			DriverConfig: docker.VolumeDriverConfig{
   435  				Name:    vo.DriverConfig.Name,
   436  				Options: vo.DriverConfig.Options,
   437  			},
   438  		}
   439  	case "bind":
   440  		hm.BindOptions = &docker.BindOptions{
   441  			Propagation: m.BindOptions.Propagation,
   442  		}
   443  	case "tmpfs":
   444  		if m.Source != "" {
   445  			return hm, fmt.Errorf(`invalid source, must be "" for tmpfs`)
   446  		}
   447  		hm.TempfsOptions = &docker.TempfsOptions{
   448  			SizeBytes: m.TmpfsOptions.SizeBytes,
   449  			Mode:      m.TmpfsOptions.Mode,
   450  		}
   451  	default:
   452  		return hm, fmt.Errorf(`invalid mount type, must be "bind", "volume", "tmpfs": %q`, m.Type)
   453  	}
   454  
   455  	return hm, nil
   456  }
   457  
   458  type DockerVolumeOptions struct {
   459  	NoCopy       bool                     `codec:"no_copy"`
   460  	Labels       hclutils.MapStrStr       `codec:"labels"`
   461  	DriverConfig DockerVolumeDriverConfig `codec:"driver_config"`
   462  }
   463  
   464  type DockerBindOptions struct {
   465  	Propagation string `codec:"propagation"`
   466  }
   467  
   468  type DockerTmpfsOptions struct {
   469  	SizeBytes int64 `codec:"size"`
   470  	Mode      int   `codec:"mode"`
   471  }
   472  
   473  // DockerVolumeDriverConfig holds a map of volume driver specific options
   474  type DockerVolumeDriverConfig struct {
   475  	Name    string             `codec:"name"`
   476  	Options hclutils.MapStrStr `codec:"options"`
   477  }
   478  
   479  type DriverConfig struct {
   480  	Endpoint        string       `codec:"endpoint"`
   481  	Auth            AuthConfig   `codec:"auth"`
   482  	TLS             TLSConfig    `codec:"tls"`
   483  	GC              GCConfig     `codec:"gc"`
   484  	Volumes         VolumeConfig `codec:"volumes"`
   485  	AllowPrivileged bool         `codec:"allow_privileged"`
   486  	AllowCaps       []string     `codec:"allow_caps"`
   487  	GPURuntimeName  string       `codec:"nvidia_runtime"`
   488  }
   489  
   490  type AuthConfig struct {
   491  	Config string `codec:"config"`
   492  	Helper string `codec:"helper"`
   493  }
   494  
   495  type TLSConfig struct {
   496  	Cert string `codec:"cert"`
   497  	Key  string `codec:"key"`
   498  	CA   string `codec:"ca"`
   499  }
   500  
   501  type GCConfig struct {
   502  	Image              bool          `codec:"image"`
   503  	ImageDelay         string        `codec:"image_delay"`
   504  	imageDelayDuration time.Duration `codec:"-"`
   505  	Container          bool          `codec:"container"`
   506  }
   507  
   508  type VolumeConfig struct {
   509  	Enabled      bool   `codec:"enabled"`
   510  	SelinuxLabel string `codec:"selinuxlabel"`
   511  }
   512  
   513  func (d *Driver) PluginInfo() (*base.PluginInfoResponse, error) {
   514  	return pluginInfo, nil
   515  }
   516  
   517  func (d *Driver) ConfigSchema() (*hclspec.Spec, error) {
   518  	return configSpec, nil
   519  }
   520  
   521  func (d *Driver) SetConfig(c *base.Config) error {
   522  	var config DriverConfig
   523  	if len(c.PluginConfig) != 0 {
   524  		if err := base.MsgPackDecode(c.PluginConfig, &config); err != nil {
   525  			return err
   526  		}
   527  	}
   528  
   529  	d.config = &config
   530  	if len(d.config.GC.ImageDelay) > 0 {
   531  		dur, err := time.ParseDuration(d.config.GC.ImageDelay)
   532  		if err != nil {
   533  			return fmt.Errorf("failed to parse 'image_delay' duration: %v", err)
   534  		}
   535  		d.config.GC.imageDelayDuration = dur
   536  	}
   537  
   538  	if c.AgentConfig != nil {
   539  		d.clientConfig = c.AgentConfig.Driver
   540  	}
   541  
   542  	dockerClient, _, err := d.dockerClients()
   543  	if err != nil {
   544  		return fmt.Errorf("failed to get docker client: %v", err)
   545  	}
   546  	coordinatorConfig := &dockerCoordinatorConfig{
   547  		client:      dockerClient,
   548  		cleanup:     d.config.GC.Image,
   549  		logger:      d.logger,
   550  		removeDelay: d.config.GC.imageDelayDuration,
   551  	}
   552  
   553  	d.coordinator = newDockerCoordinator(coordinatorConfig)
   554  
   555  	return nil
   556  }
   557  
   558  func (d *Driver) TaskConfigSchema() (*hclspec.Spec, error) {
   559  	return taskConfigSpec, nil
   560  }
   561  
   562  func (d *Driver) Capabilities() (*drivers.Capabilities, error) {
   563  	return capabilities, nil
   564  }