Blog Brocade Japan

NOS内蔵PythonとBWCの連携

by Ken Sugai on ‎02-07-2017 10:05 PM - last edited on ‎04-07-2017 01:09 AM by aokuhara (1,391 Views)

やりたいこと

 

NOS内蔵PythonではCLIライブラリーを使って任意のNOSコマンドを実行できます。コマンド出力をパースして情報を切り出したり条件分岐やループをしたり自由自在なロジックでNOS CLIを操作できます。しかしNOSコマンドでは外部に通知を送ることができません。「○○が起こりました」とか「○○しました」という通知をどっかで拾えないと、スクリプトに黙って何かされるのは不安です。そこでPythonライブラリーを使って外部に通信しようと思います。こんな時こそBWC (Brocade Workflow Composer/StackStorm)で受けることにしましょう。窓口は一つにしておいて、そこからいろいろなチャネル(メール、Slack、ログファイル、など)にメッセージを振り分けるようにして、どこに振り分けるという指示もメッセージと一緒に送ります。つまりBWCがイベントのハブになったら便利だと思います。メッセージを転送するだけでなくBWCのアクションでいろいろな機器の設定変更もできるので、能動的なクロスドメインのワークフローも可能であり、応用の可能性はたいへん広いです。

 

Webhookを叩く案

 

BWCのトリガーの中でいちばん使いやすいWebhookを叩くスクリプトを作りました。まずはNOSでなくLinux上で実行してみます。

 

import urllib.request
import json
message = 'Just a test'
dispatch = 'slack,email' bwc = '10.20.30.40' webhook = 'eventhub' apikey = 'NDVmMDRjYTNlNzI3YjM4YjM1Y2ViNjQwYmViNTNiMTZkMmE5OTkyOTVjYTExNjhlZjdkNWUwNDU4M2JkNzQ3Zg' url = 'https://{}/api/v1/webhooks/{}'.format(bwc, webhook) headers = {'St2-Api-Key': apikey, 'Content-Type': 'application/json'} payload = {'dispatch': dispatch, 'message': message} req = urllib.request.Request(url=url, headers=headers, data=json.dumps(payload), unverifiable=True, method='POST') urllib.request.urlopen(req)

 

BWCサーバーのIPアドレスとAPI Keyだけ実際の環境に合わせて書き換えてください。(API Keyの生成方法はドキュメントの Authentication > API Keys)。

この試作ではメッセージの転送先としてメールかSlackが選べるようにします。2とおりの振り分けができれば後は20でも200でも同じことです。スクリプトの下から3行目でHTTPSリクエストのペイロードとなるディクショナリーを作っています。キー'dispatch'の値で振り分け先を指示します。'email'ならメール、'slack'ならSlackです。上のコード例のように'slack,email'とすれば両方に送ります。

BWC側ではメール用・Slack用に別々のルールを作ります。どちらも同じトリガー(core.st2.webhook)ですが、クライテリアでtrigger.body.dispatchを見て識別します。Webhookを受けてメールを送信するルールは以下のとおりです。(Slackを送るルールもほぼ同じなので省略します。アクションはslack.chat.postMessageを使ってください)。

 

---
description: 'Webhook -> Email'
tags: []
type:
  ref: standard
  parameters:
enabled: true
name: eventhub.email
trigger:
  ref: core.1fd73ce2-beec-4f3f-9d61-7a2d1e4e1e6e
  type: core.st2.webhook
  parameters:
    url: eventhub
criteria:
  trigger.body.dispatch:
    pattern: email
    type: icontains
action:
  ref: core.sendmail
  parameters:
    body: '{{trigger.headers["X-Real-Ip"]}}: {{trigger.body.message}}'
    to: ksugai@brocade.com
    subject: '{{trigger.headers["X-Real-Ip"]}}: {{trigger.body.message}}'
pack: jpdemo
ref: jpdemo.eventhub.email
id: 587ec1686bb2ea0f23f7acc0
uid: 'rule:jpdemo:eventhub.email'

 

メールの件名と本文に、スクリプトを実行したサーバーのIPアドレスとメッセージを入れています。

ところが、残念ながらこのスクリプトはNOS内蔵Pythonでは動作しませんでした。NOSのPython環境にはurllibライブラリーはインストールされていますがsslライブラリーがないためHTTPSリクエストができず、Webhookを叩くことはできませんでした。

 

Syslogを送る案

 

次に考えたのはSyslogメッセージをBWCサーバーのUDP:514に送ることです。サーバーがこのメッセージを受け取るかどうか、受け取ってどのログファイルに書くかは設定しだいですが、検証に使ったUbuntuでは何も設定しなくても/var/log/syslogに書き込まれました。このログファイルをlinux.file_watch.lineトリガーで見張って特定の文字列があったら反応するルールを作ることにします。

まずスクリプトは以下のとおりです。

 

from CLI import CLI
import re
from logging import getLogger, INFO
from logging.handlers import SysLogHandler
# Message
message = 'just a test'
dispatch = 'slack'
# BWC information BWC = '10.20.30.40' tag = 'EventHub' # Sender information showsys = CLI('show system', do_print=False) m = re.search(r'#Unit Name\s*:\s*([^#]+)#', '#'.join(showsys.get_output()), re.I) unitname = m.group(1) # Send syslog datagram logger = getLogger(tag) handler = SysLogHandler(address=(BWC,514)) handler.setLevel(INFO) logger.setLevel(INFO) logger.addHandler(handler) logger.info('#'.join(['', tag, dispatch, unitname, message]))

BWCサーバーの/var/log/syslogには以下の1行が書かれます。

 

Jan 31 14:09:49 10.20.30.99 #EventHub#email#vdx02#just a test

最初の#の前まではsyslogdが付加した情報で、タイムスタンプと送信元のIPアドレスです。#以降がスクリプトが送信した内容です。Webhookではディクショナリーを渡せましたがSyslogでは1行のテキストしか渡せないので4つの項目を#でつなげてパックしました。(ベタですみません)。内容は左から、目印の文字列、転送先、送信元のUnit Name、メッセージです。

次はログファイルを見張るトリガーの設定です。/var/log/syslog のモードが600だったので sudo chmod a+r してBWCが読めるようにしてください。それから /opt/stackstorm/packs/linux/config.yaml に以下の内容を入れてから st2ctl reload します。

 

file_watch_sensor:
  file_paths:
    - /var/log/syslog

ルールは以下のとおり、クライテリアで対象のログを発見し、そのままワークフローに渡します。

 

Rule

Rule_cont

 

 ワークフローは以下のとおりです。

 

---
version: '2.0'

default.EventDispatch:
  input:
    - line
  tasks:
    Start:
      # [235, 26]
      action: core.noop
      publish:
        items: <% regex('#').split($.line) %>
      on-complete:
        - email: <% $.items[2] = 'email' %>
        - slack: <% $.items[2] = 'slack' %>
    email:
      # [105, 128]
      action: core.sendmail
      input:
        to: 'ksugai@brocade.com'
        subject: '<% $.items[0] %> <% $.items[3] %> <% $.items[4] %>'
        body: <% $.items[4] %>
    slack:
      # [365, 128]
      action: slack.chat.postMessage
      input:
        channel: 'random'
        text: '<% $.items[0] %> <% $.items[3] %> <% $.items[4] %>'

1行のSyslogメッセージにパックされて来た情報をアンパックする必要があるのでYAQLのパターンマッチ機能を使っています。その後、振り分け指示を見てCase文のようなYAML構文でタスクを振り分けます。

 

 従来からBWCがVDXから情報を取る「プル」操作はできましたが、VDX側から「プッシュ」ができるとワークフローの自由度がまったく違ってきます。いろいろ応用していただければ幸いです。

 

関連リンク

PyNOSを使ってみよう

NOS内蔵Python

BWCでVDXの疎通確認

 

StackStorm Slack日本語チャネル開設 

日本語でのStackStorm情報交換の場所としてSlackの日本語チャネルを開設しました。
SlackのStackstorm-communityチームに登録されている方はそのまま#community-japanへ参加できます。
まだstackstorm-communityチームに登録されていない方は以下から参加できます

https://stackstorm.typeform.com/to/K76GRP