Last active
February 9, 2024 15:31
-
-
Save kichik/7a2ecb0d36358c50c7b878ad9fd982bc to your computer and use it in GitHub Desktop.
CloudFormation template that stops RDS from automatically starting back up
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
# aws cloudformation deploy --template-file KeepDbStopped.yml --stack-name stop-db --capabilities CAPABILITY_IAM --parameter-overrides DB=arn:aws:rds:us-east-1:XXX:db:XXX | |
Description: Automatically stop RDS instance every time it turns on due to exceeding the maximum allowed time being stopped | |
Parameters: | |
DB: | |
Description: ARN of database that needs to be stopped | |
Type: String | |
AllowedPattern: arn:aws:rds:[a-z0-9\-]+:[0-9]+:db:[^:]* | |
MaxStartupTime: | |
Description: Maximum number of minutes to wait between database is automatically started and the time it's ready to be shut down. Extend this limit if your database takes a long time to boot up. | |
Type: Number | |
MinValue: 10 | |
Default: 25 | |
Resources: | |
DatabaseStopperFunction: | |
Type: AWS::Lambda::Function | |
Properties: | |
Role: !GetAtt DatabaseStopperRole.Arn | |
Runtime: python3.6 | |
Handler: index.handler | |
Timeout: 20 | |
Code: | |
ZipFile: | |
Fn::Sub: | | |
import boto3 | |
import time | |
def handler(event, context): | |
print("got", event) | |
db = event["detail"]["SourceArn"] | |
id = event["detail"]["SourceIdentifier"] | |
message = event["detail"]["Message"] | |
region = event["region"] | |
rds = boto3.client("rds", region_name=region) | |
if message == "DB instance is being started due to it exceeding the maximum allowed time being stopped.": | |
print("database turned on automatically, setting last seen tag...") | |
last_seen = int(time.time()) | |
rds.add_tags_to_resource(ResourceName=db, Tags=[{"Key": "DbStopperLastSeen", "Value": str(last_seen)}]) | |
elif message == "DB instance started": | |
print("database started (and sort of available?)") | |
last_seen = 0 | |
for t in rds.list_tags_for_resource(ResourceName=db)["TagList"]: | |
if t["Key"] == "DbStopperLastSeen": | |
last_seen = int(t["Value"]) | |
if time.time() < last_seen + (60 * ${MaxStartupTime}): | |
print("database was automatically started in the last ${MaxStartupTime} minutes, turning off...") | |
time.sleep(10) # even waiting for the "started" event is not enough, so add some wait | |
rds.stop_db_instance(DBInstanceIdentifier=id) | |
print("success! removing auto-start tag...") | |
rds.add_tags_to_resource(ResourceName=db, Tags=[{"Key": "DbStopperLastSeen", "Value": "0"}]) | |
else: | |
print("ignoring manual database start") | |
else: | |
print("error: unknown database event!") | |
DatabaseStopperRole: | |
Type: AWS::IAM::Role | |
Properties: | |
AssumeRolePolicyDocument: | |
Version: '2012-10-17' | |
Statement: | |
- Action: | |
- sts:AssumeRole | |
Effect: Allow | |
Principal: | |
Service: | |
- lambda.amazonaws.com | |
ManagedPolicyArns: | |
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole | |
Policies: | |
- PolicyName: Notify | |
PolicyDocument: | |
Version: '2012-10-17' | |
Statement: | |
- Action: | |
- rds:StopDBInstance | |
Effect: Allow | |
Resource: !Ref DB | |
- Action: | |
- rds:AddTagsToResource | |
- rds:ListTagsForResource | |
- rds:RemoveTagsFromResource | |
Effect: Allow | |
Resource: !Ref DB | |
Condition: | |
ForAllValues:StringEquals: | |
aws:TagKeys: | |
- DbStopperLastSeen | |
DatabaseStopperPermission: | |
Type: AWS::Lambda::Permission | |
Properties: | |
Action: lambda:InvokeFunction | |
FunctionName: !GetAtt DatabaseStopperFunction.Arn | |
Principal: events.amazonaws.com | |
SourceArn: !GetAtt DatabaseStopperRule.Arn | |
DatabaseStopperRule: | |
Type: AWS::Events::Rule | |
Properties: | |
EventPattern: | |
source: | |
- aws.rds | |
detail-type: | |
- "RDS DB Instance Event" | |
resources: | |
- !Ref DB | |
detail: | |
Message: | |
- "DB instance is being started due to it exceeding the maximum allowed time being stopped." | |
- "DB instance started" | |
Targets: | |
- Arn: !GetAtt DatabaseStopperFunction.Arn | |
Id: DatabaseStopperLambda |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Run it against actual event test data.
Do you see
{'key1: 'value1', 'key2': 'value2', 'key3': 'value3'}
containingSourceArn
?