スポンサーリンク

inet-hengeを使ってネットワーク構成図を自動作成してみる

Batfish
この記事は約26分で読めます。

はじめに

技術の進歩は凄まじいもので、昨今巷ではネットワーク構成図を自動作成するところまで来ているようです。今回はinet-hengeを使ってネットワーク構成図を自動作成してみようと思います。

 

inet-hengeのgithub

inet-hengeでネットワーク構成図を自動作成する場合どのネットワーク機器同士が接続しているかを表すjsonファイルが必要になります。今回は

A. jsonファイルを用意する方法

B. jsonファイルを用意せずにbatfishでどうにかする方法

の2つを試してみます。

 

参考サイト

Bのjsonファイルを用意せずにbatfishを使う方法はこちらを参考にさせていただきました。

 

inet-hengeのカスタマイズ用

 

使用するネットワークと機器のconfigについて

構成図にするネットワークは以前batfishを触ってみたときに作った適当なネットワーク+αを使いました。

drawioで描いたネットワーク構成図はこんな感じです。Switch0,1は以前は名前を付けてなかったんですが便宜上付けました。configは初期設定からhostnameだけ変更したものなので省略します。

+αはchannel表記を見るためだけに作ったChannel-Switch0,1の2台です。自動的に構成図が作成される際にchannelの図が見たかったので追加しました。以前のrouter1,2,3,4とは接続せず2つのSwitch間をchannelで接続しているだけです。一応Channel-Switch0のconfigを載せておきます。Channel-Switch1.cfgはhostnameとIPアドレス箇所以外変わりません。

Channel-Switch0.cfg
version 16.3.2
no service timestamps log datetime msec
no service timestamps debug datetime msec
no service password-encryption
!
hostname Channel-Switch0
!
!
!
!
!
!
!
no ip cef
no ipv6 cef
!
!
!
!
!
!
!
!
!
!
!
!
!
spanning-tree mode pvst
!
!
!
!
!
!
interface Port-channel1
 no switchport
 ip address 192.168.0.1 255.255.255.0
!
interface GigabitEthernet1/0/1
!
interface GigabitEthernet1/0/2
!
interface GigabitEthernet1/0/3
!
interface GigabitEthernet1/0/4
!
interface GigabitEthernet1/0/5
!
interface GigabitEthernet1/0/6
!
interface GigabitEthernet1/0/7
!
interface GigabitEthernet1/0/8
!
interface GigabitEthernet1/0/9
!
interface GigabitEthernet1/0/10
!
interface GigabitEthernet1/0/11
!
interface GigabitEthernet1/0/12
!
interface GigabitEthernet1/0/13
!
interface GigabitEthernet1/0/14
!
interface GigabitEthernet1/0/15
!
interface GigabitEthernet1/0/16
!
interface GigabitEthernet1/0/17
!
interface GigabitEthernet1/0/18
!
interface GigabitEthernet1/0/19
!
interface GigabitEthernet1/0/20
!
interface GigabitEthernet1/0/21
!
interface GigabitEthernet1/0/22
!
interface GigabitEthernet1/0/23
 no switchport
 no ip address
 channel-group 1
 duplex auto
 speed auto
!
interface GigabitEthernet1/0/24
 no switchport
 no ip address
 channel-group 1
 duplex auto
 speed auto
!
interface GigabitEthernet1/1/1
!
interface GigabitEthernet1/1/2
!
interface GigabitEthernet1/1/3
!
interface GigabitEthernet1/1/4
!
interface Vlan1
 no ip address
 shutdown
!
ip classless
!
ip flow-export version 9
!
!
!
!
!
!
!
!
line con 0
!
line aux 0
!
line vty 0 4
 login
!
!
!
!
end

 

diff Channel-Switch0.cfg Channel-Switch1.cfg
 % diff Channel-Switch0.cfg Channel-Switch1.cfg
6c6
< hostname Channel-Switch0
---
> hostname Channel-Switch1
38c38
<  ip address 192.168.0.1 255.255.255.0
---
>  ip address 192.168.0.2 255.255.255.0
132d131
<

 

 

A. jsonファイルを用意してbatfishを使わないパターン

まずはbatfishを使用せずにinet-hengeだけで構成図を作ってみます。

 

A-1. inet-hengeの準備

まずは適当なディレクトリにinet-hengeをgit cloneします。git cloneしたらinet-henge/exampleに移動します。

git clone https://github.com/codeout/inet-henge.git

cd inet-henge/example

 

A-2. htmlとjsonファイルの用意

htmlファイルを作成します。handmade.htmlとしてます。index.htmlを参考に作成しました。

