Python で CiscoConfParse2 を使って Cisco コンフィグから必要部分を抽出する
Python の ciscoconfparse を使うと Cisco 機器のコンフィグファイルから必要な箇所を抽出することが出来ます。 このライブラリに関して以前に以下のメモを書きました。
このライブラリは後継になるバージョン 2 が別パッケージとしてリリースされています。
バージョン 1 のページには「バージョン 2 へアップグレードすべき理由」として下記の記載があります。
- It supports all major network vendor text configuration files (Arista, Cisco, F5, Juniper, Palo Alto)
- It supports searching across any number of configuration levels (ciscoconfparse only supports two config levels : a parent and child)
- It adds a string methods so you don't need to use regex matching if you don't want to
- It adds a CLI command
- Revamped documentation
- It simplifies the user interface and fixes broken ciscoconfparse default parameters (this could require changing old scripts using the original API)
- It intentionally uses a new python import to minimize confusion between itself and the original
今回は ciscoconfparse2 のチュートリアルページに掲載されている簡単な使い方をメモしておきます。
検証環境¶
| 対象 | バージョン |
|---|---|
| macOS | 14.5 |
| Python | 3.11.9 |
| ciscoconfparse2 | 0.7.74 |
インストール¶
pip でインストールします。 但し、macOS 上でインストールしようとするとエラーになってしまいました。
$ uv pip install ciscoconfparse2
(...snip...)
--- stderr:
scrypt-1.2.1/libcperciva/crypto/crypto_aes.c:6:10: fatal error: 'openssl/aes.h' file not found
#include <openssl/aes.h>
^~~~~~~~~~~~~~~
1 error generated.
error: command '/usr/bin/clang' failed with exit code 1
---
Caused by: This error likely indicates that you need to install a library that provides "openssl/aes.h" for scrypt==0.8.24
回避方法は openssl/aes.h' file not found on Mac に書かれていました。 まず環境変数を定義します。
再度、pip を実行します。 今回は正常に終了しました。
$ uv pip install ciscoconfparse2
Resolved 17 packages in 35ms
Built scrypt==0.8.24
Prepared 1 package in 3.68s
Installed 17 packages in 53ms
+ attrs==23.2.0
+ ciscoconfparse2==0.7.74
+ dnspython==2.6.1
+ hier-config==2.2.3
+ loguru==0.7.2
+ macaddress==2.0.2
+ markdown-it-py==3.0.0
+ mdurl==0.1.2
+ passlib==1.7.4
+ pygments==2.18.0
+ pyparsing==3.1.1
+ pyyaml==6.0.1
+ rich==13.7.1
+ scrypt==0.8.24
+ tomlkit==0.12.4
+ typeguard==4.1.5
+ typing-extensions==4.12.2
サンプル 1:shutdown しているインターフェイスの抽出¶
入力ファイル¶
config.txt
hostname router
!
interface GigabitEthernet0/1
ip address 10.0.1.1 255.255.255.0
no shutdown
!
interface GigabitEthernet0/2
ip address 10.0.2.2 255.255.255.0
shutdown
!
interface GigabitEthernet0/3
ip address 10.0.3.3 255.255.255.0
no shutdown
!
interface GigabitEthernet0/4
ip address 10.0.4.4 255.255.255.0
shutdown
!
end
サンプルスクリプト¶
sample.py
#!/usr/bin/env python3
from ciscoconfparse2 import CiscoConfParse
parse = CiscoConfParse('config.txt')
intf_cmds = parse.find_parent_objects(['interface', '^ shutdown'])
shut_intf_names = [" ".join(cmd.split()[1:]) for cmd in intf_cmds]
print(shut_intf_names)
実行結果¶
サンプル 2:BGP Neighbor の抽出¶
入力ファイル¶
config.txt
router bgp 65534
bgp router-id 10.0.0.100
address-family ipv4 unicast
!
neighbor 10.0.0.37
remote-as 64000
route-policy EBGP_IN in
route-policy EBGP_OUT out
!
neighbor 10.0.0.1
remote-as 65534
update-source Loopback0
route-policy MANGLE_IN in
route-policy MANGLE_OUT out
next-hop-self
!
neighbor 10.0.0.34
remote-as 64000
route-policy EBGP_IN in
route-policy EBGP_OUT out
サンプルスクリプト¶
sample.py
#!/usr/bin/env python3
from ciscoconfparse2 import CiscoConfParse
parse = CiscoConfParse('config.txt')
branches = parse.find_object_branches(('router bgp',
'neighbor',
'remote-as'))
bgp_cmd = branches[0][0]
local_asn = bgp_cmd.split()[-1]
for branch in branches:
neighbor_addr = branch[1].split()[-1]
remote_asn = branch[2].split()[-1]
if local_asn != remote_asn:
print("EBGP NEIGHBOR", neighbor_addr)