Google Compute Engine

Storing and Retrieving Metadata

Every instance has metadata associated with it. Some of this metadata can be defined by the user, and other information, such as the host name, is assigned by Google Compute Engine during the startup process.

Compute Engine might offer more than one metadata version at a single time, but it is recommended that you always use the newest metadata server version available. At any time, Google Compute Engine may add new entries to the metadata server and add new fields to responses. Check back periodically for changes!

Current version: v1

Contents

Metadata server

Every instance stores its metadata on the metadata server. You can query this metadata server programmatically for information such as the instance's host name, instance ID, startup scripts, and custom metadata. It also provides access to service account information. Your instance automatically has access to the metadata server API without any additional authorization.

Metadata is stored in the format key:value. There is a default set of metadata entries that every instance has access to and you can also choose to create custom metadata. To query for certain metadata, you can construct a request to the metadata server using the URL or the IP address.

  • Full URL: http://metadata.google.internal/computeMetadata/v1/
  • Shorthand URL: http://metadata/computeMetadata/v1/
  • IP address: http://169.254.169.254/computeMetadata/v1/

For more information, see Querying Metadata.

Default metadata

Google Compute Engine defines a set of default metadata entries that provide information about your instance or project. Default metadata is always defined and set by the server. You cannot manually edit any of these metadata pairs.

The following is a list of default metadata available to a project. Some metadata entries are directories that contain other metadata keys. This difference is marked by a trailing slash in the metadata name. For example, attributes/ is a directory that contains other keys, while numeric-project-id is a metadata key or endpoint that maps to a value.

Note: This document uses "metadata keys" and "metadata endpoints" interchangeably; both phrases refer to a metadata key that directly maps to one or more values.

Relative to http://metadata.google.internal/computeMetadata/v1/project/
Metadata Entry Description
attributes/ A directory of custom metadata values passed to the project.
attributes/sshKeys A list of ssh keys that can be used to connect to instances in the project.
numeric-project-id The numeric project ID of the instance, which is not the same as the project name visible in the Google Developers Console. Do not use this with the --project flag for any gcutil calls; instead use the project-id property value.
project-id The project ID.

The following is a list of default metadata available to an instance:

Relative to http://metadata.google.internal/computeMetadata/v1/instance/
Metadata Entry Description
attributes/ A directory of custom metadata values passed to the instance during startup. See Specifying Custom Metadata below.
description The free-text description of an instance, assigned using the --description flag, or set in the API.
disks/ A directory of disks attached to this instance.
hostname The host name of the instance.
id The ID of the instance. This is a unique, numerical ID that is generated by Google Compute Engine. This is useful for identifying instances if you do not want to use instance names.
image The fully-qualified image name.
machine-type The fully-qualified machine type name of the instance's host machine.
network-interfaces/ A directory of network interfaces for the instance.
network-interfaces/<index>/forwarded-ips/ A directory of any external IPs that are currently pointing to this virtual machine instance, for the network interface at <index>. Specifically, provides a list of external IPs served by forwarding rules that direct packets to this instance.
scheduling/ A directory with the scheduling options for the instance.
scheduling/on-host-maintenance The instance's scheduled maintenance event behavior setting. This value is set with the ‑‑on_host_maintenance flag or via the API.
scheduling/automatic-restart The instance's automatic restart setting. This value is set with the ‑‑automatic_restart flag or via the API.
maintenance-event The path that indicates that a scheduled maintenance event is affecting this instance. See Scheduled maintenance notice for details.
project-id The instance's project ID. You can use this ID in the --project flag for any gcutil calls.
service-accounts/ A directory of service accounts associated with the instance.
tags Any tags associated with the instance.
zone The instance's zone.

Querying metadata

You can query a metadata server only from its associated instance. You cannot query an instance's metadata from another instance or directly from your local computer. For example, you would send a curl or wget command from the instance to its metadata server.

You can query the metadata server using the root metadata server URL or the IP address. All of these URLs will work for your metadata requests.

  • Full URL: http://metadata.google.internal/computeMetadata/v1/
  • Shorthand URL: http://metadata/computeMetadata/v1/
  • IP address: http://169.254.169.254/computeMetadata/v1/

