AWSTemplateFormatVersion: 2010-09-09
Resources:
  SNSTopic:
    Type: 'AWS::SNS::Topic'
    Properties:
      TopicName: RDS-SNS-Storage-Scaler
    DependsOn:
      - LambdaFunction
  LambdaFunction:
    Type: 'AWS::Lambda::Function'
    Properties:
      Code:
        ZipFile: |
          import sys, botocore, boto3, json, math 
          def lambda_handler(event, context):
              ScalingUnder1000GB = 1.2
              Scaling1000GBto5000GB = 1.15 
              ScalingOver5000GB = 1.10 
              GetDBName = event['Records']
              for f in GetDBName:
                  for g, h in f.items():
                      if g == 'Sns':
                          GetDBName = h
              GetDBName = json.loads(GetDBName['Message'])
              AlarmName = [GetDBName['AlarmName']]
              cloudwatch = boto3.client('cloudwatch')
              DescribeAlarm = cloudwatch.describe_alarms(AlarmNames = AlarmName)
              DescribeAlarm = DescribeAlarm['MetricAlarms']
              for a in DescribeAlarm:
                  for a, b in a.items():
                      if a == 'AlarmActions':
                          AlarmActions = b
              for a in DescribeAlarm:
                  for a, b in a.items():
                      if a == 'EvaluationPeriods':
                          EvaluationPeriods = b
              for a in DescribeAlarm:
                  for a, b in a.items():
                      if a == 'Threshold':
                          Threshold = b
              DBName = GetDBName['Trigger']['Dimensions']
              for a in DBName:
                  for a, b in a.items():
                      if a == 'value':
                          DBName = b
              rds = boto3.client('rds')
              response = rds.describe_db_instances(DBInstanceIdentifier= DBName)
              response = response['DBInstances']
              for x in response:
                  for y, z in x.items():
                      if y == 'StorageType':
                          StorageType = z
              for g in response:
                  for h, i in g.items():
                      if h == 'Iops':
                          Iops = i
              for c in response:
                  for d, e in c.items():
                      if d == 'AllocatedStorage':
                          AllocatedStorage = e
                          if AllocatedStorage < 1000:
                            AllocatedStorage = math.ceil(AllocatedStorage * ScalingUnder1000GB)
                            Threshold = math.ceil(Threshold * ScalingUnder1000GB)
                          elif (AllocatedStorage >= 1000 and AllocatedStorage <= 5000):
                            AllocatedStorage = math.ceil(AllocatedStorage * Scaling1000GBto5000GB)
                            Threshold = math.ceil(Threshold * Scaling1000GBto5000GB)
                          elif AllocatedStorage > 5000:
                            AllocatedStorage = math.ceil(AllocatedStorage * ScalingOver5000GB)
                            Threshold = math.ceil(Threshold * ScalingOver5000GB)
                          else:
                            exit()
                          if StorageType == 'io1':
                            response = rds.modify_db_instance(DBInstanceIdentifier= DBName, Iops = Iops, AllocatedStorage= AllocatedStorage, ApplyImmediately=True)
                            modifycloudwatch = cloudwatch.put_metric_alarm(AlarmName = AlarmName[0], AlarmActions = AlarmActions, Period = 60, MetricName = 'FreeStorageSpace', Dimensions = [{'Name': 'DBInstanceIdentifier', 'Value': DBName},], Statistic = 'Average', Namespace = 'AWS/RDS', EvaluationPeriods = EvaluationPeriods, ComparisonOperator = 'LessThanThreshold', Threshold = Threshold)
                            exit()
                          else:
                            response = rds.modify_db_instance(DBInstanceIdentifier= DBName, AllocatedStorage= AllocatedStorage, ApplyImmediately=True)
                            modifycloudwatch = cloudwatch.put_metric_alarm(AlarmName = AlarmName[0], AlarmActions = AlarmActions, Period = 60, MetricName = 'FreeStorageSpace', Dimensions = [{'Name': 'DBInstanceIdentifier', 'Value': DBName},], Statistic = 'Average', Namespace = 'AWS/RDS', EvaluationPeriods = EvaluationPeriods, ComparisonOperator = 'LessThanThreshold', Threshold = Threshold)
                            exit()

      Role: !Join
        - ''
        - - 'arn:aws:iam::'
          - !Ref AWS::AccountId
          - ':role/LambdaExecutionRoleStorageScaling'
      Handler: index.lambda_handler
      FunctionName: RDS-Lambda-Storage-Scaler
      Runtime: python3.11
      Timeout: 15
  SNSSubscription:
    Type: 'AWS::SNS::Subscription'
    Properties:
      TopicArn: !Ref SNSTopic
      Endpoint: !GetAtt LambdaFunction.Arn
      Protocol: lambda
    DependsOn:
      - SNSTopic
  LambdaResourcePolicy:
    Type: 'AWS::Lambda::Permission'
    Properties: 
      Action: lambda:InvokeFunction
      FunctionName: !GetAtt LambdaFunction.Arn
      Principal: sns.amazonaws.com
      SourceArn: !Ref SNSTopic
    DependsOn:
      - LambdaFunction
        
