Python
Network
jinja2

Network Engineer のためのTemplate Engine活用術

More than 1 year has passed since last update.


概要

ネットワークの仕事をしていると、同じような設定にIPアドレスなどの値だけを変えてルータコンフィグを大量に作るということがたまにあります。

手作業で一つ一つコピペして作ってもいいのですが、プログラミング言語で用意されているテンプレートエンジンを使うと値の挿入が手軽に行えます。

ここではPythonで多く使われているJinja2というテンプレートエンジンを使って、ルータコンフィグを作ってみます。

準備段階としてまずはjinja2をインストールしてください。

pip install jinja2

pipを使ったことがない方はこちらの記事を参考にpipをインストールしてください。

Pythonで一番最初に入れるべきパッケージ setuptools と pip

http://www.lifewithpython.com/2012/11/Python-package-setuptools-pip.html


Step 1. 一行のコンフィグに1つの値を埋め込む

まずは'show bgp summary | inc (AS番号)'という一行のコンフィグ(実際はコマンドですが)の作成を試してみます。Jinja2を使うとこんな感じでかけます。


easy_jinja2.py

#! /usr/bin/env python

# -*- coding: utf-8 -*-

from jinja2 import Template

template = Template( 'show bgp summary | inc {{ asn }}' )

output_str = template.render( asn='65001' )

print output_str


実行すると以下のように表示されます。

%python easy_jinja2.py

show bgp summary | inc 65001

上記のようにJinja2では {{ }} で括った文字列を変数名として認識し、render関数を使って実際の値を埋め込むことができます。

このようにテンプレートエンジンを使うことで、任意を値を埋め込んだテキストファイルを容易に作成することができます。


Step 2. 複数行のコンフィグに複数の値を埋め込む

次はもう少し行数の多いコンフィグを作ってみます。

文字列型の変数に値を埋め込むには、Environmentクラスを使って書きます。


easy_jinja2.py

#! /usr/bin/env python

# -*- coding: utf-8 -*-

from jinja2 import Template, Environment

input_str = '''
router bgp 65000
neighbor {{ ip4 }}
shutdown

router bgp 65000
neighbor {{ ip6 }}
shutdown

show bgp summary | inc {{ asn }}
'''

template = Environment().from_string(input_str)

output_str = template.render( ip4='10.1.1.1', ip6='2000::1:1', asn='65001' )

print output_str


実行すると以下のように表示されます。

% python easy_jinja2.py

router bgp 65000
neighbor 10.1.1.1
shutdown

router bgp 65000
neighbor 2000::1:1
shutdown

show bgp summary | inc 65001


Step 3. 複数の値を埋め込んだコンフィグを大量に作る

最後に、これまでのコンフィグを、複数のIPアドレスなどの値を埋め込んで作ってみます。ただしテンプレートエンジンの使い方そのものは先ほどと同じです。

ここでは辞書型とfor文を使って、テンプレートエンジンに値を挿入しています。


easy_jinja2.py

#! /usr/bin/env python

# -*- coding: utf-8 -*-

from jinja2 import Template, Environment

input_str = '''
router bgp 65000
neighbor {{ ip4 }}
shutdown

router bgp 65000
neighbor {{ ip6 }}
shutdown
'''
input_str_2 = 'show bgp summary | inc {{ asn }} '

neighbor_info= [
{
'ip4' : '10.1.1.1',
'ip6' : '2000::1:1',
'asn' : '65001',
},
{
'ip4' : '10.1.1.2',
'ip6' : '2000::1:2',
'asn' : '65002',
},
{
'ip4' : '10.1.1.3',
'ip6' : '2000::1:3',
'asn' : '65003',
},
{
'ip4' : '10.1.1.4',
'ip6' : '2000::1:4',
'asn' : '65004',
},
{
'ip4' : '10.1.1.5',
'ip6' : '2000::1:5',
'asn' : '65005',
},
]

template = Environment().from_string(input_str)

for neighbor in neighbor_info:
output_str = template.render( ip4=neighbor['ip4'] , ip6=neighbor['ip6'] )
print output_str

template = Environment().from_string(input_str_2)

for neighbor in neighbor_info:
output_str = template.render( asn=neighbor['asn'] )
print output_str


実行結果は以下のようになります。

% python easy_jinja2.py

router bgp 65000
neighbor 10.1.1.1
shutdown

router bgp 65000
neighbor 2000::1:1
shutdown

router bgp 65000
neighbor 10.1.1.2
shutdown

router bgp 65000
neighbor 2000::1:2
shutdown

router bgp 65000
neighbor 10.1.1.3
shutdown

router bgp 65000
neighbor 2000::1:3
shutdown

router bgp 65000
neighbor 10.1.1.4
shutdown

router bgp 65000
neighbor 2000::1:4
shutdown

router bgp 65000
neighbor 10.1.1.5
shutdown

router bgp 65000
neighbor 2000::1:5
shutdown
show bgp summary | inc 65001
show bgp summary | inc 65002
show bgp summary | inc 65003
show bgp summary | inc 65004
show bgp summary | inc 65005

以上のように、テンプレートエンジンを使うことで値を変えながら同じようなコンフィグを簡単に作ることができます。


最後に

いざ目の前にこのような繰り返しが多いタスクが立ちはだかった時に「手でコピペしていったほうが早いか」「それともツールを作って工夫したほうが早いか」という迷いはよく出てきます。

重い腰を上げてツールを作り出してみると、「案外さっくり短時間でできた!」なんてことはよくあります。私が実際にこのツールを書いた時も、たまたま座れた電車の中だけで書けました。ジャスト30分でした。

一度作ってみると他の作業でも使い回しができることが多く、コンフィグ作成に限らずにあらゆるところで活用できる場面が出てきます。

手作業でルータコンフィグの作成をやっていると思わぬところでミスがあったり、「しまった、全部に一文字ずつ余計な文字が入っていた!」といったような細かいトラブルが起きた際には手で一つ一つ繰り返して修正する必要がありますが、テンプレートエンジンを使っていると1箇所直すだけで修正完了!となるケースが多く、作業そのものをシンプルにすることができます。

心が折れそうな大量のルータコンフィグを作る仕事が降ってきた際には、ぜひ一度テンプレートエンジンに挑戦してみてください。