LGTM

Looks Good To Me

Hubot にlongest match 機能をつける

ネットワーク運用をしていると,ホストアドレスから経路をルックアップしたいことが結構ある.

たとえばDDoS を受けたとき.いろいろな対処が考えられるが,網内のルーターでパケットフィルターする際に「src address → src prefix の変換をしてからガバッと止めたい」とか.

そんな面倒くさいことはBot にやってもらいたい.

実装のアイデア

ルーターにログインして変換してもいいし,ルーティングテーブルを別に持って検索してもいい.

ルーターにログインしてshow route するのはIO バウンドな処理なのでnode との相性はよさそうだが,「src address が100コ」みたいな場合では遅いと思われる.よくあるルーターだと「まとめて引数を渡して,まとめて結果を受け取る」みたいなことができないため「1コ引数を渡して,1コ結果を受け取る」を100回やらないといけない.

一方,ルーティングテーブルを別に持つのってどう実装しよう?とか自前でpatricia tree つくんの?という面倒くささがある.

MRT TABLE DUMP + patricia tree でやってみる

実は,後者の面倒くさいところを解決してくれるbgpdump2 というツールがある.「node バインディング書けばいいのでは」と思ってやってみたら,結構うまく動くっぽかった.(まだ最小限の実装しかできてないです)

github.com

これを使うとlongest match の結果を返してくれる.

var BGPDump = require('node-bgpdump2');
var bgpdump = new BGPDump('path_to_rib.bz2');
console.log(bgpdump.lookup('8.8.8.8'));

// =>
// { prefix: '8.8.8.0/24',
//   nexthop: '202.249.2.169',
//   origin_as: 15169,
//   as_path: '2497 15169' }

Hubot から使うのもカンタンで,

npm install node-bgpdump2 --save
npm install https://github.com/codeout/node-mrt.git --save

たとえばshow route モドキを返すやつ.

# scripts/route.coffee

BGPDump = require('node-bgpdump2')
MRT = require('node-mrt')
mrt = new MRT('wide')

module.exports = (robot) ->
  robot.respond /route (.*)/, (msg) ->
    mrt.get (text)->
      msg.send text
    , (path)->
      bgpdump = new BGPDump(path)
      msg.send JSON.stringify(bgpdump.lookup(msg.match[1]))

ちなみに node-mrt はarchive.routeviews.org からMRT アーカイブをダウンロードしてキャッシュしてくれるライブラリです.

もうちょい複雑なことを: DDoS 対策手順を作ってもらう

一例だけれど,たとえばDDoS を検知後に

  1. src address → src prefix に変換
  2. src prefix ベースで帯域制限する手順をつくり,GitHub Issue としてオープン

というところまでHubot にお願いしたい.
(今回は例としてsrc prefix だけの条件)

hubot-github-templated-issues というの流用すれば結構ラクにできて,8.8.8.8, 8.8.4.4, 64.6.64.6, 64.6.65.6 からのDDoS を検知したときに

hubot anti ddos packet_filter/ratelimit_2g DDoS対策
src: [
8.8.8.8,
8.8.8.8,
64.6.64.6,
64.6.65.6
]

とHubot にお願いすると,

手順書をIssue 化してくれる.
(↑ ではMRT アーカイブをダウンロードしているが,キャッシュがあればそれをつかう)

https://github.com/codeout/sandbox/issues/108

この手順書はテンプレート にパラメーターを埋めて作ったもので,hubot-github-templated-issues がよしなにやってくれます.

今回つかったスクリプト: scripts/anti_ddos.coffee

まとめ

node-bgpdump2 を使うと,Hubot にlongest match 機能をつけられてけっこう便利だと思う.

bgpdump2 自体,少しコンセプト実装っぽい側面があって完全にライブラリ化されていないため,できたら作者の方に今後のロードマップについて聞きたいところです.

iOS9 のMail.app で使えるcipher,使えないcipher

iOS9 に上げたiphone でimaps できなくなったため,Client Hello が送るcipher suite を調べた.

iOS8.4.1 iOS9.0
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 ×
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 ×
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 ×
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 ×
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 ×
TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 ×
TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA ×
TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA ×
TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA ×
TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 ×
TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 ×
TLS_ECDH_RSA_WITH_AES_256_CBC_SHA ×
TLS_ECDH_RSA_WITH_AES_128_CBC_SHA ×
TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA ×
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 ×
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 ×
TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
TLS_DHE_RSA_WITH_AES_256_CBC_SHA
TLS_DHE_RSA_WITH_AES_128_CBC_SHA
TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA
TLS_RSA_WITH_AES_256_GCM_SHA384 ×
TLS_RSA_WITH_AES_128_GCM_SHA256 ×
TLS_RSA_WITH_AES_256_CBC_SHA256
TLS_RSA_WITH_AES_128_CBC_SHA256
TLS_RSA_WITH_AES_256_CBC_SHA
TLS_RSA_WITH_AES_128_CBC_SHA
TLS_RSA_WITH_3DES_EDE_CBC_SHA
TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
TLS_ECDHE_RSA_WITH_RC4_128_SHA
TLS_ECDH_ECDSA_WITH_RC4_128_SHA ×
TLS_ECDH_RSA_WITH_RC4_128_SHA ×
TLS_RSA_WITH_RC4_128_SHA
TLS_RSA_WITH_RC4_128_MD5

ちなみにOSX Yosemite (10.10.5) はiOS8.4.1 と同じcipher を送る.

openssl ciphers -tls1 HIGH と比べる

iOS8 & iOS9 & OSX Yosemite で使えるものは以下のcipher (openssl 形式) しかない.

  • ECDHE-ECDSA-AES256-SHA (0xC00A)
  • ECDHE-ECDSA-AES128-SHA (0xC009)
  • ECDHE-ECDSA-DES-CBC3-SHA (0xC008)
  • ECDHE-RSA-AES256-SHA (0xC014)
  • ECDHE-RSA-AES128-SHA (0xC013)
  • ECDHE-RSA-DES-CBC3-SHA (0xC012)
  • DHE-RSA-AES256-SHA (0x0039)
  • DHE-RSA-AES128-SHA (0x0033)
  • EDH-RSA-DES-CBC3-SHA (0x0016)
  • AES256-SHA (0x0035)
  • AES128-SHA (0x002F)
  • DES-CBC3-SHA (0x000A)

https のほうはATS 関連でTLS v1.2 が使えるのに,imaps では使えないのがつらい.

JUNOS でCI する話

ネットワーク運用がどんどん便利になって「手軽にメトリック監視できる」「ネットワークリソース管理がほら簡単」みたいな話はけっこう聞く.ところが,本丸であるネットワーク本体への変更については「慎重に人手で」という運用をしているところが多いと思う.

それが悪いということではなくて,たぶん「頻度低いから手動がコストバランス良い」のような理由があるんだけど,じゃあ「それに合う形でワークフローを良くしたいよね」と思う.

たとえばCI を導入することで,ネットワークデバイスへの変更について議論しやすくなったり,レビューしやすくなるといいなあと.

ネットワークでのCI って難しい

ネットワークデバイスに変更を加える場合,ソフトウェア開発のように「あらかじめふるまいを確認する」のはけっこうなコストがかかる.しかし,変更はコマンドのリストとして表現できて,コマンド文法が既知だから「シンタックスが正しい」ことくらいは事前に確認できるはず.

コマンドが誤っていて手戻りが発生することも日常的にあるので,CI でシンタックスを確認するだけでもだいぶマシになるはず,と思って作ったのがこれ.

github.com

netconf 用xsd からPEG パーサーを自動生成するためのツール群と,生成されたPEG パーサーが含まれていて

  • JUNOS のシンタックスチェック
  • show configuration 形式と| display set 形式の相互変換

ができる.詳しくは JANOG36 でのLT 資料 をご覧ください.

CI やってみると どんな感じか

無料でできる Gitlab + Gitlab-CI を使った例.eBGP neighbor を1つ加え,eBGP 全体を微調整するケースを考える.

サンプルレポジトリー: https://github.com/codeout/junos-ci/tree/gitlab

1. 変更案をGitlab にプッシュする

まず,これから加えたい変更について議論したり レビューしてもらうために,変更したい内容をGitlab に掲載する.

# gitlab プロジェクトをローカルにもってくる
$ git clone ssh://git@192.168.99.100:10022/codeout/junos-ci.git
$ cd junos-ci
...

# いま master ブランチにいる
junos-ci $ git branch
* master

# 変更用ブランチをつくる
junos-ci $ git checkout -b add-neighbor
...

config/junos.conf を修正して変更したい内容を記載する.

junos-ci $ git diff
diff --git a/config/junos.conf b/config/junos.conf
index 1331682..e860cc4 100644
--- a/config/junos.conf
+++ b/config/junos.conf
@@ -14,6 +14,8 @@ protocols {
                 }
                 local-address 198.51.100.1;
             }
+            neighbor 192.0.2.3;
+            invalid statement;  # わざとエラーを混ぜる
         }
     }
 }

ここでテストを回してパスするのを確認 → git commit → Gitlab にプッシュするのが本筋だが,今回はテストが落ちることをみるためにテストせずコミット & プッシュ.

junos-ci $ git commit -am "xxxx 開通準備"
junos-ci $ git push origin add-neighbor

2. Merge Request をつくる

Gitlab プロジェクトページに “Create Merge Request” ボタンが現れる.流れに沿ってMerge Request を作成する. こうすることで,他のメンバーに「こんな変更を加えたいので,議論 / レビューしてほしい」と伝えることができる.

作成が終わると勝手にCI が作動し Gitlab 上に “failed” と表示されるので,すぐシンタックスエラーがあることがわかる.(下図)

また,将来変更を適用した際 コンフリクトが発生しそうな場合も (下の例にはないが) warning が表示される.

さらにリンクをたどれば,どの行がおかしいかわかる.
(この場合 protocols bgp group ebgp-peers invalid statement)

失敗したテストをパスさせるには,適宜修正してコミット & プッシュすればよい.再度CI が作動して “passed” に変化する.

  • Gitlab にプッシュしてから “failed” に気づくと二度手間になるので,Merge Request オーナーがプッシュ前にテストするといい
  • レビューする側はプッシュ前にテストされたかどうかわからないが,Gitlab のCI ステータスが “passed” であれば シンタックスは正しい = セマンティクスだけ議論 / レビューすればいい ことがわかる

3. Gitlab で議論 / レビュー

シンタックスチェックはCI 任せにできるので,変更内容だけを議論 / レビューすればいい.

手動でテストする

サンプルレポジトリーRakefile に,junoser を使ったテストのサンプルがある.

ディレクトリ構造やファイル拡張子がちがうと動かないかもしれないので,適宜修正ください.

junos-ci $ rake
skip ./config/cisco.conf
verifying ./config/junos.conf ... done

議論 / レビュー後のデプロイフロー

ネットワークデバイスのMerge Request にはひとつ問題がある.

  1. Merge Request をマージ
  2. デプロイ
  3. show configuration

を行ったときの 1. と 3. の結果が必ずしも一致しない.セマンティクスは同じでも コマンド構造や順序がちがうかもしれない.今回のようにネットワークデバイスの設定を直接管理している場合,ネットワークデバイスが吐く設定をマスターにしたいということもあって,単に「Merge Request をマージして完了」にできない場合がある.

取りうる戦略がいくつかあって,

  • 変更をmaster ブランチにマージ → 変更後の設定全体をデプロイ
  • 変更をマージしない → 差分だけをデプロイ → トピックブランチ*1 を変更後の設定にrebase

それぞれ少しだけ説明します.

変更をmaster ブランチにマージ → 変更後の設定全体をデプロイ

シンプルなので,こちらがオススメ.

  1. Merge Request をmaster にマージ
  2. マージ結果をload override
  3. show configuration をmaster にcommit

ほぼ コマンド投入漏れが発生しないし,変にコンフリクトしていてもshow | compare などで気づくことができる.1. と3. のセマンティクスの整合は取れていると思われるので,そのままcommit する.

可能な限りこちらに寄せたほうが良いと思う.

変更をマージしない → 差分だけをJuniper にデプロイ → トピックブランチを変更後の設定にrebase

数ステップに分けて投入したい場合など.

junos-ci $ ./bin/patch master add-neighbor
# config/junos.conf -> config/junos.conf