These are the root URLs for all instance and project metadata. Specific metadata values are defined as sub-paths below these root URLs.

When you query the metadata server, you must also provide the following header in all of your requests:

Metadata-Flavor: Google

This header indicates that the request was sent with the intention of retrieving metadata values, rather than unintentionally from an insecure source, and allows the metadata server to return the data you requested. If you do not provide this header, the metadata server denies your request.

Note: Previously, the X-Google-Metadata-Request: True header was required in requests. Both of these headers are still supported but it is recommended that you use the Metadata-Flavor header rather than the X-Google-Metadata-Request: True header.

Depending on the type of query you make, the metadata server can return data in a number of ways.

Querying directory listings

The metadata server uses directories to organize certain metadata keys. Any metadata entry ending in a trailing slash is a directory. For example, the disks/ entry is a directory of disks attached to that instance:

user@myinst:~$ curl "http://metadata.google.internal/computeMetadata/v1/instance/disks/" -H "Metadata-Flavor: Google"
0/
1/
2/

Similarly, if you wanted more information about the 1/ directory, you can query the specific URL for that directory:

user@myinst:~$ curl "http://metadata.google.internal/computeMetadata/v1/instance/disks/1/" -H "Metadata-Flavor: Google"
device-name
index
mode
type

Querying metadata endpoints

Other metadata entries are keys or endpoints that return one or more values. To query for data from a metadata endpoint, send a query to that particular endpoint. For example, to query the mode of a specific disk, query the following endpoint:

user@myinst:~$ curl "http://metadata.google.internal/computeMetadata/v1/instance/disks/1/mode" -H "Metadata-Flavor: Google"
READ_WRITE

By default, each endpoint defines the format for returned data. Some endpoints may return data in JSON format by default, while other endpoints may return data as a string. You can override the default data format specification by using the alt=json or alt=text query parameters, which returns data in JSON string format or as a plaintext representation, respectfully.

For example, the tags key automatically returns data in JSON format. You can choose to return data in text format instead, by specifying the alt=text query parameter:

user@myinst:~$ curl "http://metadata.google.internal/computeMetadata/v1/instance/tags" -H "Metadata-Flavor: Google"
["bread","butter","cheese","cream","lettuce"]

user@myinst:~$ curl "http://metadata.google.internal/computeMetadata/v1/instance/tags?alt=text" -H "Metadata-Flavor: Google"
bread
butter
cheese
cream
lettuce

Querying recursive contents

If you want to return all contents underneath a directory, use the recursive=true query parameter with your request:

user@myinst:~$ curl "http://metadata.google.internal/computeMetadata/v1/instance/disks/?recursive=true" -H "Metadata-Flavor: Google"
[{"deviceName":"boot","index":0,"mode":"READ_WRITE","type":"PERSISTENT"},
{"deviceName":"persistent-disk-1","index":1,"mode":"READ_WRITE","type":"PERSISTENT"},
{"deviceName":"persistent-disk-2","index":2,"mode":"READ_ONLY","type":"PERSISTENT"}]

By default, recursive contents are returned in JSON format. If you want to return these contents in text format, append the alt=text query parameter:

user@myinst:~$ curl "http://metadata.google.internal/computeMetadata/v1/instance/disks/?recursive=true&alt=text" -H "Metadata-Flavor: Google"
0/device-name boot
0/index 0
0/mode READ_WRITE
0/type PERSISTENT
1/device-name persistent-disk-1
1/index 1
1/mode READ_WRITE
1/type PERSISTENT
2/device-name persistent-disk-1
2/index 2
2/mode READ_ONLY
2/type PERSISTENT

Detecting if you are running in Compute Engine

You can easily detect if your applications or scripts are running within a Compute Engine instance by using the metadata server. When you make a request to the server, any response from the metadata server will contain the Metadata-Flavor: Google header. You can look for this header to reliably detect if you are running in Compute Engine.

For example, the following curl request returns a Metadata-Flavor: Google header, indicating that the request is being made from within a Compute Engine instance.

