blob: a624dd3f0784b617cffb935f865505ae165e13c3 [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: (
Alexd0391d42019-05-21 18:48:55 -050033 td[k]['desc']['section'],
Alex41485522019-04-12 17:26:18 -050034 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",
Alex9e4bfaf2019-06-11 15:21:59 -050049 const.ACT_REPO: "Repo update",
Alex41485522019-04-12 17:26:18 -050050 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
Alexd0391d42019-05-21 18:48:55 -050081def make_repo_info(repos):
82 _text = ""
83 for r in repos:
84 # tag
85 _text += r['tag'] + ": "
86 # repo header
87 _text += " ".join([
88 r['subset'],
89 r['release'],
90 r['ubuntu-release'],
91 r['type'],
92 r['arch']
93 ]) + ", "
94 # maintainer w/o email
95 _m = r['maintainer'][:r['maintainer'].find('<')-1]
96 _m_ascii = _m.encode('ascii', errors="xmlcharrefreplace")
97 _text += _m_ascii
98 # newline
99 _text += "<br />"
100 return _text
101
102
savex4448e132018-04-25 15:51:14 +0200103@six.add_metaclass(abc.ABCMeta)
104class _Base(object):
105 def __init__(self):
106 self.jinja2_env = self.init_jinja2_env()
107
108 @abc.abstractmethod
109 def __call__(self, payload):
110 pass
111
112 @staticmethod
113 def init_jinja2_env():
114 return jinja2.Environment(
115 loader=jinja2.FileSystemLoader(os.path.join(pkg_dir, 'templates')),
116 trim_blocks=True,
117 lstrip_blocks=True)
118
119
120class _TMPLBase(_Base):
121 @abc.abstractproperty
122 def tmpl(self):
123 pass
124
125 @staticmethod
126 def _count_totals(data):
127 data['counters']['total_nodes'] = len(data['nodes'])
128
Alex Savatieiev36b938d2019-01-21 11:01:18 +0100129 def __call__(self, payload):
savex4448e132018-04-25 15:51:14 +0200130 # init data structures
131 data = self.common_data()
Alex41485522019-04-12 17:26:18 -0500132 # payload should have pre-sorted structure according to report called
133 # nodes, openstack_release, mcp_release, etc...
134 data.update(payload)
savex4448e132018-04-25 15:51:14 +0200135
136 # add template specific data
137 self._extend_data(data)
138
139 # do counts global
140 self._count_totals(data)
141
142 # specific filters
savex4448e132018-04-25 15:51:14 +0200143 self.jinja2_env.filters['linebreaks'] = line_breaks
Alex41485522019-04-12 17:26:18 -0500144 self.jinja2_env.filters['get_max'] = get_max
145
146 self.jinja2_env.filters['get_sorted_keys'] = get_sorted_keys
147 self.jinja2_env.filters['make_status_label'] = make_status_label
148 self.jinja2_env.filters['make_status_class'] = make_status_class
149 self.jinja2_env.filters['make_action_label'] = make_action_label
150 self.jinja2_env.filters['make_action_class'] = make_action_class
Alexd0391d42019-05-21 18:48:55 -0500151 self.jinja2_env.filters['make_repo_info'] = make_repo_info
savex4448e132018-04-25 15:51:14 +0200152
153 # render!
Alex41485522019-04-12 17:26:18 -0500154 logger_cli.info("-> Using template: {}".format(self.tmpl))
savex4448e132018-04-25 15:51:14 +0200155 tmpl = self.jinja2_env.get_template(self.tmpl)
Alex41485522019-04-12 17:26:18 -0500156 logger_cli.info("-> Rendering")
savex4448e132018-04-25 15:51:14 +0200157 return tmpl.render(data)
158
159 def common_data(self):
160 return {
161 'counters': {},
Alex41485522019-04-12 17:26:18 -0500162 'salt_info': {},
163 'gen_date': time.strftime("%m/%d/%Y %H:%M:%S")
savex4448e132018-04-25 15:51:14 +0200164 }
165
166 def _extend_data(self, data):
167 pass
168
169
Alex41485522019-04-12 17:26:18 -0500170# HTML Package versions report
171class CSVAllPackages(_TMPLBase):
172 tmpl = "pkg_versions_csv.j2"
173
174
175# HTML Package versions report
savexce010ba2018-04-27 09:49:23 +0200176class HTMLPackageCandidates(_TMPLBase):
Alex41485522019-04-12 17:26:18 -0500177 tmpl = "pkg_versions_html.j2"
savex4448e132018-04-25 15:51:14 +0200178
179
Alex Savatieievd48994d2018-12-13 12:13:00 +0100180# Package versions report
181class HTMLModelCompare(_TMPLBase):
182 tmpl = "model_tree_cmp_tmpl.j2"
183
184 def _extend_data(self, data):
Alex Savatieiev36b938d2019-01-21 11:01:18 +0100185 # move names into separate place
Alexb8af13a2019-04-16 18:38:12 -0500186 data["names"] = data["diffs"].pop("diff_names")
187 data["tabs"] = data.pop("diffs")
Alex3ebc5632019-04-18 16:47:18 -0500188
Alex Savatieievd48994d2018-12-13 12:13:00 +0100189 # counters - mdl_diff
Alex Savatieiev4f149d02019-02-28 17:15:29 -0600190 for _tab in data["tabs"].keys():
191 data['counters'][_tab] = len(data["tabs"][_tab]["diffs"].keys())
Alex Savatieievd48994d2018-12-13 12:13:00 +0100192
193
Alex Savatieiev9b2f6512019-02-20 18:05:00 -0600194class HTMLNetworkReport(_TMPLBase):
195 tmpl = "network_check_tmpl.j2"
196
Alex Savatieiev9b2f6512019-02-20 18:05:00 -0600197
savex4448e132018-04-25 15:51:14 +0200198class ReportToFile(object):
199 def __init__(self, report, target):
200 self.report = report
201 self.target = target
202
203 def __call__(self, payload):
204 payload = self.report(payload)
205
206 if isinstance(self.target, six.string_types):
207 self._wrapped_dump(payload)
208 else:
209 self._dump(payload, self.target)
210
211 def _wrapped_dump(self, payload):
212 with open(self.target, 'wt') as target:
213 self._dump(payload, target)
214
215 @staticmethod
216 def _dump(payload, target):
217 target.write(payload)