@@ -34,6 +34,9 @@ import (
3434"google.golang.org/cloud/internal"
3535)
363637+// metadataIP is the documented metadata server IP address.
38+const metadataIP = "169.254.169.254"
39+3740type cachedValue struct {
3841k string
3942trim bool
@@ -52,18 +55,18 @@ var (
5255Transport: &internal.Transport{
5356Base: &http.Transport{
5457Dial: (&net.Dialer{
55-Timeout: 750 * time.Millisecond,
58+Timeout: 2 * time.Second,
5659KeepAlive: 30 * time.Second,
5760 }).Dial,
58-ResponseHeaderTimeout: 750 * time.Millisecond,
61+ResponseHeaderTimeout: 2 * time.Second,
5962 },
6063 },
6164 }
6265subscribeClient = &http.Client{
6366Transport: &internal.Transport{
6467Base: &http.Transport{
6568Dial: (&net.Dialer{
66-Timeout: 750 * time.Millisecond,
69+Timeout: 2 * time.Millisecond,
6770KeepAlive: 30 * time.Second,
6871 }).Dial,
6972 },
@@ -111,7 +114,7 @@ func getETag(client *http.Client, suffix string) (value, etag string, err error)
111114// know the search suffix for "metadata" is
112115// ".google.internal", and this IP address is documented as
113116// being stable anyway.
114-host = "169.254.169.254"
117+host = metadataIP
115118 }
116119url := "http://" + host + "/computeMetadata/v1/" + suffix
117120req, _ := http.NewRequest("GET", url, nil)
@@ -171,17 +174,42 @@ func OnGCE() bool {
171174return onGCE.v
172175 }
173176onGCE.set = true
174-175-// We use the DNS name of the metadata service here instead of the IP address
176-// because we expect that to fail faster in the not-on-GCE case.
177-res, err := metaClient.Get("http://metadata.google.internal")
178-if err != nil {
179-return false
180- }
181-onGCE.v = res.Header.Get("Metadata-Flavor") == "Google"
177+onGCE.v = testOnGCE()
182178return onGCE.v
183179}
184180181+func testOnGCE() bool {
182+cancel := make(chan struct{})
183+defer close(cancel)
184+185+resc := make(chan bool, 2)
186+187+// Try two strategies in parallel.
188+// See https://github.com/GoogleCloudPlatform/gcloud-golang/issues/194
189+go func() {
190+req, _ := http.NewRequest("GET", "http://"+metadataIP, nil)
191+req.Cancel = cancel
192+res, err := metaClient.Do(req)
193+if err != nil {
194+resc <- false
195+return
196+ }
197+defer res.Body.Close()
198+resc <- res.Header.Get("Metadata-Flavor") == "Google"
199+ }()
200+201+go func() {
202+addrs, err := net.LookupHost("metadata.google.internal")
203+if err != nil || len(addrs) == 0 {
204+resc <- false
205+return
206+ }
207+resc <- strsContains(addrs, metadataIP)
208+ }()
209+210+return <-resc
211+}
212+185213// Subscribe subscribes to a value from the metadata service.
186214// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/".
187215// The suffix may contain query parameters.
@@ -342,3 +370,12 @@ func Scopes(serviceAccount string) ([]string, error) {
342370 }
343371return lines("instance/service-accounts/" + serviceAccount + "/scopes")
344372}
373+374+func strsContains(ss []string, s string) bool {
375+for _, v := range ss {
376+if v == s {
377+return true
378+ }
379+ }
380+return false
381+}