Mike Henderson
Mike Henderson

Reputation: 2142

How to automatically import resource to Terraform state?

I want to develop a single Terraform module to deploy my resources, with the resources being stored in separate YAML files. For example:

# resource_group_a.yml
name: "ResourceGroupA"
location: "westus"

# resource_group_b.yml
name: "ResourceGroupB"
location: "norwayeast"

And the following Terraform module:

# deploy/main.tf

variable source_file {
  type = string # Path to a YAML file
}

locals {
  rg = yamldecode(file(var.source_file))
}

resource "azurerm_resource_group" "rg" {
  name     = local.rg.name
  location = local.rg.location
}

I can deploy the resource groups with:

terraform apply -var="source_file=resource_group_a.yml"
terraform apply -var="source_file=resource_group_b.yml"

But then I run into 2 problems, due to the state that Terraform keeps about my infrastructure:

A resource with the ID "/..." already exists - to be managed via Terraform
this resource needs to be imported into the State.

  with azurerm_resource_group.rg,
  on main.tf line 8 in resource "azurerm_resource_group" "rg"

I can import the resource into my state with

terraform import azurerm_resource_group.reg "/..."

But it's a long file and there may be multiple resources that I need to import.


So my questions are:

Upvotes: 1

Views: 7327

Answers (2)

David
David

Reputation: 67

I came up with a powershell script to do this, not the most refined, but it works:

$maxAttempts = 3
$attempt = 0

function Run-TerragruntApply {
    Write-Host "Running apply: you must manually confirm to avoid resources being modified or deleted"
    $tempFile = [System.IO.Path]::GetTempFileName()
    Start-Transcript -Path $tempFile -Append
    #Invoke-Expression "terragrunt apply"
    #Start-Process terragrunt -ArgumentList "apply" -NoNewWindow -PassThru -Wait
    terragrunt apply 2>&1 | Write-Host
    Stop-Transcript
    Write-Host "Apply finished..."
    $output = Get-Content $tempFile -Raw
    Remove-Item $tempFile -Force
    return $output
}

function Extract-Resources {
    param (
        [string[]]$output
    )
    
    $pattern = "A resource with the ID `"([^`"]+)`"[^,]+with (.*),"
    $matches = $output | Select-String -Pattern $pattern -AllMatches
    
    $resourceMappings = @()
    foreach ($match in $matches.Matches) {
        $terraformResource = $match.Groups[2].Value.Trim()
        $azureResourceId = $match.Groups[1].Value.Trim()
        $resourceMappings += @{ terraform = $terraformResource; azure = $azureResourceId }
    }
    return $resourceMappings
}

function Import-Resources {
    param (
        [array]$resourceMappings
    )
    
    foreach ($mapping in $resourceMappings) {
        Write-Host "Importing resource: $($mapping.terraform) -> $($mapping.azure)"
    }
    $confirmation = Read-Host "Are you sure you want to continue? (Y/N)"
    if ($confirmation -match "^[Yy]") {
        Write-Host "Continuing..."
    }
    else {
        Write-Host "Moving on"
        exit
    }

    foreach ($mapping in $resourceMappings) {
        Write-Host "Importing resource: $($mapping.terraform) -> $($mapping.azure)"
        & terragrunt import $mapping.terraform $mapping.azure
    }
}

Write-Host "Starting Terragrunt Apply with auto-import logic..."
while ($attempt -lt $maxAttempts) {
    $attempt++
    Write-Host "Attempt #$attempt"
    
    $output = Run-TerragruntApply
    
    $resourceMappings = Extract-Resources -output $output
    if ($resourceMappings.Count -gt 0) {
        Import-Resources -resourceMappings $resourceMappings
    }
    else {
        Write-Host "No more import errors detected. Exiting."
        break
    }
}

Write-Host "Terragrunt Apply completed."

Upvotes: 0

Mark B
Mark B

Reputation: 201138

How to keep the state separate between the two resource groups?

I recommend using Terraform Workspaces for this, which will give you separate state files, each with an associated workspace name.

How to automatically import existing resources when I run terraform apply?

That's not currently possible. There are some third-party tools out there like Terraformer for accomplishing automated imports, but in my experience they don't work very well, or they never support all the resource types you need. Even then they wouldn't import resources automatically every time you run terraform apply.

Upvotes: 1

Related Questions