Using archive_file as a resource is deprecated - terraform

I got this message when I run my terraform script:
Warning: Deprecated Resource
using archive_file as a resource is deprecated; consider using the data source instead
The question is how should I do this? I tried to read about the data source, but it didn't clear anything.
I use archive_file in lambda definition for zipping my lambda source and getting target zip hash.
resource "archive_file" "archive_csv_validate" {
type = "zip"
source_dir = "lambda/csv-validate"
output_path = "artifacts/csv-validate.zip"
}
resource "aws_lambda_function" "lambda_csv_validate_function" {
function_name = "csv-validate"
filename = archive_file.archive_csv_validate.output_path
source_code_hash = archive_file.archive_csv_validate.output_base64sha256
handler = "main.main"
role = aws_iam_role.lambda_iam_role.arn
runtime = "python3.9"
timeout = 900
}

Archive_file is now a data source.
You can transform your code as this:
data "archive_file" "archive_csv_validate" {
type = "zip"
source_dir = "lambda/csv-validate"
output_path = "artifacts/csv-validate.zip"
}
resource "aws_lambda_function" "lambda_csv_validate_function" {
function_name = "csv-validate"
filename = data.archive_file.archive_csv_validate.output_path
source_code_hash = data.archive_file.archive_csv_validate.output_base64sha256
handler = "main.main"
role = aws_iam_role.lambda_iam_role.arn
runtime = "python3.9"
timeout = 900
}

Related

how to set terraform module list variables

as i am a new bot to terraform, i am trying to create lambda permissions to multiple lambda functions using terraform.
main.tf
module "lambda1_s3_events" {
source = "./terraform-aws-modules/lambda/aws"
statement_id = "AllowS3Invoke"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.lambda1.function_name
principal = "s3.amazonaws.com"
source_arn = "arn:aws:s3:::${module.s3_bucket.name}"
}
module "lambda2_s3_events" {
source = "./terraform-aws-modules/lambda/aws"
statement_id = "AllowS3Invoke"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.lambda2.function_name
principal = "s3.amazonaws.com"
source_arn = "arn:aws:s3:::${module.s3_bucket.name}"
}
module "lambda3_s3_events" {
source = "./terraform-aws-modules/lambda/aws"
statement_id = "AllowS3Invoke"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.lambda3.function_name
principal = "s3.amazonaws.com"
source_arn = "arn:aws:s3:::${module.s3_bucket.name}"
}
and instead of creating multiple lambda permission modules as showed above. how can we create this three as one ?
i have tried add three blocks to configure
you can use a for_each meta argument on modules also, similar like resources.
module "lambda1_s3_events" {
source = "./terraform-aws-modules/lambda/aws"
for_each = toset(local.lambda_functions)
statement_id = "AllowS3Invoke"
action = "lambda:InvokeFunction"
function_name = each.value
principal = "s3.amazonaws.com"
source_arn = "arn:aws:s3:::${module.s3_bucket.name}"
}
locals {
lambda_functions = [
aws_lambda_function.lambda1.function_name,
aws_lambda_function.lambda2.function_name,
aws_lambda_function.lambda3.function_name,
## update this list with your lambda function names ##
]
}
you can do a couple of more possibilities with for_each here but I hope you get an idea.
This will enable you to use only one module call but loop over all all lambda functions.
CONSIDERATION: Module support for for_each was added in Terraform 0.13; previous versions can only use it with resources.

Terraform modules azure event subscription optional fields

