hashicorp / terraform-provider-azurerm

Terraform provider for Azure Resource Manager
https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs
Mozilla Public License 2.0
4.61k stars 4.65k forks source link

Data Source for Availability Zones #3025

Open bpoland opened 5 years ago

bpoland commented 5 years ago

Community Note

Description

When deploying VMs, it would be nice to dynamically get the list of availability zones in the region I'm deploying to. Microsoft's documentation isn't great but it seems that you can only use certain VM SKUs with availability zones, and I found there's an az command that shows the zones for a particular sku:

az vm list-skus --location eastus2 --zone

So, maybe a similar VM SKU related data source would work here. It seems a bit confusing, but I guess that's how Microsoft has organized things...

New or Affected Resource(s)

Potential Terraform Configuration

data "azurerm_virtual_machine_sku" "test" {
  name     = "Standard_D2s_v3"
  location = "eastus2"
}

Then, in the VM you could set the zone:

zones = "${element(data.azurerm_virtual_machine_sku.test.zones, count.index)}"

(as a side note, I feel like the azurerm_virtual_machine documentation on availability zones is a bit confusing -- why isn't the field just "zone" with a single zone number to put the VM in?)

References

MattMencel commented 5 years ago

Hi @tombuildsstuff is there a technical reason this was pushed to the 2.0.0 milestone? Waiting on API support or something?

I've got a client request for this feature and would be willing to invest some time unless it can't be done at the moment.

tombuildsstuff commented 5 years ago

hey @MattMencel

is there a technical reason this was pushed to the 2.0.0 milestone? Waiting on API support or something?

From our side we've got plans to write replacements for the VM and VMSS resources in 2.0; coupled with the comment above (which makes a good point: (as a side note, I feel like the azurerm_virtual_machine documentation on availability zones is a bit confusing -- why isn't the field just "zone" with a single zone number to put the VM in?)) - which is a breaking change hence we initially bucketed this for 2.0. However I don't believe there's any technical blockers for adding this new Data Source beforehand (we bucketed this since it's related to the other work).

I've got a client request for this feature and would be willing to invest some time unless it can't be done at the moment.

Awesome - taking a quick look into this it appears the CLI uses this API and there's support for this in the Azure SDK - so I believe it should be possible to add support for this.

The main question from my end is around how we name this resource, (since at first glance it appears this is a Compute specific API, rather than a VM specific API; but perhaps not - it'd be good to confirm if these Zones are the same as the ones available for VMSS's too) - as such perhaps this would make more sense as azurerm_compute_zones - WDYT?

Thanks!

bpoland commented 5 years ago

The az cli documentation does mention "compute-related resource SKUs" -- I would assume it would be the same SKUs available for VMSS: https://docs.microsoft.com/en-us/cli/azure/vm?view=azure-cli-latest#az-vm-list-skus

There is an "az vmss list-skus" but it seems to be for getting details about a particular VMSS that's already created: https://docs.microsoft.com/en-us/cli/azure/vmss?view=azure-cli-latest#az-vmss-list-skus

Regarding the name, it does look like the az cli command returns info about disks, availability sets and snapshots as well as virtual machines. And the info returned is not just the available zones. So maybe azurerm_compute_skus ?

MattMencel commented 5 years ago

My impression from looking through the documentation is that availability zones are not necessarily compute specific. The current list of supported services are...

This is from the az-overview page.

Availability Zones are unique physical locations within an Azure region. Each zone is made up of one or more datacenters equipped with independent power, cooling, and networking. To ensure resiliency, there’s a minimum of three separate zones in all enabled regions.

So it would be my understanding that these zones aren't unique for VMs or VMSS, but would be the same for all supported services.

The ask here is to get the list of zones in a region correct? So I would probably lean towards describing in the data source name what the intention is.

azurerm_availability_zones or azurerm_region_availability_zones

Or... and I don't even know if this is possible... have an azurerm_region data source where one of the attributes returned is zones.

bpoland commented 5 years ago

The thing is, it seems that certain VM SKUs are only available in some of the availability zones (or in none of them). That's why I think you need to look it up by SKU.

From some quick checking, it looks like most SKUs are supported in all AZs but some of the larger ones are sometimes supported in fewer AZs.

MattMencel commented 5 years ago

OK, I dug into the API a little bit more and I think I understand better what this requires. Using postman I was able to get a full JSON response from the Compute/ResourceSKUs API. I then used jq to filter out all elements with empty zones in the response body.

cat response.json | jq '.[][] | select((.locationInfo[].zones != null) and (.locationInfo[].zones | length) > 0)

If you filter the response again by | .resourceType there are only two types, "disks" and "virtualMachines".

There's some other capability information in the responses that there may be use cases for. For now though I can try to work on getting a basic data resource that returns the zones for a specific region and VM SKU or disk size. Something like this maybe?

# Virtual Machine Zones
data "azurerm_compute_sku" "vm" {
    type = "vm"
    name = "Standard_D2s_v3"
    location = "centralus"
}

output "azurerm_compute_sku.vm.zones" {
    value = "${data.azurerm_compute_sku.vm.zones}"
}

# Disk Zones
data "azurerm_compute_sku" "disk" {
    type = "disk"
    size = "S4"
    location = "centralus"
}

output "azurerm_compute_sku.disk.zones" {
    value = "${data.azurerm_compute_sku.disk.zones}"
}

Argument Reference

location - (Required) The Azure location where the Compute SKU exists. type - (Required) Which Compute SKU type to retrieve (disk or vm). name - (Required for type=vm) The vm SKU. size - (Required for type=disk) The disk size.

Attributes Reference

zones - A List of availability zones filtered by the criteria above.

bpoland commented 5 years ago

Thanks @MattMencel, that would work well for my original use case -- looks good to me!

Moeser commented 5 years ago

This looks like it would work great. Any progress on a data source for this?

MattMencel commented 5 years ago

I've started working on this. Progress is slow because I'm not a Go developer. I think I'm headed in the right direction, but I've got to figure out how to pull the zone information out. What I'm after is the zones from the ResourceSkuLocationInfo in the SDK.

You can see the branch I'm working on here.... still incomplete.

gek0 commented 4 years ago

Hoping one day we'll have a normal data resource for this. I'll try to come up with something as soon as I learn Go enough :)

