class NotifyTest(TestCase): def setUp(self): self.notify = Notify(logger) @mock_sns def test_customer_notify(self): conn = boto3.client('sns', region_name='us-east-1') conn.create_topic(Name="dummy-topic") response = conn.list_topics() topic_arn = response["Topics"][0]['TopicArn'] message = { 'key_string1': '2017-7-6', 'key_string2': '12345', 'decimal': Decimal('1') } response = self.notify.customer(topic_arn, message) self.assertTrue(response['ResponseMetadata']['HTTPStatusCode'] == 200) def test_backend_metrics(self): uuid = str(uuid4()) solution_id = 'SO_unit_test' customer_uuid = uuid logger.info("UUID: " + customer_uuid) data = { 'key_string1': '2017-7-6', 'key_string2': '12345', 'decimal': Decimal('1') } url = 'https://oszclq8tyh.execute-api.us-east-1.amazonaws.com/prod/generic' response = self.notify.metrics(solution_id, customer_uuid, data, url) self.assertTrue(response == 200)
def lambda_handler(event, context): logger.debug('Lambda Event') logger.debug(event) # Event triggered when AutoScaling updated from 1 to 0 desired capacity if event.get('detail', {}).get('LifecycleTransition') == 'autoscaling:EC2_INSTANCE_TERMINATING': logger.info("ASG Event: Instance Terminating") # Instantiate Custom classes cwe = CloudWatchEvent(logger, customer_uuid[:8]) ssm = SimpleSystemsManager(logger) b_id = cwe.describe_target() # Retrieve unique backup id from cwe target hook_name = event['detail']['LifecycleHookName'] asg_name = event['detail']['AutoScalingGroupName'] instance_id = event['detail']['EC2InstanceId'] document_name = "AWS-RunShellScript" replace_dict.update({'${_s3bucket}': s3_bucket}) replace_dict.update({'${_interval}': interval_tag}) replace_dict.update({'${_ddb_table_name}': ddb_table_name}) replace_dict.update({'${_backup_id}': b_id}) replace_dict.update({'${_autoscaling_grp_name}': asg_name}) replace_dict.update({'${_lifecycle_hookname}': hook_name}) replace_dict.update({'${_folder_label}': folder_label}) replace_dict.update({'${_source_efs}': source_efs_id}) # Send message to SSM ssm.send_command(instance_id, document_name, replace_dict) # Event triggered when lifecycle hook on instance completes elif event.get('detail-type') == 'EC2 Instance Terminate Successful': logger.info("ASG Event: EC2 Instance Terminate Successful") # Instantiate Custom classes cwe = CloudWatchEvent(logger, customer_uuid[:8]) notify = Notify(logger) ddb = DDB(logger, ddb_table_name) b_id = cwe.describe_target() data = ddb.read_item('BackupId', b_id) # Create SNS notification message if data is not None: if data.get('BackupStatus') == 'Incomplete': data.update({'Message': 'The EFS backup was incomplete. Either backup window expired before full backup or fpsync process was not completed.'}) notify.customer(sns_topic_arn, data) elif data.get('BackupStatus') == 'Unsuccessful': data.update({'Message': 'The EFS backup was unsuccessful. ' 'The EC2 instance was unable to find the mount IP OR mount EFS'}) notify.customer(sns_topic_arn, data) elif data.get('BackupStatus') == "fpsync failed": data.update({'Message': 'fpsync process in backup script failed or did not start'}) notify.customer(sns_topic_arn, data) elif data.get('BackupStatus') == "Rsync Delete Incomplete": data.update({'Message': 'rsync --delete process could not complete'}) notify.customer(sns_topic_arn, data) elif data.get('BackupStatus') is None: data.update({'Message': 'The SSM script could not update the DynamoDB table with backup status, ' 'please check the logs in the S3 bucket for the details.'}) data.update({'BackupStatus': 'Unknown'}) notify.customer(sns_topic_arn, data) else: if notify_customer.lower() == 'yes': data.update({'Message': 'The EFS was backed up successfully'}) notify.customer(sns_topic_arn, data) else: notification_message.update({'Message': 'Could not find the backup id: {} in the DDB table'.format(b_id)}) notify.customer(sns_topic_arn, notification_message) # Send anonymous notification if send_data.lower() == 'yes': customer_data = ['SourceEfsId', 'DestinationEfsId', 'BackupPrefix', 'ExpireItem', 'Message'] for key in customer_data: data.pop(key, None) data.update({'Region': region}) notify.metrics(solution_id, customer_uuid, data, metrics_url) # Delete CWE cwe.remove_target() cwe.delete_event() cwe.remove_permission(lambda_function_name) else: # Event to Start Backup if event.get('mode') == 'backup' and event.get('action') == 'start': logger.info("Starting Backup") # Instantiate Custom classes ddb = DDB(logger, ddb_table_name) cw = CloudWatchMetric(logger) efs = EFS(logger) cwe = CloudWatchEvent(logger, customer_uuid[:8]) asg = AutoScaling(logger, backup_asg) # Change the ASG desired capacity asg.update_asg('start_instance') # Creating DDB Item (dict) efs_cw_metrics = cw.efs_cw_metrics(source_efs_id, 'Source') ddb_item.update({'BackupId': backup_id}) ddb_item.update({'BackupWindow': backup_window_period}) ddb_item.update({'IntervalTag': interval_tag}) ddb_item.update({'RetainPeriod': retain_period}) ddb_item.update({'ExpireItem': set_item_time_to_live()}) ddb_item.update({'S3BucketSize': cw.s3_cw_metrics(s3_bucket)}) ddb_item.update({'SourceEfsSize': efs.size(source_efs_id)}) ddb_item.update({'SourceEfsId': source_efs_id}) ddb_item.update({'DestinationEfsId': destination_efs_id}) ddb_item.update({'BackupPrefix': backup_prefix}) ddb_item.update({'DestinationEfsSize': efs.size(destination_efs_id)}) ddb_item.update({'SourcePerformanceMode': efs.performance_mode(source_efs_id)}) ddb_item.update({'InstanceType': instance_type}) ddb_item.update({'DestinationPerformanceMode': destination_efs_mode}) ddb_item.update({'BackupStartTime': (datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%S"))}) item = dict(ddb_item, **efs_cw_metrics) # Merging two dictionaries # Put DDB item ddb.write_item(item) # Create CWE to update desired capacity in ASG event_rule_arn = cwe.create_event(backup_window_period) cwe.add_target(lambda_function_name, terminate_event()) cwe.add_permission(lambda_function_name, event_rule_arn) # Event to Stop Backup elif event.get('mode') == 'backup' and event.get('action') == 'stop' and \ validate_stop_event(event): logger.info("Stopping Backup") # Instantiate Custom classes asg = AutoScaling(logger, backup_asg) # Change the ASG desired capacity asg.update_asg('stop_instance') else: if not validate_stop_event(event): # If stop event triggered lambda during CloudWatch event creation, it should be ignored logger.info('Ignoring STOP backup event occurring within 10 minutes of the START backup event.') else: logger.error('Invalid Event. No action taken.')
def setUp(self): self.notify = Notify(logger)