blob: 326969ef2483b77c267891ff4d883d5865295c40 [file] [log] [blame]
savex4448e132018-04-25 15:51:14 +02001import jinja2
2import six
3import abc
4import os
5
Alex Savatieievd48994d2018-12-13 12:13:00 +01006from ci_checker.common import const
savex4448e132018-04-25 15:51:14 +02007
8pkg_dir = os.path.dirname(__file__)
9pkg_dir = os.path.join(pkg_dir, os.pardir)
10pkg_dir = os.path.normpath(pkg_dir)
11
12
13def shortname(node_fqdn):
14 # form shortname out of node fqdn
15 return node_fqdn.split(".", 1)[0]
16
17
18def is_equal(pkg_dict):
19 # compare versions of given package
20 return pkg_dict['installed'] == pkg_dict['candidate']
21
22
23def is_active(node_dict):
24 # check node status in node dict
25 return node_dict['status'] == const.NODE_UP
26
27
28def line_breaks(text):
29 # replace python linebreaks with html breaks
30 return text.replace("\n", "<br />")
31
32
33@six.add_metaclass(abc.ABCMeta)
34class _Base(object):
35 def __init__(self):
36 self.jinja2_env = self.init_jinja2_env()
37
38 @abc.abstractmethod
39 def __call__(self, payload):
40 pass
41
42 @staticmethod
43 def init_jinja2_env():
44 return jinja2.Environment(
45 loader=jinja2.FileSystemLoader(os.path.join(pkg_dir, 'templates')),
46 trim_blocks=True,
47 lstrip_blocks=True)
48
49
50class _TMPLBase(_Base):
51 @abc.abstractproperty
52 def tmpl(self):
53 pass
54
55 @staticmethod
56 def _count_totals(data):
57 data['counters']['total_nodes'] = len(data['nodes'])
58
Alex Savatieievd48994d2018-12-13 12:13:00 +010059 def __call__(self, nodes={}, mdl_diff={}):
savex4448e132018-04-25 15:51:14 +020060 # init data structures
61 data = self.common_data()
62 data.update({
Alex Savatieievd48994d2018-12-13 12:13:00 +010063 "nodes": nodes,
64 "compare": data
savex4448e132018-04-25 15:51:14 +020065 })
66
67 # add template specific data
68 self._extend_data(data)
69
70 # do counts global
71 self._count_totals(data)
72
73 # specific filters
74 self.jinja2_env.filters['shortname'] = shortname
75 self.jinja2_env.filters['is_equal'] = is_equal
76 self.jinja2_env.filters['is_active'] = is_active
77 self.jinja2_env.filters['linebreaks'] = line_breaks
78
79 # render!
80 tmpl = self.jinja2_env.get_template(self.tmpl)
81 return tmpl.render(data)
82
83 def common_data(self):
84 return {
85 'counters': {},
86 'salt_info': {}
87 }
88
89 def _extend_data(self, data):
90 pass
91
92
93# Package versions report
savexce010ba2018-04-27 09:49:23 +020094class HTMLPackageCandidates(_TMPLBase):
savex4448e132018-04-25 15:51:14 +020095 tmpl = "pkg_versions_tmpl.j2"
96
97 @staticmethod
98 def is_fail_uniq(p_dict, p_name, nodes, node_name):
99 # look up package fail for nodes with similar role
100 _tgroup = nodes[node_name]['node_group']
101 # filter all nodes with the same role
102 _nodes_list = filter(
103 lambda nd: nodes[nd]['node_group'] == _tgroup and nd != node_name,
104 nodes
105 )
106 # lookup same package
107 _fail_uniq = False
108 for _node_name in _nodes_list:
109 # check if there is a package present on node
110 _nd = nodes[_node_name]['packages']
111 if p_name not in _nd:
112 continue
113 # if both backages has same version and differ from candidate
114 if p_dict['candidate'] == _nd[p_name]['candidate'] \
115 and _nd[p_name]['candidate'] == _nd[p_name]['installed']:
116 # it is not uniq, mark and break
117 _fail_uniq = True
118 return _fail_uniq
119
120 def _extend_data(self, data):
121 _all_pkg = 0
122 for key, value in data['nodes'].iteritems():
123 # add count of packages for this node to total
124 _all_pkg += len(value.keys())
125
126 # count differences
127 data['counters'][key] = {}
128 data['counters'][key]['packages'] = len(value['packages'].keys())
129 data['counters'][key]['package_diff'] = 0
130 for pkg_name, pkg_value in value['packages'].iteritems():
131 if pkg_value['installed'] != pkg_value['candidate']:
132 pkg_value['is_equal'] = False
133 pkg_value['fail_uniq'] = self.is_fail_uniq(
134 pkg_value,
135 pkg_name,
136 data['nodes'],
137 key
138 )
139 data['counters'][key]['package_diff'] += 1
140 else:
141 pkg_value['is_equal'] = True
142 pkg_value['fail_uniq'] = False
143
144 data['counters']['total_packages'] = _all_pkg
145
146
Alex Savatieievd48994d2018-12-13 12:13:00 +0100147# Package versions report
148class HTMLModelCompare(_TMPLBase):
149 tmpl = "model_tree_cmp_tmpl.j2"
150
151 def _extend_data(self, data):
152 # extend data with the compare dict
153
154 # counters - mdl_diff
155 data['counters']['mdl_diff'] = 51
156
157 pass
158
159
savex4448e132018-04-25 15:51:14 +0200160class ReportToFile(object):
161 def __init__(self, report, target):
162 self.report = report
163 self.target = target
164
165 def __call__(self, payload):
166 payload = self.report(payload)
167
168 if isinstance(self.target, six.string_types):
169 self._wrapped_dump(payload)
170 else:
171 self._dump(payload, self.target)
172
173 def _wrapped_dump(self, payload):
174 with open(self.target, 'wt') as target:
175 self._dump(payload, target)
176
177 @staticmethod
178 def _dump(payload, target):
179 target.write(payload)