hubot-aws-cfpb
Version:
CFPB-specific Hubot aws commands. Forked from the excellent https://github.com/yoheimuta/hubot-aws/ and heavily modified for our particular usage needs
129 lines (112 loc) • 4.07 kB
text/coffeescript
# Description:
# Commands for reserving ec2 instances and listing existing reservations
#
# Commands:
# hubot ec2 reserve <instance-id-nickname> <branch-name> <reservation comment> - Reserve an instance
# hubot ec2 unreserve <instance-id-nickname> - Unreserve an instance
# hubot ec2 reserve-ls - Displays a list of currently reserved instances
#
_ = require 'underscore'
cson = require 'cson'
ec2 = require('../../ec2.coffee')
moment = require 'moment'
tags = require './tags'
mdTable = require('markdown-table')
RESERVE_TAGS = {
user: 'ReservationUser',
time: 'ReservationTime',
branch: 'ReservationBranch',
description: 'ReservationDescription',
}
RESERVE_CONFIG_ENV_VAR = "HUBOT_AWS_RESERVE_CONFIG"
try
INSTANCE_ID_MAP = cson.parseCSONFile process.env[RESERVE_CONFIG_ENV_VAR]
catch e
# TODO switch to `robot.logger()` here _without_ constantly reparsing config file
if e.name == "TypeError"
console.log "#{RESERVE_CONFIG_ENV_VAR} is not defined"
else
console.log "#{RESERVE_CONFIG_ENV_VAR} could not be loaded " +
"(#{process.env.HUBOT_AWS_RESERVE_CONFIG})"
INSTANCE_ID_MAP = {}
getReservationTags = (msg) ->
args = if msg.match[1] then msg.match[1].trim().split(/\s+/).slice(1) else []
if args.length < 2
[]
else
[
{Key: RESERVE_TAGS.user, Value: msg.message.user.name},
{Key: RESERVE_TAGS.time, Value: Date.now().toString()},
{Key: RESERVE_TAGS.branch, Value: args[0]},
{Key: RESERVE_TAGS.description, Value: args.slice(1).join(" ")},
]
formatReservationsList = (instances) ->
if not instances.length
return '[None]'
getTag = (_tags, tag) -> _.first(t.Value for t in _tags when t.Key is tag) || ''
instanceMap = _.invert(INSTANCE_ID_MAP)
rows = (
{
id: instanceMap[i.InstanceId] || "UNKNOWN",
resUser: getTag(i.Tags, RESERVE_TAGS.user),
resTime: getTag(i.Tags, RESERVE_TAGS.time),
resBranch: getTag(i.Tags, RESERVE_TAGS.branch),
resDescrip: getTag(i.Tags, RESERVE_TAGS.description),
state: i.State.Name,
} for i in instances
).sort (a, b) -> a.id > b.id
timeFmt = "MMM Do YYYY, h:mm a"
tableHead = [
'instance', 'user', 'reserved time', 'branch', 'comment', 'status'
]
tableRows = (
[
r.id,
r.resUser,
moment(parseInt(r.resTime)).format(timeFmt),
r.resBranch,
r.resDescrip,
r.state,
] for r in rows
)
tableRows.unshift tableHead
mdTable tableRows, {align: 'l'}
module.exports = (robot) ->
robot.respond /ec2 reserve (.*)$/i, (msg) ->
instance = msg.match[1].trim().split(/\s+/)[0]
if !INSTANCE_ID_MAP[instance]
validInstanceIDs = Object.keys(INSTANCE_ID_MAP).join(", ")
return msg.send "Unknown instance nickname. Choose from: #{validInstanceIDs}"
reservationTags = getReservationTags(msg)
if !reservationTags.length
msg.send "Cannot reserve: please provide a branch and a comment"
else
tags.addReservation(msg, INSTANCE_ID_MAP[instance], reservationTags)
msg.send "Reservation added to #{instance}."
robot.respond /ec2 unreserve (.*)$/i, (msg) ->
instance = msg.match[1].trim().split(/\s+/)[0]
if !INSTANCE_ID_MAP[instance]
return msg.send "Unknown instance: #{instance}"
reservationTags = [
{Key: RESERVE_TAGS.user, Value: "--"},
{Key: RESERVE_TAGS.time, Value: Date.now().toString()},
{Key: RESERVE_TAGS.branch, Value: "--"},
{Key: RESERVE_TAGS.description, Value: "--"},
]
tags.addReservation(msg, INSTANCE_ID_MAP[instance], reservationTags)
msg.send "Unreserved instance: #{instance}."
robot.respond /ec2 reserve-ls$/i, (msg) ->
params = {
Filters: [
{
Name: 'tag-key',
Values: [RESERVE_TAGS.user]
}
]
}
ec2.describeInstances params, (err, res) ->
if err
msg.send "DescribeInstancesError: #{err}"
else
instances = _.flatten(i for i in (r.Instances for r in res.Reservations))
msg.send(formatReservationsList(instances))