Cloudformation sub function for cloudwatch dashboard body - amazon-web-services

I'm running into issues using the !Sub intrinsic cloudformation function with AWS::Region pseudoparameter within the body of my cloudwatch dashboard (to ensure my stack is region agnostic). The cloudformation I am using is given below
OrderDashboard:
Type: AWS::CloudWatch::Dashboard
Properties:
DashboardBody: !Sub '{ "widgets": [ { "type": "metric", "x": 6, "y": 0, "width": 6, "height": 6, "properties": { "metrics": [ [ "address", "validateAddressApiLatency" ] ], "view": "timeSeries", "stacked": false, "region": "${AWS::Region}", "title": "ValidateAddressApiSuccessLatencyP99", "period": 300, "stat": "p99" } }, { "type": "metric", "x": 12, "y": 0, "width": 8, "height": 6, "properties": { "metrics": [ [ "address", "validateAddressApiErrorLatency" ] ], "view": "timeSeries", "stacked": false, "region": "${AWS::Region}", "title": "ValidateAddressApiErrorLatencyP99", "period": 300, "stat": "p99" } }, { "type": "text", "x": 0, "y": 0, "width": 6, "height": 6, "properties": { "markdown": "# Heading \nThis dashboard exists to show that our success latency metric and error latency metric are published successfully using a single annotation and aspectj.\n\nThe first row shows the 99th percentile latencies, and the bottom column shows the count of the number of calls" } }, { "type": "metric", "x": 6, "y": 6, "width": 6, "height": 6, "properties": { "metrics": [ [ { "expression": "SELECT COUNT(validateAddressApiLatency) FROM SCHEMA(address)", "label": "NumberOfSuccessfulCalls", "id": "q1", "region": "${AWS::Region}" } ] ], "view": "timeSeries", "stacked": false, "region": "${AWS::Region}", "stat": "Average", "period": 300, "title": "NumberOfSuccessfulValidateCalls" } }, { "type": "metric", "x": 12, "y": 6, "width": 6, "height": 6, "properties": { "metrics": [ [ { "expression": "SELECT COUNT(validateAddressApiErrorLatency) FROM SCHEMA(address)", "label": "NumberOfErroredCalls", "id": "q1", "region": "${AWS::Region}" } ] ], "view": "timeSeries", "stacked": false, "region": "${AWS::Region}", "stat": "Average", "period": 300, "title": "NumberOfErrorValidateCalls" } } ]}'
DashboardName: order-dashboard
When I deploy the dashboard, the region is not substituted
The interesting thing is I use sub with the region parameter other places in the template, it works.
Outputs:
OrderApiUrl:
Description: "The endpoint you can use to place orders. Make sure to append the order id to the end"
Value: !Sub "https://${OrderApi}.execute-api.${AWS::Region}.amazonaws.com/v1/orders/"
Any idea on what I can do to get the value substituted? Thanks

I agree with #ErikAsplund, something like:
OrderDashboard:
Type: AWS::CloudWatch::Dashboard
Properties:
DashboardName: order-dashboard
DashboardBody: !Sub |
{
"widgets": [
{
"properties": {
"metrics": [
"AWS/Lambda",
"Duration",
"FunctionName",
"${MyReference}"
]
}
}
}

The code that you provided works perfectly fine. Thus the issue that you have must be related to other factors than your CloudFormation code in the question.
Maybe you are using some other code, not the one in the question.

Related

How do I use aggregates in grouped marks?

I'm trying to use the min and max aggregates of a quantitative column (Total bombers) grouped by another column (Country) in a rule mark of my visual. I want the rule y property to start at the minimum value of Total bombers and the rule y2 property to end at the maximum value of total bombers, but I can't seem to find the right syntax for the min and max aggregates of the rule mark. I can get the result I'm looking for by not grouping the marks but I would like to implement it for grouped marks so I can re-use it more easily.
Spec for grouped version I'm trying to use min and max aggregates in:
https://vega.github.io/editor/#/url/vega/N4IgJAzgxgFgpgWwIYgFwhgF0wBwqgegIDc4BzJAOjIEtMYBXAI0poHsDp5kTykSArJQBWENgDsQAGhAATONABONHJnaT0AQQAETJBBpRtAGxri422EkWZtcAB5IEOY3ErSQAdxqz6aAQAMATLwNGRYaABMQTI4SLKyZmT+MgZk4kjGEGgA2gC6MrJImCioOaAZCHBoIExsCExwitkyDIrGNVi4+ES0EJjUdIxMDBBNUBKYcOIDEwgkssRsbIryigQCTADMAQCcuwDssgAcBwHHCUgHx1tMTJFMuwKykXC7cABmWwAsBIpIngIACF6o1FABSSICaIAcSQOEoUAgxA8HxWyEwaFAmAAnjhqugkSjYtYxliQAAVNglYy6UFNbLocQMBpNDwATTg1hqzNZihAAF8BTJMP9xBA0YoELlsXiCSBJQgGMYUDJ9DUilMPA4cPz0GoqgAKTVwA1wY3FFmUTnWKTaACMdvtAEpnYKpLL8TUPjRjFN+TIdXq5JaENauYptAAeAC8Dt2xwCgryAoKIGgmQUMpAlXl9g8uK9+poVQ8YrI8u8vhgHlk9SQZnJmtKtXpzVRNDgxlkGuK1SFHpzTnlOILcpqpnM3Jk5floXCmJk4kMBNFDDgMgAXk02Gg1xu5PXG6hQM2anU+S0FZ3uzUqTS6ZfBcKKsOahNjCsx0WQCtEhkOhnJBxArd8+zIFZR0KI8NFPYoWwvMErx9Lse3QABhNgGBmRRRyFNMkHsLMylAFZOxmc9qUweoPAzVwanzF9f2UaZMXQVwPkXdMoEzGo8LTZBFAAa0ZcoQELeUyEULCcFRaTpRPBUkCgU1yVzGoxhYq8z3QRCGQ8KSZKYUcMKwnC8OFEBBJE7N5CUFQ1AkGoABkzAsSU7CWYwGEc8RtDYD5tGoh89OaXQcUsMzRSg8Tx3Yty5JoxSdPTJpO2ySzpgmeRyVYtlFPzRS6LzDtUN7LVLJM0Bir40rb3Qe9MkfJD3XTUU2CEglqp4+jCTYT8A2vMrTOw6LWv6aTOvQ+FyWITJ1xqaTsJ7SyJo6uAAHUfD8RS5u8gktlW9rOoAeTiKA6CqkA9oW1AAkoAQhQHU8FCgZRVHUGoAAU2DMTAIG0Dzgqa0KAeMyLRtw795QgHEGn6xKFLgkoNLSrNMvEbKupAPK9VAQrut49B8xkFD6pDCqZCumr0Bism0MpakQbbDLUhobdZvmglAksn1jA6IqevlD8v1Jm8GcwyG8NSY7Nu2mtdq5qIAiOybsZu+VTAXCAhJxJh9ufVocBNck+eMM7lMuzmDdQe1VfWi2Ltxa3bpVyyYDYUg8batXHatxWbbtp7Bzst6HM+9AACVlQZXRTU8OBpgh8ygqZ2lQu0XkWpFOKQEUGPEabeDUa01qsrYHLFIYY2+3JAnuKJkASaG8mTcq8kaZAOnxbvNPmv0yrIhdglohVmW1eHicwiwHW9YN+3Oq26tJ9QQ7x4d87-dADW0Hux6npTFMgA
Spec for non-grouped version that achieves what I want to do:
https://vega.github.io/editor/#/url/vega/N4IgJAzgxgFgpgWwIYgFwhgF0wBwqgegIDc4BzJAOjIEtMYBXAI0poHsDp5kTykSArJQBWENgDsQAGhAATONABONHJnaT0AQQAETJBBpRtAGxri422EkWZtcAB5IEOY3ErSQAdxqz6aAQAMATLwNGRYaABMQTI4SLKyZmT+MgZk4kjGEGgA2gC6MrJImCioOaAZCHBoIExsCExwitkyDIrGNVi4+ES0EJjUdIxMDBBNUBKYcOIDEwgkssRsbIryigQCTADMAQCcuwDssgAcBwHHCUgHx1tMTJFMuwKykXC7cABmWwAsBIpIngIACF6o1FABSSICaIAcSQOEoUAgxA8HxWyEwaFAmAAnjhqugkSjYtYxliQAAVNglYy6UFNbLocQMBpNDwATTg1hqzNZihAAF8BTJMP9xBA0YoELlsXiCSBJQgGMYUDJ9DUilMPA4cPz0GoqgAKTVwA1wY3FFmUTnWKTaACMdvtAEpnYKpLL8TUPjRjFN+TIdXq5JaENauYptAAeAC8Dt2xwC7s98pwNCWmJkZEUbAYOCYONyIBt-IKCpocGMshqAGFczNFIWZMRMgx5VSaXS+dlhSnvejlaqQOr0CbtfZdTUzRaptPNVaS06na7kyBcV70IrBx4R5TqZku2CWiAgxrQzkAOQAZTYxArtgAquJ1Be8toANTaecIS9PuhwWRtCvEopggV9BTyXsQEqeU4FIGZjxbYw20ZcoQAAOSceUhxLNB7SeSIZAAEQUKBlFUdQagAGRWRBtBUCAWVXTCqhqJgOQjPDdgANmCEASKUFQ1AkGoAEk8BZExaOlAUy1FJBxUVGU1zlfspW3NVGRDLVAwnYM52KU0aCNb9w1tB1lzdWTZNSKBMgUZSYJqewPHXeUzQ8MUyHlbxfBgDxZHqJAzHJTVSlqelmlRCsqzPLUhQ9aCsJqJsVI3EBTHMbkZC8+VQnCTNoMMAlRTbGQAC8mjYNBSrgQogpC1BQDCtjIuPH1K2rdAOwPOpu0FKCnMJNhjBWVzVPQFZEgyDocoU7yajsqYyBWVLAuQRrmuKcK+qPaLOtretRULIUyyQewHLKUAVgrGZWuweoPGgeznNXG7pkxdBXA+QrntcFKIJkZBFAAa1Q5rSPI4SNBAKizAsSU7CWZDoe0NgPm0B8r0PBlxvSzLqhkD4c2lJrtJ2tr3RPcQJnkckPrZMmXLJv75RcomYq67TqmFEBCxZuz-vQVKOti9A-ymQDgMMntUlFNgQbgGt4XJJC2xqHMGHEatef6HNFYAdR8PwybVgktl1+XFYAeTiKA6H50AzbQAJKAEIUEohwSKJE9AAAU2DMTAIG0RGsZxqKRQmkAIBxBoRtREnQu21r+t56ZaYJUAGb1UBmdAVnXo5g7R0MqnHZjwX5RFzmaglgCgJAhzdZoSrVdbAlAl5n1jA6AWXuG0aA3LEuQDrLXjqpvWFbgI2-Pb5CCWiS39azkBna+sIsAgEGcSYReBtaHAxzJnvjFtpB7dxBf1dQe0V5ni+r4rjeAgSjBb0ZgurbgJ+HZvgk98PaJXkN7aG1F4ahxWEjEaDBUboyAree8EdjxuRqATROj0yYtXQLtXG6caZsDpmTHO5J86VwHiAdmI8xbc3LuSQuwt9q0JvHeU0mNnwiQforZWOAAEa3rDrOWq854mydh3NAFthGPztv-U2EjUCu3dsAr2ZEhKUX9oHBCUDIysOQXgyOaV5Sx3jrNBUSdsEp1wZTAhmd6YzC-lQhhVci40K5mOXmFdGF82YVzPR7C-xcNSK3NeG8u4c17s4yhEwh6+MOhPRsU8f6iP8vIg+qBl7SMVvwzeBUd57wPu-PMJ9QBnz-tfNJt975ZN-rIip4j0lv15jAT+ucY4-3KS-BRQDPZGI1sqQm5isFbRKKnPatiiFr1IUzKJQsnHF1oR4mQXiXFMIWX4pBATOGSE8ZEWZ1c4ni2fJLRuMsp4hJyeE8skT+5zJiWNdZ8SGwnRqSky53DQkKIylvYOu997qyKcfMup9fTnzqV09J1T2mr06Tk12FtmmtIYR08FOSenWSAA
Any help much appreciated!
What you're trying to do isn't logically possible. You have faceted on country. That means each country gets a line (working), a symbol (working) but how would it get a rule where the start point is one country and the end point is the other. One group does not know anything about the other group so you couldn't have a rule spanning the two countries.
If you want to keep your facet, you can do the following:
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"description": "A basic line chart example.",
"width": 500,
"height": 200,
"padding": 5,
"signals": [],
"data": [
{
"name": "bombers",
"url": "https://gist.githubusercontent.com/vdvoorder/5b30997d8708dda783bb2b95d2e9ef34/raw/Bomber%2520Gap.csv",
"format": {
"type": "csv",
"parse": {"Total bombers": "number", "Year": "number"}
},
"transform": [
{
"type": "formula",
"as": "date",
"expr": "time(datetime(datum.Year, 1, 1))"
},
{"type": "filter", "expr": "datum.Year <= 1980"}
]
},
{
"name": "bombers2",
"source": "bombers",
"transform": [
{
"type": "pivot",
"field": "Country",
"value": "Total bombers",
"groupby": ["date"]
}
]
}
],
"scales": [
{
"name": "x",
"type": "time",
"range": "width",
"domain": {"data": "bombers", "field": "date"}
},
{
"name": "y",
"type": "linear",
"range": "height",
"nice": true,
"zero": true,
"domain": {"data": "bombers", "field": "Total bombers"}
},
{
"name": "color",
"type": "ordinal",
"range": "category",
"domain": {"data": "bombers", "field": "Country"}
}
],
"axes": [
{"orient": "bottom", "scale": "x"},
{"orient": "left", "scale": "y"}
],
"marks": [
{
"type": "group",
"from": {
"facet": {"name": "series", "data": "bombers", "groupby": "Country"}
},
"marks": [
{
"description": "Line for evolution of total bombers by country",
"type": "line",
"from": {"data": "series"},
"encode": {
"enter": {
"x": {"scale": "x", "field": "date"},
"y": {"scale": "y", "field": "Total bombers"},
"stroke": {"scale": "color", "field": "Country"},
"strokeCap": {"value": "round"},
"strokeWidth": {"value": 3},
"strokeOpacity": {"value": 0.5}
}
}
},
{
"description": "Points for total bombers by country",
"type": "symbol",
"from": {"data": "series"},
"encode": {
"enter": {
"x": {"scale": "x", "field": "date"},
"y": {"scale": "y", "field": "Total bombers"},
"size": {"value": 50},
"fill": {"scale": "color", "field": "Country"},
"strokeWidth": {"value": 20},
"stroke": {"value": "lightskyblue"}
},
"update": {
"fillOpacity": {"value": 1},
"strokeOpacity": {"value": 0}
},
"hover": {"strokeOpacity": {"value": 1}}
}
}
]
},
{
"description": "Rulers between country total bomber numbers",
"type": "rule",
"from": {"data": "bombers2"},
"encode": {
"update": {
"x": {"scale": "x", "field": "date"},
"y": {"scale": "y", "field": "Soviet Union"},
"y2": {"scale": "y", "field": "United States"},
"stroke": {"value": "lightskyblue"},
"strokeWidth": {"value": 3},
"strokeOpacity": {"value": 0.5}
}
}
}
]
}

Cannot add widget to AWS Cloudwatch Dashboard

I am trying to configure an existing AWS Dashboard with adding one new widget.
In Amazon Kinesis / Analytics application / Streaming application I click on the graphs 'View in metrics" of which I would like to add to my dashboard
In the next screen I click Actions / Add to dashboard
after selecting my dashboard I click add, and then I can see my dashboard with the chart:
However, if I click on "Save" I get the following error:
There was an error while trying to save your dashboard:
The dashboard body is invalid, there are 6 validation errors: [
{ "dataPath": "/widgets/5/properties/metrics/0", "message": "Should NOT have more than 4 items" },
{ "dataPath": "/widgets/5/properties/metrics/1", "message": "Should NOT have more than 4 items" },
{ "dataPath": "/widgets/5/properties/yAxis/left", "message": "Should be null" },
{ "dataPath": "/widgets/5/properties/yAxis/left", "message": "Should match some schema in anyOf" },
{ "dataPath": "/widgets/5/properties/yAxis/right", "message": "Should be null" },
{ "dataPath": "/widgets/5/properties/yAxis/right", "message": "Should match some schema in anyOf" } ]
I am totally clueless, as I did not enter anything manually, all I done was just clicking on the menu items. What is the problem here? I don't even understand the error messages even. I have 4 logs, and 1 chart already on the screen, this would be the 6th item if that is important.
Update: adding the source code of the template (I censored some sensitive information with "......."):
{
"widgets": [
{
"height": 6,
"width": 24,
"y": 12,
"x": 0,
"type": "log",
"properties": {
"query": "SOURCE '/aws/kinesis-analytics/.......' | fields #timestamp, message | filter applicationARN like /arn:aws:kinesisanalytics:eu-west-1:......./| filter messageType = \"ERROR\"| sort #timestamp desc",
"region": "eu-west-1",
"title": "Error log (last 1000 records)",
"view": "table"
}
},
{
"height": 6,
"width": 24,
"y": 6,
"x": 0,
"type": "log",
"properties": {
"query": "SOURCE '/aws/kinesis-analytics/.......' | fields #timestamp, message | filter applicationARN like /arn:aws:kinesisanalytics:eu-west-1:......./| sort #timestamp desc",
"region": "eu-west-1",
"title": "Full log (last 1000 records)",
"view": "table"
}
},
{
"height": 6,
"width": 24,
"y": 18,
"x": 0,
"type": "log",
"properties": {
"query": "SOURCE '/aws/kinesis-analytics/.......' | fields #timestamp, message | filter applicationARN like /arn:aws:kinesisanalytics:eu-west-1:......./| filter message like / OEE Data Streaming app v / | sort #timestamp desc",
"region": "eu-west-1",
"title": "Version - works only right after deployment, othervise look at the name of the jar file :) ",
"view": "table"
}
},
{
"height": 6,
"width": 24,
"y": 0,
"x": 0,
"type": "log",
"properties": {
"query": "SOURCE '/aws/kinesis-analytics/.......' | fields #timestamp, message | filter applicationARN like /arn:aws:kinesisanalytics:eu-west-1:338785721659:.......") | sort #timestamp desc",
"region": "eu-west-1",
"stacked": false,
"title": "OEE app inside logs",
"view": "table"
}
},
{
"height": 6,
"width": 6,
"y": 24,
"x": 0,
"type": "metric",
"properties": {
"region": "eu-west-1",
"yAxis": {
"left": {
"min": 0
}
},
"metrics": [
[ "AWS/Kinesis", "GetRecords.Records", "StreamName", ".......", { "id": "m3", "visible": true } ]
],
"stat": "Sum",
"title": "GetRecords - .......",
"start": "-PT3H",
"end": "P0D",
"view": "timeSeries",
"stacked": false
}
}
]
}
and if I try to add the uptime widget, it's code is this :
{
"type": "metric",
"x": 6,
"y": 24,
"width": 6,
"height": 6,
"properties": {
"region": "eu-west-1",
"yAxis": {
"left": {
"min": 0,
"stat": "Maximum",
"showUnits": false
},
"right": {
"min": 0,
"stat": "Maximum",
"showUnits": false
}
},
"metrics": [
[ "AWS/KinesisAnalytics", "uptime", "Application", "...", { "yAxis": "left", "label": "uptime", "stat": "Maximum", "showUnits": false } ],
[ ".", "fullRestarts", ".", ".", { "yAxis": "right", "label": "fullRestarts", "stat": "Maximum", "showUnits": false } ]
],
"stat": "Maximum",
"title": "Uptime (Milliseconds) - Maximum",
"start": "-PT3H",
"end": "P0D",
"view": "timeSeries",
"stacked": false
}
}
but I cannot save it now with the error message I described earlier.
Looks like the properties on axis definition and metric definition are mixed up.
Axis should not have the stat property: https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/CloudWatch-Dashboard-Body-Structure.html#CloudWatch-Dashboard-Properties-YAxis-Properties-Format
Metric definition should not have the showUnits property: https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/CloudWatch-Dashboard-Body-Structure.html#CloudWatch-Dashboard-Properties-Rendering-Object-Format
Try removing the stat property from both left and right axis definition. Also remove the showUnits property from the metrics definition (that should only be on the axis definitions).
If this was generated automatically, then it looks like a bug in the console.