me@my-inst:~$ curl metadata.google.internal -i
HTTP/1.1 200 OK
Metadata-Flavor: Google
Content-Type: application/text
Date: Thu, 10 Apr 2014 19:24:27 GMT
Server: Metadata Server for VM
Content-Length: 22
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN

0.1/
computeMetadata/

Specifying custom metadata

You can set custom metadata for an instance or project outside of the server-defined metadata. This is useful for passing in arbitrary values to your project or instance that can be queried by your code on the instance.

When you specify custom metadata, the metadata server stores it in the attributes/ directory for that instance or project. To query for all the custom metadata available to an instance or project, query the attributes/ directory:

curl "http://metadata.google.internal/computeMetadata/v1/<instance|project>/attributes/" -H "Metadata-Flavor: Google"

Note: Google Compute Engine limits the length of your custom metadata value to 32768 bytes. If your metadata exceeds this limit, you won't be able to specify it on the command line. Instead, you create startup scripts, store them on Google Cloud Storage, and run the scripts during instance creation time. See startup scripts for more information.

Setting custom instance metadata

You can set custom metadata for an instance either using the --metadata flag during instance creation, or by using the gcutil setinstancemetadata method on a running instance.

Setting Metadata during Instance Creation

To pass in custom metadata during instance creation, provide the --metadata flag with your request. You can provide this flag as many times as you would like, and pass in multiple metadata pairs. The following example demonstrates starting a new instance with the key "bread" and the value "butter", and querying it from the instance.

$ gcutil --project=myproject addinstance myinstance --metadata=bread:butter
... select a zone, machine type, and image...
INFO: Waiting for insert of myinstance. Sleeping for 3s.
INFO: Waiting for insert of myinstance. Sleeping for 3s.
...
$ gcutil --project=myproject ssh myinstance
...omit ssh startup info...
user@myinstance:~$ curl "http://metadata.google.internal/computeMetadata/v1/instance/attributes/bread" -H "Metadata-Flavor: Google"
butter

Updating Or Setting Metadata on a Running Instance

If you want to set or update the metadata entries for a running instance, you can use the gcutil setinstancemetadata command:

gcutil --project=<project-id> setinstancemetadata <instance-name> --metadata=<key-1:value-1> --metadata=<key-2:value-2> --metadata=<key-n:value-n> --fingerprint=<current-fingerprint-hash> 

Important Flags and Parameters:

--project=<project-id>
[Required] The project ID of the instance.
<instance-name>
[Required] The instance name for which you want to update metadata.
--metadata=<key-n:value-n>
[Required] Metadata data entries to update. All metadata updates are done in a batch request. This means that you must set all metadata entries in every update request, even if you are just updating one or two entries. For example, assume your instance metadata looks like this:
| metadata               |                |
| fingerprint            | K5IUL75tSYQ=   |
|   bread                | mayo           |
|   cheese               | cheddar        |
|   lettuce              | butter         |

If you want to remove the lettuce:butter entry, you need to update the entire list, omitting the entry you want to delete:

gcutil --project=myproject setinstancemetadata ... --metadata=bread:mayo --metadata=cheese:chedder

--fingerprint=<current-fingerprint-hash>
[Required] The current fingerprint hash of the metadata list. You can grab the fingerprint hash by performing a gcutil getinstance <instance-name> command, and copying the value of the metadata fingerprint field. The fingerprint you supply must match the current fingerprint on the instance. This performs optimistic locking, so that only one user may update the metadata list at any one time.

For example:

$ gcutil --project=myproject getinstance myinstance
+------------------------+--------------------------------------------------------------------------------------------+
|        property        |                                       value                                                |
+------------------------+--------------------------------------------------------------------------------------------+
| name                   | myinstance                                                                                 |
| description            |                                                                                            |
| creation-time          | 2013-01-18T11:15:54.054-08:00                                                              |
| machine                | n1-standard-1                                                                              |
| image                  | projects/debian-cloud/global/images/debian-7-wheezy-vYYYYMMDD                              |
| zone                   | <zone>                                                                                     |
| tags-fingerprint       | kFyURcqFcPg=                                                                               |
| metadata-fingerprint   | 42WmSpB8rSM=                                                                               |
| status                 | RUNNING                                                                                    |
| status-message         |                                                                                            |
|                        |                                                                                            |
| disk                   | 0                                                                                          |
|   type                 | PERSISTENT                                                                                 |
|   mode                 | READ_WRITE                                                                                 |
|   deviceName           | pd1                                                                                        |
|   source               | http://www.googleapis.com/compute/v1/projects/<project-id>/zones/<zone>/disks/<disk> |
|                        |                                                                                            |
| network-interface      |                                                                                            |
|   network              | default                                                                                    |
|   ip                   | 00.000.000.000                                                                             |
|   access-configuration | External NAT                                                                               |
|     type               | ONE_TO_ONE_NAT                                                                             |
|     external-ip        | 000.000.00.000                                                                             |
|                        |                                                                                            |
| metadata               |                                                                                            |
| fingerprint            | 42WmSpB8rSM=                                                                               |
|   foo                  | bar                                                                                        |
|   baz                  | bat                                                                                        |
|   fe                   | fi                                                                                         |
|   fo                   | fum                                                                                        |
| tags                   |                                                                                            |
| fingerprint            | kFyURcqFcPg=                                                                               |
|                        | cheese                                                                                     |
|                        | mustard                                                                                    |
|                        | romaine                                                                                    |
+------------------------+--------------------------------------------------------------------------------------------+

$ gcutil --project=myproject setinstancemetadata --metadata=foo:bar --metadata=baz:bat --fingerprint=42WmSpB8rSM= myinstance
INFO: Waiting for setMetadata of instance myinstance. Sleeping for 3s
....

$ gcutil --project=myproject getinstance myinstance
+------------------------+--------------------------------------------------------------------------------------------+
|        property        |                                       value                                                |
+------------------------+--------------------------------------------------------------------------------------------+
| name                   | myinstance                                                                                 |
| description            |                                                                                            |
| creation-time          | 2013-01-18T11:15:54.054-08:00                                                              |
| machine                | n1-standard-1                                                                              |
| image                  | projects/debian-cloud/global/images/debian-7-wheezy-vYYYYMMDD                              |
| zone                   | <zone>                                                                                     |
| tags-fingerprint       | wkFyURcqFcPg=                                                                              |
| metadata-fingerprint   | 76YdAlA9rSL=                                                                               |
| status                 | RUNNING                                                                                    |
| status-message         |                                                                                            |
|                        |                                                                                            |
| disk                   | 0                                                                                          |
|   type                 | PERSISTENT                                                                                 |
|   mode                 | READ_WRITE                                                                                 |
|   deviceName           | pd1                                                                                        |
|   source               | http://www.googleapis.com/compute/v1/projects/<project-id>/zones/<zone>/disks/<disk> |
|                        |                                                                                            |
| network-interface      |                                                                                            |
|   network              | default                                                                                    |
|   ip                   | 00.000.000.000                                                                             |
|   access-configuration | External NAT                                                                               |
|     type               | ONE_TO_ONE_NAT                                                                             |
|     external-ip        | 000.000.00.000                                                                             |
|                        |                                                                                            |
| metadata               |                                                                                            |
| fingerprint            | 76YdAlA9rSL=                                                                               |
|   foo                  | bar                                                                                        |
|   baz                  | bat                                                                                        |
| tags                   |                                                                                            |
| fingerprint            | kFyURcqFcPg=                                                                               |
|                        | cheese                                                                                     |
|                        | mustard                                                                                    |
|                        | romaine                                                                                    |
+------------------------+--------------------------------------------------------------------------------------------+

Applying a Startup Script using Custom Metadata

The custom metadata option is especially useful for specifying startup scripts that run during instance boot. Startup scripts can be used to install software, check and start services, or set custom environment variables. Using gcutil, you can pass in startup scripts directly using the --metadata flag or from a local file using the --metadata_from_file flag. For example:

  • Passing in a startup script from a local file:
    gcutil addinstance test-instance --metadata_from_file=startup-script:<file> --project=<project-id>
  • Passing in a startup script from Google Cloud Storage:
    gcutil addinstance test-instance --metadata=startup-script-url:<url> --project=<project-id>
  • Passing in your startup script directly:
    gcutil addinstance test-instance --metadata=startup-script:"#! /bin/bash
    > # Installs apache and a custom homepage
    > apt-get update
    > apt-get install -y apache2
    > cat <<EOF > /var/www/index.html
    > <html><body><h1>Hello World</h1>
    > <p>This page was created from a simple start up script!</p>
    > </body></html>
    > EOF"

For more information about startup scripts and how to use them, see Using Startup Scripts.

Setting project-wide custom metadata

If you want to set project-level custom metadata, which is accessible by all instances in that project, you can do so using the setcommoninstancemetadata command. For example, if you define a project-wide metadata pair of baz:bat, the metadata pair is automatically available to all instances at the project/attributes/ directory:

http://metadata.google.internal/computeMetadata/v1/project/attributes/

To set project-wide metadata using the gcutil command tool, use the gcutil setcommoninstancemetadata command. For example:

$ gcutil --project=myproject setcommoninstancemetadata --metadata foo:bar --metadata baz:bat [-f]
$ gcutil --project=myproject getproject
+--------------------------+---------------------------------------+
| name                     | myproject                             |
| description              |                                       |
| creation-time            | 2012-01-11T17:45:37.812-08:00         |
| usage                    |                                       |
|   snapshots              | 1.0/1000.0                            |
|   networks               | 4.0/5.0                               |
|   firewalls              | 4.0/100.0                             |
|   images                 | 3.0/100.0                             |
|   routes                 | 8.0/100.0                             |
|   forwarding-rules       | 1.0/50.0                              |
|   target-pools           | 2.0/50.0                              |
|   health-checks          | 2.0/50.0                              |
| common-instance-metadata |                                       |
|   foo                    | bar                                   |
|   baz                    | bat                                   |
+--------------------------+---------------------------------------+

Important Flags and Parameters:

--project=<project-id>
[Required] This flag is required for every gcutil command except help, unless you have previously specified the --cache_flag_values flag to store your project ID information.
--metadata
[Optional] Specifies a single entry specified as a colon-separated key value pair. This flag can be specified multiple times on the command line.
--metadata_from_file
[Optional] Specifies a single entry specified as a key and a file from which to read the key. The two parts are separated by a colon. This flag can be specified multiple times on the command line.
-f
[Optional] Specifies that the update should be forced even if it will remove existing metadata entries. Since project-wide metadata is updated in a single batch operation, this flag is required if any of the existing metadata keys are not specified in the command. This helps prevent deleting metadata accidentally.

Updating Project-Wide Metadata

Similar to instance metadata, project metadata updates are done in batch requests. This means that you must set all metadata entries in every update request, even if you are just updating one or two entries. For example, lets assume you have the following metadata entries:

+-----------------------------------------+---------------------------------+
| common-instance-metadata                |                                 |
|   baz                                   | bat                             |
|   foo                                   | bar                             |
|   try                                   | eat                             |
|   car                                   | saw                             |
+-----------------------------------------+---------------------------------+

If you wanted to update the metadata value for baz and foo, you must also set the values of try and car, even if their values are the same. If you don't explicitly set every metadata value, gcutil safely blocks the operation, unless you provide the -f flag. With the -f flag, gcutil removes existing metadata entries that aren't set in your request. To update baz and foo, you would need to do the following:

$ gcutil setcommoninstancemetadata --metadata baz:new --metadata foo:new --metadata try:eat metadata car:saw --project=my-project

If you're sure you want to erase the metadata entries that aren't explicitly set in your update request, rerun your command with the -f flag.

If you're updating metadata that may be several strings long, you may want to use the --metadata_from_file flag, which reads in the contents of a file as the key value:

gcutil setcommoninstancemetadata --metadata_from_file=<key>:<file> --project=my-project

This is especially useful for setting metadata attributes like sshKeys, which is usually a random combination of several strings. Rather than providing the raw string value, you could just save the string in the file and provide the file with the --metadata_from_file flag.

Note: Setting and updating project metadata is slightly different than setting instance metadata because you're not required to provide a fingerprint hash with your request. However, you must explicitly define every metadata entry or provide the -f flag in your request to erase metadata entries you didn't redefine.

Waiting for change

