Merge upstream version
Related-PROD: PROD-28199
Change-Id: I5d9dbde1c3ac577fb30fa5d6b1ff18bcee28a0d7
diff --git a/cfg_checker/reports/reporter.py b/cfg_checker/reports/reporter.py
index e1d6b6f..377c061 100644
--- a/cfg_checker/reports/reporter.py
+++ b/cfg_checker/reports/reporter.py
@@ -1,35 +1,82 @@
-import jinja2
-import six
import abc
+import jinja2
import os
+import six
+import time
from cfg_checker.common import const
+from cfg_checker.common import logger, logger_cli
+from cfg_checker.helpers.console_utils import Progress
pkg_dir = os.path.dirname(__file__)
pkg_dir = os.path.join(pkg_dir, os.pardir, os.pardir)
pkg_dir = os.path.normpath(pkg_dir)
-def shortname(node_fqdn):
- # form shortname out of node fqdn
- return node_fqdn.split(".", 1)[0]
-
-
-def is_equal(pkg_dict):
- # compare versions of given package
- return pkg_dict['installed'] == pkg_dict['candidate']
-
-
-def is_active(node_dict):
- # check node status in node dict
- return node_dict['status'] == const.NODE_UP
-
-
def line_breaks(text):
# replace python linebreaks with html breaks
return text.replace("\n", "<br />")
+def get_sorted_keys(td):
+ # detect if we can sort by desc
+ # Yes, this is slow, but bullet-proof from empty desc
+ _desc = all([bool(td[k]['desc']) for k in td.keys()])
+ # Get sorted list
+ if not _desc:
+ return sorted(td.keys())
+ else:
+ return sorted(
+ td.keys(),
+ key=lambda k: (
+ td[k]['desc']['component'],
+ td[k]['desc']['app'],
+ k
+ )
+ )
+
+
+def get_max(_list):
+ return sorted(_list)[-1]
+
+
+def make_action_label(act):
+ _act_labels = {
+ const.ACT_UPGRADE: "Upgrade possible",
+ const.ACT_NEED_UP: "Needs upgrade",
+ const.ACT_NEED_DOWN: "Needs downgrade",
+ const.ACT_REPO: "Needs repo update",
+ const.ACT_NA: ""
+ }
+ return _act_labels[act]
+
+
+def make_action_class(act):
+ _act_classes = {
+ const.ACT_UPGRADE: "possible",
+ const.ACT_NEED_UP: "needs_up",
+ const.ACT_NEED_DOWN: "needs_down",
+ const.ACT_REPO: "needs_repo",
+ const.ACT_NA: ""
+ }
+ return _act_classes[act]
+
+
+def make_status_label(sts):
+ _status_labels = {
+ const.VERSION_OK: "OK",
+ const.VERSION_UP: "Upgraded",
+ const.VERSION_DOWN: "Downgraded",
+ const.VERSION_ERR: "ERROR",
+ const.VERSION_NA: "N/A"
+ }
+ return _status_labels[sts]
+
+
+def make_status_class(sts):
+ return const.all_statuses[sts]
+
+
@six.add_metaclass(abc.ABCMeta)
class _Base(object):
def __init__(self):
@@ -59,14 +106,9 @@
def __call__(self, payload):
# init data structures
data = self.common_data()
- # payload should have pre-sorted structure
- # system, nodes, clusters, and the rest in other
- data.update({
- "nodes": payload['nodes'],
- "rc_diffs": payload['rc_diffs'],
- "pkg_diffs": payload['pkg_diffs'],
- "tabs": {}
- })
+ # payload should have pre-sorted structure according to report called
+ # nodes, openstack_release, mcp_release, etc...
+ data.update(payload)
# add template specific data
self._extend_data(data)
@@ -75,83 +117,40 @@
self._count_totals(data)
# specific filters
- self.jinja2_env.filters['shortname'] = shortname
- self.jinja2_env.filters['is_equal'] = is_equal
- self.jinja2_env.filters['is_active'] = is_active
self.jinja2_env.filters['linebreaks'] = line_breaks
+ self.jinja2_env.filters['get_max'] = get_max
+
+ self.jinja2_env.filters['get_sorted_keys'] = get_sorted_keys
+ self.jinja2_env.filters['make_status_label'] = make_status_label
+ self.jinja2_env.filters['make_status_class'] = make_status_class
+ self.jinja2_env.filters['make_action_label'] = make_action_label
+ self.jinja2_env.filters['make_action_class'] = make_action_class
# render!
+ logger_cli.info("-> Using template: {}".format(self.tmpl))
tmpl = self.jinja2_env.get_template(self.tmpl)
+ logger_cli.info("-> Rendering")
return tmpl.render(data)
def common_data(self):
return {
'counters': {},
- 'salt_info': {}
+ 'salt_info': {},
+ 'gen_date': time.strftime("%m/%d/%Y %H:%M:%S")
}
def _extend_data(self, data):
pass
-# Package versions report
+# HTML Package versions report
+class CSVAllPackages(_TMPLBase):
+ tmpl = "pkg_versions_csv.j2"
+
+
+# HTML Package versions report
class HTMLPackageCandidates(_TMPLBase):
- tmpl = "pkg_versions_tmpl.j2"
-
- @staticmethod
- def is_fail_uniq(p_dict, p_name, nodes, node_name):
- # look up package fail for nodes with similar role
- _tgroup = nodes[node_name]['node_group']
- # filter all nodes with the same role
- _nodes_list = filter(
- lambda nd: nodes[nd]['node_group'] == _tgroup and nd != node_name,
- nodes
- )
- # lookup same package
- _fail_uniq = False
- for _node_name in _nodes_list:
- # check if there is a package present on node
- _nd = nodes[_node_name]['packages']
- if p_name not in _nd:
- continue
- # if both backages has same version and differ from candidate
- if p_dict['candidate'] == _nd[p_name]['candidate'] \
- and _nd[p_name]['candidate'] == _nd[p_name]['installed']:
- # it is not uniq, mark and break
- _fail_uniq = True
- return _fail_uniq
-
- def _extend_data(self, data):
- # Count values on per-node basis
- for key, value in data['nodes'].iteritems():
- # count differences
- data['counters'][key] = {}
- data['counters'][key]['packages'] = len(value['packages'].keys())
- data['counters'][key]['package_diff'] = 0
- data['counters'][key]['package_eq'] = 0
-
- # Lookup if this fail is uniq for this node
- for pkg_name, pkg_value in value['packages'].iteritems():
- if pkg_value['is_equal']:
- pkg_value['fail_uniq'] = False
- data['counters'][key]['package_eq'] += 1
- else:
- pkg_value['fail_uniq'] = self.is_fail_uniq(
- pkg_value,
- pkg_name,
- data['nodes'],
- key
- )
- data['counters'][key]['package_diff'] += 1
-
- # Count values on all-diffs basis
- for key, value in data['pkg_diffs'].iteritems():
- data['counters'][key] = {}
- data['counters'][key]['df_nodes'] = len(value['df_nodes'].keys())
- data['counters'][key]['eq_nodes'] = len(value['eq_nodes'])
-
- # Save all packages counter
- data['counters']['total_packages'] = data['pkg_diffs'].keys()
+ tmpl = "pkg_versions_html.j2"
# Package versions report
@@ -171,10 +170,6 @@
class HTMLNetworkReport(_TMPLBase):
tmpl = "network_check_tmpl.j2"
- def _extend_data(self, data):
-
- return
-
class ReportToFile(object):
def __init__(self, report, target):