Skip to content

Instantly share code, notes, and snippets.

@dennisroche
Last active February 12, 2021 01:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dennisroche/287915ca6a0874157d71b0903ec3999b to your computer and use it in GitHub Desktop.
Save dennisroche/287915ca6a0874157d71b0903ec3999b to your computer and use it in GitHub Desktop.
CloudFormation custom resource to create HTTP2 Target Group
'''
Uses crhelper https://github.com/aws-cloudformation/custom-resource-helper
Requires
- 'elasticloadbalancing:*'
- 'ec2:DescribeInternetGateways'
- 'ec2:DescribeVpcs'
'''
from crhelper import CfnResource
import logging
import boto3
import uuid
from time import sleep
logger = logging.getLogger(__name__)
helper = CfnResource(json_logging=True, log_level='DEBUG',
boto_level='CRITICAL')
try:
elb = boto3.client('elbv2')
except Exception as e:
helper.init_failure(e)
def without_service_token(event):
'''Remove ServiceToken from the CloudFormation `event` to so it can be splatted into boto3'''
return {k: event[k] for k in event if k not in {"ServiceToken"}}
def convertToInt(key, dict):
if key in dict:
dict[key] = int(dict[key])
def generateName(prefix):
return '{}-{}'.format(prefix[0:19], uuid.uuid4().hex.upper()[0:12])
@helper.create
@helper.update
def create(event, context):
if (event['RequestType'] == 'Update'):
try:
logger.info('Replacing target group {}'.format(
event['PhysicalResourceId']))
elb.delete_target_group(TargetGroupArn=event['PhysicalResourceId'])
except Exception as e:
logging.critical(e, exc_info=True)
pass
request = without_service_token(event['ResourceProperties'])
targetGroupRequest = without_service_token(event['ResourceProperties'])
del targetGroupRequest['TargetGroupAttributes']
# fix request payload
# boto3 expects int but cfn request has converted to str
convertToInt('HealthCheckIntervalSeconds', targetGroupRequest)
convertToInt('HealthCheckTimeoutSeconds', targetGroupRequest)
convertToInt('Port', targetGroupRequest)
# max 32 characters
targetGroupRequest['Name'] = generateName(targetGroupRequest['Name'])
# default to HTTP2, so that it can be overridden to gRPC
if 'ProtocolVersion' not in targetGroupRequest:
targetGroupRequest['ProtocolVersion'] = 'HTTP2'
logger.info('Creating target group')
logger.info(targetGroupRequest)
targetGroupResponse = elb.create_target_group(**targetGroupRequest)
logger.info(targetGroupResponse)
arn = targetGroupResponse['TargetGroups'][0]['TargetGroupArn']
attributesRequest = {
'TargetGroupArn': arn,
'Attributes': request['TargetGroupAttributes']
}
logger.info('Setting target group attributes')
logger.info(attributesRequest)
attributesResponse = elb.modify_target_group_attributes(
**attributesRequest)
logger.info(attributesResponse)
return targetGroupResponse['TargetGroups'][0]['TargetGroupArn']
@helper.delete
def delete(event, context):
try:
logger.info('Delete target group {}'.format(
event['PhysicalResourceId']))
elb.delete_target_group(TargetGroupArn=event['PhysicalResourceId'])
except Exception as e:
logging.critical(e, exc_info=True)
pass
return
def handler(event, context):
helper(event, context)
AWSTemplateFormatVersion: 2010-09-09
Description: 'ECS Fargate deployment and dependant resources'
Parameters:
Name:
Description: Name
Type: String
VpcId:
Description: VPC Id
Type: AWS::EC2::VPC::Id
ServicePort:
Type: String
Description: The port of the ECS Service
Resources:
Http2LoadBalancerTargetGroup:
Type: Custom::Http2TargetGroup
Properties:
ServiceToken: !Sub arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:cfn-http2-target-group
Name: !Sub ${Name}-tg
VpcId: !Ref VpcId
Protocol: HTTP
Port: !Ref ServicePort
TargetType: ip
TargetGroupAttributes:
- Key: deregistration_delay.timeout_seconds
Value: '5'
- Key: stickiness.enabled
Value: 'true'
- Key: stickiness.type
Value: lb_cookie
- Key: stickiness.lb_cookie.duration_seconds
Value: '86400' #1 day
HealthCheckIntervalSeconds: 300
HealthCheckTimeoutSeconds: 30
HealthCheckPath: !Sub /health
HealthCheckProtocol: HTTP
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment