Accelerating AzApi Adoption with Newres

Earlier this year Microsoft released version 2.0 of the AzApi Terraform provider. My favorite feature of this release was the implementation of Dynamic Properties, no more Json Encoding and Decoding! Removing the requirement for JSON formatting in favor of HCL (HashiCorp Configuration Language) was the final push I needed to start module development with AzAPI. Unlike the AzureRM provider, AzAPI resource templates are found on Microsoft Learn. AzAPI resource formats are different than those used by AzureRM as shown below.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#AzAPI
resource "azapi_resource" "symbolicname" {
 type = "Microsoft.Resources/resourceGroups@2024-11-01"
 name = "string"
 location = "string"
 managedBy = "string"
 tags = {
   {customized property} = "string"
 }
 body = {
   properties = {
   }
 }
}

#AzureRM
resource "azurerm_resource_group" "example" {
 name     = "example"
 location = "West Europe"
}

The differences between the provider can be quite intimidating if you are used AzureRM exclusively. To help ease the transition to AzAPI, we turn on a slick tool called newres. Newres is a command-line tool that provides the ability to create boilerplate module resources for several Terraform providers. Recently newres has been updated to allow the generation of resources for the AzAPI provider.

AzureRM Resource Creation with Newres

Newres makes it easy to generate boilerplate code when starting your module development. The command below will generate the following main.tf and variables.tf file for the deployment on an Azure Resource Group.

1
newres -dir ./ -r azurerm_resource_group
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#Main.tf

resource "azurerm_resource_group" "this" {
  location = var.resource_group_location
  name     = var.resource_group_name
  tags     = var.resource_group_tags

  dynamic "timeouts" {
    for_each = var.resource_group_timeouts == null ? [] : var.resource_group_timeouts
    content {
      create = timeouts.value.create
      delete = timeouts.value.delete
      read   = timeouts.value.read
      update = timeouts.value.update
    }
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#Variables.tf

variable "resource_group_location" {
  type        = string
  description = "(Required) The Azure Region where the Resource Group should exist. Changing this forces a new Resource Group to be created."
  nullable    = false
}

variable "resource_group_name" {
  type        = string
  description = "(Required) The Name which should be used for this Resource Group. Changing this forces a new Resource Group to be created."
  nullable    = false
}

variable "resource_group_tags" {
  type        = map(string)
  default     = null
  description = "(Optional) A mapping of tags which should be assigned to the Resource Group."
}

variable "resource_group_timeouts" {
  type = object({
    create = optional(string)
    delete = optional(string)
    read   = optional(string)
    update = optional(string)
  })
  default     = null
  description = <<-EOT
 - `create` - (Defaults to 1 hour and 30 minutes) Used when creating the Resource Group.
 - `delete` - (Defaults to 1 hour and 30 minutes) Used when deleting the Resource Group.
 - `read` - (Defaults to 5 minutes) Used when retrieving the Resource Group.
 - `update` - (Defaults to 1 hour and 30 minutes) Used when updating the Resource Group.
EOT
}

This code generation saves a considerable amount of time during initial module development. This time saving allows developers to focus more on the specific customizations required to meet their environment security and compliance requirements. For the development of a complex module, this can be a significant time savings.

AzAPI Resource Generation with Newres

Baseline AzApi resource generation can now be done with a simple command to newres.

1
newres --azapi-resource-type "Microsoft.Resources/resourceGroups@2021-04-01" -r azapi_resource --dir .

This will generate the require main.tf and variables.tf for the resource provided.

main.tf

1
2
3
4
5
6
7
8
resource "azapi_resource" "this" {
  type      = "Microsoft.Resources/resourceGroups@2021-04-01"
  body      = var.resource_body
  location  = var.resource_location
  name      = var.resource_name
  parent_id = var.resource_parent_id
  tags      = var.resource_tags
}

Variables.tf

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
variable "resource_body" {
  type = object({
    managedBy = optional(string)
  })
  description = <<-EOT
 - `managedBy` - 

 ---
 `properties` block supports the following:
EOT
  nullable    = false
}

variable "resource_location" {
  type        = stringhttps://www.bing.com/ck/a?!&&p=a51fc3e7a50e6b8f30ff9ae9e13d8458f17711626ca396bd655755ff6a557498JmltdHM9MTczNTYwMzIwMA&ptn=3&ver=2&hsh=4&fclid=29395f82-9cea-661a-2925-4c6b9d1a6749&psq=backup+movies+with+mkv&u=a1aHR0cHM6Ly93d3cuaG93dG9nZWVrLmNvbS8xNjE0OTgvaG93LXRvLWJhY2t1cC15b3VyLWR2ZC1hbmQtYmx1LXJheS1tb3ZpZS1jb2xsZWN0aW9uLw&ntb=1
  description = "The location of the resource group. It cannot be changed after the resource group has been created. It must be one of the supported Azure locations."
  nullable    = false
}

variable "resource_name" {
  type        = string
  description = "The resource name"
  nullable    = false
}

variable "resource_parent_id" {
  type        = string
  description = "The ID of the azure resource in which this resource is created."
  nullable    = false
}

variable "resource_tags" {
  type        = map(string)
  default     = null
  description = "The tags attached to the resource group."
}

Caveats When Using Newres

Conclusion

Support for AzApi resource modules with newres enables our team to investigate the replacement of our azureRM based modules knowing we will continue to have the same development speed and experience we have come to rely on for module creation. It is a difficult task to ask your team to try and develop new resource modules with the tools that introduce time savings to the process. Immediately there is an natural opposition to a process that feels slower and more time consuming then your current process. Even if the results provide additional benefits, the adoption of that process will be slow and difficult.

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy