blob: 377c061bb554eb8dbe1c1aca37913902926c1d86 [file] [log] [blame]
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 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):
self.jinja2_env = self.init_jinja2_env()
@abc.abstractmethod
def __call__(self, payload):
pass
@staticmethod
def init_jinja2_env():
return jinja2.Environment(
loader=jinja2.FileSystemLoader(os.path.join(pkg_dir, 'templates')),
trim_blocks=True,
lstrip_blocks=True)
class _TMPLBase(_Base):
@abc.abstractproperty
def tmpl(self):
pass
@staticmethod
def _count_totals(data):
data['counters']['total_nodes'] = len(data['nodes'])
def __call__(self, payload):
# init data structures
data = self.common_data()
# 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)
# do counts global
self._count_totals(data)
# specific filters
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': {},
'gen_date': time.strftime("%m/%d/%Y %H:%M:%S")
}
def _extend_data(self, data):
pass
# HTML Package versions report
class CSVAllPackages(_TMPLBase):
tmpl = "pkg_versions_csv.j2"
# HTML Package versions report
class HTMLPackageCandidates(_TMPLBase):
tmpl = "pkg_versions_html.j2"
# Package versions report
class HTMLModelCompare(_TMPLBase):
tmpl = "model_tree_cmp_tmpl.j2"
def _extend_data(self, data):
# move names into separate place
data["names"] = data["rc_diffs"].pop("diff_names")
data["tabs"] = data.pop("rc_diffs")
# counters - mdl_diff
for _tab in data["tabs"].keys():
data['counters'][_tab] = len(data["tabs"][_tab]["diffs"].keys())
class HTMLNetworkReport(_TMPLBase):
tmpl = "network_check_tmpl.j2"
class ReportToFile(object):
def __init__(self, report, target):
self.report = report
self.target = target
def __call__(self, payload):
payload = self.report(payload)
if isinstance(self.target, six.string_types):
self._wrapped_dump(payload)
else:
self._dump(payload, self.target)
def _wrapped_dump(self, payload):
with open(self.target, 'wt') as target:
self._dump(payload, target)
@staticmethod
def _dump(payload, target):
target.write(payload)