Terraform: Migrate from template_file Data Sources

Overview

I stumbled across this problem when using a new MacBook Pro M1 CPU. I had some legacy code that used aws_template for a user data script. The template function is now deprecated, and the only way around this is to use the templatefile a function that was introduced in Terraform 0.12.

This is simple for the new code, but if, like me, you have legacy code that is still embedded into production, you will have issues.

This is the error I was getting:

ShellScript
template v2.2.0 does not have a package available for your current platform, darwin_arm64

There are many suggested fixes online, but they just fix the issue locally. It doesn’t fix the issue in the code and the terraform state files (mine are located in S3)

Migrating

Locate current usage

To begin, you can check to see what requires this provider in your current code – in the below example, you can see that the template provider is required by both resources in module.jenkins and the state:

Please note that I use AWS-Vault to access my cloud resources.

ShellScript
aws-vault exec <my-aws-profile> --no-session -- terraform providers

ShellScript
Providers required by configuration: . 
โ”œโ”€โ”€ provider[registry.terraform.io/hashicorp/aws] 
โ”œโ”€โ”€ provider[registry.terraform.io/opsgenie/opsgenie] 0.6.10 
โ”œโ”€โ”€ provider[terraform.io/builtin/terraform] 
โ””โ”€โ”€ module.jenkins 
โ”œโ”€โ”€ provider[registry.terraform.io/hashicorp/random] 
โ”œโ”€โ”€ provider[registry.terraform.io/hashicorp/template] 
โ”œโ”€โ”€ provider[registry.terraform.io/hashicorp/aws] 
โ”œโ”€โ”€ module.codebuild_label 
โ”‚ โ””โ”€โ”€ provider[registry.terraform.io/hashicorp/aws] 
โ”œโ”€โ”€ module.iam_label 
โ”‚ โ””โ”€โ”€ provider[registry.terraform.io/hashicorp/aws] 
โ”œโ”€โ”€ module.s3_label 
โ”‚ โ””โ”€โ”€ provider[registry.terraform.io/hashicorp/aws] 
โ”œโ”€โ”€ module.security_label 
โ”‚ โ””โ”€โ”€ provider[registry.terraform.io/hashicorp/aws] 
โ”œโ”€โ”€ module.slaves_label 
โ”‚ โ””โ”€โ”€ provider[registry.terraform.io/hashicorp/aws] 
โ”œโ”€โ”€ module.network_label 
โ”‚ โ””โ”€โ”€ provider[registry.terraform.io/hashicorp/aws] 
โ”œโ”€โ”€ module.ec2_label 
โ”‚ โ””โ”€โ”€ provider[registry.terraform.io/hashicorp/aws] 
โ”œโ”€โ”€ module.lb_label 
โ”‚ โ””โ”€โ”€ provider[registry.terraform.io/hashicorp/aws] 
โ”œโ”€โ”€ module.log_label 
โ”‚ โ””โ”€โ”€ provider[registry.terraform.io/hashicorp/aws] 
โ”œโ”€โ”€ module.api_integration_autoscaling 
โ”‚ โ””โ”€โ”€ provider[registry.terraform.io/opsgenie/opsgenie] 0.6.10 
โ”œโ”€โ”€ module.jenkins_alert_poli
โ”‚ โ””โ”€โ”€ provider[registry.terraform.io/opsgenie/opsgenie] 0.6.10
โ”œโ”€โ”€ module.certs_label 
โ”‚ โ””โ”€โ”€ provider[registry.terraform.io/hashicorp/aws]
โ””โ”€โ”€ module.api_integration_cloudwatch #
โ””โ”€โ”€ provider[registry.terraform.io/opsgenie/opsgenie] 
0.6.10 Providers required by state:  provider[registry.terraform.io/opsgenie/opsgenie]  provider[registry.terraform.io/hashicorp/aws]  provider[registry.terraform.io/hashicorp/random]  provider[registry.terraform.io/hashicorp/template]  provider[terraform.io/builtin/terraform]

Removing Current usage

Search for all instances of the template_file data resource and replace it with a template file function – for example, this CloudWatch dashboard changes

From This:

ShellScript
data "template_file" "dashboard" { 
template = file("${path.module}/templates/dashboard.template")
resource "aws_cloudwatch_dashboard" "jenkins" {
dashboard_name = "Jenkins" dashboard_body = data.template_file.dashboard.rendered
}
}

To This:

ShellScript
resource "aws_cloudwatch_dashboard" "jenkins" { 
dashboard_name = "Jenkins" 
dashboard_body = templatefile("${path.module}/templates/dashboard.template", {})
}

Full details of how to use the function, and pass variables, can be found here

Now, if you check the providers again, you should see that the modules are no longer listing template as a required provider – however, the state does:

ShellScript
aws-vault exec <my-aws-profile> --no-session -- terraform providers

ShellScript
Providers required by configuration: . 
โ”œโ”€โ”€ provider[registry.terraform.io/opsgenie/opsgenie] 0.6.10 
โ”œโ”€โ”€ provider[registry.terraform.io/hashicorp/aws] 
โ”œโ”€โ”€ provider[terraform.io/builtin/terraform] 
โ””โ”€โ”€ module.jenkins 
โ”œโ”€โ”€ provider[registry.terraform.io/hashicorp/aws] 
โ”œโ”€โ”€ provider[registry.terraform.io/hashicorp/random] 
โ”œโ”€โ”€ module.network_label 
โ”‚ โ””โ”€โ”€ provider[registry.terraform.io/hashicorp/aws] 
โ”œโ”€โ”€ module.certs_label 
โ”‚ โ””โ”€โ”€ provider[registry.terraform.io/hashicorp/aws] 
โ”œโ”€โ”€ module.codebuild_label 
โ”‚ โ””โ”€โ”€ provider[registry.terraform.io/hashicorp/aws] 
โ”œโ”€โ”€ module.ec2_label 
โ”‚ โ””โ”€โ”€ provider[registry.terraform.io/hashicorp/aws] 
โ”œโ”€โ”€ module.iam_label 
โ”‚ โ””โ”€โ”€ provider[registry.terraform.io/hashicorp/aws] 
โ”œโ”€โ”€ module.api_integration_autoscaling 
โ”‚ โ””โ”€โ”€ provider[registry.terraform.io/opsgenie/opsgenie] 0.6.10
โ”œโ”€โ”€ module.api_integration_cloudwatch 
โ”‚ โ””โ”€โ”€ provider[registry.terraform.io/opsgenie/opsgenie] 0.6.10 
โ”œโ”€โ”€ module.slaves_label 
โ”‚ โ””โ”€โ”€ provider[registry.terraform.io/hashicorp/aws] 
โ”œโ”€โ”€ module.jenkins_alert_policy 
โ”‚ โ””โ”€โ”€ provider[registry.terraform.io/opsgenie/opsgenie] 0.6.10 
โ”œโ”€โ”€ module.s3_label 
โ”‚ โ””โ”€โ”€ provider[registry.terraform.io/hashicorp/aws] 
โ”œโ”€โ”€ module.security_label 
โ”‚ โ””โ”€โ”€ provider[registry.terraform.io/hashicorp/aws] 
โ”œโ”€โ”€ module.log_label #
โ”‚ โ””โ”€โ”€ provider[registry.terraform.io/hashicorp/aws] 
โ””โ”€โ”€ module.lb_label 
โ””โ”€โ”€ provider[registry.terraform.io/hashicorp/aws] 
Providers required by state:  provider[registry.terraform.io/opsgenie/opsgenie]  
provider[registry.terraform.io/hashicorp/aws]  provider[registry.terraform.io/hashicorp/random]  provider[registry.terraform.io/hashicorp/template]  provider[terraform.io/builtin/terraform]

Update State

Apply the Terraform and (assuming you got your code correct!) you should see that there were no changes to apply – this is because the template should be the same, just the method of generating it has changed:

ShellScript
aws-vault exec <my-aws-profile>  --no-session -- terraform apply ... No changes. 

Your infrastructure matches the configuration. Your configuration already matches the changes detected above. If you'd like to update the Terraform state to match, create and apply a refresh-only plan: terraform apply -refresh-only Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

After you successfully apply, you should refresh the state:

ShellScript
aws-vault exec <my-aws-profile> --no-session -- terraform apply -refresh-only .... No changes. Your infrastructure still matches the configuration. Terraform has checked that the real remote objects still match the result of your most recent changes, and found no differences. Would you like to update the Terraform state to reflect these detected changes? Terraform will write these changes to the state without modifying any real infrastructure. There is no undo. Only 'yes' will be accepted to confirm.  Enter a value: yes  Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Now when you check, you will see that the provider is no longer needed by the state either:

ShellScript
Providers required by state:  provider[terraform.io/builtin/terraform]  provider[registry.terraform.io/opsgenie/opsgenie]  provider[registry.terraform.io/hashicorp/aws]  provider[registry.terraform.io/hashicorp/random]

At this point, you can remove the .terraform directory and re-init the code (terraform init -reconfigure) – all the modules and providers (now excluding the template provider) will be installed and the .terraform.lock.hcl will have its entry for the template provider removed.

At this point, you can commit your code back to git.

Elsewhere On TurboGeek:  How to Structure Your Terraform Code

Richard.Bailey

Richard Bailey, a seasoned tech enthusiast, combines a passion for innovation with a knack for simplifying complex concepts. With over a decade in the industry, he's pioneered transformative solutions, blending creativity with technical prowess. An avid writer, Richard's articles resonate with readers, offering insightful perspectives that bridge the gap between technology and everyday life. His commitment to excellence and tireless pursuit of knowledge continues to inspire and shape the tech landscape.

You may also like...

2 Responses

  1. some person says:

    How about providing some complete examples? Where are the closing brackets for your example functions and data resources?

Leave a Reply

Your email address will not be published. Required fields are marked *

Translate ยป