import boto3
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.pagesizes import letter
from reportlab.lib.colors import red, green
from datetime import timedelta
def seconds_to_time(seconds):
return str(timedelta(seconds=seconds))
# Get list of regions
ec2 = boto3.client('ec2')
regions = [region['RegionName'] for region in ec2.describe_regions()['Regions']]
doc = SimpleDocTemplate("resilience-report.pdf", pagesize=letter)
flowables = []
style = getSampleStyleSheet()["BodyText"]
header_style = ParagraphStyle('header',
parent=style,
fontSize=14,
spaceAfter=12)
# Loop over each region
for region in regions:
try:
arh = boto3.client('resiliencehub', region_name=region)
apps = arh.list_apps()
except:
continue
# Get list of apps in a region
app_arns = [app['appArn'] for app in apps['appSummaries']]
while 'NextToken' in apps:
apps = arh.list_apps(NextToken = apps['NextToken'])
for app in apps['appSummaries']:
app_arns.append(app['appArn'])
# Loop over list of apps to retrieve details
for app_arn in app_arns:
app_details = arh.describe_app(appArn=app_arn)['app']
app_name = app_details['name']
app_arn = app_details['appArn']
app_compliance = app_details['complianceStatus']
app_res_score = app_details['resiliencyScore']
app_tier = 'unknown'
# Check if a resiliency policy is associated with the application
if 'policyArn' in app_details:
policy_details = arh.describe_resiliency_policy(policyArn=app_details['policyArn'])
app_tier = policy_details['policy']['tier']
flowables.append(Paragraph(f"Application: {app_name}", header_style))
flowables.append(Spacer(1, 12))
flowables.append(Paragraph(f"ARN: {app_arn}", style))
flowables.append(Paragraph(f"Compliance Status: {app_compliance}", style))
flowables.append(Paragraph(f"Resiliency Score: {app_res_score}", style))
flowables.append(Paragraph(f"Application Tier: {app_tier}", style))
flowables.append(Spacer(1, 12))
if app_compliance != 'NotAssessed':
assessment_arns = []
assessment_summaries = arh.list_app_assessments(appArn=app_arn)['assessmentSummaries']
for assessment in assessment_summaries:
assessment_arns.append(assessment['assessmentArn'])
while 'NextToken' in assessment_summaries:
assessment_summaries = arh.list_app_assessments(appArn=app_arn, NextToken = assessment_summaries['NextToken'])['assessmentSummaries']
for assessment in assessment_summaries:
assessment_arns.append(assessment['assessmentArn'])
assessment_details_list = [arh.describe_app_assessment(assessmentArn=arn)['assessment'] for arn in assessment_arns]
# Get the latest assessment
latest_assessment = max(assessment_details_list, key=lambda x: x['endTime'])
# Filter successful assessments
successful_assessments = [a for a in assessment_details_list if a['assessmentStatus'] == 'Success']
# Get the latest successful assessment
if successful_assessments:
latest_assessment = max(successful_assessments, key=lambda x: x['endTime'])
assessment_name = latest_assessment['assessmentName']
assessment_arn = latest_assessment['assessmentArn']
assessment_compliance_status = latest_assessment['complianceStatus']
end_time = latest_assessment['endTime']
flowables.append(Paragraph(f"Latest Assessment Name: {assessment_name}", style))
flowables.append(Paragraph(f"Assessment Compliance Status: {assessment_compliance_status}", style))
flowables.append(Paragraph(f"End Time: {end_time}", style))
flowables.append(Spacer(1, 12))
component_compliances = []
response = arh.list_app_component_compliances(assessmentArn=assessment_arn)
component_compliances.extend(response['componentCompliances'])
while 'NextToken' in response:
response = arh.list_app_component_compliances(assessmentArn=assessment_arn, NextToken=response['NextToken'])
component_compliances.extend(response['componentCompliances'])
for dtype in ['AZ', 'Region', 'Hardware', 'Software']:
if dtype in latest_assessment['compliance']:
current_rto = latest_assessment['compliance'][dtype]['currentRtoInSecs']
target_rto = latest_assessment['policy']['policy'][dtype]['rtoInSecs']
current_rpo = latest_assessment['compliance'][dtype]['currentRpoInSecs']
target_rpo = latest_assessment['policy']['policy'][dtype]['rpoInSecs']
rto_color = green if latest_assessment['compliance'][dtype]['currentRtoInSecs'] <= latest_assessment['policy']['policy'][dtype]['rtoInSecs'] else red
rpo_color = green if latest_assessment['compliance'][dtype]['currentRpoInSecs'] <= latest_assessment['policy']['policy'][dtype]['rpoInSecs'] else red
flowables.append(Paragraph(f"{dtype} Disruption Type:", style))
flowables.append(Paragraph(f" Current RTO: {seconds_to_time(current_rto)} Target RTO: {seconds_to_time(target_rto)}", style))
flowables.append(Paragraph(f" Current RPO: {seconds_to_time(current_rpo)} Target RPO: {seconds_to_time(target_rpo)}", style))
flowables.append(Spacer(1, 12))
for component_compliance in component_compliances:
app_component_name = component_compliance['appComponentName']
component_compliance_status = component_compliance['status']
component_current_rto = component_compliance['compliance'][dtype]['currentRtoInSecs']
component_current_rpo = component_compliance['compliance'][dtype]['currentRpoInSecs']
component_rto_description = component_compliance['compliance'][dtype]['rtoDescription']
component_rpo_description = component_compliance['compliance'][dtype]['rpoDescription']
# Check if component compliance matches the current RTO and RPO
if (component_current_rto == current_rto):
flowables.append(Paragraph(f"RTO Description: {component_rto_description} ({app_component_name})", style))
if (component_current_rpo == current_rpo):
flowables.append(Paragraph(f"RPO Description: {component_rpo_description} ({app_component_name})", style))
flowables.append(Spacer(1, 12))
doc.build(flowables)