handmade.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <link href="style.css" rel="stylesheet" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.js"></script>
    <script src="../vendor/cola.min.js"></script>
    <script src="../inet-henge.js"></script>
  </head>

  <body>
    <div id="diagram"></div>
  </body>

  <script>
   var diagram = new Diagram('#diagram', 'handmade.json', {pop: /^([^\s-]+)-/, bundle: true, width: 1280, height: 1024});
  diagram.init('loopback', 'interface');
  </script>
</html>

色が変わっている行にあるbundle: trueは機器間の接続を多重化(要はchannelを表示)するために設定しています。

width: 1280, height: 1024はブラウザでネットワーク構成図を表示する範囲を広げるために設定しました。

 

次にhandmade.jsonを作成します。こちらもindex.jsonとか参考にして一生懸命手書きしました。

handmade.json
{
  "nodes": [
    { "name": "Router0", "icon": "./images/router.png" },
    { "name": "Router1", "icon": "./images/router.png" },
    { "name": "Router2", "icon": "./images/router.png" },
    { "name": "Router3", "icon": "./images/router.png" },
    { "name": "Switch0", "icon": "./images/switch.png" },
    { "name": "Switch1", "icon": "./images/switch.png" },
    { "name": "Channel-Switch0", "icon": "./images/switch.png" },
    { "name": "Channel-Switch1", "icon": "./images/switch.png" }
  ],

  "links": [
    { "source": "Router0", "target": "Switch0" ,
      "meta": { "interface": { "source": "ge0/1", "target": "ge0/1"} } },
    { "source": "Router1", "target": "Switch0" ,
      "meta": { "interface": { "source": "ge0/1", "target": "ge0/2"} } },
    { "source": "Router0", "target": "Router2" ,
      "meta": { "interface": { "source": "ge0/0", "target": "ge0/0"} } },
    { "source": "Router1", "target": "Router3" ,
      "meta": { "interface": { "source": "ge0/0", "target": "ge0/0"} } },
    { "source": "Router2", "target": "Switch1" ,
      "meta": { "interface": { "source": "ge0/1", "target": "ge0/1"} } },
    { "source": "Router3", "target": "Switch1" ,
      "meta": { "interface": { "source": "ge0/1", "target": "ge0/2"} } },
    { "source": "Channel-Switch0", "target": "Channel-Switch1",
      "meta": { "interface": { "source": "ge-1/0/23", "target": "ge-1/0/23"} } },
    { "source": "Channel-Switch0", "target": "Channel-Switch1",
      "meta": { "interface": { "source": "ge-1/0/24", "target": "ge-1/0/24"} } }
  ]
}

nodeが表示されるnodeですね(そのまんま)

linksが接続している線ですね(そのまんま)

説明不要なくらいわかりやすい形してますねw

 

A-3. webサーバの起動

git cloneしたinet-hengeディレクトリに移動してwebサーバを起動します。

python3が入っているなら以下コマンドを実行します。この辺はgithub参照。

python3 -m http.server

 

A-4. 動作確認

webブラウザ立ち上げて先ほど立ち上げたwebサーバにアクセスします。私はchromeを使いました。

awsのec2で実行しているのでpublic ipにアクセスします。このときは54.199.84.108でした。

http://54.199.84.108:8000

アクセスするとこんな画面になります。

 

ちなみにここでexampleをクリックするとindex.htmlにアクセスすることになり、inet-hengeのサンプルを見ることができます。shownet.htmlもサンプルの様子。

http://54.199.84.108:8000/example/index.html
http://54.199.84.108:8000/example/shownet.html

 

先ほど作ったhandmade.htmlにアクセスしてみます。

http://54.199.84.108:8000/example/handmade.html

うまく行くとこんな感じの構成図が表示されます↓

 

少し位置を調整して拡大するとこんな感じになります↓

draw.ioで作った構成図とほぼ同じ図が作成されています!

channel部分も二重に接続されているのが表現されています。すごいですねinet-henge!

 

B. jsonファイルを用意せずにbatfishでどうにかする方法

今度はjsonファイルの代わりにbatfishからtopologyデータを取得して表示する方法です。まんま参考サイトのままですが試してみます。

 

B-1. batfishをpybatfishから起動

まずbatfishを動かします。今回はpybatfishを使う方法にしていますが、同じ設定のJupyter NotebookをRunさせても構成図を自動作成してくれます。

 

まずは以前と同様にでbatfish/allinoneのコンテナを起動させます。

docker-compose up -d

 

以下コマンドでpython3を起動させます。

docker exec -it batfish python3

 

その後以下のコマンドを実行します。

from pybatfish.client.commands import *
from pybatfish.question.question import load_questions, list_questions
from pybatfish.question import bfq

load_questions()


NETWORK_NAME = "mynetwork"
SNAPSHOT_NAME = "mysnapshot"
SNAPSHOT_PATH = "/notebooks/mynetworks/"

bf_set_network(NETWORK_NAME)
bf_init_snapshot(SNAPSHOT_PATH, name=SNAPSHOT_NAME, overwrite=True)

 

ログはこちら

ubuntu@MyEC2 ~/batfish % docker exec -it batfish python3
Python 3.5.2 (default, Nov 12 2018, 13:43:14)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from pybatfish.client.commands import *
>>> from pybatfish.question.question import load_questions, list_questions
>>> from pybatfish.question import bfq
>>>
>>> load_questions()
Successfully loaded 63 questions from remote
>>>
>>> NETWORK_NAME = "mynetwork"
>>> SNAPSHOT_NAME = "mysnapshot"
>>> SNAPSHOT_PATH = "/notebooks/mynetworks/"
>>>
>>> bf_set_network(NETWORK_NAME)
'mynetwork'
>>>
>>> bf_init_snapshot(SNAPSHOT_PATH, name=SNAPSHOT_NAME, overwrite=True)
status: TRYINGTOASSIGN
.... no task information
status: CHECKINGSTATUS
.... no task information
status: CHECKINGSTATUS
.... Fri Sep 27 14:16:23 2019 UTC Begin job.
status: CHECKINGSTATUS
.... Fri Sep 27 14:16:23 2019 UTC Parse network configs 0 / 8.
status: CHECKINGSTATUS
.... Fri Sep 27 14:16:23 2019 UTC Parse network configs 0 / 8.
status: ASSIGNED
.... Fri Sep 27 14:16:23 2019 UTC Parse network configs 0 / 8.
status: CHECKINGSTATUS
.... Fri Sep 27 14:16:23 2019 UTC Parse network configs 0 / 8.
status: CHECKINGSTATUS
.... Fri Sep 27 14:16:23 2019 UTC Parse network configs 0 / 8.
status: ASSIGNED
.... Fri Sep 27 14:16:23 2019 UTC Parse network configs 0 / 8.
status: ASSIGNED
.... Fri Sep 27 14:16:23 2019 UTC Parse network configs 0 / 8. (00:00:05 elapsed)
status: ASSIGNED
.... Fri Sep 27 14:16:23 2019 UTC Parse network configs 0 / 8. (00:00:06 elapsed)
status: ASSIGNED
.... Fri Sep 27 14:16:23 2019 UTC Parse network configs 0 / 8. (00:00:07 elapsed)
status: CHECKINGSTATUS
.... Fri Sep 27 14:16:23 2019 UTC Parse network configs 0 / 8. (00:00:08 elapsed)
status: CHECKINGSTATUS
.... Fri Sep 27 14:16:23 2019 UTC Parse network configs 0 / 8. (00:00:09 elapsed)
status: CHECKINGSTATUS
.... Fri Sep 27 14:16:23 2019 UTC Parse network configs 0 / 8. (00:00:10 elapsed)
status: CHECKINGSTATUS
.... Fri Sep 27 14:16:23 2019 UTC Serializing 'org.batfish.representation.cisco.CiscoConfiguration' instances to disk 0 / 8. (00:00:11 elapsed)
status: ASSIGNED
.... Fri Sep 27 14:16:23 2019 UTC Convert configurations to vendor-independent format 8 / 8. (00:00:12 elapsed)
status: TERMINATEDNORMALLY
.... Fri Sep 27 14:16:23 2019 UTC Deserializing objects of type 'org.batfish.datamodel.Configuration' from files 8 / 8. (00:00:13 elapsed)
Default snapshot is now set to mysnapshot
status: UNASSIGNED
.... no task information
status: ASSIGNED
.... no task information
status: TERMINATEDNORMALLY
.... Fri Sep 27 14:16:37 2019 UTC Begin job.
'mysnapshot'
>>>

重要なのはNETWORK_NAMEとSNAPSHOT_NAMEです。ここまでコマンドを実行したら画面放置で次へ進みます。

 

B-2. inet-hengeの準備

先ほどと同じようにinet-henge/example配下にhtmlファイルを用意します。jsonファイルは用意しません。ファイル名は参考サイトと同様にbatfish.htmlとしています。

batfish.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8"/>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.js"></script>
    <script src="https://inet-henge.herokuapp.com/js/cola.min.js"></script>
    <script src="https://inet-henge.herokuapp.com/js/inet-henge.js"></script>
    <style>
        .path-label {
            font-size: 7px;
        }
    </style>
</head>

<body>
<div id="diagram">
</div>
</body>

