Hi,
I have the following piece of code to be converted from cloudformation to terraform:
Cloudformation
lbdServicesBInfoDurationAlarm:
Type: 'AWS::CloudWatch::Alarm'
Properties:
AlarmName: lbdServicesBInfoDurationAlarm
AlarmDescription: Alarm if elapsed wall clock time is too high
AlarmActions:
- !ImportValue
'Fn::Sub': '${EnvName}CWNotificationTopicARN'
Dimensions:
- Name: FunctionName
Value: !Sub '${lbdServicesBInfoFunctionName}-${EnvName}'**
Namespace: AWS/Lambda
MetricName: Duration
ComparisonOperator: GreaterThanThreshold
EvaluationPeriods: '1'
Period: '300'
Statistic: Sum
Threshold: '30000'
TreatMissingData: missing
Terraform:
resource "aws_cloudwatch_metric_alarm" "lbdServicesBInfoDurationAlarm" {
alarm_name = "lbdServicesBInfoDurationAlarm"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = "1"
metric_name = "Duration"
namespace = "AWS/Lambda"
period = "300"
statistic = "Sum"
threshold = "30000"
alarm_description = "Alarm if elapsed wall clock time is too high"
treat_missing_data = "missing"
insufficient_data_actions = []
}
I am not sure how to convert AlarmActions and Dimensions from CF to TF. Any help will be appreciated.
Hi @Tyroform,
I think the closest equivalent to !ImportValue
in Terraform would be to use a data source to read the data you need. If you are doing a gradual migration where this notification topic ARN will remain in CloudFormation for now then you can directly translate !ImportValue
into a use of the aws_cloudformation_export
data source, which knows how to read an exported value from CloudFormation in the same way that !ImportValue
does:
variable "environment_name" {
type = string
}
data "aws_cloudformation_export" "topic_arn" {
name = "${var.environment_name}CWNotificationTopicARN"
}
resource "aws_cloudwatch_metric_alarm" "lbdServicesBInfoDurationAlarm" {
alarm_name = "lbdServicesBInfoDurationAlarm"
alarm_actions = [data.aws_cloudformation_export.topic_arn.value]
comparison_operator = "GreaterThanThreshold"
evaluation_periods = "1"
metric_name = "Duration"
namespace = "AWS/Lambda"
period = "300"
statistic = "Sum"
threshold = "30000"
alarm_description = "Alarm if elapsed wall clock time is too high"
treat_missing_data = "missing"
insufficient_data_actions = []
}
For Fn::Sub
you don’t really need to do anything particularly special in Terraform, because Terraform interprets all quoted strings as templates supporting interpolation by default. You can see one example of that above in the name
argument in data "aws_cloudformation_export" "topic_arn"
. A similar principle would apply to your dimensions value, using ${var.environment_name}
just as I did above along with some other referenc equivalent to lbdServicesBInfoFunctionName
(but I don’t know what that is in order to make a specific suggestion.)
Another note I would add, since we’re talking about converting from CloudFormation to Terraform anyway, is the more subjective concern of naming conventions. The names you’ve translated directly from CloudFormation are syntactically valid in Terraform, but don’t suit the typical Terraform style conventions. In particular:
-
Names within Terraform conventionally use lowercase letters with underscores separating words, like lbd_services_b_info_duration_alarm
rather than lbdServicesBInfoDurationAlarm
.
This style matches the style that Terraform providers use for the names they declare, and that Terraform itself uses for its built-in language features.
-
Because we always refer to a resource by stating both its type and its name, the name portion typically shouldn’t duplicate nouns from the type.
For example, the “alarm” at the end of lbd_services_b_info_duration_alarm
is redundant because we would only ever use that name as part of the address aws_cloudwatch_metric_alarm.lbd_services_b_info_duration_alarm
. Instead, I’d suggest declaring it as just lbd_services_b_info_duration
, giving the full address aws_cloudwatch_metric_alarm.lbd_services_b_info_duration_alarm
. Note that (unlike in CloudFormation) Terraform resources are uniquely identified by their type and name together, so it’s common and expected to have several resources of different types but the same name within a single module.
Terraform itself (the software) doesn’t enforce either of these, but following these conventions will make your configuration feel more familiar to folks who already have some Terraform experience.
1 Like
Thank you for your valuable feedback @apparentlymart!!!
@shadycuz I got the following error when I try to convert the cloud formation template to terraform script.
% cf2tf lambda_cdk_template.yml
// Converting lambda_cdk_template.yml to Terraform!
existing repo found.
Traceback (most recent call last):
File "/opt/homebrew/bin/cf2tf", line 8, in <module>
sys.exit(cli())
^^^^^
File "/opt/homebrew/lib/python3.11/site-packages/click/core.py", line 1157, in __call__
return self.main(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/homebrew/lib/python3.11/site-packages/click/core.py", line 1078, in main
rv = self.invoke(ctx)
^^^^^^^^^^^^^^^^
File "/opt/homebrew/lib/python3.11/site-packages/click/core.py", line 1434, in invoke
return ctx.invoke(self.callback, **ctx.params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/homebrew/lib/python3.11/site-packages/click/core.py", line 783, in invoke
return __callback(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/homebrew/lib/python3.11/site-packages/cf2tf/app.py", line 44, in cli
config = TemplateConverter(tmpl_path.stem, cf_template, search_manger).convert()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/homebrew/lib/python3.11/site-packages/cf2tf/convert.py", line 92, in convert
tf_resources = self.convert_to_tf(self.manifest)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/homebrew/lib/python3.11/site-packages/cf2tf/convert.py", line 139, in convert_to_tf
tf_resources.extend(converter(resources))
^^^^^^^^^^^^^^^^^^^^
File "/opt/homebrew/lib/python3.11/site-packages/cf2tf/convert.py", line 297, in convert_resources
valid_arguments, valid_attributes = doc_file.parse_attributes(docs_path)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/homebrew/lib/python3.11/site-packages/cf2tf/terraform/doc_file.py", line 15, in parse_attributes
attributes = parse_section("Attributes Reference", file)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/homebrew/lib/python3.11/site-packages/cf2tf/terraform/doc_file.py", line 31, in parse_section
section_location = find_section(name, file)
^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/homebrew/lib/python3.11/site-packages/cf2tf/terraform/doc_file.py", line 111, in find_section
raise Exception()
Exception