Reputation: 2142
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:
.tfstate
file prior to running apply
, and the resource group already exists, I get an error: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:
terraform apply
?Upvotes: 1
Views: 7327
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
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