How can i include all the widgets for a particular resource (eg:ec2, ebs) in the dashboard at AWS cloudwatch using terraform

I created terraform file to create dashboard in AWS cloudwatch.
here is my sample file to create dashboard
// provider module
provider "aws"{
access_key = var.access_key
secret_key = var.secret_key
region = var.region
}
// cloudwatch dashboard module
resource "aws_cloudwatch_dashboard" "main" {
dashboard_name = var.dashboard_name
dashboard_body = <<EOF
{
"widgets": [
{
"type": "metric",
"x": 0,
"y": 0,
"width": 12,
"height": 6,
"properties": {
"metrics": [
[
"AWS/EBS",
"VolumeReadOps",
"VolumeId",
"vol-04b26d88efe8ecd54"
]
],
"period": 300,
"stat": "Average",
"region": "ap-south-1",
"title": "VolumeRead"
}
},
{
"type": "metric",
"x": 0,
"y": 0,
"width": 12,
"height": 6,
"properties": {
"metrics": [
[
"AWS/EBS",
"VolumeQueueLength",
"VolumeId",
"vol-04b26d88efe8ecd54"
]
],
"period": 300,
"stat": "Average",
"region": "ap-south-1",
"title": "VolumeQueueLength"
}
},
{
"type": "metric",
"x": 14,
"y": 13,
"width": 12,
"height": 6,
"properties": {
"metrics": [
[
"AWS/EBS",
"BurstBalance",
"VolumeId",
"vol-04b26d88efe8ecd54"
]
],
"period": 300,
"stat": "Average",
"region": "ap-south-1",
"title": "BurstBalance"
}
}
]
}
EOF
}
Is there any possibility to add all the metrics available in the particular resource (eg:ec2, ebs, rds) in same widget or separate widget for each all the metrics in one function without indicating every metrics in separate function in terraform file?
In aws console just tick the checkbox above all the metrics inside the resource will include all the metrics in same widget. But i couldnt find the proper answer for terraform provision

