Azure Instance Metadata and Scheduled Events

Earlier last week Microsoft announced the public preview of the VM Instance Metadata service. This service allows you to query information about a VM, from inside the VM itself, it's something that has been available on AWS for a long time and has some really interesting uses for users or code running inside your virtual machines. In this post we'll dig a bit deeper into the service and how it can be used.

The Preview of this service is currently only available in the West US Central Region

Retrieving Instance Metadata

Getting the instance metadata is done by calling a URI from inside the VM, this is on a non rotatable IP, so you can only get this information from inside the VM itself. The URL that you need to call is:

http://169.254.169.254/metadata/instance?api-version=2017-03-01

However if you just call that URL directly, you'll get an error as it is also expecting some information in the header of your request, namely a property of "metadata" with a value of "true". So to call this from PowerShell on windows, you would not something like:

curl -H @{'Metadata'='true'} http://169.254.169.254/metadata/instance?api-version=2017-03-01

Note "curl" in PowerShell is just an alias for "Invoke-Webrequest"

The content of the response is JSON which contains two objects:

{
    "compute":  {
    "location":  "westcentralus",
    "name":  "MetaData",
    "offer":  "WindowsServer",
    "osType":  "Windows",
    "platformFaultDomain":  "0",
    "platformUpdateDomain":  "0",
    "publisher":  "MicrosoftWindowsServer",
    "sku":  "2012-R2-Datacenter",
    "version":  "4.127.20170406",
    "vmId":  "efd3aced-81c4-4521-bbe7-154bcb11e816",
    "vmSize":  "Standard_DS2_v2"
    },
    "network":  {
    "interface":  [
      "@{ipv4=; ipv6=; mac=000D3AF8563C}"
      ]
    }
}

Compute

The Compute object provides basic information about the VM your running this command on, this information can be useful in a variety of scenarios:

  • Getting a unique VM ID for the VM your running on to uniquely identify the machine you are running on
  • Getting the VM Size to determine whether scale up or down is something you want to do, or to report the VM size to your custom billing or cost tracking solution
  • Checking the version of the VM's OS image to determine if it needs an update
  • Checking the VM fault and upgrade domain, this is particularly important for clusters and HA and this data can be used to check your nodes are all in separate fault and upgrade domains

The data is pulled in as JSON, so you can easily convert this into a PowerShell object which can be manipulated as required:

$rawMetaData=$(curl -H @{'Metadata'='true'} http://169.254.169.254/metadata/instance?api-version=2017-03-01).content
$metaData= convertFrom-JSON $rawMetaData
write-host "VM ID is $($metaData.compute.vmID)"

You can also get a specific value from the metadata by including this in your URL, for example for the VMID, your URL would look like this:

http://169.254.169.254/metadata/instance/compute/vmId?api-version=2017-03-01&format=text

Network

The network object provides some basic information about the VM's network configuration, this is broken down into multiple objects, so is a bit more complicated than the compute object, but we can retrieve:

  • MAC Address
  • IPv4 Configuration including the VM's public and private IP
  • IPv6 Configuration if in use

This information can be very useful when running code to allow access to remote resources, obtain licences from a licence service etc.

For example, to retrieve the MAC and public IP:

$rawMetaData=$(curl -H @{'Metadata'='true'} http://169.254.169.254/metadata/instance?api-version=2017-03-01).content
$metaData= convertFrom-JSON $rawMetaData

$MAC=$metaData.network.interface.mac
$publicIP=$metaData.network.interface.ipv4.ipaddress.publicIP

Scheduled Events

There is also another metadata service available for your VM's, this has been available for a little while now, that works similarly to the instance meta data - scheduled events. The scheduled events service is available on a similar URL from inside the VM and when called will give you information on any scheduled maintenance events that are planned for this VM. The scheduled events service can only provide details of an event when it knows it is planned, so you may find that some events only appear a few minutes before they occur, others may be present for longer. Obviously unplanned maintenance is unlikely to be shown.

To get this data your again going to hit the 169.254.169.254 URL, but with some different data, using PowerShell your request would look like:

curl -H @{'Metadata'='true'} http://169.254.169.254/metadata/latest/scheduledevents``

The content of the response will include an "Events" array. If there are no events scheduled this will be empty. If there are events planned, the array will contain an object with information on the event, similar to :

 "Events":[
      {
        "EventId":{eventID},
        "EventType":"Reboot",
        "ResourceType":"VirtualMachine",
        "Resources":[{resourceName}],
        "EventStatus":"Scheduled",
        "NotBefore":{timeInUTC},  
     }
 ]

The EventType will describe what event is going to take place, and be one of three options:

  • Freeze: The Virtual Machine is scheduled to pause for few seconds. There is no impact on memory, open files, or network connections
  • Reboot: The Virtual Machine is scheduled for reboot (memory is wiped).
  • Redeploy: The Virtual Machine is scheduled to move to another node (ephemeral disk are lost).

The EventStatus will indicate whether the event is "Scheduled", going to happen in the future, or "InProgress" indicating it is happening now.

If the event is scheduled, a NotBeforeTime will indicate the earliest time the event will occur.

Expediting an Event

If an event is scheduled for the future, you can make a request to trigger the event earlier than the NotBefore time. This is done by making a POST request back to the scheduled event service. Azure will then expedite the event where possible, but there is no guarantee it will occur early.

To submit a request for expediting, you need to send an array of StartRequests to the API using the EventID you were provided in the event message:

$startRequests = [array]@{"EventId" = <eventID>}
$scheduledEventsApproval = @{"StartRequests" = $startRequests} 
$approvalString = ConvertTo-Json $scheduledEventsApproval
Invoke-RestMethod -Uri http://169.254.169.254/metadata/latest/scheduledevents -Headers @{"Metadata"="true"} -Method POST -Body $approvalString

Further Reading

Azure's Instance Metadata Service --Preview

Azure Metadata Service - Scheduled Events (Preview)