Created
March 26, 2019 20:08
-
-
Save homeyjd/7d228c86ef3ddaf7c4585a516dc44252 to your computer and use it in GitHub Desktop.
lifecycle-poller Lambda with less characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
let AWS = require('aws-sdk') | |
let ecs = new AWS.ECS() | |
let sqs = new AWS.SQS() | |
let asg = new AWS.AutoScaling() | |
let cluster = process.env.CLUSTER | |
let QueueUrl = process.env.QUEUE_URL | |
let drainingTimeout = process.env.DRAINING_TIMEOUT | |
async function getContainerInstanceArn(id) { | |
let o = { cluster, filter: `ec2InstanceId == '${id}'` } | |
console.log("getContainerInstanceArn(", o, ")") | |
return (await ecs.listContainerInstances(o).promise()).containerInstanceArns[0] | |
} | |
async function countTasks(containerInstance) { | |
let o = { cluster, containerInstance } | |
console.log("countTasks(", o, ")") | |
return (await ecs.listTasks(o).promise()).taskArns.length | |
} | |
function drainInstance(arn) { | |
let o = { cluster, containerInstances: [arn], status: 'DRAINING' } | |
console.log("drainInstance(", o, ")") | |
return ecs.updateContainerInstancesState(o).promise() | |
} | |
function wait(r) { | |
r = { | |
Service: 'DrainInstance', | |
Event: 'custom:DRAIN_WAIT', | |
ContainerInstanceArn: r.ContainerInstanceArn, | |
AutoScalingGroupName: r.AutoScalingGroupName, | |
LifecycleHookName: r.LifecycleHookName, | |
LifecycleActionToken: r.LifecycleActionToken, | |
TerminateTime: r.TerminateTime, | |
} | |
console.log("wait(", r, ")") | |
return sqs.sendMessage({ | |
QueueUrl, | |
DelaySeconds: 60, | |
MessageBody: JSON.stringify(r) | |
}).promise() | |
} | |
function deleteMessage(ReceiptHandle) { | |
let req = { QueueUrl, ReceiptHandle } | |
console.log("deleteMessage(", req, ")") | |
return sqs.deleteMessage(req).promise() | |
} | |
function terminateInstance(r) { | |
r = { | |
AutoScalingGroupName: r.AutoScalingGroupName, | |
LifecycleHookName: r.LifecycleHookName, | |
LifecycleActionToken: r.LifecycleActionToken, | |
LifecycleActionResult: 'CONTINUE' | |
} | |
console.log("terminateInstance(", r, ")") | |
return asg.completeLifecycleAction(r).promise() | |
} | |
function heartbeat(r) { | |
r = { | |
AutoScalingGroupName: r.AutoScalingGroupName, | |
LifecycleHookName: r.LifecycleHookName, | |
LifecycleActionToken: r.LifecycleActionToken, | |
} | |
console.log("heartbeat(", r, ")") | |
return asg.recordLifecycleActionHeartbeat(r).promise() | |
} | |
exports.handler = async event => { | |
console.log(`Invoke: ${JSON.stringify(event)}`) | |
let rec = event.Records[0]; | |
let body = JSON.parse(rec.body)// batch size is 1 | |
if (body.Service === 'AWS Auto Scaling') { | |
if (body.Event === 'autoscaling:TEST_NOTIFICATION') { | |
console.log('Ignoring autoscaling:TEST_NOTIFICATION') | |
} else if (body.LifecycleTransition === 'autoscaling:EC2_INSTANCE_TERMINATING') { | |
body.ContainerInstanceArn = await getContainerInstanceArn(body.EC2InstanceId) | |
body.TerminateTime = body.Time | |
await Promise.all([drainInstance(body.ContainerInstanceArn), wait(body)]) | |
} | |
} else if (body.Service === 'DrainInstance' && body.Event === 'custom:DRAIN_WAIT') { | |
if (0 === await countTasks(body.ContainerInstanceArn)) { | |
await terminateInstance(body) | |
} else { | |
let actionDuration = Math.abs(new Date(body.TerminateTime).getTime() - new Date().getTime()) / 1000 | |
if (actionDuration < drainingTimeout) { | |
await Promise.all([heartbeat(body), wait(body)]) | |
} else { | |
console.log('Timeout for instance termination reached.') | |
await terminateInstance(body) | |
} | |
} | |
} else { | |
console.log('Ignoring invalid event ...') | |
} | |
await deleteMessage(rec.receiptHandle) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment