Vagrantでfireflyを動かしたら自動化開発が捗った話

[NetOpsCoding Advent Calendar2016](http://qiita.com/advent-calendar/2016/netopscoding) の12/5分の記事です。

本記事では、Vagrant でfireflyを動かすためのTipsを紹介します。

# Vagrant + fireflyがなぜ必要だったか。
前回の記事 [PyEZとJSNAPyを使ってみた](http://qiita.com/taijijiji/items/065eef08f7b673cb7bb6) でJuniper自動化ツールを試すために、気軽にローカルPC内で試せるJUNOS環境を欲しかったので、構築しました。

もともと社内の検証用ルータ(お高いもの)をリモートアクセスしてツール開発をしていたのですが、以下のような理由で効率が大変悪かったので、社内リソースとは切り離した環境を作りたかったのが今回のモチベーションです。

- 少し調べ物をしてるとルータor踏み台サーバとのsshセッションがタイムアウトしてしまい、再接続に手間がかかる
- 他担当者が検証用ルータを利用していると作業が衝突してしまう
- 採用しているJUNOSルータの情報(特にユーザ情報やOS version)が社外に漏れると危険なため、それら情報を利用しているプログラム自体も公開しづらくなる
- リモート環境で開発していると、ローカルPCで利用しているテキストエディタ(AtomやVisualStudio Codeなどリッチなもの)がリモート環境では利用できないことが多い

以前の記事[VagrantでQuaggaを複数台作ってBGP] (http://qiita.com/taijijiji/items/4cdb62317896f5509101)で試した、ローカルPC内で構築した Vagrant + Quagga の構成の非常に便利だったので、この仕組みをJUNOSルータで実現できないかなと探していました。そんな中でJuniper公式の[vagrant-junos](https://github.com/JNPRAutomate/vagrant-junos)というリポジトリを見つけたのでさっそく試してみました。ただしこのリポジトリが現在はメンテナンスされていないようで、このまま利用するとfireflyのversionが古いため途中で失敗してしまいます。そこで今回はこのリポジトリを直接使わない形でVagrant + firefly環境を構築する手順をまとめてみました。

# 環境
以下の構成で環境構築しました。

- MacBookAir OSX El Capitan 10.11.6
- Vagrant 1.7.4
- Virtualbox 4.3.30
- firefly-perimeter JUNOS version 12.1X47-D20.7

# 事前準備
ここではVagrantをVirtualBoxを利用して仮想サーバを構築する環境を利用していますが、Vagrantの使い方やインストール工程は省略します。以下の記事などを参考にして準備してください。

[インストール | Vagrant日本語ドキュメント](http://raqda.com/vagrant/installation/index.html)
[ドットインストール Vagrant入門](http://dotinstall.com/lessons/basic_vagrant)
[Vagrantのインストール、設定手順](http://qiita.com/Esfahan/items/41c4469f28f6011ab33b)

ここからVagrant + Fireflyを構築するための事前準備です。
まずローカルPC内に適当なディレクトリを作成します。

```
mkdir firefly
cd firefly
```

次に、Vagrant 実行環境を構築していきます。
(2017/11/17追記: リンク切れのためURL変更
https://atlas.hashicorp.com/juniper/boxes/ffp-12.1X47-D20.7
-> https://atlas.hashicorp.com/juniper/boxes/ffp-12.1X47-D15.4-packetmode )

```
vagrant box add firefly https://atlas.hashicorp.com/juniper/boxes/ffp-12.1X47-D15.4-packetmode

1) virtualbox
2) vmware_desktop

Enter your choice: 1 (ここでは仮想サーバにVirtual Boxを使って進めています)

....
```

```
vagrant init firefly 
...

ls -al
total 8
drwxr-xr-x   3 taiji  staff   102 12  4 12:53 ./
drwxr-xr-x  22 taiji  staff   748 12  4 12:08 ../
-rw-r--r--   1 taiji  staff  3019 12  4 12:53 Vagrantfile
```

ディレクトリ内にVagrantfileというファイルが生成されていれば準備OKです。

場合によっては以下のプラグインが必要になるかもしれません。エラーが出たら試してみてください。

```
vagrant plugin install vagrant-junos

vagrant plugin install vagrant-host-shell
```

これで準備は完了です。


# fireflyを1台作成する

作成されたVagrantfileを以下のように書き換えます。
IPアドレスは適当で構いません。ここでは、のちにfireflyを2台構築するシーンを紹介するため、明示的に「firefly1」と命名しています。

```
# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure(2) do |config|
    config.vm.box = "firefly"
    config.vm.define :firefly1 do | firefly1 |
        firefly1.vm.hostname = 'firefly1'
        firefly1.vm.network "private_network",ip: "192.168.33.1",netmask: "255.255.255.0"
    end
end
```

この状態で、vagrant upコマンドをfireflyが構築されます。(1分程度時間がかかります。)

なおfireflyは、動作要件としてメモリ4GB以上が推奨されているので構築前にホストマシンのメモリ空き容量を確認されることをおすすめします。
私の環境ではメモリ2.07GBで動いていることが確認できています。

```
vagrant up firefly1
```

vagrant upのメッセージが終了したら、正常に構築されたかvagrant statusコマンドで確認します。

```
vagrant status

Current machine states:

firefly1                  running (virtualbox)

The VM is running. To stop this VM, you can run `vagrant halt` to
shut it down forcefully, or you can run `vagrant suspend` to simply
suspend the virtual machine. In either case, to restart it again,
simply run `vagrant up`.
```

問題なく構築されたことが確認されたら、次はvagrant ssh コマンドで構築したfireflyにログインします。

```
vagrant ssh firefly1

--- JUNOS 12.1X47-D20.7 built 2015-03-03 21:53:50 UTC
root@firefly1%
```

これでfirefly構築およびログインは完了です。
つぎにfireflyに設定を投入していきます。

まずは CLIモードに変更します。

```
root@firefly1%
root@firefly1% cli
root@firefly1>
```

試しにshow versionコマンドを実施すると、他のJUNOSルータ同様に以下のような結果が出力されます。

```
root@firefly1> show version
Hostname: firefly1
Model: firefly-perimeter
JUNOS Software Release [12.1X47-D20.7]
```

firefly vagrantでは、デフォルトのインタフェース設定では、ge-0/0/0がDHCP、ge-0/0/1に、Vagrantfileで指定したIPアドレスが付与されるようになっています。(ちなみにVagrantfileで２つ目のIPを指定すると、ge-0/0/2に付与されます。)

```
root@firefly1> show configuration interfaces

ge-0/0/0 {
    unit 0 {
        family inet {
            dhcp;
        }
    }
}
ge-0/0/1 {
    unit 0 {
        family inet {
            address 192.168.33.1/24;
        }
    }
}
```

show interfaces terseコマンドではこのような結果が出力されます。

```
root@firefly1> show interfaces terse
Interface               Admin Link Proto    Local                 Remote
ge-0/0/0                up    up
ge-0/0/0.0              up    up   inet     10.0.2.15/24
gr-0/0/0                up    up
ip-0/0/0                up    up
lsq-0/0/0               up    up
lt-0/0/0                up    up
mt-0/0/0                up    up
sp-0/0/0                up    up
sp-0/0/0.0              up    up   inet
                                   inet6
sp-0/0/0.16383          up    up   inet     10.0.0.1            --> 10.0.0.16
                                            10.0.0.6            --> 0/0
                                            128.0.0.1           --> 128.0.1.16
                                            128.0.0.6           --> 0/0
ge-0/0/1                up    up
ge-0/0/1.0              up    up   inet     192.168.33.1/24
dsc                     up    up
gre                     up    up
ipip                    up    up
irb                     up    up
lo0                     up    up
lo0.16384               up    up   inet     127.0.0.1           --> 0/0
lo0.16385               up    up   inet     10.0.0.1            --> 0/0
                                            10.0.0.16           --> 0/0
                                            128.0.0.1           --> 0/0
                                            128.0.0.4           --> 0/0
                                            128.0.1.16          --> 0/0
lo0.32768               up    up
lsi                     up    up
mtun                    up    up
pimd                    up    up
pime                    up    up
pp0                     up    up
ppd0                    up    up
ppe0                    up    up
st0                     up    up
tap                     up    up
vlan                    up    down
```

あとはfirefly設定マニュアルを参考に設定を進めていきます。マニュアルが充実してるところはありがたいところですね。

[VMware PlayerではじめるFirefly Perimeter Fireflyの初期設定](https://www.juniper.net/assets/jp/jp/local/pdf/others/startup_firefly.pdf)
[VMware PlayerではじめるFirefly Perimeter ユースケース2 : JUNOS Router <Static/Dynamic Routing>](https://www.juniper.net/assets/jp/jp/local/pdf/others/usecase_firefly_router.pdf)

ここではfireflyに下記の設定を投入していきました。

```
set system root-authentication plain-text-password
set system login user <ユーザ名> class super-user
set system login user <ユーザ名> authentication plain-text-password

# デフォルト設定ではge-0/0/1がuntrust zoneに設定されているため、ホストマシンとの通信ができません。
# ここではホストマシン(MacbookAir)で自動化ツールを動作させて通信させたいのでge-0/0/1をtrust zoneに変更しています。
set security zones security-zone trust interfaces ge-0/0/1
set security zones security-zone trust interfaces ge-0/0/1.0 host-inbound-traffic system-services all
set system time-zone Asia/Tokyo

# PyEZなどの自動化ツールを利用するために、NETCONF over SSH (TCP 830) をオープンにしています。
set system services netconf ssh

# デフォルト設定はflow-based転送モード(firewall機能を動作させるモード)が有効になっており、
# このままではBGPやOSPFなどのルーティングプロトコルは動作しません。
# ここではルーティングプロトコルを動作させるために、packet-based転送モードに変更する設定を実施しています。
# モードの切替には、設定後の再起動が必要です。
delete security policies
set security forwarding-options family mpls mode packet-based
set security forwarding-options family inet6 mode packet-based
```

最後にfireflyを再起動させます。(packet-based転送モードの切替のため)

```
run request system reboot
```

再起動完了後、ホストマシン(ここではMacbookAir)からpingおよびSSHできることが確認できたら、構築完了です。

```
ping 192.168.33.1

ssh <ユーザ名>@192.168.33.1
```


# fireflyを2台作成する
今度はBGP環境を構築するためにfirefly2台を立ち上げることを実施してみました。

設定の要領は1台のときと一緒ですが、firefly2台の間を通信させるためにVagrantfileを若干工夫する必要があります。

実際は以下のようにVagrantfileを修正しました。
ゲストOS間の通信を許可するためには、private_network + virtualbox__intnet
の設定が必要なようです。

```
# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure(2) do |config|
    config.vm.box = "firefly"
    config.vm.define :firefly1 do | firefly1 |
        firefly1.vm.hostname = 'firefly1'
        firefly1.vm.network "private_network",ip: "192.168.33.1",netmask: "255.255.255.0"
        firefly1.vm.network "private_network",ip: "192.168.35.1",netmask: "255.255.255.252",virtualbox__intnet: "PNI"
    end
    config.vm.define :firefly2 do | firefly2 |
        firefly2.vm.hostname = 'firefly2'
        firefly2.vm.network "private_network",ip: "192.168.34.1",netmask: "255.255.255.0"
        firefly2.vm.network "private_network",ip: "192.168.35.2",netmask: "255.255.255.252",virtualbox__intnet: "PNI"
    end
end
```

このように設定してvagrant upさせることで、二台のfirefly1が下記の構成で起動します。

```
firefly1
- ge-0/0/0: DHCP (今回は使いません)
- ge-0/0/1: 192.168.33.1/24 (ホストマシンとの通信に利用)
- ge-0/0/2: 192.168.35.1/30 (firefly2と直接接続)
firefly2
- ge-0/0/0: DHCP (今回は使いません)
- ge-0/0/1: 192.168.34.1/24 (ホストマシンとの通信に利用)
- ge-0/0/2: 192.168.35.2/30 (firefly1と直接接続)
```

なおfireflyは一台あたり少なくとも2GB以上使う(推奨は一台メモリ4GB以上)ので起動時のメモリ空き状況にご注意ください。私の場合、二台同時にvagrant upしたらPCが固まりました。。

残りメモリを確認しながら、以下のように一台ずつvagrant upさせることをお勧めします。

```
vagrant up firefly1
...

vagrant up firefly2
...
```

最後に、先ほど紹介したfireflyの設定を投入すれば、環境構築は完了です。


```
set system root-authentication plain-text-password
set system login user <ユーザ名> class super-user
set system login user <ユーザ名> authentication plain-text-password
set security zones security-zone trust interfaces ge-0/0/1
set security zones security-zone trust interfaces ge-0/0/2
set security zones security-zone trust interfaces ge-0/0/1.0 host-inbound-traffic system-services all
set security zones security-zone trust interfaces ge-0/0/2.0 host-inbound-traffic system-services all
set system time-zone Asia/Tokyo
set system services netconf ssh
delete security policies
set security forwarding-options family mpls mode packet-based
set security forwarding-options family inet6 mode packet-based
```


# まとめ

今回はVagrantでfireflyを構築する手順を紹介しました。この環境を利用することでローカルPC内で開発した自動化ツールを、リモートアクセスすることなく即時に動作を試すことができるので、非常に開発が捗りました。

実際に、ローカルPC内にvagrantで作ったfirefly2台を構築し、さらにローカルPC内で開発した自動化ツールを試しているシーンをデモとして撮影してみました。画面左のツールは、[PyEZとJSNAPyを使ってみた。](http://qiita.com/taijijiji/items/065eef08f7b673cb7bb6)で紹介しているものです。

![demo_v4.gif](https://qiita-image-store.s3.amazonaws.com/0/45596/c29b2bca-e4e0-aab9-58c7-f2e382ceea2f.gif)


もし自動化ソフトウェアを手元で動作確認したい方がいらっしゃれば、ぜひこの記事をご参考にしていただければと思います。