github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/client/taskenv/services_test.go (about)

     1  package taskenv
     2  
     3  import (
     4  	"testing"
     5  	"time"
     6  
     7  	"github.com/hashicorp/nomad/ci"
     8  	"github.com/hashicorp/nomad/helper/pointer"
     9  	"github.com/hashicorp/nomad/nomad/structs"
    10  	"github.com/stretchr/testify/require"
    11  )
    12  
    13  // TestInterpolateServices asserts that all service
    14  // and check fields are properly interpolated.
    15  func TestInterpolateServices(t *testing.T) {
    16  	ci.Parallel(t)
    17  
    18  	services := []*structs.Service{
    19  		{
    20  			Name:      "${name}",
    21  			PortLabel: "${portlabel}",
    22  			Tags:      []string{"${tags}"},
    23  			Meta: map[string]string{
    24  				"meta-key": "${meta}",
    25  			},
    26  			CanaryMeta: map[string]string{
    27  				"canarymeta-key": "${canarymeta}",
    28  			},
    29  			Address: "${address}",
    30  			TaggedAddresses: map[string]string{
    31  				"${ta-key}": "${ta-address}",
    32  			},
    33  			Checks: []*structs.ServiceCheck{
    34  				{
    35  					Name:          "${checkname}",
    36  					Type:          "${checktype}",
    37  					Command:       "${checkcmd}",
    38  					Args:          []string{"${checkarg}"},
    39  					Path:          "${checkstr}",
    40  					Protocol:      "${checkproto}",
    41  					PortLabel:     "${checklabel}",
    42  					InitialStatus: "${checkstatus}",
    43  					Method:        "${checkmethod}",
    44  					Header: map[string][]string{
    45  						"${checkheaderk}": {"${checkheaderv}"},
    46  					},
    47  				},
    48  			},
    49  		},
    50  	}
    51  
    52  	env := &TaskEnv{
    53  		EnvMap: map[string]string{
    54  			"name":         "name",
    55  			"portlabel":    "portlabel",
    56  			"tags":         "tags",
    57  			"meta":         "meta-value",
    58  			"address":      "example.com",
    59  			"ta-key":       "public_wan",
    60  			"ta-address":   "1.2.3.4",
    61  			"canarymeta":   "canarymeta-value",
    62  			"checkname":    "checkname",
    63  			"checktype":    "checktype",
    64  			"checkcmd":     "checkcmd",
    65  			"checkarg":     "checkarg",
    66  			"checkstr":     "checkstr",
    67  			"checkpath":    "checkpath",
    68  			"checkproto":   "checkproto",
    69  			"checklabel":   "checklabel",
    70  			"checkstatus":  "checkstatus",
    71  			"checkmethod":  "checkmethod",
    72  			"checkheaderk": "checkheaderk",
    73  			"checkheaderv": "checkheaderv",
    74  		},
    75  	}
    76  
    77  	interpolated := InterpolateServices(env, services)
    78  
    79  	exp := []*structs.Service{
    80  		{
    81  			Name:      "name",
    82  			PortLabel: "portlabel",
    83  			Tags:      []string{"tags"},
    84  			Meta: map[string]string{
    85  				"meta-key": "meta-value",
    86  			},
    87  			CanaryMeta: map[string]string{
    88  				"canarymeta-key": "canarymeta-value",
    89  			},
    90  			Address: "example.com",
    91  			TaggedAddresses: map[string]string{
    92  				"public_wan": "1.2.3.4",
    93  			},
    94  			Checks: []*structs.ServiceCheck{
    95  				{
    96  					Name:          "checkname",
    97  					Type:          "checktype",
    98  					Command:       "checkcmd",
    99  					Args:          []string{"checkarg"},
   100  					Path:          "checkstr",
   101  					Protocol:      "checkproto",
   102  					PortLabel:     "checklabel",
   103  					InitialStatus: "checkstatus",
   104  					Method:        "checkmethod",
   105  					Header: map[string][]string{
   106  						"checkheaderk": {"checkheaderv"},
   107  					},
   108  				},
   109  			},
   110  		},
   111  	}
   112  
   113  	require.Equal(t, exp, interpolated)
   114  }
   115  
   116  var testEnv = NewTaskEnv(
   117  	map[string]string{"foo": "bar", "baz": "blah"},
   118  	map[string]string{"foo": "bar", "baz": "blah"},
   119  	nil, nil, "", "")
   120  
   121  func TestInterpolate_interpolateMapStringSliceString(t *testing.T) {
   122  	ci.Parallel(t)
   123  
   124  	t.Run("nil", func(t *testing.T) {
   125  		require.Nil(t, interpolateMapStringSliceString(testEnv, nil))
   126  	})
   127  
   128  	t.Run("not nil", func(t *testing.T) {
   129  		require.Equal(t, map[string][]string{
   130  			"a":   {"b"},
   131  			"bar": {"blah", "c"},
   132  		}, interpolateMapStringSliceString(testEnv, map[string][]string{
   133  			"a":      {"b"},
   134  			"${foo}": {"${baz}", "c"},
   135  		}))
   136  	})
   137  }
   138  
   139  func TestInterpolate_interpolateMapStringString(t *testing.T) {
   140  	ci.Parallel(t)
   141  
   142  	t.Run("nil", func(t *testing.T) {
   143  		require.Nil(t, interpolateMapStringString(testEnv, nil))
   144  	})
   145  
   146  	t.Run("not nil", func(t *testing.T) {
   147  		require.Equal(t, map[string]string{
   148  			"a":   "b",
   149  			"bar": "blah",
   150  		}, interpolateMapStringString(testEnv, map[string]string{
   151  			"a":      "b",
   152  			"${foo}": "${baz}",
   153  		}))
   154  	})
   155  }
   156  
   157  func TestInterpolate_interpolateMapStringInterface(t *testing.T) {
   158  	ci.Parallel(t)
   159  
   160  	t.Run("nil", func(t *testing.T) {
   161  		require.Nil(t, interpolateMapStringInterface(testEnv, nil))
   162  	})
   163  
   164  	t.Run("not nil", func(t *testing.T) {
   165  		require.Equal(t, map[string]interface{}{
   166  			"a":   1,
   167  			"bar": 2,
   168  		}, interpolateMapStringInterface(testEnv, map[string]interface{}{
   169  			"a":      1,
   170  			"${foo}": 2,
   171  		}))
   172  	})
   173  }
   174  
   175  func TestInterpolate_interpolateConnect(t *testing.T) {
   176  	ci.Parallel(t)
   177  
   178  	e := map[string]string{
   179  		"tag1":              "_tag1",
   180  		"port1":             "12345",
   181  		"address1":          "1.2.3.4",
   182  		"destination1":      "_dest1",
   183  		"datacenter1":       "_datacenter1",
   184  		"localbindaddress1": "127.0.0.2",
   185  		"path1":             "_path1",
   186  		"protocol1":         "_protocol1",
   187  		"port2":             "_port2",
   188  		"config1":           "_config1",
   189  		"driver1":           "_driver1",
   190  		"user1":             "_user1",
   191  		"config2":           "_config2",
   192  		"env1":              "_env1",
   193  		"env2":              "_env2",
   194  		"mode1":             "_mode1",
   195  		"device1":           "_device1",
   196  		"cidr1":             "10.0.0.0/64",
   197  		"ip1":               "1.1.1.1",
   198  		"server1":           "10.0.0.1",
   199  		"search1":           "10.0.0.2",
   200  		"option1":           "10.0.0.3",
   201  		"port3":             "_port3",
   202  		"network1":          "_network1",
   203  		"port4":             "_port4",
   204  		"network2":          "_network2",
   205  		"resource1":         "_resource1",
   206  		"meta1":             "_meta1",
   207  		"meta2":             "_meta2",
   208  		"signal1":           "_signal1",
   209  		"bind1":             "_bind1",
   210  		"address2":          "10.0.0.4",
   211  		"config3":           "_config3",
   212  		"protocol2":         "_protocol2",
   213  		"service1":          "_service1",
   214  		"host1":             "_host1",
   215  	}
   216  	env := NewTaskEnv(e, e, nil, nil, "", "")
   217  
   218  	connect := &structs.ConsulConnect{
   219  		Native: false,
   220  		SidecarService: &structs.ConsulSidecarService{
   221  			Tags: []string{"${tag1}", "tag2"},
   222  			Port: "${port1}",
   223  			Proxy: &structs.ConsulProxy{
   224  				LocalServiceAddress: "${address1}",
   225  				LocalServicePort:    10000,
   226  				Upstreams: []structs.ConsulUpstream{{
   227  					DestinationName:  "${destination1}",
   228  					Datacenter:       "${datacenter1}",
   229  					LocalBindPort:    10001,
   230  					LocalBindAddress: "${localbindaddress1}",
   231  				}},
   232  				Expose: &structs.ConsulExposeConfig{
   233  					Paths: []structs.ConsulExposePath{{
   234  						Path:          "${path1}",
   235  						Protocol:      "${protocol1}",
   236  						ListenerPort:  "${port2}",
   237  						LocalPathPort: 10002,
   238  					}},
   239  				},
   240  				Config: map[string]interface{}{
   241  					"${config1}": 1,
   242  					"port":       "${port1}",
   243  				},
   244  			},
   245  		},
   246  		SidecarTask: &structs.SidecarTask{
   247  			Name:   "name", // not interpolated by taskenv
   248  			Driver: "${driver1}",
   249  			User:   "${user1}",
   250  			Config: map[string]interface{}{"${config2}": 2},
   251  			Env:    map[string]string{"${env1}": "${env2}"},
   252  			Resources: &structs.Resources{
   253  				CPU:      1,
   254  				MemoryMB: 2,
   255  				DiskMB:   3,
   256  				IOPS:     4,
   257  				Networks: structs.Networks{{
   258  					Mode:   "${mode1}",
   259  					Device: "${device1}",
   260  					CIDR:   "${cidr1}",
   261  					IP:     "${ip1}",
   262  					MBits:  1,
   263  					DNS: &structs.DNSConfig{
   264  						Servers:  []string{"${server1}"},
   265  						Searches: []string{"${search1}"},
   266  						Options:  []string{"${option1}"},
   267  					},
   268  					ReservedPorts: []structs.Port{{
   269  						Label:       "${port3}",
   270  						Value:       9000,
   271  						To:          9000,
   272  						HostNetwork: "${network1}",
   273  					}},
   274  					DynamicPorts: []structs.Port{{
   275  						Label:       "${port4}",
   276  						Value:       9001,
   277  						To:          9001,
   278  						HostNetwork: "${network2}",
   279  					}},
   280  				}},
   281  				Devices: structs.ResourceDevices{{
   282  					Name: "${resource1}",
   283  				}},
   284  			},
   285  			Meta:        map[string]string{"${meta1}": "${meta2}"},
   286  			KillTimeout: pointer.Of(1 * time.Second),
   287  			LogConfig: &structs.LogConfig{
   288  				MaxFiles:      1,
   289  				MaxFileSizeMB: 2,
   290  			},
   291  			ShutdownDelay: pointer.Of(2 * time.Second),
   292  			KillSignal:    "${signal1}",
   293  		},
   294  		Gateway: &structs.ConsulGateway{
   295  			Proxy: &structs.ConsulGatewayProxy{
   296  				ConnectTimeout:                  pointer.Of(3 * time.Second),
   297  				EnvoyGatewayBindTaggedAddresses: true,
   298  				EnvoyGatewayBindAddresses: map[string]*structs.ConsulGatewayBindAddress{
   299  					"${bind1}": {
   300  						Address: "${address2}",
   301  						Port:    8000,
   302  					},
   303  				},
   304  				EnvoyGatewayNoDefaultBind: true,
   305  				Config: map[string]interface{}{
   306  					"${config3}": 4,
   307  				},
   308  			},
   309  			Ingress: &structs.ConsulIngressConfigEntry{
   310  				TLS: &structs.ConsulGatewayTLSConfig{
   311  					Enabled: true,
   312  				},
   313  				Listeners: []*structs.ConsulIngressListener{{
   314  					Protocol: "${protocol2}",
   315  					Port:     8001,
   316  					Services: []*structs.ConsulIngressService{{
   317  						Name:  "${service1}",
   318  						Hosts: []string{"${host1}", "host2"},
   319  					}},
   320  				}},
   321  			},
   322  		},
   323  	}
   324  
   325  	interpolateConnect(env, connect)
   326  
   327  	require.Equal(t, &structs.ConsulConnect{
   328  		Native: false,
   329  		SidecarService: &structs.ConsulSidecarService{
   330  			Tags: []string{"_tag1", "tag2"},
   331  			Port: "12345",
   332  			Proxy: &structs.ConsulProxy{
   333  				LocalServiceAddress: "1.2.3.4",
   334  				LocalServicePort:    10000,
   335  				Upstreams: []structs.ConsulUpstream{{
   336  					DestinationName:  "_dest1",
   337  					Datacenter:       "_datacenter1",
   338  					LocalBindPort:    10001,
   339  					LocalBindAddress: "127.0.0.2",
   340  				}},
   341  				Expose: &structs.ConsulExposeConfig{
   342  					Paths: []structs.ConsulExposePath{{
   343  						Path:          "_path1",
   344  						Protocol:      "_protocol1",
   345  						ListenerPort:  "_port2",
   346  						LocalPathPort: 10002,
   347  					}},
   348  				},
   349  				Config: map[string]interface{}{
   350  					"_config1": 1,
   351  					"port":     "12345",
   352  				},
   353  			},
   354  		},
   355  		SidecarTask: &structs.SidecarTask{
   356  			Name:   "name", // not interpolated by InterpolateServices
   357  			Driver: "_driver1",
   358  			User:   "_user1",
   359  			Config: map[string]interface{}{"_config2": 2},
   360  			Env:    map[string]string{"_env1": "_env2"},
   361  			Resources: &structs.Resources{
   362  				CPU:      1,
   363  				MemoryMB: 2,
   364  				DiskMB:   3,
   365  				IOPS:     4,
   366  				Networks: structs.Networks{{
   367  					Mode:   "_mode1",
   368  					Device: "_device1",
   369  					CIDR:   "10.0.0.0/64",
   370  					IP:     "1.1.1.1",
   371  					MBits:  1,
   372  					DNS: &structs.DNSConfig{
   373  						Servers:  []string{"10.0.0.1"},
   374  						Searches: []string{"10.0.0.2"},
   375  						Options:  []string{"10.0.0.3"},
   376  					},
   377  					ReservedPorts: []structs.Port{{
   378  						Label:       "_port3",
   379  						Value:       9000,
   380  						To:          9000,
   381  						HostNetwork: "_network1",
   382  					}},
   383  					DynamicPorts: []structs.Port{{
   384  						Label:       "_port4",
   385  						Value:       9001,
   386  						To:          9001,
   387  						HostNetwork: "_network2",
   388  					}},
   389  				}},
   390  				Devices: structs.ResourceDevices{{
   391  					Name: "_resource1",
   392  				}},
   393  			},
   394  			Meta:        map[string]string{"_meta1": "_meta2"},
   395  			KillTimeout: pointer.Of(1 * time.Second),
   396  			LogConfig: &structs.LogConfig{
   397  				MaxFiles:      1,
   398  				MaxFileSizeMB: 2,
   399  			},
   400  			ShutdownDelay: pointer.Of(2 * time.Second),
   401  			KillSignal:    "_signal1",
   402  		},
   403  		Gateway: &structs.ConsulGateway{
   404  			Proxy: &structs.ConsulGatewayProxy{
   405  				ConnectTimeout:                  pointer.Of(3 * time.Second),
   406  				EnvoyGatewayBindTaggedAddresses: true,
   407  				EnvoyGatewayBindAddresses: map[string]*structs.ConsulGatewayBindAddress{
   408  					"_bind1": {
   409  						Address: "10.0.0.4",
   410  						Port:    8000,
   411  					},
   412  				},
   413  				EnvoyGatewayNoDefaultBind: true,
   414  				Config: map[string]interface{}{
   415  					"_config3": 4,
   416  				},
   417  			},
   418  			Ingress: &structs.ConsulIngressConfigEntry{
   419  				TLS: &structs.ConsulGatewayTLSConfig{
   420  					Enabled: true,
   421  				},
   422  				Listeners: []*structs.ConsulIngressListener{{
   423  					Protocol: "_protocol2",
   424  					Port:     8001,
   425  					Services: []*structs.ConsulIngressService{{
   426  						Name:  "_service1",
   427  						Hosts: []string{"_host1", "host2"},
   428  					}},
   429  				}},
   430  			},
   431  		},
   432  	}, connect)
   433  }