Query VM metadata

Stay organized with collections Save and categorize content based on your preferences.

Every VM stores its metadata on a metadata server. Use these instructions to query these metadata values. For more information about metadata, see VM metadata.

You can query for default VM metadata, such as the VM's host name, instance ID, and service account information programmatically from within a VM. For a list of default metadata values, see Default VM metadata values.

You can also query any custom metadata such as startup and shutdown scripts programmatically from within a VM, or, you can use the Google Cloud console or Google Cloud CLI.

This documents shows how to complete the following tasks:

Before you begin

Permissions

To query VM metadata, the following minimum permissions are required:

  • compute.projects.get on the project
  • compute.instances.get on the VM

You can also use a predefined role. To find predefined roles that contain these permissions, see Compute Engine IAM Roles.

How metadata values are arranged

  • Project and instance metadata: Metadata can be assigned to both projects and VMs. Project metadata propagates to all VMs within a project, while instance metadata only applies to a single VM.

  • Directory listings: 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 metadata keys.

Programmatically query metadata

From within a VM, you can programmatically query either default or custom metadata values using tools such as curl on Linux or Invoke-RestMethod on Windows.

Query a single metadata entry

Linux VMs

From within your Linux VMs, use the curl tool to make a query.

For example, to query the boot image for the VM, run the following query:

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

The output is similar to the following:

projects/rhel-cloud/global/images/rhel-8-v20210122

Windows

From within your Windows VMs, use the Invoke-RestMethod command.

For example, to query the boot image for the VM, run the following query:

PS C:\> 
$value = (Invoke-RestMethod `
         -Headers @{'Metadata-Flavor' = 'Google'} `
         -Uri "http://metadata.google.internal/computeMetadata/v1/instance/image")
$value

The output is similar to the following:

projects/windows-cloud/global/images/windows-server-2019-dc-v20210112

Query metadata directory listings

The metadata server uses directories to organize certain metadata keys. Any metadata entry ending in a trailing slash is a directory.

Linux

For example, the disks/ entry is a directory of disks attached to that VM.

To query the disks entry, from your Linux VM, run the following commands:

  1. Run the curl command on the disks directory.

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

    The output is similar to the following:

    0/
    1/
    2/
    
  2. If you want more information about disk 0/ directory, you can then query the specific URL for that directory:

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

    The output is similar to the following:

    device-name
    index
    mode
    type
    
  3. Then to query the disk type (type) for disks 0/, you can run the following:

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

    The output is similar to the following:

    PERSISTENT
    

Windows

For example, the disks/ entry is a directory of disks attached to that VM.

To query the disks entry, from your Windows VM, run the following commands:

  1. Use the Invoke-RestMethod command.

    PS C:\> 
    $value = (Invoke-RestMethod `
            -Headers @{'Metadata-Flavor' = 'Google'} `
            -Uri "http://metadata.google.internal/computeMetadata/v1/instance/disks/")
    $value
    

    The output is similar to the following:

    0/
    1/
    2/
    
  2. If you want more information about disk 0/ directory, you can query the specific URL for that directory:

    PS C:\> 
    $value = (Invoke-RestMethod `
             -Headers @{'Metadata-Flavor' = 'Google'} `
             -Uri "http://metadata.google.internal/computeMetadata/v1/instance/disks/0/")
    $value
    

    The output is similar to the following:

    device-name
    index
    mode
    type
    
  3. Then to query the disk type (type) for disks 0/, you can run the following:

    PS C:\> 
    $value = (Invoke-RestMethod `
             -Headers @{'Metadata-Flavor' = 'Google'} `
             -Uri "http://metadata.google.internal/computeMetadata/v1/instance/disks/0/type")
    $value
    

    The output is similar to the following:

    PERSISTENT
    

Recursively query directory listings

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

Linux

From within your Linux VMs, use the curl tool to make a query.

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

The output is similar to the following:

