예제 #1
0
def lambda_rename_dbinstance(event, context):
    """Handles rename of a DB instance"""
    region = os.environ['Region']
    rds = boto3.client('rds', region)
    result = {}
    original_instance_identifier = ''
    modified_instance_identifier = ''
    try:
        if event.get('Error') == 'InstanceRestoreException' and \
                'Identifier' in event.get('Cause'):
            #rename revert scenario in case of db restore failure
            response = util.get_identifier_from_error(event)
            modified_instance_identifier = response["modified_identifier"]
            original_instance_identifier = response["original_identifier"]

        else:
            original_instance_identifier = event['identifier']
            modified_instance_identifier = event['identifier'] + '-temp'

        rds.modify_db_instance(
            DBInstanceIdentifier = original_instance_identifier,
            ApplyImmediately = True,
            NewDBInstanceIdentifier = modified_instance_identifier)

        result['taskname'] = constants.RENAME
        result['identifier'] = modified_instance_identifier
        return result

    except Exception as error:
        error_message = util.get_error_message(original_instance_identifier, error)
        if constants.RATE_EXCEEDED in str(error):
            raise custom_exceptions.RateExceededException(error_message)
        else:
            raise custom_exceptions.RenameException(error_message)
def lambda_delete_dbcluster(event, context):
    """Handles deletion of a DB cluster and its corresponding readers and writers"""
    region = os.environ['Region']
    rds = boto3.client('rds', region)
    result = {}
    cluster_id = event['identifier'] + constants.TEMP_POSTFIX
    try:
        describe_db_response = rds.describe_db_clusters(
            DBClusterIdentifier=cluster_id)
        for db_cluster_member in describe_db_response['DBClusters'][0][
                'DBClusterMembers']:
            rds.delete_db_instance(
                DBInstanceIdentifier=db_cluster_member['DBInstanceIdentifier'],
                SkipFinalSnapshot=True)
        rds.delete_db_cluster(DBClusterIdentifier=cluster_id,
                              SkipFinalSnapshot=True)
        result['taskname'] = constants.DELETE
        result['identifier'] = cluster_id
        return result
    except Exception as error:
        error_message = util.get_error_message(cluster_id, error)
        if constants.RATE_EXCEEDED in str(error):
            raise custom_exceptions.RateExceededException(error_message)
        else:
            raise custom_exceptions.DeletionException(error_message)
def lambda_rename_dbcluster(event, context):
    """Handles rename of a DB cluster and its corresponding readers and writers"""
    region = os.environ['Region']
    rds = boto3.client('rds', region)
    result = {}
    rename_response = {}
    try:
        #rename revert scenario in case of db cluster restore failure
        if event.get('Error') == 'ClusterRestoreException' and \
                'Identifier' in event.get('Cause'):
            rename_response = cluster_instance_rename_reversal(event, rds)
        else:
            rename_response = cluster_instance_rename(event, rds)
        #rename of the db cluster
        rds.modify_db_cluster(
            DBClusterIdentifier = rename_response["original_cluster_identifier"],
            ApplyImmediately = True,
            NewDBClusterIdentifier = rename_response["modified_cluster_identifier"]
        )
        result['taskname'] = constants.RENAME
        result['identifier'] = rename_response["modified_cluster_identifier"]
        return result
    except Exception as error:
        if constants.RATE_EXCEEDED in str(error):
            raise custom_exceptions.RateExceededException(str(error))
        else:
            raise custom_exceptions.RenameException(str(error))
예제 #4
0
파일: utility.py 프로젝트: namitad/Trapheus
def eval_exception(error, identifier, taskname):
    result = {}
    error_message = constants.IDENTIFIER + identifier + ' \n' + str(error)
    if taskname == constants.DELETE and \
         (str(error) == constants.CLUSTER_UNAVAILABLE or
          constants.CLUSTER_NOT_FOUND in str(error) or constants.NOT_FOUND in str(error)):
        result['task'] = constants.TASK_COMPLETE
        result['identifier'] = identifier
        result['taskname'] = taskname
        return result
    elif str(error) == constants.INSTANCE_UNAVAILABLE or constants.INSTANCE_NOT_FOUND in str(error) \
            or str(error) == constants.CLUSTER_UNAVAILABLE or constants.CLUSTER_NOT_FOUND in str(error) \
            or constants.NOT_FOUND in str(error):
        raise custom_exceptions.InstanceUnavailableException(error_message)
    elif constants.RATE_EXCEEDED in str(error) or constants.WAITER_MAX in str(error):
        raise custom_exceptions.RateExceededException(error_message)
    elif constants.WAITER_FAILURE in str(error):
        result['task'] = constants.TASK_FAILED
        result['status'] = error_message
        result['identifier'] = identifier
        result['taskname'] = taskname
        return result
    elif taskname in constants.TASK_ERROR_MAP:
        raise constants.TASK_ERROR_MAP[taskname](error_message)
    else:
        raise Exception(error_message)
예제 #5
0
def lambda_restore_dbinstance(event, context):
    """Handles restore of a db instance from its snapshot"""
    region = os.environ['Region']
    rds = boto3.client('rds', region)
    result = {}
    response = util.get_modified_identifier(event['identifier'])
    try:
        describe_db_response = rds.describe_db_instances(
            DBInstanceIdentifier=event['identifier'])
        vpc_security_groups = describe_db_response['DBInstances'][0][
            'VpcSecurityGroups']
        vpc_security_group_ids = []
        for vpc_security_group in vpc_security_groups:
            vpc_security_group_ids.append(
                vpc_security_group['VpcSecurityGroupId'])
        rds.restore_db_instance_from_db_snapshot(
            DBInstanceIdentifier=response["instance_id"],
            DBSnapshotIdentifier=response["snapshot_id"],
            DBSubnetGroupName=describe_db_response['DBInstances'][0]
            ['DBSubnetGroup']['DBSubnetGroupName'],
            VpcSecurityGroupIds=vpc_security_group_ids)
        result['taskname'] = constants.DB_RESTORE
        result['identifier'] = response["instance_id"]
        return result
    except Exception as error:
        error_message = util.get_error_message(response["instance_id"], error)
        if constants.RATE_EXCEEDED in str(error):
            raise custom_exceptions.RateExceededException(error_message)
        else:
            raise custom_exceptions.InstanceRestoreException(error_message)
예제 #6
0
 def setUp(self):
     self.event = {"identifier": "database-1"}
     self.instance_id = self.event['identifier'] + constants.TEMP_POSTFIX
     self.mocked_rate_exceeded_exception = custom_exceptions.RateExceededException(
         "Identifier:database-1-temp \nthrottling error: Rate exceeded")
     self.mocked_instance_not_found_exception = custom_exceptions.SnapshotCreationException(
         "Identifier:database-1-temp \nInstanceNotFoundFault")
예제 #7
0
 def setUp(self):
     self.mock_waiter = Mock()
     self.task_complete = "TASK_COMPLETE"
     self.task_failed = "TASK_FAILED"
     self.mock_rateexceeded_exception = custom_exceptions.RateExceededException(
         "Identifier:database-1 \nWaiter database-1 Max attempts exceeded")
     self.mock_instance_not_found_failure = custom_exceptions.InstanceUnavailableException(
         "Identifier:database-1 \nWaiter database-1 not found")
     self.mock_snapshot_creation_failure_status = "Identifier:database-1 \nWaiter encountered a terminal failure state"
