github.com/bigcommerce/nomad@v0.9.3-bc/client/fingerprint/env_gce_test.go (about)

     1  package fingerprint
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"net/http"
     7  	"net/http/httptest"
     8  	"os"
     9  	"strings"
    10  	"testing"
    11  
    12  	"github.com/hashicorp/nomad/client/config"
    13  	"github.com/hashicorp/nomad/helper/testlog"
    14  	"github.com/hashicorp/nomad/nomad/structs"
    15  )
    16  
    17  func TestGCEFingerprint_nonGCE(t *testing.T) {
    18  	os.Setenv("GCE_ENV_URL", "http://127.0.0.1/computeMetadata/v1/instance/")
    19  	f := NewEnvGCEFingerprint(testlog.HCLogger(t))
    20  	node := &structs.Node{
    21  		Attributes: make(map[string]string),
    22  	}
    23  
    24  	request := &FingerprintRequest{Config: &config.Config{}, Node: node}
    25  	var response FingerprintResponse
    26  	err := f.Fingerprint(request, &response)
    27  	if err != nil {
    28  		t.Fatalf("err: %v", err)
    29  	}
    30  
    31  	if response.Detected {
    32  		t.Fatalf("expected response to not be applicable")
    33  	}
    34  
    35  	if len(response.Attributes) > 0 {
    36  		t.Fatalf("Should have zero attributes without test server")
    37  	}
    38  }
    39  
    40  func testFingerprint_GCE(t *testing.T, withExternalIp bool) {
    41  	node := &structs.Node{
    42  		Attributes: make(map[string]string),
    43  	}
    44  
    45  	// configure mock server with fixture routes, data
    46  	routes := routes{}
    47  	if err := json.Unmarshal([]byte(GCE_routes), &routes); err != nil {
    48  		t.Fatalf("Failed to unmarshal JSON in GCE ENV test: %s", err)
    49  	}
    50  	networkEndpoint := &endpoint{
    51  		Uri:         "/computeMetadata/v1/instance/network-interfaces/?recursive=true",
    52  		ContentType: "application/json",
    53  	}
    54  	if withExternalIp {
    55  		networkEndpoint.Body = `[{"accessConfigs":[{"externalIp":"104.44.55.66","type":"ONE_TO_ONE_NAT"},{"externalIp":"104.44.55.67","type":"ONE_TO_ONE_NAT"}],"forwardedIps":[],"ip":"10.240.0.5","network":"projects/555555/networks/default"}]`
    56  	} else {
    57  		networkEndpoint.Body = `[{"accessConfigs":[],"forwardedIps":[],"ip":"10.240.0.5","network":"projects/555555/networks/default"}]`
    58  	}
    59  	routes.Endpoints = append(routes.Endpoints, networkEndpoint)
    60  
    61  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    62  		value, ok := r.Header["Metadata-Flavor"]
    63  		if !ok {
    64  			t.Fatal("Metadata-Flavor not present in HTTP request header")
    65  		}
    66  		if value[0] != "Google" {
    67  			t.Fatalf("Expected Metadata-Flavor Google, saw %s", value[0])
    68  		}
    69  
    70  		uavalue, ok := r.Header["User-Agent"]
    71  		if !ok {
    72  			t.Fatal("User-Agent not present in HTTP request header")
    73  		}
    74  		if !strings.Contains(uavalue[0], "Nomad/") {
    75  			t.Fatalf("Expected User-Agent to contain Nomad/, got %s", uavalue[0])
    76  		}
    77  
    78  		found := false
    79  		for _, e := range routes.Endpoints {
    80  			if r.RequestURI == e.Uri {
    81  				w.Header().Set("Content-Type", e.ContentType)
    82  				fmt.Fprintln(w, e.Body)
    83  			}
    84  			found = true
    85  		}
    86  
    87  		if !found {
    88  			w.WriteHeader(404)
    89  		}
    90  	}))
    91  	defer ts.Close()
    92  	os.Setenv("GCE_ENV_URL", ts.URL+"/computeMetadata/v1/instance/")
    93  	f := NewEnvGCEFingerprint(testlog.HCLogger(t))
    94  
    95  	request := &FingerprintRequest{Config: &config.Config{}, Node: node}
    96  	var response FingerprintResponse
    97  	err := f.Fingerprint(request, &response)
    98  	if err != nil {
    99  		t.Fatalf("err: %v", err)
   100  	}
   101  
   102  	if !response.Detected {
   103  		t.Fatalf("expected response to be applicable")
   104  	}
   105  
   106  	keys := []string{
   107  		"unique.platform.gce.id",
   108  		"unique.platform.gce.hostname",
   109  		"platform.gce.zone",
   110  		"platform.gce.machine-type",
   111  		"platform.gce.zone",
   112  		"platform.gce.tag.abc",
   113  		"platform.gce.tag.def",
   114  		"unique.platform.gce.tag.foo",
   115  		"platform.gce.attr.ghi",
   116  		"platform.gce.attr.jkl",
   117  		"unique.platform.gce.attr.bar",
   118  	}
   119  
   120  	for _, k := range keys {
   121  		assertNodeAttributeContains(t, response.Attributes, k)
   122  	}
   123  
   124  	if len(response.Links) == 0 {
   125  		t.Fatalf("Empty links for Node in GCE Fingerprint test")
   126  	}
   127  
   128  	// Make sure Links contains the GCE ID.
   129  	for _, k := range []string{"gce"} {
   130  		assertNodeLinksContains(t, response.Links, k)
   131  	}
   132  
   133  	assertNodeAttributeEquals(t, response.Attributes, "unique.platform.gce.id", "12345")
   134  	assertNodeAttributeEquals(t, response.Attributes, "unique.platform.gce.hostname", "instance-1.c.project.internal")
   135  	assertNodeAttributeEquals(t, response.Attributes, "platform.gce.zone", "us-central1-f")
   136  	assertNodeAttributeEquals(t, response.Attributes, "platform.gce.machine-type", "n1-standard-1")
   137  	assertNodeAttributeEquals(t, response.Attributes, "platform.gce.network.default", "true")
   138  	assertNodeAttributeEquals(t, response.Attributes, "unique.platform.gce.network.default.ip", "10.240.0.5")
   139  	if withExternalIp {
   140  		assertNodeAttributeEquals(t, response.Attributes, "unique.platform.gce.network.default.external-ip.0", "104.44.55.66")
   141  		assertNodeAttributeEquals(t, response.Attributes, "unique.platform.gce.network.default.external-ip.1", "104.44.55.67")
   142  	} else if _, ok := response.Attributes["unique.platform.gce.network.default.external-ip.0"]; ok {
   143  		t.Fatal("unique.platform.gce.network.default.external-ip is set without an external IP")
   144  	}
   145  
   146  	assertNodeAttributeEquals(t, response.Attributes, "platform.gce.scheduling.automatic-restart", "TRUE")
   147  	assertNodeAttributeEquals(t, response.Attributes, "platform.gce.scheduling.on-host-maintenance", "MIGRATE")
   148  	assertNodeAttributeEquals(t, response.Attributes, "platform.gce.cpu-platform", "Intel Ivy Bridge")
   149  	assertNodeAttributeEquals(t, response.Attributes, "platform.gce.tag.abc", "true")
   150  	assertNodeAttributeEquals(t, response.Attributes, "platform.gce.tag.def", "true")
   151  	assertNodeAttributeEquals(t, response.Attributes, "unique.platform.gce.tag.foo", "true")
   152  	assertNodeAttributeEquals(t, response.Attributes, "platform.gce.attr.ghi", "111")
   153  	assertNodeAttributeEquals(t, response.Attributes, "platform.gce.attr.jkl", "222")
   154  	assertNodeAttributeEquals(t, response.Attributes, "unique.platform.gce.attr.bar", "333")
   155  }
   156  
   157  const GCE_routes = `
   158  {
   159    "endpoints": [
   160      {
   161        "uri": "/computeMetadata/v1/instance/id",
   162        "content-type": "text/plain",
   163        "body": "12345"
   164      },
   165      {
   166        "uri": "/computeMetadata/v1/instance/hostname",
   167        "content-type": "text/plain",
   168        "body": "instance-1.c.project.internal"
   169      },
   170      {
   171        "uri": "/computeMetadata/v1/instance/zone",
   172        "content-type": "text/plain",
   173        "body": "projects/555555/zones/us-central1-f"
   174      },
   175      {
   176        "uri": "/computeMetadata/v1/instance/machine-type",
   177        "content-type": "text/plain",
   178        "body": "projects/555555/machineTypes/n1-standard-1"
   179      },
   180      {
   181        "uri": "/computeMetadata/v1/instance/tags",
   182        "content-type": "application/json",
   183        "body": "[\"abc\", \"def\", \"unique.foo\"]"
   184      },
   185      {
   186        "uri": "/computeMetadata/v1/instance/attributes/?recursive=true",
   187        "content-type": "application/json",
   188        "body": "{\"ghi\":\"111\",\"jkl\":\"222\",\"unique.bar\":\"333\"}"
   189      },
   190      {
   191        "uri": "/computeMetadata/v1/instance/scheduling/automatic-restart",
   192        "content-type": "text/plain",
   193        "body": "TRUE"
   194      },
   195      {
   196        "uri": "/computeMetadata/v1/instance/scheduling/on-host-maintenance",
   197        "content-type": "text/plain",
   198        "body": "MIGRATE"
   199      },
   200      {
   201        "uri": "/computeMetadata/v1/instance/cpu-platform",
   202        "content-type": "text/plain",
   203        "body": "Intel Ivy Bridge"
   204      }
   205    ]
   206  }
   207  `
   208  
   209  func TestFingerprint_GCEWithExternalIp(t *testing.T) {
   210  	testFingerprint_GCE(t, true)
   211  }
   212  
   213  func TestFingerprint_GCEWithoutExternalIp(t *testing.T) {
   214  	testFingerprint_GCE(t, false)
   215  }