180 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			YAML
		
	
	
			
		
		
	
	
			180 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			YAML
		
	
	
| AWSTemplateFormatVersion: '2010-09-09'
 | |
| Description: Schedule automatic deletion of CloudFormation stacks
 | |
| Metadata:
 | |
|   AWS::CloudFormation::Interface:
 | |
|     ParameterGroups:
 | |
|       - Label:
 | |
|           default: Input configuration
 | |
|         Parameters:
 | |
|           - StackName
 | |
|           - TTL
 | |
|     ParameterLabels:
 | |
|       StackName:
 | |
|         default: Stack name
 | |
|       TTL:
 | |
|         default: Time-to-live
 | |
| Parameters:
 | |
|   BUILDID:
 | |
|     Type: String
 | |
|     Default: ''
 | |
|   StackName:
 | |
|     Type: String
 | |
|     Description: Stack name that will be deleted.
 | |
|   TTL:
 | |
|     Type: Number
 | |
|     Description: Time-to-live in minutes for the stack.
 | |
| Resources:
 | |
|   DeleteCFNLambdaExecutionRole:
 | |
|     Type: "AWS::IAM::Role"
 | |
|     Properties:
 | |
|       AssumeRolePolicyDocument:
 | |
|         Version: "2012-10-17"
 | |
|         Statement:
 | |
|         - Effect: "Allow"
 | |
|           Principal:
 | |
|             Service: ["lambda.amazonaws.com"]
 | |
|           Action: "sts:AssumeRole"
 | |
|       Path: "/"
 | |
|       Policies:
 | |
|       - PolicyName: !Join [ "", [ 'DeleteCFNLambdaExecutionRole', !Ref BUILDID ] ]
 | |
|         PolicyDocument:
 | |
|           Version: "2012-10-17"
 | |
|           Statement:
 | |
|           - Effect: "Allow"
 | |
|             Action:
 | |
|             - "logs:CreateLogGroup"
 | |
|             - "logs:CreateLogStream"
 | |
|             - "logs:PutLogEvents"
 | |
|             Resource: "arn:aws:logs:*:*:*"
 | |
|           - Effect: "Allow"
 | |
|             Action:
 | |
|             - "cloudformation:DeleteStack"
 | |
|             Resource: !Sub "arn:aws:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/${StackName}/*"
 | |
|   DeleteCFNLambda:
 | |
|     Type: "AWS::Lambda::Function"
 | |
|     DependsOn:
 | |
|       - DeleteCFNLambdaExecutionRole
 | |
|     Properties:
 | |
|       FunctionName: !Sub "DeleteCFNLambda-${StackName}"
 | |
|       Code:
 | |
|         ZipFile: |
 | |
|           import boto3
 | |
|           import os
 | |
|           import json
 | |
|           
 | |
|           stack_name = os.environ['stackName']
 | |
|           
 | |
|           def delete_cfn(stack_name):
 | |
|               try:
 | |
|                   cfn = boto3.resource('cloudformation')
 | |
|                   stack = cfn.Stack(stack_name)
 | |
|                   stack.delete()
 | |
|                   return "SUCCESS"
 | |
|               except:
 | |
|                   return "ERROR" 
 | |
|           
 | |
|           def handler(event, context):
 | |
|               print("Received event:")
 | |
|               print(json.dumps(event))
 | |
|               return delete_cfn(stack_name)          
 | |
|       Environment:
 | |
|         Variables:
 | |
|           stackName: !Ref 'StackName'
 | |
|       Handler: "index.handler"
 | |
|       Runtime: "python3.6"
 | |
|       Timeout: "5"
 | |
|       Role: !GetAtt DeleteCFNLambdaExecutionRole.Arn
 | |
|   DeleteStackEventRule:
 | |
|      DependsOn:
 | |
|        - DeleteCFNLambda
 | |
|        - GenerateCronExpression
 | |
|      Type: "AWS::Events::Rule"
 | |
|      Properties:
 | |
|        Name: !Join [ "", [ 'DeleteStackEventRule', !Ref BUILDID ] ]
 | |
|        Description: Delete stack event
 | |
|        ScheduleExpression: !GetAtt GenerateCronExpression.cron_exp
 | |
