経緯
- OpsWorks(Chef)の実行時間は長い
- 完了はできるだけ早く知りたい
- 誰かが操作したら教えて欲しい
- つまり、操作の通知の機能が欲しい
OpsWorksには通知の機能がない
インスタンス間のオーケストレーション的な通知はあるんですが、SNSでイベント通知的な機能がない。
作ってみた
各操作の情報は OpsWorks:DescribeDeployments
で取れる。 Deploymentsと書いてるけどCommandsも取れるので、これを監視して新しいのが来たら通知する感じ。
依存ライブラリ
- aws-sdk (2.1.42)
- cron (1.0.9)
※()内は実際に使用しているバージョンでそれでしか動かないわけではないです
必要なIAM権限
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"opsworks:Describe*"
],
"Resource": [
"*"
]
}
]
}
Hubot Script
stack_id
やchannel
、cron周期やメッセージ内容は適宜変更してください。
IAM Roleが付与されたEC2で動く前提なので、そうではない場合はcredentialの指定が必要です。
あと、 :opsworks:
はカスタム絵文字なのでSlack標準では無いです。
opswork-deployment-notify.coffee
# Description
# OpsWorks deployment notify
#
# Configuration:
# None
#
# Commands:
# None
#
# Author:
# Masashi Terui
cron = require('cron').CronJob
AWS = require('aws-sdk');
opsworks = new AWS.OpsWorks({region: 'us-east-1'});
channel = '#your-channel'
module.exports = (robot) ->
new cron '*/10 * * * * *', () =>
before = Math.floor(new Date().getTime() / 1000) - 10
opsworks.describeStacks {}, (err, stacks) ->
if err
console.log(err, err.stack)
else
for stack in stacks.Stacks
opsworks.describeDeployments {StackId: stack.StackId}, (err, deploys) ->
if err
console.log(err, err.stack)
else
for deploy in deploys.Deployments
created_at = Math.floor(new Date(deploy.CreatedAt).getTime() / 1000)
if deploy.CompletedAt == ""
completed_at = 0
else
completed_at = Math.floor(new Date(deploy.CompletedAt).getTime() / 1000)
if before <= created_at
data = deploy
opsworks.describeInstances {InstanceIds: data.InstanceIds}, (err, instances) ->
if err
console.log(err, err.stack)
else
ins_list = []
for instance in instances.Instances
ins_list.push "- #{instance.Hostname} (#{instance.PrivateIp})"
msg = "
:opsworks: 開始しました \n
```\n
ID: #{data.DeploymentId} \n
Command: #{data.Command.Name} \n
Comment: #{data.Comment} \n
[Instances] \n#{ins_list.join('\n')} \n
```\n
"
robot.send {room: channel}, msg
if before <= completed_at
data = deploy
opsworks.describeInstances {InstanceIds: data.InstanceIds}, (err, instances) ->
if err
console.log(err, err.stack)
else
ins_list = []
for instance in instances.Instances
ins_list.push "- #{instance.Hostname} (#{instance.PrivateIp})"
emoji = ':ok:'
emoji = ':ng:' if deploy.Status == "failed"
msg = "
:opsworks: 終了しました #{emoji} \n
```\n
ID: #{data.DeploymentId} \n
Status : #{data.Status} \n
Command: #{data.Command.Name} \n
Comment: #{data.Comment} \n
[Instances] \n#{ins_list.join('\n')} \n
```\n
"
robot.send {room: channel}, msg
, null, true, "Asia/Tokyo"
ソース汚くてごめんなさい。。。
でも、これで快適なOpsWorks生活に一歩近づきました。