metadata.go 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839
  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. // Package metadata provides access to Google Compute Engine (GCE)
  15. // metadata and API service accounts.
  16. //
  17. // This package is a wrapper around the GCE metadata service,
  18. // as documented at https://cloud.google.com/compute/docs/metadata/overview.
  19. package metadata // import "cloud.google.com/go/compute/metadata"
  20. import (
  21. "context"
  22. "encoding/json"
  23. "fmt"
  24. "io"
  25. "net"
  26. "net/http"
  27. "net/url"
  28. "os"
  29. "strings"
  30. "sync"
  31. "time"
  32. )
  33. const (
  34. // metadataIP is the documented metadata server IP address.
  35. metadataIP = "169.254.169.254"
  36. // metadataHostEnv is the environment variable specifying the
  37. // GCE metadata hostname. If empty, the default value of
  38. // metadataIP ("169.254.169.254") is used instead.
  39. // This is variable name is not defined by any spec, as far as
  40. // I know; it was made up for the Go package.
  41. metadataHostEnv = "GCE_METADATA_HOST"
  42. userAgent = "gcloud-golang/0.1"
  43. )
  44. type cachedValue struct {
  45. k string
  46. trim bool
  47. mu sync.Mutex
  48. v string
  49. }
  50. var (
  51. projID = &cachedValue{k: "project/project-id", trim: true}
  52. projNum = &cachedValue{k: "project/numeric-project-id", trim: true}
  53. instID = &cachedValue{k: "instance/id", trim: true}
  54. )
  55. var defaultClient = &Client{hc: newDefaultHTTPClient()}
  56. func newDefaultHTTPClient() *http.Client {
  57. return &http.Client{
  58. Transport: &http.Transport{
  59. Dial: (&net.Dialer{
  60. Timeout: 2 * time.Second,
  61. KeepAlive: 30 * time.Second,
  62. }).Dial,
  63. IdleConnTimeout: 60 * time.Second,
  64. },
  65. Timeout: 5 * time.Second,
  66. }
  67. }
  68. // NotDefinedError is returned when requested metadata is not defined.
  69. //
  70. // The underlying string is the suffix after "/computeMetadata/v1/".
  71. //
  72. // This error is not returned if the value is defined to be the empty
  73. // string.
  74. type NotDefinedError string
  75. func (suffix NotDefinedError) Error() string {
  76. return fmt.Sprintf("metadata: GCE metadata %q not defined", string(suffix))
  77. }
  78. func (c *cachedValue) get(ctx context.Context, cl *Client) (v string, err error) {
  79. defer c.mu.Unlock()
  80. c.mu.Lock()
  81. if c.v != "" {
  82. return c.v, nil
  83. }
  84. if c.trim {
  85. v, err = cl.getTrimmed(ctx, c.k)
  86. } else {
  87. v, err = cl.GetWithContext(ctx, c.k)
  88. }
  89. if err == nil {
  90. c.v = v
  91. }
  92. return
  93. }
  94. var (
  95. onGCEOnce sync.Once
  96. onGCE bool
  97. )
  98. // OnGCE reports whether this process is running on Google Compute Platforms.
  99. // NOTE: True returned from `OnGCE` does not guarantee that the metadata server
  100. // is accessible from this process and have all the metadata defined.
  101. func OnGCE() bool {
  102. onGCEOnce.Do(initOnGCE)
  103. return onGCE
  104. }
  105. func initOnGCE() {
  106. onGCE = testOnGCE()
  107. }
  108. func testOnGCE() bool {
  109. // The user explicitly said they're on GCE, so trust them.
  110. if os.Getenv(metadataHostEnv) != "" {
  111. return true
  112. }
  113. ctx, cancel := context.WithCancel(context.Background())
  114. defer cancel()
  115. resc := make(chan bool, 2)
  116. // Try two strategies in parallel.
  117. // See https://github.com/googleapis/google-cloud-go/issues/194
  118. go func() {
  119. req, _ := http.NewRequest("GET", "http://"+metadataIP, nil)
  120. req.Header.Set("User-Agent", userAgent)
  121. res, err := newDefaultHTTPClient().Do(req.WithContext(ctx))
  122. if err != nil {
  123. resc <- false
  124. return
  125. }
  126. defer res.Body.Close()
  127. resc <- res.Header.Get("Metadata-Flavor") == "Google"
  128. }()
  129. go func() {
  130. resolver := &net.Resolver{}
  131. addrs, err := resolver.LookupHost(ctx, "metadata.google.internal.")
  132. if err != nil || len(addrs) == 0 {
  133. resc <- false
  134. return
  135. }
  136. resc <- strsContains(addrs, metadataIP)
  137. }()
  138. tryHarder := systemInfoSuggestsGCE()
  139. if tryHarder {
  140. res := <-resc
  141. if res {
  142. // The first strategy succeeded, so let's use it.
  143. return true
  144. }
  145. // Wait for either the DNS or metadata server probe to
  146. // contradict the other one and say we are running on
  147. // GCE. Give it a lot of time to do so, since the system
  148. // info already suggests we're running on a GCE BIOS.
  149. timer := time.NewTimer(5 * time.Second)
  150. defer timer.Stop()
  151. select {
  152. case res = <-resc:
  153. return res
  154. case <-timer.C:
  155. // Too slow. Who knows what this system is.
  156. return false
  157. }
  158. }
  159. // There's no hint from the system info that we're running on
  160. // GCE, so use the first probe's result as truth, whether it's
  161. // true or false. The goal here is to optimize for speed for
  162. // users who are NOT running on GCE. We can't assume that
  163. // either a DNS lookup or an HTTP request to a blackholed IP
  164. // address is fast. Worst case this should return when the
  165. // metaClient's Transport.ResponseHeaderTimeout or
  166. // Transport.Dial.Timeout fires (in two seconds).
  167. return <-resc
  168. }
  169. // Subscribe calls Client.SubscribeWithContext on the default client.
  170. //
  171. // Deprecated: Please use the context aware variant [SubscribeWithContext].
  172. func Subscribe(suffix string, fn func(v string, ok bool) error) error {
  173. return defaultClient.SubscribeWithContext(context.Background(), suffix, func(ctx context.Context, v string, ok bool) error { return fn(v, ok) })
  174. }
  175. // SubscribeWithContext calls Client.SubscribeWithContext on the default client.
  176. func SubscribeWithContext(ctx context.Context, suffix string, fn func(ctx context.Context, v string, ok bool) error) error {
  177. return defaultClient.SubscribeWithContext(ctx, suffix, fn)
  178. }
  179. // Get calls Client.GetWithContext on the default client.
  180. //
  181. // Deprecated: Please use the context aware variant [GetWithContext].
  182. func Get(suffix string) (string, error) {
  183. return defaultClient.GetWithContext(context.Background(), suffix)
  184. }
  185. // GetWithContext calls Client.GetWithContext on the default client.
  186. func GetWithContext(ctx context.Context, suffix string) (string, error) {
  187. return defaultClient.GetWithContext(ctx, suffix)
  188. }
  189. // ProjectID returns the current instance's project ID string.
  190. //
  191. // Deprecated: Please use the context aware variant [ProjectIDWithContext].
  192. func ProjectID() (string, error) {
  193. return defaultClient.ProjectIDWithContext(context.Background())
  194. }
  195. // ProjectIDWithContext returns the current instance's project ID string.
  196. func ProjectIDWithContext(ctx context.Context) (string, error) {
  197. return defaultClient.ProjectIDWithContext(ctx)
  198. }
  199. // NumericProjectID returns the current instance's numeric project ID.
  200. //
  201. // Deprecated: Please use the context aware variant [NumericProjectIDWithContext].
  202. func NumericProjectID() (string, error) {
  203. return defaultClient.NumericProjectIDWithContext(context.Background())
  204. }
  205. // NumericProjectIDWithContext returns the current instance's numeric project ID.
  206. func NumericProjectIDWithContext(ctx context.Context) (string, error) {
  207. return defaultClient.NumericProjectIDWithContext(ctx)
  208. }
  209. // InternalIP returns the instance's primary internal IP address.
  210. //
  211. // Deprecated: Please use the context aware variant [InternalIPWithContext].
  212. func InternalIP() (string, error) {
  213. return defaultClient.InternalIPWithContext(context.Background())
  214. }
  215. // InternalIPWithContext returns the instance's primary internal IP address.
  216. func InternalIPWithContext(ctx context.Context) (string, error) {
  217. return defaultClient.InternalIPWithContext(ctx)
  218. }
  219. // ExternalIP returns the instance's primary external (public) IP address.
  220. //
  221. // Deprecated: Please use the context aware variant [ExternalIPWithContext].
  222. func ExternalIP() (string, error) {
  223. return defaultClient.ExternalIPWithContext(context.Background())
  224. }
  225. // ExternalIPWithContext returns the instance's primary external (public) IP address.
  226. func ExternalIPWithContext(ctx context.Context) (string, error) {
  227. return defaultClient.ExternalIPWithContext(ctx)
  228. }
  229. // Email calls Client.EmailWithContext on the default client.
  230. //
  231. // Deprecated: Please use the context aware variant [EmailWithContext].
  232. func Email(serviceAccount string) (string, error) {
  233. return defaultClient.EmailWithContext(context.Background(), serviceAccount)
  234. }
  235. // EmailWithContext calls Client.EmailWithContext on the default client.
  236. func EmailWithContext(ctx context.Context, serviceAccount string) (string, error) {
  237. return defaultClient.EmailWithContext(ctx, serviceAccount)
  238. }
  239. // Hostname returns the instance's hostname. This will be of the form
  240. // "<instanceID>.c.<projID>.internal".
  241. //
  242. // Deprecated: Please use the context aware variant [HostnameWithContext].
  243. func Hostname() (string, error) {
  244. return defaultClient.HostnameWithContext(context.Background())
  245. }
  246. // HostnameWithContext returns the instance's hostname. This will be of the form
  247. // "<instanceID>.c.<projID>.internal".
  248. func HostnameWithContext(ctx context.Context) (string, error) {
  249. return defaultClient.HostnameWithContext(ctx)
  250. }
  251. // InstanceTags returns the list of user-defined instance tags,
  252. // assigned when initially creating a GCE instance.
  253. //
  254. // Deprecated: Please use the context aware variant [InstanceTagsWithContext].
  255. func InstanceTags() ([]string, error) {
  256. return defaultClient.InstanceTagsWithContext(context.Background())
  257. }
  258. // InstanceTagsWithContext returns the list of user-defined instance tags,
  259. // assigned when initially creating a GCE instance.
  260. func InstanceTagsWithContext(ctx context.Context) ([]string, error) {
  261. return defaultClient.InstanceTagsWithContext(ctx)
  262. }
  263. // InstanceID returns the current VM's numeric instance ID.
  264. //
  265. // Deprecated: Please use the context aware variant [InstanceIDWithContext].
  266. func InstanceID() (string, error) {
  267. return defaultClient.InstanceIDWithContext(context.Background())
  268. }
  269. // InstanceIDWithContext returns the current VM's numeric instance ID.
  270. func InstanceIDWithContext(ctx context.Context) (string, error) {
  271. return defaultClient.InstanceIDWithContext(ctx)
  272. }
  273. // InstanceName returns the current VM's instance ID string.
  274. //
  275. // Deprecated: Please use the context aware variant [InstanceNameWithContext].
  276. func InstanceName() (string, error) {
  277. return defaultClient.InstanceNameWithContext(context.Background())
  278. }
  279. // InstanceNameWithContext returns the current VM's instance ID string.
  280. func InstanceNameWithContext(ctx context.Context) (string, error) {
  281. return defaultClient.InstanceNameWithContext(ctx)
  282. }
  283. // Zone returns the current VM's zone, such as "us-central1-b".
  284. //
  285. // Deprecated: Please use the context aware variant [ZoneWithContext].
  286. func Zone() (string, error) {
  287. return defaultClient.ZoneWithContext(context.Background())
  288. }
  289. // ZoneWithContext returns the current VM's zone, such as "us-central1-b".
  290. func ZoneWithContext(ctx context.Context) (string, error) {
  291. return defaultClient.ZoneWithContext(ctx)
  292. }
  293. // InstanceAttributes calls Client.InstanceAttributesWithContext on the default client.
  294. //
  295. // Deprecated: Please use the context aware variant [InstanceAttributesWithContext.
  296. func InstanceAttributes() ([]string, error) {
  297. return defaultClient.InstanceAttributesWithContext(context.Background())
  298. }
  299. // InstanceAttributesWithContext calls Client.ProjectAttributesWithContext on the default client.
  300. func InstanceAttributesWithContext(ctx context.Context) ([]string, error) {
  301. return defaultClient.InstanceAttributesWithContext(ctx)
  302. }
  303. // ProjectAttributes calls Client.ProjectAttributesWithContext on the default client.
  304. //
  305. // Deprecated: Please use the context aware variant [ProjectAttributesWithContext].
  306. func ProjectAttributes() ([]string, error) {
  307. return defaultClient.ProjectAttributesWithContext(context.Background())
  308. }
  309. // ProjectAttributesWithContext calls Client.ProjectAttributesWithContext on the default client.
  310. func ProjectAttributesWithContext(ctx context.Context) ([]string, error) {
  311. return defaultClient.ProjectAttributesWithContext(ctx)
  312. }
  313. // InstanceAttributeValue calls Client.InstanceAttributeValueWithContext on the default client.
  314. //
  315. // Deprecated: Please use the context aware variant [InstanceAttributeValueWithContext].
  316. func InstanceAttributeValue(attr string) (string, error) {
  317. return defaultClient.InstanceAttributeValueWithContext(context.Background(), attr)
  318. }
  319. // InstanceAttributeValueWithContext calls Client.InstanceAttributeValueWithContext on the default client.
  320. func InstanceAttributeValueWithContext(ctx context.Context, attr string) (string, error) {
  321. return defaultClient.InstanceAttributeValueWithContext(ctx, attr)
  322. }
  323. // ProjectAttributeValue calls Client.ProjectAttributeValueWithContext on the default client.
  324. //
  325. // Deprecated: Please use the context aware variant [ProjectAttributeValueWithContext].
  326. func ProjectAttributeValue(attr string) (string, error) {
  327. return defaultClient.ProjectAttributeValueWithContext(context.Background(), attr)
  328. }
  329. // ProjectAttributeValueWithContext calls Client.ProjectAttributeValueWithContext on the default client.
  330. func ProjectAttributeValueWithContext(ctx context.Context, attr string) (string, error) {
  331. return defaultClient.ProjectAttributeValueWithContext(ctx, attr)
  332. }
  333. // Scopes calls Client.ScopesWithContext on the default client.
  334. //
  335. // Deprecated: Please use the context aware variant [ScopesWithContext].
  336. func Scopes(serviceAccount string) ([]string, error) {
  337. return defaultClient.ScopesWithContext(context.Background(), serviceAccount)
  338. }
  339. // ScopesWithContext calls Client.ScopesWithContext on the default client.
  340. func ScopesWithContext(ctx context.Context, serviceAccount string) ([]string, error) {
  341. return defaultClient.ScopesWithContext(ctx, serviceAccount)
  342. }
  343. func strsContains(ss []string, s string) bool {
  344. for _, v := range ss {
  345. if v == s {
  346. return true
  347. }
  348. }
  349. return false
  350. }
  351. // A Client provides metadata.
  352. type Client struct {
  353. hc *http.Client
  354. }
  355. // NewClient returns a Client that can be used to fetch metadata.
  356. // Returns the client that uses the specified http.Client for HTTP requests.
  357. // If nil is specified, returns the default client.
  358. func NewClient(c *http.Client) *Client {
  359. if c == nil {
  360. return defaultClient
  361. }
  362. return &Client{hc: c}
  363. }
  364. // getETag returns a value from the metadata service as well as the associated ETag.
  365. // This func is otherwise equivalent to Get.
  366. func (c *Client) getETag(ctx context.Context, suffix string) (value, etag string, err error) {
  367. // Using a fixed IP makes it very difficult to spoof the metadata service in
  368. // a container, which is an important use-case for local testing of cloud
  369. // deployments. To enable spoofing of the metadata service, the environment
  370. // variable GCE_METADATA_HOST is first inspected to decide where metadata
  371. // requests shall go.
  372. host := os.Getenv(metadataHostEnv)
  373. if host == "" {
  374. // Using 169.254.169.254 instead of "metadata" here because Go
  375. // binaries built with the "netgo" tag and without cgo won't
  376. // know the search suffix for "metadata" is
  377. // ".google.internal", and this IP address is documented as
  378. // being stable anyway.
  379. host = metadataIP
  380. }
  381. suffix = strings.TrimLeft(suffix, "/")
  382. u := "http://" + host + "/computeMetadata/v1/" + suffix
  383. req, err := http.NewRequestWithContext(ctx, "GET", u, nil)
  384. if err != nil {
  385. return "", "", err
  386. }
  387. req.Header.Set("Metadata-Flavor", "Google")
  388. req.Header.Set("User-Agent", userAgent)
  389. var res *http.Response
  390. var reqErr error
  391. retryer := newRetryer()
  392. for {
  393. res, reqErr = c.hc.Do(req)
  394. var code int
  395. if res != nil {
  396. code = res.StatusCode
  397. }
  398. if delay, shouldRetry := retryer.Retry(code, reqErr); shouldRetry {
  399. if res != nil && res.Body != nil {
  400. res.Body.Close()
  401. }
  402. if err := sleep(ctx, delay); err != nil {
  403. return "", "", err
  404. }
  405. continue
  406. }
  407. break
  408. }
  409. if reqErr != nil {
  410. return "", "", reqErr
  411. }
  412. defer res.Body.Close()
  413. if res.StatusCode == http.StatusNotFound {
  414. return "", "", NotDefinedError(suffix)
  415. }
  416. all, err := io.ReadAll(res.Body)
  417. if err != nil {
  418. return "", "", err
  419. }
  420. if res.StatusCode != 200 {
  421. return "", "", &Error{Code: res.StatusCode, Message: string(all)}
  422. }
  423. return string(all), res.Header.Get("Etag"), nil
  424. }
  425. // Get returns a value from the metadata service.
  426. // The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/".
  427. //
  428. // If the GCE_METADATA_HOST environment variable is not defined, a default of
  429. // 169.254.169.254 will be used instead.
  430. //
  431. // If the requested metadata is not defined, the returned error will
  432. // be of type NotDefinedError.
  433. //
  434. // Deprecated: Please use the context aware variant [Client.GetWithContext].
  435. func (c *Client) Get(suffix string) (string, error) {
  436. return c.GetWithContext(context.Background(), suffix)
  437. }
  438. // GetWithContext returns a value from the metadata service.
  439. // The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/".
  440. //
  441. // If the GCE_METADATA_HOST environment variable is not defined, a default of
  442. // 169.254.169.254 will be used instead.
  443. //
  444. // If the requested metadata is not defined, the returned error will
  445. // be of type NotDefinedError.
  446. //
  447. // NOTE: Without an extra deadline in the context this call can take in the
  448. // worst case, with internal backoff retries, up to 15 seconds (e.g. when server
  449. // is responding slowly). Pass context with additional timeouts when needed.
  450. func (c *Client) GetWithContext(ctx context.Context, suffix string) (string, error) {
  451. val, _, err := c.getETag(ctx, suffix)
  452. return val, err
  453. }
  454. func (c *Client) getTrimmed(ctx context.Context, suffix string) (s string, err error) {
  455. s, err = c.GetWithContext(ctx, suffix)
  456. s = strings.TrimSpace(s)
  457. return
  458. }
  459. func (c *Client) lines(ctx context.Context, suffix string) ([]string, error) {
  460. j, err := c.GetWithContext(ctx, suffix)
  461. if err != nil {
  462. return nil, err
  463. }
  464. s := strings.Split(strings.TrimSpace(j), "\n")
  465. for i := range s {
  466. s[i] = strings.TrimSpace(s[i])
  467. }
  468. return s, nil
  469. }
  470. // ProjectID returns the current instance's project ID string.
  471. //
  472. // Deprecated: Please use the context aware variant [Client.ProjectIDWithContext].
  473. func (c *Client) ProjectID() (string, error) { return c.ProjectIDWithContext(context.Background()) }
  474. // ProjectIDWithContext returns the current instance's project ID string.
  475. func (c *Client) ProjectIDWithContext(ctx context.Context) (string, error) { return projID.get(ctx, c) }
  476. // NumericProjectID returns the current instance's numeric project ID.
  477. //
  478. // Deprecated: Please use the context aware variant [Client.NumericProjectIDWithContext].
  479. func (c *Client) NumericProjectID() (string, error) {
  480. return c.NumericProjectIDWithContext(context.Background())
  481. }
  482. // NumericProjectIDWithContext returns the current instance's numeric project ID.
  483. func (c *Client) NumericProjectIDWithContext(ctx context.Context) (string, error) {
  484. return projNum.get(ctx, c)
  485. }
  486. // InstanceID returns the current VM's numeric instance ID.
  487. //
  488. // Deprecated: Please use the context aware variant [Client.InstanceIDWithContext].
  489. func (c *Client) InstanceID() (string, error) {
  490. return c.InstanceIDWithContext(context.Background())
  491. }
  492. // InstanceIDWithContext returns the current VM's numeric instance ID.
  493. func (c *Client) InstanceIDWithContext(ctx context.Context) (string, error) {
  494. return instID.get(ctx, c)
  495. }
  496. // InternalIP returns the instance's primary internal IP address.
  497. //
  498. // Deprecated: Please use the context aware variant [Client.InternalIPWithContext].
  499. func (c *Client) InternalIP() (string, error) {
  500. return c.InternalIPWithContext(context.Background())
  501. }
  502. // InternalIPWithContext returns the instance's primary internal IP address.
  503. func (c *Client) InternalIPWithContext(ctx context.Context) (string, error) {
  504. return c.getTrimmed(ctx, "instance/network-interfaces/0/ip")
  505. }
  506. // Email returns the email address associated with the service account.
  507. //
  508. // Deprecated: Please use the context aware variant [Client.EmailWithContext].
  509. func (c *Client) Email(serviceAccount string) (string, error) {
  510. return c.EmailWithContext(context.Background(), serviceAccount)
  511. }
  512. // EmailWithContext returns the email address associated with the service account.
  513. // The serviceAccount parameter default value (empty string or "default" value)
  514. // will use the instance's main account.
  515. func (c *Client) EmailWithContext(ctx context.Context, serviceAccount string) (string, error) {
  516. if serviceAccount == "" {
  517. serviceAccount = "default"
  518. }
  519. return c.getTrimmed(ctx, "instance/service-accounts/"+serviceAccount+"/email")
  520. }
  521. // ExternalIP returns the instance's primary external (public) IP address.
  522. //
  523. // Deprecated: Please use the context aware variant [Client.ExternalIPWithContext].
  524. func (c *Client) ExternalIP() (string, error) {
  525. return c.ExternalIPWithContext(context.Background())
  526. }
  527. // ExternalIPWithContext returns the instance's primary external (public) IP address.
  528. func (c *Client) ExternalIPWithContext(ctx context.Context) (string, error) {
  529. return c.getTrimmed(ctx, "instance/network-interfaces/0/access-configs/0/external-ip")
  530. }
  531. // Hostname returns the instance's hostname. This will be of the form
  532. // "<instanceID>.c.<projID>.internal".
  533. //
  534. // Deprecated: Please use the context aware variant [Client.HostnameWithContext].
  535. func (c *Client) Hostname() (string, error) {
  536. return c.HostnameWithContext(context.Background())
  537. }
  538. // HostnameWithContext returns the instance's hostname. This will be of the form
  539. // "<instanceID>.c.<projID>.internal".
  540. func (c *Client) HostnameWithContext(ctx context.Context) (string, error) {
  541. return c.getTrimmed(ctx, "instance/hostname")
  542. }
  543. // InstanceTags returns the list of user-defined instance tags.
  544. //
  545. // Deprecated: Please use the context aware variant [Client.InstanceTagsWithContext].
  546. func (c *Client) InstanceTags() ([]string, error) {
  547. return c.InstanceTagsWithContext(context.Background())
  548. }
  549. // InstanceTagsWithContext returns the list of user-defined instance tags,
  550. // assigned when initially creating a GCE instance.
  551. func (c *Client) InstanceTagsWithContext(ctx context.Context) ([]string, error) {
  552. var s []string
  553. j, err := c.GetWithContext(ctx, "instance/tags")
  554. if err != nil {
  555. return nil, err
  556. }
  557. if err := json.NewDecoder(strings.NewReader(j)).Decode(&s); err != nil {
  558. return nil, err
  559. }
  560. return s, nil
  561. }
  562. // InstanceName returns the current VM's instance ID string.
  563. //
  564. // Deprecated: Please use the context aware variant [Client.InstanceNameWithContext].
  565. func (c *Client) InstanceName() (string, error) {
  566. return c.InstanceNameWithContext(context.Background())
  567. }
  568. // InstanceNameWithContext returns the current VM's instance ID string.
  569. func (c *Client) InstanceNameWithContext(ctx context.Context) (string, error) {
  570. return c.getTrimmed(ctx, "instance/name")
  571. }
  572. // Zone returns the current VM's zone, such as "us-central1-b".
  573. //
  574. // Deprecated: Please use the context aware variant [Client.ZoneWithContext].
  575. func (c *Client) Zone() (string, error) {
  576. return c.ZoneWithContext(context.Background())
  577. }
  578. // ZoneWithContext returns the current VM's zone, such as "us-central1-b".
  579. func (c *Client) ZoneWithContext(ctx context.Context) (string, error) {
  580. zone, err := c.getTrimmed(ctx, "instance/zone")
  581. // zone is of the form "projects/<projNum>/zones/<zoneName>".
  582. if err != nil {
  583. return "", err
  584. }
  585. return zone[strings.LastIndex(zone, "/")+1:], nil
  586. }
  587. // InstanceAttributes returns the list of user-defined attributes,
  588. // assigned when initially creating a GCE VM instance. The value of an
  589. // attribute can be obtained with InstanceAttributeValue.
  590. //
  591. // Deprecated: Please use the context aware variant [Client.InstanceAttributesWithContext].
  592. func (c *Client) InstanceAttributes() ([]string, error) {
  593. return c.InstanceAttributesWithContext(context.Background())
  594. }
  595. // InstanceAttributesWithContext returns the list of user-defined attributes,
  596. // assigned when initially creating a GCE VM instance. The value of an
  597. // attribute can be obtained with InstanceAttributeValue.
  598. func (c *Client) InstanceAttributesWithContext(ctx context.Context) ([]string, error) {
  599. return c.lines(ctx, "instance/attributes/")
  600. }
  601. // ProjectAttributes returns the list of user-defined attributes
  602. // applying to the project as a whole, not just this VM. The value of
  603. // an attribute can be obtained with ProjectAttributeValue.
  604. //
  605. // Deprecated: Please use the context aware variant [Client.ProjectAttributesWithContext].
  606. func (c *Client) ProjectAttributes() ([]string, error) {
  607. return c.ProjectAttributesWithContext(context.Background())
  608. }
  609. // ProjectAttributesWithContext returns the list of user-defined attributes
  610. // applying to the project as a whole, not just this VM. The value of
  611. // an attribute can be obtained with ProjectAttributeValue.
  612. func (c *Client) ProjectAttributesWithContext(ctx context.Context) ([]string, error) {
  613. return c.lines(ctx, "project/attributes/")
  614. }
  615. // InstanceAttributeValue returns the value of the provided VM
  616. // instance attribute.
  617. //
  618. // If the requested attribute is not defined, the returned error will
  619. // be of type NotDefinedError.
  620. //
  621. // InstanceAttributeValue may return ("", nil) if the attribute was
  622. // defined to be the empty string.
  623. //
  624. // Deprecated: Please use the context aware variant [Client.InstanceAttributeValueWithContext].
  625. func (c *Client) InstanceAttributeValue(attr string) (string, error) {
  626. return c.InstanceAttributeValueWithContext(context.Background(), attr)
  627. }
  628. // InstanceAttributeValueWithContext returns the value of the provided VM
  629. // instance attribute.
  630. //
  631. // If the requested attribute is not defined, the returned error will
  632. // be of type NotDefinedError.
  633. //
  634. // InstanceAttributeValue may return ("", nil) if the attribute was
  635. // defined to be the empty string.
  636. func (c *Client) InstanceAttributeValueWithContext(ctx context.Context, attr string) (string, error) {
  637. return c.GetWithContext(ctx, "instance/attributes/"+attr)
  638. }
  639. // ProjectAttributeValue returns the value of the provided
  640. // project attribute.
  641. //
  642. // If the requested attribute is not defined, the returned error will
  643. // be of type NotDefinedError.
  644. //
  645. // ProjectAttributeValue may return ("", nil) if the attribute was
  646. // defined to be the empty string.
  647. //
  648. // Deprecated: Please use the context aware variant [Client.ProjectAttributeValueWithContext].
  649. func (c *Client) ProjectAttributeValue(attr string) (string, error) {
  650. return c.ProjectAttributeValueWithContext(context.Background(), attr)
  651. }
  652. // ProjectAttributeValueWithContext returns the value of the provided
  653. // project attribute.
  654. //
  655. // If the requested attribute is not defined, the returned error will
  656. // be of type NotDefinedError.
  657. //
  658. // ProjectAttributeValue may return ("", nil) if the attribute was
  659. // defined to be the empty string.
  660. func (c *Client) ProjectAttributeValueWithContext(ctx context.Context, attr string) (string, error) {
  661. return c.GetWithContext(ctx, "project/attributes/"+attr)
  662. }
  663. // Scopes returns the service account scopes for the given account.
  664. // The account may be empty or the string "default" to use the instance's
  665. // main account.
  666. //
  667. // Deprecated: Please use the context aware variant [Client.ScopesWithContext].
  668. func (c *Client) Scopes(serviceAccount string) ([]string, error) {
  669. return c.ScopesWithContext(context.Background(), serviceAccount)
  670. }
  671. // ScopesWithContext returns the service account scopes for the given account.
  672. // The account may be empty or the string "default" to use the instance's
  673. // main account.
  674. func (c *Client) ScopesWithContext(ctx context.Context, serviceAccount string) ([]string, error) {
  675. if serviceAccount == "" {
  676. serviceAccount = "default"
  677. }
  678. return c.lines(ctx, "instance/service-accounts/"+serviceAccount+"/scopes")
  679. }
  680. // Subscribe subscribes to a value from the metadata service.
  681. // The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/".
  682. // The suffix may contain query parameters.
  683. //
  684. // Deprecated: Please use the context aware variant [Client.SubscribeWithContext].
  685. func (c *Client) Subscribe(suffix string, fn func(v string, ok bool) error) error {
  686. return c.SubscribeWithContext(context.Background(), suffix, func(ctx context.Context, v string, ok bool) error { return fn(v, ok) })
  687. }
  688. // SubscribeWithContext subscribes to a value from the metadata service.
  689. // The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/".
  690. // The suffix may contain query parameters.
  691. //
  692. // SubscribeWithContext calls fn with the latest metadata value indicated by the
  693. // provided suffix. If the metadata value is deleted, fn is called with the
  694. // empty string and ok false. Subscribe blocks until fn returns a non-nil error
  695. // or the value is deleted. Subscribe returns the error value returned from the
  696. // last call to fn, which may be nil when ok == false.
  697. func (c *Client) SubscribeWithContext(ctx context.Context, suffix string, fn func(ctx context.Context, v string, ok bool) error) error {
  698. const failedSubscribeSleep = time.Second * 5
  699. // First check to see if the metadata value exists at all.
  700. val, lastETag, err := c.getETag(ctx, suffix)
  701. if err != nil {
  702. return err
  703. }
  704. if err := fn(ctx, val, true); err != nil {
  705. return err
  706. }
  707. ok := true
  708. if strings.ContainsRune(suffix, '?') {
  709. suffix += "&wait_for_change=true&last_etag="
  710. } else {
  711. suffix += "?wait_for_change=true&last_etag="
  712. }
  713. for {
  714. val, etag, err := c.getETag(ctx, suffix+url.QueryEscape(lastETag))
  715. if err != nil {
  716. if _, deleted := err.(NotDefinedError); !deleted {
  717. time.Sleep(failedSubscribeSleep)
  718. continue // Retry on other errors.
  719. }
  720. ok = false
  721. }
  722. lastETag = etag
  723. if err := fn(ctx, val, ok); err != nil || !ok {
  724. return err
  725. }
  726. }
  727. }
  728. // Error contains an error response from the server.
  729. type Error struct {
  730. // Code is the HTTP response status code.
  731. Code int
  732. // Message is the server response message.
  733. Message string
  734. }
  735. func (e *Error) Error() string {
  736. return fmt.Sprintf("compute: Received %d `%s`", e.Code, e.Message)
  737. }