kakkotetsu

1か月間リモートワーク/引きこもり生活していた雑記 (2020/03)

最初に

COVID-19 絡みで 2020/03/02(月) 以降リモートワークしつつ引きこもり生活をしております
丁度 1 か月経ったので、どんな生活だったか色々と所感を交えながらダラダラと垂れ流します
リモートワークに関する仕事論やシステムの話やコスト(交通費や光熱費など)などの難しい話はしません

書いた人

首都圏在住 30 代の独身男性(IT 関係の会社員)です
普段は東京 23 区内の会社に通勤して、平日 10:30-19:00くらい (フレックス制度あり)で働く生活をしています
リモートワークをするのは 8 年ぶりくらいです

仕事

私は IT 系ということもあり、リモートワークで困らないどころかそちらの方が捗っていますが、これは業務内容や人によるので詳しいことは書きません
(私の場合は元々オフィスに行っても一言も喋らない日が珍しくもなく、オフィスが騒がしくて集中できないとかの煩わしさも感じていました)

環境周りで言うと ↓ とかは凄いなーと思って見ていました

仕事環境のために買った/買いたいもの

1週間くらい仕事をしてみて、まず気になったのは椅子でした

むかーしリモートワークをしていた時(20台後半だった筈)は、当時ノートPCとフリーアドレスな会社だったこともあり、家でもノートPCオンリーで横になったり椅子に座ったりしながら仕事していました
が、この数年で体は老いたし贅沢になったし、今回は大き目のディスプレイとそれなりにちゃんとしたキーボード(これらは元々の自宅環境)を使って仕事をしていました
そうなると、ずっと机の前で椅子(背もたれが低く、ひじ掛けもない数千円くらいのデスクチェア)に座りっぱなしということになり...疲れるなーと

アーロンチェアを買おうかと思ったのですが、安めのゲーミングチェアにしてみました
椅子はもっと金をかけても良いだろうと思っているので、しばらく使ってみて体に合わなかったら...ちゃんと本気なやつを買おうかと

背もたれを180℃倒してユラユラとゆりかごのような動きもできたりして、半月つかってみた今時点では結構気に入っています

それから半月...椅子ほどに切羽詰まっていないのですが、今は「机を昇降式デスクにリプレイス」・「もっと良いディスプレイを増設、何なら現行機もリプレイス」・「ついでにモニターアーム導入」なんかを考えています
が、机の置き換えは相当手間になるのでなかなか踏み切れず...

外出

公共交通機関を使った外出は後述の 1 日だけで、あとは徒歩圏内(自転車は持ってますが使っていない)で生活しております
散々言われている通り「自分が無自覚な感染者であると仮定して、感染を広げないように行動する」を心掛けております

旅行

元々、旅行や温泉が好きで月に1度以上は小旅行をしていたのですが、3月は一切行ってません (というか2月中旬以降)
今回の騒動に伴う生活の変化で、これが一番しんどいです.......

「静かで人が減った今がチャンス」と言って出かけている人達を後目に、体があまり強くない上に 11 か月前まで喫煙者だった自分は引きこもっております
ただ、会社で隣席の方が↑な人で出かけ捲っているらしいので、いずれ出社するようになった時が怖い...

スパ銭

スパ銭が好きで、日頃から会社帰りに23区内や埼玉のものに週1くらいの頻度で通っていたのですが...これも勿論止めております
しんどー

ちなみに行かないにも関わらず、スパ銭界隈の対応状況は調査して垂れ流していました(以下の一連のスレッド)
「こういう事態でどういう対処をするか」は施設の信頼性につながるかなーとか思いつつ、結局ディズニーランドなどと一緒で長期休業などの対処が出来るのは体力がある大手だけだろうな、とも

消えたイベント/予定達

私が参加予定だった 3~4 月の色々なイベント(ライブ、スポーツ観戦)は当然ながら全て中止/延期になりました
プロ野球は今年開幕できないんじゃないかな

あー、ただ普通なら人気が高くて参加抽選が厳しそうな IT 系勉強会がリモート開催(参加者上限なし)になったお陰で参加できたのは良かったですね
今後もリモート開催の IT 系勉強会が増えると良いなーと
(発表者に凸って質問する、みたいなのは出来なくなるのでパブリックな場で話せることしか質問できなくはなりそうですが...)

外食

外食を避けるようになった結果ガッツリ系な食事が大幅に減って、軽めのコンビニ飯やカップ麺や蕎麦を茹でて食べることが多くなりました
コンビニのサラダチキン+野菜とかコスパは悪いけど楽だし「まあこれでいいや」とか思いながら食べることが増えました
調べてみたら、3月に外食(いわゆるイートインの話で、スーパーマーケット弁当とかは除く)したのは以下だけでした

  • 03/07 昼食 : 近所でまぜそば
  • 03/16 昼食 : 池袋でラーメン
  • 03/27 昼食 : 近所でマサラカレー
  • 03/28 休憩 : 近所でアイスコーヒー

先に書いた通り、旅行が趣味で食べ歩きも大好きだったので、普段の外食を控えるようにするのもなかなか辛いです
ストレスの所為か、今月はデスソースの消費量が増えました

1 日だけ電車に乗って出社した日

で、公共交通機関を使ったのは 2020/03/16 の 1 日だけです
Web会議ではダメで対面で、と指定された打ち合わせのために出社しました
それにかこつけて、その日に色々とやりました

半月ぶりに電車に乗って、会社に向かう(午前リモートワーク、午後出社) 途中の池袋駅西武ライオンズ70周年ポスターをパシャリ

約10日ぶりの外食 これも池袋のラーメン屋

会社で打ち合わせを終えたら、速攻でフレックス退勤しました
既に「人が集まっている状態がとても怖く感じる」ようになってしまっていました... (ホリエモンがいうところの「ヒステリー」に私も軽く陥っているのかも知れません)

とか言いつつ、帰りに「どうせ外出してしまったのだから」と言い訳しながら、2020/02/29(土) に公開された SHIROBAKO 劇場版 をやっと観られました
本当は初日に観る気満々だったんですけどね...
なかなかに良かったので、平和になったらもう一度くらいは観に行きたいですが.......公開期間中は難しそうですねえ

運動不足問題と体重の変化

体重

在宅勤務の話でよく言われる「運動不足で太る」問題
私の場合、体重は 1 か月ではそんなに変わらなかったです
2kg くらい減っていますが、この体重だと通常の増減範囲かと思います(先に書いた通り、ガッツリ外食が減ったことも関係しているかも)

f:id:kakkotetsu:20200331142332p:plain
1か月間の体重変化

運動

有酸素運動は全然やってないですが、なるべく歩くようにしました
リモートワークを始める前に「普段出社している日は大体 9500 歩程度」だからその辺を目標にしようと考えつつ、週末に近所を散歩してみてなかなか 9500 歩とか行かないなーとかやっていました

で、実際にやってみたらこんな感じです
平均 6300 歩くらいということで、まあまあ歩いてるじゃんって感覚

f:id:kakkotetsu:20200331142420p:plain
1か月の歩数

歩いたのは天気が良い日だけで、あまり歩数目標とかは決めずに義務感なくやってました 、太陽光を浴びて歩くの気持ちいい~っていう散歩感覚
朝、諸々の用事を済ませて仕事を始めるかな、って時にチョイと 20-30 分歩いてみる・昼休みに徒歩 5 分のスーパーマーケットに行くときにちょっと大回りして、20-40 分くらい歩いてみる... これらはとても良い気分転換になりました

この辺の測定には、有名どころですが Fitbit の腕時計型フィットネストラッカー(自分はやや型落ちの Charge2 というやつ、現時点の最新は Charge3 というやつ ↓ )を使ってます

元々、禁煙したことに伴う睡眠障害(連日の早朝覚醒)をどうにかすることを目的として、その一環で睡眠状態の測定をするために買ったものですが

移動距離と時間 (Google Map タイムラインより)

Google Map から月次でハイライトのメールが送られてきます
これで 3 月と 2 月を比較すると差は一目瞭然ですねー

f:id:kakkotetsu:20200407233844p:plain
2020/03 Google Map ハイライトより

f:id:kakkotetsu:20200407233919p:plain
2020/02 Google Map ハイライトより

最後に

発散した内容なので、まとめという程のことでもないですが

  • やはり出社は悪い文化
    • 通勤電車や賑やかなオフィス環境に起因するイライラがなくなりました 嬉しい
    • 世界が平和になった後も、 誰もが柔軟にリモートワークできる制度がある会社で働きたい... という思いを新たにしました
    • こうやってリモートワークに切り替えてそれについてあーだこーだと議論できるようになったのは、今回の騒動の数少ないメリットかなーと
  • 早く平和になってくれー
    • 元々宅内に引きこもってPCカタカタしているだけでも楽しめる人種ではあるのだけど...
      • この騒動の最中で、各社様色々なコンテンツを公開して下さっていますし (本当にありがとうございます)
        • それで派手にやらかしたところもあるけど
    • 外でやる趣味を封じられると結構しんどいのは確か
      • 普段書かないこんなポエムエントリを書いた、というのは精神に何らかの影響が出ていそう
    • とはいえ、 私個人でできることって、感染拡大を防ぐためにこういうリモートワーク/引きこもり生活を続けることなので、継続してやっていくます

ARISTA cEOS-lab で NETCONF を動かす (小ネタ)

小ネタです
twitter で「A社のnetconf動作確認失敗」「マニュアルでは記載あるのに使えない」「たぶん、旧バージョンでは使えていたけど新バージョンで廃止。でドキュメントはメンテしてないのパターンだろう」という噂を見かけたので、実際にどうなのか動かしてみます

結果から先に書くと、2020/03/23 時点でダウンロードできた最新の cEOS-lab 4.23.2F で最低限の動作(<get-config>)は動きました

事前情報

環境情報

ARISTA 公式の Software Download ページ からとってきた 2020/03/23 時点で最新版 の cEOS-lab

localhost>show ver
 cEOSLab
Hardware version:
Serial number:
System MAC address:  0242.ac11.3eb8

Software image version: 4.23.2F
Architecture:           i686
Internal build version: 4.23.2F-15405360.4232F
Internal build ID:      4cde5c53-3642-4934-8bcc-05691ffd79b3

cEOS tools version: 1.1

Uptime:                 7 weeks, 3 days, 4 hours and 33 minutes
Total memory:           2040924 kB
Free memory:            1282940 kB

上記の docker image を動かす母艦

$ cat /etc/os-release
NAME="Ubuntu"
VERSION="18.04.4 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04.4 LTS"
VERSION_ID="18.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic


$ uname -a
Linux testvm 4.15.0-76-generic #86-Ubuntu SMP Fri Jan 17 17:24:28 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux


$ docker --version
Docker version 19.03.8, build afacb8b7f0

動作確認

環境準備 (cEOS-lab deploy)

