Juniperコンフィグを変換するツール

概要
====
Juniperルータにおいて、"show configration"コマンドにて出力されるコンフィグファイルを、ルータに実際に投入できる"set/edit"コマンド書式に変換してくれるツールを公開しました。
https://github.com/taijiji/junos_config_converter

作った動機
========
Ciscoルータだと"show running-config"コマンドで出力される結果をそのままコピーするだけで設定することができますが、Juniperルータの場合、"show configuration"コマンドで出力された結果をルータに投入できる"set/edit"形式の変換を手修正する必要があるので面倒でした。そこでpythonの勉強も含めて、えいやと勢いで作りました。

- 補足 20150412  
Juniperルータでは"show configuration | display set"と入力すると設定中のコンフィグをset/edit形式で出力してくれる機能や、"load merge terminal"と入力すると"show configuration"形式の設定コンフィグを受け入れてくれる機能が備わっています。  
本ツールでは事前に設定コマンドや手順書を作成する状況において、ルータを使わずに手軽に設定コンフィグを作成することを目的としています。

コード
=====
難しいことはせずに、さっくりと作れました。
ここでは、Juniperルータで"show configuration"コマンドで出力される形式のコンフィグからルータに設定できる"set/edit"が含まれた形式で出力するプログラムを実装しています。
ただし、逆に"set/edit"形式のコンフィグを"show configuration"形式に変換するプログラムは未実装です。


```py:junos_config_converter/convert_config.py
#! /usr/bin/env python
# -*- coding: utf-8 -*-

def convert_from_show_to_set(input_text):
    output_text = ''
    indent = ''
    for line in input_text.splitlines():
        if line == '':
            output_text += '\n'
        elif line[-1] == '{':
            output_text += indent + 'edit ' + line[:-1].strip() + '\n'
            indent += ' ' * 4
        elif line[-1] == ';':
            output_text += indent + 'set  ' + line[:-1].strip() + '\n'
        elif line[-1] == '}':
            indent = indent[:-4]
            output_text += indent + 'up\n'
        elif '; ## SECRET-DATA' in line:
            # ignore sentence of "## SECRET-DATA"
            output_text += indent + 'set ' + line.strip('; ## SECRET-DATA') + '\n'
        else:
            output_text += line + '\n'
    return output_text
```

使い方
=====
使い方は簡単で、convert_from_show_to_set()関数を呼び出すだけです。

- 入力例 (show configuration形式)  

```junos_config_converter/sample/sample_config_show.txt
system {
    host-name R1;
    time-zone Asia/Tokyo;
    root-authentication {
        encrypted-password "$1$9kcwd00g$YDqr8sBMaAh8SOCjQ2f4b0"; ## SECRET-DATA
    }
}
interfaces {
    fe-0/0/0 {
        unit 0 {
            family inet {
                address 192.168.1.1/24;
            }
        }
    }
}
```

- ツール利用例  

```py:junos_config_converter/sample/sample_from_show_to_set.py

#! /usr/bin/env python
# -*- coding: utf-8 -*-
import os, sys
import datetime
from convert_config import convert_from_show_to_set

sys.path.append(os.getcwd())

file_input = open('sample_config_show.txt', 'r')
input_text = file_input.read()
file_input.close()

output_text = convert_from_show_to_set( input_text )

# example: 20150405_2151
current_date_str = datetime.datetime.today().strftime( '%Y%m%d_%H%M' )

file_output = open ('output' + current_date_str + '.txt', 'w')
file_output.write( output_text )
file_output.close
```

- 出力例  (set/edit形式)  

```junos_config_converter/sample/output20150405_2151.txt
edit system
    set  host-name R1
    set  time-zone Asia/Tokyo
    edit root-authentication
        set encrypted-password "$1$9kcwd00g$YDqr8sBMaAh8SOCjQ2f4b0"
    up
up
edit interfaces
    edit fe-0/0/0
        edit unit 0
            edit family inet
                set  address 192.168.1.1/24
            up
        up
    up
up
```

開発状況
====
現在は"show configration" -> "set/edit"の変換のみを実装しています。(convert_from_show_to_set関数)
"set/edit"-> "show configration"の変換も実装している途中ですが(convert_from_set_to_show関数)、実装するにあたってJUNOSコンフィグの構造解析をする必要があり苦戦しています。

たとえばset/editの入力として下記のようなコンフィグがあった場合、どの単語がJUNOS固有の定型語か、もしくはユーザが定義した変数であるかを判別する必要があります。（JUNOS定型語をベタ書きで定義付けすれば実装可能ですが、少し骨が折れる作業です）

- 入力

```
set routing-options rib inet.0 static route 192.168.2.1/24  next-hop 192.168.1.1
```

- 出力

```
routing-options {
            rib inet.0 {
                static {
                    route 192.168.2.1/24 next-hop 192.168.1.1;
                }
            }
}
```

個人的な感覚としては、"show configration" -> "set/edit"の変換は手順書作成を中心によく使いますが、"set/edit"-> "show configration"変換はネットワーク運用の仕事では使う機会が少なく、実装のモチベーション自体が低めです。実装してほしいというニーズがあればコメントいただけると助かります。