【cloudpack 大阪 BLOG】MSPのシステム化について Google Apps ScriptからPagerDutyに通知する
現在cloudpackではPagerDutyを試験的に導入していってます。
PagerDutyとは何ぞや?と言う方への説明や導入方法を記載すべきところですが
それはおいおいしていくとして(置いといてよいのかw)、
今回は「Google Apps ScriptからPagerDutyに通知する」を試します。
※ほとんど備忘録です
まずは通知先のPD側の設定を行います。下記画面で設定します。
そして設定した画面のService API Keyの情報をメモします。
でGASのプログラミング部分は下記になります
function sendToPagerDuty(service_key) {
var url = "https://events.pagerduty.com/generic/2010-04-15/create_event.json";
var data = {
"service_key": service_key,
"event_type": "trigger",
"description": "FAILURE for production/HTTP on machine srv01.acme.com",
"client": "Sample Monitoring Service",
"client_url": "https://monitoring.service.com",
"details": {
"ping time": "1500ms",
"load avg": 0.75
},
"contexts":[
{
"type": "link",
"href": "http://acme.pagerduty.com",
"text": "View the incident on PagerDuty"
},{
"type": "image",
"src": "https://chart.googleapis.com/chart?chs=600x400&chd=t:6,2,9,5,2,5,7,4,8,2,1&cht=lc&chds=a&chxt=y&chm=D,0033FF,0,0,5,1"
}
]
};
var payload = JSON.stringify(data);
var headers = {"Accept":"application/json",
"Content-Type":"application/json",
"Authorization":"Basic _authcode_"
};
var options = { "method" : "POST",
"contentType" : "application/json",
"headers" : headers,
"payload" : payload
};
try {
var response = UrlFetchApp.fetch(url, options);
var json = JSON.parse(response.getContentText());
Logger.log("status:" + json.status + " message:" + json.message + " incident_key:" + json.incident_key);
} catch(e){
var error = e;
Logger.log("message:" + error.message + "fileName:" + error.fileName + "\nlineNumber:" + error.lineNumber + "\nstack:" + error.stack);
}
}
※サンプルコードをそのままGASに移植していますので内容が気になる方は
を参考にしてください。
上記を実行すると
のような画面がPDの画面にインシデントとして表示されます。
Google Apps Scriptから”インシデントとしての”の登録はまず無いとは思いますが
PDのインシデント管理機能とエスカレーション機能を使って
作業をその日の当番の方に明示的に通知とかも出来るので、
計画作業(Googleカレンダーに登録されている作業)や日次・週次的な作業の通知&
状態管理なんかに使いたいと思っています(今までHubotに任せていた状態管理部分をPDへ)。
基本的な使い方ではなく、いきなり応用編になってしまいましたが、PagerDutyは
スケジュール作成の部分に癖?(シンプルすぎるので一手間必要でここをどう対応したかはまた今度)もありますが、試す分には非常に簡単ですので試してみてください。
【cloudpack 大阪 BLOG】MSPのシステム化について GMailとGoogle スプレッドシートとslack連携
本来なら
「MSPのシステム化について Hubotでの状態管理(mysql)とGoogleカレンダーとslack連携 その2」
なのですが、自身のHubot熱が急速に冷めて行っている&JAWS-UG大阪で廣山さんが
発表した資料
の中に記載されているPagerDutyの導入を比企のほうで進める事になり、
Hubot&MYSQLで対応している部分をPagerDutyに置き換えよう熱が高まったので
その2は延期?させて貰います汗。
※HubotのNode.jsのコールバック地獄がMSPしながらだと
※どうしても手軽に実現できない事情もあります(単純に開発だけしてたら良い時期は
※今考えたら楽でしたねw)
今回はGMailとGoogle スプレッドシートとslack連携について
お題は
①Backlogの担当者が未設定のものをslackに通知する
②監視サーバーからのアラートメールに状況(Google スプレッドシートに記載しているものをマッチング)を送付してslackに通知する
です。
まず①ですが、処理する方法は
Gmailにアクセスする(1/7):初心者のためのGoogle Apps Scriptプログラミング入門
を見て頂ければ処理の仕方はわかるので、上記を参照して頂ければと思いますが
引っかかった部分としてgmailのAPIを個別にCALLにしてしまうと、
メールが少ない場合は問題ないのですが、②も含め、cloudpackはメールの量が多いので
GASの処理可能時間を簡単に消費して24時間経たないと処理が再実行されない状況になります。
var thds = GmailApp.search('検索条件');
var thd = thds[n];
var msgs = thd.getMessages();
var msg = msgs[m];
var from = msg.getFrom();
var to = msg.getTo();
var date = msg.getDate();
var subject = msg.getSubject();
var body = msg.getBody();
などは処理上仕方ないのですが
msg.markRead();
GmailApp.moveMessageToTrash(msg);
などメールの個別のAPIをコールせずに
GmailApp.markThreadsRead(thds);
GmailApp.moveThreadsToTrash(thds);
などのスレッドに対するAPIで処理をまとめて行うようなAPIをコールして処理を行わないと処理が回らなくなりました。
また、処理の実行間隔のタイミングはGASは1分・5分・10分・15分しか設定できないので、
var d1 = new Date();
if((d1.getMinutes()%2) != 0) return;
関数の先頭で、上記コードで2分間隔ぐらいで実施するように修正しました。
※地味だけど本当に処理時間に気をつけないといけないので汗
またこれも処理時間ネタですが②に関してもGoogle スプレッドシートを
スプレッドシート利用の基本(1/5):初心者のためのGoogle Apps Scriptプログラミング入門
のサンプルで実装するととりあえず動くものは簡単に出来るのですが、
これもGoogle スプレッドシートの処理APIを毎回コールすると、処理の量が多いと
すぐにあふれてしまうので、
var data = getMainSheet().getRange(取得開始業,取得開始列,取得終了行,取得終了列).getValues();
でスプレッドシートの値を範囲指定で取得し
data[取得行][取得列]
な配列でアクセスして処理時間を短くする必要があります。
※処理時間は関数単位ではなく、アカウント全体での時間になるので自分が作った関数だけちょっと重いけどまあいいやなんて
※感じでその場限りで対応すると後でトラブった時に詰んでしまいますので処理時間は必ずスクリプトのメニューの表示→実行トランスクリプトの
※処理時間を見ながら計算してください。
そしてslackへの投稿部分ですが
でslack側で出力先のチャンネル名を設定し、登録後のURLをメモしておき
UrlFetchApp.fetchを使って下記コードでslackへ送信します。
function sendToSlack(channel,body) {
var r;
try {
var url = "メモしたslackのURL";
var data = {"channel": channel, "username": "bot名称", "text": body, "icon_emoji": ":smiling_imp:"};
var payload = JSON.stringify(data);
var headers = {"Accept":"application/json",
"Content-Type":"application/json",
"Authorization":"Basic _authcode_"
};
var options = { "method" : "POST",
"contentType" : "application/json",
"headers" : headers,
"payload" : payload
};
var response = UrlFetchApp.fetch(url, options);
} catch(e){
var error = e;
Logger.log("message:" + error.message + "\nfileName:" + error.fileName + "\nlineNumber:" + error.lineNumber + "\nstack:" + error.stack);
r = null
return false;
}
return true;
}
なお現在ですが
Hubotによる自動化の推進は止めて、PagerDutyの運用を24365の
MSP業務に合わせる為に導入設計・導入を対応していますが、
PagerDutyの導入が一段落したらPagerDutyをベースに既存機能の置き換えや
PagerDutyによるMSP業務の見える化を実施する予定です。
うまく今あるサービスを活用し、足りない部分を実装して運用の負荷を減らして
いきたいと思います。
PagerDutyの解説(運用方法)もニーズがあれば投稿します
運用縛りのテーマ「オペレーションじょうず」を開催しました
5月23日(土)ですが、テーマを運用縛りにした「オペレーションじょうず」を主催しました。
毎回開催のテーマに関してはあまり悩まない(だいたいニーズがあるものは読める)
のですが、今回はちょっとどうなるのかと自問自答しながらの運営でした。
ただ、自分が去年の4月にcloupackに入り、6月から構築/運用で24/365のチームに
配属されてから運用に入った時にイメージと現実が隔離している事に愕然として
DevOpsだよね〜なんて軽口叩いていた開発から運用への自分の勘違いをテーマに
TOPバッターはもちろん波田野さん。
資料には記載できてない話があるのですが、そこがオペレーションじょうずの
裏テーマだったんですが自重らしくUP資料からは割愛されていますw
こういうケースもあるので、是非皆様現地にお越し下さいw
「東急ハンズの運用削減事例と方針」をハンズラボ株式会社の田部井さん
「CG映像制作におけるAWSの活用(スポットインスタンスによるCGレンダリング)」
を株式会社石田大成社の戸崎さん。
創業の100年の老舗がAWSでレンダリングでさらにスポットインスタンス。
資料の公開が待たれますが、サミットでもお話するようで、資料はそれ以降ですね
吉田姓の為に登壇するcloudpack吉田ヒロカズさんw
サーバーワークスの柳瀬さんは「AWSのAPIを使うときに気をつけていること」
JAWSUG大阪の森さんの登壇後に波田野さんが森さんの内容についてトークする瞬間。
とりはNRIネットコム株式会社の佐藤さん。
でも記載されているので、資料とまとめを見て頂ければと思います。
【cloudpack 大阪 BLOG】MSPのシステム化について Hubotでの状態管理(mysql)とGoogleカレンダーとslack連携 その1
一年間寝かし(放置してしまった汗)ておいた
をようやく実施できるようになりました汗。
クラウドユーザーグループ7つ+αによる合同勉強会。
去年の2月のXEggはJAWS-UGとJAZUGのみで、他のコミュニティの方にも
ご協力いただきましたが、今回はクラウドユーザーグループメインでの実施が
可能になりました。
1年でたくさんのクラウドユーザーグループが産まれたのはうれしいですね。
今回はHUBOTとmysqlとgoogle カレンダーとgoogle apps script(以降GAS)とslackの連携となります。
今回実施したかった事は、計画的作業の見える化です。
cloudpackでは計画的な時刻指定の作業は、
backlogやgoogle カレンダーに記載して対応していましたが、
担当者の作業忘れや作業を取りかかっているかどうかが他の人(cloudpack依頼者)から
見えないなど、結果的には出来ていたのですが、もやっとした部分があったので
日次処理のつぶやきのように、slackへのカレンダーの通知(作業着手URL付き)と、
作業着手を受け付けたのを表示するつぶやきと、作業着手できない場合は、
定期的に出来ていない事を通知する機能を実装する事にしました。
今回はgoogleカレンダーの連携にGASを利用しました。
hubotからgoogleカレンダーのAPIを呼ぶのも出来るようですが、
自身の理解力が無いのか、情報が古いのかわかりませんが、
少しやってうまくいかなかったので、GASを使って
googleカレンダーの連携を行います。
GASでの方法は、単純で、定期的にgoogleカレンダーにアクセスして
つぶやきたい時間の範囲のカレンダーのデータを取得し、hubotに投げるだけです。
※以降の処理はhubotでさせる。
GASでカレンダーに連携するのは下記のURLを参考にさせて頂きました。
Googleカレンダーにアクセスする(1/5):初心者のためのGoogle Apps Scriptプログラミング入門
※GASですが、非常に便利ですが、色々と罠(仕様)や不具合が潜んでいます。
※簡単お手軽で、サンプルを張ってちょっと修正して動いちゃうのですごく良いのですが
※そこだけを見ていると痛い目に遭いますので注意(今回の範囲ではなかったので記載しません)
//カレンダー連携
function googlecalender() {var calendarId = "抽出したいカレンダーのID";
var cal = CalendarApp.getCalendarById(calendarId);
var urlstr = "連携先のhubotのurl";
// 現在時刻を生成
var date = new Date();
var d1 = new Date();
d1.setMinutes(d1.getMinutes());
var d2 = new Date;
d2.setMinutes(d2.getMinutes() + 15);
var evts = cal.getEvents(d1,d2);
var body = "";
if (evts.length > 0){
for (var i in evts){
var evt = evts[i];
if(!evt.isAllDayEvent()){ //終日では無い場合
var creators = evt.getCreators();
var responsible = "@" + creators[0].slice(0,creators[0].indexOf("@")) + " (イベント作成者)";
var guests = evt.getGuestsStatus();
if (guests.length >= 1){//招待者(担当)が登録されていたら招待者を担当者として上書き
responsible = guests[0].getEmail()
responsible = "@" + responsible.slice(0,responsible.indexOf("@")) + " (招待者)"
}
var Id = evt.getId()
var Title = evt.getTitle()
var Description = evt.getDescription()
var StartTime = Utilities.formatDate( evt.getStartTime(), 'JST', 'yyyy年M月d日HH時間mm分')
var EndTime = Utilities.formatDate( evt.getEndTime(), 'JST', 'yyyy年M月d日HH時間mm分')
var StartTimeInt = evt.getStartTime();
StartTimeInt.setMinutes(StartTimeInt.getMinutes() - 3);//処理時間の誤差を許容する為に
StartTimeInt = Utilities.formatDate( StartTimeInt, 'JST', 'yyyyMMddHHmm')
var EndTimeInt = Utilities.formatDate( evt.getEndTime(), 'JST', 'yyyyMMddHHmm')
var query =
{
"Id" : Id,
"Title" : Title,
"Description" : Description,
"StartTime" : StartTime,
"EndTime" : EndTime,
"StartTimeInt" : StartTimeInt,
"responsible" : responsible,
"EndTimeInt" : EndTimeInt
};
var options =
{
"method" : "post",
"payload" : query
};
UrlFetchApp.fetch(urlstr, options);
}
}
}
}
な感じで、GASは実装させて頂きました。
実装の詳細ですが
var calendarId = "抽出したいカレンダーのID";
var cal = CalendarApp.getCalendarById(calendarId);
で、抽出したいカレンダーにアクセスします。
var date = new Date();
var d1 = new Date();
d1.setMinutes(d1.getMinutes());
var d2 = new Date;
d2.setMinutes(d2.getMinutes() + 15);
取得したい期間を作成し
var evts = cal.getEvents(d1,d2);
その期間のカレンダーデータを取得します。
evts.length
カレンダーのイベントがあるのかを確認し
for (var i in evts){
データがあればでループさせ、
var evt = evts[i];
一つ一つのカレンダー情報にアクセスします。
evt.isAllDayEvent()
カレンダーが終日かを確認し、終日でなければ
var creators = evt.getCreators();
〜
var EndTimeInt = Utilities.formatDate( evt.getEndTime(), 'JST', 'yyyyMMddHHmm')
hubotに投げる情報を作ります。
そして
var query =
{
"Id" : Id,
"Title" : Title,
"Description" : Description,
"StartTime" : StartTime,
"EndTime" : EndTime,
"StartTimeInt" : StartTimeInt,
"responsible" : responsible,
"EndTimeInt" : EndTimeInt
};
var options =
{
"method" : "post",
"payload" : query
};
UrlFetchApp.fetch(urlstr, options);
でHubotのURLにカレンダー情報を投げます。
今回は③と④の情報を記載しました。
GASの"UrlFetchApp.fetch"での連携は非常に便利ですが
getとpostのみget/post/put/deleteの対応でpatchメソッド非対応なので使う方はちょっと検討する必要があります。
Google Apps Script Documentation - UrlFech Services - Class UrlFechApp
【cloudpack 大阪 BLOG】MSPのシステム化について(不定期連載) Hubotに定期的につぶやかせる&作業の管理をさせる
なんて記事が出ていて、時代の先を行っているな俺とかわけのわからん優越感に
浸っていますw
今回は<Hubotに日次作業を定期的につぶやかせる&作業の管理をさせる>です
①と②のやり取りの部分は前回で基本は出来るようになります•••
そしてよくHubotの最初に実装されている機能で、Slackにpingと入力したらpongと
返したりするのを少し楽しみますが・・・これからどう活用するの?で
PCの電源をそっとOFFにして、Heroku上には実装を待ち続ける、野良Hubotが
5万といるのではないかと推測されます・・・汗
とりあえず日次業務をつぶやかせるには、Hubotの機能だけでは無理なので
状態を管理する機能と、時間になったらHubotをつぶかす機能が必要になります。
今回状態を管理させるのは、Redisを使用し、
時間によるトリガーはnode.jsのモジュールである、cronモジュールを使います。
redisのインストールと設定は
sudo yum --enablerepo=epel install npm redis
sudo /etc/init.d/redis start
sudo chkconfig redis on
で、行いcronのインストールは
npm install cron
で、行いました。
これで下準備はOKでつぶやかせるには○の所に時間を入れて
cron = require('cron').CronJob
client = require("redis").createClient()module.exports = (robot) ->
new cron('0 0 ○ * * *', () ->
robot.messageRoom つぶやかしたいルーム名, "MSPの皆様おはようございます。本日の日次処理担当の方、○時になりましたので日次処理の対応よろしくお願いします"
, null, true, 'Asia/Tokyo').start()
で出来て、redisへの値のセットは
client.set "○", 1
な感じで(○はキー名として時間で”1”はセットしたい値です)簡単に値のセットが可能です・・・が、hubotに対する指示(ここでは作業を着手した)を、毎回キーボードで
入力してって言ったら、間違いなく使ってくれない・・・と言う事で、
HubotがURLを表示して、クリックされたらHubotが受け付けてつぶやく事をやめるような、お手軽なUIの実装を行います。
Hubotはnode.jsなので
request = require 'request'
module.exports = (robot) ->
robot.router.get "/hubot/daily", (req, res) ->
な形で、WEBサーバーとしてURLを受け付ける事も可能ですが、
SlackでURLを表示してしまうと、もれなくSlackのプレビュー機能で、
そのURLがコールされるというかなり残念な状況になってしまい、
表示=URLを叩かれた状態で処理が勝手に完了して、
全く無意味な状態になるので、コード上でユーザーエージェントを確認し
if req.headers['user-agent'] == 'Slackbot-LinkExpanding 1.0 (+https://api.slack.com/robots)'
return
slackからのプレビュー表示なら、処理を抜けるような実装をしてあげる必要があります。
で後は
client.get "○",(err, val) ->
if err
return
# エラーが無ければデータを取得
if val == 1
client.set "○", 0
robot.messageRoom "ルーム名","*○時の日時処理の受付完了しました*"
な感じで、redisから値を取得して状態を見て、問題なければつぶやくような実装をすれば
な感じでつぶやいてくれるようになります。
なお今回の機能を実装するにあたり下記のページを参考にさせて頂きました
私のブログは実装側を目的としているのではなく、
課題に対するアプローチがメインなので、ざっくりとした形で抜粋させてもらっていますので、実装は色んなBLOGを参考にして頂ければと思います。
今回の実装の仕方は、Hubotが初めてでもあったのと、見たサンプルを元に
実装していったために、作りが固定で汎用性が無いものになっていますが
とりあえず24/365を目標にずっと稼働しているので、今のところは目的を果たしていますし、担当者が作業を忘れていても、Slackを見ている他の人が気がつくようになっています。
クリックしないと、10分おき(時間が遅くなると5分おき)につぶやくので、
Slack上でのやり取りを中断してしまう?って話もありましたが、
気がつけばすぐにクリックと、作業漏れや作業着手の遅れが可視化されたので、
とりあえずはよしかなと思っていますが、よりMSPや他のメンバーにわかりやすくできる案が頭の中では出来たので、いつのタイミングかで実装/投入したいと思います。
次回はこの機能の実装を汎用化させた、
googleカレンダーとgoogle app scriptとhubotとslackの連携を書きます。