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