예제 #8
0
def lambda_restore_dbcluster(event, context):
    """Handles restore of a db cluster from its snapshot"""
    region = os.environ['Region']
    result = {}
    rds = boto3.client('rds', region)
    old_cluster_id = event['identifier']
    response = util.get_modified_identifier(event['identifier'])
    cluster_id = response["instance_id"]
    cluster_snapshot_id = response["snapshot_id"]
    try:
        describe_db_response = rds.describe_db_clusters(
            DBClusterIdentifier=old_cluster_id)
        vpc_security_groups = describe_db_response['DBClusters'][0][
            'VpcSecurityGroups']
        engine = describe_db_response['DBClusters'][0]['Engine']
        engine_version = describe_db_response['DBClusters'][0]['EngineVersion']
        vpc_security_groups_ids = []
        for vpc_security_group in vpc_security_groups:
            vpc_security_groups_ids.append(
                vpc_security_group['VpcSecurityGroupId'])
        rds.restore_db_cluster_from_snapshot(
            DBClusterIdentifier=cluster_id,
            SnapshotIdentifier=cluster_snapshot_id,
            Engine=engine,
            EngineVersion=engine_version,
            DBSubnetGroupName=describe_db_response['DBClusters'][0]
            ['DBSubnetGroup'],
            Port=describe_db_response['DBClusters'][0]['Port'],
            DatabaseName=describe_db_response['DBClusters'][0]['DatabaseName'],
            VpcSecurityGroupIds=vpc_security_groups_ids)
        for db_cluster_member in describe_db_response['DBClusters'][0][
                'DBClusterMembers']:
            desc_db_response = rds.describe_db_instances(
                DBInstanceIdentifier=db_cluster_member['DBInstanceIdentifier'])
            dbinstance_identifier = util.get_modified_identifier(
                db_cluster_member['DBInstanceIdentifier'])["instance_id"]
            rds.create_db_instance(
                DBInstanceIdentifier=dbinstance_identifier,
                DBInstanceClass=desc_db_response['DBInstances'][0]
                ['DBInstanceClass'],
                Engine=engine,
                DBClusterIdentifier=cluster_id)

        result['taskname'] = constants.CLUSTER_RESTORE
        result['identifier'] = cluster_id
        return result
    except Exception as error:
        error_message = util.get_error_message(cluster_id, error)
        if constants.RATE_EXCEEDED in str(error):
            raise custom_exceptions.RateExceededException(error_message)
        else:
            raise custom_exceptions.ClusterRestoreException(error_message)
예제 #9
0
    def setUp(self):
        self.event = {"identifier": "database-1-temp"}
        self.cluster_id = "database-1"
        self.mocked_rate_exceeded_exception = custom_exceptions.RateExceededException(
            "Identifier:database-1 \nthrottling error: Rate exceeded")
        self.mocked_cluster_not_found_exception = custom_exceptions.ClusterRestoreException(
            "Identifier:database-1 \nDBClusterNotFound")
        self.cluster_restore_exception = custom_exceptions.ClusterRestoreException(
            "Identifier:database-1 \nCluster restoration failed")
        self.dbinstance_creation_exception = custom_exceptions.ClusterRestoreException(
            "Identifier:database-1-instance-1 \nDBInstance creation failed")
        self.mocked_describe_db_clusters = {
            "ResponseMetadata": {
                'HTTPStatusCode': 200
            },
            "DBClusters": [{
                "DBClusterIdentifier":
                "database-1-temp",
                "DatabaseName":
                "POSTGRES",
                "Port":
                3306,
                "Engine":
                "xyzz",
                "EngineVersion":
                10.7,
                "VpcSecurityGroups": [{
                    "VpcSecurityGroupId": "abc"
                }],
                "DBSubnetGroup": {
                    "DBSubnetGroupName": "xyz"
                },
                "DBClusterMembers": [{
                    "DBInstanceIdentifier": "database-1-instance-1-temp",
                    "IsClusterWriter": True,
                    "PromotionTier": 123
                }]
            }]
        }

        self.mocked_describe_db_instances = {
            'ResponseMetadata': {
                'HTTPStatusCode': 200
            },
            "DBInstances": [{
                "DBInstanceIdentifier": "database-1-instance-1-temp",
                "DBInstanceClass": "postgres-ee"
            }]
        }
예제 #10
0
def lambda_delete_dbinstance(event, context):
    """Handles deletion of a RDS db instance"""
    region = os.environ['Region']
    rds = boto3.client('rds', region)
    result = {}
    instance_id = event['identifier'] + constants.TEMP_POSTFIX
    try:
        rds.delete_db_instance(DBInstanceIdentifier=instance_id,
                               SkipFinalSnapshot=True)
        result['taskname'] = constants.DELETE
        result['identifier'] = instance_id
        return result
    except Exception as error:
        error_message = util.get_error_message(instance_id, error)
        if constants.RATE_EXCEEDED in str(error):
            raise custom_exceptions.RateExceededException(error_message)
        else:
            raise custom_exceptions.DeletionException(error_message)
예제 #11
0
def eval_snapshot_exception(error, identifier, rds_client):
    error_message = constants.IDENTIFIER + identifier + ' \n' + str(error)
    snapshot_id = identifier + constants.SNAPSHOT_POSTFIX
    if constants.RATE_EXCEEDED in str(error):
        raise custom_exceptions.RateExceededException(error_message)
    elif constants.CLUSTER_SNAPSHOT_EXISTS in str(error):
        waiter = rds_client.get_waiter('db_cluster_snapshot_deleted')
        rds_client.delete_db_cluster_snapshot(
            DBClusterSnapshotIdentifier=snapshot_id)
        waiter.wait(DBClusterSnapshotIdentifier=snapshot_id)
        raise custom_exceptions.RetryClusterSnapshotException(error_message)
    elif constants.DB_SNAPSHOT_EXISTS in str(error):
        waiter = rds_client.get_waiter('db_snapshot_deleted')
        rds_client.delete_db_snapshot(DBSnapshotIdentifier=snapshot_id)
        waiter.wait(DBSnapshotIdentifier=snapshot_id)
        raise custom_exceptions.RetryDBSnapshotException(error_message)
    else:
        raise custom_exceptions.SnapshotCreationException(error_message)
 def setUp(self):
     self.event = {'identifier': 'database-1'}
     self.cluster_id = self.event['identifier'] + constants.TEMP_POSTFIX
     self.mocked_rate_exceeded_exception = custom_exceptions.RateExceededException(
         "Identifier:database-1-temp \nthrottling error: Rate exceeded")
     self.mocked_cluster_not_found_exception = custom_exceptions.DeletionException(
         "Identifier:database-1-temp \nDBClusterNotFound")
     self.mocked_instance_not_found_exception = custom_exceptions.DeletionException(
         "Identifier:database-1-temp \nInstanceDeletionFailure")
     self.mocked_describe_db_clusters = {
         'ResponseMetadata': {
             'HTTPStatusCode': 200
         },
         'DBClusters': [{
             "DBClusterIdentifier":
             "database-1-temp",
             "DBClusterMembers": [{
                 "DBInstanceIdentifier": "database-1-instance-1-temp",
                 "IsClusterWriter": True,
                 "PromotionTier": 123
             }]
         }]
     }
예제 #13
0
 def setUp(self):
     self.mock_waiter = Mock()
     self.task_complete = "TASK_COMPLETE"
     self.task_failed = "TASK_FAILED"
     self.mock_rateexceeded_exception = custom_exceptions.RateExceededException(
         "Identifier:database-1 \nWaiter database-1 Max attempts exceeded")
     self.mock_instance_not_found_failure = custom_exceptions.InstanceUnavailableException(
         "Identifier:database-1 \nWaiter database-1 not found")
     self.mock_snapshot_creation_failure_status = "Identifier:database-1 \nWaiter encountered a terminal failure state"
     self.mocked_describe_db_clusters = {
         "ResponseMetadata": {
             'HTTPStatusCode': 200
         },
         "DBClusters": [{
             "DBClusterIdentifier":
             "database-1",
             "DatabaseName":
             "POSTGRES",
             "Port":
             3306,
             "Engine":
             "xyzz",
             "EngineVersion":
             10.7,
             "VpcSecurityGroups": [{
                 "VpcSecurityGroupId": "abc"
             }],
             "DBSubnetGroup": {
                 "DBSubnetGroupName": "xyz"
             },
             "DBClusterMembers": [{
                 "DBInstanceIdentifier": "database-1-instance-1",
                 "IsClusterWriter": True,
                 "PromotionTier": 123
             }]
         }]
     }
    def setUp(self):
        self.event = {"identifier": "database-1"}
        self.revert_event = {"Error": "ClusterRestoreException","Cause": "DBClusterIdentifier:database-1 \n ThrottlingError: Rate exceeded"}
        self.updated_cluster_id = self.event['identifier'] + constants.TEMP_POSTFIX
        self.original_cluster_id = self.event['identifier']
        self.mocked_rate_exceeded_exception = custom_exceptions.RateExceededException("Identifier:database-1-temp \nthrottling error: Rate exceeded")
        self.mocked_cluster_not_found_exception = custom_exceptions.RenameException("Identifier:database-1-temp \nDBClusterNotFound")
        self.mocked_instance_not_found_exception = custom_exceptions.RenameException("Identifier:database-1-temp \nDBInstanceNotFound")
        self.mocked_describe_db_clusters = {
            'ResponseMetadata': {
                'HTTPStatusCode': 200
            },
            'DBClusters': [{
                "DBClusterIdentifier": "database-1",
                "DBClusterMembers": [{
                    "DBInstanceIdentifier": "database-1-instance-1",
                    "IsClusterWriter": True,
                    "PromotionTier": 123
                }]
            }]
        }

        self.mocked_modify_db_cluster = {
            'ResponseMetadata': {
                'HTTPStatusCode': 200
            },
            'DBClusters': {
                "DBClusterIdentifier": "database-1-temp",
                "Status": "renaming",
                "DBClusterMembers": [{
                    "DBInstanceIdentifier": "database-1-instance-1-temp",
                    "IsClusterWriter": True,
                    "PromotionTier": 123
                }]
            }
        }
예제 #15
0
 def setUp(self):
     self.event = {"identifier": "database-1-temp"}
     self.restored_instance_id = "database-1"
     self.mocked_rate_exceeded_exception = custom_exceptions.RateExceededException(
         "Identifier:database-1 \nthrottling error: Rate exceeded")
     self.mocked_instance_not_found_exception = custom_exceptions.InstanceRestoreException(
         "Identifier:database-1 \nDBInstanceNotFound")
     self.mocked_duplicate_instance_exception = custom_exceptions.InstanceRestoreException(
         "Identifier:database-1 \nDBInstanceAlreadyExistsFault")
     self.mocked_describe_db_instances = {
         'ResponseMetadata': {
             'HTTPStatusCode': 200
         },
         "DBInstances": [{
             "DBInstanceIdentifier":
             "database-1-temp",
             "VpcSecurityGroups": [{
                 "VpcSecurityGroupId": "abc"
             }],
             "DBSubnetGroup": {
                 "DBSubnetGroupName": "xyz"
             }
         }]
     }
 def setUp(self):
     self.event = {"identifier": "database-1"}
     self.mocked_rate_exceeded_exception = custom_exceptions.RateExceededException("Identifier:database-1 \nthrottling error: Rate exceeded")
     self.mocked_cluster_not_found_exception = custom_exceptions.SnapshotCreationException("Identifier:database-1 \nDBClusterNotFound")
     self.mocked_duplicate_snapshot_exception = custom_exceptions.RetryClusterSnapshotException("Identifier:database-1 \nDBClusterSnapshotAlreadyExistsFault")