NetTesterでad-hocなテスト作業を拡張する

# この記事?
この記事は、[NetOpsCoding Advent Calendar 2016](http://qiita.com/advent-calendar/2016/netopscoding) の 2016年12月13日 の記事です。

この記事の内容は、[Trema Day #10](https://trema.connpass.com/event/40434/) で発表した [ワンライナーでもここまでできる! NetTester+pryでお手軽ネットワークテスト](https://gist.github.com/corestate55/91dd3e4dc54e858082ca082a4270c004) という話の内容とほぼ同じです。当日は直接コード入力しながらデモをしたのですが、ちゃんと図とか出せていなかったし、Gist で書いた手順メモくらいしか用意できなかったので、あとで読み返せるものがなかったんですよね。あらためて Asciinema でそのデモを録画してみたので、それを元に解説してみたいと思います。

# Background

## NetTester?
[NetTester](https://github.com/net-tester/net-tester) は「物理ネットワークの受け入れテストツール」です。どんなツールなのかについては、[NetOpsCoding#4](https://atnd.org/events/82204) の LT や、先週 [Trema Day #10](https://trema.connpass.com/event/40434/) でも高宮さんや村木さんが発表しているので、そちらを見ていただければと思います。

## ここでいうテストって?
「テスト」って立場によって見方が変わるので、ここではどう考えるか、というのだけ先に出しておきます。

- 機器単体ではなく、複数のNW機器がつながった「ネットワーク」がテスト対象。
- ネットワークを作った人(いわゆるネットワークエンジニア)が作業者
- ネットワーク上で何ができるか? を確認する
    - end-to-end での通信テスト、ネットワークの機能試験
    - ネットワークの中身は問わない(ブラックボックステスト)

ネットワークエンジニアが、ネットワーク機器をいろいろつなぎあわせて設定を入れます。一通りできたら、そのネットワークの上でやりたかったこと(どこからどこへ、どんなアプリケーションで、どんな通信ができる/できない)を確認します。

こうしたテストは、ネットワークを利用する側から提示された要件に基づいておこなわれます。作ったネットワークが、利用者から見て「やりたいことがやれる」ネットワークになっているかどうかを見ます。…という観点で「物理ネットワークの受け入れテスト」と言っています。

## デモでは、なんのために、なにをしているのか?

NetTester は、テスト用のホストをつくったり、それをテスト対象のネットワークにつなぎこむための API を提供してくれます。今回、[Cucumber でネットワークの受け入れテストを書く](https://github.com/net-tester/examples/tree/feature/ood_demo)、というのをいろいろ試しているのですが、実際作業していると、以下のような状況で、ちょっとした手作業をやりたいことがあります。

- Cucumber でテストを書くときに、テストで使いたいコマンドのオプションこれでよかったんだっけ? ……というのを実際に試しながら決めたい
- テストがコケたので、ちょっと ping 実行して、テスト対象ネットワークでちゃんと通信できるかどうかを確認しておきたい(テストコードの問題かテスト対象ネットワークの問題かを、手作業で、試しながら切り分けたい)

当然、テスト用PCをスイッチに接続しにいちいち席を立つ……みたいなことをやりたくないわけです。そういうシチュエーションだと思ってください。そんなときに作ったスクリプトを NetTester の解説用にちょっと書きなおして、NetTester を使うとどんなことができるのかを書いてみます。

## 環境

こんな感じです。(この図は特に "応用編" での状況を描いたものです。) テスト対象ネットワークは Cisco Catalyst 3750G (L2SW1/2, L3SW), Juniper SSG (FW1/2) で組んであります。なお、L2SW1/2 の port9-10 は trunk port になっています。
![Demo Environment](https://qiita-image-store.s3.amazonaws.com/0/154230/0559d023-4e0c-6d27-d8f6-4ef4fc631fb7.png)

# デモ

## 基礎編: テスト用のホストを2個作って ping をうつ

[![NetTester example1 asciinema](https://asciinema.org/a/0vykmluxkgv0mkbn94gpymtx7.png)](https://asciinema.org/a/0vykmluxkgv0mkbn94gpymtx7)

[example1.rb](https://gist.github.com/corestate55/91dd3e4dc54e858082ca082a4270c004#file-example1-rb) を使ってます。コード自体は、解説用ということもあって、かなりベタというか冗長な書き方をしてあります。

デモ見てもらうとわかるかなあと思うのですが、

- `NetTester::Netns` で作ったテスト用のホストの実体は Linux network namespace
- `#new` に渡している `virtual_port_number`, `physical_port_number` がパッチパネルの端点番号を表す (図参照)
    - 裏では、NetTester が OVS/物理OFSに flow rule (OpenFlow) をいれて、テスト対象のネットワークに直結されているように見せかけています。
- `#exec` で、その namespace 上でコマンドを実行する

重要なのは NetTester の使い方です。基本的には 3 steps になります。

- `NetTester.run` して NetTester を起動する
- `NetTester::Netns.new` でテストに使うホストを作る + ホスト上で作業を行う
- `NetTester.kill` して後始末をする

`Netns.new` のパラメタについては工夫次第でもっと簡潔にかけるようになります。[Cucumber でテストシナリオ作っていく時には、FactoryGirl を使った](https://github.com/net-tester/examples/blob/feature/ood_demo/features/factories.rb)りしています。

## 応用編: 複数ホストを使う操作をrubyで拡張する

[![NetTester example2 asciinema](https://asciinema.org/a/4a3lbtsoja8zounjt0dzizezh.png)](https://asciinema.org/a/4a3lbtsoja8zounjt0dzizezh)

[example2.rb](https://gist.github.com/corestate55/91dd3e4dc54e858082ca082a4270c004#file-example2-rb) を使います。[example1.rb](https://gist.github.com/corestate55/91dd3e4dc54e858082ca082a4270c004#file-example1-rb)と中身はたいして違いません。作るホストの数を増やしたのでちょっとパラメタ設定のところを変えてある程度です。

example2.rb では、セグメントごと/物理スイッチごとにテスト用のノードを2個ずつつくっています(図参照)。その上で、

- 各ホストが、自分の default gateway に対して通信(ping)できること
- 各ホストが、自分以外のホストに対して通信(ping)できること

を確認しています。これで次のことがわかります。

- テスト対象ネットワークに default gateway がいて、各スイッチ・各セグメントにあるホストからの ping に応答すること
- テスト対象ネットワークの、セグメント間ルーティングと、default gateway, L2SW1/L2SW2 間のアクティブな経路のすべてが問題なく動いていること
    - L2SW ではそれぞれ、ひとつのセグメントに2個ずつホストを置いているので、スイッチ内でのセグメント折り返しまで見ています。

ちなみに、[Mininet](http://mininet.org/) 触ったことのある方はお気づきかもしれませんが、Mininet にある `pingall` コマンドがこれと同じことをしてくれます。それと同等のものが、NetTester と pry をつかえばほんの数行のループ書くだけで作れてしまうということですね。

# まとめ

ネットワークを作って、そこに通信確認用のホストを数台置きたい、置いたホスト間でまとめて何かを繰り返し実行したい、みたいな話はよくあると思います。手作業でいちいち作業用PC用意してスイッチに配線しに席を立たなくても、こんな感じでコードで操作できるようになったらどうでしょう? パターンまとめて実行したいなー、みたいなことも、その場でインタラクティブにコーディングできちゃったりしたら、おもしろいと思いませんか?

途中、いろいろリンクはってありますが、参考になりそうな資料等を最後にまとめておきます。もともと NetTester はソフトウェア開発で使われているいろいろなテストツールとの連携を想定して作っています(Cucumber でネットワークのテストシナリオをかいてみるというのを実際にやってみています)。興味のある方はぜひご覧ください。

- [NetTester GitHub](https://github.com/net-tester)
    - [シナリオテストのサンプル](https://github.com/net-tester/examples/tree/feature/ood_demo)
- 解説
    - [OOD2016](http://www.okinawaopenlabs.org/ood/2016/program_day4/)で[発表した資料](http://www.okinawaopenlabs.org/ood/2016/pdf/1208/OOD2016_1208_hagiwara.pdf) (pdf)
    - [シナリオテストの解説付きデモ動画](https://www.youtube.com/watch?v=C7z3aaWgsf4) (youtube)
    - [Trema Day #10 in Okinawa Powered by APC](https://trema.connpass.com/event/40434/) & [ツイートまとめ](http://togetter.com/li/1057689): NetTester チームで発表しています。資料とかは追って公開されていくはずです。