1package types
2
3import (
4	"encoding/json"
5	"fmt"
6	"time"
7)
8
9// UnsupportedProperties not yet supported by this implementation of the compose file
10var UnsupportedProperties = []string{
11	"build",
12	"cgroupns_mode",
13	"cgroup_parent",
14	"devices",
15	"domainname",
16	"external_links",
17	"ipc",
18	"links",
19	"mac_address",
20	"network_mode",
21	"pid",
22	"privileged",
23	"restart",
24	"security_opt",
25	"shm_size",
26	"userns_mode",
27}
28
29// DeprecatedProperties that were removed from the v3 format, but their
30// use should not impact the behaviour of the application.
31var DeprecatedProperties = map[string]string{
32	"container_name": "Setting the container name is not supported.",
33	"expose":         "Exposing ports is unnecessary - services on the same network can access each other's containers on any port.",
34}
35
36// ForbiddenProperties that are not supported in this implementation of the
37// compose file.
38var ForbiddenProperties = map[string]string{
39	"extends":       "Support for `extends` is not implemented yet.",
40	"volume_driver": "Instead of setting the volume driver on the service, define a volume using the top-level `volumes` option and specify the driver there.",
41	"volumes_from":  "To share a volume between services, define it using the top-level `volumes` option and reference it from each service that shares it using the service-level `volumes` option.",
42	"cpu_quota":     "Set resource limits using deploy.resources",
43	"cpu_shares":    "Set resource limits using deploy.resources",
44	"cpuset":        "Set resource limits using deploy.resources",
45	"mem_limit":     "Set resource limits using deploy.resources",
46	"memswap_limit": "Set resource limits using deploy.resources",
47}
48
49// ConfigFile is a filename and the contents of the file as a Dict
50type ConfigFile struct {
51	Filename string
52	Config   map[string]interface{}
53}
54
55// ConfigDetails are the details about a group of ConfigFiles
56type ConfigDetails struct {
57	Version     string
58	WorkingDir  string
59	ConfigFiles []ConfigFile
60	Environment map[string]string
61}
62
63// Duration is a thin wrapper around time.Duration with improved JSON marshalling
64type Duration time.Duration
65
66func (d Duration) String() string {
67	return time.Duration(d).String()
68}
69
70// ConvertDurationPtr converts a typedefined Duration pointer to a time.Duration pointer with the same value.
71func ConvertDurationPtr(d *Duration) *time.Duration {
72	if d == nil {
73		return nil
74	}
75	res := time.Duration(*d)
76	return &res
77}
78
79// MarshalJSON makes Duration implement json.Marshaler
80func (d Duration) MarshalJSON() ([]byte, error) {
81	return json.Marshal(d.String())
82}
83
84// MarshalYAML makes Duration implement yaml.Marshaler
85func (d Duration) MarshalYAML() (interface{}, error) {
86	return d.String(), nil
87}
88
89// LookupEnv provides a lookup function for environment variables
90func (cd ConfigDetails) LookupEnv(key string) (string, bool) {
91	v, ok := cd.Environment[key]
92	return v, ok
93}
94
95// Config is a full compose file configuration
96type Config struct {
97	Filename string                     `yaml:"-" json:"-"`
98	Version  string                     `json:"version"`
99	Services Services                   `json:"services"`
100	Networks map[string]NetworkConfig   `yaml:",omitempty" json:"networks,omitempty"`
101	Volumes  map[string]VolumeConfig    `yaml:",omitempty" json:"volumes,omitempty"`
102	Secrets  map[string]SecretConfig    `yaml:",omitempty" json:"secrets,omitempty"`
103	Configs  map[string]ConfigObjConfig `yaml:",omitempty" json:"configs,omitempty"`
104	Extras   map[string]interface{}     `yaml:",inline" json:"-"`
105}
106
107// MarshalJSON makes Config implement json.Marshaler
108func (c Config) MarshalJSON() ([]byte, error) {
109	m := map[string]interface{}{
110		"version":  c.Version,
111		"services": c.Services,
112	}
113
114	if len(c.Networks) > 0 {
115		m["networks"] = c.Networks
116	}
117	if len(c.Volumes) > 0 {
118		m["volumes"] = c.Volumes
119	}
120	if len(c.Secrets) > 0 {
121		m["secrets"] = c.Secrets
122	}
123	if len(c.Configs) > 0 {
124		m["configs"] = c.Configs
125	}
126	for k, v := range c.Extras {
127		m[k] = v
128	}
129	return json.Marshal(m)
130}
131
132// Services is a list of ServiceConfig
133type Services []ServiceConfig
134
135// MarshalYAML makes Services implement yaml.Marshaller
136func (s Services) MarshalYAML() (interface{}, error) {
137	services := map[string]ServiceConfig{}
138	for _, service := range s {
139		services[service.Name] = service
140	}
141	return services, nil
142}
143
144// MarshalJSON makes Services implement json.Marshaler
145func (s Services) MarshalJSON() ([]byte, error) {
146	data, err := s.MarshalYAML()
147	if err != nil {
148		return nil, err
149	}
150	return json.MarshalIndent(data, "", "  ")
151}
152
153// ServiceConfig is the configuration of one service
154type ServiceConfig struct {
155	Name string `yaml:"-" json:"-"`
156
157	Build           BuildConfig                      `yaml:",omitempty" json:"build,omitempty"`
158	CapAdd          []string                         `mapstructure:"cap_add" yaml:"cap_add,omitempty" json:"cap_add,omitempty"`
159	CapDrop         []string                         `mapstructure:"cap_drop" yaml:"cap_drop,omitempty" json:"cap_drop,omitempty"`
160	CgroupNSMode    string                           `mapstructure:"cgroupns_mode" yaml:"cgroupns_mode,omitempty" json:"cgroupns_mode,omitempty"`
161	CgroupParent    string                           `mapstructure:"cgroup_parent" yaml:"cgroup_parent,omitempty" json:"cgroup_parent,omitempty"`
162	Command         ShellCommand                     `yaml:",omitempty" json:"command,omitempty"`
163	Configs         []ServiceConfigObjConfig         `yaml:",omitempty" json:"configs,omitempty"`
164	ContainerName   string                           `mapstructure:"container_name" yaml:"container_name,omitempty" json:"container_name,omitempty"`
165	CredentialSpec  CredentialSpecConfig             `mapstructure:"credential_spec" yaml:"credential_spec,omitempty" json:"credential_spec,omitempty"`
166	DependsOn       []string                         `mapstructure:"depends_on" yaml:"depends_on,omitempty" json:"depends_on,omitempty"`
167	Deploy          DeployConfig                     `yaml:",omitempty" json:"deploy,omitempty"`
168	Devices         []string                         `yaml:",omitempty" json:"devices,omitempty"`
169	DNS             StringList                       `yaml:",omitempty" json:"dns,omitempty"`
170	DNSSearch       StringList                       `mapstructure:"dns_search" yaml:"dns_search,omitempty" json:"dns_search,omitempty"`
171	DomainName      string                           `mapstructure:"domainname" yaml:"domainname,omitempty" json:"domainname,omitempty"`
172	Entrypoint      ShellCommand                     `yaml:",omitempty" json:"entrypoint,omitempty"`
173	Environment     MappingWithEquals                `yaml:",omitempty" json:"environment,omitempty"`
174	EnvFile         StringList                       `mapstructure:"env_file" yaml:"env_file,omitempty" json:"env_file,omitempty"`
175	Expose          StringOrNumberList               `yaml:",omitempty" json:"expose,omitempty"`
176	ExternalLinks   []string                         `mapstructure:"external_links" yaml:"external_links,omitempty" json:"external_links,omitempty"`
177	ExtraHosts      HostsList                        `mapstructure:"extra_hosts" yaml:"extra_hosts,omitempty" json:"extra_hosts,omitempty"`
178	Hostname        string                           `yaml:",omitempty" json:"hostname,omitempty"`
179	HealthCheck     *HealthCheckConfig               `yaml:",omitempty" json:"healthcheck,omitempty"`
180	Image           string                           `yaml:",omitempty" json:"image,omitempty"`
181	Init            *bool                            `yaml:",omitempty" json:"init,omitempty"`
182	Ipc             string                           `yaml:",omitempty" json:"ipc,omitempty"`
183	Isolation       string                           `mapstructure:"isolation" yaml:"isolation,omitempty" json:"isolation,omitempty"`
184	Labels          Labels                           `yaml:",omitempty" json:"labels,omitempty"`
185	Links           []string                         `yaml:",omitempty" json:"links,omitempty"`
186	Logging         *LoggingConfig                   `yaml:",omitempty" json:"logging,omitempty"`
187	MacAddress      string                           `mapstructure:"mac_address" yaml:"mac_address,omitempty" json:"mac_address,omitempty"`
188	NetworkMode     string                           `mapstructure:"network_mode" yaml:"network_mode,omitempty" json:"network_mode,omitempty"`
189	Networks        map[string]*ServiceNetworkConfig `yaml:",omitempty" json:"networks,omitempty"`
190	Pid             string                           `yaml:",omitempty" json:"pid,omitempty"`
191	Ports           []ServicePortConfig              `yaml:",omitempty" json:"ports,omitempty"`
192	Privileged      bool                             `yaml:",omitempty" json:"privileged,omitempty"`
193	ReadOnly        bool                             `mapstructure:"read_only" yaml:"read_only,omitempty" json:"read_only,omitempty"`
194	Restart         string                           `yaml:",omitempty" json:"restart,omitempty"`
195	Secrets         []ServiceSecretConfig            `yaml:",omitempty" json:"secrets,omitempty"`
196	SecurityOpt     []string                         `mapstructure:"security_opt" yaml:"security_opt,omitempty" json:"security_opt,omitempty"`
197	ShmSize         string                           `mapstructure:"shm_size" yaml:"shm_size,omitempty" json:"shm_size,omitempty"`
198	StdinOpen       bool                             `mapstructure:"stdin_open" yaml:"stdin_open,omitempty" json:"stdin_open,omitempty"`
199	StopGracePeriod *Duration                        `mapstructure:"stop_grace_period" yaml:"stop_grace_period,omitempty" json:"stop_grace_period,omitempty"`
200	StopSignal      string                           `mapstructure:"stop_signal" yaml:"stop_signal,omitempty" json:"stop_signal,omitempty"`
201	Sysctls         Mapping                          `yaml:",omitempty" json:"sysctls,omitempty"`
202	Tmpfs           StringList                       `yaml:",omitempty" json:"tmpfs,omitempty"`
203	Tty             bool                             `mapstructure:"tty" yaml:"tty,omitempty" json:"tty,omitempty"`
204	Ulimits         map[string]*UlimitsConfig        `yaml:",omitempty" json:"ulimits,omitempty"`
205	User            string                           `yaml:",omitempty" json:"user,omitempty"`
206	UserNSMode      string                           `mapstructure:"userns_mode" yaml:"userns_mode,omitempty" json:"userns_mode,omitempty"`
207	Volumes         []ServiceVolumeConfig            `yaml:",omitempty" json:"volumes,omitempty"`
208	WorkingDir      string                           `mapstructure:"working_dir" yaml:"working_dir,omitempty" json:"working_dir,omitempty"`
209
210	Extras map[string]interface{} `yaml:",inline" json:"-"`
211}
212
213// BuildConfig is a type for build
214// using the same format at libcompose: https://github.com/docker/libcompose/blob/master/yaml/build.go#L12
215type BuildConfig struct {
216	Context    string            `yaml:",omitempty" json:"context,omitempty"`
217	Dockerfile string            `yaml:",omitempty" json:"dockerfile,omitempty"`
218	Args       MappingWithEquals `yaml:",omitempty" json:"args,omitempty"`
219	Labels     Labels            `yaml:",omitempty" json:"labels,omitempty"`
220	CacheFrom  StringList        `mapstructure:"cache_from" yaml:"cache_from,omitempty" json:"cache_from,omitempty"`
221	ExtraHosts HostsList         `mapstructure:"extra_hosts" yaml:"extra_hosts,omitempty" json:"extra_hosts,omitempty"`
222	Network    string            `yaml:",omitempty" json:"network,omitempty"`
223	Target     string            `yaml:",omitempty" json:"target,omitempty"`
224}
225
226// ShellCommand is a string or list of string args
227type ShellCommand []string
228
229// StringList is a type for fields that can be a string or list of strings
230type StringList []string
231
232// StringOrNumberList is a type for fields that can be a list of strings or
233// numbers
234type StringOrNumberList []string
235
236// MappingWithEquals is a mapping type that can be converted from a list of
237// key[=value] strings.
238// For the key with an empty value (`key=`), the mapped value is set to a pointer to `""`.
239// For the key without value (`key`), the mapped value is set to nil.
240type MappingWithEquals map[string]*string
241
242// Mapping is a mapping type that can be converted from a list of
243// key[=value] strings.
244// For the key with an empty value (`key=`), or key without value (`key`), the
245// mapped value is set to an empty string `""`.
246type Mapping map[string]string
247
248// Labels is a mapping type for labels
249type Labels map[string]string
250
251// MappingWithColon is a mapping type that can be converted from a list of
252// 'key: value' strings
253type MappingWithColon map[string]string
254
255// HostsList is a list of colon-separated host-ip mappings
256type HostsList []string
257
258// LoggingConfig the logging configuration for a service
259type LoggingConfig struct {
260	Driver  string            `yaml:",omitempty" json:"driver,omitempty"`
261	Options map[string]string `yaml:",omitempty" json:"options,omitempty"`
262}
263
264// DeployConfig the deployment configuration for a service
265type DeployConfig struct {
266	Mode           string         `yaml:",omitempty" json:"mode,omitempty"`
267	Replicas       *uint64        `yaml:",omitempty" json:"replicas,omitempty"`
268	Labels         Labels         `yaml:",omitempty" json:"labels,omitempty"`
269	UpdateConfig   *UpdateConfig  `mapstructure:"update_config" yaml:"update_config,omitempty" json:"update_config,omitempty"`
270	RollbackConfig *UpdateConfig  `mapstructure:"rollback_config" yaml:"rollback_config,omitempty" json:"rollback_config,omitempty"`
271	Resources      Resources      `yaml:",omitempty" json:"resources,omitempty"`
272	RestartPolicy  *RestartPolicy `mapstructure:"restart_policy" yaml:"restart_policy,omitempty" json:"restart_policy,omitempty"`
273	Placement      Placement      `yaml:",omitempty" json:"placement,omitempty"`
274	EndpointMode   string         `mapstructure:"endpoint_mode" yaml:"endpoint_mode,omitempty" json:"endpoint_mode,omitempty"`
275}
276
277// HealthCheckConfig the healthcheck configuration for a service
278type HealthCheckConfig struct {
279	Test        HealthCheckTest `yaml:",omitempty" json:"test,omitempty"`
280	Timeout     *Duration       `yaml:",omitempty" json:"timeout,omitempty"`
281	Interval    *Duration       `yaml:",omitempty" json:"interval,omitempty"`
282	Retries     *uint64         `yaml:",omitempty" json:"retries,omitempty"`
283	StartPeriod *Duration       `mapstructure:"start_period" yaml:"start_period,omitempty" json:"start_period,omitempty"`
284	Disable     bool            `yaml:",omitempty" json:"disable,omitempty"`
285}
286
287// HealthCheckTest is the command run to test the health of a service
288type HealthCheckTest []string
289
290// UpdateConfig the service update configuration
291type UpdateConfig struct {
292	Parallelism     *uint64  `yaml:",omitempty" json:"parallelism,omitempty"`
293	Delay           Duration `yaml:",omitempty" json:"delay,omitempty"`
294	FailureAction   string   `mapstructure:"failure_action" yaml:"failure_action,omitempty" json:"failure_action,omitempty"`
295	Monitor         Duration `yaml:",omitempty" json:"monitor,omitempty"`
296	MaxFailureRatio float32  `mapstructure:"max_failure_ratio" yaml:"max_failure_ratio,omitempty" json:"max_failure_ratio,omitempty"`
297	Order           string   `yaml:",omitempty" json:"order,omitempty"`
298}
299
300// Resources the resource limits and reservations
301type Resources struct {
302	Limits       *ResourceLimit `yaml:",omitempty" json:"limits,omitempty"`
303	Reservations *Resource      `yaml:",omitempty" json:"reservations,omitempty"`
304}
305
306// ResourceLimit is a resource to be limited
307type ResourceLimit struct {
308	// TODO: types to convert from units and ratios
309	NanoCPUs    string    `mapstructure:"cpus" yaml:"cpus,omitempty" json:"cpus,omitempty"`
310	MemoryBytes UnitBytes `mapstructure:"memory" yaml:"memory,omitempty" json:"memory,omitempty"`
311	Pids        int64     `mapstructure:"pids" yaml:"pids,omitempty" json:"pids,omitempty"`
312}
313
314// Resource is a resource to be reserved
315type Resource struct {
316	// TODO: types to convert from units and ratios
317	NanoCPUs         string            `mapstructure:"cpus" yaml:"cpus,omitempty" json:"cpus,omitempty"`
318	MemoryBytes      UnitBytes         `mapstructure:"memory" yaml:"memory,omitempty" json:"memory,omitempty"`
319	GenericResources []GenericResource `mapstructure:"generic_resources" yaml:"generic_resources,omitempty" json:"generic_resources,omitempty"`
320}
321
322// GenericResource represents a "user defined" resource which can
323// only be an integer (e.g: SSD=3) for a service
324type GenericResource struct {
325	DiscreteResourceSpec *DiscreteGenericResource `mapstructure:"discrete_resource_spec" yaml:"discrete_resource_spec,omitempty" json:"discrete_resource_spec,omitempty"`
326}
327
328// DiscreteGenericResource represents a "user defined" resource which is defined
329// as an integer
330// "Kind" is used to describe the Kind of a resource (e.g: "GPU", "FPGA", "SSD", ...)
331// Value is used to count the resource (SSD=5, HDD=3, ...)
332type DiscreteGenericResource struct {
333	Kind  string `json:"kind"`
334	Value int64  `json:"value"`
335}
336
337// UnitBytes is the bytes type
338type UnitBytes int64
339
340// MarshalYAML makes UnitBytes implement yaml.Marshaller
341func (u UnitBytes) MarshalYAML() (interface{}, error) {
342	return fmt.Sprintf("%d", u), nil
343}
344
345// MarshalJSON makes UnitBytes implement json.Marshaler
346func (u UnitBytes) MarshalJSON() ([]byte, error) {
347	return []byte(fmt.Sprintf(`"%d"`, u)), nil
348}
349
350// RestartPolicy the service restart policy
351type RestartPolicy struct {
352	Condition   string    `yaml:",omitempty" json:"condition,omitempty"`
353	Delay       *Duration `yaml:",omitempty" json:"delay,omitempty"`
354	MaxAttempts *uint64   `mapstructure:"max_attempts" yaml:"max_attempts,omitempty" json:"max_attempts,omitempty"`
355	Window      *Duration `yaml:",omitempty" json:"window,omitempty"`
356}
357
358// Placement constraints for the service
359type Placement struct {
360	Constraints []string               `yaml:",omitempty" json:"constraints,omitempty"`
361	Preferences []PlacementPreferences `yaml:",omitempty" json:"preferences,omitempty"`
362	MaxReplicas uint64                 `mapstructure:"max_replicas_per_node" yaml:"max_replicas_per_node,omitempty" json:"max_replicas_per_node,omitempty"`
363}
364
365// PlacementPreferences is the preferences for a service placement
366type PlacementPreferences struct {
367	Spread string `yaml:",omitempty" json:"spread,omitempty"`
368}
369
370// ServiceNetworkConfig is the network configuration for a service
371type ServiceNetworkConfig struct {
372	Aliases     []string `yaml:",omitempty" json:"aliases,omitempty"`
373	Ipv4Address string   `mapstructure:"ipv4_address" yaml:"ipv4_address,omitempty" json:"ipv4_address,omitempty"`
374	Ipv6Address string   `mapstructure:"ipv6_address" yaml:"ipv6_address,omitempty" json:"ipv6_address,omitempty"`
375}
376
377// ServicePortConfig is the port configuration for a service
378type ServicePortConfig struct {
379	Mode      string `yaml:",omitempty" json:"mode,omitempty"`
380	Target    uint32 `yaml:",omitempty" json:"target,omitempty"`
381	Published uint32 `yaml:",omitempty" json:"published,omitempty"`
382	Protocol  string `yaml:",omitempty" json:"protocol,omitempty"`
383}
384
385// ServiceVolumeConfig are references to a volume used by a service
386type ServiceVolumeConfig struct {
387	Type        string               `yaml:",omitempty" json:"type,omitempty"`
388	Source      string               `yaml:",omitempty" json:"source,omitempty"`
389	Target      string               `yaml:",omitempty" json:"target,omitempty"`
390	ReadOnly    bool                 `mapstructure:"read_only" yaml:"read_only,omitempty" json:"read_only,omitempty"`
391	Consistency string               `yaml:",omitempty" json:"consistency,omitempty"`
392	Bind        *ServiceVolumeBind   `yaml:",omitempty" json:"bind,omitempty"`
393	Volume      *ServiceVolumeVolume `yaml:",omitempty" json:"volume,omitempty"`
394	Tmpfs       *ServiceVolumeTmpfs  `yaml:",omitempty" json:"tmpfs,omitempty"`
395}
396
397// ServiceVolumeBind are options for a service volume of type bind
398type ServiceVolumeBind struct {
399	Propagation string `yaml:",omitempty" json:"propagation,omitempty"`
400}
401
402// ServiceVolumeVolume are options for a service volume of type volume
403type ServiceVolumeVolume struct {
404	NoCopy bool `mapstructure:"nocopy" yaml:"nocopy,omitempty" json:"nocopy,omitempty"`
405}
406
407// ServiceVolumeTmpfs are options for a service volume of type tmpfs
408type ServiceVolumeTmpfs struct {
409	Size int64 `yaml:",omitempty" json:"size,omitempty"`
410}
411
412// FileReferenceConfig for a reference to a swarm file object
413type FileReferenceConfig struct {
414	Source string  `yaml:",omitempty" json:"source,omitempty"`
415	Target string  `yaml:",omitempty" json:"target,omitempty"`
416	UID    string  `yaml:",omitempty" json:"uid,omitempty"`
417	GID    string  `yaml:",omitempty" json:"gid,omitempty"`
418	Mode   *uint32 `yaml:",omitempty" json:"mode,omitempty"`
419}
420
421// ServiceConfigObjConfig is the config obj configuration for a service
422type ServiceConfigObjConfig FileReferenceConfig
423
424// ServiceSecretConfig is the secret configuration for a service
425type ServiceSecretConfig FileReferenceConfig
426
427// UlimitsConfig the ulimit configuration
428type UlimitsConfig struct {
429	Single int `yaml:",omitempty" json:"single,omitempty"`
430	Soft   int `yaml:",omitempty" json:"soft,omitempty"`
431	Hard   int `yaml:",omitempty" json:"hard,omitempty"`
432}
433
434// MarshalYAML makes UlimitsConfig implement yaml.Marshaller
435func (u *UlimitsConfig) MarshalYAML() (interface{}, error) {
436	if u.Single != 0 {
437		return u.Single, nil
438	}
439	return u, nil
440}
441
442// MarshalJSON makes UlimitsConfig implement json.Marshaller
443func (u *UlimitsConfig) MarshalJSON() ([]byte, error) {
444	if u.Single != 0 {
445		return json.Marshal(u.Single)
446	}
447	// Pass as a value to avoid re-entering this method and use the default implementation
448	return json.Marshal(*u)
449}
450
451// NetworkConfig for a network
452type NetworkConfig struct {
453	Name       string                 `yaml:",omitempty" json:"name,omitempty"`
454	Driver     string                 `yaml:",omitempty" json:"driver,omitempty"`
455	DriverOpts map[string]string      `mapstructure:"driver_opts" yaml:"driver_opts,omitempty" json:"driver_opts,omitempty"`
456	Ipam       IPAMConfig             `yaml:",omitempty" json:"ipam,omitempty"`
457	External   External               `yaml:",omitempty" json:"external,omitempty"`
458	Internal   bool                   `yaml:",omitempty" json:"internal,omitempty"`
459	Attachable bool                   `yaml:",omitempty" json:"attachable,omitempty"`
460	Labels     Labels                 `yaml:",omitempty" json:"labels,omitempty"`
461	Extras     map[string]interface{} `yaml:",inline" json:"-"`
462}
463
464// IPAMConfig for a network
465type IPAMConfig struct {
466	Driver string      `yaml:",omitempty" json:"driver,omitempty"`
467	Config []*IPAMPool `yaml:",omitempty" json:"config,omitempty"`
468}
469
470// IPAMPool for a network
471type IPAMPool struct {
472	Subnet string `yaml:",omitempty" json:"subnet,omitempty"`
473}
474
475// VolumeConfig for a volume
476type VolumeConfig struct {
477	Name       string                 `yaml:",omitempty" json:"name,omitempty"`
478	Driver     string                 `yaml:",omitempty" json:"driver,omitempty"`
479	DriverOpts map[string]string      `mapstructure:"driver_opts" yaml:"driver_opts,omitempty" json:"driver_opts,omitempty"`
480	External   External               `yaml:",omitempty" json:"external,omitempty"`
481	Labels     Labels                 `yaml:",omitempty" json:"labels,omitempty"`
482	Extras     map[string]interface{} `yaml:",inline" json:"-"`
483}
484
485// External identifies a Volume or Network as a reference to a resource that is
486// not managed, and should already exist.
487// External.name is deprecated and replaced by Volume.name
488type External struct {
489	Name     string `yaml:",omitempty" json:"name,omitempty"`
490	External bool   `yaml:",omitempty" json:"external,omitempty"`
491}
492
493// MarshalYAML makes External implement yaml.Marshaller
494func (e External) MarshalYAML() (interface{}, error) {
495	if e.Name == "" {
496		return e.External, nil
497	}
498	return External{Name: e.Name}, nil
499}
500
501// MarshalJSON makes External implement json.Marshaller
502func (e External) MarshalJSON() ([]byte, error) {
503	if e.Name == "" {
504		return []byte(fmt.Sprintf("%v", e.External)), nil
505	}
506	return []byte(fmt.Sprintf(`{"name": %q}`, e.Name)), nil
507}
508
509// CredentialSpecConfig for credential spec on Windows
510type CredentialSpecConfig struct {
511	Config   string `yaml:",omitempty" json:"config,omitempty"` // Config was added in API v1.40
512	File     string `yaml:",omitempty" json:"file,omitempty"`
513	Registry string `yaml:",omitempty" json:"registry,omitempty"`
514}
515
516// FileObjectConfig is a config type for a file used by a service
517type FileObjectConfig struct {
518	Name           string                 `yaml:",omitempty" json:"name,omitempty"`
519	File           string                 `yaml:",omitempty" json:"file,omitempty"`
520	External       External               `yaml:",omitempty" json:"external,omitempty"`
521	Labels         Labels                 `yaml:",omitempty" json:"labels,omitempty"`
522	Extras         map[string]interface{} `yaml:",inline" json:"-"`
523	Driver         string                 `yaml:",omitempty" json:"driver,omitempty"`
524	DriverOpts     map[string]string      `mapstructure:"driver_opts" yaml:"driver_opts,omitempty" json:"driver_opts,omitempty"`
525	TemplateDriver string                 `mapstructure:"template_driver" yaml:"template_driver,omitempty" json:"template_driver,omitempty"`
526}
527
528// SecretConfig for a secret
529type SecretConfig FileObjectConfig
530
531// ConfigObjConfig is the config for the swarm "Config" object
532type ConfigObjConfig FileObjectConfig
533