OpenStack MonascaのWebhook統合

2016-03-25

OpenStack MonascaのWebhook統合

Machine-translated — the English original is authoritative.

グレアムのWebhook簡易歴史 [非技術編]

もちろん、皆さんはWebhookが何かご存知でしょうが、私は先月、別のHelion OpenStack統合の準備をするまでそれを知りませんでした。

私の理解を簡略化すると – Webhookは「プッシュ通知」です。

インターネットの登場により、私たちは非常に迅速に賢くなり、M2M通信のためにこれらの奇妙なUDPやTCPプロトコルを使い始めました。帯域幅は問題にならなかった(冗談です)ため、効率性は最初の要件ではありませんでした。

多くの監視ソリューションはHTTPを最適なプロトコルとして採用し、関心のあるリソースを単純にポーリングして応答を待ちました。このアプローチを使用したい場合は、MonascaがRESTful APIを提供しています。

しかし、クラウドにはスケールの課題が伴います。そして、数秒間で何十万ものサービスをポーリングしようとしている場合、効率性は非常に重要です。そこでWebhookが登場し、事態を救います。

報告するものがなくてもHTTP GETに続いてHTTP POSTを必要とする、‘昔ながら’で非効率なポーリングとは異なり、Webhookは単一のHTTP POSTを必要とし、POSTする価値のあるものがあって初めてトリガーされます!!!

要約すると – 頻繁なHTTP GET/POST versus 稀なHTTP POSTです。GithubがWebhookを導入した際、新しいコード変更を監視するユーザーからのサーバー負荷を66倍削減したという都市伝説がネット上に流れています。[ 私には事実がありません ]

設定方法は?簡単です。特に以前のSMTP統合ブログをお読みであれば。まずはGUIから始めましょう – これはすべてCLIから実行可能ですが、それにはさらに多くの資料を読む必要があります。

注: 運用コンソールのGUIはHelion OpenStackディストリビューション固有のものです。Helionを使用していない場合は、Monasca CLIを使用する必要があります。

HOS MonascaでのWebhook設定

  1. クラウド管理者ユーザーとしてHelion Ops Consoleにログインします。
    Operations Portal

  2. 画面左上の‘ハンバーガー’メニューから「Notification Methods」オプションを選択します。
    menu

  3. 新しい通知方法を作成し、Webhookを選択して、HTTP POSTで通知を送信したいURLの詳細を入力します。
    createNewNotif

これでWebhookの設定は完了です。しかし待ってください、「どうやってテストして検証するのか」とお考えでしょう… 続きを読む。

テストアラームの作成

再び‘ハンバーガー’メニューに戻り、今回は「Alarm Creation」を選択して、以下のように新しいアラームを作成します – ここでは誤警報を発生させたいので、メトリックとして cpu.idle を使用し、おかしな値を設定します –
TestAlarm
新しいアラーム定義の作成

これはこのアラームが初めて実行されるため、以前の状態を持っていないため、最初は「Unknown(不明)」のアラームが2つ表示される場合があります。しかし、辛抱強く待ってください。数分後には、以下に示すようにダッシュボードが点灯するはずです。
Alarm dashboard
数分待ちます(5分)

これで、詳細を表示するためにアラームを選択できます。
Alarm List
アラームを確認
Alarm detail
アラーム詳細の表示

そして当然のことながら、私たちが待望していたもの – Webhookアラート!!!

おっと!Webhookアラートをどうテストするのか…

多くのエンタープライズグレードの監視ソリューションは、今日でもWebhookをサポートしていません – これらの企業はアジャイルを理解できず、なぜ小規模な競合他社に追い越されるのか不思議がっています。

再度言いますが、これから見ることを本番環境で実行することはお勧めしません – これはWebhookをテストおよび検証するためだけのものです。また、HOSコントロールプレーンのファイアウォールでポートを開け、デプロイノードをポート3001で実行されるWebhookサーバーとして使用できるようにしました。[ この手順をラボ内でテストしたい場合は、以前のSMTP投稿を参照してください ]

注: 世界中のコーダーの皆様、私が破っているすべてのルール、悪いコーディングなどについて、今から謝罪します。あなたの公開物のおかげでこれらの例をこじつけたので、優しく見守ってください 🙂

以下に2つの例示スクリプトを提供します。1つはNodeJS用、もう1つはPython用です。Pythonは多くのOpenStackユーザーに馴染みがあるためです。NodeJSは、それを使う良い機会が欲しかったからです – とても良いです!ここではPythonやNodeの環境設定方法についてはカバーしません。これらのトピックに関するブログは山ほどあります。Pythonを使用する場合は、仮想環境(virtualenv)があなたの味方です – それを使用してください。

Pythonの例

以下のPythonスクリプトをコピーしてファイルに保存し、webhook.py という名前を付けてください。このスクリプトはWebhook通知を待ち受け、受信するとログファイルに書き込みます。これはレガシーな監視ソリューションがアラートを解析するために使用できます – エンタープライズグレードではありませんが、例として提示しています。

webhook.py

# Author: Graham Joseph Land
# Blog: allthingscloud.eu
# Twitter: @allthingsclowd
# Email: graham@ the above domain
# Date: 24/03/2016
# 
# Name: webhook.py
# Version: 0.1
# Purpose: This script listens for webhook notifications and then writes them to a logfile
#
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
import json
import logging
import logging.handlers

# log file for this script
log_file = '/home/stack/monitoring/venv/webhook/webhook.log'

log_max_size = 25165824         # 24 MB
log_level = logging.INFO
#log_level = logging.DEBUG      # DEBUG is quite verbose

log = logging.getLogger('log')
log.setLevel(log_level)
log_handler = logging.handlers.RotatingFileHandler(log_file,
                                                   maxBytes=log_max_size,
                                                   backupCount=4)
f = logging.Formatter("%(asctime)s %(filename)s %(levelname)s %(message)s",
                      "%B %d %H:%M:%S")
log_handler.setFormatter(f)
log.addHandler(log_handler)

class webhookReceiver(BaseHTTPRequestHandler):

    def do_POST(self):
        """
            receives post, handles it
        """
        log.info('<<<<<<<<< Alert Start >>>>>>>>')
        message = 'OK'
        self.rfile._sock.settimeout(5)
        data_string = self.rfile.read(int(self.headers['Content-Length']))
        self.send_response(200)
        self.send_header("Content-type", "text")
        self.send_header("Content-length", str(len(message)))
        self.end_headers()
        self.wfile.write(message)

        # parse data
        text = json.loads(data_string)
        text = json.dumps(text, indent=2)
        log.info(text)
        log.info('<<<<<<<<< Alert End >>>>>>>>')

    def log_message(self, formate, *args):
        """
            disable printing to stdout/stderr for every post
        """
        return

def main():
    """
        the main event.
    """
    try:
        server = HTTPServer(('', 3001), webhookReceiver)
        log.info('started web server...')
        server.serve_forever()
    except KeyboardInterrupt:
        log.info('ctrl-c pressed, shutting down.')
        server.socket.close()

if __name__ == '__main__':

スクリプトを実行し、ログファイルをtailします – 今、戻ってアラートを再度生成し、何が起こるか確認してください..
Webhook Alarm

これで完了です – Webhook – 「簡単!」

Monascaの問題を除外するために、以下のようにcurlコマンドを使用してこのスクリプトをテストすることもできます。

curl -H "Content-Type: application/json" -X POST -d '{"alarm_id": "1234","alarm_definition_id": "freddef","alarm_name": "fire alarm","alarm_description": "alarmDescription","alarm_timestamp": "timestamp","state": "Critical","old_state": "oldState","message": "this is the message","tenant_id": "tenant1234","metrics": "1234"}' --trace-ascii debugdump.txt http://172.16.60.9:3000/openstack/alerts

NodeJSの例

Pythonの例で使用したものとは異なるWebhookエンドポイントを使用していることに注意してください。
nodejswebhook

NodeJSの例示アプリケーションには、やや複雑なファイル構造が必要です。

メインの app server.js を使用し、そこから受信時にWebhookを処理する‘route’アプリ webhook.js を呼び出します。

(venv)stack@helion-cp1-c0-m1-mgmt:~/monitoring/nodejs$ tree -I node_modules
.
|-- routers
|   `-- webhook.js
`-- server.js

以下の2つのアプリを、上記に示すディレクトリ構造と同じ名前のファイルにコピーします。

server.js

var bodyParser  = require( 'body-parser' ),
    express     = require( 'express' ),
    app         = express();

var webhook        = require( './routers/webhook' );

app.use( bodyParser.json() );
app.use( bodyParser.urlencoded({
  extended: true
}) );

app.get( '/', function ( req, res, next ) {
    res.send( 'Hooks listener running' );
});
app.use( '/openstack/alerts', webhook );

app.listen( 3001 );

そしてroutersサブディレクトリ内には

webhook.js

var express = require( 'express' ),
    bodyParser = require('body-parser'),
    router  = express.Router();

router.use(bodyParser.json());

router.post( '/', function ( req, res, next ) {
    console.log(req.body);

    res.status(200).json({message: 'Monasca Hook received!'})
});

module.exports  = router;

アプリを起動し、まずcurlでテストします –

stack@helion-cp1-c0-m1-mgmt:~$ curl -H "Content-Type: application/json" -X POST -d '{"alarm_id": "1234","alarm_definition_id": "freddef","alarm_name": "fire alarm","alarm_description": "alarmDescription","alarm_timestamp": "timestamp","state": "Critical","old_state": "oldState","message": "this is the message","tenant_id": "tenant1234","metrics": "1234"}' --trace-ascii debugdump.txt http://172.16.60.9:3001/openstack/alerts
{"message":"Monasca Hook received!"}stack@helion-cp1-c0-m1-mgmt:~$

結果は以下のようになります

(venv)stack@helion-cp1-c0-m1-mgmt:~/monitoring/nodejs$ nodejs server.js
{ alarm_id: '1234',
  alarm_definition_id: 'freddef',
  alarm_name: 'fire alarm',
  alarm_description: 'alarmDescription',
  alarm_timestamp: 'timestamp',
  state: 'Critical',
  old_state: 'oldState',
  message: 'this is the message',
  tenant_id: 'tenant1234',
  metrics: '1234' }

最後に、前述の手順に従ってMonascaからアラートを送信し、Webhook通知が届いてアプリによって処理されるのを見ます。
NodeAlerts


[注: 通知配信のトラブルシューティング]

cd ~/scratch/ansible/next/hos/ansible
ansible-playbook -i hosts/verb_hosts monasca-reconfigure.yml

Originally published on allthingscloud.eu (2016-03-25).

← All posts