github.com/AliyunContainerService/cli@v0.0.0-20181009023821-814ced4b30d0/cli/compose/loader/full-struct_test.go (about)

     1  package loader
     2  
     3  import (
     4  	"fmt"
     5  	"path/filepath"
     6  	"time"
     7  
     8  	"github.com/docker/cli/cli/compose/types"
     9  )
    10  
    11  func fullExampleConfig(workingDir, homeDir string) *types.Config {
    12  	return &types.Config{
    13  		Version:  "3.7",
    14  		Services: services(workingDir, homeDir),
    15  		Networks: networks(),
    16  		Volumes:  volumes(),
    17  		Configs:  configs(workingDir),
    18  		Secrets:  secrets(workingDir),
    19  		Extras: map[string]interface{}{
    20  			"x-foo": "bar",
    21  			"x-bar": "baz",
    22  			"x-nested": map[string]interface{}{
    23  				"foo": "bar",
    24  				"bar": "baz",
    25  			},
    26  		},
    27  	}
    28  }
    29  
    30  func services(workingDir, homeDir string) []types.ServiceConfig {
    31  	return []types.ServiceConfig{
    32  		{
    33  			Name: "foo",
    34  
    35  			Build: types.BuildConfig{
    36  				Context:    "./dir",
    37  				Dockerfile: "Dockerfile",
    38  				Args:       map[string]*string{"foo": strPtr("bar")},
    39  				Target:     "foo",
    40  				Network:    "foo",
    41  				CacheFrom:  []string{"foo", "bar"},
    42  				Labels:     map[string]string{"FOO": "BAR"},
    43  			},
    44  			CapAdd:       []string{"ALL"},
    45  			CapDrop:      []string{"NET_ADMIN", "SYS_ADMIN"},
    46  			CgroupParent: "m-executor-abcd",
    47  			Command:      []string{"bundle", "exec", "thin", "-p", "3000"},
    48  			Configs: []types.ServiceConfigObjConfig{
    49  				{
    50  					Source: "config1",
    51  				},
    52  				{
    53  					Source: "config2",
    54  					Target: "/my_config",
    55  					UID:    "103",
    56  					GID:    "103",
    57  					Mode:   uint32Ptr(0440),
    58  				},
    59  			},
    60  			ContainerName: "my-web-container",
    61  			DependsOn:     []string{"db", "redis"},
    62  			Deploy: types.DeployConfig{
    63  				Mode:     "replicated",
    64  				Replicas: uint64Ptr(6),
    65  				Labels:   map[string]string{"FOO": "BAR"},
    66  				RollbackConfig: &types.UpdateConfig{
    67  					Parallelism:     uint64Ptr(3),
    68  					Delay:           types.Duration(10 * time.Second),
    69  					FailureAction:   "continue",
    70  					Monitor:         types.Duration(60 * time.Second),
    71  					MaxFailureRatio: 0.3,
    72  					Order:           "start-first",
    73  				},
    74  				UpdateConfig: &types.UpdateConfig{
    75  					Parallelism:     uint64Ptr(3),
    76  					Delay:           types.Duration(10 * time.Second),
    77  					FailureAction:   "continue",
    78  					Monitor:         types.Duration(60 * time.Second),
    79  					MaxFailureRatio: 0.3,
    80  					Order:           "start-first",
    81  				},
    82  				Resources: types.Resources{
    83  					Limits: &types.Resource{
    84  						NanoCPUs:    "0.001",
    85  						MemoryBytes: 50 * 1024 * 1024,
    86  					},
    87  					Reservations: &types.Resource{
    88  						NanoCPUs:    "0.0001",
    89  						MemoryBytes: 20 * 1024 * 1024,
    90  						GenericResources: []types.GenericResource{
    91  							{
    92  								DiscreteResourceSpec: &types.DiscreteGenericResource{
    93  									Kind:  "gpu",
    94  									Value: 2,
    95  								},
    96  							},
    97  							{
    98  								DiscreteResourceSpec: &types.DiscreteGenericResource{
    99  									Kind:  "ssd",
   100  									Value: 1,
   101  								},
   102  							},
   103  						},
   104  					},
   105  				},
   106  				RestartPolicy: &types.RestartPolicy{
   107  					Condition:   "on-failure",
   108  					Delay:       durationPtr(5 * time.Second),
   109  					MaxAttempts: uint64Ptr(3),
   110  					Window:      durationPtr(2 * time.Minute),
   111  				},
   112  				Placement: types.Placement{
   113  					Constraints: []string{"node=foo"},
   114  					Preferences: []types.PlacementPreferences{
   115  						{
   116  							Spread: "node.labels.az",
   117  						},
   118  					},
   119  				},
   120  				EndpointMode: "dnsrr",
   121  			},
   122  			Devices:    []string{"/dev/ttyUSB0:/dev/ttyUSB0"},
   123  			DNS:        []string{"8.8.8.8", "9.9.9.9"},
   124  			DNSSearch:  []string{"dc1.example.com", "dc2.example.com"},
   125  			DomainName: "foo.com",
   126  			Entrypoint: []string{"/code/entrypoint.sh", "-p", "3000"},
   127  			Environment: map[string]*string{
   128  				"FOO": strPtr("foo_from_env_file"),
   129  				"BAR": strPtr("bar_from_env_file_2"),
   130  				"BAZ": strPtr("baz_from_service_def"),
   131  				"QUX": strPtr("qux_from_environment"),
   132  			},
   133  			EnvFile: []string{
   134  				"./example1.env",
   135  				"./example2.env",
   136  			},
   137  			Expose: []string{"3000", "8000"},
   138  			ExternalLinks: []string{
   139  				"redis_1",
   140  				"project_db_1:mysql",
   141  				"project_db_1:postgresql",
   142  			},
   143  			ExtraHosts: []string{
   144  				"somehost:162.242.195.82",
   145  				"otherhost:50.31.209.229",
   146  			},
   147  			Extras: map[string]interface{}{
   148  				"x-bar": "baz",
   149  				"x-foo": "bar",
   150  			},
   151  			HealthCheck: &types.HealthCheckConfig{
   152  				Test:        types.HealthCheckTest([]string{"CMD-SHELL", "echo \"hello world\""}),
   153  				Interval:    durationPtr(10 * time.Second),
   154  				Timeout:     durationPtr(1 * time.Second),
   155  				Retries:     uint64Ptr(5),
   156  				StartPeriod: durationPtr(15 * time.Second),
   157  			},
   158  			Hostname: "foo",
   159  			Image:    "redis",
   160  			Ipc:      "host",
   161  			Labels: map[string]string{
   162  				"com.example.description": "Accounting webapp",
   163  				"com.example.number":      "42",
   164  				"com.example.empty-label": "",
   165  			},
   166  			Links: []string{
   167  				"db",
   168  				"db:database",
   169  				"redis",
   170  			},
   171  			Logging: &types.LoggingConfig{
   172  				Driver: "syslog",
   173  				Options: map[string]string{
   174  					"syslog-address": "tcp://192.168.0.42:123",
   175  				},
   176  			},
   177  			MacAddress:  "02:42:ac:11:65:43",
   178  			NetworkMode: "container:0cfeab0f748b9a743dc3da582046357c6ef497631c1a016d28d2bf9b4f899f7b",
   179  			Networks: map[string]*types.ServiceNetworkConfig{
   180  				"some-network": {
   181  					Aliases:     []string{"alias1", "alias3"},
   182  					Ipv4Address: "",
   183  					Ipv6Address: "",
   184  				},
   185  				"other-network": {
   186  					Ipv4Address: "172.16.238.10",
   187  					Ipv6Address: "2001:3984:3989::10",
   188  				},
   189  				"other-other-network": nil,
   190  			},
   191  			Pid: "host",
   192  			Ports: []types.ServicePortConfig{
   193  				//"3000",
   194  				{
   195  					Mode:     "ingress",
   196  					Target:   3000,
   197  					Protocol: "tcp",
   198  				},
   199  				{
   200  					Mode:     "ingress",
   201  					Target:   3001,
   202  					Protocol: "tcp",
   203  				},
   204  				{
   205  					Mode:     "ingress",
   206  					Target:   3002,
   207  					Protocol: "tcp",
   208  				},
   209  				{
   210  					Mode:     "ingress",
   211  					Target:   3003,
   212  					Protocol: "tcp",
   213  				},
   214  				{
   215  					Mode:     "ingress",
   216  					Target:   3004,
   217  					Protocol: "tcp",
   218  				},
   219  				{
   220  					Mode:     "ingress",
   221  					Target:   3005,
   222  					Protocol: "tcp",
   223  				},
   224  				//"8000:8000",
   225  				{
   226  					Mode:      "ingress",
   227  					Target:    8000,
   228  					Published: 8000,
   229  					Protocol:  "tcp",
   230  				},
   231  				//"9090-9091:8080-8081",
   232  				{
   233  					Mode:      "ingress",
   234  					Target:    8080,
   235  					Published: 9090,
   236  					Protocol:  "tcp",
   237  				},
   238  				{
   239  					Mode:      "ingress",
   240  					Target:    8081,
   241  					Published: 9091,
   242  					Protocol:  "tcp",
   243  				},
   244  				//"49100:22",
   245  				{
   246  					Mode:      "ingress",
   247  					Target:    22,
   248  					Published: 49100,
   249  					Protocol:  "tcp",
   250  				},
   251  				//"127.0.0.1:8001:8001",
   252  				{
   253  					Mode:      "ingress",
   254  					Target:    8001,
   255  					Published: 8001,
   256  					Protocol:  "tcp",
   257  				},
   258  				//"127.0.0.1:5000-5010:5000-5010",
   259  				{
   260  					Mode:      "ingress",
   261  					Target:    5000,
   262  					Published: 5000,
   263  					Protocol:  "tcp",
   264  				},
   265  				{
   266  					Mode:      "ingress",
   267  					Target:    5001,
   268  					Published: 5001,
   269  					Protocol:  "tcp",
   270  				},
   271  				{
   272  					Mode:      "ingress",
   273  					Target:    5002,
   274  					Published: 5002,
   275  					Protocol:  "tcp",
   276  				},
   277  				{
   278  					Mode:      "ingress",
   279  					Target:    5003,
   280  					Published: 5003,
   281  					Protocol:  "tcp",
   282  				},
   283  				{
   284  					Mode:      "ingress",
   285  					Target:    5004,
   286  					Published: 5004,
   287  					Protocol:  "tcp",
   288  				},
   289  				{
   290  					Mode:      "ingress",
   291  					Target:    5005,
   292  					Published: 5005,
   293  					Protocol:  "tcp",
   294  				},
   295  				{
   296  					Mode:      "ingress",
   297  					Target:    5006,
   298  					Published: 5006,
   299  					Protocol:  "tcp",
   300  				},
   301  				{
   302  					Mode:      "ingress",
   303  					Target:    5007,
   304  					Published: 5007,
   305  					Protocol:  "tcp",
   306  				},
   307  				{
   308  					Mode:      "ingress",
   309  					Target:    5008,
   310  					Published: 5008,
   311  					Protocol:  "tcp",
   312  				},
   313  				{
   314  					Mode:      "ingress",
   315  					Target:    5009,
   316  					Published: 5009,
   317  					Protocol:  "tcp",
   318  				},
   319  				{
   320  					Mode:      "ingress",
   321  					Target:    5010,
   322  					Published: 5010,
   323  					Protocol:  "tcp",
   324  				},
   325  			},
   326  			Privileged: true,
   327  			ReadOnly:   true,
   328  			Restart:    "always",
   329  			Secrets: []types.ServiceSecretConfig{
   330  				{
   331  					Source: "secret1",
   332  				},
   333  				{
   334  					Source: "secret2",
   335  					Target: "my_secret",
   336  					UID:    "103",
   337  					GID:    "103",
   338  					Mode:   uint32Ptr(0440),
   339  				},
   340  			},
   341  			SecurityOpt: []string{
   342  				"label=level:s0:c100,c200",
   343  				"label=type:svirt_apache_t",
   344  			},
   345  			StdinOpen:       true,
   346  			StopSignal:      "SIGUSR1",
   347  			StopGracePeriod: durationPtr(20 * time.Second),
   348  			Tmpfs:           []string{"/run", "/tmp"},
   349  			Tty:             true,
   350  			Ulimits: map[string]*types.UlimitsConfig{
   351  				"nproc": {
   352  					Single: 65535,
   353  				},
   354  				"nofile": {
   355  					Soft: 20000,
   356  					Hard: 40000,
   357  				},
   358  			},
   359  			User: "someone",
   360  			Volumes: []types.ServiceVolumeConfig{
   361  				{Target: "/var/lib/mysql", Type: "volume"},
   362  				{Source: "/opt/data", Target: "/var/lib/mysql", Type: "bind"},
   363  				{Source: workingDir, Target: "/code", Type: "bind"},
   364  				{Source: filepath.Join(workingDir, "static"), Target: "/var/www/html", Type: "bind"},
   365  				{Source: homeDir + "/configs", Target: "/etc/configs/", Type: "bind", ReadOnly: true},
   366  				{Source: "datavolume", Target: "/var/lib/mysql", Type: "volume"},
   367  				{Source: filepath.Join(workingDir, "opt"), Target: "/opt", Consistency: "cached", Type: "bind"},
   368  				{Target: "/opt", Type: "tmpfs", Tmpfs: &types.ServiceVolumeTmpfs{
   369  					Size: int64(10000),
   370  				}},
   371  			},
   372  			WorkingDir: "/code",
   373  		},
   374  	}
   375  }
   376  
   377  func networks() map[string]types.NetworkConfig {
   378  	return map[string]types.NetworkConfig{
   379  		"some-network": {},
   380  
   381  		"other-network": {
   382  			Driver: "overlay",
   383  			DriverOpts: map[string]string{
   384  				"foo": "bar",
   385  				"baz": "1",
   386  			},
   387  			Ipam: types.IPAMConfig{
   388  				Driver: "overlay",
   389  				Config: []*types.IPAMPool{
   390  					{Subnet: "172.16.238.0/24"},
   391  					{Subnet: "2001:3984:3989::/64"},
   392  				},
   393  			},
   394  			Labels: map[string]string{
   395  				"foo": "bar",
   396  			},
   397  		},
   398  
   399  		"external-network": {
   400  			Name:     "external-network",
   401  			External: types.External{External: true},
   402  		},
   403  
   404  		"other-external-network": {
   405  			Name:     "my-cool-network",
   406  			External: types.External{External: true},
   407  			Extras: map[string]interface{}{
   408  				"x-bar": "baz",
   409  				"x-foo": "bar",
   410  			},
   411  		},
   412  	}
   413  }
   414  
   415  func volumes() map[string]types.VolumeConfig {
   416  	return map[string]types.VolumeConfig{
   417  		"some-volume": {},
   418  		"other-volume": {
   419  			Driver: "flocker",
   420  			DriverOpts: map[string]string{
   421  				"foo": "bar",
   422  				"baz": "1",
   423  			},
   424  			Labels: map[string]string{
   425  				"foo": "bar",
   426  			},
   427  		},
   428  		"another-volume": {
   429  			Name:   "user_specified_name",
   430  			Driver: "vsphere",
   431  			DriverOpts: map[string]string{
   432  				"foo": "bar",
   433  				"baz": "1",
   434  			},
   435  		},
   436  		"external-volume": {
   437  			Name:     "external-volume",
   438  			External: types.External{External: true},
   439  		},
   440  		"other-external-volume": {
   441  			Name:     "my-cool-volume",
   442  			External: types.External{External: true},
   443  		},
   444  		"external-volume3": {
   445  			Name:     "this-is-volume3",
   446  			External: types.External{External: true},
   447  			Extras: map[string]interface{}{
   448  				"x-bar": "baz",
   449  				"x-foo": "bar",
   450  			},
   451  		},
   452  	}
   453  }
   454  
   455  func configs(workingDir string) map[string]types.ConfigObjConfig {
   456  	return map[string]types.ConfigObjConfig{
   457  		"config1": {
   458  			File: filepath.Join(workingDir, "config_data"),
   459  			Labels: map[string]string{
   460  				"foo": "bar",
   461  			},
   462  		},
   463  		"config2": {
   464  			Name:     "my_config",
   465  			External: types.External{External: true},
   466  		},
   467  		"config3": {
   468  			Name:     "config3",
   469  			External: types.External{External: true},
   470  		},
   471  		"config4": {
   472  			Name: "foo",
   473  			File: workingDir,
   474  			Extras: map[string]interface{}{
   475  				"x-bar": "baz",
   476  				"x-foo": "bar",
   477  			},
   478  		},
   479  	}
   480  }
   481  
   482  func secrets(workingDir string) map[string]types.SecretConfig {
   483  	return map[string]types.SecretConfig{
   484  		"secret1": {
   485  			File: filepath.Join(workingDir, "secret_data"),
   486  			Labels: map[string]string{
   487  				"foo": "bar",
   488  			},
   489  		},
   490  		"secret2": {
   491  			Name:     "my_secret",
   492  			External: types.External{External: true},
   493  		},
   494  		"secret3": {
   495  			Name:     "secret3",
   496  			External: types.External{External: true},
   497  		},
   498  		"secret4": {
   499  			Name: "bar",
   500  			File: workingDir,
   501  			Extras: map[string]interface{}{
   502  				"x-bar": "baz",
   503  				"x-foo": "bar",
   504  			},
   505  		},
   506  	}
   507  }
   508  
   509  func fullExampleYAML(workingDir string) string {
   510  	return fmt.Sprintf(`version: "3.7"
   511  services:
   512    foo:
   513      build:
   514        context: ./dir
   515        dockerfile: Dockerfile
   516        args:
   517          foo: bar
   518        labels:
   519          FOO: BAR
   520        cache_from:
   521        - foo
   522        - bar
   523        network: foo
   524        target: foo
   525      cap_add:
   526      - ALL
   527      cap_drop:
   528      - NET_ADMIN
   529      - SYS_ADMIN
   530      cgroup_parent: m-executor-abcd
   531      command:
   532      - bundle
   533      - exec
   534      - thin
   535      - -p
   536      - "3000"
   537      configs:
   538      - source: config1
   539      - source: config2
   540        target: /my_config
   541        uid: "103"
   542        gid: "103"
   543        mode: 288
   544      container_name: my-web-container
   545      depends_on:
   546      - db
   547      - redis
   548      deploy:
   549        mode: replicated
   550        replicas: 6
   551        labels:
   552          FOO: BAR
   553        update_config:
   554          parallelism: 3
   555          delay: 10s
   556          failure_action: continue
   557          monitor: 1m0s
   558          max_failure_ratio: 0.3
   559          order: start-first
   560        rollback_config:
   561          parallelism: 3
   562          delay: 10s
   563          failure_action: continue
   564          monitor: 1m0s
   565          max_failure_ratio: 0.3
   566          order: start-first
   567        resources:
   568          limits:
   569            cpus: "0.001"
   570            memory: "52428800"
   571          reservations:
   572            cpus: "0.0001"
   573            memory: "20971520"
   574            generic_resources:
   575            - discrete_resource_spec:
   576                kind: gpu
   577                value: 2
   578            - discrete_resource_spec:
   579                kind: ssd
   580                value: 1
   581        restart_policy:
   582          condition: on-failure
   583          delay: 5s
   584          max_attempts: 3
   585          window: 2m0s
   586        placement:
   587          constraints:
   588          - node=foo
   589          preferences:
   590          - spread: node.labels.az
   591        endpoint_mode: dnsrr
   592      devices:
   593      - /dev/ttyUSB0:/dev/ttyUSB0
   594      dns:
   595      - 8.8.8.8
   596      - 9.9.9.9
   597      dns_search:
   598      - dc1.example.com
   599      - dc2.example.com
   600      domainname: foo.com
   601      entrypoint:
   602      - /code/entrypoint.sh
   603      - -p
   604      - "3000"
   605      environment:
   606        BAR: bar_from_env_file_2
   607        BAZ: baz_from_service_def
   608        FOO: foo_from_env_file
   609        QUX: qux_from_environment
   610      env_file:
   611      - ./example1.env
   612      - ./example2.env
   613      expose:
   614      - "3000"
   615      - "8000"
   616      external_links:
   617      - redis_1
   618      - project_db_1:mysql
   619      - project_db_1:postgresql
   620      extra_hosts:
   621      - somehost:162.242.195.82
   622      - otherhost:50.31.209.229
   623      hostname: foo
   624      healthcheck:
   625        test:
   626        - CMD-SHELL
   627        - echo "hello world"
   628        timeout: 1s
   629        interval: 10s
   630        retries: 5
   631        start_period: 15s
   632      image: redis
   633      ipc: host
   634      labels:
   635        com.example.description: Accounting webapp
   636        com.example.empty-label: ""
   637        com.example.number: "42"
   638      links:
   639      - db
   640      - db:database
   641      - redis
   642      logging:
   643        driver: syslog
   644        options:
   645          syslog-address: tcp://192.168.0.42:123
   646      mac_address: 02:42:ac:11:65:43
   647      network_mode: container:0cfeab0f748b9a743dc3da582046357c6ef497631c1a016d28d2bf9b4f899f7b
   648      networks:
   649        other-network:
   650          ipv4_address: 172.16.238.10
   651          ipv6_address: 2001:3984:3989::10
   652        other-other-network: null
   653        some-network:
   654          aliases:
   655          - alias1
   656          - alias3
   657      pid: host
   658      ports:
   659      - mode: ingress
   660        target: 3000
   661        protocol: tcp
   662      - mode: ingress
   663        target: 3001
   664        protocol: tcp
   665      - mode: ingress
   666        target: 3002
   667        protocol: tcp
   668      - mode: ingress
   669        target: 3003
   670        protocol: tcp
   671      - mode: ingress
   672        target: 3004
   673        protocol: tcp
   674      - mode: ingress
   675        target: 3005
   676        protocol: tcp
   677      - mode: ingress
   678        target: 8000
   679        published: 8000
   680        protocol: tcp
   681      - mode: ingress
   682        target: 8080
   683        published: 9090
   684        protocol: tcp
   685      - mode: ingress
   686        target: 8081
   687        published: 9091
   688        protocol: tcp
   689      - mode: ingress
   690        target: 22
   691        published: 49100
   692        protocol: tcp
   693      - mode: ingress
   694        target: 8001
   695        published: 8001
   696        protocol: tcp
   697      - mode: ingress
   698        target: 5000
   699        published: 5000
   700        protocol: tcp
   701      - mode: ingress
   702        target: 5001
   703        published: 5001
   704        protocol: tcp
   705      - mode: ingress
   706        target: 5002
   707        published: 5002
   708        protocol: tcp
   709      - mode: ingress
   710        target: 5003
   711        published: 5003
   712        protocol: tcp
   713      - mode: ingress
   714        target: 5004
   715        published: 5004
   716        protocol: tcp
   717      - mode: ingress
   718        target: 5005
   719        published: 5005
   720        protocol: tcp
   721      - mode: ingress
   722        target: 5006
   723        published: 5006
   724        protocol: tcp
   725      - mode: ingress
   726        target: 5007
   727        published: 5007
   728        protocol: tcp
   729      - mode: ingress
   730        target: 5008
   731        published: 5008
   732        protocol: tcp
   733      - mode: ingress
   734        target: 5009
   735        published: 5009
   736        protocol: tcp
   737      - mode: ingress
   738        target: 5010
   739        published: 5010
   740        protocol: tcp
   741      privileged: true
   742      read_only: true
   743      restart: always
   744      secrets:
   745      - source: secret1
   746      - source: secret2
   747        target: my_secret
   748        uid: "103"
   749        gid: "103"
   750        mode: 288
   751      security_opt:
   752      - label=level:s0:c100,c200
   753      - label=type:svirt_apache_t
   754      stdin_open: true
   755      stop_grace_period: 20s
   756      stop_signal: SIGUSR1
   757      tmpfs:
   758      - /run
   759      - /tmp
   760      tty: true
   761      ulimits:
   762        nofile:
   763          soft: 20000
   764          hard: 40000
   765        nproc: 65535
   766      user: someone
   767      volumes:
   768      - type: volume
   769        target: /var/lib/mysql
   770      - type: bind
   771        source: /opt/data
   772        target: /var/lib/mysql
   773      - type: bind
   774        source: /foo
   775        target: /code
   776      - type: bind
   777        source: %s
   778        target: /var/www/html
   779      - type: bind
   780        source: /bar/configs
   781        target: /etc/configs/
   782        read_only: true
   783      - type: volume
   784        source: datavolume
   785        target: /var/lib/mysql
   786      - type: bind
   787        source: %s
   788        target: /opt
   789        consistency: cached
   790      - type: tmpfs
   791        target: /opt
   792        tmpfs:
   793          size: 10000
   794      working_dir: /code
   795      x-bar: baz
   796      x-foo: bar
   797  networks:
   798    external-network:
   799      name: external-network
   800      external: true
   801    other-external-network:
   802      name: my-cool-network
   803      external: true
   804      x-bar: baz
   805      x-foo: bar
   806    other-network:
   807      driver: overlay
   808      driver_opts:
   809        baz: "1"
   810        foo: bar
   811      ipam:
   812        driver: overlay
   813        config:
   814        - subnet: 172.16.238.0/24
   815        - subnet: 2001:3984:3989::/64
   816      labels:
   817        foo: bar
   818    some-network: {}
   819  volumes:
   820    another-volume:
   821      name: user_specified_name
   822      driver: vsphere
   823      driver_opts:
   824        baz: "1"
   825        foo: bar
   826    external-volume:
   827      name: external-volume
   828      external: true
   829    external-volume3:
   830      name: this-is-volume3
   831      external: true
   832      x-bar: baz
   833      x-foo: bar
   834    other-external-volume:
   835      name: my-cool-volume
   836      external: true
   837    other-volume:
   838      driver: flocker
   839      driver_opts:
   840        baz: "1"
   841        foo: bar
   842      labels:
   843        foo: bar
   844    some-volume: {}
   845  secrets:
   846    secret1:
   847      file: %s/secret_data
   848      labels:
   849        foo: bar
   850    secret2:
   851      name: my_secret
   852      external: true
   853    secret3:
   854      name: secret3
   855      external: true
   856    secret4:
   857      name: bar
   858      file: %s
   859      x-bar: baz
   860      x-foo: bar
   861  configs:
   862    config1:
   863      file: %s/config_data
   864      labels:
   865        foo: bar
   866    config2:
   867      name: my_config
   868      external: true
   869    config3:
   870      name: config3
   871      external: true
   872    config4:
   873      name: foo
   874      file: %s
   875      x-bar: baz
   876      x-foo: bar
   877  x-bar: baz
   878  x-foo: bar
   879  x-nested:
   880    bar: baz
   881    foo: bar
   882  `,
   883  		filepath.Join(workingDir, "static"),
   884  		filepath.Join(workingDir, "opt"),
   885  		workingDir,
   886  		workingDir,
   887  		workingDir,
   888  		workingDir)
   889  }
   890  
   891  func fullExampleJSON(workingDir string) string {
   892  	return fmt.Sprintf(`{
   893    "configs": {
   894      "config1": {
   895        "file": "%s/config_data",
   896        "external": false,
   897        "labels": {
   898          "foo": "bar"
   899        }
   900      },
   901      "config2": {
   902        "name": "my_config",
   903        "external": true
   904      },
   905      "config3": {
   906        "name": "config3",
   907        "external": true
   908      },
   909      "config4": {
   910        "name": "foo",
   911        "file": "%s",
   912        "external": false
   913      }
   914    },
   915    "networks": {
   916      "external-network": {
   917        "name": "external-network",
   918        "ipam": {},
   919        "external": true
   920      },
   921      "other-external-network": {
   922        "name": "my-cool-network",
   923        "ipam": {},
   924        "external": true
   925      },
   926      "other-network": {
   927        "driver": "overlay",
   928        "driver_opts": {
   929          "baz": "1",
   930          "foo": "bar"
   931        },
   932        "ipam": {
   933          "driver": "overlay",
   934          "config": [
   935            {
   936              "subnet": "172.16.238.0/24"
   937            },
   938            {
   939              "subnet": "2001:3984:3989::/64"
   940            }
   941          ]
   942        },
   943        "external": false,
   944        "labels": {
   945          "foo": "bar"
   946        }
   947      },
   948      "some-network": {
   949        "ipam": {},
   950        "external": false
   951      }
   952    },
   953    "secrets": {
   954      "secret1": {
   955        "file": "%s/secret_data",
   956        "external": false,
   957        "labels": {
   958          "foo": "bar"
   959        }
   960      },
   961      "secret2": {
   962        "name": "my_secret",
   963        "external": true
   964      },
   965      "secret3": {
   966        "name": "secret3",
   967        "external": true
   968      },
   969      "secret4": {
   970        "name": "bar",
   971        "file": "%s",
   972        "external": false
   973      }
   974    },
   975    "services": {
   976      "foo": {
   977        "build": {
   978          "context": "./dir",
   979          "dockerfile": "Dockerfile",
   980          "args": {
   981            "foo": "bar"
   982          },
   983          "labels": {
   984            "FOO": "BAR"
   985          },
   986          "cache_from": [
   987            "foo",
   988            "bar"
   989          ],
   990          "network": "foo",
   991          "target": "foo"
   992        },
   993        "cap_add": [
   994          "ALL"
   995        ],
   996        "cap_drop": [
   997          "NET_ADMIN",
   998          "SYS_ADMIN"
   999        ],
  1000        "cgroup_parent": "m-executor-abcd",
  1001        "command": [
  1002          "bundle",
  1003          "exec",
  1004          "thin",
  1005          "-p",
  1006          "3000"
  1007        ],
  1008        "configs": [
  1009          {
  1010            "source": "config1"
  1011          },
  1012          {
  1013            "source": "config2",
  1014            "target": "/my_config",
  1015            "uid": "103",
  1016            "gid": "103",
  1017            "mode": 288
  1018          }
  1019        ],
  1020        "container_name": "my-web-container",
  1021        "credential_spec": {},
  1022        "depends_on": [
  1023          "db",
  1024          "redis"
  1025        ],
  1026        "deploy": {
  1027          "mode": "replicated",
  1028          "replicas": 6,
  1029          "labels": {
  1030            "FOO": "BAR"
  1031          },
  1032          "update_config": {
  1033            "parallelism": 3,
  1034            "delay": "10s",
  1035            "failure_action": "continue",
  1036            "monitor": "1m0s",
  1037            "max_failure_ratio": 0.3,
  1038            "order": "start-first"
  1039          },
  1040          "rollback_config": {
  1041            "parallelism": 3,
  1042            "delay": "10s",
  1043            "failure_action": "continue",
  1044            "monitor": "1m0s",
  1045            "max_failure_ratio": 0.3,
  1046            "order": "start-first"
  1047          },
  1048          "resources": {
  1049            "limits": {
  1050              "cpus": "0.001",
  1051              "memory": "52428800"
  1052            },
  1053            "reservations": {
  1054              "cpus": "0.0001",
  1055              "memory": "20971520",
  1056              "generic_resources": [
  1057                {
  1058                  "discrete_resource_spec": {
  1059                    "kind": "gpu",
  1060                    "value": 2
  1061                  }
  1062                },
  1063                {
  1064                  "discrete_resource_spec": {
  1065                    "kind": "ssd",
  1066                    "value": 1
  1067                  }
  1068                }
  1069              ]
  1070            }
  1071          },
  1072          "restart_policy": {
  1073            "condition": "on-failure",
  1074            "delay": "5s",
  1075            "max_attempts": 3,
  1076            "window": "2m0s"
  1077          },
  1078          "placement": {
  1079            "constraints": [
  1080              "node=foo"
  1081            ],
  1082            "preferences": [
  1083              {
  1084                "spread": "node.labels.az"
  1085              }
  1086            ]
  1087          },
  1088          "endpoint_mode": "dnsrr"
  1089        },
  1090        "devices": [
  1091          "/dev/ttyUSB0:/dev/ttyUSB0"
  1092        ],
  1093        "dns": [
  1094          "8.8.8.8",
  1095          "9.9.9.9"
  1096        ],
  1097        "dns_search": [
  1098          "dc1.example.com",
  1099          "dc2.example.com"
  1100        ],
  1101        "domainname": "foo.com",
  1102        "entrypoint": [
  1103          "/code/entrypoint.sh",
  1104          "-p",
  1105          "3000"
  1106        ],
  1107        "environment": {
  1108          "BAR": "bar_from_env_file_2",
  1109          "BAZ": "baz_from_service_def",
  1110          "FOO": "foo_from_env_file",
  1111          "QUX": "qux_from_environment"
  1112        },
  1113        "env_file": [
  1114          "./example1.env",
  1115          "./example2.env"
  1116        ],
  1117        "expose": [
  1118          "3000",
  1119          "8000"
  1120        ],
  1121        "external_links": [
  1122          "redis_1",
  1123          "project_db_1:mysql",
  1124          "project_db_1:postgresql"
  1125        ],
  1126        "extra_hosts": [
  1127          "somehost:162.242.195.82",
  1128          "otherhost:50.31.209.229"
  1129        ],
  1130        "hostname": "foo",
  1131        "healthcheck": {
  1132          "test": [
  1133            "CMD-SHELL",
  1134            "echo \"hello world\""
  1135          ],
  1136          "timeout": "1s",
  1137          "interval": "10s",
  1138          "retries": 5,
  1139          "start_period": "15s"
  1140        },
  1141        "image": "redis",
  1142        "ipc": "host",
  1143        "labels": {
  1144          "com.example.description": "Accounting webapp",
  1145          "com.example.empty-label": "",
  1146          "com.example.number": "42"
  1147        },
  1148        "links": [
  1149          "db",
  1150          "db:database",
  1151          "redis"
  1152        ],
  1153        "logging": {
  1154          "driver": "syslog",
  1155          "options": {
  1156            "syslog-address": "tcp://192.168.0.42:123"
  1157          }
  1158        },
  1159        "mac_address": "02:42:ac:11:65:43",
  1160        "network_mode": "container:0cfeab0f748b9a743dc3da582046357c6ef497631c1a016d28d2bf9b4f899f7b",
  1161        "networks": {
  1162          "other-network": {
  1163            "ipv4_address": "172.16.238.10",
  1164            "ipv6_address": "2001:3984:3989::10"
  1165          },
  1166          "other-other-network": null,
  1167          "some-network": {
  1168            "aliases": [
  1169              "alias1",
  1170              "alias3"
  1171            ]
  1172          }
  1173        },
  1174        "pid": "host",
  1175        "ports": [
  1176          {
  1177            "mode": "ingress",
  1178            "target": 3000,
  1179            "protocol": "tcp"
  1180          },
  1181          {
  1182            "mode": "ingress",
  1183            "target": 3001,
  1184            "protocol": "tcp"
  1185          },
  1186          {
  1187            "mode": "ingress",
  1188            "target": 3002,
  1189            "protocol": "tcp"
  1190          },
  1191          {
  1192            "mode": "ingress",
  1193            "target": 3003,
  1194            "protocol": "tcp"
  1195          },
  1196          {
  1197            "mode": "ingress",
  1198            "target": 3004,
  1199            "protocol": "tcp"
  1200          },
  1201          {
  1202            "mode": "ingress",
  1203            "target": 3005,
  1204            "protocol": "tcp"
  1205          },
  1206          {
  1207            "mode": "ingress",
  1208            "target": 8000,
  1209            "published": 8000,
  1210            "protocol": "tcp"
  1211          },
  1212          {
  1213            "mode": "ingress",
  1214            "target": 8080,
  1215            "published": 9090,
  1216            "protocol": "tcp"
  1217          },
  1218          {
  1219            "mode": "ingress",
  1220            "target": 8081,
  1221            "published": 9091,
  1222            "protocol": "tcp"
  1223          },
  1224          {
  1225            "mode": "ingress",
  1226            "target": 22,
  1227            "published": 49100,
  1228            "protocol": "tcp"
  1229          },
  1230          {
  1231            "mode": "ingress",
  1232            "target": 8001,
  1233            "published": 8001,
  1234            "protocol": "tcp"
  1235          },
  1236          {
  1237            "mode": "ingress",
  1238            "target": 5000,
  1239            "published": 5000,
  1240            "protocol": "tcp"
  1241          },
  1242          {
  1243            "mode": "ingress",
  1244            "target": 5001,
  1245            "published": 5001,
  1246            "protocol": "tcp"
  1247          },
  1248          {
  1249            "mode": "ingress",
  1250            "target": 5002,
  1251            "published": 5002,
  1252            "protocol": "tcp"
  1253          },
  1254          {
  1255            "mode": "ingress",
  1256            "target": 5003,
  1257            "published": 5003,
  1258            "protocol": "tcp"
  1259          },
  1260          {
  1261            "mode": "ingress",
  1262            "target": 5004,
  1263            "published": 5004,
  1264            "protocol": "tcp"
  1265          },
  1266          {
  1267            "mode": "ingress",
  1268            "target": 5005,
  1269            "published": 5005,
  1270            "protocol": "tcp"
  1271          },
  1272          {
  1273            "mode": "ingress",
  1274            "target": 5006,
  1275            "published": 5006,
  1276            "protocol": "tcp"
  1277          },
  1278          {
  1279            "mode": "ingress",
  1280            "target": 5007,
  1281            "published": 5007,
  1282            "protocol": "tcp"
  1283          },
  1284          {
  1285            "mode": "ingress",
  1286            "target": 5008,
  1287            "published": 5008,
  1288            "protocol": "tcp"
  1289          },
  1290          {
  1291            "mode": "ingress",
  1292            "target": 5009,
  1293            "published": 5009,
  1294            "protocol": "tcp"
  1295          },
  1296          {
  1297            "mode": "ingress",
  1298            "target": 5010,
  1299            "published": 5010,
  1300            "protocol": "tcp"
  1301          }
  1302        ],
  1303        "privileged": true,
  1304        "read_only": true,
  1305        "restart": "always",
  1306        "secrets": [
  1307          {
  1308            "source": "secret1"
  1309          },
  1310          {
  1311            "source": "secret2",
  1312            "target": "my_secret",
  1313            "uid": "103",
  1314            "gid": "103",
  1315            "mode": 288
  1316          }
  1317        ],
  1318        "security_opt": [
  1319          "label=level:s0:c100,c200",
  1320          "label=type:svirt_apache_t"
  1321        ],
  1322        "stdin_open": true,
  1323        "stop_grace_period": "20s",
  1324        "stop_signal": "SIGUSR1",
  1325        "tmpfs": [
  1326          "/run",
  1327          "/tmp"
  1328        ],
  1329        "tty": true,
  1330        "ulimits": {
  1331          "nofile": {
  1332            "soft": 20000,
  1333            "hard": 40000
  1334          },
  1335          "nproc": 65535
  1336        },
  1337        "user": "someone",
  1338        "volumes": [
  1339          {
  1340            "type": "volume",
  1341            "target": "/var/lib/mysql"
  1342          },
  1343          {
  1344            "type": "bind",
  1345            "source": "/opt/data",
  1346            "target": "/var/lib/mysql"
  1347          },
  1348          {
  1349            "type": "bind",
  1350            "source": "/foo",
  1351            "target": "/code"
  1352          },
  1353          {
  1354            "type": "bind",
  1355            "source": "%s",
  1356            "target": "/var/www/html"
  1357          },
  1358          {
  1359            "type": "bind",
  1360            "source": "/bar/configs",
  1361            "target": "/etc/configs/",
  1362            "read_only": true
  1363          },
  1364          {
  1365            "type": "volume",
  1366            "source": "datavolume",
  1367            "target": "/var/lib/mysql"
  1368          },
  1369          {
  1370            "type": "bind",
  1371            "source": "%s",
  1372            "target": "/opt",
  1373            "consistency": "cached"
  1374          },
  1375          {
  1376            "type": "tmpfs",
  1377            "target": "/opt",
  1378            "tmpfs": {
  1379              "size": 10000
  1380            }
  1381          }
  1382        ],
  1383        "working_dir": "/code"
  1384      }
  1385    },
  1386    "version": "3.7",
  1387    "volumes": {
  1388      "another-volume": {
  1389        "name": "user_specified_name",
  1390        "driver": "vsphere",
  1391        "driver_opts": {
  1392          "baz": "1",
  1393          "foo": "bar"
  1394        },
  1395        "external": false
  1396      },
  1397      "external-volume": {
  1398        "name": "external-volume",
  1399        "external": true
  1400      },
  1401      "external-volume3": {
  1402        "name": "this-is-volume3",
  1403        "external": true
  1404      },
  1405      "other-external-volume": {
  1406        "name": "my-cool-volume",
  1407        "external": true
  1408      },
  1409      "other-volume": {
  1410        "driver": "flocker",
  1411        "driver_opts": {
  1412          "baz": "1",
  1413          "foo": "bar"
  1414        },
  1415        "external": false,
  1416        "labels": {
  1417          "foo": "bar"
  1418        }
  1419      },
  1420      "some-volume": {
  1421        "external": false
  1422      }
  1423    },
  1424    "x-bar": "baz",
  1425    "x-foo": "bar",
  1426    "x-nested": {
  1427      "bar": "baz",
  1428      "foo": "bar"
  1429    }
  1430  }`,
  1431  		workingDir,
  1432  		workingDir,
  1433  		workingDir,
  1434  		workingDir,
  1435  		filepath.Join(workingDir, "static"),
  1436  		filepath.Join(workingDir, "opt"))
  1437  }