hello
Last active
April 3, 2024 06:14
-
-
Save jhw/3476ce0621d0d642bf0e98e048053256 to your computer and use it in GitHub Desktop.
Lambda Cloudwatch Alarm demo
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
env | |
*.pyc | |
__pycache__ | |
tmp | |
setenv-priv.sh |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
AppName=cloudwatch-alarm-demo |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
. app.props | |
aws cloudformation delete-stack --stack-name $AppName |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
. app.props | |
aws cloudformation deploy --stack-name $AppName --template-file stack.yaml --capabilities CAPABILITY_NAMED_IAM | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from botocore.exceptions import ClientError | |
import boto3, os, re, sys, time | |
def fetch_log_events(logs, kwargs): | |
events, token = [], None | |
while True: | |
if token: | |
kwargs["nextToken"]=token | |
resp=logs.filter_log_events(**kwargs) | |
events+=resp["events"] | |
if "nextToken" in resp: | |
token=resp["nextToken"] | |
else: | |
break | |
return sorted(events, | |
key=lambda x: x["timestamp"]) | |
if __name__=="__main__": | |
try: | |
if len(sys.argv) < 3: | |
raise RuntimeError("please enter lambda name, window") | |
lambdaname, window = sys.argv[1:3] | |
if not re.search("^\\d+$", window): | |
raise RuntimeError("window is invalid") | |
window=int(window) | |
logs=boto3.client("logs") | |
starttime=int(1000*(time.time()-window)) | |
loggroupname="/aws/lambda/%s" % lambdaname | |
kwargs={"logGroupName": loggroupname, | |
"startTime": starttime, | |
"interleaved": True} | |
events=fetch_log_events(logs, kwargs) | |
for event in events: | |
msg=re.sub("\\r|\\n", "", event["message"]) | |
print (msg) | |
except RuntimeError as error: | |
print ("Error: %s" % str(error)) | |
except ClientError as error: | |
print ("Error: %s" % str(error)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
. app.props | |
aws cloudformation describe-stack-events --stack-name $AppName --query "StackEvents[].{\"1.Timestamp\":Timestamp,\"2.Id\":LogicalResourceId,\"3.Type\":ResourceType,\"4.Status\":ResourceStatus,\"5.Reason\":ResourceStatusReason}" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
. app.props | |
aws cloudformation describe-stacks --stack-name $AppName --query 'Stacks[0].Outputs' --output table |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
. app.props | |
aws cloudformation describe-stack-resources --stack-name $AppName --query "StackResources[].{\"1.Timestamp\":Timestamp,\"2.LogicalId\":LogicalResourceId,\"3.PhysicalId\":PhysicalResourceId,\"4.Type\":ResourceType,\"5.Status\":ResourceStatus}" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
aws cloudformation describe-stacks --query "Stacks[].{\"1.Name\":StackName,\"2.Status\":StackStatus}" |
- AWS::SNS::Topic, AWS::SNS::Subscription
- AWS::CloudWatch::Alarm
- alarm mixin (like Slack) defining topic, subscription, function (logger.warning), role and policy
- not sure this function needs a subscription filter
- then there is a hook() function which adds the cloudwatch alarm, connecting the target function to the topic via the alarm
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from botocore.exceptions import ClientError | |
import boto3, json, os, re, time | |
def hungarorise(text): | |
return "".join([tok.capitalize() | |
for tok in re.split("\\-|\\_", text)]) | |
def fetch_outputs(cf, stackname): | |
outputs={} | |
for stack in cf.describe_stacks()["Stacks"]: | |
if (stack["StackName"].startswith(stackname) and | |
"Outputs" in stack): | |
for output in stack["Outputs"]: | |
outputs[output["OutputKey"]]=output["OutputValue"] | |
return outputs | |
if __name__=="__main__": | |
try: | |
props=dict([tuple(row.split("=")) | |
for row in open("app.props").read().split("\n") | |
if row!='']) | |
stackname=props["AppName"] | |
cf=boto3.client("cloudformation") | |
outputs=fetch_outputs(cf, stackname) | |
targetkey=hungarorise("target-lambda-function-name") | |
if targetkey not in outputs: | |
raise RuntimeError("target not found") | |
targetname=outputs[targetkey] | |
L=boto3.client("lambda") | |
for i in range(10): | |
print (L.invoke(FunctionName=targetname, | |
InvocationType='RequestResponse', | |
Payload=json.dumps({"hello": "world"}))) | |
time.sleep(1) | |
except RuntimeError as error: | |
print ("Error: %s" % str(error)) | |
except ClientError as error: | |
print ("Error: %s" % str(error)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
awscli | |
boto3 | |
botocore | |
pyyaml | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
export AWS_DEFAULT_OUTPUT=table | |
export AWS_PROFILE=#{your-aws-profile-here} | |
export AWS_REGION=#{your-aws-region-here} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
AWSTemplateFormatVersion: '2010-09-09' | |
Resources: | |
TargetLambdaFunction: | |
Type: AWS::Lambda::Function | |
Properties: | |
Code: | |
ZipFile: | | |
def handler(event, context): | |
print("Target Lambda called") | |
return { | |
'statusCode': 200, | |
'body': 'Hello from Lambda!' | |
} | |
Handler: index.handler | |
Role: !GetAtt GenericLambdaRole.Arn | |
Runtime: python3.10 | |
AlarmTopic: | |
Type: AWS::SNS::Topic | |
CloudWatchAlarm: | |
Type: AWS::CloudWatch::Alarm | |
Properties: | |
AlarmDescription: "Invoke Alarm when target Lambda is called more than 5 times in 1 minute" | |
Namespace: "AWS/Lambda" | |
MetricName: "Invocations" | |
Dimensions: | |
- Name: "FunctionName" | |
Value: !Ref TargetLambdaFunction | |
Statistic: "Sum" | |
Period: 60 | |
EvaluationPeriods: 1 | |
Threshold: 5 | |
ComparisonOperator: "GreaterThanThreshold" | |
AlarmActions: | |
- Ref: AlarmTopic | |
GenericLambdaRole: | |
Type: AWS::IAM::Role | |
Properties: | |
AssumeRolePolicyDocument: | |
Version: '2012-10-17' | |
Statement: | |
- Effect: Allow | |
Principal: | |
Service: lambda.amazonaws.com | |
Action: sts:AssumeRole | |
Policies: | |
- PolicyName: AlarmLambdaPolicy | |
PolicyDocument: | |
Version: '2012-10-17' | |
Statement: | |
- Effect: Allow | |
Action: | |
- logs:CreateLogGroup | |
- logs:CreateLogStream | |
- logs:PutLogEvents | |
Resource: arn:aws:logs:*:*:* | |
- Effect: Allow | |
Action: "lambda:InvokeFunction" | |
Resource: "*" | |
AlarmLambdaFunction: | |
Type: AWS::Lambda::Function | |
Properties: | |
Code: | |
ZipFile: | | |
def handler(event, context): | |
print (event) | |
Handler: index.handler | |
Role: !GetAtt GenericLambdaRole.Arn | |
Runtime: python3.10 | |
TopicSubscriptionForAlarm: | |
Type: AWS::SNS::Subscription | |
Properties: | |
TopicArn: !Ref AlarmTopic | |
Protocol: lambda | |
Endpoint: !GetAtt AlarmLambdaFunction.Arn | |
PermissionForAlarmLambda: | |
Type: AWS::Lambda::Permission | |
Properties: | |
FunctionName: !GetAtt AlarmLambdaFunction.Arn | |
Action: "lambda:InvokeFunction" | |
Principal: "sns.amazonaws.com" | |
SourceArn: !Ref AlarmTopic | |
Outputs: | |
TargetLambdaFunctionName: | |
Value: !Ref TargetLambdaFunction | |
AlarmLambdaFunctionName: | |
Value: !Ref AlarmLambdaFunction |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment