layout: true class: center, middle, inverse --- # Azure Terrafy *A tool brings existing Azure resources under the management of [Terraform](https://terraform.io/)* --- ## Terraform Intro --- layout: false .left-column[ ## Terraform Intro ### - Typical Workflow ] .right-column[ ### Intro An open-source infrastructure as code software tool that provides a consistent CLI workflow to manage hundreds of cloud services. ] -- .right-column[ #### Typical Workflow ![workflow](./img/workflow.png) ] --- .left-column[ ## Terraform Intro ### - Typical Workflow ### - Import ] .right-column[ ### Import `terraform import` imports an existing resource into your Terraform state. While it **DOES NOT** generate the Terraform configuration to manage the infrastructure. ] -- .right-column[ ![import](./img/import-workflow.png) ] -- .right-column[ 1. Identify the existing infrastructure to be imported (manual) 2. Import infrastructure into your Terraform state (`terraform import`) 3. Write Terraform configuration that matches the infrastructure (manual) 4. Review the Terraform plan to ensure the configuration matches state of the infra (manual) ] --- layout: true class: center, middle, inverse --- # Requirement --- layout: false .left-column[ ## Requirement ] -- .right-column[ ### Goals * Automatically identify resources to be imported * Automatically generate the Terraform state file * Automatically generate the **valid** Terraform configuration file: * Pins version on the provider under used * The resource should match its state in the remote platform (verified via `terraform plan`) * Defines the cross resource dependencies * Up-to-date support to the provider ] -- .right-column[ ### Non Goals * Infrastructure 100% reproducible via the generated configuration (due to feature gaps between the provider and the platform) * Configuration files do not need to be elegent (e.g. `for_each`, implicit dependencies, etc.) * Modules do not need to be generated ] --- layout: true class: center, middle, inverse --- # Exist Tools --- layout: false .left-column[ ## Exist Tools ### - Overview ] .right-column[ ### Overview A bunch of existing tools in the community: - Terraform Team - Terraform v1.1+ (currently in alpha) - apparentlymart/terrafy (experimental purpose) - 3rd Party - dtan4/terraforming - GoogleCloudPlatform/terraformer - cycloidio/terracognita ] --- .left-column[ ## Exist Tools ### - Overview ### - Terraform Team ] .right-column[ ### Terraform v1.1+ A new command `terraform add` is introduced in version: `v1.1.0-alpha20210811` ] -- .right-column[ ```hcl » terraform add random_pet.meow resource "random_pet" "meow" { } » terraform add -optional random_pet.meow resource "random_pet" "meow" { keepers = null length = 3 prefix = "add" separator = "-" } » terraform add -from-state=random_pet.example random_pet.meow resource "random_pet" "meow" { id = "add-vigorously-refined-doe" keepers = null length = 3 prefix = "add" separator = "-" } ``` ] --- .left-column[ ## Exist Tools ### - Overview ### - Terraform Team ] .right-column[ ### Terraform v1.1+ Limitations: - One resource only, i.e. no cross resource dependencies - The generated configuration not guarantee to be valid, but as a starting point ] -- .right-column[ **Unfortunately, this feature is drawn back in the final release of v1.1...** ] --- .left-column[ ## Exist Tools ### - Overview ### - Terraform Team ] .right-column[ ### Terrafy (@apparentlymart) ] -- .right-column[ > ... > I wrote it primarily to explore the problem space of implementing these features generically using the current provider featureset > ... ] --- .left-column[ ## Exist Tools ### - Overview ### - Terraform Team ] .right-column[ ### Terrafy (@apparentlymart) ```hcl # main.tfy data "aws_instances" "existing" { instance_tags = { Subsystem = "renderer" Environment = "production" } } import "aws_instance" "example" { id = tolist(data.aws_instances.existing.ids) } ``` Workflow: 1. Write **.tfy** files 2. `terrafy` imports the resources 3. `terrafy` converts the state to configuration ] --- .left-column[ ## Exist Tools ### - Overview ### - Terraform Team ] .right-column[ ### Terrafy (@apparentlymart) Limitations: - The users need terraform background to write the **.tfy** files - The users need to identify the resources to import - The generated configuration not guarantee to be valid - No cross resource dependencies ] --- .left-column[ ## Exist Tools ### - Overview ### - Terraform Team ### - 3rd Party ] .right-column[ ### dtan4/terraforming ![terraforming](https://img.shields.io/github/stars/dtan4/terraforming) Template based implementation. Terraforming gets all attributes from cloud APIs and creates HCL and tfstate files with templating. ] -- .right-column[ Limitations: - AWS only - Not scalable: When a provider adds new attributes the terraforming code needs to be updated - Invalid configuration/state: Generated files from templating can be broken with illegal syntax - Not actively maintained (last commit is on 2019) ] --- .left-column[ ## Exist Tools ### - Overview ### - Terraform Team ### - 3rd Party ] .right-column[ ### GoogleCloudPlatform/terraformer ![terraformer](https://img.shields.io/github/stars/GoogleCloudPlatform/terraformer) Terraformer uses Terraform providers and is designed to easily support newly added resources. Terraformer supports major clouds. Workflow: 1. Users specify the resources to import (either one by one, or by specifying a scope, with some filter capabilities) 2. `terraformer` imports the resources into state 3. `terraformer` converts the state into configuration based on the *provider schema* (`terraform providers schema`) 4. Add cross resource dependencies into the configuration ] --- .left-column[ ## Exist Tools ### - Overview ### - Terraform Team ### - 3rd Party ] .right-column[ ### GoogleCloudPlatform/terraformer ![terraformer](https://img.shields.io/github/stars/GoogleCloudPlatform/terraformer) Limitations: - Manual code needed to support a new resource. i.e., users can only import the supported resources by terraformer, even though it is supported by the provider - The generated configuration is not guaranteed to be **valid** - The cross resource dependencies needs to manually maintain per resource, per provider. This is also not reliable and might be incorrect (see issue: [#587](https://github.com/GoogleCloudPlatform/terraformer/issues/587)) ] --- .left-column[ ## Exist Tools ### - Overview ### - Terraform Team ### - 3rd Party ] .right-column[ ### cycloidio/terracognita ![terracognita](https://img.shields.io/github/stars/cycloidio/terracognita) Almost the same as `terraformer` > About Terraformer, it almost does the same things than what we did and globally the same way. We already started to work on our project (Terracognita) when they published their own/we heard about it. *From one of the developer in this [reddit comment](https://www.reddit.com/r/Terraform/comments/c4jhy7/cycloid_opensource_terracognita_project/erxi21f/)* ] --- .left-column[ ## Exist Tools ### - Overview ### - Terraform Team ### - 3rd Party ### - Summary ] .right-column[ ### Requirement (review) * Automatically identify resources to be imported * Automatically generate the Terraform state file * Automatically generate the **valid** Terraform configuration file * Up-to-date support to the provider ] --- .left-column[ ## Exist Tools ### - Overview ### - Terraform Team ### - 3rd Party ### - Summary ] .right-column[ ### Requirement (review) * Automatically identify resources to be imported * Automatically generate the Terraform state file * .red[Automatically generate the **valid** Terraform configuration file] * .red[Up-to-date support to the provider] ] -- .right-column[ ### Reason - The conversion from state to configuration doesn't have enough knowledge - Manual support for each resource ] --- layout: true class: center, middle, inverse --- # Azure Terrafy --- layout: false .left-column[ ## Azure Terrafy ### - Intro ] .right-column[ ### Intro A tool to bring your existing Azure resources under the management of Terraform. ] -- .right-column[ Workflow: 1. Run `aztfy
` from command line 2. `aztfy` *automatically* identify existing resources reside in the resource group 3. `aztfy` asks the user to input the Terraform resource identifier for each Azure resource (manual now, but can improve) 4. `aztfy` *automatically* import each resource to the state, and convert the state to a **valid** terraform configuration ] --- .left-column[ ## Azure Terrafy ### - Intro ### - Deep Dive ] .right-column[ ### Provider Schema ![arch](./img/terraform-plugin-overview.png) ] -- .right-column[ **Terraform Core** has a definition for the provider schema (go package: `hashicorp/terraform-json`). This is what you got via `terraform providers schema`. ] -- .right-column[ **Provider** has a similar definition for the provider schema (go package: `hashicorp/hashicorp-plugin-sdk/v2`) ] -- .right-column[ **Terraform Core** Schema
⊂
**Provider** Schema ] --- .left-column[ ## Azure Terrafy ### - Intro ### - Deep Dive ] .right-column[ ### ARM Template ] -- .right-column[ **A**zure **R**esource **M**anagement Template is the Azure specific IaC toolset. ![arm](https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/media/overview/template-processing.png) ] -- .right-column[ Why using ARM template? - Listing resources inside a resource group, flattening the resource hierarchy - Retrieve cross resource dependencies ] --- .left-column[ ## Azure Terrafy ### - Intro ### - Deep Dive ### - Demo ] .right-column[ ### Demo ![demo](https://go.dev/images/gophers/motorcycle.svg) ] --- layout: true class: center, middle, inverse --- # Enjoy