In the meantime, I've come up with my own solution using AZ cli and external modules. Solutions looks/works good enough for now, and should not be much different after data resource is available.

The external module used https://registry.terraform.io/modules/matti/resource/shell/1.0.7 (simple, works great and no infinite plan/apply issues)

Code example:

module "availability_zones_calculator" {
  source  = "matti/resource/shell"
  version = "1.0.7"

  command = "az vm list-skus --location $REGION --zone --resource-type virtualMachines --size $INSTANCE_TYPE --query '[].locationInfo[0].zones' --output jsonc"
  environment = {
    REGION        = data.azurerm_resource_group.resource_group.location
    INSTANCE_TYPE = var.instance_type
  }
}
locals {
  vm_availability_zones = sort(flatten(jsondecode(module.availability_zones_calculator.stdout)))
}

Output is list(string) of sorted strings, aka. available zones for that VM tier/location for eg. ["2", "3"] and easy to use in managed disks/virtual machines resources. Hope somebody finds it useful :slightly_smiling_face:

surajmuthreja commented 4 years ago

This is indeed a required feature to get the availability zone list and create the resources in a particular zone. Do we have any update on when can this be available?

clemlesne commented 1 year ago

I strongly support this. Maybe something similar, to the way AWS done the trick with aws_region..

And what about the resource azurerm_zones from this post?

HappyTobi commented 1 year ago

@clemlesne @tombuildsstuff

I requested a hashicorp azure SDK update, to improve / extend the existing implementation for the azurerm_extended_locations data source. The idea is, that the data service provide more additional information like zones etc.

See also: Azure Rest documentation

clemlesne commented 1 year ago

From a developer perspective, it would be useful to have something like:

Named azurerm_region, would make more sense than azurerm_locations (what is a "location"?).

Example usage:

data "azurerm_region" "current" {}

Arguments:

Schema:

{
  "mode": "data",
  "type": "azurerm_region",
  "name": "region",
  "provider": "provider[\"registry.terraform.io/hashicorp/azurerm\"]",
  "instances": [
    {
      "schema_version": 0,
      "attributes": {
        "id": "/subscriptions/xxx-xxx-xxx-xxx-xxx/region/northeurope",
        "region_id": "northeurope",
        "region_name": "North Europe",
        "region_type": "Physical",
        "zone_ids": ["1", "2", "3"],
        "zone_names": ["northeurope-az1", "northeurope-az2", "northeurope-az3"],
        "zone_mapping": [
          {
            "id": "1",
            "name": "northeurope-az1"
          },
          {
            "id": "2",
            "name": "northeurope-az3"
          },
          {
            "id": "3",
            "name": "northeurope-az2"
          }
        ]
      },
      "sensitive_attributes": []
    }
  ]
}
tombuildsstuff commented 1 year ago

@clemlesne FWIW the name for this should be location and not region for consistency across the provider - whilst Azure uses Region in the Portal - Location is used throughout the API and depending on the API this can comprise both an Azure Region, Extended Locations and other off-Azure locations (e.g. Arc/Hybrid - I vaguely recall some of the AWS related resources in Azure using a field named location to handle AWS regions too, but I maybe misremembering?)

theonlyames commented 11 months ago

While this isn't strictly related to availability zones, now that there is an azurerm_location data source would it make sense to include the paired region/location for a given location in the azurerm_location data source as well?