Skip to content

Instantly share code, notes, and snippets.

@AlJohri
Created November 14, 2020 21:30
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AlJohri/fa18bf58b338888934a140c8b6214fdd to your computer and use it in GitHub Desktop.
Save AlJohri/fa18bf58b338888934a140c8b6214fdd to your computer and use it in GitHub Desktop.
# Source: https://stackoverflow.com/questions/50003378/automatically-set-listenerrule-priority-in-cloudformation-template
import random
import uuid
import traceback
import boto3
# Member must have value less than or equal to 50000
ALB_RULE_PRIORITY_RANGE = 1, 50000
def handler(event, context):
physical_resource_id = event.get("PhysicalResourceId", str(uuid.uuid4()))
response_data = {}
listener_arn = event["ResourceProperties"]["ListenerArn"]
if event["RequestType"] == "Create":
elbv2_client = boto3.client("elbv2")
result = elbv2_client.describe_rules(ListenerArn=listener_arn)
in_use = list(
filter(lambda s: s.isdecimal(), [r["Priority"] for r in result["Rules"]])
)
priority = None
while not priority or priority in in_use:
priority = str(random.randint(*ALB_RULE_PRIORITY_RANGE))
response_data = {"Priority": priority}
return {"PhysicalResourceId": physical_resource_id, "Data": response_data}
const loadBalancerName = `${titleCase(stage)}PublicLoadBalancer`
const loadBalancer = elbv2.ApplicationLoadBalancer.fromLookup(
this,
`LoadBalancer`,
{
loadBalancerTags: { Name: loadBalancerName },
}
)
const listener = elbv2.ApplicationListener.fromLookup(this, `Listener`, {
loadBalancerTags: { Name: loadBalancerName },
listenerProtocol: elbv2.ApplicationProtocol.HTTPS,
})
const hostedZone = route53.HostedZone.fromLookup(this, `HostedZone`, {
domainName: "blahblahblah.io",
})
let subdomain = `${client}-snowplow-collector`
if (stage === STAGE.DEVELOPMENT) subdomain = `${stage}-${subdomain}`
const recordName = `${subdomain}.blahblahblah.io`
new route53.ARecord(this, `AliasRecord`, {
zone: hostedZone,
recordName,
target: route53.RecordTarget.fromAlias(
new alias.LoadBalancerTarget(loadBalancer)
),
})
const targetGroup = new elbv2.ApplicationTargetGroup(scope, `TargetGroup`, {
port: 80,
healthCheck: {
port: "traffic-port",
path: "/health",
},
targets: [service],
vpc: vpc,
})
const nextListenerRulePriorityLambda = new CustomResource(
this,
"nextListenerRulePriority",
{
resourceType: "Custom::AllocateAlbRulePriority",
serviceToken: Fn.importValue("AllocateAlbRulePriority-serviceToken"),
properties: {
ListenerArn: listener.listenerArn,
},
}
)
const nextListenerRulePriority = nextListenerRulePriorityLambda.getAttString(
"Priority"
)
const listenerRule = new elbv2.ApplicationListenerRule(
this,
"ListenerRule",
{
action: elbv2.ListenerAction.forward([targetGroup]),
conditions: [elbv2.ListenerCondition.hostHeaders([recordName])],
listener,
priority: 9999,
}
)
// Source: https://github.com/aws/aws-cdk/issues/9296#issuecomment-723294027
const albRuleEscapeHatch = listenerRule.node
.defaultChild as elbv2.CfnListenerRule
albRuleEscapeHatch.priority = Token.asNumber(nextListenerRulePriority)
}
import * as cdk from "@aws-cdk/core"
import * as logs from "@aws-cdk/aws-logs"
import * as path from "path"
import * as iam from "@aws-cdk/aws-iam"
import * as lambda from "@aws-cdk/aws-lambda"
import * as cr from "@aws-cdk/custom-resources"
import { CfnOutput } from "@aws-cdk/core"
/**
* Central lambdas used throughout the team.
*/
export default function createLambdas(scope: cdk.Stack) {
const fn = new lambda.Function(scope, "AllocateAlbRulePriority", {
runtime: lambda.Runtime.PYTHON_3_6,
handler: "allocate_alb_rule_priority.handler",
timeout: cdk.Duration.seconds(30),
code: lambda.Code.fromAsset(
path.join(__dirname, "..", "..", "lambdas", "allocate-alb-rule-priority")
),
initialPolicy: [
new iam.PolicyStatement({
sid: "DescribeRulesPolicy",
actions: ["elasticloadbalancing:DescribeRules"],
resources: ["*"],
}),
],
})
const provider = new cr.Provider(scope, "AllocateAlbRulePriorityProvider", {
onEventHandler: fn,
logRetention: logs.RetentionDays.ONE_DAY,
})
new cdk.CfnOutput(scope, "AllocateAlbRulePriorityServiceToken", {
value: provider.serviceToken,
exportName: "AllocateAlbRulePriority-serviceToken",
})
}
@kirankharel
Copy link

Could you please share some instructions on how exactly to use this code ? Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment