Skip to content

Commit a56a2de

Browse files
committed
Initial commit
0 parents  commit a56a2de

File tree

3 files changed

+172
-0
lines changed

3 files changed

+172
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*.xml

README.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# zabbix-template-convertor
2+
3+
This Python script aims to resolve compatability issues when migrating Zabbix
4+
template XML files between versions of Zabbix. For example, you may wish to
5+
import a Zabbix v3.2 template into Zabbix v2.2. This operation will likely fail
6+
if new features have been implemented in the exported template.
7+
8+
__WARNING__: This project is still under active development and not ready for
9+
release.
10+
11+
## License
12+
13+
Copyright (c) 2015 Ryan Armstrong
14+
15+
Permission is hereby granted, free of charge, to any person obtaining a copy
16+
of this software and associated documentation files (the "Software"), to deal
17+
in the Software without restriction, including without limitation the rights
18+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
19+
copies of the Software, and to permit persons to whom the Software is
20+
furnished to do so, subject to the following conditions:
21+
22+
The above copyright notice and this permission notice shall be included in
23+
all copies or substantial portions of the Software.
24+
25+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
31+
THE SOFTWARE.

zabbix-template-convertor

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
#!/usr/bin/python
2+
import xml.etree.ElementTree as ET
3+
import argparse
4+
5+
__version__ = '1.1.0'
6+
7+
# parse cmdline args
8+
parser = argparse.ArgumentParser(description='Migrate Zabbix templates between versions')
9+
parser.add_argument('-v', '--version',
10+
action='version',
11+
version='%%(prog)s %s' % __version__)
12+
13+
parser.add_argument('-o', '--output-version',
14+
help='target Zabbix version',
15+
dest='output_version',
16+
type=str,
17+
metavar='X.Y.Z',
18+
required=True)
19+
20+
parser.add_argument('-s', '--squash-value-maps',
21+
help='remove references to value maps for versions older than 3.0.0',
22+
dest='squash_value_maps',
23+
action='store_true')
24+
25+
parser.add_argument('file',
26+
help='Zabbix template XML file',
27+
type=file)
28+
29+
args = parser.parse_args()
30+
31+
def debug(msg):
32+
from sys import stderr
33+
stderr.write('%s\n' % msg)
34+
35+
class NotApplicableError(Exception):
36+
"""
37+
Exception to be raised if a rule is not applicable for the desired output
38+
version
39+
"""
40+
41+
def __str__(self):
42+
return 'Rule not applicable for the desired output version'
43+
44+
class ConversionRule(object):
45+
"""Base abstract class for all conversion rules"""
46+
47+
def __init__(self, root, version):
48+
self.root = root
49+
self.version = version
50+
51+
def __str__(self):
52+
return "Base conversion rule class"
53+
54+
def apply(self):
55+
"""
56+
Apply this rule to self.root. Should throw NotApplicableError if this
57+
rule does not apply for the desired output version (self.version).
58+
"""
59+
60+
raise NotImplementedError('apply method not implemented for %s' % self.__class__.__name__)
61+
62+
def versioncmp(self, version):
63+
"""Compare two Zabbix version strings"""
64+
65+
from pkg_resources import parse_version as V
66+
return cmp(V(self.version), V(version))
67+
68+
class VersionMustMatch(ConversionRule):
69+
"""
70+
Rule to ensure the /zabbix_export/version element is set to the correct
71+
version
72+
"""
73+
74+
def __str__(self):
75+
return 'Template version string must be \'%s\'' % self.outversion
76+
77+
def apply(self):
78+
if self.versioncmp('3') < 0: self.outversion = '2.0'
79+
elif self.versioncmp('3.2') < 0: self.outversion = '3.0'
80+
elif self.versioncmp('3.3') < 0: self.outversion = '3.2'
81+
else:
82+
self.outversion = 'unknown'
83+
raise ValueError('Unsupported output version: %s' % self.version)
84+
85+
root.find('version').text = self.outversion
86+
87+
class TimeStampMustBeUpdated(ConversionRule):
88+
"""Rule to update the /zabbix_export/date timestamp"""
89+
90+
def __str__(self):
91+
return 'Document timestamp must be updated'
92+
93+
def apply(self):
94+
from datetime import datetime
95+
root.find('date').text = datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ')
96+
97+
class ValueMapsMustNotBeExported(ConversionRule):
98+
"""Rule to remove value map definitions from templates older than 3.0"""
99+
100+
def __str__(self):
101+
return 'Value map definitions must not be exported'
102+
103+
def apply(self):
104+
if self.versioncmp('3') >= 0:
105+
raise NotApplicableError()
106+
107+
root.remove(root.find('value_maps'))
108+
109+
class ValueMapsMustNotBeReferenced(ConversionRule):
110+
"""Rule to remove references to value maps"""
111+
112+
def __str__(self):
113+
return 'References to value maps must not exist'
114+
115+
def apply(self):
116+
if not args.squash_value_maps or self.versioncmp('3') >= 0:
117+
raise NotApplicableError()
118+
119+
for itemtype in [ 'item', 'item_prototype' ]:
120+
for node in self.root.findall('.//%s/valuemap' % itemtype):
121+
node.clear()
122+
123+
# read xml template
124+
doc = ET.parse(args.file)
125+
root = doc.getroot()
126+
127+
# load rules
128+
rules = []
129+
for c in ConversionRule.__subclasses__():
130+
rules.append(c(root, args.output_version))
131+
132+
# apply rules
133+
for rule in rules:
134+
try:
135+
rule.apply()
136+
debug('Applied: %s' % rule)
137+
except NotApplicableError:
138+
pass
139+
140+
ET.dump(doc)

0 commit comments

Comments
 (0)