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