Skip to content

Commit

Permalink
Create top level function and apply it to some alarm modules
Browse files Browse the repository at this point in the history
- Avoid some repetition
  • Loading branch information
direnakkoc committed Mar 21, 2023
1 parent ace9bbf commit d83d500
Show file tree
Hide file tree
Showing 14 changed files with 105 additions and 178 deletions.
4 changes: 2 additions & 2 deletions core/alarms/alarms.ts
Expand Up @@ -48,8 +48,8 @@ export default function addAlarms (alarmProperties: SlicWatchAlarmsConfig, funct
Object.assign(resources,
...alarmFunctions.map((alarmFn, i) => {
const config: any = alarmConfigs[i]
if (config !== false && config.enabled !== false) {
return alarmFn(config, context, compiledTemplate)
if (config?.enabled !== false || i === 0) {
return alarmFn(config, context, compiledTemplate) ?? {}
}
return {}
}))
Expand Down
52 changes: 15 additions & 37 deletions core/alarms/alb.ts
@@ -1,11 +1,9 @@
'use strict'

import { getResourcesByType } from '../cf-template'
import type { Context, DefaultAlarmsProperties, CfAlarmsProperties } from './default-config-alarms'
import { createAlarm } from './default-config-alarms'
import { getStatisticName } from './get-statistic-name'
import { makeResourceName } from './make-name'
import type { Context, DefaultAlarmsProperties } from './default-config-alarms'
import { fetchAlarmResources } from './default-config-alarms'
import type Template from 'cloudform-types/types/template'
import { getStatisticName } from './get-statistic-name'

export interface AlbAlarmProperties {
enabled?: boolean
Expand All @@ -22,38 +20,18 @@ const executionMetrics: AlbMetrics[] = [

/**
* albAlarmProperties The fully resolved alarm configuration
* Add all required Application Load Balancer alarms for Application Load Balancer to the provided CloudFormation template
* based on the resources found within
* A CloudFormation template object
*/
export default function createALBAlarms (albAlarmProperties: AlbAlarmProperties, context: Context, compiledTemplate: Template) {
/**
* Add all required Application Load Balancer alarms for Application Load Balancer to the provided CloudFormation template
* based on the resources found within
*
* A CloudFormation template object
*/
const loadBalancerResources = getResourcesByType('AWS::ElasticLoadBalancingV2::LoadBalancer', compiledTemplate)

const resources = {}

for (const [loadBalancerResourceName] of Object.entries(loadBalancerResources)) {
for (const metric of executionMetrics) {
const config = albAlarmProperties[metric]
if (config.enabled !== false) {
const { enabled, ...rest } = config
const albAlarmProperties: CfAlarmsProperties = {
AlarmName: `LoadBalancer${metric.replaceAll('_', '')}Alarm_${loadBalancerResourceName}`,
AlarmDescription: `LoadBalancer ${metric} ${getStatisticName(config)} for ${loadBalancerResourceName} breaches ${config.Threshold}`,
MetricName: metric,
Namespace: 'AWS/ApplicationELB',
Dimensions: [
{ Name: 'LoadBalancer', Value: `\${${loadBalancerResourceName}.LoadBalancerFullName}` }
],
...rest
}
const resourceName = makeResourceName('LoadBalancer', loadBalancerResourceName, metric)
const resource = createAlarm(albAlarmProperties, context)
resources[resourceName] = resource
}
}
}
return resources
return fetchAlarmResources('AWS::ElasticLoadBalancingV2::LoadBalancer', 'LoadBalancer', executionMetrics, albAlarmProperties, context, compiledTemplate,
({ metric, resourceName, config }) => ({
AlarmName: `LoadBalancer${metric.replaceAll('_', '')}Alarm_${resourceName}`,
AlarmDescription: `LoadBalancer ${metric} ${getStatisticName(config)} for ${resourceName} breaches ${config.Threshold}`,
Namespace: 'AWS/ApplicationELB',
Dimensions: [
{ Name: 'LoadBalancer', Value: `\${${resourceName}.LoadBalancerFullName}` }
]
}))
}
1 change: 0 additions & 1 deletion core/alarms/api-gateway.ts
Expand Up @@ -89,7 +89,6 @@ export default function createApiGatewayAlarms (apiGwAlarmProperties: ApiGwAlarm
for (const [apiResourceName, apiResource] of Object.entries(apiResources)) {
for (const metric of executionMetrics) {
const config: DefaultAlarmsProperties = apiGwAlarmProperties[metric]
console.log(metric)
if (config.enabled !== false) {
const { enabled, ...rest } = config
const apiName = resolveRestApiNameAsCfn(apiResource, apiResourceName)
Expand Down
2 changes: 1 addition & 1 deletion core/alarms/appsync.ts
Expand Up @@ -34,9 +34,9 @@ export default function createAppSyncAlarms (appSyncAlarmProperties: AppSyncAlar
for (const [appSyncResourceName, appSyncResource] of Object.entries(appSyncResources)) {
for (const metric of executionMetrics) {
const config: DefaultAlarmsProperties = appSyncAlarmProperties[metric]
const { enabled, ...rest } = config
if (config.enabled !== false) {
const graphQLName: string = appSyncResource.Properties?.Name
const { enabled, ...rest } = config
const appSyncAlarmProperties: CfAlarmsProperties = {
AlarmName: `AppSync${metric}Alarm_${graphQLName}`,
AlarmDescription: `AppSync ${metric} ${getStatisticName(config)} for ${graphQLName} breaches ${config.Threshold}`,
Expand Down
46 changes: 35 additions & 11 deletions core/alarms/default-config-alarms.ts
Expand Up @@ -15,7 +15,42 @@ import type { SfAlarmsConfig } from './step-functions'
import type { AlarmProperties } from 'cloudform-types/types/cloudWatch/alarm'
import type Resource from 'cloudform-types/types/resource'
import type { Value } from 'cloudform-types/types/dataTypes'
import { getResourcesByType } from '../cf-template'
import { makeResourceName } from './make-name'
import type Template from 'cloudform-types/types/template'

export function fetchAlarmResources (type: string, service: string, metrics: string[], config, context: Context, compiledTemplate: Template, getAlarm) {
const resources = {}
const resourcesOfType = getResourcesByType(type, compiledTemplate)

for (const resourceName of Object.keys(resourcesOfType)) {
for (const metric of metrics) {
const { enabled, ...rest } = config[metric]
if (enabled !== false) {
const alarm = getAlarm({ metric, resourceName, config: rest })
const name = makeResourceName(service, resourceName, metric)
const resource = createAlarm({
MetricName: metric,
...alarm,
...rest
}, context)
resources[name] = resource
}
}
}
return resources
}

export function createAlarm (alarm: CfAlarmsProperties, context?: Context): ReturnResource {
return {
Type: 'AWS::CloudWatch::Alarm',
Properties: {
ActionsEnabled: true,
AlarmActions: context?.alarmActions,
...alarm
}
}
}
export interface ReturnResource {
Type: string
Properties: CfAlarmsProperties
Expand All @@ -42,17 +77,6 @@ export interface Context {
alarmActions: string[]
}

export function createAlarm (alarm: CfAlarmsProperties, context?: Context): ReturnResource {
return {
Type: 'AWS::CloudWatch::Alarm',
Properties: {
ActionsEnabled: true,
AlarmActions: context?.alarmActions,
...alarm
}
}
}

export type AlarmsConfig = AlbTargetAlarmProperties & AlbAlarmProperties & ApiGwAlarmProperties & AppSyncAlarmProperties & DynamoDbAlarmProperties
& EcsAlarmsConfig & EventsAlarmsConfig & KinesisAlarmProperties & LambdaFunctionAlarmProperties & SnsAlarmsConfig & SqsAlarmsConfig & SfAlarmsConfig

Expand Down
2 changes: 1 addition & 1 deletion core/alarms/dynamodb.ts
Expand Up @@ -37,8 +37,8 @@ export default function createDynamoDbAlarms (dynamoDbAlarmProperties: DynamoDbA
for (const [tableResourceName, tableResource] of Object.entries(tableResources)) {
for (const metric of dynamoDbMetrics) {
const config: DefaultAlarmsProperties = dynamoDbAlarmProperties[metric]
const { enabled, ...rest } = config
if (config.enabled !== false) {
const { enabled, ...rest } = config
const dynamoDBAlarmProperties: CfAlarmsProperties = {
AlarmName: `DDB_${metric}_${tableResourceName}`,
AlarmDescription: `DynamoDB ${config.Statistic} for ${tableResourceName} breaches ${config.Threshold}`,
Expand Down
14 changes: 5 additions & 9 deletions core/alarms/ecs.ts
Expand Up @@ -38,25 +38,21 @@ const executionMetrics: EcsMEtrics[] = ['MemoryUtilization', 'CPUUtilization']

/**
* ecsAlarmsConfig The fully resolved alarm configuration
* Add all required ECS alarms to the provided CloudFormation template
* based on the ECS Service resources
* A CloudFormation template object
*/
export default function createECSAlarms (ecsAlarmsConfig: EcsAlarmsConfig, context: Context, compiledTemplate: Template) {
/**
* Add all required ECS alarms to the provided CloudFormation template
* based on the ECS Service resources
*
* A CloudFormation template object
*/

const resources = {}
const serviceResources = getResourcesByType('AWS::ECS::Service', compiledTemplate)

for (const [serviceResourceName, serviceResource] of Object.entries(serviceResources)) {
for (const metric of executionMetrics) {
const cluster = serviceResource.Properties?.Cluster
const clusterName = resolveEcsClusterNameAsCfn(cluster)
const config = ecsAlarmsConfig[metric]
const config: DefaultAlarmsProperties = ecsAlarmsConfig[metric]
const { enabled, ...rest } = config
if (config.enabled !== false) {
const { enabled, ...rest } = config
const ecsAlarmProperties: CfAlarmsProperties = {
AlarmName: `ECS_${metric.replaceAll('Utilization', 'Alarm')}_\${${serviceResourceName}.Name}`,
AlarmDescription: `ECS ${metric} for ${serviceResourceName}.Name breaches ${config.Threshold}`,
Expand Down
44 changes: 12 additions & 32 deletions core/alarms/eventbridge.ts
@@ -1,9 +1,8 @@

'use strict'

import { getResourcesByType } from '../cf-template'
import type { Context, DefaultAlarmsProperties, CfAlarmsProperties } from './default-config-alarms'
import { createAlarm } from './default-config-alarms'
import type { Context, DefaultAlarmsProperties } from './default-config-alarms'
import { fetchAlarmResources } from './default-config-alarms'
import type Template from 'cloudform-types/types/template'

export interface EventsAlarmsConfig {
Expand All @@ -18,35 +17,16 @@ const executionMetrics: EventMetrics[] = ['FailedInvocations', 'ThrottledRules']

/**
* The fully resolved alarm configuration
* Add all required Events alarms to the provided CloudFormation template
* based on the EventBridge Rule found within
*
*/
export default function createRuleAlarms (eventsAlarmsConfig: EventsAlarmsConfig, context: Context, compiledTemplate: Template) {
/**
* Add all required Events alarms to the provided CloudFormation template
* based on the EventBridge Rule found within
*
*/

const resources = {}
const ruleResources = getResourcesByType('AWS::Events::Rule', compiledTemplate)

for (const [ruleResourceName] of Object.entries(ruleResources)) {
for (const metric of executionMetrics) {
const config: DefaultAlarmsProperties = eventsAlarmsConfig[metric]
if (config.enabled !== false) {
const { enabled, ...rest } = config
const eventbridgeAlarmProperties: CfAlarmsProperties = {
AlarmName: `Events_${metric}Alarm_${ruleResourceName}`,
AlarmDescription: `EventBridge ${metric} for \${${ruleResourceName}} breaches ${config.Threshold}`,
MetricName: metric,
Namespace: 'AWS/Events',
Dimensions: [{ Name: 'RuleName', Value: { Ref: ruleResourceName } as any }],
...rest
}
const resourceName = `slicWatchEvents${metric}Alarm${ruleResourceName}`
const resource = createAlarm(eventbridgeAlarmProperties, context)
resources[resourceName] = resource
}
}
}
return resources
return fetchAlarmResources('AWS::Events::Rule', 'Events', executionMetrics, eventsAlarmsConfig, context, compiledTemplate,
({ metric, resourceName, config }) => ({
AlarmName: `Events_${metric}Alarm_${resourceName}`,
AlarmDescription: `EventBridge ${metric} for \${${resourceName}} breaches ${config.Threshold}`,
Namespace: 'AWS/Events',
Dimensions: [{ Name: 'RuleName', Value: { Ref: resourceName } as any }]
}))
}
12 changes: 4 additions & 8 deletions core/alarms/kinesis.ts
Expand Up @@ -28,23 +28,19 @@ const kinesisAlarmTypes = {

/**
* The fully resolved alarm configuration for Kinesis Data Streams
* Add all required Kinesis Data Stream alarms to the provided CloudFormation template
* based on the resources found within
* A CloudFormation template object
*/
export default function createKinesisAlarms (kinesisAlarmProperties: KinesisAlarmProperties, context: Context, compiledTemplate: Template) {
/**
* Add all required Kinesis Data Stream alarms to the provided CloudFormation template
* based on the resources found within
*
* A CloudFormation template object
*/

const resources = {}
const streamResources = getResourcesByType('AWS::Kinesis::Stream', compiledTemplate)

for (const [streamResourceName] of Object.entries(streamResources)) {
for (const [type, metric] of Object.entries(kinesisAlarmTypes)) {
const config: DefaultAlarmsProperties = kinesisAlarmProperties[metric]
const { enabled, ...rest } = config
if (config.enabled !== false) {
const { enabled, ...rest } = config
const kinesisAlarmProperties: CfAlarmsProperties = {
AlarmName: `Kinesis_${type}_${streamResourceName}`,
AlarmDescription: `Kinesis ${getStatisticName(config)} ${metric} for ${streamResourceName} breaches ${config.Threshold} milliseconds`,
Expand Down
45 changes: 12 additions & 33 deletions core/alarms/sns.ts
@@ -1,8 +1,7 @@
'use strict'

import { getResourcesByType } from '../cf-template'
import type { Context, DefaultAlarmsProperties, CfAlarmsProperties } from './default-config-alarms'
import { createAlarm } from './default-config-alarms'
import type { Context, DefaultAlarmsProperties } from './default-config-alarms'
import { fetchAlarmResources } from './default-config-alarms'
import type Template from 'cloudform-types/types/template'

export interface SnsAlarmsConfig {
Expand All @@ -17,36 +16,16 @@ const executionMetrics: SnsMetrics[] = ['NumberOfNotificationsFilteredOut-Invali

/**
* snsAlarmsConfig The fully resolved alarm configuration
* Add all required SNS alarms to the provided CloudFormation template
* based on the SNS resources found within
* A CloudFormation template object
*/
export default function createSNSAlarms (snsAlarmsConfig: SnsAlarmsConfig, context: Context, compiledTemplate: Template) {
/**
* Add all required SNS alarms to the provided CloudFormation template
* based on the SNS resources found within
*
* A CloudFormation template object
*/

const resources = {}
const topicResources = getResourcesByType('AWS::SNS::Topic', compiledTemplate)

for (const [topicLogicalId] of Object.entries(topicResources)) {
for (const metric of executionMetrics) {
const config: DefaultAlarmsProperties = snsAlarmsConfig[metric]
const { enabled, ...rest } = config
if (enabled !== false) {
const snsAlarmProperties: CfAlarmsProperties = {
AlarmName: `SNS_${metric.replaceAll('-', '')}Alarm_\${${topicLogicalId}.TopicName}`,
AlarmDescription: `${metric} for \${${topicLogicalId}.TopicName} breaches (${config.Threshold}`,
MetricName: metric,
Namespace: 'AWS/SNS',
Dimensions: [{ Name: 'TopicName', Value: `\${${topicLogicalId}.TopicName}` }],
...rest
}
const resourceName = `slicWatch${metric.replaceAll('-', '')}Alarm${topicLogicalId}`
const resource = createAlarm(snsAlarmProperties, context)
resources[resourceName] = resource
}
}
}
return resources
return fetchAlarmResources('AWS::SNS::Topic', 'SNS', executionMetrics, snsAlarmsConfig, context, compiledTemplate,
({ metric, resourceName, config }) => ({
AlarmName: `SNS_${metric.replaceAll('-', '')}Alarm_${resourceName}`,
AlarmDescription: `${metric} for \${${resourceName}.TopicName} breaches (${config.Threshold}`,
Namespace: 'AWS/SNS',
Dimensions: [{ Name: 'TopicName', Value: `\${${resourceName}.TopicName}` }]
}))
}
10 changes: 3 additions & 7 deletions core/alarms/sqs.ts
Expand Up @@ -13,15 +13,11 @@ export interface SqsAlarmsConfig {

/**
* @param {object} sqsAlarmsConfig The fully resolved alarm configuration
* Add all required SQS alarms to the provided CloudFormation template
* based on the SQS resources found within
* A CloudFormation template object
*/
export default function createSQSAlarms (sqsAlarmsConfig: SqsAlarmsConfig, context: Context, compiledTemplate: Template) {
/**
* Add all required SQS alarms to the provided CloudFormation template
* based on the SQS resources found within
*
* A CloudFormation template object
*/

const resources = {}
const queueResources = getResourcesByType('AWS::SQS::Queue', compiledTemplate)

Expand Down

0 comments on commit d83d500

Please sign in to comment.