github.com/khulnasoft/cli@v0.0.0-20240402070845-01bcad7beefa/cli/compose/loader/full-struct_test.go (about)

     1  // FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
     2  //go:build go1.19
     3  
     4  package loader
     5  
     6  import (
     7  	"time"
     8  
     9  	"github.com/khulnasoft/cli/cli/compose/types"
    10  )
    11  
    12  func fullExampleConfig(workingDir, homeDir string) *types.Config {
    13  	return &types.Config{
    14  		Version:  "3.12",
    15  		Services: services(workingDir, homeDir),
    16  		Networks: networks(),
    17  		Volumes:  volumes(),
    18  		Configs:  configs(workingDir),
    19  		Secrets:  secrets(workingDir),
    20  		Extras: map[string]any{
    21  			"x-foo": "bar",
    22  			"x-bar": "baz",
    23  			"x-nested": map[string]any{
    24  				"foo": "bar",
    25  				"bar": "baz",
    26  			},
    27  		},
    28  	}
    29  }
    30  
    31  func services(workingDir, homeDir string) []types.ServiceConfig {
    32  	return []types.ServiceConfig{
    33  		{
    34  			Name: "foo",
    35  
    36  			Build: types.BuildConfig{
    37  				Context:    "./dir",
    38  				Dockerfile: "Dockerfile",
    39  				Args:       map[string]*string{"foo": strPtr("bar")},
    40  				Target:     "foo",
    41  				Network:    "foo",
    42  				CacheFrom:  []string{"foo", "bar"},
    43  				ExtraHosts: types.HostsList{
    44  					"ipv4.example.com:127.0.0.1",
    45  					"ipv6.example.com:::1",
    46  				},
    47  				Labels: map[string]string{"FOO": "BAR"},
    48  			},
    49  			CapAdd:       []string{"ALL"},
    50  			CapDrop:      []string{"NET_ADMIN", "SYS_ADMIN"},
    51  			CgroupParent: "m-executor-abcd",
    52  			Command:      []string{"bundle", "exec", "thin", "-p", "3000"},
    53  			Configs: []types.ServiceConfigObjConfig{
    54  				{
    55  					Source: "config1",
    56  				},
    57  				{
    58  					Source: "config2",
    59  					Target: "/my_config",
    60  					UID:    "103",
    61  					GID:    "103",
    62  					Mode:   uint32Ptr(0o440),
    63  				},
    64  			},
    65  			ContainerName: "my-web-container",
    66  			DependsOn:     []string{"db", "redis"},
    67  			Deploy: types.DeployConfig{
    68  				Mode:     "replicated",
    69  				Replicas: uint64Ptr(6),
    70  				Labels:   map[string]string{"FOO": "BAR"},
    71  				RollbackConfig: &types.UpdateConfig{
    72  					Parallelism:     uint64Ptr(3),
    73  					Delay:           types.Duration(10 * time.Second),
    74  					FailureAction:   "continue",
    75  					Monitor:         types.Duration(60 * time.Second),
    76  					MaxFailureRatio: 0.3,
    77  					Order:           "start-first",
    78  				},
    79  				UpdateConfig: &types.UpdateConfig{
    80  					Parallelism:     uint64Ptr(3),
    81  					Delay:           types.Duration(10 * time.Second),
    82  					FailureAction:   "continue",
    83  					Monitor:         types.Duration(60 * time.Second),
    84  					MaxFailureRatio: 0.3,
    85  					Order:           "start-first",
    86  				},
    87  				Resources: types.Resources{
    88  					Limits: &types.ResourceLimit{
    89  						NanoCPUs:    "0.001",
    90  						MemoryBytes: 50 * 1024 * 1024,
    91  						Pids:        100,
    92  					},
    93  					Reservations: &types.Resource{
    94  						NanoCPUs:    "0.0001",
    95  						MemoryBytes: 20 * 1024 * 1024,
    96  						GenericResources: []types.GenericResource{
    97  							{
    98  								DiscreteResourceSpec: &types.DiscreteGenericResource{
    99  									Kind:  "gpu",
   100  									Value: 2,
   101  								},
   102  							},
   103  							{
   104  								DiscreteResourceSpec: &types.DiscreteGenericResource{
   105  									Kind:  "ssd",
   106  									Value: 1,
   107  								},
   108  							},
   109  						},
   110  					},
   111  				},
   112  				RestartPolicy: &types.RestartPolicy{
   113  					Condition:   "on-failure",
   114  					Delay:       durationPtr(5 * time.Second),
   115  					MaxAttempts: uint64Ptr(3),
   116  					Window:      durationPtr(2 * time.Minute),
   117  				},
   118  				Placement: types.Placement{
   119  					Constraints: []string{"node=foo"},
   120  					MaxReplicas: uint64(5),
   121  					Preferences: []types.PlacementPreferences{
   122  						{
   123  							Spread: "node.labels.az",
   124  						},
   125  					},
   126  				},
   127  				EndpointMode: "dnsrr",
   128  			},
   129  			Devices:    []string{"/dev/ttyUSB0:/dev/ttyUSB0"},
   130  			DNS:        []string{"8.8.8.8", "9.9.9.9"},
   131  			DNSSearch:  []string{"dc1.example.com", "dc2.example.com"},
   132  			DomainName: "foo.com",
   133  			Entrypoint: []string{"/code/entrypoint.sh", "-p", "3000"},
   134  			Environment: map[string]*string{
   135  				"FOO": strPtr("foo_from_env_file"),
   136  				"BAR": strPtr("bar_from_env_file_2"),
   137  				"BAZ": strPtr("baz_from_service_def"),
   138  				"QUX": strPtr("qux_from_environment"),
   139  			},
   140  			EnvFile: []string{
   141  				"./example1.env",
   142  				"./example2.env",
   143  			},
   144  			Expose: []string{"3000", "8000"},
   145  			ExternalLinks: []string{
   146  				"redis_1",
   147  				"project_db_1:mysql",
   148  				"project_db_1:postgresql",
   149  			},
   150  			ExtraHosts: []string{
   151  				"somehost:162.242.195.82",
   152  				"otherhost:50.31.209.229",
   153  				"host.docker.internal:host-gateway",
   154  			},
   155  			Extras: map[string]any{
   156  				"x-bar": "baz",
   157  				"x-foo": "bar",
   158  			},
   159  			HealthCheck: &types.HealthCheckConfig{
   160  				Test:          types.HealthCheckTest([]string{"CMD-SHELL", "echo \"hello world\""}),
   161  				Interval:      durationPtr(10 * time.Second),
   162  				Timeout:       durationPtr(1 * time.Second),
   163  				Retries:       uint64Ptr(5),
   164  				StartPeriod:   durationPtr(15 * time.Second),
   165  				StartInterval: durationPtr(1 * time.Second),
   166  			},
   167  			Hostname: "foo",
   168  			Image:    "redis",
   169  			Ipc:      "host",
   170  			Labels: map[string]string{
   171  				"com.example.description": "Accounting webapp",
   172  				"com.example.number":      "42",
   173  				"com.example.empty-label": "",
   174  			},
   175  			Links: []string{
   176  				"db",
   177  				"db:database",
   178  				"redis",
   179  			},
   180  			Logging: &types.LoggingConfig{
   181  				Driver: "syslog",
   182  				Options: map[string]string{
   183  					"syslog-address": "tcp://192.168.0.42:123",
   184  				},
   185  			},
   186  			MacAddress:  "02:42:ac:11:65:43",
   187  			NetworkMode: "container:0cfeab0f748b9a743dc3da582046357c6ef497631c1a016d28d2bf9b4f899f7b",
   188  			Networks: map[string]*types.ServiceNetworkConfig{
   189  				"some-network": {
   190  					Aliases:     []string{"alias1", "alias3"},
   191  					Ipv4Address: "",
   192  					Ipv6Address: "",
   193  				},
   194  				"other-network": {
   195  					Ipv4Address: "172.16.238.10",
   196  					Ipv6Address: "2001:3984:3989::10",
   197  				},
   198  				"other-other-network": nil,
   199  			},
   200  			Pid: "host",
   201  			Ports: []types.ServicePortConfig{
   202  				// "3000",
   203  				{
   204  					Mode:     "ingress",
   205  					Target:   3000,
   206  					Protocol: "tcp",
   207  				},
   208  				{
   209  					Mode:     "ingress",
   210  					Target:   3001,
   211  					Protocol: "tcp",
   212  				},
   213  				{
   214  					Mode:     "ingress",
   215  					Target:   3002,
   216  					Protocol: "tcp",
   217  				},
   218  				{
   219  					Mode:     "ingress",
   220  					Target:   3003,
   221  					Protocol: "tcp",
   222  				},
   223  				{
   224  					Mode:     "ingress",
   225  					Target:   3004,
   226  					Protocol: "tcp",
   227  				},
   228  				{
   229  					Mode:     "ingress",
   230  					Target:   3005,
   231  					Protocol: "tcp",
   232  				},
   233  				// "8000:8000",
   234  				{
   235  					Mode:      "ingress",
   236  					Target:    8000,
   237  					Published: 8000,
   238  					Protocol:  "tcp",
   239  				},
   240  				// "9090-9091:8080-8081",
   241  				{
   242  					Mode:      "ingress",
   243  					Target:    8080,
   244  					Published: 9090,
   245  					Protocol:  "tcp",
   246  				},
   247  				{
   248  					Mode:      "ingress",
   249  					Target:    8081,
   250  					Published: 9091,
   251  					Protocol:  "tcp",
   252  				},
   253  				// "49100:22",
   254  				{
   255  					Mode:      "ingress",
   256  					Target:    22,
   257  					Published: 49100,
   258  					Protocol:  "tcp",
   259  				},
   260  				// "127.0.0.1:8001:8001",
   261  				{
   262  					Mode:      "ingress",
   263  					Target:    8001,
   264  					Published: 8001,
   265  					Protocol:  "tcp",
   266  				},
   267  				// "127.0.0.1:5000-5010:5000-5010",
   268  				{
   269  					Mode:      "ingress",
   270  					Target:    5000,
   271  					Published: 5000,
   272  					Protocol:  "tcp",
   273  				},
   274  				{
   275  					Mode:      "ingress",
   276  					Target:    5001,
   277  					Published: 5001,
   278  					Protocol:  "tcp",
   279  				},
   280  				{
   281  					Mode:      "ingress",
   282  					Target:    5002,
   283  					Published: 5002,
   284  					Protocol:  "tcp",
   285  				},
   286  				{
   287  					Mode:      "ingress",
   288  					Target:    5003,
   289  					Published: 5003,
   290  					Protocol:  "tcp",
   291  				},
   292  				{
   293  					Mode:      "ingress",
   294  					Target:    5004,
   295  					Published: 5004,
   296  					Protocol:  "tcp",
   297  				},
   298  				{
   299  					Mode:      "ingress",
   300  					Target:    5005,
   301  					Published: 5005,
   302  					Protocol:  "tcp",
   303  				},
   304  				{
   305  					Mode:      "ingress",
   306  					Target:    5006,
   307  					Published: 5006,
   308  					Protocol:  "tcp",
   309  				},
   310  				{
   311  					Mode:      "ingress",
   312  					Target:    5007,
   313  					Published: 5007,
   314  					Protocol:  "tcp",
   315  				},
   316  				{
   317  					Mode:      "ingress",
   318  					Target:    5008,
   319  					Published: 5008,
   320  					Protocol:  "tcp",
   321  				},
   322  				{
   323  					Mode:      "ingress",
   324  					Target:    5009,
   325  					Published: 5009,
   326  					Protocol:  "tcp",
   327  				},
   328  				{
   329  					Mode:      "ingress",
   330  					Target:    5010,
   331  					Published: 5010,
   332  					Protocol:  "tcp",
   333  				},
   334  			},
   335  			Privileged: true,
   336  			ReadOnly:   true,
   337  			Restart:    "always",
   338  			Secrets: []types.ServiceSecretConfig{
   339  				{
   340  					Source: "secret1",
   341  				},
   342  				{
   343  					Source: "secret2",
   344  					Target: "my_secret",
   345  					UID:    "103",
   346  					GID:    "103",
   347  					Mode:   uint32Ptr(0o440),
   348  				},
   349  			},
   350  			SecurityOpt: []string{
   351  				"label=level:s0:c100,c200",
   352  				"label=type:svirt_apache_t",
   353  			},
   354  			StdinOpen:       true,
   355  			StopSignal:      "SIGUSR1",
   356  			StopGracePeriod: durationPtr(20 * time.Second),
   357  			Sysctls: map[string]string{
   358  				"net.core.somaxconn":      "1024",
   359  				"net.ipv4.tcp_syncookies": "0",
   360  			},
   361  			Tmpfs: []string{"/run", "/tmp"},
   362  			Tty:   true,
   363  			Ulimits: map[string]*types.UlimitsConfig{
   364  				"nproc": {
   365  					Single: 65535,
   366  				},
   367  				"nofile": {
   368  					Soft: 20000,
   369  					Hard: 40000,
   370  				},
   371  			},
   372  			User: "someone",
   373  			Volumes: []types.ServiceVolumeConfig{
   374  				{Target: "/var/lib/mysql", Type: "volume"},
   375  				{Source: "/opt/data", Target: "/var/lib/mysql", Type: "bind"},
   376  				{Source: workingDir, Target: "/code", Type: "bind"},
   377  				{Source: workingDir + "/static", Target: "/var/www/html", Type: "bind"},
   378  				{Source: homeDir + "/configs", Target: "/etc/configs/", Type: "bind", ReadOnly: true},
   379  				{Source: "datavolume", Target: "/var/lib/mysql", Type: "volume"},
   380  				{Source: workingDir + "/opt", Target: "/opt", Consistency: "cached", Type: "bind"},
   381  				{Target: "/opt", Type: "tmpfs", Tmpfs: &types.ServiceVolumeTmpfs{
   382  					Size: int64(10000),
   383  				}},
   384  				{Source: "group:mygroup", Target: "/srv", Type: "cluster"},
   385  			},
   386  			WorkingDir: "/code",
   387  		},
   388  	}
   389  }
   390  
   391  func networks() map[string]types.NetworkConfig {
   392  	return map[string]types.NetworkConfig{
   393  		"some-network": {},
   394  
   395  		"other-network": {
   396  			Driver: "overlay",
   397  			DriverOpts: map[string]string{
   398  				"foo": "bar",
   399  				"baz": "1",
   400  			},
   401  			Ipam: types.IPAMConfig{
   402  				Driver: "overlay",
   403  				Config: []*types.IPAMPool{
   404  					{Subnet: "172.16.238.0/24"},
   405  					{Subnet: "2001:3984:3989::/64"},
   406  				},
   407  			},
   408  			Labels: map[string]string{
   409  				"foo": "bar",
   410  			},
   411  		},
   412  
   413  		"external-network": {
   414  			Name:     "external-network",
   415  			External: types.External{External: true},
   416  		},
   417  
   418  		"other-external-network": {
   419  			Name:     "my-cool-network",
   420  			External: types.External{External: true},
   421  			Extras: map[string]any{
   422  				"x-bar": "baz",
   423  				"x-foo": "bar",
   424  			},
   425  		},
   426  	}
   427  }
   428  
   429  func volumes() map[string]types.VolumeConfig {
   430  	return map[string]types.VolumeConfig{
   431  		"some-volume": {},
   432  		"other-volume": {
   433  			Driver: "flocker",
   434  			DriverOpts: map[string]string{
   435  				"foo": "bar",
   436  				"baz": "1",
   437  			},
   438  			Labels: map[string]string{
   439  				"foo": "bar",
   440  			},
   441  		},
   442  		"another-volume": {
   443  			Name:   "user_specified_name",
   444  			Driver: "vsphere",
   445  			DriverOpts: map[string]string{
   446  				"foo": "bar",
   447  				"baz": "1",
   448  			},
   449  		},
   450  		"external-volume": {
   451  			Name:     "external-volume",
   452  			External: types.External{External: true},
   453  		},
   454  		"other-external-volume": {
   455  			Name:     "my-cool-volume",
   456  			External: types.External{External: true},
   457  		},
   458  		"external-volume3": {
   459  			Name:     "this-is-volume3",
   460  			External: types.External{External: true},
   461  			Extras: map[string]any{
   462  				"x-bar": "baz",
   463  				"x-foo": "bar",
   464  			},
   465  		},
   466  		"cluster-volume": {
   467  			Driver: "my-csi-driver",
   468  			Spec: &types.ClusterVolumeSpec{
   469  				Group: "mygroup",
   470  				AccessMode: &types.AccessMode{
   471  					Scope:       "single",
   472  					Sharing:     "none",
   473  					BlockVolume: &types.BlockVolume{},
   474  				},
   475  				AccessibilityRequirements: &types.TopologyRequirement{
   476  					Requisite: []types.Topology{
   477  						{
   478  							Segments: types.Mapping{"region": "R1", "zone": "Z1"},
   479  						},
   480  						{
   481  							Segments: types.Mapping{"region": "R1", "zone": "Z2"},
   482  						},
   483  					},
   484  					Preferred: []types.Topology{
   485  						{
   486  							Segments: types.Mapping{"region": "R1", "zone": "Z1"},
   487  						},
   488  					},
   489  				},
   490  				CapacityRange: &types.CapacityRange{
   491  					RequiredBytes: types.UnitBytes(1 * 1024 * 1024 * 1024),
   492  					LimitBytes:    types.UnitBytes(8 * 1024 * 1024 * 1024),
   493  				},
   494  				Secrets: []types.VolumeSecret{
   495  					{Key: "mycsisecret", Secret: "secret1"},
   496  					{Key: "mycsisecret2", Secret: "secret4"},
   497  				},
   498  				Availability: "active",
   499  			},
   500  		},
   501  	}
   502  }
   503  
   504  func configs(workingDir string) map[string]types.ConfigObjConfig {
   505  	return map[string]types.ConfigObjConfig{
   506  		"config1": {
   507  			File: workingDir + "/config_data",
   508  			Labels: map[string]string{
   509  				"foo": "bar",
   510  			},
   511  		},
   512  		"config2": {
   513  			Name:     "my_config",
   514  			External: types.External{External: true},
   515  		},
   516  		"config3": {
   517  			Name:     "config3",
   518  			External: types.External{External: true},
   519  		},
   520  		"config4": {
   521  			Name: "foo",
   522  			File: workingDir,
   523  			Extras: map[string]any{
   524  				"x-bar": "baz",
   525  				"x-foo": "bar",
   526  			},
   527  		},
   528  	}
   529  }
   530  
   531  func secrets(workingDir string) map[string]types.SecretConfig {
   532  	return map[string]types.SecretConfig{
   533  		"secret1": {
   534  			File: workingDir + "/secret_data",
   535  			Labels: map[string]string{
   536  				"foo": "bar",
   537  			},
   538  		},
   539  		"secret2": {
   540  			Name:     "my_secret",
   541  			External: types.External{External: true},
   542  		},
   543  		"secret3": {
   544  			Name:     "secret3",
   545  			External: types.External{External: true},
   546  		},
   547  		"secret4": {
   548  			Name: "bar",
   549  			File: workingDir,
   550  			Extras: map[string]any{
   551  				"x-bar": "baz",
   552  				"x-foo": "bar",
   553  			},
   554  		},
   555  	}
   556  }