#これは何?
Ciscoのコンフィグ*を生成するPythonスクリプト。Jinja2を使ってパラメータを埋めるサンプル。何かと汎用性が高そうなので、自分用にメモ。変数を含むコンフィグテンプレートと、変数に対する値をまとめたCSVの二つを用意して、スクリプト実行すれば複数のコンフィグがファイル出力される。
*CiscoでなくてももちろんOK。
Jinja2って何?
Python用のテンプレートエンジン。詳しくは、本家を参照。
The name Jinja was chosen because it’s the name of a Japanese temple and temple and template share a similar pronunciation. It is not named after the city in Uganda.
日本のテンプル(神社)は、テンプレートと発音が似ているから。
(ウガンダにJinjaという都市があるけど、それじゃないよ)
0. 準備
pipでJinja2を使えるようにしておく。
ファイルを三つと、ディレクトリを一つ用意(それぞれ、以下で解説)。
~ $pip3 list | grep Jinja2
Jinja2 (2.8)
~ $ls
build_templates.py config_template.txt configs inventory.csv
~ $
- configs ... 複数コンフィグファイルが生成されるディレクトリ。中身は空っぽ。
- inventory.csv ... コンフィグテンプレートの変数ファイル。
- config_template.txt ... コンフィグのテンプレートファイル。
- build_templates.py ... メインのスクリプト。
1. configsディレクトリ
空っぽです。
~ $ls ./configs
~ $
2. inventory.csv
Excelで作るも良し、変数をスクリプトで管理するも良し。
~ $cat inventory.csv
hostName,serialNumber,platformId,site,ipAddress,subnet,username,password,enablepass
Cat01,12345678901,WS-C2960X-48FPD-L,Tokyo,10.10.10.101,255.255.255.0,cisco,C1sco12345,C1$co
Cat02,22345678901,WS-C2960X-48FPD-L,Osaka,10.10.10.102,255.255.255.0,cisco,C1sco12345,C1$co
Cat03,32345678901,WS-C2960X-48FPD-L,Nagoya,10.10.10.103,255.255.255.0,cisco,C1sco12345,C1$co
3. config_template.txt
ネットワークエンジニアには見慣れたコンフィグですが、動的に補完したいパラメータを {{変数}} とします。AnsibleでもJinja2が使われているため、違和感がない方も多いかもしれません。
~ $cat config_template.txt
hostname {{hostName}}
!
enable password {{enablepass}}
!
username {{username}} password 0 {{password}}
no aaa new-model
!
int vlan 1
ip address {{ipAddress}} {{subnet}}
!
end
As already referenced in the variables section, Ansible uses Jinja2 templating to enable dynamic expressions and access to variables.
4. build_templates.py
build_templatesは、コンフィグテンプレート(config_template.txt)と変数のCSV(inventory.csv)を入力し、複数のコンフィグファイルを出力する関数のサンプル。
# -*- coding: utf-8 -*-
import jinja2
import csv
CONFIGS_DIR= "./configs/"
DEVICES="./inventory.csv"
TEMPLATE="./config_template.txt"
def build_templates(template_file, devices):
templateLoader = jinja2.FileSystemLoader('./')
templateEnv = jinja2.Environment(loader=templateLoader)
template = templateEnv.get_template(template_file)
f = open(devices, 'rt')
try:
reader = csv.DictReader(f)
for dict_row in reader:
outputText = template.render(dict_row)
config_filename = CONFIGS_DIR + dict_row['hostName'] + '-' + dict_row['site'] + '-config'
with open(config_filename, 'w') as config_file:
config_file.write(outputText)
print("コンフィグ生成: %s" % config_filename)
finally:
f.close()
if __name__ == "__main__":
build_templates(TEMPLATE, DEVICES)
ポイント
- CSVファイルから行ごと(デバイスごと)にPythonディクショナリで読込(csv.DictReader)
- テンプレートに変数補完(template.render(dict_row))して出力
- 装置の数だけループ(for dict_row in reader)
- Jinja2の書き方は、分けて書いていますが以下のように一つでも書いても良さそうです
※引用元:Load a Jinja2 template from the filesystem and render it
import os
import jinja2
def render(tpl_path, context):
path, filename = os.path.split(tpl_path)
return jinja2.Environment(
loader=jinja2.FileSystemLoader(path or './')
).get_template(filename).render(context)
5. 実行
~ $python3 build_templates.py
コンフィグ生成: ./configs/Cat01-Tokyo-config
コンフィグ生成: ./configs/Cat02-Osaka-config
コンフィグ生成: ./configs/Cat03-Nagoya-config
~ $
~ $ls ./configs/
Cat01-Tokyo-config Cat02-Osaka-config Cat03-Nagoya-config
~ $
~ $cat ./configs/Cat01-Tokyo-config
hostname Cat01
!
enable password C1$co
!
username cisco password 0 C1sco12345
no aaa new-model
!
int vlan 1
ip address 10.10.10.101 255.255.255.0
!
end
~ $
~ $
~ $cat ./configs/Cat02-Osaka-config
hostname Cat02
!
enable password C1$co
!
username cisco password 0 C1sco12345
no aaa new-model
!
int vlan 1
ip address 10.10.10.102 255.255.255.0
!
end
~ $
~ $
いい感じですね。他にも使えそうです。
参考
Usage of csv.DictReader ... CSVパースの解説がわかりやすい
CiscoDevNet/apic-em-samples-aradford ... ごちゃごちゃしてるけど、色々入っている