github.com/ncodes/nomad@v0.5.7-0.20170403112158-97adf4a74fb3/client/driver/env/env_test.go (about)

     1  package env
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"reflect"
     7  	"sort"
     8  	"strings"
     9  	"testing"
    10  
    11  	"github.com/ncodes/nomad/nomad/mock"
    12  	"github.com/ncodes/nomad/nomad/structs"
    13  )
    14  
    15  const (
    16  	// Node values that tests can rely on
    17  	metaKey   = "instance"
    18  	metaVal   = "t2-micro"
    19  	attrKey   = "arch"
    20  	attrVal   = "amd64"
    21  	nodeName  = "test node"
    22  	nodeClass = "test class"
    23  
    24  	// Environment variable values that tests can rely on
    25  	envOneKey = "NOMAD_IP"
    26  	envOneVal = "127.0.0.1"
    27  	envTwoKey = "NOMAD_PORT_WEB"
    28  	envTwoVal = ":80"
    29  )
    30  
    31  var (
    32  	// Networks that tests can rely on
    33  	networks = []*structs.NetworkResource{
    34  		&structs.NetworkResource{
    35  			IP:            "127.0.0.1",
    36  			ReservedPorts: []structs.Port{{Label: "http", Value: 80}},
    37  			DynamicPorts:  []structs.Port{{Label: "https", Value: 8080}},
    38  		},
    39  	}
    40  	portMap = map[string]int{
    41  		"https": 443,
    42  	}
    43  )
    44  
    45  func testTaskEnvironment() *TaskEnvironment {
    46  	n := mock.Node()
    47  	n.Attributes = map[string]string{
    48  		attrKey: attrVal,
    49  	}
    50  	n.Meta = map[string]string{
    51  		metaKey: metaVal,
    52  	}
    53  	n.Name = nodeName
    54  	n.NodeClass = nodeClass
    55  
    56  	envvars := map[string]string{
    57  		envOneKey: envOneVal,
    58  		envTwoKey: envTwoVal,
    59  	}
    60  	return NewTaskEnvironment(n).SetEnvvars(envvars).Build()
    61  }
    62  
    63  func TestEnvironment_ParseAndReplace_Env(t *testing.T) {
    64  	env := testTaskEnvironment()
    65  
    66  	input := []string{fmt.Sprintf(`"${%v}"!`, envOneKey), fmt.Sprintf("${%s}${%s}", envOneKey, envTwoKey)}
    67  	act := env.ParseAndReplace(input)
    68  	exp := []string{fmt.Sprintf(`"%s"!`, envOneVal), fmt.Sprintf("%s%s", envOneVal, envTwoVal)}
    69  
    70  	if !reflect.DeepEqual(act, exp) {
    71  		t.Fatalf("ParseAndReplace(%v) returned %#v; want %#v", input, act, exp)
    72  	}
    73  }
    74  
    75  func TestEnvironment_ParseAndReplace_Meta(t *testing.T) {
    76  	input := []string{fmt.Sprintf("${%v%v}", nodeMetaPrefix, metaKey)}
    77  	exp := []string{metaVal}
    78  	env := testTaskEnvironment()
    79  	act := env.ParseAndReplace(input)
    80  
    81  	if !reflect.DeepEqual(act, exp) {
    82  		t.Fatalf("ParseAndReplace(%v) returned %#v; want %#v", input, act, exp)
    83  	}
    84  }
    85  
    86  func TestEnvironment_ParseAndReplace_Attr(t *testing.T) {
    87  	input := []string{fmt.Sprintf("${%v%v}", nodeAttributePrefix, attrKey)}
    88  	exp := []string{attrVal}
    89  	env := testTaskEnvironment()
    90  	act := env.ParseAndReplace(input)
    91  
    92  	if !reflect.DeepEqual(act, exp) {
    93  		t.Fatalf("ParseAndReplace(%v) returned %#v; want %#v", input, act, exp)
    94  	}
    95  }
    96  
    97  func TestEnvironment_ParseAndReplace_Node(t *testing.T) {
    98  	input := []string{fmt.Sprintf("${%v}", nodeNameKey), fmt.Sprintf("${%v}", nodeClassKey)}
    99  	exp := []string{nodeName, nodeClass}
   100  	env := testTaskEnvironment()
   101  	act := env.ParseAndReplace(input)
   102  
   103  	if !reflect.DeepEqual(act, exp) {
   104  		t.Fatalf("ParseAndReplace(%v) returned %#v; want %#v", input, act, exp)
   105  	}
   106  }
   107  
   108  func TestEnvironment_ParseAndReplace_Mixed(t *testing.T) {
   109  	input := []string{
   110  		fmt.Sprintf("${%v}${%v%v}", nodeNameKey, nodeAttributePrefix, attrKey),
   111  		fmt.Sprintf("${%v}${%v%v}", nodeClassKey, nodeMetaPrefix, metaKey),
   112  		fmt.Sprintf("${%v}${%v}", envTwoKey, nodeClassKey),
   113  	}
   114  	exp := []string{
   115  		fmt.Sprintf("%v%v", nodeName, attrVal),
   116  		fmt.Sprintf("%v%v", nodeClass, metaVal),
   117  		fmt.Sprintf("%v%v", envTwoVal, nodeClass),
   118  	}
   119  	env := testTaskEnvironment()
   120  	act := env.ParseAndReplace(input)
   121  
   122  	if !reflect.DeepEqual(act, exp) {
   123  		t.Fatalf("ParseAndReplace(%v) returned %#v; want %#v", input, act, exp)
   124  	}
   125  }
   126  
   127  func TestEnvironment_ReplaceEnv_Mixed(t *testing.T) {
   128  	input := fmt.Sprintf("${%v}${%v%v}", nodeNameKey, nodeAttributePrefix, attrKey)
   129  	exp := fmt.Sprintf("%v%v", nodeName, attrVal)
   130  	env := testTaskEnvironment()
   131  	act := env.ReplaceEnv(input)
   132  
   133  	if act != exp {
   134  		t.Fatalf("ParseAndReplace(%v) returned %#v; want %#v", input, act, exp)
   135  	}
   136  }
   137  
   138  func TestEnvironment_AsList(t *testing.T) {
   139  	n := mock.Node()
   140  	a := mock.Alloc()
   141  	a.Resources.Networks[0].ReservedPorts = append(a.Resources.Networks[0].ReservedPorts,
   142  		structs.Port{Label: "ssh", Value: 22},
   143  		structs.Port{Label: "other", Value: 1234},
   144  	)
   145  	a.TaskResources["web"].Networks[0].DynamicPorts[0].Value = 2000
   146  	a.TaskResources["ssh"] = &structs.Resources{
   147  		Networks: []*structs.NetworkResource{
   148  			{
   149  				Device: "eth0",
   150  				IP:     "192.168.0.100",
   151  				MBits:  50,
   152  				ReservedPorts: []structs.Port{
   153  					{Label: "ssh", Value: 22},
   154  					{Label: "other", Value: 1234},
   155  				},
   156  			},
   157  		},
   158  	}
   159  	env := NewTaskEnvironment(n).
   160  		SetNetworks(networks).
   161  		SetPortMap(portMap).
   162  		SetTaskMeta(map[string]string{"foo": "baz"}).
   163  		SetAlloc(a).
   164  		SetTaskName("taskA").Build()
   165  
   166  	act := env.EnvList()
   167  	exp := []string{
   168  		"NOMAD_ADDR_http=127.0.0.1:80",
   169  		"NOMAD_PORT_http=80",
   170  		"NOMAD_IP_http=127.0.0.1",
   171  		"NOMAD_ADDR_https=127.0.0.1:443",
   172  		"NOMAD_PORT_https=443",
   173  		"NOMAD_IP_https=127.0.0.1",
   174  		"NOMAD_HOST_PORT_http=80",
   175  		"NOMAD_HOST_PORT_https=8080",
   176  		"NOMAD_META_FOO=baz",
   177  		"NOMAD_META_foo=baz",
   178  		"NOMAD_ADDR_web_main=192.168.0.100:5000",
   179  		"NOMAD_ADDR_web_http=192.168.0.100:2000",
   180  		"NOMAD_PORT_web_main=5000",
   181  		"NOMAD_PORT_web_http=2000",
   182  		"NOMAD_IP_web_main=192.168.0.100",
   183  		"NOMAD_IP_web_http=192.168.0.100",
   184  		"NOMAD_TASK_NAME=taskA",
   185  		"NOMAD_ADDR_ssh_other=192.168.0.100:1234",
   186  		"NOMAD_ADDR_ssh_ssh=192.168.0.100:22",
   187  		"NOMAD_IP_ssh_other=192.168.0.100",
   188  		"NOMAD_IP_ssh_ssh=192.168.0.100",
   189  		"NOMAD_PORT_ssh_other=1234",
   190  		"NOMAD_PORT_ssh_ssh=22",
   191  		fmt.Sprintf("NOMAD_ALLOC_ID=%s", a.ID),
   192  	}
   193  	sort.Strings(act)
   194  	sort.Strings(exp)
   195  	if len(act) != len(exp) {
   196  		t.Fatalf("wat: %d != %d", len(act), len(exp))
   197  	}
   198  	for i := range act {
   199  		if act[i] != exp[i] {
   200  			t.Errorf("%d %q != %q", i, act[i], exp[i])
   201  		}
   202  	}
   203  }
   204  
   205  func TestEnvironment_VaultToken(t *testing.T) {
   206  	n := mock.Node()
   207  	env := NewTaskEnvironment(n).SetVaultToken("123", false).Build()
   208  
   209  	act := env.EnvList()
   210  	if len(act) != 0 {
   211  		t.Fatalf("Unexpected environment variables: %v", act)
   212  	}
   213  
   214  	env = env.SetVaultToken("123", true).Build()
   215  	act = env.EnvList()
   216  	exp := []string{"VAULT_TOKEN=123"}
   217  	if !reflect.DeepEqual(act, exp) {
   218  		t.Fatalf("env.List() returned %v; want %v", act, exp)
   219  	}
   220  }
   221  
   222  func TestEnvironment_ClearEnvvars(t *testing.T) {
   223  	n := mock.Node()
   224  	env := NewTaskEnvironment(n).
   225  		SetNetworks(networks).
   226  		SetPortMap(portMap).
   227  		SetEnvvars(map[string]string{"foo": "baz", "bar": "bang"}).Build()
   228  
   229  	act := env.EnvList()
   230  	exp := []string{
   231  		"NOMAD_ADDR_http=127.0.0.1:80",
   232  		"NOMAD_PORT_http=80",
   233  		"NOMAD_IP_http=127.0.0.1",
   234  		"NOMAD_ADDR_https=127.0.0.1:443",
   235  		"NOMAD_PORT_https=443",
   236  		"NOMAD_IP_https=127.0.0.1",
   237  		"NOMAD_HOST_PORT_http=80",
   238  		"NOMAD_HOST_PORT_https=8080",
   239  		"bar=bang",
   240  		"foo=baz",
   241  	}
   242  	sort.Strings(act)
   243  	sort.Strings(exp)
   244  	if !reflect.DeepEqual(act, exp) {
   245  		t.Fatalf("env.List() returned %v; want %v", act, exp)
   246  	}
   247  
   248  	// Clear the environent variables.
   249  	env.ClearEnvvars().Build()
   250  
   251  	act = env.EnvList()
   252  	exp = []string{
   253  		"NOMAD_ADDR_http=127.0.0.1:80",
   254  		"NOMAD_PORT_http=80",
   255  		"NOMAD_IP_http=127.0.0.1",
   256  		"NOMAD_ADDR_https=127.0.0.1:443",
   257  		"NOMAD_PORT_https=443",
   258  		"NOMAD_IP_https=127.0.0.1",
   259  		"NOMAD_HOST_PORT_https=8080",
   260  		"NOMAD_HOST_PORT_http=80",
   261  	}
   262  	sort.Strings(act)
   263  	sort.Strings(exp)
   264  	if !reflect.DeepEqual(act, exp) {
   265  		t.Fatalf("env.List() returned %v; want %v", act, exp)
   266  	}
   267  }
   268  
   269  func TestEnvironment_Interpolate(t *testing.T) {
   270  	env := testTaskEnvironment().
   271  		SetEnvvars(map[string]string{"test": "${node.class}", "test2": "${attr.arch}"}).
   272  		Build()
   273  
   274  	act := env.EnvList()
   275  	exp := []string{fmt.Sprintf("test=%s", nodeClass), fmt.Sprintf("test2=%s", attrVal)}
   276  	sort.Strings(act)
   277  	sort.Strings(exp)
   278  	if !reflect.DeepEqual(act, exp) {
   279  		t.Fatalf("env.List() returned %v; want %v", act, exp)
   280  	}
   281  }
   282  
   283  func TestEnvironment_AppendHostEnvvars(t *testing.T) {
   284  	host := os.Environ()
   285  	if len(host) < 2 {
   286  		t.Skip("No host environment variables. Can't test")
   287  	}
   288  	skip := strings.Split(host[0], "=")[0]
   289  	env := testTaskEnvironment().
   290  		AppendHostEnvvars([]string{skip}).
   291  		Build()
   292  
   293  	act := env.EnvMap()
   294  	if len(act) < 1 {
   295  		t.Fatalf("Host environment variables not properly set")
   296  	}
   297  	if _, ok := act[skip]; ok {
   298  		t.Fatalf("Didn't filter environment variable %q", skip)
   299  	}
   300  }
   301  
   302  // TestEnvironment_DashesInTaskName asserts dashes in port labels are properly
   303  // converted to underscores in environment variables.
   304  // See: https://github.com/ncodes/nomad/issues/2405
   305  func TestEnvironment_DashesInTaskName(t *testing.T) {
   306  	env := testTaskEnvironment()
   307  	env.SetNetworks([]*structs.NetworkResource{
   308  		{
   309  			Device: "eth0",
   310  			DynamicPorts: []structs.Port{
   311  				{
   312  					Label: "just-some-dashes",
   313  					Value: 9000,
   314  				},
   315  			},
   316  		},
   317  	})
   318  	env.Build()
   319  
   320  	if env.TaskEnv["NOMAD_PORT_just_some_dashes"] != "9000" {
   321  		t.Fatalf("Expected NOMAD_PORT_just_some_dashes=9000 in TaskEnv; found:\n%#v", env.TaskEnv)
   322  	}
   323  }