Zabbix: Python3 script to export all Templates to individual XML files

By default, Zabbix permits the export of all templates, but what if I wanted to download all the templates as individual XML files.

Someone wrote a fantastic python script to export all Zabbix templates to individual XML files, seven years before I needed to use it. A lot has changed in seven years. Zabbix versions to Python versions. This script in its existing form will produce only errors. After some doing, I was able to get this Python script to work as expected using Python3 and with Zabbix 5.0 LTS.

Fortunately, there is a tool that will convert most of the common differences between Python2 and Python3. This tool is 2to3 and available via a pip3 install.

pip3 install 2to3
2to3 thebrokenpythonscript.py -w

After executing the script again, there was yet another error.

#from
f = open(oput, 'w+')
#to
f = open(oput, 'wb+')

That resolved all the problems and the script worked as expected.

However, the xml version information needs to be corrected.

#from 
<?xml version="1.0"?>
#to
<?xml version="1.0" encoding="utf-8"?>

Do this.

#from      
f.write(template.toprettyxml(indent='  ').encode('utf-8'))
#to
f.write(template.toprettyxml(indent="  ", encoding="utf-8"))

Here is the complete script.

#!/usr/bin/python3

import argparse
import logging
import os
import xml.dom.minidom
from zabbix.api import ZabbixAPI
from sys import exit

parser = argparse.ArgumentParser(description='This is a simple tool to export zabbix templates for backup. Please note it will always set the data on export to 5/12/2020 (The release date of Zabbix 5.0 LTS) so git wont update unless something substantial happens.')
parser.add_argument('--templates', help='Name of specific template to export', default='All')
parser.add_argument('--out-dir', help='Directory to output templates to.', default='./templates')
parser.add_argument('--debug', help='Enable debug mode, this will show you all the json-rpc calls and responses', action="store_true")
parser.add_argument('--url', help='URL to the zabbix server (example: https://monitor.example.com/zabbix)', required=True)
parser.add_argument('--user', help='The zabbix api user', required=True)
parser.add_argument('--password', help='The zabbix api password', required=True)
args = parser.parse_args()

if args.debug:
    logging.basicConfig(
        level=logging.DEBUG,
        format='%(asctime)s %(message)s',
        datefmt='%m/%d/%Y %I:%M:%S %p'
    )
    logger = logging.getLogger(__name__)


def main():
    global args
    global parser

    if args.url is None:
        print("Error: Missing --url\n\n")
        exit(2)

    if args.user is None:
        print("Error: Missing --user\n\n")
        exit(3)

    if args.password is None:
        print("Error: Missing --password\n\n")
        exit(4)

    if not os.path.isdir(args.out_dir):
        os.mkdir(args.out_dir)

    zm = ZabbixTemplates(args.url, args.user, args.password)
    zm.exportTemplates(args)


class ZabbixTemplates:

    def __init__(self, _url, _user, _password):
        self.zapi = ZabbixAPI(url=_url, user=_user, password=_password)

    def exportTemplates(self, args):
        request_args = {
            "output": "extend"
        }

        if args.templates != 'All':
            request_args["filter"] = {
                "host": [args.templates]
            }

        result = self.zapi.do_request('template.get', request_args)

        if not result['result']:
            print("No matching template found for '{}'".format(args.templates))
            exit(-3)

        for t in result['result']:
            dest = args.out_dir + '/' + t['host'] + '.xml'
            self.exportTemplate(t['templateid'], dest)

    def exportTemplate(self, tid, oput):
        print("templateid: {}  output: {}".format(tid, oput))

        args = {
            "options": {
                "templates": [tid]
            },
            "format": "xml"
        }

        result = self.zapi.do_request('configuration.export', args)
        template = xml.dom.minidom.parseString(result['result'].encode('utf-8'))
        date = template.getElementsByTagName("date")[0]

        # Sanitize date so git doesn't flag the file as changed on every export
        date.firstChild.replaceWholeText('2020-05-12T01:01:01Z')

        with open(oput, 'wb') as f:
            f.write(template.toprettyxml(indent="  ", encoding="utf-8"))


if __name__ == '__main__':
    main()

Usage

python3 zabbix.template.export.py --url https://monitor.example.com/zabbix --user username --password passwordgoeshere

Output

A directory called templates will be created and all your templates will be dumped into it.

Source(s)

  • https://www.sharooq.com/solved-typeerror-write-argument-must-be-str-not-bytes-in-python
  • https://www.zabbix.com/life_cycle_and_release_policy
  • https://www.geeksforgeeks.org/automate-the-conversion-from-python2-to-python3/
  • https://github.com/CheggEng/zabbix-scripts/blob/master/zabbix.template.export.py
  • https://www.reddit.com/r/zabbix/comments/gqcoj8/how_to_download_all_templates/
  • https://stackoverflow.com/questions/68921881/add-encoding-utf-8-to-xml-file