From c84c518e58f54e9a4c53eda4885283871a043cf7 Mon Sep 17 00:00:00 2001 From: Julien Dessaux Date: Mon, 3 Jan 2022 23:18:16 +0100 Subject: Added terraform refactoring article --- content/blog/terraform/oci_state_mv.md | 122 +++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 content/blog/terraform/oci_state_mv.md (limited to 'content/blog') diff --git a/content/blog/terraform/oci_state_mv.md b/content/blog/terraform/oci_state_mv.md new file mode 100644 index 0000000..340cd85 --- /dev/null +++ b/content/blog/terraform/oci_state_mv.md @@ -0,0 +1,122 @@ +--- +title: Terraform refactoring and state move +description: An example replacing a count with a for_each +date: 2022-01-03 +tags: + - terraform +--- + +## Introduction + +When I initialised my oracle cloud free tier infrastructure in [a previous blog article]({{< ref "getting_started_oci_free_tier.md" >}}), I made a mistake of using a `count` to iterate on a list of names for the instances I wished to spawn. The drawback of doing this is that I cannot reorder the items in this list, and deleting one instance could affect the other. + +The solution to this is to change this `count` construct to a `for_each`. This way the state objects will no longer be indexed by the instance position in the list, they will be indexed by their names. + +## What changes in the terraform code + +Since in one of the resources I used the index to infer a fault domain id, I rewrote the list from this : +```hcl +oracle_amd64_instances_names = ["dalinar", "kaladin"] +``` + +to this : +```hcl +oracle_amd64_instances = { + dalinar = { "fault_domain_id" = 0 }, + kaladin = { "fault_domain_id" = 1 }, +} +``` + +Note that I renamed the variable in order to not miss anywhere it was used. Now for each resource that used this list with a `count` like the following : +```hcl +resource "oci_core_instance" "amd64-vms" { + count = length(var.oracle_amd64_instances_names) + compartment_id = var.oracle_tenancy_ocid + availability_domain = data.oci_identity_availability_domains.ads.availability_domains[0].name + fault_domain = data.oci_identity_fault_domains.fd.fault_domains[ + count.index % length(data.oci_identity_fault_domains.fd.fault_domains)].name + display_name = var.oracle_amd64_instances_names[ + count.index % length(var.oracle_amd64_instances_names)] + shape = "VM.Standard.E2.1.Micro" + preserve_boot_volume = false + create_vnic_details { + subnet_id = oci_core_subnet.adyxax-production.id + hostname_label = var.oracle_amd64_instances_names[count.index] + display_name = var.oracle_amd64_instances_names[count.index] +} +``` + +Such entries now becomes : +```hcl +resource "oci_core_instance" "amd64-vms" { + for_each = var.oracle_amd64_instances + compartment_id = var.oracle_tenancy_ocid + availability_domain = data.oci_identity_availability_domains.ads.availability_domains[0].name + fault_domain = data.oci_identity_fault_domains.fd.fault_domains[each.value["fault_domain_id"]].name + display_name = each.key + shape = "VM.Standard.E2.1.Micro" + preserve_boot_volume = false + create_vnic_details { + subnet_id = oci_core_subnet.adyxax-production.id + hostname_label = each.key + display_name = each.key +} +``` + +## How to migrate the state + +To see which resources need to be migrated you can use `terraform state list` : +```sh +julien@nas ~/git/adyxax/adyxax.org/02-permanent-hosts (master *$%) $ terraform state list +data.cloudflare_zones.adyxax-eu +data.cloudflare_zones.adyxax-org +data.cloudflare_zones.asj-fr +data.hcloud_ssh_key.adyxax +data.oci_core_image.ol8 +data.oci_core_vnic_attachments.amd64-vms-vnics[0] +data.oci_core_vnic_attachments.amd64-vms-vnics[1] +data.oci_identity_availability_domains.ads +data.oci_identity_fault_domains.fd +cloudflare_record.adyxax-org-oracle-amd64-vms-ipv4[0] +cloudflare_record.adyxax-org-oracle-amd64-vms-ipv4[1] +cloudflare_record.adyxax-org-oracle-amd64-vms-ipv6[0] +cloudflare_record.adyxax-org-oracle-amd64-vms-ipv6[1] +oci_core_instance.amd64-vms[0] +oci_core_instance.amd64-vms[1] +oci_core_internet_gateway.gw +oci_core_ipv6.amd64-vms-ipv6s[0] +oci_core_ipv6.amd64-vms-ipv6s[1] +oci_core_route_table.default-via-gw +oci_core_security_list.allow-all +oci_core_subnet.adyxax-production +oci_core_vcn.adyxax +``` + +Here we are interested with all the resources indexed with `0` and `1`. I migrated the state using the following commands : +```sh +terraform state mv data.oci_core_vnic_attachments.amd64-vms-vnics[0] \ + data.oci_core_vnic_attachments.amd64-vms-vnics[\"dalinar\"] +terraform state mv data.oci_core_vnic_attachments.amd64-vms-vnics[1] \ + data.oci_core_vnic_attachments.amd64-vms-vnics[\"kaladin\"] +terraform state mv cloudflare_record.adyxax-org-oracle-amd64-vms-ipv4[0] \ + cloudflare_record.adyxax-org-oracle-amd64-vms-ipv4[\"dalinar\"] +terraform state mv cloudflare_record.adyxax-org-oracle-amd64-vms-ipv4[1] \ + cloudflare_record.adyxax-org-oracle-amd64-vms-ipv4[\"kaladin\"] +terraform state mv cloudflare_record.adyxax-org-oracle-amd64-vms-ipv6[0] \ + cloudflare_record.adyxax-org-oracle-amd64-vms-ipv6[\"dalinar\"] +terraform state mv cloudflare_record.adyxax-org-oracle-amd64-vms-ipv6[1] \ + cloudflare_record.adyxax-org-oracle-amd64-vms-ipv6[\"kaladin\"] +terraform state mv oci_core_instance.amd64-vms[0] \ + oci_core_instance.amd64-vms[\"dalinar\"] +terraform state mv oci_core_instance.amd64-vms[1] \ + oci_core_instance.amd64-vms[\"kaladin\"] +terraform state mv oci_core_ipv6.amd64-vms-ipv6s[0] \ + oci_core_ipv6.amd64-vms-ipv6s[\"dalinar\"] +terraform state mv oci_core_ipv6.amd64-vms-ipv6s[1] \ + oci_core_ipv6.amd64-vms-ipv6s[\"kaladin\"] +``` + +Note the escaping of the quotes so that the shell does not interpret (and remove) these. We can make sure we did not do any mistake by running a plan and seeing that terraform does not report any changes : +```sh +No changes. Your infrastructure matches the configuration. +``` -- cgit v1.2.3