Reputation: 525
I have created a Elastic Beanstalk and CloudWatch Alarm in CloudFormation with the following code snippet:
"ElasticBeanstalkEnvironment": {
"Type": "AWS::ElasticBeanstalk::Environment",
"Properties": {
"ApplicationName": "my-app",
"EnvironmentName": "my-eb",
"SolutionStackName": "64bit Amazon Linux 2018.03 v3.0.1 running Tomcat 8 Java 8",
"OptionSettings": [
{
"Namespace": "aws:elb:loadbalancer",
"OptionName": "CrossZone",
"Value": "true"
},
{
"Namespace": "aws:elb:listener:80",
"OptionName": "ListenerProtocol",
"Value": "HTTP"
},
{
"Namespace": "aws:elb:listener:80",
"OptionName": "InstancePort",
"Value": "80"
},
etc...
]
},
"CloudWatchBacken500XXAlarm": {
"Type": "AWS::CloudWatch::Alarm",
"Properties" : {
"AlarmActions": ["arn:aws:sns:us-east-1:12345678:mysnstopic"],
"Namespace": "AWS/ELB",
"Dimensions": [{
"Name": "LoadBalancerName",
"Value" : {
"Fn::GetAtt": [
"ElasticBeanstalkEnvironment",
"EndpointURL"
]
}
}],
"MetricName": "HTTPCode_Backend_5XX",
"Statistic": "Sum",
"Period": "60",
"EvaluationPeriods": "1",
"ComparisonOperator": "GreaterThanOrEqualToThreshold",
"Threshold": "1"
}
}
You can see that the CloudWatch Alarm is configured to alert if the Elastic Beanstalk's load balancer receives 5XX Errors. However I am not able to get the load balancer Name attribute which would look something like this:
awseb-e-a-AWSEBLoa-AY8LC6V30OAW
Instead the Fn::GetAtt("EndpointURL") attribute returns the load balancer's DNSName which looks something like this:
awseb-e-a-AWSEBLoa-AY8LC6V30OAW-175133046.us-east-1.elb.amazonaws.com
Which will fail to create the CloudWatch alarm correctly as it expects to get the load balancer Name not DNSName.
What's the best way to get the Load Balancer's Name? I don't want to have to create the Load Balancer as an external resource like "AWS::ElasticLoadBalancing::LoadBalancer" or try to use some substring method to extract the Name string from the DNSName string.
Upvotes: 3
Views: 3263
Reputation: 51
in case it is not obvious what the code above does: it extracts the name part before -xxxxxxxx.region.elb.amazonaws.com
This is sufficient for classic loadbalancers because they do only have a name and Cloudwatch is able to monitor these LBs by their name.
For application loadbalancers it is a different story:
ApplicationLoadbalancers besides their name, they do have an arn
on their own in the format:
arn:aws:elasticloadbalancing:REGION:ACCOUNT:loadbalancer/XXXXX/my-load-balancer/DDDDDDDD
Where XXXXX is a region dependent string ( I found application in us and app in europe) and DDDDDDDD is an arbitrary number.
Cloudwatch needs this loadBalancerFullName
to monitor this LB.
So sadly you can't use this trick if you have an application loadbalancer.
Upvotes: 0
Reputation: 159
Coming here a few years later, it looks like Amazon have added the attribute now :
To quote:
LoadBalancerFullName
The full name of the load balancer. For example, app/my-load-balancer/50dc6c495c0c9188.
So you can now do :
Dimensions:
- Name: LoadBalancer
Value: !GetAtt YourALBRef.LoadBalancerFullName
Upvotes: -1
Reputation: 11
Using ebextensions would be much easier to create an alarm - as fetching the ELB name is as easy as Value: { "Ref" : "AWSEBLoadBalancer" }
Create a file with .config extension (say - BackendErrors.config) and place it in a folder with name ".ebextensions". Complete ebextension will be as follows:
Resources:
CloudWatchBacken500XXAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmDescription: "Elastic Beanstalk Has Received 5XX Backend Connection Errors"
AlarmName: { "Fn::Join" : ["", [{ "Ref" : "AWSEBEnvironmentName" }, "-Backend-5XX-Alarm." ]]}
AlarmActions:
- "arn:aws:sns:us-east-1:123456789012:mysnstopic"
Namespace: AWS/ELB
Dimensions:
- Name: LoadBalancerName
Value: { "Ref" : "AWSEBLoadBalancer" }
MetricName: HTTPCode_Backend_5XX
Statistic: Sum
Period: 60
EvaluationPeriods: 1
Threshold: 1
ComparisonOperator: GreaterThanOrEqualToThreshold
The .ebextensions folder should be created at the top level of your application source bundle:
~/workspace/my-application/
|-- .ebextensions
| |-- BackendErrors.config
Upvotes: 1
Reputation: 525
OK I found a solution, its quite the hack, I have been able to extract the LoadBalancerName from the endpoint using several Split/Select/Join calls on the DNSName string returned from - Fn::GetAtt("EndpointURL"). Here is the code:
"CloudWatchBackend500XXAlarm": {
"Type": "AWS::CloudWatch::Alarm",
"Properties" : {
"AlarmDescription": "Elastic Beanstalk Has Received 5XX Backend Connection Errors",
"AlarmActions": ["arn:aws:sns:us-east-1:1234567890:mysnstopic"],
"Namespace": "AWS/ELB",
"Dimensions": [
{
"Name": "LoadBalancerName",
"Value": {
"Fn::Join": ["", [{
"Fn::Select": [
"0",
{
"Fn::Split": ["AWSEBLoa-",
{
"Fn::GetAtt": [
"ElasticBeanstalkEnvironment",
"EndpointURL"
]
}
]
}
]
},
"AWSEBLoa-",
{
"Fn::Select": [
"0",
{
"Fn::Split": ["-",
{
"Fn::Select": [
"1",
{
"Fn::Split": ["AWSEBLoa-",
{
"Fn::GetAtt": [
"ElasticBeanstalkEnvironment",
"EndpointURL"
]
}
]
}
]
}
]
}
]
}
]]
}
}
],
"MetricName": "HTTPCode_Backend_5XX",
"Statistic": "Sum",
"Period": "60",
"EvaluationPeriods": "1",
"ComparisonOperator": "GreaterThanOrEqualToThreshold",
"Threshold": "1"
}
}
ie the code above is able to extract 'awseb-k-3-AWSEBLoa-11B26NY4PQB9A' from 'awseb-k-3-AWSEBLoa-11B26NY4PQB9A-739614614.us-east-1.elb.amazonaws.com' and the CloudWatch alarm works perfectly. I think I would have to adjust the code to work with internal load balancers, ie formatted with 'internal-' at the start of the DNSName but I am fine for now.
I've submitted a request to AWS asking them to add a CloudFormation method to return the LoadBalancer Name and not just the DNSName.
Upvotes: 1
Reputation: 2526
If you have access to the environment name, you can perform a DescribeEnvironmentResources
API call. The response would include information about the loadbalancer of your environment.
Upvotes: 0