前述の cEOS-lab image ダウンロードページに手順のテキストも置いてあるので、その通りにやっただけです
後ほど、この母艦の外から NETCONF 接続をするので docker create 時に NETCONF のデフォルトTCPポートを突けるように -p 830:830 しておくのが今回の固有ポイント

$ ll
total 391128
drwxrwxr-x 2 kotetsu kotetsu      4096 Mar 23 07:11 ./
drwxrwxr-x 3 kotetsu kotetsu      4096 Mar 23 07:10 ../
-rw-rw-r-- 1 kotetsu kotetsu 400501512 Mar 23 07:11 cEOS-lab-4.23.2F.tar.xz
-rw-rw-r-- 1 kotetsu kotetsu       153 Mar 23 07:11 cEOS-lab-4.23.2F.tar.xz.sha512sum

$ sha512sum cEOS-lab-4.23.2F.tar.xz
40af1a1fa456bb0eb3b99aabddc1905614d032f84fb947070d1818e4cb48b9f655723effbdc03ed782b44461789d01a8935f775684086b28f32bfed65df9b94d  cEOS-lab-4.23.2F.tar.xz


$ docker import cEOS-lab-4.23.2F.tar.xz ceosimage:4.23.2F
sha256:3228be9a009f6931cd07f3867f3f2f5be288f440158412f980d1197fd699dac5

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED              SIZE
ceosimage           4.23.2F             3228be9a009f        About a minute ago   1.74GB


$ docker create --name=ceos1 --privileged -p 830:830 -e INTFTYPE=eth -e ETBA=1 -e SKIP_ZEROTOUCH_BARRIER_IN_SYSDBINIT=1 -e CEOS=1 -e EOS_PLATFORM=ceoslab -e container=docker -i -t ceosimage:4.23.2F /sbin/init systemd.setenv=INTFTYPE=eth systemd.setenv=ETBA=1 systemd.setenv=SKIP_ZEROTOUCH_BARRIER_IN_SYSDBINIT=1 systemd.setenv=CEOS=1 systemd.setenv=EOS_PLATFORM=ceoslab systemd.setenv=container=docker


$ docker network create net1
fb0cef09267bc7da25ef4394cd80f6333a8433942f8380568b57d15d041b08bf

$ docker network connect net1 ceos1

$ docker start ceos1
ceos1

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
28b52fc3fbde        ceosimage:4.23.2F   "/sbin/init systemd.窶ヲ"   2 minutes ago       Up 9 seconds        0.0.0.0:830->830/tcp   ceos1


$ docker exec -it ceos1 Cli
localhost>

NETCONF 有効化設定 at cEOS-lab

NETCONF で外部から突くために ユーザ作成して NETCONF 有効化

ARISTA EOS Central / OpenConfig 4.20.2.1F Release Notes / NETCONF Transport を参考に
(なお、このリリースノートが twitter 上では「マニュアルでは記載あるのに使えない」として画面キャプされてました)

localhost#conf t
localhost(config)#username kotetsu role network-admin secret kotetsu
localhost(config)#
localhost(config)#management api ?
  external-services  Configure the external(customer specific) web services on HTTP server
  gnmi               Configure GNMI
  gribi              Configure gRIBI
  http-commands      Configure the HTTP Commands API
  netconf            Configure NETCONF
  openconfig         Configure OpenConfig
  restconf           Configure RESTCONF

localhost(config)#management api netconf ?
  <cr>

localhost(config)#management api netconf
localhost(config-mgmt-api-netconf)#transport ?
  ssh  Configure SSH transport for NETCONF

localhost(config-mgmt-api-netconf)#transport ssh ?
  WORD  Transport name

localhost(config-mgmt-api-netconf)#transport ssh TEST-NETCONF ?
  WORD  Transport name
  <cr>

localhost(config-mgmt-api-netconf)#transport ssh TEST-NETCONF
localhost(config-netconf-transport-TEST-NETCONF)#end
localhost#
localhost#show management api netconf
Enabled:            Yes
Server:             running on port 830, in default VRF
localhost#show run
! Command: show running-config
! device: localhost (cEOSLab, EOS-4.23.2F)
!
transceiver qsfp default-mode 4x10G
!
agent Bfd shutdown
agent PowerManager shutdown
agent LedPolicy shutdown
agent Thermostat shutdown
agent PowerFuse shutdown
agent StandbyCpld shutdown
agent LicenseManager shutdown
!
spanning-tree mode mstp
!
no aaa root
!
username kotetsu role network-admin secret sha512 $6$Esck1TwFdZfKszo6$K54/xPLQguinpmY2q4S9IxOg1TZASNdnJYZzhs3FkUujs6uccGJbiYR6w.yOW/ML.G2CowJrFFoU7EtpCpmJe/
!
interface Ethernet1
!
no ip routing
!
management api netconf
   transport ssh TEST-NETCONF
!
end

動作確認 (via remote ssh)

とりあえず外部から ssh で突いてみると、hello メッセージで capability リストを教えてくれてきています
長いので途中で切ってますが...
ちな、ここで <rpc>...</rpc> とか貼っていけばやりとりできます

$ ssh -l kotetsu <docker母艦のIPアドレス> -p 830 -s netconf
<hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><capabilities><capability>urn:ietf:params:netconf:base:1.0</capability><capability>urn:ietf:params:netconf:base:1.1</capability><capability>urn:ietf:params:xml:ns:netconf:base:1.0</capability><capability>urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring</capability><capability>urn:ietf:params:netconf:capability:writable-running:1.0</capability><capability>urn:ietf:params:netconf:capability:candidate:1.0</capability><capability>http://arista.com/yang/openconfig/policy/augments?module=arista-rpol-augments&amp;revision=2018-04-12</capability><capability>http://arista.com/yang/openconfig/isis/deviations?module=arista-isis-deviations&amp;revision=2019-05-14</capability><capability>http://openconfig.net/yang/hercules/qos?module=openconfig-hercules-qos&amp;revision=2018-06-01</capability><capability>urn:ietf:params:xml:ns:yang:ietf-yang-types?module=ietf-yang-types&amp;revision=2013-07-15</capability><capability>http://openconfig.net/yang/openconfig-types?module=openconfig-types&amp;revision=2019-04-16</capability><capability>http://openconfig.net/yang/lacp?module=openconfig-lacp&amp;revision=2018-11-21</capability><capability>urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring?module=ietf-netconf-monitoring&amp;revision=2010-10-04</capability><capability>http://openconfig.net/yang/aft?module=openconfig-aft&amp;revision=2019-08-01</capability><capability>http://openconfig.net/yang/system/logging?module=openconfig-system-logging&amp;revision=2018-11-21</capability><capability>http://arista.com/yang/openconfig/acl/deviations?module=arista-acl-deviations&amp;revision=2019-06-17</capability><capability>http://openconfig.net/yang/ospf-types?module=openconfig-ospf-types&amp;revision=2018-11-21</capability><capability>http://openconfig.net/yang/interfaces/ip?module=openconfig-if-ip&amp;revision=2019-01-08</capability><capability>http://arista.com/yang/openconfig/relay-agent/deviations?module=arista-relay-agent-deviations&amp;revision=2016-11-21</capability><capability>http://openconfig.net/yang/platform/fan?module=openconfig-platform-fan&amp;revision=2018-11-21</capability><capability>urn:ietf:params:xml:ns:netconf:base:1.0?module=ietf-netconf&amp;revision=2011-06-01</capability><capability>http://openconfig.net/yang/routing-policy?module=openconfig-routing-policy&amp;revision=2018-11-21</capability><capability>http://openconfig.net/yang/network-instance-l3?module=openconfig-network-instance-l3&amp;revision=2018-11-21</capability><capability>http://openconfig.net/yang/vlan-types?module=openconfig-vlan-types&amp;revision=2019-01-31</capability><capability>http://arista.com/yang/openconfig/local-routing/deviations?module=arista-local-routing-deviations&amp;revision=2017-11-22</capability><capability>http://arista.com/yang/experimental/eos/eos-types?module=arista-eos-types&amp;revision=2016-10-14</capability><capability>http://openconfig.net/yang/system/terminal?module=openconfig-system-terminal&amp;revision=2018-11-21</capability>

...snip

動作確認 (via Python ncclient)

有名どころの NETCONF クライアントライブラリを使って <get-config> くらいまでは見ておきましょーか

以下のような NETCONF クライアント用の Python venv 環境を用意して

$ pip list --format=columns
Package       Version
------------- -------
bcrypt        3.1.7
cffi          1.14.0
cryptography  2.8
lxml          4.5.0
ncclient      0.6.7
paramiko      2.7.1
pip           9.0.1
pkg-resources 0.0.0
pycparser     2.20
PyNaCl        1.3.0
setuptools    39.0.1
six           1.14.0


$ python3 --version
Python 3.6.9

NETCONF で cEOS-lab に <get-config> して xml を標準出力するだけの簡易スクリプトを用意して

#!/usr/bin/env python3
from ncclient import manager
import xml.dom.minidom

with manager.connect(host='<docker母艦のIPアドレス>', port=830, username='kotetsu', password='kotetsu', hostkey_verify=False) as m:
    c = m.get_config(source='running').data_xml
    print(xml.dom.minidom.parseString(c).toprettyxml())
$ ./nc-test.py > result.log

Gist / ceos-lab_4.23.2F_netconf_get-config.xml にカットなしのモノは置きましたが、以下が出力の一部です

<?xml version="1.0" ?>
<data time-modified="2020-03-23T08:03:36.805590273Z" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
        <acl xmlns="http://openconfig.net/yang/acl"/>
        <arista xmlns="http://arista.com/yang/experimental/eos">
                <eos>
                        <bridging xmlns="http://arista.com/yang/experimental/igmpsnooping">
                                <igmpsnooping>
                                        <config/>
                                </igmpsnooping>
                        </bridging>
                        <mlag xmlns="urn:aristanetworks:yang:experimental:eos">
                                <config>
                                        <dual-primary-action>action-none</dual-primary-action>
                                        <enabled>true</enabled>
                                        <heartbeat-interval>4000</heartbeat-interval>
                                        <heartbeat-peer-address>
                                                <address>0.0.0.0</address>
                                                <vrf/>
                                        </heartbeat-peer-address>
                                        <lacp-standby>false</lacp-standby>
                                </config>
                        </mlag>
                        <qos xmlns="http://arista.com/yang/experimental/eos/qos">
                                <acl xmlns="http://arista.com/yang/experimental/eos/qos/acl">
                                        <input>
                                                <cli>


...snip


                                <input xmlns="http://arista.com/yang/experimental/eos/qos/config">
                                        <config>
                                                <cli>
                                                        <servicePolicyConfig>
                                                                <key-direction>input</key-direction>
                                                                <key-pmapName>copp-system-policy</key-pmapName>
                                                                <key-type>mapControlPlane</key-type>
                                                        </servicePolicyConfig>
                                                </cli>
                                        </config>
                                </input>
                        </qos>
                        <routing xmlns="http://arista.com/yang/experimental/multicast">
                                <multicast>
                                        <routeconfig>
                                                <static>
                                                        <vrfConfig>
                                                                <vrfName>default</vrfName>
                                                        </vrfConfig>
                                                </static>
                                        </routeconfig>
                                </multicast>
                        </routing>
                </eos>
        </arista>

...snip

        <interfaces xmlns="http://openconfig.net/yang/interfaces">
                <interface>
                        <name>Ethernet1</name>
                        <config>
                                <description/>
                                <enabled>true</enabled>
                                <load-interval xmlns="http://arista.com/yang/openconfig/interfaces/augments">300</load-interval>
                                <loopback-mode>false</loopback-mode>
                                <mtu>0</mtu>
                                <name>Ethernet1</name>
                                <tpid xmlns="http://openconfig.net/yang/vlan" xmlns:oc-vlan-types="http://openconfig.net/yang/vlan-types">oc-vlan-types:TPID_0X8100</tpid>
                                <type xmlns:ianaift="urn:ietf:params:xml:ns:yang:iana-if-type">ianaift:ethernetCsmacd</type>
                        </config>
                        <ethernet xmlns="http://openconfig.net/yang/interfaces/ethernet">
                                <config>
                                        <fec-encoding xmlns="http://arista.com/yang/openconfig/interfaces/augments">
                                                <disabled>false</disabled>
                                                <fire-code>false</fire-code>
                                                <reed-solomon>false</reed-solomon>
                                                <reed-solomon544>false</reed-solomon544>
                                        </fec-encoding>
                                        <forwarding-viable xmlns="http://openconfig.net/yang/hercules/interfaces">true</forwarding-viable>
                                        <mac-address>00:00:00:00:00:00</mac-address>
                                        <port-speed>SPEED_UNKNOWN</port-speed>
                                        <sfp-1000base-t xmlns="http://arista.com/yang/openconfig/interfaces/augments">false</sfp-1000base-t>
                                </config>
                        </ethernet>
                        <hold-time>
                                <config>
                                        <down>0</down>
                                        <up>0</up>
                                </config>
                        </hold-time>
                        <subinterfaces>
                                <subinterface>
                                        <index>0</index>
                                        <config>
                                                <description/>
                                                <enabled>true</enabled>
                                                <index>0</index>
                                        </config>
                                        <ipv4 xmlns="http://openconfig.net/yang/interfaces/ip">
                                                <config>
                                                        <dhcp-client>false</dhcp-client>
                                                        <enabled>false</enabled>
                                                        <mtu>1500</mtu>
                                                </config>
                                        </ipv4>
                                        <ipv6 xmlns="http://openconfig.net/yang/interfaces/ip">
                                                <config>
                                                        <dhcp-client>false</dhcp-client>
                                                        <dup-addr-detect-transmits>1</dup-addr-detect-transmits>
                                                        <enabled>false</enabled>
                                                        <mtu>1500</mtu>
                                                </config>
                                        </ipv6>
                                </subinterface>
                        </subinterfaces>

...snip

                </interface>
        </interfaces>

...snip

        <lldp xmlns="http://openconfig.net/yang/lldp">
                <config>
                        <enabled>true</enabled>
                        <hello-timer>30</hello-timer>
                        <management-address xmlns="http://arista.com/yang/openconfig/lldp/augments">
                                <interface/>
                                <network-instance>default</network-instance>
                                <transmit-mode>BEST</transmit-mode>
                        </management-address>
                </config>
                <interfaces>
                        <interface>
                                <name>Ethernet1</name>
                                <config>
                                        <enabled>true</enabled>
                                </config>
                        </interface>
                </interfaces>
        </lldp>

        </system>
</data>

おしまい

最低限の動作を見ただけですが、以下まとめ/所感

  • cEOS-lab 4.23.2F で NETCONF <get-config> までは動くことを確認できた
  • 実際に生で NETCONF を使う人がいるかどうかは知らんけど(ARISTA の API としては古くから eAPI という結構良い感じのがあるし )、ARISTA のマニュアル構造的には YANG, OpenConfig のサポートのために動くようにしているのかな...
  • こういうちょっとしたコントロール系動作だけなら cEOS-lab は軽くて良さげ

4-byte AS の SNMP MIB 対応状況 (201904)

やること

JANOG20(2007.07.12) / 4-byte AS の世界へようこそ のスライド 45 で以下のように書かれています。

MIB関連  
  
■現状,最新のMIBは,RFC4273:Definitions of  
  Managed Objects for BGP-4 )  
    □AS関係は,Inteter32 として規定されているが,  
      bgpLocalAs OBJECT-TYPE  
      SYNTAX Integer32 (0..65535)  
    なっており,改訂が必要.  
    □draft-ietf-idr-bgp4-mibv2 に取り込まれる方向  
    で議論が進行中  
      □が,現在,このドラフトはExpire状態  

この状況が 12 年経った 2019/04 になっても変わっていなかった、というのを思い知ったので、その調査(ほぼ机上)を書き残したメモです。
「2019 年にもなって SNMP についてウダウダ言ってんじゃないよ!」と殴りかかるのは止めて下さい。

調査のきっかけ

ある日、4-byte Private AS(4200000001) を設定したネットワークスイッチ(仮想)を弄っていて

$ snmpwalk -v 2c -c <COMMUNITY_STRING> tor000b .1.3.6.1.2.1.15 | more
BGP4-MIB::bgpVersion.0 = Hex-STRING: 10
BGP4-MIB::bgpLocalAs.0 = INTEGER: -94967295
BGP4-MIB::bgpIdentifier.0 = IpAddress: 172.31.0.1
BGP4-MIB::bgp4PathAttrPeer.172.16.0.0.16.172.30.128.1 = IpAddress: 172.30.128.1
BGP4-MIB::bgp4PathAttrPeer.172.16.0.0.16.172.30.128.3 = IpAddress: 172.30.128.3
BGP4-MIB::bgp4PathAttrPeer.172.16.0.0.16.172.30.128.5 = IpAddress: 172.30.128.5
BGP4-MIB::bgp4PathAttrPeer.172.17.0.0.16.172.30.128.1 = IpAddress: 172.30.128.1
BGP4-MIB::bgp4PathAttrPeer.172.17.0.0.16.172.30.128.3 = IpAddress: 172.30.128.3
BGP4-MIB::bgp4PathAttrPeer.172.17.0.0.16.172.30.128.5 = IpAddress: 172.30.128.5

...snip

BGP4-MIB を舐めていたら BGP4-MIB::bgpLocalAs.0 = INTEGER: -94967295 という Overflow に出くわしました。
別にこれを SNMP でとりたいという強い想いは全くないのですが。
4-byte AS に MIB が未対応なんだろなあ...、いや今 2019 年だぞ??って少し気になって調べることに。

調査

JANOG20(2007.07.12) スライド / 4-byte AS の世界へようこそ

まず雑にググっていたら冒頭のスライド JANOG20(2007.07.12) / 4-byte AS の世界へようこそ が目に入りました。
でも今 2019 だぞ??(しつこい)

RFC4273 Definitions of Managed Objects for BGP-4

最初に突いた BGP4-MIB の定義をしている RFC4273 / Definitions of Managed Objects for BGP-4 を参照しました。
これは RFC1657 / Definitions of Managed Objects for the Fourth Version of the Border Gateway Protocol (BGP-4) using SMIv2 を Obsoletes しているやつ。

        bgpLocalAs OBJECT-TYPE

            SYNTAX     Integer32 (0..65535)
            MAX-ACCESS read-only
            STATUS     current
            DESCRIPTION
                    "The local autonomous system number."
            REFERENCE
                     "RFC 4271, Section 4.2, 'My Autonomous System'."
            ::= { bgp 2 }

        -- BGP Peer table.  This table contains, one entry per
        -- BGP peer, information about the BGP peer.

Integer32 (0..65535)...のままなんですが!!!

draft-ietf-idr-bgp4-mibv2

冒頭のスライドでは「draft-ietf-idr-bgp4-mibv2 に取り込まれる方向で議論が進行中(が,現在,このドラフトはExpire状態)」と書かれていたもので、見に行ってみると...
Tracker / draft-ietf-idr-bgp4-mibv2 ...はい、確かに Expire 状態です。

draft-ietf-idr-bgp4-mibv2 / 7. Definitions で AS Number 周りの情報を見ると

BGP4V2-MIB DEFINITIONS ::= BEGIN

    IMPORTS

        MODULE-IDENTITY, OBJECT-TYPE, NOTIFICATION-TYPE,
        mib-2, Counter32, Gauge32, Unsigned32
            FROM SNMPv2-SMI
        InetAddressType, InetAddress, InetPortNumber,
        InetAutonomousSystemNumber, InetAddressPrefixLength
            FROM INET-ADDRESS-MIB

...snip

と、AS Number の型定義は INET-ADDRESS-MIB から引っ張ってきていて。
それが定義されている RFC4001 / Textual Conventions for Internet Network Addresses を見ると

InetAutonomousSystemNumber ::= TEXTUAL-CONVENTION
    DISPLAY-HINT "d"
    STATUS       current
    DESCRIPTION
        "Represents an autonomous system number that identifies an
         Autonomous System (AS).  An AS is a set of routers under a
         single technical administration, using an interior gateway
         protocol and common metrics to route packets within the AS,
         and using an exterior gateway protocol to route packets to
         other ASes'.  IANA maintains the AS number space and has
         delegated large parts to the regional registries.

         Autonomous system numbers are currently limited to 16 bits
         (0..65535).  There is, however, work in progress to enlarge the
         autonomous system number space to 32 bits.  Therefore, this
         textual convention uses an Unsigned32 value without a
         range restriction in order to support a larger autonomous
         system number space."
    REFERENCE   "RFC 1771, RFC 1930"
    SYNTAX       Unsigned32

これは将来的な拡張のために...という理由と共に Unsigned32 と定義されております。
なので draft-ietf-idr-bgp4-mibv2 に基づいた実装ならば、4-byte AS Welcome なんでしょー。

Network OS の Private MIB

いわゆる大手メーカ NW 機器では Private MIB でどうにかしてるんだろーなーってことで、軽く見てみます。

一例 Juniper

Juniper の場合には Private MIB の BGP4-V2-MIB-JUNIPER (mib-jnx-bgpmib2)

以下のように 4-byte AS を使えるように定義しています。
REFERENCE として draft-ietf-idr-as4bytes-04 ...のちの RFC6793 / BGP Support for Four-Octet Autonomous System (AS) Number Space を明言してます。

    jnxBgpM2AsSize OBJECT-TYPE
        SYNTAX     INTEGER {
            twoOctet(1),
            fourOctet(2)
        }
        MAX-ACCESS read-only
        STATUS     current
        DESCRIPTION
            "The size of the AS value in this implementation.

             The semantics of this are determined as per the
             as-4bytes draft."
        REFERENCE
            "draft-ietf-idr-as4bytes-04"
        ::= { jnxBgpM2BaseScalars 4 }


    jnxBgpM2LocalAs OBJECT-TYPE
        SYNTAX     InetAutonomousSystemNumber
        MAX-ACCESS read-only
        STATUS     current
        DESCRIPTION
            "The local autonomous system number.

             If the jnxBgpM2AsSize is twoOctet, then the range is
             constrained to be 0-65535."
        ::= { jnxBgpM2BaseScalars 5 }

一例 Arista

Arista の場合には Private MIB の ARISTA-BGP4V2-MIB で 4-byte AS を使えるように定義しています。

まず冒頭に extracted from draft-ietf-idr-bgp4-mibv2-13.txt (例の Expire しているやつで Author は Juniper の人) と書いてあります。

-- extracted from draft-ietf-idr-bgp4-mibv2-13.txt
-- at Tue Mar 13 06:12:27 2012

具体的に AS Number についての定義を見ると

ARISTA-BGP4V2-MIB DEFINITIONS ::= BEGIN

    IMPORTS
        MODULE-IDENTITY, OBJECT-TYPE, NOTIFICATION-TYPE,
        Counter32, Gauge32, Unsigned32
            FROM SNMPv2-SMI
        InetAddressType, InetAddress, InetPortNumber,
        InetAutonomousSystemNumber, InetAddressPrefixLength
            FROM INET-ADDRESS-MIB

...snip

    aristaBgp4V2PeerLocalAs OBJECT-TYPE
        SYNTAX     InetAutonomousSystemNumber
        MAX-ACCESS read-only
        STATUS     current
        DESCRIPTION
            "Some implementations of BGP can represent themselves
             as multiple ASes. This is the AS that this peering
             session is representing itself as to the remote peer."
        ::= { aristaBgp4V2PeerEntry 7 }

てな具合に AS 番号の定義は INET-ADDRESS-MIB から持ってきているよーで、
これは draft-ietf-idr-bgp4-mibv2 の項で追った通り RFC4001 / Textual Conventions for Internet Network Addresses にて Unsigned32 で定義されております。

一例 Cumulus Linux

Cumulus Linux / Supported MIBs を見ると、BGP 周りの Private MIB は無さそうです。

少し脇に反れますが Cumulus Linux / Enable SNMP Support for FRRouting を眺めると...

At this time, SNMP does not support monitoring BGP unnumbered neighbors.

ってことで「4-byte AS 番号を使って FRRouting 同士は Unnumberd 設定にして......」なんていうことをしようとすると、実質 SNMP は使えたもんじゃなさそうです。
実際冒頭で試した target は Cumulus VX だったのですが、確かに「Unnumberd な Peer 情報はとれず、Local AS Number は Overflow」って状況でした。

ちなみに Cumulus Linux の Community Slack でこの話をしたら、Cumulus Linux SE の人から以下のように返信が。うーーん、ごもっとも。

That is one of the problems with the BGP (and others) snmp MIBs that they don’t support new standards.
Personally I always advice to look at a different solution then SNMP.

OpenConfig YANG Model

現代の SNMP MIB と言っても過言ではない(貶しているわけじゃないです、念のため) OpenConfig の YANG Model だと openconfig-inet-types.yang / typedef as-number

  typedef as-number {
    type uint32;
    description
      "A numeric identifier for an autonomous system (AS). An AS is a
      single domain, under common administrative control, which forms
      a unit of routing policy. Autonomous systems can be assigned a
      2-byte identifier, or a 4-byte identifier which may have public
      or private scope. Private ASNs are assigned from dedicated
      ranges. Public ASNs are assigned from ranges allocated by IANA
      to the regional internet registries (RIRs).";
    reference
      "RFC 1930 Guidelines for creation, selection, and registration
                of an Autonomous System (AS)
       RFC 4271 A Border Gateway Protocol 4 (BGP-4)";
  }

はい、流石に 4-byte AS 対応しているっぽいですねー。

おしまい

  • SNMP MIB なんて、この件に限らずこんな感じですよねー
  • OpenConfig の YANG Model だって "Standard(?) + メーカの Private" っていう大枠の仕組みは一緒だし、同じようなことは起き(てい)る/起きていくんでしょうね...
  • ...2019年にもなって改めて語るような内容でもなかったわ(完)

Cumulus VX の HTTP API を弄る

はじめに

やること

Cumulus Linux にも HTTP API というリモートから HTTP/HTTPS でアクセスして情報取得・設定変更・メンテナンス操作が出来る API があります。
ザックリ言うと「HTTP リクエストの中に CLI コマンドを入れて投げつける」系のやつです(Arista EOS eAPI や Cisco NX-OS の NX-API CLI と同じノリ)。
そういう作りな分、クライアント側の実装方式は割と何でも使えるのは嬉しい。

Cumulus Linux を相手にした時、実際のところ

  • Ansible の各種 Linux 系 Modules (files, apt, systemd etc) による Linux 的な操作
  • Ansible の Cumulus Linux 専用 Modules (nclu) による Network OS 的な操作
    • Ansible 公式 / nclu module を参照 (Examples で雰囲気を察することができる)
    • 内容は CLI で使う net 系コマンド(NCLU) を使ってコマンドを叩き込む expect 的なやつ(雑)

で完結できそうなのですが、後者相当のことを API でもできますよ、って話です。
繰り返し・条件判定などを要するちょっとした処理を、使い慣れた言語で使い捨てスクリプトを作ってサクッと済ませたい(人によっては Ansible Playbook の構文に付き合うより楽な筈)というような時に使えそうです。

参考資料

これだけ

API Doc 的なやつは見つからず......。

環境情報

仮想版の Cumulus VX を使っております。
アカウントを作ればだれでも使える(2019/03/09 現在)やつで、使い方の公式リンクは 「Cumulus VX で VXLAN+EVPN (original : 2017/03/22) / 参考資料」あたりにも纏めているので、適宜ご参照下さいませ。

cumulus@tor000a:~$ net show system
Hostname......... tor000a

Build............ Cumulus Linux 3.7.3
Uptime........... 22 days, 21:36:43.650000

Model............ Cumulus VX
Memory........... 426MB
Disk............. 6GB
Vendor Name...... Cumulus Networks
Part Number...... 3.7.3
Base MAC Address. 0C:AA:FD:C7:3D:00
Serial Number.... 0c:aa:fd:c7:3d:00
Product Name..... VX


cumulus@tor000a:~$ cat /etc/os-release
NAME="Cumulus Linux"
VERSION_ID=3.7.3
VERSION="Cumulus Linux 3.7.3"
PRETTY_NAME="Cumulus Linux"
ID=cumulus-linux
ID_LIKE=debian
CPE_NAME=cpe:/o:cumulusnetworks:cumulus_linux:3.7.3
HOME_URL="http://www.cumulusnetworks.com/"
SUPPORT_URL="http://support.cumulusnetworks.com/"

API を突くクライアント側は...まー何でもいいですわ。

使う

事前処理 Cumulus Linux で機能有効化

Cumulus Linux 公式 / HTTP API に従ってやれば良し。

必要なパッケージは最初から入っていそうなので

cumulus@tor000a:~$ apt search python-cumulus-restapi
Sorting... Done
Full Text Search... Done
python-cumulus-restapi/updates,now 0.1-cl3u9 all [installed]
  Rest API for Cumulus Networks

必要なサービスを起動して (認証方式や待ち受けポートなどなどは、必要に応じて nginx の設定ファイルを弄る、ここではデフォルトのまま)

cumulus@tor000a:~$ systemctl status restserver
cumulus@tor000a:~$ sudo systemctl enable restserver
cumulus@tor000a:~$ sudo systemctl start restserver
cumulus@tor000a:~$ systemctl status restserver
cumulus@tor000a:~$ systemctl status nginx

これだけ。

試用

まずは公式ガイドを参考に available な endpoint 一覧を取得。
endpoint を見ても、何となく機能が限られていそうな雰囲気(BGP とかを動かしているのに routing protocol 関係などが全く見当たらない)しか......。

cumulus@tor000a:~$ curl -X GET -k -u cumulus:CumulusLinux! https://127.0.0.1:8080 | python -m json.tool
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   573  100   573    0     0  12220      0 --:--:-- --:--:-- --:--:-- 12456
{
    "endpoints": {
        "bridgeCmd": "/ml2/v1/bridge/{bridge_name}/{vlan_id}",
        "bridgeIntfCmd": "/ml2/v1/bridge/{bridge_name}/{vlan_id}/hosts/{host}",
        "bridgeVxlanCmd": "/ml2/v1/bridge/{bridge_name}/{vlan_id}/vxlan/{vni_id}",
        "hashCmd": "/ml2/v1/hash",
        "intfCmd": "/ml2/v1/networks/{network_id}/hosts/{host}",
        "main": "/",
        "networkCmd": "/ml2/v1/networks/{network_id}",
        "rpc": "/nclu/v1/rpc",
        "vxlanCmd": "/ml2/v1/networks/{network_id}/vxlan/{vni}"
    },
    "version": {
        "api_codename": "evo",
        "api_status": "GA",
        "api_version": "0.0.2",
        "documentation": "http://docs.cumulusnetworks.com"
    }
}

公式ガイドを参考に投げ込んでみると。
これは endpoint 的には /nclu/v1/rpc を使って CLI でいうところの net コマンドを包んで投げつけておきゃー大抵のこと出来るんだろうな、って察しました。
また、net コマンドでは json とつけると JUNOS の display json や EOS の | json みたいに JSON 形式で出力を得られたり得られなかったりします(全部得られるのか知らん)。

cumulus@tor000a:~$ curl -X POST -k -u cumulus:CumulusLinux! -H "Content-Type: application/json" -d '{"cmd": "show counters"}' https://127.0.0.1:8080/nclu/v1/rpc

Kernel Interface table
Iface      MTU    Met    RX_OK    RX_ERR    RX_DRP    RX_OVR    TX_OK    TX_ERR    TX_DRP    TX_OVR  Flg
-------  -----  -----  -------  --------  --------  --------  -------  --------  --------  --------  -----
eth0      1500      0   216222         0         0         0    84162         0         0         0  BMRU
lo       65536      0      131         0         0         0      131         0         0         0  LRU
swp1      9216      0   127045         0         0         0   158455         0         0         0  BMRU
swp2      9216      0   108224         0         0         0   155806         0         0         0  BMRU
swp3      9216      0   127772         0         0         0   157187         0         0         0  BMRU
swp8      9216      0    74970         0         2         0    79474         0         0         0  BMRU
swp9      9216      0    72022         0         5         0    72909         0         0         0  BMRU



cumulus@tor000a:~$ curl -X POST -k -u cumulus:CumulusLinux! -H "Content-Type: application/json" -d '{"cmd": "show counters json"}' https://127.0.0.1:8080/nclu/v1/rpc
{
    "eth0": {
        "Flg": "BMRU",
        "MTU": 1500,
        "Met": 0,
        "RX_DRP": 0,
        "RX_ERR": 0,
        "RX_OK": 216459,
        "RX_OVR": 0,
        "TX_DRP": 0,
        "TX_ERR": 0,
        "TX_OK": 84284,
        "TX_OVR": 0
    },
    "lo": {

...<snip>

設定変更系
雰囲気でやってますが、net pending は JUNOS でいうところの show | comparenet commitcommit みたいなもんです、多分。

cumulus@tor000a:/home/kotetsu$ curl -X POST -k -u cumulus:CumulusLinux! -H "Content-Type: application/json" -d '{"cmd": "add time ntp server 10.0.0.64 iburst"}' https://127.0.0.1:8080/nclu/v1/rpc



cumulus@tor000a:/home/kotetsu$ curl -X POST -k -u cumulus:CumulusLinux! -H "Content-Type: application/json" -d '{"cmd": "pending"}' https://127.0.0.1:8080/nclu/v1/rpc
--- /etc/ntp.conf       2018-09-05 14:20:56.000000000 +0900
+++ /run/nclu/ntp/ntp.conf      2019-03-09 20:31:28.736733340 +0900
@@ -53,10 +53,11 @@
 #broadcast 192.168.123.255

 # If you want to listen to time broadcasts on your local subnet, de-comment the
 # next lines.  Please do this only if you trust everybody on the network!
 #disable auth
 #broadcastclient

 # Specify interfaces, don't listen on switch ports
 interface listen eth0

+server 10.0.0.64 iburst


net add/del commands since the last "net commit"
================================================

User     Timestamp                   Command
-------  --------------------------  ----------------------------------------
cumulus  2019-03-09 20:31:28.738095  net add time ntp server 10.0.0.64 iburst




cumulus@tor000a:/home/kotetsu$ curl -X POST -k -u cumulus:CumulusLinux! -H "Content-Type: application/json" -d '{"cmd": "commit"}' https://127.0.0.1:8080/nclu/v1/rpc
--- /etc/ntp.conf       2018-09-05 14:20:56.000000000 +0900
+++ /run/nclu/ntp/ntp.conf      2019-03-09 20:31:28.736733340 +0900
@@ -53,10 +53,11 @@
 #broadcast 192.168.123.255

 # If you want to listen to time broadcasts on your local subnet, de-comment the
 # next lines.  Please do this only if you trust everybody on the network!
 #disable auth
 #broadcastclient

 # Specify interfaces, don't listen on switch ports
 interface listen eth0

+server 10.0.0.64 iburst


net add/del commands since the last "net commit"
================================================

User     Timestamp                   Command
-------  --------------------------  ----------------------------------------
cumulus  2019-03-09 20:31:28.738095  net add time ntp server 10.0.0.64 iburst



cumulus@tor000a:/home/kotetsu$ curl -X POST -k -u cumulus:CumulusLinux! -H "Content-Type: application/json" -d '{"cmd": "pending"}' https://127.0.0.1:8080/nclu/v1/rpc
cumulus@tor000a:/home/kotetsu$

Cumulus Linux ローカルで突いていますが、remote からも勿論突けます。

$ curl --noproxy "*" -X POST -k -u cumulus:CumulusLinux! -H "Content-Type: application/json" -d '{"cmd": "show counters json"}' https://tor000a:8080/nclu/v1/rpc
{
    "eth0": {
        "Flg": "BMRU",
        "MTU": 1500,
        "Met": 0,
        "RX_DRP": 0,
        "RX_ERR": 0,
        "RX_OK": 223026,
        "RX_OVR": 0,
        "TX_DRP": 0,
        "TX_ERR": 0,
        "TX_OK": 85717,
        "TX_OVR": 0
    },

...<snip>

公式ガイドの最後に申し訳程度に載っていたサンプルをそのまま実行して /nclu/v1/rpc 以外の endpoint への PUT なんかも一応動くみたいだとはわかりましたが......。
いかんせんガイドもないので、何も分からん。
いわゆる普通の REST API っぽい雰囲気は醸し出しておりますが...。

cumulus@tor000a:~$ curl -X PUT -k -u cumulus:CumulusLinux!  https://127.0.0.1:8080/ml2/v1/bridge/"br1"/200
""


cumulus@tor000a:~$ ip l sh br1
12: br1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN mode DEFAULT group default
    link/ether f6:81:d1:12:75:fa brd ff:ff:ff:ff:ff:ff


cumulus@tor000a:~$ bridge -d vlan
port    vlan ids
br1      200

まあ /etc/network/interfaces に書き込まれちゃいないので、再起動すりゃー消えるんですが。

サンプルスクリプト

適当なサンプルとして以下のような処理をしてみます。

  • 対象機器の BGP Neighbor を走査して
  • 以下の全ての条件に合致する Neighbor だった場合は
    • Local の Peer-Group が PG_SPINE である
    • Remote の hostname が正規表現で "a$" に match しない (Remote の hostname capability が動いている前提)
  • BGP clear する

......あんまり実用的ではない気はしますが、繰り返し処理や条件処理をして Ansible で書くのに僕が面倒くささを感じるあたり、を例示したものです。
言語的には HTTP リクエストと Response の JSON 構造パースあたりがあれば何でも良いので、好きなもの使えるよって言いたいだけ。(shell + curl + jq 程度でも)
ちなみに、あんまりシンプルだからか Cumulus Networks の Github リポジトリ を探してもラッパライブラリは見つからなかったです。

例示環境の対象 BGP 設定ですが、以下が /etc/frr/frr.conf より抜粋です。

interface swp1
 description DEV=node1 IF=ens4
!
interface swp2
 description DEV=node2 IF=ens4
!
interface swp3
 description DEV=node3 IF=ens4
!
interface swp8
 description DEV=spine000a IF=swp1
!
router bgp 4200000000
 bgp router-id 172.31.0.0
 bgp bestpath as-path multipath-relax
 bgp bestpath compare-routerid
 neighbor PG_K8S peer-group
 neighbor PG_K8S remote-as external
 neighbor PG_K8S description k8s-node
 neighbor PG_SPINE peer-group
 neighbor PG_SPINE remote-as external
 neighbor PG_SPINE description tor
 neighbor swp1 interface peer-group PG_K8S
 neighbor swp2 interface peer-group PG_K8S
 neighbor swp3 interface peer-group PG_K8S
 neighbor swp8 interface peer-group PG_SPINE
 neighbor swp9 interface peer-group PG_SPINE
 !
 address-family ipv4 unicast
  redistribute connected
 exit-address-family
!

んで、さっきの処理を今回は Ruby で書きました。
例によって、例外処理とかは適当な即席なやつで。

# encoding: utf-8

require 'rest-client'
require 'optparse'
require 'json'
require 'pp'


def exec_nclu(params, cmd)

  uri = "https://#{params[:target]}:8080/nclu/v1/rpc"
  payload = {
    'cmd': cmd
  }
  headers = {content_type: 'application/json'}

  response = RestClient::Request.execute(
    :url => uri,
    :user => params[:username],
    :password => params[:password],
    :method => :post,
    :headers => headers,
    :verify_ssl => false,
    :payload => payload.to_json
  )

  case response.code
  when 200
    return JSON.parse(response) rescue ""
  else
    p response.code
    return nil
  end

end




#
# ARGV check
#

# set default params
arg_configs = {
  #:username => ENV['CUMULUS_USER'],
  #:password => ENV['CUMULUS_PASS']
}

# required ARGV
arg_required = [
  :target,
  :username,
  :password
]

# parse ARGV
OptionParser.new do |opts|
  begin
    opts = OptionParser.new
    opts.on('-t', '--target STRING',  "reaquired param. IP address or FQDN of Cumulus.") { |v| arg_configs[:target] = v }
    opts.on('-u', '--username STRING', "username of Cumulus.") { |v| arg_configs[:username] = v }
    opts.on('-p', '--password STRING',  "password of Cumulus.") { |v| arg_configs[:password] = v }

    opts.parse!(ARGV)

    for field in arg_required
      raise ArgumentError.new("recuired param #{field} is not set...") if arg_configs[field].nil?
    end

  rescue => e
    puts opts.help
    puts
    puts e.message
    exit 1
  end

end


#
# main
#
begin

  # clean proxy env if I need
  ["http_proxy", "https_proxy", "HTTP_PROXY", "HTTPS_PROXY"].each do |environment|
    ENV.delete(environment)
  end


  bgp_nei = exec_nclu(arg_configs, "show bgp neighbor json")
  exit if bgp_nei.nil?
  pp bgp_nei # for debug

  # key : value (portname : BGP Nei status)
  bgp_nei.each do |port,value|
    if value["peerGroup"] != "PG_SPINE" then
      puts "#{port} BGP peerGroup : #{value["peerGroup"]} good bye."
      next
    end

    puts "#{port} BGP peerGroup : #{value["peerGroup"]}"
    if value["hostname"] =~ Regexp.new("a$")  then
      puts "#{port} BGP Remote Hostname : #{value["hostname"]} is system A,  good bye."
      next
    end
    puts "#{port} BGP Remote Hostname : #{value["hostname"]} , OK, Let's clear!!"

    clear_bgp = exec_nclu(arg_configs, "clear bgp #{port}")
    puts "#{port} BGP Remote Hostname : #{value["hostname"]}, executed clear!!" if clear_bgp == ""
  end


rescue Exception=>e
  puts e
  puts e.backtrace
  puts "\n\n!! Oh!! Exception!!\n\n"
end

んで、これを実行すると

$ bundle exec ruby cumulus.rb -t tor000a -u cumulus -p CumulusLinux!
{"swp1"=>
  {"bgpNeighborAddr"=>"172.30.0.1",
   "remoteAs"=>4290000001,
   "localAs"=>4200000000,
   "nbrExternalLink"=>true,
   "peerGroup"=>"PG_K8S",
   "bgpVersion"=>4,
   "remoteRouterId"=>"172.16.37.60",
   "bgpState"=>"Established",
   "bgpTimerUp"=>8561000,
   "bgpTimerUpMsec"=>8561000,
   "bgpTimerUpString"=>"02:22:41",
   "bgpTimerUpEstablishedEpoch"=>1552010935,
   "bgpTimerLastRead"=>1000,
   "bgpTimerLastWrite"=>1000,
   "bgpInUpdateElapsedTimeMsecs"=>8561000,
   "bgpTimerHoldTimeMsecs"=>9000,
   "bgpTimerKeepAliveIntervalMsecs"=>3000,
   "neighborCapabilities"=>
    {"4byteAs"=>"advertisedAndReceived",
     "addPath"=>
      {"IPv4 Unicast"=>{"txReceived"=>true, "rxAdvertisedAndReceived"=>true}},
     "routeRefresh"=>"advertisedAndReceivedNew",
     "multiprotocolExtensions"=>
      {"IPv4 Unicast"=>{"advertisedAndReceived"=>true}},
     "hostName"=>{"advHostName"=>"tor000a", "advDomainName"=>"n/a"},
     "gracefulRestart"=>"advertisedAndReceived",
     "gracefulRestartRemoteTimerMsecs"=>120000,
     "addressFamiliesByPeer"=>{"IPv4 Unicast"=>{}}},
   "gracefulRestartInfo"=>
    {"endOfRibSend"=>{"IPv4 Unicast"=>true},
     "endOfRibRecv"=>{"IPv4 Unicast"=>true}},

...<snip>

 "swp9"=>
  {"bgpNeighborAddr"=>"fe80::eaa:fdff:fe52:8e01",
   "remoteAs"=>4210000001,
   "localAs"=>4200000000,
   "nbrExternalLink"=>true,
   "hostname"=>"spine000b",
   "peerGroup"=>"PG_SPINE",
   "bgpVersion"=>4,
   "remoteRouterId"=>"172.31.1.1",
   "bgpState"=>"Established",
   "bgpTimerUp"=>31000,
   "bgpTimerUpMsec"=>31000,
   "bgpTimerUpString"=>"00:00:31",
   "bgpTimerUpEstablishedEpoch"=>1552019465,
   "bgpTimerLastRead"=>1000,
   "bgpTimerLastWrite"=>1000,
   "bgpInUpdateElapsedTimeMsecs"=>29000,
   "bgpTimerHoldTimeMsecs"=>9000,
   "bgpTimerKeepAliveIntervalMsecs"=>3000,
   "neighborCapabilities"=>
    {"4byteAs"=>"advertisedAndReceived",
     "addPath"=>{"IPv4 Unicast"=>{"rxAdvertisedAndReceived"=>true}},
     "extendedNexthop"=>"advertisedAndReceived",
     "extendedNexthopFamililesByPeer"=>{"IPv4 Unicast"=>"recieved"},
     "routeRefresh"=>"advertisedAndReceivedOldNew",
     "multiprotocolExtensions"=>
      {"IPv4 Unicast"=>{"advertisedAndReceived"=>true}},
     "hostName"=>
      {"advHostName"=>"tor000a",
       "advDomainName"=>"n/a",
       "rcvHostName"=>"spine000b",
       "rcvDomainName"=>"n/a"},
     "gracefulRestart"=>"advertisedAndReceived",
     "gracefulRestartRemoteTimerMsecs"=>120000,
     "addressFamiliesByPeer"=>"none"},
   "gracefulRestartInfo"=>
    {"endOfRibSend"=>{"IPv4 Unicast"=>true},
     "endOfRibRecv"=>{"IPv4 Unicast"=>true}},

...<snip>

swp1 BGP peerGroup : PG_K8S good bye.
swp2 BGP peerGroup : PG_K8S good bye.
swp3 BGP peerGroup : PG_K8S good bye.
swp8 BGP peerGroup : PG_SPINE
swp8 BGP Remote Hostname : spine000a is system A,  good bye.
swp9 BGP peerGroup : PG_SPINE
swp9 BGP Remote Hostname : spine000b , OK, Let's clear!!
swp9 BGP Remote Hostname : spine000b, executed clear!!

とまあ、条件に合致した swp9 の Neighbor だけが BGP clear されましたとさ。めでたしめでたし。

おしまい

Cumulus Linux って名前からして「設定ファイルを書き換えて systemctl で操作!Linux と同じ管理ツールが使えて嬉しいな!!!以上!!」って感じかと勝手に思っていたんですが、こんな風にネットワーク屋さん向けなユルフワ(失礼)な API もあったんですねえ。
そんなわけで、今回は排他処理がどうこうとか面倒なことは一切していないユルフワな「やってみた」系の内容でした。

Arista + Openconfigbeat で試す OpenConfig gNMI ベース Telemetry

はじめに

やること

個人でもサクッと入手できる実装が整ってきている感じなので、軽く試してみます。
これまでは gRPC server 側に追加パッケージが必要かつ個人アカウントでは取得できない、とか gRPC client の実装が大変(& 個人で実装している特定 NOS 向け野良とか、メーカが出している自社 NOS 専用のはあったけど)とかで手を出しにくかったんですが、今やそんなこともなさそーだという。

以下やること概要

  • OpenConfig の Telemety 動作を試す
    • gNMI (gRPC Network Management Interface) ベースで動かす
    • gRPC client (collector) 側
      • Arista の Openconfigbeat という OpenConfig 準拠(っぽい)ものを使う
        • Elastic の Beats というフレームワークで実装されているので、Elasticsearch / Kibana との連携が楽
      • gRPC server に subscribe して streaming push を受け取り、Elasticsearch にデータを叩き込む
    • gRPC server 側
      • Arista vEOS
        • OpenConfig gNMI ベースで動かすのが手っ取り早そう & openconfigbeat のテストにはきっと EOS を使っているに違いない(Inteoperability でハマりにくそう)と推測したから
    • データ保持・視覚
      • Elasticsearch + Kibana
        • Beats ベースな openconfigbeat と組み合わせて使うのに、一番手っ取り早かったから

参考資料

環境情報

Arista EOS 側

いつも通りの vEOS-lab

vEOS01#show ver
Arista vEOS
Hardware version:
Serial number:
System MAC address:  0c00.da26.7071

Software image version: 4.20.1F
Architecture:           i386
Internal build version: 4.20.1F-6820520.4201F
Internal build ID:      790a11e8-5aaf-4be7-a11a-e61795d05b91

Uptime:                 21 minutes
Total memory:           2017260 kB
Free memory:            1232576 kB

Openconfigbeat 側

$ cat /etc/os-release
NAME="Ubuntu"
VERSION="18.04 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04 LTS"
VERSION_ID="18.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic

$ uname -a
Linux ocb 4.15.0-23-generic #25-Ubuntu SMP Wed May 23 18:02:16 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

Openconfigbeat をビルドするのに go と glide が必要です(が GitHub にビルド済のファイルもあるし、Docker でも動くようなので、動かし方によっては必要ない)

$ go version
go version go1.10.1 linux/amd64

$ glide --version
glide version 0.13.1-3

とってきた Openconfigbeat は以下

$ git show
commit 32d071a8bdaf7f7f2b3aa8e504d171c888a14113 (HEAD -> master, origin/master, origin/HEAD)
Author: Giuseppe Valente <gvalente@arista.com>
Date:   Wed Mar 14 12:21:13 2018 -0700

    docker: download latest release

    Change-Id: I3015b84b6f438bba8ddb884e2f332fad4f5e16e1

Elasticsearch + Kibana 環境

Elasticsearch と Kibana は docker でテキトーに動かします。母艦のサーバとしては、Openconfigbeat と相乗りです。

$ docker --version
Docker version 18.03.1-ce, build 9ee9f40

$ docker-compose --version
docker-compose version 1.21.2, build a133471

Elasticsearch も Kibana も 6.2.4

$ docker ps
CONTAINER ID        IMAGE                                                 COMMAND                  CREATED             STATUS              PORTS                              NAMES
99fc3355e3b6        docker.elastic.co/kibana/kibana:6.2.4                 "/bin/bash /usr/loca…"   4 days ago          Up 4 days           0.0.0.0:5601->5601/tcp             kibana
69663eaabc79        docker.elastic.co/elasticsearch/elasticsearch:6.2.4   "/usr/local/bin/dock…"   4 days ago          Up 4 days           0.0.0.0:9200->9200/tcp, 9300/tcp   elasticsearch

$ curl -XGET 'http://localhost:9200'
{
  "name" : "r5cOGL4",
  "cluster_name" : "docker-cluster",
  "cluster_uuid" : "wMLRO2rxT0aUX2WrcybkSw",
  "version" : {
    "number" : "6.2.4",
    "build_hash" : "ccec39f",
    "build_date" : "2018-04-12T20:37:28.497551Z",
    "build_snapshot" : false,
    "lucene_version" : "7.2.1",
    "minimum_wire_compatibility_version" : "5.6.0",
    "minimum_index_compatibility_version" : "5.0.0"
  },
  "tagline" : "You Know, for Search"
}

動かす

Elasticsearch + Kibana 環境 構築

今回は openconfigbeat と同じサーバ上で virtualenv で動かしている docker-compose を使って立ち上げました。以下が使った docker-compose.yml

version: '3'
services:
  elasticsearch:
    container_name: elasticsearch
    image: docker.elastic.co/elasticsearch/elasticsearch:6.2.4
    environment:
      - cluster.name=docker-cluster
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - esdata1:/usr/share/elasticsearch/data
    ports:
      - 9200:9200
  kibana:
    container_name: kibana
    image: docker.elastic.co/kibana/kibana:6.2.4
    ports:
      - 5601:5601
    environment:
      SERVER_NAME: ocb
      ELASTICSEARCH_URL: http://<母艦のIPアドレス>:9200

volumes:
  esdata1:
    driver: local

vEOS 側

ARISTA EOS Central / OpenConfig 4.20.2.1F Release Notes を参考に gNMI ベースで動かす設定を入れるだけです。

vEOS01(config)#management api gnmi
vEOS01(config-mgmt-api-gnmi)#transport grpc ?
  WORD  transport name
vEOS01(config-mgmt-api-gnmi)#transport grpc TEST-vEOS01


vEOS01#bash
[kotetsu@vEOS01 ~]$
[kotetsu@vEOS01 ~]$ ss -natu | grep 6030
tcp    LISTEN     0      1024     :::6030                 :::*

これで Openconfigbeat (gRPC client)からの Subscribe 要求を受ける server 動作をしている筈。
なお、Openconfigbeat 側からの user / password 認証を受けられるように、アカウントは作っておきます(ssh とかして設定している時点で、それは済んでいる筈...)。

ちなみに、プロセスやらログやらを眺めていると vEOS 上で動く server 実装も Go みたいです。今まで vEOS 上で動くもろもろって Python ばかりだった気がしますが。

Openconfigbeat 側

ビルド環境準備

前述の通り GitHub にビルド済のファイルもあるし、Docker でも動くようなので、動かし方によっては必要ないですが。今回はビルドからやっていきます。
まずは Openconfigbeat をビルドするための requirements に入っている go と glide をば。以下を参考にパパッと。

$ sudo apt install -y software-properties-common
$ sudo add-apt-repository ppa:gophers/archive
$ sudo apt install -y golang-1.10-go
$ echo "export PATH=$PATH:/usr/lib/go-1.10/bin/" | sudo tee /etc/profile.d/golang.sh

$ sudo apt install -y golang-glide

本筋ではないですが、久々に glide を使ったら前述の glide README に以下の表記が...。

The Go community now has the dep project to manage dependencies. Please consider trying to migrate from Glide to dep. If there is an issue preventing you from migrating please file an issue with dep so the problem can be corrected. Glide will continue to be supported for some time but is considered to be in a state of support rather than active feature development.

設定作成~ビルド

まずは GitHub から clone してきて

$ mkdir -p /home/kotetsu/go/src/github.com/aristanetwork
$ cd /home/kotetsu/go/src/github.com/aristanetworks/
$ git clone https://github.com/aristanetworks/openconfigbeat.git
$ cd openconfigbeat/

<git clone してきた dir>/_meta/beat.yml が設定ファイルなので、必要な情報を書き換えます。

$ more ~/go/src/github.com/aristanetworks/openconfigbeat/_meta/beat.yml
################### Openconfigbeat Configuration Example #########################

############################# Openconfigbeat ######################################

openconfigbeat:

  # The addresses of the OpenConfig devices to connect to.
  addresses: ["10.0.0.171"]

  # The OpenConfig paths to subscribe to.
  paths: ["/"]

  # The default port to connect to if none is configured.
  default_port: 6030

  # The username on the device.
  username: "kotetsu"

  # The password for the user on the device.
  password: "kotetsu"

上の例だと、以下の感じ。

  • openconfigbeat
    • gRPC server の情報
    • addresses
      • vEOS の IP アドレスを配列で書き連ねる
    • paths
      • suvscribe するツリーの指定
      • / にしておけば、とれるもんは全部送ってもらえるようになる筈
    • default_port
      • vEOS 側で設定変更していないデフォルトなら 6030
    • usernamepassword
      • vEOS のアカウント情報

また <git clone してきた dir>/openconfigbeat.ymlデフォルト値っぽいのが定義されているので そこに定義されている output.elasticsearch: hosts: ["localhost:9200"] は明示的に指定しておりません。(今回は Kibana も Openconfigbeat とサーバ相乗りしているので)

何も指定せずに <git clone してきた dir>/make すればビルドされて openconfigbeat というファイルが出来ます。

$ make
$ file openconfigbeat
openconfigbeat: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=33438dfebfda1d7a42d3a0ad3db140fbf8b47ff8, stripped
$ chmod go-w openconfigbeat.yml

Usage

$ ~/go/src/github.com/aristanetworks/openconfigbeat/openconfigbeat -h
Usage:
  openconfigbeat [flags]
  openconfigbeat [command]

Available Commands:
  export      Export current config or index template
  help        Help about any command
  keystore    Manage secrets keystore
  run         Run openconfigbeat
  setup       Setup index template, dashboards and ML jobs
  test        Test config
  version     Show current version info

Flags:
  -E, --E setting=value      Configuration overwrite
  -N, --N                    Disable actual publishing for testing
  -c, --c string             Configuration file, relative to path.config (default "openconfigbeat.yml")
      --cpuprofile string    Write cpu profile to file
  -d, --d string             Enable certain debug selectors
  -e, --e                    Log to stderr and disable syslog/file output
  -h, --help                 help for openconfigbeat
      --httpprof string      Start pprof http server
      --memprofile string    Write memory profile to this file
      --path.config string   Configuration path
      --path.data string     Data path
      --path.home string     Home path
      --path.logs string     Logs path
      --plugin pluginList    Load additional plugins
      --setup                Load the sample Kibana dashboards
      --strict.perms         Strict permission checking on config files (default true)
  -v, --v                    Log at INFO level

Use "openconfigbeat [command] --help" for more information about a command.

以下で設定確認

$ ~/go/src/github.com/aristanetworks/openconfigbeat/openconfigbeat export config
openconfigbeat:
  addresses:
  - localhost
  default_port: 6042
  paths:
  - /
output:
  elasticsearch:
    hosts:
    - localhost:9200
path:
  config: /home/kotetsu/go/src/github.com/aristanetworks/openconfigbeat
  data: /home/kotetsu/go/src/github.com/aristanetworks/openconfigbeat/data
  home: /home/kotetsu/go/src/github.com/aristanetworks/openconfigbeat
  logs: /home/kotetsu/go/src/github.com/aristanetworks/openconfigbeat/logs
setup:
  kibana: null

起動

先ほどビルドしたものを実行して、起動します。以下のようにやれば、フォアグラウンド動作・stdout に PUSH されてきた情報など垂れ流されます。

$ ./openconfigbeat -e -d openconfigbeat.go

様子を見る

ここからは Kibana で様子を見ていきます。

設定空っぽの Kibana の WebUI にアクセスすると「はよ Index 作れ」と促されるので、言われるがままに Openconfigbeat が投げ込んでくるやつ用の Index Pattern を作っておきます。

f:id:kakkotetsu:20180722220910p:plain

そうすると、Discover のところでデータがズラズラと出てくるので

f:id:kakkotetsu:20180722220853p:plain

ポチポチと様子見用の search とか Visualize とか Dashboard を作りました。今回は「vEOS の特定物理インターフェースを流れる in-octets と in-unicast-pkts (累計)」を。
何で累計かというと、Kibana で Timelion とか使って bps なり pps の算出設定をするのが面倒くさかったからです。(個人的に、その手の設定は Grafana の方がなんぼか楽)

で、平常時は LLDP と BGP KeepAlive くらいしか流れていない当該物理インターフェースに、13s 程度だけトラフィックを流してみると

f:id:kakkotetsu:20180722220928p:plain

16:06:02 - 16:06:15 くらいの間だけ、vEOS 側がインターフェースカウンタの上昇に合わせて 1s 間隔程度で push してきてくれている様子が見て取れました。(グラフの丸部分の間隔がその時だけ狭まっている)

おしまい

ダラダラと所感を。

  • gNMI と YANG に準拠してくれている(っぽい) OpenConfigbeat ならば、それに準拠している NOS ならば一元的に collector 動作してくれそうな匂いを感じとった
    • 何せ vEOS しか試せていないので...
  • Elastic の Beats というフレームワークは(自分で実装したわけじゃないけど)、fluentd プラグインと同じように使えそう
    • Ruby より Go が良いとか、fluentd のバージョン対応どうしようとか、そういう開発者には良いのかも
  • Telemetry でよく言われる「バーストトラフィック検知」は Openconfig ベースなものでも実現できそうな気がする
  • 2018/07/22 時点の感触としては、データモデルが YANG 準拠な分、メーカ独自に自分たちの NOS 向けに作りこんでいる仕組みには取得できる情報観点では及ばなさそう
    • 一例として、以前試した 「Nexus9000v で Telemetry」 だと Cisco 独自のデータモデルを使っているので、結構細かい情報も取れていた
  • 目的がハッキリしているならば、現時点でもそれなりに使えそうな感はある
    • 例えば「SNMP Get や API での監視で 1-5 min 間隔なインターフェースカウンタや細かいデータ(NOS や HW に応じた監視項目や設定に応じた table 情報)を取得し、xflow で通信内容の傾向をつかめるようにはなっている」「が、バーストトラフィックの検知ができていないからそこを何とかしたい」というような場合、こういうのがピッタリと嵌りそう
    • 逆に、何もかもこの仕組みで賄おうとするのは(当面は)夢見すぎ感ある

ThousandEyes で NW 装置 monitoring を Free Try

はじめに

やること

ShowNet 2018 で「ネットワーク可視化 SaaS」として使われていた ThousandEyes を試用します(Free Try で)。
見る機能は「SNMP 対応 NW 装置から情報収集してインターネット経由で SaaS 環境に投げ込む probe 的な Enterprise Agents を動かして様子を見る(Devices 機能)」部分に絞ります。ザッと公式ページを見た感じ、本機能はオマケっぽいですが。

こんなんが見えるところまで。

f:id:kakkotetsu:20180617232453p:plain

構成概要・環境情報

以下の通りです。

  • 宅内
    • KVM+GNS3 上で以下を動かす
      • ThousandEyes の Enterprise Agents
        • 物理 NW では NAPT で The Internet に到達可能になっている
        • こいつ自体では The Internet に到達する為のネットワーク設定をするくらいで、ほとんど弄ることはない
        • こいつが SNMP manager になるので、以下の収集対象 NW 装置と疎通可能にしておくこと
      • 収集対象 NW 装置
        • 今回は Arista の vEOS-lab を使っているが、SNMP と LLDP が動けば何でも良い筈
  • SaaS 環境のダッシュボード
    • 設定や参照は全てここでやる
    • The Internet

今回物理装置や KVM+GNS3 部分の構築には触れません。Enterprise AgentsESXi とかベアメタルサーバとか Docker とかでも動くので、そこの動かし方はやりやすいようにやれば良かろうかと。
Cisco IOS XEJuniper NFX 上の専用コンテナとかもあるみたいですが、今回弄ってないです。

参考資料

  • ThousandEyes 公式
    • top
      • Try It Free というボタンがデカデカとあるので、ありがたく使わせて頂く
    • Pricing
      • 今回試用するフリー版で出来ること、課金すると出来ること、が並んでいる
      • Devices 機能観点では、課金することでカスタム MIB を使ってより多くの情報を収集可能になりそう
    • Knowledge Base
      • マニュアル
  • その他紹介記事など

動かす

環境準備

ThousandEye Free Try 登録

まずは ThousandEyes 公式Try It Free を押して、ユーザ登録します。2018/06/17 現在、個人ユーザ + Web メールでも弾かれたりせず。

f:id:kakkotetsu:20180617232412p:plain

メールが来るので、レジスター用のリンクから本登録しておわり。
公式ページ上の Login リンクからダッシュボードに飛べます。

ThousandEye Enterprise Agents 取得 ~ GNS3にインポートして起動 ~ 初期設定

probe として動く Enterprise Agents のイメージは、ダッシュボードで SETTINGS -> Agents -> Enterprise Agents と進めばダウンロードできます。
今回は Virtual Appliance を選択して OVA を頂いてきました。

f:id:kakkotetsu:20180617232607p:plain

ダウンロードした ova ファイルを展開して、qcow2 に変換して KVM+GNS3 が動いている母艦に放り込みます。

$ ll thousandeyes-va-0.126.ova
-rw-r--r-- 1 kotetsu kotetsu 965096448 Jun 16 23:43 thousandeyes-va-0.126.ova

$ tar -xvf thousandeyes-va-0.126.ova
thousandeyes-va-64-16.04.ovf
thousandeyes-va-64-16.04-disk1.vmdk

$ ll thousandeyes-va-*
-rw-r--r-- 1 kotetsu kotetsu 965096448 Jun 16 23:43 thousandeyes-va-0.126.ova
-rw-r--r-- 1 kotetsu kotetsu 965087744 May 10 05:23 thousandeyes-va-64-16.04-disk1.vmdk
-rw-r--r-- 1 kotetsu kotetsu      6261 May 10 05:21 thousandeyes-va-64-16.04.ovf

$ qemu-img convert -f vmdk -O qcow2 thousandeyes-va-64-16.04-disk1.vmdk thousandeyes-va-64-16.04.qcow2

$ file thousandeyes-va-*
thousandeyes-va-0.126.ova:           POSIX tar archive
thousandeyes-va-64-16.04-disk1.vmdk: VMware4 disk image
thousandeyes-va-64-16.04.ovf:        XML 1.0 document, ASCII text, with very long lines
thousandeyes-va-64-16.04.qcow2:      QEMU QCOW Image (v3), 21474836480 bytes

ThousandEyes 公式 KB / How to set up the Virtual Appliance あたりと、ova に入っていた ovf の中身を参考に以下の感じで GNS3 にデプロイ。

f:id:kakkotetsu:20180617232625p:plain

f:id:kakkotetsu:20180617232634p:plain

f:id:kakkotetsu:20180617232642p:plain

以下、生情報。

$ ps -ef | grep [T]housand
root      8862  5214  2 13:32 pts/12   00:10:10 /usr/bin/qemu-system-x86_64 -name ThousandEyes-va-64-16.04-1 -m 2048M -smp cpus=1 -enable-kvm -machine smm=off -boot order=c -drive file=/home/kotetsu/GNS3/projects/thousandeyes/project-files/qemu/2c910cdc-3d96-4de7-b8f5-42541188cd17/hda_disk.qcow2,if=ide,index=0,media=disk -uuid 2c910cdc-3d96-4de7-b8f5-42541188cd17 -serial telnet:127.0.0.1:5007,server,nowait -monitor tcp:127.0.0.1:41113,server,nowait -net none -device e1000,mac=0c:00:da:cd:17:00,netdev=gns3-0 -netdev socket,id=gns3-0,udp=127.0.0.1:10031,localaddr=127.0.0.1:10030 -nographic

ネットワークインターフェースは、The Internet に到達できるように適宜 GNS3Cloud とかを使って繋いでおきます。
あとは、起動してコンソールを見ていると Enterprise Agents の初期 URL (DHCPで得た IP アドレスに http で)と初期アカウント・パスワードが出るので、それに従って WebUI でアクセスします。

f:id:kakkotetsu:20180617232716p:plain

ポチポチして、ログインパスワードや Static IP アドレスや DNS サーバや NTP サーバや Default Gateway 情報や ssh ログイン用の公開鍵を設定します。
試していないですが、ssh で入って様子を見ると Ubuntu 16.04 なので、WebUI で出来ない細かい設定も可能かもです。

f:id:kakkotetsu:20180617232741p:plain

Enterprise Agents がインターネット上の SaaS サービスに情報を送ることができていれば、ダッシュボードにこのエージェントが登場します。

f:id:kakkotetsu:20180617232835p:plain

f:id:kakkotetsu:20180617232849p:plain

SNMP + LLDP が動く NW 機器を GNS3 で動かす

何か適当にどうぞ(クソ雑)。
今回は以下の通り Arista の vEOS-lab を 3 個並べておきました。

Enterprise AgentsSNMP manager として情報を取得にくるので、そこの到達性を確保し、SNMP 設定はしておきます。あとは LLDP を動かしておくとトポロジ情報も出してくれるので、動かしておきます。

f:id:kakkotetsu:20180617232918p:plain

ダッシュボードで色々やる

Devices の登録

Enterprise Agents から情報収集する対象(Devices というらしい)の NW 装置を設定してみます。

まずは Device Credentials として収集対象の SNMP Community 設定を登録して

f:id:kakkotetsu:20180617233027p:plain

Device Settings にて Find New Devices で対象の IP アドレスや先の Device Credentials や、どの Enterprise Agents を manager として使うか、を入力すると

f:id:kakkotetsu:20180617233055p:plain

以下のように登録されます。

f:id:kakkotetsu:20180617233120p:plain

情報収集対象の Interface を選択するときには Monitored Interfaces 設定のチェックボックスをポチポチと。
interval5 minutes から変えられないっぽいですね......。

Views で Device Layer を眺める

これで何となくそれっぽいのが出力されている筈なので、ダラダラと様子を見ていきます。

Topology として LLDP ベースで勝手にそれらしい絵が出来ています(今回は vEOS 側で管理インターフェースである Ma1 の LLDP を無効化してみた)。良いねー。
なお、上の時間軸を弄ることで特定時刻の Topology や Interface Metrics の様子を見ることができます。

f:id:kakkotetsu:20180617233143p:plain

Topology はノードを DD で動かすこともできます。

2 本接続して ECMP させているリンクは、こんな風にもなるし

f:id:kakkotetsu:20180617233159p:plain

ワンクリックでバラして見ることもできます。

f:id:kakkotetsu:20180617233229p:plain

今回、仮想環境だから Et インターフェースの speed 値を取得できていなかったので、まともに動かせたのは Ma1 だけだったのですが、Highlighting で「この時間帯に帯域の XX % 以上使っていたリンクを赤くする」ってのを出来ます。まあ、interval は 5 minutes なんですが......。

Interface Metric の様子...は、まあ単に標準 ifMib 見ているだけですね。無課金なので。

f:id:kakkotetsu:20180617233245p:plain

f:id:kakkotetsu:20180617233258p:plain

通知系設定

Devices にできる設定としては以下があるようです。

  • Devices -> Notification Rules
    • トリガ
      • 対象 Devices への到達性変化 (SNMP Get の失敗とか)
      • 対象 Devices のインターフェースの増減
    • 通知方法
      • メール
      • 各種 Webhooks
      • Slack や Hipchat など
  • Alerts -> Alert Rules
    • トリガ
      • インターフェースの以下が特定の条件・閾値を超えた時
        • Throughput
        • Error
        • Discards
        • Admin Status
        • Operational Status
    • 通知方法は上のと一緒

標準 MIB ベースで SNMP Manager が拾えるトリガなので、このくらいでしょうねー。
以下設定例です。Topology の Highlighting 機能で赤くするやつだと「speed の X%」っていう設定しか出来ないのですが、こちらでは Mbps での設定も出来るようです。

f:id:kakkotetsu:20180617233316p:plain

検知を WebUI で参照した例

f:id:kakkotetsu:20180617233432p:plain

で、View の Device Layer でも Alert は時系列でオレンジ色で出してくれています。

f:id:kakkotetsu:20180617233443p:plain

おしまい

以下ダラダラtp所感です。

  • WebUI は綺麗だしサクサク (この規模だと)
  • 1000台単位で Devices を長期間動かした時の様子を見てみたい
    • Topology が一体どうなってしまうのか
    • インターフェース数はどこまで拾えるのか
    • 中身は rrd 的な動作してるのか・データの持ち方どうなっているのか(SaaS側?)
  • 5 minutes interval 固定だとすると、「メンテナンス時や障害時に設計通りにトラフィックが切り替わったかのリアルタイム/事後確認」用途には使いづらいかも (バースト検知とかは言うまでもなく...)
  • LLDP の自動描画系のは割と聞くけど、良い
    • 静的に描画するものでも描画設定ファイルを自動生成すれば良かろう、だけど面倒くさいことはしたくない
    • Network Weathermap とかで手をかけて人間が分かりやすいものをちゃんと作ってやるか、こういうので手抜きしてそれなりにやるか、ってのは情報量とか用途次第かな...
  • 適用対象によっては 「SaaS 型である」という一点で一発アウトなやつかも
  • 無課金の Devices 機能は「標準 MIB の SNMP で出来ること」が限度なので、こんなもんでしょうなー
    • 多分今回見ていない RIPE Atlas みたいな機能がメインなんだと思う
    • でもオマケにしてはよく出来ていた

ARISTA vEOS に jq を入れて使う (小ネタ)

小ネタです。twitter で「Arista に jq 欲しい」って話を見かけたので「確かに vEOS デフォルトで入ってなくて、入れりゃー使えるけど(この記事)...最初から入っていて欲しいよなあ」というだけのお話。

環境

いつも通り(3年ぶり)の vEOS ですぞな。

localhost#show version
Arista vEOS
Hardware version:
Serial number:
System MAC address:  0021.96aa.9b52

Software image version: 4.20.1F
Architecture:           i386
Internal build version: 4.20.1F-6820520.4201F
Internal build ID:      790a11e8-5aaf-4be7-a11a-e61795d05b91

Uptime:                 2 minutes
Total memory:           2017260 kB
Free memory:            1259404 kB

[admin@localhost ~]$ uname -a
Linux localhost 3.18.28.Ar-6765725.4201F #1 SMP PREEMPT Wed Nov 15 09:47:13 PST 2017 x86_64 x86_64 x86_64 GNU/Linux

インストール

前述の環境では一応 /etc/yum 配下が揃っていそうなのですが、ササッと binary ファイル取ってきて PATH 通ったところに放り込む感じで。

まず curlインターネッツからとってこれるように DNS キャッシュサーバと Ma1 の IP アドレスくらいを EOS で設定して。

ip name-server vrf default <DNSキャッシュサーバの IP address>
!
interface Management1
   ip address <EOS の IPv4 アドレス(DHCPでも)>
!
ip route 0.0.0.0/0 <インターネッツに抜ける Gateway IP address>

bash におりて binary ファイルを取ってくるだけ。

localhost#bash

Arista Networks EOS shell

[admin@localhost ~]$
[admin@localhost tmp]$ cd /var/tmp
[admin@localhost tmp]$ curl -LO https://github.com/stedolan/jq/releases/download/jq-1.5/jq-linux64

[admin@localhost tmp]$ ll
total 2964
drwxrwxrwt 4 root  root         100 Nov 29 13:30 agents
drwxrwxrwx 2 root  root          40 Nov 29 13:19 cli
-rw-r--r-- 1 admin eosadmin 3027945 Nov 29 13:40 jq-linux64
-rw-rw-rw- 1 root  root           2 Nov 29 13:20 startup-config.loaded

[admin@localhost tmp]$ sudo cp jq-linux64 /bin/jq
[admin@localhost tmp]$ sudo chmod 755 /bin/jq

[admin@localhost ~]$ which jq
/bin/jq

EOS から使う

後はお好きなように。EOS シェル側に戻れば、ほいこの通り。

localhost#show int | json | jq '.interfaces[] | [.name, .lineProtocolStatus]'
[
  "Management1",
  "up"
]
[
  "Ethernet2",
  "up"
]
[
  "Ethernet3",
  "up"
]
[
  "Ethernet1",
  "up"
]

最後に

僕も EOS にデフォルトで入れておいて欲しいです。 (EOS ならばお手軽に eAPI を突いてスクリプト言語json ライブラリで処理する、のが常道なのかも知れないけど...shell だけでチョチョイとやりたいことも多々あるよね)