diff --git a/aws/policy/data-services.yaml b/aws/policy/data-services.yaml index fcc20bb..fa3fc86 100644 --- a/aws/policy/data-services.yaml +++ b/aws/policy/data-services.yaml @@ -67,6 +67,7 @@ Statement: - rds:CreateDBClusterParameterGroup - rds:CreateDBSubnetGroup - rds:DeleteDBCluster + - rds:DeleteGlobalCluster - rds:DeleteDBParameterGroup - rds:DeleteDBClusterParameterGroup - rds:DeleteDBSubnetGroup @@ -76,6 +77,7 @@ Statement: - rds:CreateDBInstanceReadReplica - rds:CreateDBInstance - rds:ModifyDBInstance + - rds:ModifyGlobalCluster - rds:DeleteDBInstance - rds:StopDBCluster - rds:StopDBInstance @@ -117,6 +119,8 @@ Statement: - 'arn:aws:redshift:{{ aws_region }}:{{ aws_account_id }}:subnetgroup:*' - 'arn:aws:rds:{{ aws_region }}:{{ aws_account_id }}:subgrp:*' - 'arn:aws:rds:{{ aws_region }}:{{ aws_account_id }}:cluster:*' + # RDS Global Cluster Resources do not have a region + - 'arn:aws:rds::{{ aws_account_id }}:global-cluster:*' - 'arn:aws:rds:{{ aws_region }}:{{ aws_account_id }}:db:*' - 'arn:aws:rds:{{ aws_region }}:{{ aws_account_id }}:pg:*' - 'arn:aws:rds:{{ aws_region }}:{{ aws_account_id }}:cluster-pg:*' @@ -128,11 +132,14 @@ Statement: Effect: Allow Action: - rds:CreateDBCluster + - rds:CreateGlobalCluster - elasticache:CreateCacheCluster - redshift:CreateCluster Resource: - 'arn:aws:rds:{{ aws_region }}:{{ aws_account_id }}:cluster:*' - 'arn:aws:rds:{{ aws_region }}:{{ aws_account_id }}:subgrp:*' + # RDS Global Cluster Resources do not have a region + - 'arn:aws:rds::{{ aws_account_id }}:global-cluster:*' - 'arn:aws:elasticache:{{ aws_region }}:{{ aws_account_id }}:cluster:*' - 'arn:aws:elasticache:{{ aws_region }}:{{ aws_account_id }}:subnetgroup:*' - 'arn:aws:elasticache:{{ aws_region }}:{{ aws_account_id }}:parametergroup:*' diff --git a/aws/terminator/data_services.py b/aws/terminator/data_services.py index 5816be9..68e4974 100644 --- a/aws/terminator/data_services.py +++ b/aws/terminator/data_services.py @@ -393,3 +393,34 @@ def age_limit(self): def terminate(self): self.client.delete_cluster(ClusterArn=self.id) + + +class RdsGlobalCluster(DbTerminator): + @staticmethod + def create(credentials): + return Terminator._create(credentials, RdsGlobalCluster, 'rds', lambda client: client.describe_global_clusters()['GlobalClusters']) + + @property + def id(self): + return self.instance['GlobalClusterArn'] + + @property + def name(self): + return self.instance['GlobalClusterIdentifier'] + + @property + def age_limit(self): + # Use an age_limit slightly lower than RdsDbCluster so that global cluster members won't conflict with that class before they're detached + return datetime.timedelta(minutes=55) + + @property + def members(self): + return self.instance['GlobalClusterMembers'] + + def terminate(self): + # The primary and secondary clusters must already be detached or destroyed first. + for db in self.members: + self.client.remove_from_global_cluster(GlobalClusterIdentifier=self.id, DbClusterIdentifier=[db['DBClusterArn']]) + + self.client.modify_global_cluster(GlobalClusterIdentifier=self.name, DeletionProtection=False) + self.client.delete_global_cluster(GlobalClusterIdentifier=self.name)