Given that metadata values can change while your instance is running, the metadata server offers the ability to be notified of metadata changes using the wait-for-change feature. This feature allows you to perform hanging GET requests that only returns when your specified metadata has changed. You can use this feature on custom metadata or server-defined metadata, so if anything changes about your instance or project, or if someone updates a custom metadata, you can programmatically react to the change. For example, you can perform a request on the tags key so that the request only returns if the contents of the tags metadata has changed. When the request returns, it provides the new value of that metadata key.

Note: You can only perform a wait-for-change request on a metadata endpoint or recursively on the contents of a directory. It is not possible to perform a wait-for-change request on a directory listing and the metadata server fails your request if you try to do so.

It is also not possible to perform a wait-for-change request for a service account token. If you try to make a wait-for-change request to the service account token URL, the request fails immediately.

In both these cases, Google Compute Engine returns a 400 Invalid Request error.

To perform a wait-for-change request, query a metadata key and append the ?wait_for_change=true query parameter:

user$myinst:~$ curl "http://metadata.google.internal/computeMetadata/v1/instance/tags?wait_for_change=true" -H "Metadata-Flavor: Google"

Once there is a change to the specified metadata key, the query returns with the new value. In this example, if a request is made to the setInstanceTags method, the request returns with the new values:

user@myinst:~$ curl "http://metadata.google.internal/computeMetadata/v1/instance/tags?wait_for_change=true" -H "Metadata-Flavor: Google"
cheese
lettuce

You can also perform a wait-for-change request recursively on the contents of a directory:

user$myinst:~$ curl "http://metadata.google.internal/computeMetadata/v1/instance/attributes/?recursive=true&wait_for_change=true" -H "Metadata-Flavor: Google"

The metadata server returns the new contents if there is any change:

user@myinst:~$ curl "http://metadata.google.internal/computeMetadata/v1/instance/attributes/?recursive=true&wait_for_change=true" -H "Metadata-Flavor: Google"
{"cheese":"lettuce","cookies":"cream"}

The wait-for-change feature also lets you match ETags with your request and set timeouts.

Using ETags

If you submit a simple wait-for-change query, the metadata server returns if anything has changed in the contents of that metadata. However, there is an inherent race condition between a metadata update and a wait-for-change request being issued, so it is useful to have a reliable way to know you are getting the latest metadata value. To help with this, you can use the last_etag query parameter, which compares the ETag value you provide with the ETag value saved on the metadata server. If the ETag values match, then the wait-for-change request will be accepted. If the ETag values do not match, this indicates that the contents of the metadata has changed since the last time you retrieved the ETag value, and the metadata server returns immediately with this latest value.

To grab the current ETag value for a metadata key, make a request to that key and print the headers. In CURL, you can do this with the -v flag:

user@myinst:~$ curl -v "http://metadata.google.internal/computeMetadata/v1/instance/tags" -H "Metadata-Flavor: Google"
* About to connect() to metadata port 80 (#0)
*   Trying 169.254.169.254... connected
* Connected to metadata (169.254.169.254) port 80 (#0)
> GET /computeMetadata/v1/instance/tags?wait_for_change=true HTTP/1.1
> User-Agent: curl/7.19.7 (x86_64-pc-linux-gnu) libcurl/7.19.7 OpenSSL/0.9.8k zlib/1.2.3.3 libidn/1.15
> Host: metadata
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: application/text
< ETag: 411261ca6c9e654e
< Date: Wed, 13 Feb 2013 22:43:45 GMT
< Server: Metadata Server for VM
< Content-Length: 26
< X-XSS-Protection: 1; mode=block
< X-Frame-Options: SAMEORIGIN
<
cheese
lettuce

You can also grab the ETag programmatically. The following example uses Python to extract the ETag value from the metadata response:

import httplib2

def main():
  http = httplib2.Http()
  response, content = http.request('http://metadata.google.internal/computeMetadata/v1/instance/tags', headers={'Metadata-Flavor': 'True'})
  etag = response['etag']

  print etag

if __name__ == '__main__':
  main()

Use that ETag value in your wait-for-change request:

user@myinst:~$ curl "http://metadata.google.internal/computeMetadata/v1/instance/tags?wait_for_change=true&last_etag=411261ca6c9e654e" -H "Metadata-Flavor: Google"

The metadata server will match your specified ETag value and if that value changes, the request returns with the new contents of your metadata key.

Using 0 As Your ETag Value

The metadata server will never return 0 as an ETag. You could use that information to simplify some of your code. For example, the following code example sets the initial ETag value as 0, performs a request to the server, which immediately returns with the initial data and the current ETag value, and then uses that information to wait for a change. This method would save you from writing additional lines of code to grab the first initial ETag.

import httplib2

METADATA_URL = 'http://metadata.google.internal/computeMetadata/v1/'

def main():
  http = httplib2.Http()
  tagsUrl = METADATA_URL + 'instance/tags?wait_for_change=true'

  # set the first last_etag as 0
  last_etag = 0
  while True:
    # returns immediately on the initial request because 0 is invalid
    # otherwise wait until something changes
    resp,content = http.request(uri=tagsUrl + '&last_etag=' + str(last_etag), method='GET', body='', headers={'Metadata-Flavor': 'True'})

    if resp != 500:
      last_etag = resp['etag']
      print content

if __name__ == '__main__':
  main()

Setting timeouts

If you would like your wait-for-change request to time out after a certain number of seconds, you can set the timeout_sec=<timeout-in-seconds> query parameter. The timeout_sec parameter limits the wait time of your request to the number of seconds you specified and once the request reaches that limit, it returns the current contents of the metadata key. Here is an example of a wait-for-change request that is set to time out after 360 seconds:

user@myinst:~$ curl "http://metadata.google.internal/computeMetadata/v1/instance/tags?wait_for_change=true&timeout_sec=360" -H "Metadata-Flavor: Google"

When you set the timeout_sec parameter, the request always returns after the specified number of seconds, whether or not the metadata value has actually changed. It is only possible to set an integer value for your timeout.

Status codes

When you perform a wait-for-change request, the metadata server returns standard HTTP status codes to indicate success or failures. In the case of errors, network conditions may cause the metadata server to fail your request and return an error code. In these cases, you should design your application to be fault-tolerant and to be able recognize and handle these errors.

The possible states that the metadata server returns are:

Status Description
HTTP 200 Success! A value was changed, or you reached your specified timeout_sec and the request returned successfully.
Error 400 Your request was invalid. Please fix your query and retry the request.
Error 404 The metadata value you specified no longer exists. This error also returns if your metadata is deleted while you are waiting on a change.
Error 500 There was a temporary server error. Please retry your request.

Scheduled maintenance notice

The metadata server provides information about an instance's scheduling options and settings, through the scheduling/ directory and the maintenance-event attribute. You can use these attributes to learn about a virtual machine instance's scheduling options, and also use this information to notify you when a maintenance event is about to happen, specifically through the maintenance-event attribute.

The maintenance-event attribute changes its value to indicate the start and end of a maintenance event. The initial value of the attribute is NONE, which indicates that no maintenance event is starting. 60 seconds before a scheduled maintenance event, the maintenance-event value changes from NONE to MIGRATE_ON_HOST_MAINTENANCE. Throughout the duration of the maintenance event, the value remains the same. Once the maintenance event ends, the value returns to NONE.

Caution: To receive notification of maintenance events through the metadata server, your instance's scheduling option must be set to migrate. The maintenance-event attribute will only update for virtual machine instances set to the migrate option. Virtual machine instances that are set to terminate will experience a power button push and won't be notified of maintenance events through this attribute.

To query the maintenance-event attribute, make a request like so:

user@myinst:~$ curl http://metadata.google.internal/computeMetadata/v1/instance/maintenance-event
NONE

You can use the maintenance-event with the Waiting for change feature to notify your scripts and applications when a maintenance event is about to start and end. This lets you automate any actions that you might want to run before or after the event. The following Python sample provides an example of how you might implement these two features together.

Note: During the maintenance event, the metadata server might briefly return a 503 Service Unavailable code. If your application receives a 503 error code, you should retry your request.

import httplib
import sys
import time
import urllib
import urllib2

METADATA_URL = 'http://metadata.google.internal/computeMetadata/v1/'


class Error(Exception):
  pass


class UnexpectedStatusException(Error):
  pass


class UnexpectedMaintenanceEventException(Error):
  pass


def WatchMetadata(metadata_key, handler, initial_value=None):
  """Watches for a change in the value of metadata.

  Args:
    metadata_key: The key identifying which metadata to watch for changes.
    handler: A callable to call when the metadata value changes. Will be passed
      a single parameter, the new value of the metadata.
    initial_value: The expected initial value for the metadata. The handler will
      not be called on the initial metadata request unless the value differs
      from this.

  Raises:
    UnexpectedStatusException: If the http request is unsuccessful for an
      unexpected reason.
  """
  params = {
      'wait_for_change': 'true',
      'last_etag': 0,
      }

  while True:
    value = initial_value
    # start a hanging-GET request for maintenance change events.
    url = '{base_url}{key}?{params}'.format(
        base_url=METADATA_URL,
        key=metadata_key,
        params=urllib.urlencode(params)
        )
    req = urllib2.Request(url, headers={'Metadata-Flavor': ''})

    try:
      response = urllib2.urlopen(req)
      content = response.read()
      status = response.getcode()
    except urllib2.HTTPError as e:
      content = None
      status = e.code

    if status == httplib.SERVICE_UNAVAILABLE:
      time.sleep(1)
      continue
    elif status == httplib.OK:
      # Extract new maintenance-event value and latest etag.
      new_value = content
      headers = response.info()
      params['last_etag'] = headers['ETag']
    else:
      raise UnexpectedStatusException(status)

    # If the maintenance value changed, call the appropriate handler.
    if value != new_value:
      value = new_value
      handler(value)


def HandleMaintenance(on_maintenance_start, on_maintenance_end):
  """Watches for and responds to maintenance-event status changes.

  Args:
    on_maintenance_start: a callable to call before host maintenance starts.
    on_maintenance_end: a callable to call after host maintenance ends.

  Raises:
    UnexpectedStatusException: If the http request is unsuccessful for an
      unexpected reason.
    UnexpectedMaintenanceEventException: If the maintenance-event value is not
      either NONE or MIGRATE_ON_HOST_MAINTENANCE.

  Note: Instances that are set to TERMINATE_ON_HOST_MAINTENANCE will receive a
  power-button push and will not be notified through this script.
  """
  maintenance_key = 'instance/maintenance-event'

  def Handler(event):
    if event == 'MIGRATE_ON_HOST_MAINTENANCE':
      on_maintenance_start()
    elif event == 'NONE':
      on_maintenance_end()
    else:
      raise UnexpectedMaintenanceEventException(event)

  WatchMetadata(maintenance_key, Handler, initial_value='NONE')


def OnMaintenanceStart():
  # Add commands to perform before maintenance starts here.
  pass


def OnMaintenanceEnd():
  # Add commands to perform after maintenance is complete here.
  pass


if __name__ == '__main__':
  # Perform actions when maintenance events occur.
  HandleMaintenance(OnMaintenanceStart, OnMaintenanceEnd)

  # An example of watching for changes in a different metadata field.
  # Replace 'foo' with an existing custom metadata key of your choice
  #
  # WatchMetadata('instance/attributes/foo',
  #               lambda val: sys.stdout.write('%s\n' % val))

Transitioning to v1

The v1 metadata server functions slightly differently that the previous v1beta1 server. Here are some of the changes that need to be made for the new metadata server:

  • Update metadata requests to include the Metadata-Flavor: Google header

    The new metadata server requires that all requests provide the Metadata-Flavor: Google header, which indicates that the request was made with the intention of retrieving metadata values, Update your requests to include this new header. For example, a request to the disks/ attribute now looks like the following:

    user@myinst:~$ curl "http://metadata.google.internal/computeMetadata/v1/instance/disks/" -H "Metadata-Flavor: Google"
  • Update requests that use the header X-Forwarded-For header

    These requests are automatically rejected by the server, as it generally indicates that the requests are proxied. Update your requests so they do not contain this header.

Authentication required

You need to be signed in with Google+ to do that.

Signing you in...

Google Developers needs your permission to do that.