AWS Terraform cloudwatch - Dashboard body reading from a list

I have the following body for my AWS_CloudWatch_Resource on terraform:
dashboard_body = jsonencode(
dashboard_body = jsonencode(
{
"widgets": [
{
"type": "metric",
"x": 0,
"y": 0,
"width": 9,
"height": 6,
"properties": {
"view": "bar",
"stacked": false,
"metrics": [
[ "AWS/AutoScaling", "GroupDesiredCapacity", "AutoScalingGroupName", "Momo-Test-ASG1" ],
[ ".", "GroupMaxSize", ".", "." ],
[ ".", "GroupTotalCapacity", ".", "." ],
[ ".", "GroupTotalInstances", ".", "." ],
[ ".", "GroupInServiceInstances", ".", "." ]
],
"region": "eu-central-1",
"title": "ASG1 statistics"
}
},
{
"type": "metric",
"x": 9,
"y": 0,
"width": 9,
"height": 6,
"properties": {
"view": "bar",
"stacked": false,
"metrics": [
[ "AWS/AutoScaling", "GroupDesiredCapacity", "AutoScalingGroupName", "Momo-Test-ASG2" ],
[ ".", "GroupMaxSize", ".", "." ],
[ ".", "GroupTotalCapacity", ".", "." ],
[ ".", "GroupTotalInstances", ".", "." ],
[ ".", "GroupInServiceInstances", ".", "." ]
],
"region": "eu-central-1",
"period": 300,
"title": "ASG2 statistics"
}
},
{
"type": "explorer",
"x": 0,
"y": 6,
"width": 24,
"height": 15,
"properties": {
"metrics": [
{
"metricName": "CPUUtilization",
"resourceType": "AWS::EC2::Instance",
"stat": "Average"
},
{
"metricName": "NetworkIn",
"resourceType": "AWS::EC2::Instance",
"stat": "Average"
},
{
"metricName": "DiskReadOps",
"resourceType": "AWS::EC2::Instance",
"stat": "Average"
},
{
"metricName": "DiskWriteOps",
"resourceType": "AWS::EC2::Instance",
"stat": "Average"
},
{
"metricName": "NetworkOut",
"resourceType": "AWS::EC2::Instance",
"stat": "Average"
}
],
"aggregateBy": {
"key": "*",
"func": "AVG"
},
"labels": [
{
"key": "aws:autoscaling:groupName",
"value": "Momo-Test-ASG1"
},
{
"key": "aws:autoscaling:groupName",
"value": "Momo-Test-ASG2"
}
],
"widgetOptions": {
"legend": {
"position": "bottom"
},
"view": "timeSeries",
"stacked": false,
"rowsPerPage": 40,
"widgetsPerRow": 3
},
"period": 300,
"splitBy": "",
"title": "Average ASG1 and ASG2"
}
},
{
"type": "metric",
"x": 0,
"y": 21,
"width": 6,
"height": 6,
"properties": {
"metrics": [
[ { "expression": "AVG(METRICS())", "label": "Average", "id": "e1" } ],
[ "CWAgent", "mem_used_percent", "InstanceId", "i-0f67225a5c04aebf9", "AutoScalingGroupName", "Momo-Test-ASG2", "ImageId", "ami-0502e817a62226e03", "InstanceType", "t2.micro", { "yAxis": "left", "id": "m1" } ],
[ "...", "i-00198c860886391f4", ".", "Momo-Test-ASG1", ".", ".", ".", ".", { "id": "m2" } ]
],
"view": "timeSeries",
"stacked": false,
"region": "eu-central-1",
"period": 300,
"stat": "Average",
"title": "mem_used_percent"
}
}
]
}
)
}
As you can see, I am having the same widget for my Momo-Test-ASG1 ( first Autoscaling group ) and Momo-Test-ASG2 ( second Autenter code here scaling group ).
If I would have many ASGs to test, It would be problematic to hardcode the same thing for a lot of groups.
Is there any solution to make terraform read the ASGs from a list? instead of having to reproduce the same parts?
HashiCorp Terraform 0.12 Preview: For and For-Each
Using for
locals {
asg_names = [
"Momo-Test-ASG1",
"Momo-Test-ASG2",
]
}
locals {
body = [for asg_name in local.asg_names :
{
type: "metric",
x: 0,
y: 0,
width: 9,
height: 6,
properties: {
view: "bar",
stacked: false,
metrics: [
[ "AWS/AutoScaling", "GroupDesiredCapacity", "AutoScalingGroupName", asg_name ],
[ ".", "GroupMaxSize", ".", "." ],
[ ".", "GroupTotalCapacity", ".", "." ],
[ ".", "GroupTotalInstances", ".", "." ],
[ ".", "GroupInServiceInstances", ".", "." ]
]
region: "eu-central-1",
title: asg_name
}
}
]
}
resource "aws_cloudwatch_dashboard" "main" {
dashboard_name = "my-dashboard"
dashboard_body = jsonencode({
widgets: concat(local.body, [{
type: "text",
x: 0,
y: 7,
width: 3,
height: 3,
properties: {
markdown: "Hello world"
}
}])
})
}