I am trying to work with terraform modules to create event subscription pointing to storage queue as an endpoint to it.
Below is the module
resource "azurerm_eventgrid_event_subscription" "events" {
name = var.name
scope = var.scope
subject_filter = var.subject_filter
storage_queue_endpoint = var.storage_queue_endpoint
}
and terraform is
module "storage_account__event_subscription" {
source = "../modules/event"
name = "testevent"
scope = test
subject_filter = {
subject_begins_with = "/blobServices/default/containers/test/blobs/in"
}
storage_queue_endpoint = {
storage_account_id = test
queue_name = test
}
}
Error message:
: subject_filter {
Blocks of type "subject_filter" are not expected here.
Error: Unsupported block type
on azure.tf line 90, in module "storage_account__event_subscription":
: storage_queue_endpoint {
Blocks of type "storage_queue_endpoint" are not expected here.
How do i parse the optional fields properly in terraform modules ?
In you module:
resource "azurerm_eventgrid_event_subscription" "events" {
name = var.name
scope = var.scope
subject_filter = {
subject_begins_with = var.subject_begins_with
}
storage_queue_endpoint = var.storage_queue_endpoint
}
Formatting is off here so make sure to run terraform fmt to account for my poor formatting. Also add the variable to the variables.tf file.
Your Terraform file:
module "storage_account__event_subscription" {
source = "../modules/event"
name = "testevent"
scope = test
subject_begins_with = "/blobServices/default/containers/test/blobs/in"
storage_queue_endpoint = {
storage_account_id = test
queue_name = test
}
}
You create the full structure in the module and then you assign the variables in the terraform file.
Anything that will have the same, or generally the same, value can have a default value set in the variables.tf as well so that you get smaller chunks in the TF file.

How to use variable in a interpolated string for the 'endpoint' of 'aws_sns_topic_subscription'?

I want to use a variable for lambda function name. For example:
variable "lambda_function_name" {
default = "my-project-lambda-func"
}
resource "aws_lambda_function" "${var.lambda_function_name}" {
filename = "${data.archive_file.package-zip.output_path}"
function_name = "this_is_a_test"
handler = "lambda_function.simple_handler"
source_code_hash = "${data.archive_file.package-zip.output_base64sha256}"
runtime = "python3.7"
tags = "${var.tags}"
timeout = 300
}
I want to use the variable to create a SNS subscription:
resource "aws_sns_topic_subscription" "call_lambda_by_sns" {
topic_arn = "${module.myproject_event_sns.arn}"
protocol = "lambda"
endpoint = "${aws_lambda_function.${var.lambda_rotate_db_function_name}.arn}"
}
It throws this error when I run terraform validate
Error reading config for
aws_sns_topic_subscription[call_lambda_by_sns]: parse error at 1:23:
expected "}" but found invalid sequence "$"
So I tried an alternative:
resource "aws_sns_topic_subscription" "call_lambda_by_sns" {
topic_arn = "${module.myproject_event_sns.arn}"
protocol = "lambda"
endpoint = "aws_lambda_function.${var.lambda_rotate_db_function_name}.arn"
}
Now the endpoint line causes this error:
Error: Error parsing address 'aws_lambda_function.${var.lambda_rotate_db_function_name}': invalid resource address "aws_lambda_function.${var.lambda_rotate_db_function_name}"
So what is the syntax to allow me to use a variable here?
This can be completed after fixing a few issues
You cannot use an interpolation in a resource name so change
resource "aws_lambda_function" "${var.lambda_function_name}" {
to a hard coded, generic value
resource "aws_lambda_function" "default" {
cannot use interpolation within an interpolation so change
endpoint = "${aws_lambda_function.${var.lambda_rotate_db_function_name}.arn}"
to use the generic name of default from above
endpoint = "${aws_lambda_function.default.arn}"
Working Terraform
variable "lambda_function_name" {
default = "my-project-lambda-func"
}
resource "aws_lambda_function" "default" {
filename = "${data.archive_file.package-zip.output_path}"
function_name = "this_is_a_test"
handler = "lambda_function.simple_handler"
source_code_hash = "${data.archive_file.package-zip.output_base64sha256}"
runtime = "python3.7"
tags = "${var.tags}"
timeout = 300
}
resource "aws_sns_topic_subscription" "call_lambda_by_sns" {
topic_arn = "${module.myproject_event_sns.arn}"
protocol = "lambda"
endpoint = "${aws_lambda_function.default.arn}"
}

using count.index in terraform?

I am trying to generate a bunch of files from templates. I need to replace the hardcoded 1 with the count.index, not sure what format terraform will allow me to use.
resource "local_file" "foo" {
count = "${length(var.files)}"
content = "${data.template_file.tenant_repo_multi.1.rendered}"
#TODO: Replace 1 with count index.
filename = "${element(var.files, count.index)}"
}
data "template_file" "tenant_repo_multi" {
count = "${length(var.files)}"
template = "${file("templates/${element(var.files, count.index)}")}"
}
variable "files" {
type = "list"
default = ["filebeat-config_filebeat.yml",...]
}
I am running with:
Terraform v0.11.7
+ provider.gitlab v1.0.0
+ provider.local v1.1.0
+ provider.template v1.0.0
You can iterate through the tenant_repo_multi data source like so -
resource "local_file" "foo" {
count = "${length(var.files)}"
content = "${element(data.template_file.tenant_repo_multi.*.rendered, count.index)}"
filename = "${element(var.files, count.index)}"
}
However, have you considered using the template_dir resource in the Terraform Template provider. An example below -
resource "template_dir" "config" {
source_dir = "./unrendered"
destination_dir = "./rendered"
vars = {
message = "world"
}
}

Multiple user_data File use in Terraform

I am trying to have a common user_data file for common tasks such as folder creation and certain package install and a separate user_data file for application specific configuration
I am trying the below -
user_data = "${data.template_file.userdata_common.rendered}", "${data.template_file.userdata_master.rendered}"
With these configs -
Common User Data Template
data "template_file" "userdata_common" {
template = "${file("${path.module}/userdata_common.sh")}"
vars {
"ALBTarget" = "${var.ALBTarget}"
"s3bucket" = "${var.s3bucket}"
"centrifydomain" = "${lookup(var.centrifydomain, format("%s-%s", lower(var.env),var.region))}"
"centrifyadgroup" = "${lookup(var.centrifyadgroup, format("%s-%s", lower(var.env),var.region))}"
}
}
Application Specific Config
data "template_file" "userdata_master" {
template = "${file("${path.module}/userdata_master.sh")}"
vars {
"ALBTarget" = "${var.ALBTarget}"
"s3bucket" = "${var.s3bucket}"
"centrifydomain" = "${lookup(var.centrifydomain, format("%s-%s", lower(var.env),var.region))}"
"centrifyadgroup" = "${lookup(var.centrifyadgroup, format("%s-%s", lower(var.env),var.region))}"
}
}
I get the below Error when i do Plan -
Failed to load root config module: Error parsing /terraform/main.tf: key ${data.template_file.userdata_common.rendered}"' expected start of object ('{') or assignment ('=')
Is this possible using Terraform (0.9.3)?
If not, what's the best way to do this with Terraform?
Did you try template_cloudinit_config?
Add below codes.
data "template_cloudinit_config" "master" {
gzip = true
base64_encode = true
# get common user_data
part {
filename = "common.cfg"
content_type = "text/part-handler"
content = "${data.template_file.userdata_common.rendered}"
}
# get master user_data
part {
filename = "master.cfg"
content_type = "text/part-handler"
content = "${data.template_file.userdata_master.rendered}"
}
}
# sample code to use it.
resource "aws_instance" "web" {
ami = "ami-d05e75b8"
instance_type = "t2.micro"
user_data = "${data.template_cloudinit_config.master.rendered}"
}
Let me know if it works.
You can use "provisioner" to modify the infrastructure you are creating using the Terraform, Here is the example from them https://www.terraform.io/intro/getting-started/provision.html

Resources