aboutsummaryrefslogtreecommitdiff
path: root/content/blog/terraform/oci_state_mv.md
diff options
context:
space:
mode:
Diffstat (limited to 'content/blog/terraform/oci_state_mv.md')
-rw-r--r--content/blog/terraform/oci_state_mv.md122
1 files changed, 122 insertions, 0 deletions
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.
+```