aboutsummaryrefslogtreecommitdiff
path: root/content/blog/terraform/oci_state_mv.md
blob: 340cd859a1025cd26024d2f78ae680276fef1c3d (plain)
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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
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.
```