Skip to content

Commit

Permalink
Add support for ALB alarms and dashboard
Browse files Browse the repository at this point in the history
  • Loading branch information
direnakkoc committed Aug 15, 2022
1 parent 56bbf69 commit b22c4bb
Show file tree
Hide file tree
Showing 14 changed files with 37,644 additions and 21,793 deletions.
3 changes: 2 additions & 1 deletion lerna.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{
"packages": [
"serverless-plugin",
"serverless-test-project"
"serverless-test-project",
"serverless-test-project-alb"
],
"version": "1.3.0"
}
108 changes: 67 additions & 41 deletions serverless-plugin/alarms-alb.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
'use strict'

const { makeResourceName, getStatisticName } = require('./util')
/**
* Given CloudFormation syntax for an Target Group, derive CloudFormation syntax for
* the LoadBalancer LogicalId name
*
* @param loadBalancerResources syntax for an Load Balancer Application
* @returns CloudFormation syntax for the cluster's name
*/
function resolveLoadBalancerLogicalIdName (loadBalancerResources) {
for (const key in loadBalancerResources) {
if (loadBalancerResources[key].Type === 'AWS::ElasticLoadBalancingV2::LoadBalancer') {
return key
}
}
}

/**
* @param {object} albAlarmConfig The fully resolved alarm configuration
Expand Down Expand Up @@ -39,35 +53,46 @@ module.exports = function ALBlarms (albAlarmConfig, context) {
)
cfTemplate.addResource(rejectedConnectionCount.resourceName, rejectedConnectionCount.resource)
}
}

const targetGroupResources = cfTemplate.getResourcesByType(
'AWS::ElasticLoadBalancingV2::TargetGroup'
)
for (const [targetGroupResourceName, targetGroupResource] of Object.entries(targetGroupResources)) {
const loadBalancerName = resolveLoadBalancerLogicalIdName(loadBalancerResources)

if (albAlarmConfig.HTTPCode_Target_5XX_Count.enabled) {
const httpCodeTarget5XXCount = createHTTPCodeTarget5XXCountAlarm(
loadBalancerResourceName,
loadBalancerResource,
targetGroupResourceName,
targetGroupResource,
loadBalancerName,
albAlarmConfig.HTTPCode_Target_5XX_Count
)
cfTemplate.addResource(httpCodeTarget5XXCount.resourceName, httpCodeTarget5XXCount.resource)
}
if (albAlarmConfig.UnHealthyHostCount.enabled) {
const unHealthyHostCount = createUnHealthyHostCountAlarm(
loadBalancerResourceName,
loadBalancerResource,
targetGroupResourceName,
targetGroupResource,
loadBalancerName,
albAlarmConfig.UnHealthyHostCount
)
cfTemplate.addResource(unHealthyHostCount.resourceName, unHealthyHostCount.resource)
}
if (albAlarmConfig.LambdaInternalError.enabled) {
const lambdaInternalError = createLambdaInternalErrorAlarm(
loadBalancerResourceName,
loadBalancerResource,
targetGroupResourceName,
targetGroupResource,
loadBalancerName,
albAlarmConfig.LambdaInternalError
)
cfTemplate.addResource(lambdaInternalError.resourceName, lambdaInternalError.resource)
}
if (albAlarmConfig.LambdaUserError.enabled) {
const lambdaUserError = createLambdaUserErrorAlarm(
loadBalancerResourceName,
loadBalancerResource,
targetGroupResourceName,
targetGroupResource,
loadBalancerName,
albAlarmConfig.LambdaUserError
)
cfTemplate.addResource(lambdaUserError.resourceName, lambdaUserError.resource)
Expand All @@ -78,7 +103,7 @@ module.exports = function ALBlarms (albAlarmConfig, context) {
function createLoadBalancerAlarm (
alarmName,
alarmDescription,
loadBalancer,
loadBalancerResourceName, // Logical ID of the CloudFormation Load Balancer Resource
comparisonOperator,
threshold,
metricName,
Expand All @@ -88,8 +113,9 @@ module.exports = function ALBlarms (albAlarmConfig, context) {
evaluationPeriods,
treatMissingData
) {
const loadBalancerFullName = { 'Fn::GetAtt': [loadBalancerResourceName, 'LoadBalancerFullName'] }
const metricProperties = {
Dimensions: [{ Name: 'LoadBalancer', Value: loadBalancer }],
Dimensions: [{ Name: 'LoadBalancer', Value: loadBalancerFullName }],
MetricName: metricName,
Namespace: 'AWS/ApplicationELB',
Period: period,
Expand All @@ -116,7 +142,8 @@ module.exports = function ALBlarms (albAlarmConfig, context) {
function createLoadBalancerTargetAlarm (
alarmName,
alarmDescription,
targetGroup,
targetGroupResourceName, // Logical ID of the CloudFormation Target Group Resource
loadBalancerName,
comparisonOperator,
threshold,
metricName,
Expand All @@ -126,8 +153,10 @@ module.exports = function ALBlarms (albAlarmConfig, context) {
evaluationPeriods,
treatMissingData
) {
const targetGroupFullName = { 'Fn::GetAtt': [targetGroupResourceName, 'TargetGroupFullName'] }
const loadBalancerFullName = { 'Fn::GetAtt': [loadBalancerName, 'LoadBalancerFullName'] }
const metricProperties = {
Dimensions: [{ Name: 'TargetGroup', Value: targetGroup }],
Dimensions: [{ Name: 'TargetGroup', Value: targetGroupFullName }, { Name: 'LoadBalancer', Value: loadBalancerFullName }],
MetricName: metricName,
Namespace: 'AWS/ApplicationELB',
Period: period,
Expand All @@ -152,14 +181,13 @@ module.exports = function ALBlarms (albAlarmConfig, context) {
}

function createHTTPCodeELB5XXCountAlarm (loadBalancerResourceName, loadBalancerResource, config) {
const loadBalancer = 'app/awesome-loadBalancer/c2c94aafd2470792'
const threshold = config.Threshold
return {
resourceName: makeResourceName('LoadBalancer', loadBalancerResourceName, 'HTTPCodeELB5XXCount'),
resource: createLoadBalancerAlarm(
`LoadBalancerHTTPCodeELB5XXCountAlarm_${loadBalancerResourceName}`,
`LoadBalancer HTTP Code ELB 5XX Count ${getStatisticName(config)} for ${loadBalancerResourceName} breaches ${threshold}`,
loadBalancer,
loadBalancerResourceName,
config.ComparisonOperator,
threshold,
'HTTPCode_ELB_5XX_Count', // metricName
Expand All @@ -173,14 +201,13 @@ module.exports = function ALBlarms (albAlarmConfig, context) {
}

function createRejectedConnectionCountAlarm (loadBalancerResourceName, loadBalancerResource, config) {
const loadBalancer = 'app/awesome-loadBalancer/c2c94aafd2470792'
const threshold = config.Threshold
return {
resourceName: makeResourceName('LoadBalancer', loadBalancerResourceName, 'RejectedConnectionCount'),
resource: createLoadBalancerAlarm(
`LoadBalancerRejectedConnectionCountAlarm_${loadBalancerResourceName}`,
`LoadBalancer Rejected Connection Count ${getStatisticName(config)} for ${loadBalancerResourceName} breaches ${threshold}`,
loadBalancer,
loadBalancerResourceName,
config.ComparisonOperator,
threshold,
'RejectedConnectionCount', // metricName
Expand All @@ -193,15 +220,15 @@ module.exports = function ALBlarms (albAlarmConfig, context) {
}
}

function createHTTPCodeTarget5XXCountAlarm (loadBalancerResourceName, loadBalancerResource, config) {
const targetGroup = 'targetgroup/10bf92242b4efc6ad3241b156008f170/1498f14364393da3'
function createHTTPCodeTarget5XXCountAlarm (targetGroupResourceName, targetGroupResource, loadBalancerName, config) {
const threshold = config.Threshold
return {
resourceName: makeResourceName('LoadBalancer', loadBalancerResourceName, 'HTTPCodeTarget5XXCount'),
resourceName: makeResourceName('LoadBalancer', targetGroupResourceName, 'HTTPCodeTarget5XXCount'),
resource: createLoadBalancerTargetAlarm(
`LoadBalancerHTTPCodeTarget5XXCountAlarm_${loadBalancerResourceName}`,
`LoadBalancer HTTP Code Target 5XX Count ${getStatisticName(config)} for ${loadBalancerResourceName} breaches ${threshold}`,
targetGroup,
`LoadBalancerHTTPCodeTarget5XXCountAlarm_${targetGroupResourceName}`,
`LoadBalancer HTTP Code Target 5XX Count ${getStatisticName(config)} for ${targetGroupResourceName} breaches ${threshold}`,
targetGroupResourceName,
loadBalancerName,
config.ComparisonOperator,
threshold,
'HTTPCode_Target_5XX_Count',
Expand All @@ -214,16 +241,15 @@ module.exports = function ALBlarms (albAlarmConfig, context) {
}
}

function createUnHealthyHostCountAlarm (loadBalancerResourceName, loadBalancerResource, config) {
// const loadBalancerResourceName = loadBalancerResource.Properties.Name // TODO: Allow for Ref usage in resource names (see #14)
const targetGroup = 'targetgroup/10bf92242b4efc6ad3241b156008f170/1498f14364393da3'
function createUnHealthyHostCountAlarm (targetGroupResourceName, targetGroupResource, loadBalancerName, config) {
const threshold = config.Threshold
return {
resourceName: makeResourceName('LoadBalancer', loadBalancerResourceName, 'UnHealthyHostCount'),
resourceName: makeResourceName('LoadBalancer', targetGroupResourceName, 'UnHealthyHostCount'),
resource: createLoadBalancerTargetAlarm(
`LoadBalancerUnHealthyHostCountAlarm_${loadBalancerResourceName}`,
`LoadBalancer UnHealthy Host Count ${getStatisticName(config)} for ${loadBalancerResourceName} breaches ${threshold}`,
targetGroup,
`LoadBalancerUnHealthyHostCountAlarm_${targetGroupResourceName}`,
`LoadBalancer UnHealthy Host Count ${getStatisticName(config)} for ${targetGroupResourceName} breaches ${threshold}`,
targetGroupResourceName,
loadBalancerName,
config.ComparisonOperator,
threshold,
'UnHealthyHostCount',
Expand All @@ -236,15 +262,15 @@ module.exports = function ALBlarms (albAlarmConfig, context) {
}
}

function createLambdaInternalErrorAlarm (loadBalancerResourceName, loadBalancerResource, config) {
const targetGroup = 'targetgroup/10bf92242b4efc6ad3241b156008f170/1498f14364393da3'
function createLambdaInternalErrorAlarm (targetGroupResourceName, targetGroupResource, loadBalancerName, config) {
const threshold = config.Threshold
return {
resourceName: makeResourceName('LoadBalancer', loadBalancerResourceName, 'LambdaInternalError'),
resourceName: makeResourceName('LoadBalancer', targetGroupResourceName, 'LambdaInternalError'),
resource: createLoadBalancerTargetAlarm(
`LoadBalancerLambdaInternalErrorAlarm_${loadBalancerResourceName}`,
`LoadBalancer Lambda Internal Error ${getStatisticName(config)} for ${loadBalancerResourceName} breaches ${threshold}`,
targetGroup,
`LoadBalancerLambdaInternalErrorAlarm_${targetGroupResourceName}`,
`LoadBalancer Lambda Internal Error ${getStatisticName(config)} for ${targetGroupResourceName} breaches ${threshold}`,
targetGroupResourceName,
loadBalancerName,
config.ComparisonOperator,
threshold,
'LambdaInternalError',
Expand All @@ -257,15 +283,15 @@ module.exports = function ALBlarms (albAlarmConfig, context) {
}
}

function createLambdaUserErrorAlarm (loadBalancerResourceName, loadBalancerResource, config) {
const targetGroup = 'targetgroup/10bf92242b4efc6ad3241b156008f170/1498f14364393da3'
function createLambdaUserErrorAlarm (targetGroupResourceName, targetGroupResource, loadBalancerName, config) {
const threshold = config.Threshold
return {
resourceName: makeResourceName('LoadBalancer', loadBalancerResourceName, 'LambdaUserError'),
resourceName: makeResourceName('LoadBalancer', targetGroupResourceName, 'LambdaUserError'),
resource: createLoadBalancerTargetAlarm(
`LoadBalancerLambdaUserErrorAlarm_${loadBalancerResourceName}`,
`LoadBalancer Lambda User Error ${getStatisticName(config)} for ${loadBalancerResourceName} breaches ${threshold}`,
targetGroup,
`LoadBalancerLambdaUserErrorAlarm_${targetGroupResourceName}`,
`LoadBalancer Lambda User Error ${getStatisticName(config)} for ${targetGroupResourceName} breaches ${threshold}`,
targetGroupResourceName,
loadBalancerName,
config.ComparisonOperator,
threshold,
'LambdaUserError',
Expand Down
3 changes: 2 additions & 1 deletion serverless-plugin/config-schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ const supportedWidgets = {
ECS: ['MemoryUtilization', 'CPUUtilization'],
SNS: ['NumberOfNotificationsFilteredOut-InvalidAttributes', 'NumberOfNotificationsFailed'],
Events: ['FailedInvocations', 'ThrottledRules', 'Invocations'],
ApplicationELB: ['HTTPCode_ELB_5XX_Count', 'RejectedConnectionCount', 'HTTPCode_Target_5XX_Count', 'UnHealthyHostCount', 'LambdaInternalError', 'LambdaUserError']
ApplicationELB: ['HTTPCode_ELB_5XX_Count', 'RejectedConnectionCount'],
ApplicationELBTarget: ['HTTPCode_Target_5XX_Count', 'UnHealthyHostCount', 'LambdaInternalError', 'LambdaUserError']
}

const commonAlarmProperties = {
Expand Down

0 comments on commit b22c4bb

Please sign in to comment.