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 }