package status import ( "net/http" "net/http/httptest" "testing" "time" ) // A box that knows nothing but its own instance id still publishes a // Metrics block: the id is the join the console's architecture page hangs // the whole cloud half on, and the attach rule must not drop it for want of // a memory reading. func TestCollectBoxPublishesInstanceIDAlone(t *testing.T) { box := CollectBox(nil, Probes{InstanceID: "i-0c8e41d9"}, time.Now()) if box.Metrics == nil { t.Fatal("a box that knows its instance id must publish a Metrics block") } if box.Metrics.InstanceID != "i-0c8e41d9" { t.Errorf("InstanceID = %q, want i-0c8e41d9", box.Metrics.InstanceID) } } // Off-cloud there is no instance id, and absence is the honest answer: it // is what tells the console this is somebody else's hardware rather than a // machine it failed to find. func TestCollectBoxOmitsAnAbsentInstanceID(t *testing.T) { box := CollectBox(nil, Probes{}, time.Now()) if box.Metrics != nil && box.Metrics.InstanceID != "" { t.Errorf("InstanceID = %q, want empty", box.Metrics.InstanceID) } } // InstanceID reads IMDSv2: a PUT for a token, then a GET carrying it. A // server that refuses the token (IMDSv1-only, or the uid-gate) yields "", // never a partial or a panic. func TestInstanceIDReadsIMDSv2(t *testing.T) { var sawToken bool srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch { case r.Method == http.MethodPut && r.URL.Path == "/latest/api/token": if r.Header.Get("X-aws-ec2-metadata-token-ttl-seconds") == "" { t.Error("token request must carry a TTL header") } w.Write([]byte("tok123")) case r.URL.Path == "/latest/meta-data/instance-id": if r.Header.Get("X-aws-ec2-metadata-token") == "tok123" { sawToken = true } w.Write([]byte("i-0abcdef")) default: http.NotFound(w, r) } })) defer srv.Close() if got := instanceIDFrom(srv.URL, time.Second); got != "i-0abcdef" { t.Errorf("instanceIDFrom = %q, want i-0abcdef", got) } if !sawToken { t.Error("the metadata GET must present the IMDSv2 token") } } func TestInstanceIDIsEmptyWhenIMDSIsUnreachable(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { http.Error(w, "denied", http.StatusForbidden) })) defer srv.Close() if got := instanceIDFrom(srv.URL, time.Second); got != "" { t.Errorf("instanceIDFrom = %q, want empty when IMDS refuses", got) } if got := instanceIDFrom("http://127.0.0.1:1", 200*time.Millisecond); got != "" { t.Errorf("instanceIDFrom = %q, want empty when nothing answers", got) } }