Terraform Import (Manually)
Terraform’s all great and all, but what if you already have infrastructure and
you can’t just burn it all down and build it back up again using Terraform?
Well, terraform import
to the rescue.
…except it’s not as simple as that: you have to import individual resources by specifying their type and ID, one by one. But that’s not a big deal and the plan is to support a more robust import in the future.
…except the future is the future and import
may not be supported by
the Provider you’re using. In my case, OpenStack. So I have three options to
get my existing infrastructure under Terraform:
Don’t.
Implement that functionality in the Provider.
Fake it out.
The first isn’t really an option; I only included it because I’d already typed “three options” and didn’t want to go back. The second is very non-trivial because I have only started experimenting with Go. The third seems like a decent option, given that the Terraform state files are JSON (which I can’t stand but anyway) and that Terraform is a pretty solid tool I feel I can confidently play jokes on without it getting angry.
How that went: the first VM
I started with a pretty simple server (one attached volume, no floating IP,
default security group). I had an older terraform.tfstate
file for this
OpenStack project (‘tenant’ in older nomenclature) from earlier
experimentation and used this as a base, copying old stanzas, updating them
for new VMs, and commenting out the old ones. After some fiddling and
experimentation, I got a successful terraform plan
where the Terraform
configuration and state matched such that Terraform noted:
No changes. Infrastructure is up-to-date.
This means that Terraform did not detect any differences between your
configuration and real physical resources that exist. As a result, no
actions need to be performed.
Note that since terraform plan
does not make any changes, it does not affect
the state file, so I’m free to continue editing that file without it being
affected externally to the editor. This will be important later on when I get
things synced up and then want to make a change.
How that went: the second VM
I sadly ran into a wall on the second node I tried to import this way, which took some time to figure out. I would get the message:
* openstack_compute_instance_v2.node2: openstack_compute_instance_v2.node2: Resource not found
If you know Terraform, this is pretty vague because a lot of things are
resources, and there are dependencies between them. Right off the bat I
suspected it wasn’t the node itself that couldn’t be found, but I wasn’t sure
what. I set TF_LOG=DEBUG
and carefully read through the resulting reams,
and developed a suspicion Terraform was having trouble sorting out the network
configuration, because that was the last thing the debug logs showing being
examined before an exception is thrown.
It wound up being the flavour, which I knew was an older flavour discontinued
by our OpenStack team. For whatever reason, the OpenStack provider for
Terraform, given one of flavor_name
or flavor_id
, queries for the other so
it has the pair. The older flavour still exists in our OpenStack–otherwise
my node could not–but it’s not listed or visible to users so they don’t have
it as a choice in creating new VMs.
Fortunately, we have new flavours which are, for my purposes, identical. I used OpenStack’s resize to resize it to a newer flavour, which required a reboot, I adjusted the Terraform confiration and state file to reflect the new flavour’s ID and name, and I was able to proceed.
How that went: floating IPs, security groups and rules
Updating other elements went more or less fine. The problem isn’t that it’s difficult, it’s that it’s tedious as anything. Which leads me to: I could write a script to do this. Which in turns leads me to: maybe I should just learn Go and update the OpenStack provider.