set protocols bgp group ebgp-peers neighbor 192.0.2.3
set protocols bgp group ebgp-peers invalid statement

上のように差分をset コマンドに変換して投入した場合,コンフリクトに気付けない可能性がある.

  1. Merge Request をmaster にマージせず,差分をデプロイ
  2. この時点のshow configuration がトピックブランチと一致するかは保証されない
  3. なので,トピックブランチをrebase して確認する
  4. Merge Request をマージ

rebase 時にコンフリクトした場合,設定順序含めてトピックブランチを整理するのがかなり面倒.ただし大きなMerge Request だと 途中で確認を挟まないといけないため,こちらの戦略を取らざるを得ない.

まとめ

  • junoser を使えばJUNOS でCI できる
  • Gitlab のようなツールを使えば,議論 / レビューが楽になる
  • ネットワークへのデプロイ方法によってマージ方法が変わるが,なるべくマージ → 設定全体をデプロイしたほうがいい

ツールの具体的な設定方法を飛ばして「できた後はどんな感じか?」について書きましたが,ネットワークデバイスの設定をGitlab / Github 管理したらワークフローがどうなるか,CI し始めたらワークフローがどうなるか,イメージしてもらえるとうれしいです.

*1:変更のために作ったブランチ

Gitlab + Gitlab CI をためす

Gitlab + Jenkins があまりグッとこなかったので,Gitlab + Gitlab CI をためしてみた.結論から言えば,Gitlab + Jenkins より良いと思う.

Docker 上に準備

やることは

  1. Gitlab コンテナを動かす
  2. Gitlab CI コンテナを動かす
  3. Gitlab Runner コンテナを動かす

OSX 環境でためしたので,

$ docker-machine ip default
192.168.99.100

文中の192.168.99.100 とポートは適宜読み替えてください.

1. Gitlab コンテナを動かす

$ curl https://raw.githubusercontent.com/sameersbn/docker-gitlab/master/docker-compose.yml > gitlab.yml
$ docker-compose -f gitlab.yml up

http://192.168.99.100:10080 にアクセスできるようになるので,

  1. root ログインして必要なユーザーをつくる
    • 鍵を登録する
    • 適当なプロジェクトをつくる
  2. System OAuth applications に,あとで必要になる “http://192.168.99.100:10081/user_sessions/callback” を登録しておく
    • Application Id: b3c0249b80e96cc35c4952bd288d8ba27fdfdbb93cfac6939d1438ffbdb9aa63
    • Secret: a791b4b8e7a6515b457cf94a5246b74c1a72377ada25c009413fe0932f152753

参考: https://hub.docker.com/r/sameersbn/gitlab/

2. Gitlab CI コンテナを動かす

$ curl https://raw.githubusercontent.com/sameersbn/docker-gitlab-ci/master/docker-compose.yml > gitlab-ci.yml
$ vi gitlab-ci.yml

適宜編集

-postgresql:
+ci-postgresql:
   image: sameersbn/postgresql:9.4-3
   environment:
     - DB_USER=gitlab_ci
@@ -6,24 +6,24 @@
     - DB_NAME=gitlab_ci_production
   volumes:
     - /srv/docker/gitlab-ci/postgresql:/var/lib/postgresql
-redis:
+ci-redis:
   image: sameersbn/redis:latest
   volumes:
     - /srv/docker/gitlab-ci/redis:/var/lib/redis
 ci:
   image: sameersbn/gitlab-ci:7.13.5
   links:
-    - redis:redisio
-    - postgresql:postgresql
+    - ci-redis:redisio
+    - ci-postgresql:postgresql
   ports:
     - "10081:80"
   environment:
     - TZ=Asia/Kolkata