[{"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"

The output is similar to the following:

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

Windows

From within your Windows VMs, use the Invoke-RestMethod command.

PS C:\> 
$value = (Invoke-RestMethod `
          -Headers @{'Metadata-Flavor' = 'Google'} `
          -Uri "http://metadata.google.internal/computeMetadata/v1/instance/disks/?recursive=true")
$value

The output is similar to the following:

[{"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:

PS C:\> 
$value = (Invoke-RestMethod `
          -Headers @{'Metadata-Flavor' = 'Google'} `
          -Uri "http://metadata.google.internal/computeMetadata/v1/instance/disks/?recursive=true&alt=text")
$value

The output is similar to the following:

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

Format query output

By default, each endpoint has a predefined format for the response. Some endpoints might return data in JSON format by default, while other endpoints might return data as a string. You can override the default data format specification by using the alt=json or alt=text query parameters, which return data in JSON string format or as a plain text representation, respectively.

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

Linux

From within your Linux VMs, use the curl tool to make a query.

Default query

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

The output is similar to the following:

["http-server", "db-client", "app-server", "mysql-server"]

Query with formatting

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

The output is similar to the following:

http-server
db-client
app-server
mysql-server

Windows

From within your Windows VMs, use the Invoke-RestMethod command.

Default query

PS C:\> 
$value = (Invoke-RestMethod `
          -Headers @{'Metadata-Flavor' = 'Google'} `
          -Uri "http://metadata.google.internal/computeMetadata/v1/instance/tags")
$value

The output is similar to the following:

["http-server", "db-client", "app-server", "mysql-server"]

Query with formatting

PS C:\> 
$value = (Invoke-RestMethod `
          -Headers @{'Metadata-Flavor' = 'Google'} `
          -Uri "http://metadata.google.internal/computeMetadata/v1/instance/tags?alt=text")
$value

The output is similar to the following:

http-server
db-client
app-server
mysql-server

Wait for updates

Given that metadata values can change while your VM is running, the metadata server can be notified of metadata changes by using the wait-for-change feature. With this option, the request only returns an output when your specified metadata has changed.

You can use this feature on custom metadata or server-defined metadata, so if anything changes about your VM 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.

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

When working with thewait-for-change feature, consider the following:

  • You can only perform a wait-for-change request on a metadata endpoint or recursively on the contents of a directory. You cannot perform a wait-for-change request on a directory listing. If you try to do this, the metadata server fails your request and returns a 400 Invalid Request error.

  • You cannot 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 and 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:

Linux VMs

From within your Linux VMs, use the curl tool to make a query.

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

After there is a change to the specified metadata key, the query returns with the new value.

Examples

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"

The output is similar to the following:

http-server
db-client

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:

{"foo":"bar","baz":"bat"}

Windows

From within your Windows VMs, use the Invoke-RestMethod command.

PS C:\> 
$value = (Invoke-RestMethod `
          -Headers @{'Metadata-Flavor' = 'Google'} `
          -Uri "http://metadata.google.internal/computeMetadata/v1/METADATA_KEY?wait_for_change=true")
$value

Examples

After 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:

PS C:\> 
$value = (Invoke-RestMethod `
          -Headers @{'Metadata-Flavor' = 'Google'} `
          -Uri "http://metadata.google.internal/computeMetadata/v1/instance/tags?wait_for_change=true")
$value

The output is similar to the following:

http-server
db-client

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

PS C:\> 
$value = (Invoke-RestMethod `
          -Headers @{'Metadata-Flavor' = 'Google'} `
          -Uri "http://metadata.google.internal/computeMetadata/v1/instance/attributes?recursive=true&wait_for_change=true")
$value

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

{"foo":"bar","baz":"bat"}

Use ETags

When you submit a simple wait-for-change query, the metadata server returns a response 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's 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 is 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.

Linux VMs

To get the current ETag value for a metadata key, complete the following steps:

  1. Make a request to that key and print the headers. In curl, you can do this by using the -v flag:

    user@myinst:~$ curl -v "http://metadata.google.internal/computeMetadata/v1/instance/tags" -H "Metadata-Flavor: Google"
    

    The output is similar to the following:

    * 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 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
    <
    http-server
    db-client
  2. You can then use that ETag value with the Invoke-RestMethod command 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 matches your specified ETag value, and if that value changes, the request returns with the new contents of your metadata key.

Windows VMs

To get the current ETag value for a metadata key, complete the following steps:

  1. Make a request to that key and print the headers. On Windows, use the use the Invoke-WebRequest command.

    PS C:\> 
    $value = (Invoke-WebRequest -Headers @{'Metadata-Flavor' = 'Google'} `
    -Uri http://metadata.google.internal/computeMetadata/v1/instance/tags)
    
    $value.Headers.ETag
    

    The output is similar to the following:

    * 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 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
    <
    http-server
    db-client

  2. You can then use that ETag value in your wait-for-change request:

    PS C:\> 
    $value = (Invoke-RestMethod `
              -Headers @{'Metadata-Flavor' = 'Google'} `
              -Uri "http://metadata.google.internal/computeMetadata/v1/instance/tags?wait_for_change=true&last_etag=411261ca6c9e654e")
    $value
    

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

Python

The following Python sample shows how to programmatically watch the metadata server for changes.

This sample sets the initial ETag to 0. The metadata server never returns a response with 0 as the ETag. When 0 is specified as the last ETag in a request, the metadata server responds with the current value and ETag. This saves a bit of the code needed to get the initial value and ETag.

last_etag = '0'

while True:
    r = requests.get(
        url,
        params={'last_etag': last_etag, 'wait_for_change': True},
        headers=METADATA_HEADERS)

    # During maintenance the service can return a 503, so these should
    # be retried.
    if r.status_code == 503:
        time.sleep(1)
        continue
    r.raise_for_status()

    last_etag = r.headers['etag']

Set 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 parameter. The timeout_sec parameter limits the wait time of your request to the number of seconds you specified, and when the request reaches that limit, it returns the current contents of the metadata key.

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.

Here is an example of a wait-for-change request that is set to time out after 360 seconds:

Linux

From within your Linux VMs, use the curl tool to make a query.

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

Windows

From within your Windows VMs, use the Invoke-RestMethod command.

PS C:\> 
$value = (Invoke-RestMethod `
          -Headers @{'Metadata-Flavor' = 'Google'} `
          -Uri "http://metadata.google.internal/computeMetadata/v1/instance/tags?wait_for_change=true&timeout_sec=360")
$value

Status codes

When you perform a wait-for-change request, the metadata server returns standard HTTP status codes to indicate success or failure. In the case of errors, network conditions can 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 to recognize and handle these errors.

The possible statuses 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. The metadata server also returns this error if your metadata is deleted while you are waiting on a change.
Error 503 There was a temporary server error or a temporary maintenance event. Retry the request.

Use the Google Cloud console or gcloud CLI to query metadata

You can use the Google Cloud console or the gcloud CLI to find custom metadata values.

Query custom project metadata

Query project metadata to view custom metadata that applies to all VMs in your project.

Console

  1. In the Google Cloud console, go to the Metadata page.

    Go to Metadata

    • From the Metadata tab, you can review most of your custom project metadata with the exception of SSH key metadata.
    • From the SSH keys tab, you can review all your project-level SSH key metadata.

gcloud

Use the gcloud compute project-info describe command to query project metadata:

gcloud compute project-info describe

The output is similar to the following:

commonInstanceMetadata:
  fingerprint: HcSFdS_1_1I=
  items:
  - key: ssh-keys
    value: USERNAME:ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDWZ...
  kind: compute#metadata
...

The commonInstanceMetadata field shows the custom metadata that applies to all VMs in your project.

Query custom instance metadata

Query instance metadata to view custom metadata that applies to a single VM.

Console

  1. In the Google Cloud console, go to the VM instances page.

    Go to VM instances

  2. Click the name of the VM for which you want to view metadata.

    • SSH keys for this instance. In the Security and access section, view the SSH keys field.

      • A value of None indicates there are no SSH keys stored in instance metadata.

      • Any other value indicates that there are SSH keys stored in instance metadata.

    • SSH keys for a project. In the Security and access section, view the Block project-wide SSH keys field.

      • A value of On indicates that the value of the metadata key block-project-ssh-keys is TRUE in instance metadata.

      • A value of Off indicates that the value of the metadata key block-project-ssh-keys is FALSE, or that the key isn't set.

    • All other custom metadata. View the Custom metadata section. You see all custom metadata keys and values, other than SSH key metadata.

gcloud

Use the gcloud compute instances describe command to query instance metadata:

gcloud compute instances describe VM_NAME

Replace VM_NAME with the name of the VM you want to find metadata for.

The output is similar to the following:

...
metadata:
  fingerprint: MTgTJ5m-Cjs=
  items:
  - key: enable-oslogin
    value: 'true'
  kind: compute#metadata
...

The metadata field shows the custom metadata that applies to the VM.

What's next