aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/cloud.google.com/go/compute
diff options
context:
space:
mode:
authorNathan Dench <ndenc2@gmail.com>2019-05-24 15:16:44 +1000
committerNathan Dench <ndenc2@gmail.com>2019-05-24 15:16:44 +1000
commit107c1cdb09c575aa2f61d97f48d8587eb6bada4c (patch)
treeca7d008643efc555c388baeaf1d986e0b6b3e28c /vendor/cloud.google.com/go/compute
parent844b5a68d8af4791755b8f0ad293cc99f5959183 (diff)
downloadterraform-provider-statuscake-107c1cdb09c575aa2f61d97f48d8587eb6bada4c.tar.gz
terraform-provider-statuscake-107c1cdb09c575aa2f61d97f48d8587eb6bada4c.tar.zst
terraform-provider-statuscake-107c1cdb09c575aa2f61d97f48d8587eb6bada4c.zip
Upgrade to 0.12
Diffstat (limited to 'vendor/cloud.google.com/go/compute')
-rw-r--r--vendor/cloud.google.com/go/compute/metadata/metadata.go513
1 files changed, 513 insertions, 0 deletions
diff --git a/vendor/cloud.google.com/go/compute/metadata/metadata.go b/vendor/cloud.google.com/go/compute/metadata/metadata.go
new file mode 100644
index 0000000..125b703
--- /dev/null
+++ b/vendor/cloud.google.com/go/compute/metadata/metadata.go
@@ -0,0 +1,513 @@
1// Copyright 2014 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15// Package metadata provides access to Google Compute Engine (GCE)
16// metadata and API service accounts.
17//
18// This package is a wrapper around the GCE metadata service,
19// as documented at https://developers.google.com/compute/docs/metadata.
20package metadata // import "cloud.google.com/go/compute/metadata"
21
22import (
23 "context"
24 "encoding/json"
25 "fmt"
26 "io/ioutil"
27 "net"
28 "net/http"
29 "net/url"
30 "os"
31 "runtime"
32 "strings"
33 "sync"
34 "time"
35)
36
37const (
38 // metadataIP is the documented metadata server IP address.
39 metadataIP = "169.254.169.254"
40
41 // metadataHostEnv is the environment variable specifying the
42 // GCE metadata hostname. If empty, the default value of
43 // metadataIP ("169.254.169.254") is used instead.
44 // This is variable name is not defined by any spec, as far as
45 // I know; it was made up for the Go package.
46 metadataHostEnv = "GCE_METADATA_HOST"
47
48 userAgent = "gcloud-golang/0.1"
49)
50
51type cachedValue struct {
52 k string
53 trim bool
54 mu sync.Mutex
55 v string
56}
57
58var (
59 projID = &cachedValue{k: "project/project-id", trim: true}
60 projNum = &cachedValue{k: "project/numeric-project-id", trim: true}
61 instID = &cachedValue{k: "instance/id", trim: true}
62)
63
64var (
65 defaultClient = &Client{hc: &http.Client{
66 Transport: &http.Transport{
67 Dial: (&net.Dialer{
68 Timeout: 2 * time.Second,
69 KeepAlive: 30 * time.Second,
70 }).Dial,
71 ResponseHeaderTimeout: 2 * time.Second,
72 },
73 }}
74 subscribeClient = &Client{hc: &http.Client{
75 Transport: &http.Transport{
76 Dial: (&net.Dialer{
77 Timeout: 2 * time.Second,
78 KeepAlive: 30 * time.Second,
79 }).Dial,
80 },
81 }}
82)
83
84// NotDefinedError is returned when requested metadata is not defined.
85//
86// The underlying string is the suffix after "/computeMetadata/v1/".
87//
88// This error is not returned if the value is defined to be the empty
89// string.
90type NotDefinedError string
91
92func (suffix NotDefinedError) Error() string {
93 return fmt.Sprintf("metadata: GCE metadata %q not defined", string(suffix))
94}
95
96func (c *cachedValue) get(cl *Client) (v string, err error) {
97 defer c.mu.Unlock()
98 c.mu.Lock()
99 if c.v != "" {
100 return c.v, nil
101 }
102 if c.trim {
103 v, err = cl.getTrimmed(c.k)
104 } else {
105 v, err = cl.Get(c.k)
106 }
107 if err == nil {
108 c.v = v
109 }
110 return
111}
112
113var (
114 onGCEOnce sync.Once
115 onGCE bool
116)
117
118// OnGCE reports whether this process is running on Google Compute Engine.
119func OnGCE() bool {
120 onGCEOnce.Do(initOnGCE)
121 return onGCE
122}
123
124func initOnGCE() {
125 onGCE = testOnGCE()
126}
127
128func testOnGCE() bool {
129 // The user explicitly said they're on GCE, so trust them.
130 if os.Getenv(metadataHostEnv) != "" {
131 return true
132 }
133
134 ctx, cancel := context.WithCancel(context.Background())
135 defer cancel()
136
137 resc := make(chan bool, 2)
138
139 // Try two strategies in parallel.
140 // See https://github.com/googleapis/google-cloud-go/issues/194
141 go func() {
142 req, _ := http.NewRequest("GET", "http://"+metadataIP, nil)
143 req.Header.Set("User-Agent", userAgent)
144 res, err := defaultClient.hc.Do(req.WithContext(ctx))
145 if err != nil {
146 resc <- false
147 return
148 }
149 defer res.Body.Close()
150 resc <- res.Header.Get("Metadata-Flavor") == "Google"
151 }()
152
153 go func() {
154 addrs, err := net.LookupHost("metadata.google.internal")
155 if err != nil || len(addrs) == 0 {
156 resc <- false
157 return
158 }
159 resc <- strsContains(addrs, metadataIP)
160 }()
161
162 tryHarder := systemInfoSuggestsGCE()
163 if tryHarder {
164 res := <-resc
165 if res {
166 // The first strategy succeeded, so let's use it.
167 return true
168 }
169 // Wait for either the DNS or metadata server probe to
170 // contradict the other one and say we are running on
171 // GCE. Give it a lot of time to do so, since the system
172 // info already suggests we're running on a GCE BIOS.
173 timer := time.NewTimer(5 * time.Second)
174 defer timer.Stop()
175 select {
176 case res = <-resc:
177 return res
178 case <-timer.C:
179 // Too slow. Who knows what this system is.
180 return false
181 }
182 }
183
184 // There's no hint from the system info that we're running on
185 // GCE, so use the first probe's result as truth, whether it's
186 // true or false. The goal here is to optimize for speed for
187 // users who are NOT running on GCE. We can't assume that
188 // either a DNS lookup or an HTTP request to a blackholed IP
189 // address is fast. Worst case this should return when the
190 // metaClient's Transport.ResponseHeaderTimeout or
191 // Transport.Dial.Timeout fires (in two seconds).
192 return <-resc
193}
194
195// systemInfoSuggestsGCE reports whether the local system (without
196// doing network requests) suggests that we're running on GCE. If this
197// returns true, testOnGCE tries a bit harder to reach its metadata
198// server.
199func systemInfoSuggestsGCE() bool {
200 if runtime.GOOS != "linux" {
201 // We don't have any non-Linux clues available, at least yet.
202 return false
203 }
204 slurp, _ := ioutil.ReadFile("/sys/class/dmi/id/product_name")
205 name := strings.TrimSpace(string(slurp))
206 return name == "Google" || name == "Google Compute Engine"
207}
208
209// Subscribe calls Client.Subscribe on a client designed for subscribing (one with no
210// ResponseHeaderTimeout).
211func Subscribe(suffix string, fn func(v string, ok bool) error) error {
212 return subscribeClient.Subscribe(suffix, fn)
213}
214
215// Get calls Client.Get on the default client.
216func Get(suffix string) (string, error) { return defaultClient.Get(suffix) }
217
218// ProjectID returns the current instance's project ID string.
219func ProjectID() (string, error) { return defaultClient.ProjectID() }
220
221// NumericProjectID returns the current instance's numeric project ID.
222func NumericProjectID() (string, error) { return defaultClient.NumericProjectID() }
223
224// InternalIP returns the instance's primary internal IP address.
225func InternalIP() (string, error) { return defaultClient.InternalIP() }
226
227// ExternalIP returns the instance's primary external (public) IP address.
228func ExternalIP() (string, error) { return defaultClient.ExternalIP() }
229
230// Hostname returns the instance's hostname. This will be of the form
231// "<instanceID>.c.<projID>.internal".
232func Hostname() (string, error) { return defaultClient.Hostname() }
233
234// InstanceTags returns the list of user-defined instance tags,
235// assigned when initially creating a GCE instance.
236func InstanceTags() ([]string, error) { return defaultClient.InstanceTags() }
237
238// InstanceID returns the current VM's numeric instance ID.
239func InstanceID() (string, error) { return defaultClient.InstanceID() }
240
241// InstanceName returns the current VM's instance ID string.
242func InstanceName() (string, error) { return defaultClient.InstanceName() }
243
244// Zone returns the current VM's zone, such as "us-central1-b".
245func Zone() (string, error) { return defaultClient.Zone() }
246
247// InstanceAttributes calls Client.InstanceAttributes on the default client.
248func InstanceAttributes() ([]string, error) { return defaultClient.InstanceAttributes() }
249
250// ProjectAttributes calls Client.ProjectAttributes on the default client.
251func ProjectAttributes() ([]string, error) { return defaultClient.ProjectAttributes() }
252
253// InstanceAttributeValue calls Client.InstanceAttributeValue on the default client.
254func InstanceAttributeValue(attr string) (string, error) {
255 return defaultClient.InstanceAttributeValue(attr)
256}
257
258// ProjectAttributeValue calls Client.ProjectAttributeValue on the default client.
259func ProjectAttributeValue(attr string) (string, error) {
260 return defaultClient.ProjectAttributeValue(attr)
261}
262
263// Scopes calls Client.Scopes on the default client.
264func Scopes(serviceAccount string) ([]string, error) { return defaultClient.Scopes(serviceAccount) }
265
266func strsContains(ss []string, s string) bool {
267 for _, v := range ss {
268 if v == s {
269 return true
270 }
271 }
272 return false
273}
274
275// A Client provides metadata.
276type Client struct {
277 hc *http.Client
278}
279
280// NewClient returns a Client that can be used to fetch metadata. All HTTP requests
281// will use the given http.Client instead of the default client.
282func NewClient(c *http.Client) *Client {
283 return &Client{hc: c}
284}
285
286// getETag returns a value from the metadata service as well as the associated ETag.
287// This func is otherwise equivalent to Get.
288func (c *Client) getETag(suffix string) (value, etag string, err error) {
289 // Using a fixed IP makes it very difficult to spoof the metadata service in
290 // a container, which is an important use-case for local testing of cloud
291 // deployments. To enable spoofing of the metadata service, the environment
292 // variable GCE_METADATA_HOST is first inspected to decide where metadata
293 // requests shall go.
294 host := os.Getenv(metadataHostEnv)
295 if host == "" {
296 // Using 169.254.169.254 instead of "metadata" here because Go
297 // binaries built with the "netgo" tag and without cgo won't
298 // know the search suffix for "metadata" is
299 // ".google.internal", and this IP address is documented as
300 // being stable anyway.
301 host = metadataIP
302 }
303 u := "http://" + host + "/computeMetadata/v1/" + suffix
304 req, _ := http.NewRequest("GET", u, nil)
305 req.Header.Set("Metadata-Flavor", "Google")
306 req.Header.Set("User-Agent", userAgent)
307 res, err := c.hc.Do(req)
308 if err != nil {
309 return "", "", err
310 }
311 defer res.Body.Close()
312 if res.StatusCode == http.StatusNotFound {
313 return "", "", NotDefinedError(suffix)
314 }
315 all, err := ioutil.ReadAll(res.Body)
316 if err != nil {
317 return "", "", err
318 }
319 if res.StatusCode != 200 {
320 return "", "", &Error{Code: res.StatusCode, Message: string(all)}
321 }
322 return string(all), res.Header.Get("Etag"), nil
323}
324
325// Get returns a value from the metadata service.
326// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/".
327//
328// If the GCE_METADATA_HOST environment variable is not defined, a default of
329// 169.254.169.254 will be used instead.
330//
331// If the requested metadata is not defined, the returned error will
332// be of type NotDefinedError.
333func (c *Client) Get(suffix string) (string, error) {
334 val, _, err := c.getETag(suffix)
335 return val, err
336}
337
338func (c *Client) getTrimmed(suffix string) (s string, err error) {
339 s, err = c.Get(suffix)
340 s = strings.TrimSpace(s)
341 return
342}
343
344func (c *Client) lines(suffix string) ([]string, error) {
345 j, err := c.Get(suffix)
346 if err != nil {
347 return nil, err
348 }
349 s := strings.Split(strings.TrimSpace(j), "\n")
350 for i := range s {
351 s[i] = strings.TrimSpace(s[i])
352 }
353 return s, nil
354}
355
356// ProjectID returns the current instance's project ID string.
357func (c *Client) ProjectID() (string, error) { return projID.get(c) }
358
359// NumericProjectID returns the current instance's numeric project ID.
360func (c *Client) NumericProjectID() (string, error) { return projNum.get(c) }
361
362// InstanceID returns the current VM's numeric instance ID.
363func (c *Client) InstanceID() (string, error) { return instID.get(c) }
364
365// InternalIP returns the instance's primary internal IP address.
366func (c *Client) InternalIP() (string, error) {
367 return c.getTrimmed("instance/network-interfaces/0/ip")
368}
369
370// ExternalIP returns the instance's primary external (public) IP address.
371func (c *Client) ExternalIP() (string, error) {
372 return c.getTrimmed("instance/network-interfaces/0/access-configs/0/external-ip")
373}
374
375// Hostname returns the instance's hostname. This will be of the form
376// "<instanceID>.c.<projID>.internal".
377func (c *Client) Hostname() (string, error) {
378 return c.getTrimmed("instance/hostname")
379}
380
381// InstanceTags returns the list of user-defined instance tags,
382// assigned when initially creating a GCE instance.
383func (c *Client) InstanceTags() ([]string, error) {
384 var s []string
385 j, err := c.Get("instance/tags")
386 if err != nil {
387 return nil, err
388 }
389 if err := json.NewDecoder(strings.NewReader(j)).Decode(&s); err != nil {
390 return nil, err
391 }
392 return s, nil
393}
394
395// InstanceName returns the current VM's instance ID string.
396func (c *Client) InstanceName() (string, error) {
397 host, err := c.Hostname()
398 if err != nil {
399 return "", err
400 }
401 return strings.Split(host, ".")[0], nil
402}
403
404// Zone returns the current VM's zone, such as "us-central1-b".
405func (c *Client) Zone() (string, error) {
406 zone, err := c.getTrimmed("instance/zone")
407 // zone is of the form "projects/<projNum>/zones/<zoneName>".
408 if err != nil {
409 return "", err
410 }
411 return zone[strings.LastIndex(zone, "/")+1:], nil
412}
413
414// InstanceAttributes returns the list of user-defined attributes,
415// assigned when initially creating a GCE VM instance. The value of an
416// attribute can be obtained with InstanceAttributeValue.
417func (c *Client) InstanceAttributes() ([]string, error) { return c.lines("instance/attributes/") }
418
419// ProjectAttributes returns the list of user-defined attributes
420// applying to the project as a whole, not just this VM. The value of
421// an attribute can be obtained with ProjectAttributeValue.
422func (c *Client) ProjectAttributes() ([]string, error) { return c.lines("project/attributes/") }
423
424// InstanceAttributeValue returns the value of the provided VM
425// instance attribute.
426//
427// If the requested attribute is not defined, the returned error will
428// be of type NotDefinedError.
429//
430// InstanceAttributeValue may return ("", nil) if the attribute was
431// defined to be the empty string.
432func (c *Client) InstanceAttributeValue(attr string) (string, error) {
433 return c.Get("instance/attributes/" + attr)
434}
435
436// ProjectAttributeValue returns the value of the provided
437// project attribute.
438//
439// If the requested attribute is not defined, the returned error will
440// be of type NotDefinedError.
441//
442// ProjectAttributeValue may return ("", nil) if the attribute was
443// defined to be the empty string.
444func (c *Client) ProjectAttributeValue(attr string) (string, error) {
445 return c.Get("project/attributes/" + attr)
446}
447
448// Scopes returns the service account scopes for the given account.
449// The account may be empty or the string "default" to use the instance's
450// main account.
451func (c *Client) Scopes(serviceAccount string) ([]string, error) {
452 if serviceAccount == "" {
453 serviceAccount = "default"
454 }
455 return c.lines("instance/service-accounts/" + serviceAccount + "/scopes")
456}
457
458// Subscribe subscribes to a value from the metadata service.
459// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/".
460// The suffix may contain query parameters.
461//
462// Subscribe calls fn with the latest metadata value indicated by the provided
463// suffix. If the metadata value is deleted, fn is called with the empty string
464// and ok false. Subscribe blocks until fn returns a non-nil error or the value
465// is deleted. Subscribe returns the error value returned from the last call to
466// fn, which may be nil when ok == false.
467func (c *Client) Subscribe(suffix string, fn func(v string, ok bool) error) error {
468 const failedSubscribeSleep = time.Second * 5
469
470 // First check to see if the metadata value exists at all.
471 val, lastETag, err := c.getETag(suffix)
472 if err != nil {
473 return err
474 }
475
476 if err := fn(val, true); err != nil {
477 return err
478 }
479
480 ok := true
481 if strings.ContainsRune(suffix, '?') {
482 suffix += "&wait_for_change=true&last_etag="
483 } else {
484 suffix += "?wait_for_change=true&last_etag="
485 }
486 for {
487 val, etag, err := c.getETag(suffix + url.QueryEscape(lastETag))
488 if err != nil {
489 if _, deleted := err.(NotDefinedError); !deleted {
490 time.Sleep(failedSubscribeSleep)
491 continue // Retry on other errors.
492 }
493 ok = false
494 }
495 lastETag = etag
496
497 if err := fn(val, ok); err != nil || !ok {
498 return err
499 }
500 }
501}
502
503// Error contains an error response from the server.
504type Error struct {
505 // Code is the HTTP response status code.
506 Code int
507 // Message is the server response message.
508 Message string
509}
510
511func (e *Error) Error() string {
512 return fmt.Sprintf("compute: Received %d `%s`", e.Code, e.Message)
513}