-    - GITLAB_URL=http://localhost:10080
-    - GITLAB_APP_ID=
-    - GITLAB_APP_SECRET=
-    - GITLAB_CI_SECRETS_SESSION_KEY_BASE=
-    - GITLAB_CI_SECRETS_DB_KEY_BASE=
+    - GITLAB_URL=http://192.168.99.100:10080
+    - GITLAB_APP_ID=b3c0249b80e96cc35c4952bd288d8ba27fdfdbb93cfac6939d1438ffbdb9aa63  # Application Id
+    - GITLAB_APP_SECRET= a791b4b8e7a6515b457cf94a5246b74c1a72377ada25c009413fe0932f152753  # Secret
+    - GITLAB_CI_SECRETS_SESSION_KEY_BASE=v5W2GBFZP9TxTd29tkxSmpdFm66BD8S9fTrVMrJkmGQ2KddgSqRdCL4t4Npk2vWh # pwgen -Bsv1 64 などで作成
+    - GITLAB_CI_SECRETS_DB_KEY_BASE=94fzWmKLLfWKkWlklQ9C4GXN8svTmnS2wMC7Xm9pw6hwdpLXgCcDl3R9Txxv8nLR # pwgen -Bsv1 64 などで作成
     - GITLAB_CI_HOST=localhost
     - GITLAB_CI_PORT=10081
     - GITLAB_CI_EMAIL=ci@example.com
$ docker-compose -f gitlab-ci.yml up

http://192.168.99.100:10081 にアクセスできるようになるので,

  1. OAuth ログイン
  2. プロジェクト一覧が取れる → 必要なプロジェクトを “Add project to CI”
  3. Runners pageトークンを調べる
    • 9967476047fe03df0f230dca181cf4

参考: https://hub.docker.com/r/sameersbn/gitlab-ci/

3. Gitlab Runner コンテナを動かす

$ docker run -d --name gitlab-runner --restart always \
  -v /srv/gitlab-runner/config:/etc/gitlab-runner \
  gitlab/gitlab-runner:latest