Terraform for loop

I've been learning terraform, and have been playing with dashboards.
I have the following file which generates a dashboard.
resource "aws_cloudwatch_dashboard" "main" {
dashboard_name = "sample_dashboard"
dashboard_body = <<EOF
{
"widgets": [
${templatefile("${path.module}/cpu.tmpl", { ids = aws_instance.web[*].id })},
${templatefile("${path.module}/network.tmpl", { ids = aws_instance.web[*].id })}
]
}
EOF
}
Here is the cpu template file.
{
"type": "metric",
"x": 0,
"y": 0,
"width": 12,
"height": 6,
"properties": {
"metrics": ${jsonencode([for id in ids : ["AWS/EC2","CPUUtilization","InstanceId", "${id}"]])},
"period": 300,
"stat": "Average",
"region": "us-east-1",
"title": "EC2 Instance CPU"
}
}
Here have the network template file.
{
"type": "metric",
"x": 12,
"y": 0,
"width": 12,
"height": 6,
"properties": {
"metrics": ${jsonencode([for id in ids :
["AWS/EC2", "NetworkIn", "InstanceId", "${id}"]
])},
"period": 300,
"stat": "Average",
"region": "us-east-1",
"title": "EC2 Instance Network"
}
}
Everything works as expected, and I get the following dashboard.
The problem I'm having is when trying to add another metric in the for loop I get an error.
{
"type": "metric",
"x": 12,
"y": 0,
"width": 12,
"height": 6,
"properties": {
"metrics": ${jsonencode([for id in ids :
["AWS/EC2", "NetworkIn", "InstanceId", "${id}"],
["AWS/EC2", "NetworkOut", "InstanceId", "${id}"]
])},
"period": 300,
"stat": "Average",
"region": "us-east-1",
"title": "EC2 Instance Network"
}
}
I get the following error.
Call to function "templatefile" failed: ./network.tmpl:9,70-71:
Invalid 'for' expression; Extra characters after the end of the 'for'
expression..
As always thanks in advance for you help.
One way to overcome the issue would be to concat your metrics:
{
"type": "metric",
"x": 12,
"y": 0,
"width": 12,
"height": 6,
"properties": {
"metrics": ${jsonencode(concat([for id in ids :
["AWS/EC2", "NetworkIn", "InstanceId", "${id}"]
], [for id in ids :
["AWS/EC2", "NetworkOut", "InstanceId", "${id}"]
]))},
"period": 300,
"stat": "Average",
"region": "us-east-1",
"title": "EC2 Instance Network"
}
}