import datetime import json import os import subprocess import boto3 from app import app from app.alarms import get_proxy_alarm from app.extensions import db from app.models.alarms import Alarm, AlarmState from app.models.mirrors import Proxy from app.terraform.proxy import ProxyAutomation class ProxyCloudfrontAutomation(ProxyAutomation): short_name = "proxy_cloudfront" provider = "cloudfront" template_parameters = [ "aws_access_key", "aws_secret_key" ] template = """ terraform { required_providers { aws = { version = "~> 4.4.0" } } } provider "aws" { access_key = "{{ aws_access_key }}" secret_key = "{{ aws_secret_key }}" region = "us-east-2" } {% for group in groups %} module "label_{{ group.id }}" { source = "cloudposse/label/null" version = "0.25.0" namespace = "{{ global_namespace }}" tenant = "{{ group.group_name }}" label_order = ["namespace", "tenant", "name", "attributes"] } module "log_bucket_{{ group.id }}" { source = "cloudposse/s3-log-storage/aws" version = "0.28.0" context = module.label_{{ group.id }}.context name = "logs" attributes = ["cloudfront"] acl = "log-delivery-write" standard_transition_days = 30 glacier_transition_days = 60 expiration_days = 90 } resource "aws_sns_topic" "alarms_{{ group.id }}" { name = "${module.label_{{ group.id }}.id}-cloudfront-alarms" } {% endfor %} {% for proxy in proxies %} module "cloudfront_{{ proxy.id }}" { source = "sr2c/bc-proxy/aws" version = "0.0.7" origin_domain = "{{ proxy.origin.domain_name }}" logging_bucket = module.log_bucket_{{ proxy.origin.group.id }}.bucket_domain_name sns_topic_arn = aws_sns_topic.alarms_{{ proxy.origin.group.id }}.arn low_bandwidth_alarm = false context = module.label_{{ proxy.origin.group.id }}.context name = "proxy" attributes = ["{{ proxy.origin.domain_name }}"] bypass_token = "{{ bypass_token }}" } {% endfor %} """ def import_cloudfront_values(): terraform = subprocess.run( ['terraform', 'show', '-json'], cwd=os.path.join( app.config['TERRAFORM_DIRECTORY'], "proxy_cloudfront"), stdout=subprocess.PIPE) state = json.loads(terraform.stdout) for mod in state['values']['root_module']['child_modules']: if mod['address'].startswith('module.cloudfront_'): for res in mod['resources']: if res['address'].endswith('aws_cloudfront_distribution.this'): proxy = Proxy.query.filter(Proxy.id == mod['address'][len('module.cloudfront_'):]).first() proxy.url = "https://" + res['values']['domain_name'] proxy.slug = res['values']['id'] proxy.terraform_updated = datetime.datetime.utcnow() db.session.commit() break def import_cloudwatch_alarms(): cloudwatch = boto3.client('cloudwatch', aws_access_key_id=app.config['AWS_ACCESS_KEY'], aws_secret_access_key=app.config['AWS_SECRET_KEY'], region_name='us-east-2') dist_paginator = cloudwatch.get_paginator('describe_alarms') page_iterator = dist_paginator.paginate(AlarmNamePrefix="bandwidth-out-high-") for page in page_iterator: for cw_alarm in page['MetricAlarms']: dist_id = cw_alarm["AlarmName"][len("bandwidth-out-high-"):] proxy = Proxy.query.filter(Proxy.slug == dist_id).first() if proxy is None: print("Skipping unknown proxy " + dist_id) continue alarm = get_proxy_alarm(proxy.id, "bandwidth-out-high") if cw_alarm['StateValue'] == "OK": alarm.update_state(AlarmState.OK, "CloudWatch alarm OK") elif cw_alarm['StateValue'] == "ALARM": alarm.update_state(AlarmState.CRITICAL, "CloudWatch alarm ALARM") else: alarm.update_state(AlarmState.UNKNOWN, f"CloudWatch alarm {cw_alarm['StateValue']}") alarm = Alarm.query.filter( Alarm.alarm_type == "cloudfront-quota" ).first() if alarm is None: alarm = Alarm() alarm.target = "service/cloudfront" alarm.alarm_type = "cloudfront-quota" alarm.state_changed = datetime.datetime.utcnow() db.session.add(alarm) alarm.last_updated = datetime.datetime.utcnow() deployed_count = len(Proxy.query.filter( Proxy.destroyed == None).all()) old_state = alarm.alarm_state if deployed_count > 370: alarm.alarm_state = AlarmState.CRITICAL elif deployed_count > 320: alarm.alarm_state = AlarmState.WARNING else: alarm.alarm_state = AlarmState.OK if alarm.alarm_state != old_state: alarm.state_changed = datetime.datetime.utcnow() db.session.commit() if __name__ == "__main__": with app.app_context(): auto = ProxyCloudfrontAutomation() auto.pre_housekeeping() auto.generate_terraform() auto.terraform_init() auto.terraform_apply(refresh=False) import_cloudfront_values() import_cloudwatch_alarms()