🤖
PythonでZabbixのxmlから情報を抽出する
Zabbixの数万行に及ぶ設定内容を、パラメーターシートとして提出しなければいけない事があります。
人力では無理ですので、Pythonにやってもらいます。
前提
目的は、Zabbixから出力されたxml形式のファイルから、指定の情報を抽出することです。
zabbixから出力されるxmlは、データの内容によってDOM構造が異なりますが、スクリプト内のパスを書き換えれば、どのようなxmlでも処理できます。
xml
今回は長文にしたくないのでお手軽に、ホスト情報のxmlから「ホスト名」「テンプレート名」「グループ名」「ホストのIPアドレス」を取得してみます。
今回処理するxmlは次のような構造です。
<?xml version="1.0" encoding="UTF-8"?>
<zabbix_export>
<groups></groups>
<hosts>
<host>
<host>HOST</host>
<name>NAME</name>
<status>DISABLED</status>
<templates>
<template>
<name>MY_TEMPLATE</name>
</template>
</templates>
<groups>
<group>
<name>GROUP</name>
</group>
</groups>
<interfaces>
<interface>
<ip>IP_ADDRESS</ip>
<interface_ref>if1</interface_ref>
</interface>
</interfaces>
</host>
.
. #以降<host></host>要素がホストの数だけあります
.
</hosts>
</zabbix_export>
このxmlから「ホスト名」「テンプレート名」「グループ名」「ホストのIPアドレス」を抽出して、次のような形式でエクセルにまとめます。
Template | Group | IPaddr | |
---|---|---|---|
Host A | Cisco | Swithes | 10.1.1.1 |
Host B | Original | APs | 10.1.2.2 |
Host C | HPE | Servers | 10.1.3.3 |
ひとつの要素に複数の値がある場合はリストのまま表示します。()
Template | Group | IPaddr | |
---|---|---|---|
Host A | ['tempA','tempB'] | ['gpA','gpB'] | 10.1.1.1 |
カッコ、コンマ、クオートを除去して、改行文字を入れる処理を追加したいところですが、未実装です。
これを処理するスクリプトが以下です。
import xml.etree.ElementTree as ET
import pandas as pd
from pandas.core.common import flatten
class DomCrawler:
def __init__(self, source) -> None:
self.source = source
self.all_elements = []
self.result = []
# この関数が返すのは、指定した要素が持つ値のリストです。
def crawler(self, terget):
self.terget = terget
# 与えられたDom要素をひとつづつ処理します。
for element in self.source:
# その中から、指定されたタグ名の要素を全て取得します。
self.all_elements = element.findall(self.terget)
if len(self.all_elements) > 0:
# 要素が持つ値を全て文字列に変換します。
for i in range(len(self.all_elements)):
self.all_elements[i] = self.all_elements[i].text
self.result.append(self.all_elements)
else:
# 要素がなかった場合、空白をリストに格納します。
self.result.append([''])
return self.result
# xmlファイルを指定してパースします。
file = 'zbx_export_hosts.xml'
xml = ET.parse(file)
# 全ての<host>要素から<name>タグが持つ文字列を取得してリストに格納します。
# このホスト名は後ほどSeriesを結合する際のキーとして使用します。
all_hosts = xml.findall('hosts/host')
host_name = DomCrawler(all_hosts).crawler('name')
# <name>タグもfindallメソッドで取得しているため一次元化します。
flat_host = list(flatten(host_name))
# 全ての<host>要素から、指定のpathの要素が持つテキストを取得して、Seriesにします。
template = pd.Series(DomCrawler(all_hosts).crawler('templates/template/name'), index=flat_host, name='Template')
group = pd.Series(DomCrawler(all_hosts).crawler('groups/group/name'), index=flat_host, name='Group')
ip = pd.Series(DomCrawler(all_hosts).crawler('interfaces/interface/ip'), index=flat_host, name='IPaddr')
# Seriesを任意の順番で並べておき、結合する際にこれを指定します。
datas = [template, group, ip]
# 出力ファイルを作成して書き込みます。
with open('result.csv', mode='w', newline='') as f:
pd.concat(datas, axis=1).to_csv(f)
Discussion