blob: 8b14a8a35799e5a880d314c58650b700b14a5b0d [file] [log] [blame]
import jinja2
import six
import abc
import os
from check_versions.common import const
pkg_dir = os.path.dirname(__file__)
pkg_dir = os.path.join(pkg_dir, 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 />")
@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, nodes):
# init data structures
data = self.common_data()
data.update({
"nodes": nodes
})
# add template specific data
self._extend_data(data)
# do counts global
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
# render!
tmpl = self.jinja2_env.get_template(self.tmpl)
return tmpl.render(data)
def common_data(self):
return {
'counters': {},
'salt_info': {}
}
def _extend_data(self, data):
pass
# 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):
_all_pkg = 0
for key, value in data['nodes'].iteritems():
# add count of packages for this node to total
_all_pkg += len(value.keys())
# count differences
data['counters'][key] = {}
data['counters'][key]['packages'] = len(value['packages'].keys())
data['counters'][key]['package_diff'] = 0
for pkg_name, pkg_value in value['packages'].iteritems():
if pkg_value['installed'] != pkg_value['candidate']:
pkg_value['is_equal'] = False
pkg_value['fail_uniq'] = self.is_fail_uniq(
pkg_value,
pkg_name,
data['nodes'],
key
)
data['counters'][key]['package_diff'] += 1
else:
pkg_value['is_equal'] = True
pkg_value['fail_uniq'] = False
data['counters']['total_packages'] = _all_pkg
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)