github.com/Ilhicas/nomad@v1.0.4-0.20210304152020-e86851182bc3/drivers/docker/config.go (about)

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