Help us understand the problem. What is going on with this article?

Vyatta(VyOS)のコンフィグをXML化する

More than 3 years have passed since last update.

このエントリは、Bluemix(SoftLayer) Advent Calendar 2016の7日目の記事です。

Vyatta(VyOS)とは

Bluemix Infrastructure(旧SoftLayer)で柔軟なネットワークを構築したいときに、ソフトウェアルータであるVyatta(VyOS)がよく利用されます。
ルーティングはもちろん、ステートフルファイアウォールやVPNなどの機能が使えます。

Vyattaのコンフィグ

Vyattaの設定は、プロンプトから"show configuration"を実行するといわゆるrunning-configが表示されます。なんかJSONっぽい!

vyatta@vy01:~$ show configuration 
firewall {
    all-ping enable
    broadcast-ping disable
    config-trap disable
    group {
        address-group ipsec-peer {
      ・・・
        }
    }
}
interfaces {
      ・・・
}
・・・

完全にJSONだったら楽だったのですが、残念ながらJSONとも違う謎の記述法で書かれています。少なくとも木構造ではあるようです。
そこでこのコンフィグを扱いやすいデータ記述法に変換して、自動でExcelなどに貼り付けられたら、管理表が最新でないだの、実機と設定が違うだの、運用でありがちな問題から開放されるなーということで、変換ツールを作ってみます。開放されたい!

コンフィグ変換の方針

変換するツールはどんなのが便利か考えてみました。


形式

なんでもよいのですが、VBAでExcelに貼りたかったので今回はMSXMLなどパーサが充実しているXMLにします。

ポータビリティ

ツールは特定の環境に依存せず使えることが理想です。もっと言えばVyattaの上で実行できれば文句なしです。VyattaはDebianベースのLinuxなので、ある程度のコマンドが使えます。

環境を汚さない

Vyattaの上で実行するとなれば、一時ファイルとかは残したくないです。あまりゴリゴリ重いこともやりたくないです。

上記方針を加味した結果、sedとtrだけでいこうとおもいます
Vyatta上でも実行できるし、コンフィグを取ってきてローカルのcygwinやMacで実行してもよし。
やってみてだめだったら大人しくパールのようなものを使って書きます。(PythonはVyattaに入っていました。Rubyはなかった。)

XML化するにあたってルール決めが必要なところは以下のようにしました。

・要素名にハイフンは使わない
要素名にハイフンが含まれるとXMLが扱いにくくなる言語があるため、ハイフンはアンダースコアに変換します。

host-name vy01
   ↓
<host_name>vy01</host_name>

・名前っぽいところには属性を使う

ethernet eth1 {
    address 172.16.0.1/24
}
   ↓
<ethernet name="eth1">
    <address>172.16.0.1/24</address>
</ethernet>

・宣言だけのところは適宜単語を補う

rfc3768-compatibility
   ↓
<rfc3768_compatibility>true</rfc3768_compatibility>

呪文

上記ルールに沿うようsedのコマンドを機械的に追加していった結果、よくわからないものが出来上がりました。真面目にPythonで書けばよかった!

"show configuration"の結果をパイプで食わせてあげればXMLが出てきます。

vyatta@vy01:~$ show configuration | 呪文
呪文
sed 's/enable-default-log/enable_default_log true/' |\
sed 's/rfc3768-compatibility/rfc3768_compatibility true/' |\
sed 's/repository supported/repository_supported/' |\
sed 's/local-zone$/local_zone true/' |\
sed 's/system$/forward_to system/' |\
sed 's@^\( *\)\([^ {}]\+\) \([^ {}]\+\)\( *\)$@\1<\2>\3</\2>\4@' | \
tr '\n' '~' | \
sed 's@\(~ *\)\([^{}~]*\) {~\([^{}]*~*\)\( *\)}~@\1<\2>~\3\4</\2>~@g' | \
sed 's@\(~ *\)\([^{}~]*\) {~\( *\)}~@\1<\2></\2>~@g' | \
sed 's@\(~ *\)\([^{}~]*\) {~\([^{}]*~\)\( *\)}~@\1<\2>~\3\4</\2>~@g' | \
sed 's@\(~ *\)\([^{}~]*\) {~\([^{}]*~\)\( *\)}~@\1<\2>~\3\4</\2>~@g' | \
sed 's@\(~ *\)\([^{}~]*\) {~\([^{}]*~\)\( *\)}~@\1<\2>~\3\4</\2>~@g' | \
sed 's@\(~ *\)\([^{}~]*\) {~\([^{}]*~\)\( *\)}~@\1<\2>~\3\4</\2>~@g' | \
sed 's@\(~ *\)\([^{}~]*\) {~\([^{}]*~\)\( *\)}~@\1<\2>~\3\4</\2>~@g' | \
sed 's@\(~ *\)\([^{}~]*\) {~\([^{}]*~\)\( *\)}~@\1<\2>~\3\4</\2>~@g' | \
sed 's@\(~ *\)\([^{}~]*\) {~\([^{}]*~\)\( *\)}~@\1<\2>~\3\4</\2>~@g' | \
sed 's@^\( *\)\([^{}~]*\) {~\([^{}]*~\)\( *\)}~@\1<\2>~\3\4</\2>~@g' | \
tr '~' '\n' | \
sed 's@<address-group \([^>]\+\)>@<address_group name="\1">@' |\
sed 's@</address-group [^>]\+>@</address_group>@' |\
sed 's@<name \([^>]\+\)>@<rule_set name="\1">@' |\
sed 's@</name [^>]\+>@</rule_set>@' |\
sed 's@<rule \([^>]\+\)>@<rule priority="\1">@' |\
sed 's@</rule [^>]\+>@</rule>@' |\
sed 's@<bonding \([^>]\+\)>@<bonding name="\1">@' |\
sed 's@</bonding [^>]\+>@</bonding>@' |\
sed 's@<vif \([^>]\+\)>@<vif name="\1">@' |\
sed 's@</vif [^>]\+>@</vif>@' |\
sed 's@<vrrp-group \([^>]\+\)>@<vrrp_group name="\1">@' |\
sed 's@</vrrp-group [^>]\+>@</vrrp_group>@' |\
sed 's@<ethernet \([^>]\+\)>@<ethernet name="\1">@' |\
sed 's@</ethernet [^>]\+>@</ethernet>@' |\
sed 's@<loopback \([^>]\+\)>@<loopback name="\1">@' |\
sed 's@</loopback [^>]\+>@</loopback>@' |\
sed 's@<vti \([^>]\+\)>@<vti name="\1">@' |\
sed 's@</vti [^>]\+>@</vti>@' |\
sed 's@<interface-route \([^>]\+\)>@<interface_route network="\1">@' |\
sed 's@</interface-route [^>]\+>@</interface_route>@' |\
sed 's@<next-hop-interface \([^>]\+\)>@<next_hop_interface name="\1">@' |\
sed 's@</next-hop-interface [^>]\+>@</next_hop_interface>@' |\
sed 's@<route \([^>]\+\)>@<route network="\1">@' |\
sed 's@</route [^>]\+>@</route>@' |\
sed 's@<route6 \([^>]\+\)>@<route6 network="\1">@' |\
sed 's@</route6 [^>]\+>@</route6>@' |\
sed 's@<next-hop \([^>]\+\)>@<next_hop address="\1">@' |\
sed 's@</next-hop [^>]\+>@</next_hop>@' |\
sed 's@<remote-router \([^>]\+\)>@<remote_router address="\1">@' |\
sed 's@</remote-router [^>]\+>@</remote_router>@' |\
sed 's@<sync-map \([^>]\+\)>@<sync_map name="\1">@' |\
sed 's@</sync-map [^>]\+>@</sync_map>@' |\
sed 's@<community \([^>]\+\)>@<community name="\1">@' |\
sed 's@</community [^>]\+>@</community>@' |\
sed 's@<device \([^>]\+\)>@<device name="\1">@' |\
sed 's@</device [^>]\+>@</device>@' |\
sed 's@<user \([^>]\+\)>@<user name="\1">@' |\
sed 's@</user [^>]\+>@</user>@' |\
sed 's@<server \([^>]\+\)>@<server name="\1">@' |\
sed 's@</server [^>]\+>@</server>@' |\
sed 's@<repository \([^>]\+\)>@<repository name="\1">@' |\
sed 's@</repository [^>]\+>@</repository>@' |\
sed 's@<facility \([^>]\+\)>@<facility name="\1">@' |\
sed 's@</facility [^>]\+>@</facility>@' |\
sed 's@<esp-group \([^>]\+\)>@<esp_group name="\1">@' |\
sed 's@</esp-group [^>]\+>@</esp_group>@' |\
sed 's@<ike-group \([^>]\+\)>@<ike_group name="\1">@' |\
sed 's@</ike-group [^>]\+>@</ike_group>@' |\
sed 's@<proposal \([^>]\+\)>@<proposal number="\1">@' |\
sed 's@</proposal [^>]\+>@</proposal>@' |\
sed 's@<peer \([^>]\+\)>@<peer name="\1">@' |\
sed 's@</peer [^>]\+>@</peer>@' |\
sed 's@<zone \([^>]\+\)>@<zone name="\1">@' |\
sed 's@</zone [^>]\+>@</zone>@' |\
sed 's@<from \([^>]\+\)>@<from zone="\1">@' |\
sed 's@</from [^>]\+>@</from>@' |\
sed 's@<\([^-<>"]\+\)-\([^>]\+\)>@<\1_\2>@' |\
sed 's@</\([^-<>"]\+\)-\([^>]\+\)>@</\1_\2>@' |\
sed 's@<\([^-<>"]\+\)-\([^>]\+\)>@<\1_\2>@' |\
sed 's@</\([^-<>"]\+\)-\([^>]\+\)>@</\1_\2>@' |\
sed 's@<\([^-<>"]\+\)-\([^>]\+\)>@<\1_\2>@' |\
sed 's@</\([^-<>"]\+\)-\([^>]\+\)>@</\1_\2>@' |\
sed 's@^@    @' |\
sed '1i\<root>' |\
sed '$a\</root>'

Vyatta上にファイル置いちゃってもいいよという人は、スクリプトにして/tmpの下とかに置くといいとおもいます。

いろいろサニタイズして大幅に削っていますが、XMLは以下のようなものが出力されます。

<root>
    <interfaces>
        <ethernet name="eth0">
            <address>192.168.0.1/24</address>
            <duplex>auto</duplex>
            <hw_id>XX:XX:XX:XX:XX:XX</hw_id>
            <smp_affinity>auto</smp_affinity>
            <speed>auto</speed>
            <vrrp>
                <vrrp_group name="1">
                    <advertise_interval>1</advertise_interval>
                    <preempt>true</preempt>
                    <priority>254</priority>
                    <rfc3768_compatibility>true</rfc3768_compatibility>
                    <sync_group>vgroup1</sync_group>
                    <virtual_address>192.168.0.3/24</virtual_address>
                </vrrp_group>
            </vrrp>
        </ethernet>
        <ethernet name="eth1">
            <address>172.16.0.1/24</address>
            <duplex>auto</duplex>
            <hw_id>XX:XX:XX:XX:XX:XX</hw_id>
            <smp_affinity>auto</smp_affinity>
            <speed>auto</speed>
            <vrrp>
                <vrrp_group name="1">
                    <advertise_interval>1</advertise_interval>
                    <preempt>true</preempt>
                    <priority>254</priority>
                    <rfc3768_compatibility>true</rfc3768_compatibility>
                    <sync_group>vgroup1</sync_group>
                    <virtual_address>172.16.0.3/24</virtual_address>
                </vrrp_group>
            </vrrp>
        </ethernet>
        <loopback name="lo">
        </loopback>
    </interfaces>
    <service>
        <dns>
            <forwarding>
                <cache_size>150</cache_size>
                <listen_on>eth1</listen_on>
                <forward_to>system</forward_to>
            </forwarding>
        </dns>
        <ssh>
            <port>22</port>
        </ssh>
    </service>
    <system>
        <config_management>
            <commit_revisions>20</commit_revisions>
        </config_management>
        <console>
            <device name="ttyS0">
                <speed>9600</speed>
            </device>
        </console>
        <gateway_address>192.168.0.1</gateway_address>
        <host_name>vy01</host_name>
        <login>
            <user name="vyatta">
                <authentication>
                    <encrypted_password>****************</encrypted_password>
                </authentication>
                <level>admin</level>
            </user>
        </login>
        <name_server>192.168.0.1</name_server>
        <ntp>
            <server name="ntp.nict.jp">
            </server>
        </ntp>
        <package>
            <auto_sync>1</auto_sync>
            <repository_supported>
                <components>main</components>
                <distribution>stable</distribution>
                <password>****************</password>
                <url>http://packages.vyatta.com/vyatta_supported</url>
                <username>""</username>
            </repository_supported>
        </package>
        <syslog>
            <global>
                <facility name="all">
                    <level>notice</level>
                </facility>
                <facility name="protocols">
                    <level>debug</level>
                </facility>
            </global>
        </syslog>
        <time_zone>Asia/Tokyo</time_zone>
    </system>
</root>

これを使ってVBAでExcelにぺたぺた貼ると、図のようなドキュメントが自動で作れました。便利。
spreadsheet.png

よく設定変更するところしかテストできていないので、不足がいっぱいあると思います。基本的にsedの行を追加すれば対応できると思いますが、コメントなどで教えていただけますと幸いです。
VBAのコードは来年のアドベントカレンダーにでも。。

kadzus
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした