Importing terraform resources using Atlantis

Posted on July 22, 2022 by Adrian Wyssmann ‐ 3 min read

Using atlantis to apply changes on existing works great, but how you deal with importing of exiting resources? Let me explain what is the issue, and how I solved it.

What is the issue?

Yeah, atlantis really helps to accelerate our terraform-journey. But when you start the journey, you may already have existing resources, which means that you have to run terraform import. I work in a more restricted environment, where we don’t have direct access to production environment. So even if we want manually applying a terraform state, we have to go some extra miles by doing this on a machine, which would have access to production environment. atlantis takes that extra mile away, cause everything is done via PR - well except to import resources, as atlantis only runs plan and apply. So how can I run terraform import with atlantis?

My solution to the problem

Looking at what atlantis offers, the one solution which seems suitable for me is to use custom workflows, which I could use to achieve what I want. First, I add a custom workflow called import to my server config:

...
repoConfig: |
 ---
 repos:
 - id: /.*/
   apply_requirements: [approved, mergeable]
   workflow: default
   allowed_overrides: [workflow]
   allow_custom_workflows: false
 workflows:
   default:
     plan:
       steps: [init, plan]
     apply:
       steps: [apply]
   import:
     plan:
       steps:
       - init
       - run: chmod u+x ./import-resources.sh && ./import-resources.sh
       - plan 

As you can see, this workflow relies on a file called import-resources.sh. This file has to be updated with the terraform import-statements for all new resources. This file is places in each tf project, for example:

.
├── cluster1
│  ├── main.tf
│  ├── import-resources.sh
│  ...
├── cluster2
│  ├── main.tf
│  ├── import-resources.sh
│  ...
...

I add some minimal stuff in there

#!/usr/bin/env bash

echo "[Info] Start importing resources ..."
# terraform import rancher2_app_v2.monitoring c-xxxxx.cattle-monitoring-system/rancher-monitoring

The idea is, that whenever this file is changed, the custom workflow runs and hence executes all necessary import statements, before terraform plan is applied. In order for that to happen, I also add an atlantis.yaml to the rpeo

version: 3
automerge: true
projects:
- name: project1
  dir: project1
  workflow: default
  autoplan:
    when_modified: ["*.tf*", "!import-resources.sh"]
- name: project1-import
  dir: project1
  workflow: import
  autoplan:
    when_modified: ["import-resources.sh"]
- name: project2
  dir: project2
  workflow: default
  autoplan:
    when_modified: ["*.tf*", "!import-resources.sh"]
- name: project1-import
- name: project2-import
  dir: project2
  workflow: import
  autoplan:
    when_modified: ["import-resources.sh"]

With this config, if I only change .tf-files, we run the default-workflow, if import-resources.sh is changed, atlantis will run the import-workflow. Important is the statement !import-resources.sh so we ensure that only one workflow is triggerd and not both.

Let’s assume you want to import this resource in a file called monitoring.tf

resource "rancher2_app_v2" "monitoring" {
  cluster_id = rancher2_cluster.cluster.id
  name = "rancher-monitoring"
  namespace = "cattle-monitoring-system"
  repo_name = "rancher-charts"
  chart_name = "rancher-monitoring"
  chart_version = "100.1.2+up19.0.3"
  values = file("monitoring/values.monitoring.yaml")
}

Then you would add the following line to import-resources:

terraform import rancher2_app_v2.monitoring c-xxxxx.cattle-monitoring-system/rancher-monitoring

The change is contained in the PR…

pullrequest
A PR which contains changes in import-resources.sh

… which then will trigger the import-workload:

build job
Build job for import workflow was triggered

This will trigger the execution of the import-resources.sh-script:

import resource
Execution of the import-resources.sh-script

Conclusion

It works and in my situation, I think it’s a nice solution to accelerate things, cause it makes it easy to import resources, in a transparent way. Is it a good solution? It has it’s flaws, especially if you have to update the PR, you may need manually intervene - mostly cause the script already run once and imported the resources to your state, so for further executions of terraform import will just throw an error. Let me know what you think about in the comments below.