docker exec -it gitlab-runner gitlab-runner register
Please enter the gitlab-ci coordinator URL (e.g. http://gitlab-ci.org:3000/):
http://192.168.99.100:10081/
Please enter the gitlab-ci token for this runner:
9967476047fe03df0f230dca181cf4
Please enter the gitlab-ci description for this runner:
[8370d5d6805a]:
INFO[0129] 99674760 Registering runner... succeeded
Please enter the executor: docker-ssh, ssh, shell, parallels, docker:
[shell]:
INFO[0133] Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!

Runners page をリロードすると,Runner が登録されている.

Runner に必要なビルド環境をつくる.(たとえば) ruby をインストール.

$ docker exec -it gitlab-runner bash

$ apt-get update
$ apt-get install -y wget curl gcc libxml2-dev libxslt-dev libcurl4-openssl-dev libreadline6-dev libc6-dev libssl-dev make build-essential zlib1g-dev openssh-server git-core libyaml-dev postfix libpq-dev libicu-dev

$ su gitlab-runner

$ git clone https://github.com/sstephenson/rbenv.git ~/.rbenv
$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
$ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
$ source ~/.bash_profile
$ git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
$ rbenv install 2.2.3
$ rbenv global 2.2.3

参考: https://gitlab.com/gitlab-org/gitlab-ci-multi-runner/blob/master/docs/install/docker.md

Gitlab CI ができること

  • branch 作成時にCI を回す
  • Merge Request 作成時にCI を回す
    • Gitlab 上に結果表示
  • Status Badge
  • 結果をSlack / HipChat に通知
  • Gitlab と連携
    • OAuth
    • プロジェクト取得

おおよそ十分な機能をもっている.Jenkins がJava なのに対し,go + ruby + rails

Gitlab と一緒に使うならJenkins より直観的だし,プロジェクトごとにrunner を分けられて安心だなと思った.

フルルート入れるのにgobgp を使ってみる

「どの程度お手軽にフルルートを注入できるか?」の続編です.

2015/08/12 追記 : gobgp の不具合,修正されました

codeout.hatenablog.com

今回 gobgp のコミッターさんから「mrt 実装しましたー,もしお時間あったら試してみてください!」と連絡もらったので 試しました.

MRT TABLE_DUMP からフルルートを注入してみます.

gobgp ?

BGP Daemon のGo 実装です. 速そうだしガンガン機能が足されていて 注目のbgpd.

  • Go なので,マルチコアをうまく使ってくれそう
  • gobgpd (サーバー) とgobgp (CLI) で構成されている
  • サーバー <-> CLI 間はgrpc
  • MRT から経路生成できるし,MRT Dump もできる
  • 経路フィルター書けたり,VRF つくれたり,RPKI できたり,route server できたり,EVPN できたりしそう (未確認)
  • ドキュメント

特にサーバーはgrpc を話すので,「手軽にクライアント作れるかもしれないな」とも思ってます.

bgpsimple vs. gobgp

フルルート注入スピードについて,bgpsimple *1と比べてみると

bgpsimple gobgpd
ピアが上がるまで 0'00" 0'07"
フルルート広告し終わるまで 2'42" 1'43"
clear bgp 後,フルルート広告し終わるまで 3'12" 1'24"

gobgp めっちゃ速い!!!

bgpsimple がシングルスレッドなのに対し,gobgpd はマルチスレッドで CPU バウンドな処理と相性よさそう.実際にマルチコアをうまく使ってくれます.

環境

経路受信側は別Hypervisor のvSRX.ボトルネックにならないよう,経路はすべてreject する設定.

gobgp の長所

  • 速い!!!
  • CLI から多少コントロールできる
  • MRT を読んで一旦RIB に格納しているため,経路広告前にbest path selection が走っている
    • 経路の整合性が取れていて,受信側の負荷が下がる
  • MRT を直接入力できる (bgpdump 不要)

gobgp の短所

  • 不具合ありそう
    • eBGP UPDATE メッセージにLP 属性が入っている
    • eBGP UPDATE メッセージのAS_PATH 属性に,自分のAS が入っていない

    見つけた不具合はすぐ修正してもらえました.ありがとうございます

  • サポートOS が少ないかも?

    UNIX 系OS のうち,TCP-MD5 がきちんと実装されているのはLinux くらいだが

    • gobgp「TCP-MD5 サポートのためにLinux 以外は一旦忘れます」
    • 他bgpd「TCP-MD5 は動かないかもしれないけど,他のOS もサポートします」

個人的にはデバッグのためOSX で動くとうれしいが,Linux も手に入りやすい部類だと思う.上記の不具合が解決したら 積極的に使っていきたい.

*1:bgpsimple はMRT から経路生成するならお手軽で便利なので,イチオシだったbgpd

Bot にお願いして 手順書を書いてもらう

ネットワーク運用のなかに「手順書を書く」という業務がある.事業者によっては

  1. 書く
  2. レビュー
  3. 直す
  4. レビュー
  5. 直す

みたいな比較的コスト高い作業になる.

ネットワークは事前にテストしづらく「壊れるとヤバい」という側面から,日本では手作業による温かみのある作業が好まれる.Web アプリのような PRレビュー → Mergeボタン押す → 勝手にデプロイ みたいな自動ワークフローは,エンジニアにとってゴールではあるが,多くの場合まだ現実的でない.

Hubot に手順書を書いてもらう

じゃあ,ということで

GitHub に手順書のテンプレートを置いといて,パラメーターと一緒にお願いしたら,手順書つくってIssue にしてくれるHubot スクリプト

作った.

https://github.com/codeout/hubot-github-templated-issues

f:id:codeout:20150629010651p:plain

テンプレートエンジンはECT を選んだ.

トラブルが起こったときには,すでに手順書ができている

手順書作成のトリガーが人間でない場合もある.たとえばよくあるネットワークトラブルとか,パターン化できてるやつは「通知を受けたときにトラブル対応手順ができてる」のが望ましい.

使っているチャットやログ管理ツールによるが,たとえばHipChat + fluentd の場合:

  1. ネットワークデバイスがsyslog を吐く
  2. fluentd がsyslog をフィルター + 整形して,HipChat にHubot コマンド形式で書く
  3. Hubot が手順書をつくる

ような動作をさせることができる.ここまで自動.*1

f:id:codeout:20150629010658p:plain

# fluent.conf

<source>
  type syslog
  tag network
</source>

<filter network.**>
  type grep
  regexp1 message SNMP_TRAP_LINK_DOWN
</filter>

<filter network.**>
  type record_transformer
  enable_ruby
  <record>
message ${ message =~ /ifName (\S+)/; "hubot issue create templated-issues/intf-down\nhostname: " + host + "\nintfname: " + $1 }
  </record>
</filter>

*1:Slack だと,Web API / Incoming Webhook でHubot にコマンドを送れないため,ひと工夫ひつようっぽい