1
votes

I have App1, App2, App3, etc. To reuse code, I want to create them using Terraform module.

The common infrastructure called by modules is: root\Common_infra\main.tf:

resource "aws_lambda_function" "app" {
     # count = “${var.should_launch}”
     function_name = "app"
     …
}
resource "aws_cloudwatch_event_rule" "app" {
  name                = " ${var.app_name } "
  schedule_expression = "${var.app_schedule}"
}
resource "aws_cloudwatch_event_target" "app_target" {
  rule      = "${aws_cloudwatch_event_rule.app.name}"
  arn       = "${aws_lambda_function.app.arn}"
  input = <<EOF
{
  "app_name": "${var.app_name}"
}
EOF
}
resource "aws_lambda_permission" "allow_cloudwatch_to_call_lambda"   {
  action        = "lambda:InvokeFunction"
  function_name =     "${aws_lambda_function.app.function_name}"
  principal     = "events.amazonaws.com"
  source_arn    = "${aws_cloudwatch_event_rule.app.arn}"
}
# Other resources each app need to create.

The module for app1 is as follows: root\app1\main.tf:

module "app1" {
  # should_launch = 1
  source  = "../common_infra"
  app_name = "app1"
  schedule = "cron(01 01 ? * * *)"
  ……
}

Using the module, I have successfully launched a cloudwatch event which triggers the lambda at schedule, and I have successfully launched the lambda called “app”. The lambda gets the app_name = app1 as input and then work on app1.

when I create another app2 as follows, root\app2\main.tf:

module "app2" {
  # should_launch = 0
  source = "../common_infra"
  app_name = "app2"
  schedule = "cron(01 01 ? * * *)"
  ……
}

It tries to create another lambda but fails because the lambda has been created by app1 module. In fact I do not want to create a new lambda because It is unnecessary to create multiple lambda for app1, app2…. I can use input = app_name to control what lambda should do.

I try to use should_launch (see above commented lines) to have lambda created only when app1 is created. But it does not work. When deploying app1, the lambda is created. When creating app2. Terrform complains:

aws_cloudwatch_event_target.app_target 

cannot find

arn = "${aws_lambda_function.app.arn}"

My question is: how to organize the layout/structure of my code so that the lambda resource is only declared once for multiple modules? e.g. maybe I should create a new folder root/resource_called_by_all_module/lambda.tf? and then deploy this new folder in advance?

1
Are you asking how to organize your code so that the lambda resource is only declared once in multiple modules, or why it is that one module can declare it and another cannot, or how to organize the code such that the lambda setup is independent of the application specific resources, or something else entirely? You describe the current status quite well, but it is unclear what you are asking since it is unclear what path you want here as the question you literally ask is quite broad.Matt Schuchard
@MattSchuchard: Thanks I have updated my post. I mean what is the right layout/structure of my code for that.user389955

1 Answers

2
votes

Yeah so as you have pointed out, in the current setup all your modules will try to create all the resources in that file individually. Because the name of your lambda is hard-coded, terraform will rightly complain.

If you have a resource that other things are dependent on like that, you can rearrange your terraform to construct that resource on a separate Terraform apply.

So you could take that Lambda resource out of those files, and place it into a separate folder. Then you simply run Terraform apply for those shared resources first ('app' lambda) before the resources that are dependent on them ('app1','app2').

Once the shared resources are created, you can retrieve the details you need from them by using Terraform Data Sources (usually to get names or ARNs).