<script>
//document.write("test1");
  const batfishToInethenge = (data) => {
    const nodes = new Set();
    data.forEach((i) => {
      nodes.add(i.node1);
      nodes.add(i.node2);
    });

    const links = data.map((i) => ({
      source: i.node1, target: i.node2,
      meta: {
        interface: {source: i.node1interface, target: i.node2interface},
      }
    }));

    return {
      nodes: Array.from(nodes).map((i) => ({
        name: i, icon: 'https://inet-henge.herokuapp.com/images/router.png'
      })),
      links: links,
    };
  };

  // Tweak distance
  const distance = (force) => force.jaccardLinkLengths(100, 0.2);

  (async () => {
    const response = await fetch('http://54.199.84.108:9996/v2/networks/mynetwork/snapshots/mysnapshot/topology', {
      headers: {'X-Batfish-Version': '0.36.0'},
    });
    new Diagram(
            '#diagram',
            batfishToInethenge(await response.json()),
            {pop: /^as\d+/, bundle: true, width: 1280, height: 1024}).init('interface');}
    )();
</script>
</html>

const response = await fetch・・・箇所で指定しているアドレスはawsのIPv4 パブリック IPです。mynetwork、mysnapshotはpybatfishで指定したNETWORK_NAMEとSNAPSHOT_NAMEです。

 

B-3. webサーバの起動

jsonファイルを用意するほうと同じです。inet-hengeディレクトリで以下コマンドを実行します。

python3 -m http.server

 

B-4. 動作確認

同じように先ほど作成したbatfish.htmlにアクセスします。

http://54.199.84.108:8000/example/batfish.html

 

うまく行くと無事ネットワーク構成図が表示されます。

何も表示されない場合、右クリックから検証を選択してエラーの内容を確認すると原因がわかるかも? ※batfish.html内のIPアドレスはlocalhostにしてアクセスできないときに重宝しました。

表示されるのはこんな感じの図です。

 

位置を調整して拡大するとこんな感じになります。

 

jsonファイルをハンドメイドした場合と違ってだいぶ違う図になってますね。理由はjsonファイルの内容が違うからのようです。

 

B-おまけ:jsonなしバージョンでcurlで取得している情報について

curlでbatfishから取得している情報をjqで見やすくしたものを載せておきます。

これをbatfish.html内のjavascriptでjsonデータとして加工してくれています。

channel-switch0と1の接続IFはPort-Channel1と表示されています。L3ベースなのかな?

※つまりこの情報を強化すればもっと意図したネットワーク構成図が作れるかも?でもbatfishよくわからん。。

ubuntu@MyEC2 ~/batfish % curl -H "X-Batfish-Version: 0.36.0" http://localhost:9996/v2/networks/mynetwork/snapshots/mysnapshot/topology | jq
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  1153  100  1153    0     0  88692      0 --:--:-- --:--:-- --:--:-- 88692
[
  {
    "node1": "channel-switch0",
    "node1interface": "Port-Channel1",
    "node2": "channel-switch1",
    "node2interface": "Port-Channel1"
  },
  {
    "node1": "channel-switch1",
    "node1interface": "Port-Channel1",
    "node2": "channel-switch0",
    "node2interface": "Port-Channel1"
  },
  {
    "node1": "router0",
    "node1interface": "GigabitEthernet0/0",
    "node2": "router2",
    "node2interface": "GigabitEthernet0/0"
  },
  {
    "node1": "router0",
    "node1interface": "GigabitEthernet0/1",
    "node2": "router1",
    "node2interface": "GigabitEthernet0/1"
  },
  {
    "node1": "router1",
    "node1interface": "GigabitEthernet0/0",
    "node2": "router3",
    "node2interface": "GigabitEthernet0/0"
  },
  {
    "node1": "router1",
    "node1interface": "GigabitEthernet0/1",
    "node2": "router0",
    "node2interface": "GigabitEthernet0/1"
  },
  {
    "node1": "router2",
    "node1interface": "GigabitEthernet0/0",
    "node2": "router0",
    "node2interface": "GigabitEthernet0/0"
  },
  {
    "node1": "router2",
    "node1interface": "GigabitEthernet0/1",
    "node2": "router3",
    "node2interface": "GigabitEthernet0/1"
  },
  {
    "node1": "router3",
    "node1interface": "GigabitEthernet0/0",
    "node2": "router1",
    "node2interface": "GigabitEthernet0/0"
  },
  {
    "node1": "router3",
    "node1interface": "GigabitEthernet0/1",
    "node2": "router2",
    "node2interface": "GigabitEthernet0/1"
  }
]

 

最後に

2つの例でinet-hengeを使ってみました。

個人的にはAのjsonファイルを細かく作るほうが意図した構成図を作れるので好きです。ただ大規模なネットワークでは厳しいかなと思いましたがその辺は工夫すれば何とかなるじゃないかなと。小規模ならハンドメイドでも良いですしね。

将来的にbatfishがもっといい感じになってBパターンで出来たら楽ですけどね。知らないだけで既に出来るなら最高。

スポンサーリンク
Batfishcisco
スポンサーリンク
hakenをフォローする
定年まで泣くんじゃない
タイトルとURLをコピーしました