3. Update Lambda Function

In this step, we will update the Lambda function with necessary code that executes the cross region failover. The Anomaly detection model is expected to trigger the CloudWatch Alarm. Once the alarm threshold is breached, the SNS topic associated with the alarm will trigger the subscribed Lambda function to execute failover to Ohio Region. Let’s begin!

  1. Select the Services dropdown at the very top of the AWS management console and type Lambda. Select Lambda from the filtered results to navigate to the Lambda service console
  2. Select the function with name similar to the pattern -CrossRegionFailoverLambda-
  3. Scroll down to the Function code section, and replace existing code under index.py with the following:

    import boto3
    import os
    import re
    
    def _get_client(service, region):
        return boto3.client(service, region_name=region)
    
    def _get_failover_region_nlb(region):
        try:
            client = _get_client('elbv2', region)
            response = client.describe_load_balancers()
            dns_name = response['LoadBalancers'][0]['DNSName']
            hosted_zone =  response['LoadBalancers'][0]['CanonicalHostedZoneId']
            return dns_name, hosted_zone
        except Exception:
            raise RuntimeError("Could not retrieve network load balancer information in failover region {}".format(region))
    
    def _get_hosted_zone_id_by_name(hostedzone, client):
        zones = client.list_hosted_zones_by_name(DNSName=hostedzone)
        if 'HostedZones' not in zones:
            raise RuntimeError("No hosted zones were returned for lookup")
    
        matched_zones = [zone for zone in zones['HostedZones'] if re.match('^{}\\.?$'.format(hostedzone), zone['Name'])]
        if len(matched_zones) != 1:
            raise RuntimeError("Could not find a matching hosted zone. Matching zones: {}".format(zones))
        return client.get_hosted_zone(Id=matched_zones[0]['Id'])['HostedZone']['Id']
    
    
    def _apply_changes(hosted_zone_name, remote_region, record):
        client = _get_client('route53', remote_region)
        hosted_zone_id = _get_hosted_zone_id_by_name(hosted_zone_name, client)
        remote_record, remote_zone = _get_failover_region_nlb(remote_region)
        alias_fqdn = '.'.join([record, hosted_zone_name])
    
        response = client.change_resource_record_sets(
            HostedZoneId=hosted_zone_id,
            ChangeBatch={
                'Changes': [
                    {
                        "Action": "UPSERT",
                        "ResourceRecordSet": {
                            "Name": alias_fqdn,
                            "Type": "A",
                            "AliasTarget": {
                                "HostedZoneId": remote_zone,
                                "DNSName": remote_record,
                                "EvaluateTargetHealth": False
                            }
                        }
                    }
                ]
            })
        return response
    
    
    def handler(event,context):
        hosted_zone = os.environ.get('HOSTED_ZONE_NAME', 'unicornsaregreat.com.')
        remote_region = os.environ.get('FAILOVER_REGION', 'us-east-2')
        record = os.environ.get('MANAGED_RECORD', 'api')
        _apply_changes(hosted_zone, remote_region, record)

  4. Select Save