|        State: "ENABLED"
 | |
|        Targets: 
 | |
|           - 
 | |
|             Arn: !GetAtt DeleteCFNLambda.Arn
 | |
|             Id: 'DeleteCFNLambda' 
 | |
|   PermissionForDeleteCFNLambda: 
 | |
|     Type: "AWS::Lambda::Permission"
 | |
|     Properties: 
 | |
|       FunctionName: !Sub "arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:DeleteCFNLambda-${StackName}"
 | |
|       Action: "lambda:InvokeFunction"
 | |
|       Principal: "events.amazonaws.com"
 | |
|       SourceArn: !GetAtt DeleteStackEventRule.Arn
 | |
|   BasicLambdaExecutionRole:
 | |
|     Type: "AWS::IAM::Role"
 | |
|     Properties:
 | |
|       AssumeRolePolicyDocument:
 | |
|         Version: "2012-10-17"
 | |
|         Statement:
 | |
|         - Effect: "Allow"
 | |
|           Principal:
 | |
|             Service: ["lambda.amazonaws.com"]
 | |
|           Action: "sts:AssumeRole"
 | |
|       Path: "/"
 | |
|       Policies:
 | |
|       - PolicyName: !Join [ "", [ 'BasicLambdaExecutionRole', !Ref BUILDID ] ]
 | |
|         PolicyDocument:
 | |
|           Version: "2012-10-17"
 | |
|           Statement:
 | |
|           - Effect: "Allow"
 | |
|             Action:
 | |
|             - "logs:CreateLogGroup"
 | |
|             - "logs:CreateLogStream"
 | |
|             - "logs:PutLogEvents"
 | |
|             Resource: "arn:aws:logs:*:*:*"
 | |
|   GenerateCronExpLambda:
 | |
|     Type: "AWS::Lambda::Function"
 | |
|     Properties:
 | |
|       Name: !Join [ "", [ 'GenerateCronExpLambda', !Ref BUILDID ] ]
 | |
|       Code:
 | |
|         ZipFile: |
 | |
|           from datetime import datetime, timedelta
 | |
|           import os
 | |
|           import logging
 | |
|           import json
 | |
|           import cfnresponse
 | |
|           
 | |
|           def deletion_time(ttl):
 | |
|               delete_at_time = datetime.now() + timedelta(minutes=int(ttl))
 | |
|               hh = delete_at_time.hour
 | |
|               mm = delete_at_time.minute
 | |
|               yyyy = delete_at_time.year
 | |
|               month = delete_at_time.month
 | |
|               dd = delete_at_time.day
 | |
|               # minutes hours day month day-of-week year
 | |
|               cron_exp = "cron({} {} {} {} ? {})".format(mm, hh, dd, month, yyyy)
 | |
|               return cron_exp
 | |
|           
 | |
|           def handler(event, context):
 | |
|             print('Received event: %s' % json.dumps(event))
 | |
|             status = cfnresponse.SUCCESS
 | |
|             try:
 | |
|                 if event['RequestType'] == 'Delete':
 | |
|                     cfnresponse.send(event, context, status, {})
 | |
|                 else:
 | |
|                     ttl = event['ResourceProperties']['ttl']
 | |
|                     responseData = {}
 | |
|                     responseData['cron_exp'] = deletion_time(ttl)
 | |
|                     cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData)
 | |
|             except Exception as e:
 | |
|                 logging.error('Exception: %s' % e, exc_info=True)
 | |
|                 status = cfnresponse.FAILED
 | |
|                 cfnresponse.send(event, context, status, {}, None)          
 | |
|       Handler: "index.handler"
 | |
|       Runtime: "python3.6"
 | |
|       Timeout: "5"
 | |
|       Role: !GetAtt BasicLambdaExecutionRole.Arn
 | |
| 
 | |
|   GenerateCronExpression:
 | |
|     Type: "Custom::GenerateCronExpression"
 | |
|     Version: "1.0"
 | |
|     Properties:
 | |
|       Name: !Join [ "", [ 'GenerateCronExpression', !Ref BUILDID ] ]
 | |
|       ServiceToken: !GetAtt GenerateCronExpLambda.Arn
 | |
|       ttl: !Ref 'TTL'
 |