はじめに
こんにちは、
GMOアドマーケティング 開発本部 本部長のクリスです。
インフラチームのマネージャーも兼任してます。
先日、インフラチームのために、
Google Cloud Functionsを使ってSlackで依頼されたタスクを自動的にRedmineに登録する仕組みを作りました。今回、そちらについて紹介したいと思います。
普段マネジメントがメインですが、久しぶりに開発ができてとても楽しかったです。
背景
最近、プロダクトの増加に連れて、インフラチームへのタスク依頼も増えています。
会社ではSlackを使っていますが、コミュニケーションが取りやすい分、インフラへの依頼があちこちのチャンネルに分散されている状態でした。
・マネジメント側としては、タスクの依頼状況の全体がみえず、フォロー、調整がしにくい
・インフラエンジニア側としては、タスクのチケット登録に追われ、あちこちのチャンネルで依頼者との調整などで業務効率が落ちる
といった問題がありました。
それを改善するため、開発本部内、他チームとも調整した結果、インフラチームへの依頼は#dev_infraというチャンネルに集約することとなりました。
また、業務効率化のため、Slackでの依頼事項をそのまま、自動的にRedmineに登録することにしました。
前置きが長くなりましたが、その仕組について簡単に紹介したいと思います。
実際Slackではこんな感じ
@infra-redmineにフォーマット化された依頼事項を送ると、そのままRedmineに登録されます。そして発行されたチケットのURLがまたSlackにポストされるといった仕様です。
また、インフラメンバーにもメンションをつけて送ると、チケットの担当者として登録されます。 ← これはかなりうちのメンバに喜ばれました。😀
仕組みは以下の通り
全体像
メインのプログラムはもともとGASを使う予定でしたが、G Suiteの権限の制約でSlack(サーバー)からアクセスができないため、Cloud Functionsを選択しました。
流れは以下の通りです。
1.まずは、SlackのOutgoing Webhooksを使ってタスク依頼をキャッチします。
メンションでキャッチしたかったのでこちらの記事を参考にしました。
↓
2.1からPOSTされたJSONデータを解析してから、
RedmineのPOST /issues.jsonを通して、チケット登録を行います。
↓
3.成功すると、チケット番号が返却されるので、それを使ってチケットURLを作成します。
↓
4.最後にSlackのchat.postMessageを使って
チャンネルにチケットのURLをポストして、これで完了です。
Cloud Functionsで作成したコードのサンプル(Node.js)は以下の通りです。細かい処理は省略しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
/** * Responds to any HTTP request. * * @param {!express:Request} req HTTP request context. * @param {!express:Response} res HTTP response context. */ const request = require('request'); exports.slackToRedmine = (req, res) => { const text = req.body.text; createIssue(text); res.status(200).send('OK'); }; const createIssue = (text) => { const redmineUrl = 'https://redmine.example.com/issues.json'; const redmineAPIKey = '********************************'; //textからチケットのタイトル、説明文、担当者などの抽出処理は省略する const issue = { project_id: プロジェクトのID, subject: 'チケットのタイトル', description: 'チケットの説明文', tracker_id: トラッカーのID, status_id: ステータスのID, priority_id: プライオリティーのID, assigned_to_id: 担当者のID, category_id: カテゴリのID }; const payload = { issue: issue }; const user = 'basic認証のID'; const pass = 'basic認証のPW'; const buffer = new Buffer(user + ':' + pass); const headers = { 'Authorization': ' Basic ' + buffer.toString('base64'), //basic認証があるなら使う 'X-Redmine-API-Key': redmineAPIKey, 'Content-Type': 'application/json' }; const options = { url: redmineUrl, method: 'POST', headers: headers, body: JSON.stringify(payload) }; request(options, (error, response, body) => { if (error) { console.log('error:' , error); return; } if (body) { body = JSON.parse(body); const url = 'https://redmine.example.com/issues/' + body.issue.id; let msg = 'チケットは以下の通りに登録されました。\n'; msg = msg + url; msgToSlack(msg); }else { msgToSlack('登録できませんでした。'); } }) } const msgToSlack = (msg) => { const slackToken = 'xoxb-********************************'; const headers = { 'Content-Type': 'application/json' } const options = { url: 'https://slack.com/api/chat.postMessage', method: 'POST', headers: headers, json: true, form: { token: slackToken, channel: 'dev_infra', icon_emoji: ':ghost:', username: 'infra-redmine', text: msg } } request(options, (error, response, body) => { //処理がいるならここで書く }) } |
最後に
今回、個人としてはじめてGoogle Cloud Functionsを使用しましたが
Consoleを使った開発もできて非常に手軽な印象でした。
しかも従量課金で、無料枠も設けられてるので、
今回のような開発業務をサポートするツール系の開発はもってこいな環境だと思います。
これからもどんどん活用していきたいと思います。
インフラエンジニア絶賛募集中
弊社ではGCPを活用したインフラ構築、運用を積極的に行っています。
もし興味あればぜひご応募ください。
カジュアル面談でもOKです。
GMOアドマーケティング 開発本部 本部長