blob: 08015cf118ba9b8c4455ea25ca97f9b04c670182 [file] [log] [blame]
savex4448e132018-04-25 15:51:14 +02001import abc
2import os
Alex41485522019-04-12 17:26:18 -05003import time
savex4448e132018-04-25 15:51:14 +02004
Alex Savatieiev5118de02019-02-20 15:50:42 -06005from cfg_checker.common import const
Alex3ebc5632019-04-18 16:47:18 -05006from cfg_checker.common import logger_cli
7
8import jinja2
9
10import six
savex4448e132018-04-25 15:51:14 +020011
12pkg_dir = os.path.dirname(__file__)
Alex Savatieiev6d010be2019-03-11 10:36:59 -050013pkg_dir = os.path.join(pkg_dir, os.pardir, os.pardir)
savex4448e132018-04-25 15:51:14 +020014pkg_dir = os.path.normpath(pkg_dir)
15
16
savex4448e132018-04-25 15:51:14 +020017def line_breaks(text):
18 # replace python linebreaks with html breaks
19 return text.replace("\n", "<br />")
20
21
Alex41485522019-04-12 17:26:18 -050022def get_sorted_keys(td):
23 # detect if we can sort by desc
24 # Yes, this is slow, but bullet-proof from empty desc
25 _desc = all([bool(td[k]['desc']) for k in td.keys()])
26 # Get sorted list
27 if not _desc:
28 return sorted(td.keys())
29 else:
30 return sorted(
31 td.keys(),
32 key=lambda k: (
33 td[k]['desc']['component'],
34 td[k]['desc']['app'],
35 k
36 )
37 )
38
39
40def get_max(_list):
41 return sorted(_list)[-1]
42
43
44def make_action_label(act):
45 _act_labels = {
46 const.ACT_UPGRADE: "Upgrade possible",
47 const.ACT_NEED_UP: "Needs upgrade",
48 const.ACT_NEED_DOWN: "Needs downgrade",
49 const.ACT_REPO: "Needs repo update",
50 const.ACT_NA: ""
51 }
52 return _act_labels[act]
53
54
55def make_action_class(act):
56 _act_classes = {
57 const.ACT_UPGRADE: "possible",
58 const.ACT_NEED_UP: "needs_up",
59 const.ACT_NEED_DOWN: "needs_down",
60 const.ACT_REPO: "needs_repo",
61 const.ACT_NA: ""
62 }
63 return _act_classes[act]
64
65
66def make_status_label(sts):
67 _status_labels = {
68 const.VERSION_OK: "OK",
69 const.VERSION_UP: "Upgraded",
70 const.VERSION_DOWN: "Downgraded",
71 const.VERSION_ERR: "ERROR",
72 const.VERSION_NA: "N/A"
73 }
74 return _status_labels[sts]
75
76
77def make_status_class(sts):
78 return const.all_statuses[sts]
79
80
savex4448e132018-04-25 15:51:14 +020081@six.add_metaclass(abc.ABCMeta)
82class _Base(object):
83 def __init__(self):
84 self.jinja2_env = self.init_jinja2_env()
85
86 @abc.abstractmethod
87 def __call__(self, payload):
88 pass
89
90 @staticmethod
91 def init_jinja2_env():
92 return jinja2.Environment(
93 loader=jinja2.FileSystemLoader(os.path.join(pkg_dir, 'templates')),
94 trim_blocks=True,
95 lstrip_blocks=True)
96
97
98class _TMPLBase(_Base):
99 @abc.abstractproperty
100 def tmpl(self):
101 pass
102
103 @staticmethod
104 def _count_totals(data):
105 data['counters']['total_nodes'] = len(data['nodes'])
106
Alex Savatieiev36b938d2019-01-21 11:01:18 +0100107 def __call__(self, payload):
savex4448e132018-04-25 15:51:14 +0200108 # init data structures
109 data = self.common_data()
Alex41485522019-04-12 17:26:18 -0500110 # payload should have pre-sorted structure according to report called
111 # nodes, openstack_release, mcp_release, etc...
112 data.update(payload)
savex4448e132018-04-25 15:51:14 +0200113
114 # add template specific data
115 self._extend_data(data)
116
117 # do counts global
118 self._count_totals(data)
119
120 # specific filters
savex4448e132018-04-25 15:51:14 +0200121 self.jinja2_env.filters['linebreaks'] = line_breaks
Alex41485522019-04-12 17:26:18 -0500122 self.jinja2_env.filters['get_max'] = get_max
123
124 self.jinja2_env.filters['get_sorted_keys'] = get_sorted_keys
125 self.jinja2_env.filters['make_status_label'] = make_status_label
126 self.jinja2_env.filters['make_status_class'] = make_status_class
127 self.jinja2_env.filters['make_action_label'] = make_action_label
128 self.jinja2_env.filters['make_action_class'] = make_action_class
savex4448e132018-04-25 15:51:14 +0200129
130 # render!
Alex41485522019-04-12 17:26:18 -0500131 logger_cli.info("-> Using template: {}".format(self.tmpl))
savex4448e132018-04-25 15:51:14 +0200132 tmpl = self.jinja2_env.get_template(self.tmpl)
Alex41485522019-04-12 17:26:18 -0500133 logger_cli.info("-> Rendering")
savex4448e132018-04-25 15:51:14 +0200134 return tmpl.render(data)
135
136 def common_data(self):
137 return {
138 'counters': {},
Alex41485522019-04-12 17:26:18 -0500139 'salt_info': {},
140 'gen_date': time.strftime("%m/%d/%Y %H:%M:%S")
savex4448e132018-04-25 15:51:14 +0200141 }
142
143 def _extend_data(self, data):
144 pass
145
146
Alex41485522019-04-12 17:26:18 -0500147# HTML Package versions report
148class CSVAllPackages(_TMPLBase):
149 tmpl = "pkg_versions_csv.j2"
150
151
152# HTML Package versions report
savexce010ba2018-04-27 09:49:23 +0200153class HTMLPackageCandidates(_TMPLBase):
Alex41485522019-04-12 17:26:18 -0500154 tmpl = "pkg_versions_html.j2"
savex4448e132018-04-25 15:51:14 +0200155
156
Alex Savatieievd48994d2018-12-13 12:13:00 +0100157# Package versions report
158class HTMLModelCompare(_TMPLBase):
159 tmpl = "model_tree_cmp_tmpl.j2"
160
161 def _extend_data(self, data):
Alex Savatieiev36b938d2019-01-21 11:01:18 +0100162 # move names into separate place
Alexb8af13a2019-04-16 18:38:12 -0500163 data["names"] = data["diffs"].pop("diff_names")
164 data["tabs"] = data.pop("diffs")
Alex3ebc5632019-04-18 16:47:18 -0500165
Alex Savatieievd48994d2018-12-13 12:13:00 +0100166 # counters - mdl_diff
Alex Savatieiev4f149d02019-02-28 17:15:29 -0600167 for _tab in data["tabs"].keys():
168 data['counters'][_tab] = len(data["tabs"][_tab]["diffs"].keys())
Alex Savatieievd48994d2018-12-13 12:13:00 +0100169
170
Alex Savatieiev9b2f6512019-02-20 18:05:00 -0600171class HTMLNetworkReport(_TMPLBase):
172 tmpl = "network_check_tmpl.j2"
173
Alex Savatieiev9b2f6512019-02-20 18:05:00 -0600174
savex4448e132018-04-25 15:51:14 +0200175class ReportToFile(object):
176 def __init__(self, report, target):
177 self.report = report
178 self.target = target
179
180 def __call__(self, payload):
181 payload = self.report(payload)
182
183 if isinstance(self.target, six.string_types):
184 self._wrapped_dump(payload)
185 else:
186 self._dump(payload, self.target)
187
188 def _wrapped_dump(self, payload):
189 with open(self.target, 'wt') as target:
190 self._dump(payload, target)
191
192 @staticmethod
193 def _dump(payload, target):
194 target.write(payload)