Network check HTML report

- uniform map generation
- POC for additional checks on env

Change-Id: I52edcc94f4d9826cbfb1159e5311514097a15f62
Related-PROD: PROD-32792
diff --git a/cfg_checker/common/const.py b/cfg_checker/common/const.py
index 966f3d3..5826f43 100644
--- a/cfg_checker/common/const.py
+++ b/cfg_checker/common/const.py
@@ -35,7 +35,7 @@
     ACT_NA: ""
 }
 
-all_statuses = {
+all_pkg_statuses = {
     VERSION_OK: "ok",
     VERSION_UP: "upgraded",
     VERSION_DOWN: "downgraded",
@@ -43,6 +43,11 @@
     VERSION_NA: "no status"
 }
 
+node_status = {
+    NODE_UP: "up",
+    NODE_DOWN: "down"
+}
+
 uknown_code = "unk"
 
 all_roles_map = {
diff --git a/cfg_checker/helpers/errors.py b/cfg_checker/helpers/errors.py
index 83ae803..95e1495 100644
--- a/cfg_checker/helpers/errors.py
+++ b/cfg_checker/helpers/errors.py
@@ -102,12 +102,12 @@
         # format message
         _msg = "### {}:\n    Description: {}\n{}".format(
             _code,
-            self._get_error_type_text(self._errors[index]['type']),
+            self.get_error_type_text(self._errors[index]['type']),
             "\n".join(_data)
         )
         return _msg
 
-    def _get_error_type_text(self, err_type):
+    def get_error_type_text(self, err_type):
         if err_type not in self._types:
             raise ErrorMappingException(
                 "type code {} not found".format(err_type)
diff --git a/cfg_checker/modules/network/__init__.py b/cfg_checker/modules/network/__init__.py
index 6b06022..6b9013a 100644
--- a/cfg_checker/modules/network/__init__.py
+++ b/cfg_checker/modules/network/__init__.py
@@ -66,15 +66,6 @@
     return _parser
 
 
-def _prepare_map():
-    _mapper = mapper.NetworkMapper()
-    _mapper.map_network(_mapper.RECLASS)
-    _mapper.map_network(_mapper.RUNTIME)
-    _mapper.map_network(_mapper.CONFIG)
-
-    return _mapper
-
-
 def do_check(args):
     # Net Checks
     # should not print map, etc...
@@ -104,6 +95,10 @@
     _filename = args_utils.get_arg(args, 'html')
 
     netChecker = checker.NetworkChecker()
+    netChecker.check_networks(map=False)
+
+    # save what was collected
+    netChecker.errors.save_iteration_data()
     netChecker.create_html_report(_filename)
 
     return
@@ -114,7 +109,9 @@
     # Should generate network map to console or HTML
     logger_cli.info("# Network report")
 
-    networkMap = _prepare_map()
+    networkMap = mapper.NetworkMapper()
+    networkMap.prepare_all_maps()
+    networkMap.create_map()
     networkMap.print_map()
 
     return
diff --git a/cfg_checker/modules/network/checker.py b/cfg_checker/modules/network/checker.py
index 89db6ba..acd3bb1 100644
--- a/cfg_checker/modules/network/checker.py
+++ b/cfg_checker/modules/network/checker.py
@@ -10,11 +10,13 @@
         self.errors = NetworkErrors()
         self.mapper = NetworkMapper(self.errors)
 
-    def check_networks(self):
+    def check_networks(self, map=True):
         self.mapper.map_network(self.mapper.RECLASS)
         self.mapper.map_network(self.mapper.RUNTIME)
 
-        self.mapper.print_map()
+        self.mapper.create_map()
+        if map:
+            self.mapper.print_map()
 
     def print_summary(self):
         logger_cli.info(self.errors.get_summary(print_zeros=False))
@@ -39,10 +41,10 @@
             filename
         )
         _report({
-            "nodes": self.nodes,
-            "network": {},
-            "mcp_release": self.mcp_release,
-            "openstack_release": self.openstack_release
+            "nodes": self.mapper.nodes,
+            "map": self.mapper.map,
+            "mcp_release": self.mapper.cluster['mcp_release'],
+            "openstack_release": self.mapper.cluster['openstack_release']
 
         })
         logger_cli.info("-> Done")
diff --git a/cfg_checker/modules/network/mapper.py b/cfg_checker/modules/network/mapper.py
index c3e3b73..ba9a256 100644
--- a/cfg_checker/modules/network/mapper.py
+++ b/cfg_checker/modules/network/mapper.py
@@ -36,6 +36,7 @@
         # init networks and nodes
         self.networks = {}
         self.nodes = salt_master.get_nodes()
+        self.cluster = salt_master.get_info()
         # init and pre-populate interfaces
         self.interfaces = {k: {} for k in self.nodes}
         # Init errors class
@@ -45,6 +46,11 @@
             logger_cli.debug("... init error logs folder")
             self.errors = NetworkErrors()
 
+    def prepare_all_maps(self):
+        self.map_network(self.RECLASS)
+        self.map_network(self.RUNTIME)
+        self.map_network(self.CONFIG)
+
     # adding net data to tree
     def _add_data(self, _list, _n, _h, _d):
         if _n not in _list:
@@ -253,32 +259,23 @@
         self.networks[source] = _networks
         return _networks
 
-    def print_map(self):
-        """
-        Create text report for CLI
+    def create_map(self):
+        """Create all needed elements for map output
 
         :return: none
         """
         _runtime = self.networks[self.RUNTIME]
         _reclass = self.networks[self.RECLASS]
-        logger_cli.info("# Networks")
-        logger_cli.info(
-            "    {0:8} {1:25} {2:25} {3:6} {4:10} {5:10} {6}/{7}".format(
-                "Host",
-                "IF",
-                "IP",
-                "Proto",
-                "MTU",
-                "State",
-                "Gate",
-                "Def.Gate"
-            )
-        )
+
+        # main networks, target vars
+        _map = {}
         # No matter of proto, at least one IP will be present for the network
+        # we interested in, since we are to make sure that L3 level
+        # is configured according to reclass model
         for network in _reclass:
             # shortcuts
             _net = str(network)
-            logger_cli.info("-> {}".format(_net))
+            _map[_net] = {}
             if network not in _runtime:
                 # reclass has network that not found in runtime
                 self.errors.add_error(
@@ -290,6 +287,7 @@
             # hostnames
             names = sorted(_runtime[network].keys())
             for hostname in names:
+                _notes = []
                 node = hostname.split('.')[0]
                 if not salt_master.is_node_available(hostname, log=False):
                     logger_cli.info(
@@ -300,9 +298,15 @@
                         self.errors.NET_NODE_NON_RESPONSIVE,
                         host=hostname
                     )
+                    _notes.append(
+                        self.errors.get_error_type_text(
+                            self.errors.NET_NODE_NON_RESPONSIVE
+                        )
+                    )
                     continue
                 # lookup interface name on node using network CIDR
                 _if_name = _runtime[network][hostname][0]["name"]
+                _raw = self.interfaces[hostname][_if_name]['runtime']
                 # get proper reclass
                 _r = self.interfaces[hostname][_if_name]['reclass']
                 _if_name_suffix = ""
@@ -315,6 +319,11 @@
                         host=hostname,
                         if_name=_if_name
                     )
+                    _notes.append(
+                        self.errors.get_error_type_text(
+                            self.errors.NET_NODE_UNEXPECTED_IF
+                        )
+                    )
                     _if_rc = "*"
 
                 if "proto" in _r:
@@ -379,6 +388,11 @@
                                     ip=_ip_str,
                                     gateway=_gate
                                 )
+                                _notes.append(
+                                    self.errors.get_error_type_text(
+                                        self.errors.NET_UNEXPECTED_GATEWAY
+                                    )
+                                )
                                 _gate_error = "*"
 
                         # IF status in reclass
@@ -389,6 +403,11 @@
                                 host=hostname,
                                 if_name=_if_name
                             )
+                            _notes.append(
+                                self.errors.get_error_type_text(
+                                    self.errors.NET_NO_RC_IF_STATUS
+                                )
+                            )
                             _up_error = "*"
 
                         _rc_mtu = _r['mtu'] if 'mtu' in _r else None
@@ -408,6 +427,11 @@
                                         reclass_mtu=_rc_mtu,
                                         runtime_mtu=_host['mtu']
                                     )
+                                    _notes.append(
+                                        self.errors.get_error_type_text(
+                                            self.errors.NET_MTU_MISMATCH
+                                        )
+                                    )
                                     _rc_mtu_s = "/" + _rc_mtu_s
                                     _mtu_error = "*"
                                 else:
@@ -424,48 +448,111 @@
                                     if_cidr=_ip_str,
                                     if_mtu=_host['mtu']
                                 )
+                                _notes.append(
+                                    self.errors.get_error_type_text(
+                                        self.errors.NET_MTU_EMPTY
+                                    )
+                                )
                                 _mtu_error = "*"
                         else:
                             # this is a VIP
                             _if_name = " "*7
                             _if_name_suffix = ""
                             _ip_str += " VIP"
-                        # Host IF IP Proto MTU State Gate Def.Gate
-                        _text = "{:7} {:17} {:25} {:6} {:10} " \
-                                "{:10} {} / {}".format(
-                                    _if_name + _if_rc,
-                                    _if_name_suffix,
-                                    _ip_str,
-                                    _proto,
-                                    _host['mtu'] + _rc_mtu_s + _mtu_error,
-                                    _host['state'] + _up_error,
-                                    _gate + _gate_error,
-                                    _d_gate_str
-                                )
-                        logger_cli.info(
-                            "    {0:8} {1}".format(
-                                node,
-                                _text
+                        # Save all data
+                        _values = {
+                            "interface": _if_name,
+                            "interface_error": _if_rc,
+                            "interface_note": _if_name_suffix,
+                            "ip_address": _ip_str,
+                            "address_type": _proto,
+                            "rt_mtu": _host['mtu'],
+                            "rc_mtu": _rc_mtu_s,
+                            "mtu_error": _mtu_error,
+                            "status": _host['state'],
+                            "status_error": _up_error,
+                            "subnet_gateway": _gate,
+                            "subnet_gateway_error": _gate_error,
+                            "default_gateway": _d_gate_str,
+                            "raw_data": _raw,
+                            "error_note": " and ".join(_notes)
+                        }
+                        if node in _map[_net]:
+                            # add if to host
+                            _map[_net][node].append(_values)
+                        else:
+                            _map[_net][node] = [_values]
+                        _notes = []
+
+        # save map
+        self.map = _map
+        # other runtime networks found
+        # docker, etc
+
+        return
+
+    def print_map(self):
+        """
+        Create text report for CLI
+
+        :return: none
+        """
+        logger_cli.info("# Networks")
+        logger_cli.info(
+            "    {0:8} {1:25} {2:25} {3:6} {4:10} {5:10} {6}/{7}".format(
+                "Host",
+                "IF",
+                "IP",
+                "Proto",
+                "MTU",
+                "State",
+                "Gate",
+                "Def.Gate"
+            )
+        )
+        for network in self.map.keys():
+            logger_cli.info("-> {}".format(network))
+            for hostname in self.map[network].keys():
+                node = hostname.split('.')[0]
+                _n = self.map[network][hostname]
+                for _i in _n:
+                    # Host IF IP Proto MTU State Gate Def.Gate
+                    _text = "{:7} {:17} {:25} {:6} {:10} " \
+                            "{:10} {} / {}".format(
+                                _i['interface'] + _i['interface_error'],
+                                _i['interface_note'],
+                                _i['ip_address'],
+                                _i['address_type'],
+                                _i['rt_mtu'] + _i['rc_mtu'] + _i['mtu_error'],
+                                _i['status'] + _i['status_error'],
+                                _i['subnet_gateway'] +
+                                _i['subnet_gateway_error'],
+                                _i['default_gateway']
                             )
-                        )
-
-        logger_cli.info("\n# Other networks")
-        _other = [n for n in _runtime if n not in _reclass]
-        for network in _other:
-            logger_cli.info("-> {}".format(str(network)))
-            names = sorted(_runtime[network].keys())
-
-            for hostname in names:
-                for _n in _runtime[network][hostname]:
-                    _ifs = [str(ifs.ip) for ifs in _n['ifs']]
-                    _text = "{:25} {:25} {:6} {:10} {}".format(
-                        _n['name'],
-                        ", ".join(_ifs),
-                        "-",
-                        _n['mtu'],
-                        _n['state']
-                    )
                     logger_cli.info(
-                        "    {0:8} {1}".format(hostname.split('.')[0], _text)
+                        "    {0:8} {1}".format(
+                            node,
+                            _text
+                        )
                     )
-        logger_cli.info("\n")
+
+        # logger_cli.info("\n# Other networks")
+        # _other = [n for n in _runtime if n not in _reclass]
+        # for network in _other:
+        #     logger_cli.info("-> {}".format(str(network)))
+        #     names = sorted(_runtime[network].keys())
+
+        #     for hostname in names:
+        #         for _n in _runtime[network][hostname]:
+        #             _ifs = [str(ifs.ip) for ifs in _n['ifs']]
+        #             _text = "{:25} {:25} {:6} {:10} {}".format(
+        #                 _n['name'],
+        #                 ", ".join(_ifs),
+        #                 "-",
+        #                 _n['mtu'],
+        #                 _n['state']
+        #             )
+        #             logger_cli.info(
+        #                 "    {0:8} {1}".format(hostname.split('.')[0], _text)
+        #             )
+        # logger_cli.info("\n")
diff --git a/cfg_checker/nodes.py b/cfg_checker/nodes.py
index 5e535b4..ca4e261 100644
--- a/cfg_checker/nodes.py
+++ b/cfg_checker/nodes.py
@@ -140,6 +140,53 @@
             self.gather_node_info()
         return self.nodes
 
+    def get_info(self):
+        _info = {
+           'mcp_release': self.mcp_release,
+           'openstack_release': self.openstack_release
+        }
+        return _info
+
+    def get_cmd_for_nodes(self, cmd, target_key, target_dict=None):
+        """Function runs. cmd.run and parses result into place
+        or into dict structure provided
+
+        :return: no return value, data pulished internally
+        """
+        logger_cli.debug(
+            "... collecting results for '{}'".format(cmd)
+        )
+        if target_dict:
+            _nodes = target_dict
+        else:
+            _nodes = self.nodes
+        _result = self.execute_cmd_on_active_nodes(cmd)
+        for node, data in _nodes.iteritems():
+            if node in self.skip_list:
+                logger_cli.debug(
+                    "... '{}' skipped while collecting '{}'".format(
+                        node,
+                        cmd
+                    )
+                )
+                continue
+            # Prepare target key
+            if target_key not in data:
+                data[target_key] = None
+            # Save data
+            if data['status'] == const.NODE_DOWN:
+                data[target_key] = None
+            elif not _result[node]:
+                logger_cli.debug(
+                    "... '{}' not responded after '{}'".format(
+                        node,
+                        config.salt_timeout
+                    )
+                )
+                data[target_key] = None
+            else:
+                data[target_key] = _result[node]
+
     def get_specific_pillar_for_nodes(self, pillar_path):
         """Function gets pillars on given path for all nodes
 
@@ -322,6 +369,20 @@
         self.not_responded = [_n for _n in _r.keys() if not _r[_n]]
         return _r
 
+    def execute_cmd_on_active_nodes(self, cmd):
+        # execute cmd
+        self.not_responded = []
+        _r = self.salt.cmd(
+            self.active_nodes_compound,
+            'cmd.run',
+            param=cmd,
+            expr_form="compound"
+        )
+
+        # all false returns means that there is no response
+        self.not_responded = [_n for _n in _r.keys() if not _r[_n]]
+        return _r
+
     def is_node_available(self, node, log=True):
         if node in self.skip_list:
             if log:
diff --git a/cfg_checker/reports/reporter.py b/cfg_checker/reports/reporter.py
index a624dd3..8059fab 100644
--- a/cfg_checker/reports/reporter.py
+++ b/cfg_checker/reports/reporter.py
@@ -4,6 +4,7 @@
 
 from cfg_checker.common import const
 from cfg_checker.common import logger_cli
+from cfg_checker.nodes import salt_master
 
 import jinja2
 
@@ -13,6 +14,12 @@
 pkg_dir = os.path.join(pkg_dir, os.pardir, os.pardir)
 pkg_dir = os.path.normpath(pkg_dir)
 
+# % threshhold values
+_disk_warn = 80
+_disk_critical = 90
+_ram_warn = 5
+_ram_critical = 3
+
 
 def line_breaks(text):
     # replace python linebreaks with html breaks
@@ -41,7 +48,7 @@
     return sorted(_list)[-1]
 
 
-def make_action_label(act):
+def make_pkg_action_label(act):
     _act_labels = {
         const.ACT_UPGRADE: "Upgrade possible",
         const.ACT_NEED_UP: "Needs upgrade",
@@ -52,7 +59,7 @@
     return _act_labels[act]
 
 
-def make_action_class(act):
+def make_pkg_action_class(act):
     _act_classes = {
         const.ACT_UPGRADE: "possible",
         const.ACT_NEED_UP: "needs_up",
@@ -63,7 +70,7 @@
     return _act_classes[act]
 
 
-def make_status_label(sts):
+def make_pkg_status_label(sts):
     _status_labels = {
         const.VERSION_OK: "OK",
         const.VERSION_UP: "Upgraded",
@@ -74,8 +81,12 @@
     return _status_labels[sts]
 
 
-def make_status_class(sts):
-    return const.all_statuses[sts]
+def make_pkg_status_class(sts):
+    return const.all_pkg_statuses[sts]
+
+
+def make_node_status(sts):
+    return const.node_status[sts]
 
 
 def make_repo_info(repos):
@@ -144,10 +155,11 @@
         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
+        self.jinja2_env.filters['pkg_status_label'] = make_pkg_status_label
+        self.jinja2_env.filters['pkg_status_class'] = make_pkg_status_class
+        self.jinja2_env.filters['pkg_action_label'] = make_pkg_action_label
+        self.jinja2_env.filters['pkg_action_class'] = make_pkg_action_class
+        self.jinja2_env.filters['node_status_class'] = make_node_status
         self.jinja2_env.filters['make_repo_info'] = make_repo_info
 
         # render!
@@ -194,6 +206,130 @@
 class HTMLNetworkReport(_TMPLBase):
     tmpl = "network_check_tmpl.j2"
 
+    def _extend_data(self, data):
+        def get_bytes(value):
+            if value[-1] == 'G':
+                return int(float(value[:-1]) * 1024 * 1024 * 1024)
+            elif value[-1] == 'M':
+                return int(float(value[:-1]) * 1024 * 1024)
+            elif value[-1] == 'K':
+                return int(float(value[:-1]) * 1024)
+            else:
+                return int(value)
+
+        def _lscpu(field, key, _dict):
+            _f_cmd = salt_master.get_cmd_for_nodes
+            _cmd = "lscpu | grep -e \"^{}:\" | cut -d\":\" -f2 " \
+                   "| sed -e 's/^[[:space:]]*//'"
+            _f_cmd(_cmd.format(field), key, target_dict=_dict)
+
+        def _free(field, key, _dict):
+            _f_cmd = salt_master.get_cmd_for_nodes
+            _cmd = "free -h | sed -n '/Mem/s/ \\+/ /gp' | cut -d\" \" -f {}"
+            _f_cmd(_cmd.format(field), key, target_dict=_dict)
+
+        def _services(_dict):
+            _key = "services"
+            _key_r = "services_raw"
+            _f_cmd = salt_master.get_cmd_for_nodes
+            _cmd = "service --status-all"
+            _f_cmd(_cmd, _key_r, target_dict=_dict)
+            for node, dt in _dict.iteritems():
+                dt[_key] = {}
+                lines = dt[_key_r].splitlines()
+                for line in lines:
+                    li = line.split()
+                    _status = li[1]
+                    _name = li[3]
+                    if _status == '-':
+                        dt[_key][_name] = False
+                    elif _status == '+':
+                        dt[_key][_name] = True
+                    else:
+                        dt[_key][_name] = None
+                dt.pop(_key_r)
+
+        data["const"] = {
+            "ram_warn": _ram_warn,
+            "ram_critical": _ram_critical,
+            "disk_warn": _disk_warn,
+            "disk_critical": _disk_critical
+        }
+
+        # get kernel version
+        salt_master.get_cmd_for_nodes(
+            "uname -r",
+            "kernel",
+            target_dict=data["nodes"]
+        )
+        # cpu info
+        # Sample: VT-x, KVM, full
+        _lscpu("Virtualization", "virt_mode", data["nodes"])
+        _lscpu("Hypervisor vendor", "virt_vendor", data["nodes"])
+        _lscpu("Virtualization type", "virt_type", data["nodes"])
+        # sample: 4
+        _lscpu("CPU(s)", "cpus", data["nodes"])
+
+        # free ram
+        # sample: 16425392 14883144 220196
+        _free("2", "ram_total", data["nodes"])
+        _free("3", "ram_used", data["nodes"])
+        _free("4", "ram_free", data["nodes"])
+        _free("7", "ram_available", data["nodes"])
+        for _data in data["nodes"].itervalues():
+            _total = get_bytes(_data["ram_total"])
+            _avail = get_bytes(_data["ram_available"])
+            _m = _avail * 100.0 / _total
+            if _m < _ram_critical:
+                _data["ram_status"] = "fail"
+            elif _m < _ram_warn:
+                _data["ram_status"] = "warn"
+            else:
+                _data["ram_status"] = ""
+
+        # disk space
+        # sample: /dev/vda1 78G 33G 45G 43%
+        salt_master.get_cmd_for_nodes(
+            "df -h | sed -n '/^\\/dev/s/ \\+/ /gp' | cut -d\" \" -f 1-5",
+            "disk_raw",
+            target_dict=data["nodes"]
+        )
+        for _data in data["nodes"].itervalues():
+            _data["disk"] = {}
+            # show first device row by default
+            _data["disk_max_dev"] = None
+            _d = _data["disk"]
+            _r = _data["disk_raw"]
+            _r = _r.splitlines()
+            _max = -1
+            for idx in range(0, len(_r)):
+                _t = _r[idx].split()
+                _d[_t[0]] = {}
+                _d[_t[0]]['v'] = _t[1:]
+                _chk = int(_t[-1].split('%')[0])
+                if _chk > _max:
+                    _data["disk_max_dev"] = _t[0]
+                    _max = _chk
+                if _chk > _disk_critical:
+                    _d[_t[0]]['f'] = "fail"
+                elif _chk > _disk_warn:
+                    _d[_t[0]]['f'] = "warn"
+                else:
+                    _d[_t[0]]['f'] = ""
+
+        # prepare networks data for report
+        for net, net_v in data['map'].iteritems():
+            for node, ifs in net_v.iteritems():
+                for d in ifs:
+                    _err = "fail"
+                    d['interface_error'] = _err if d['interface_error'] else ""
+                    d['mtu_error'] = _err if d['mtu_error'] else ""
+                    d['status_error'] = _err if d['status_error'] else ""
+                    d['subnet_gateway_error'] = \
+                        _err if d['subnet_gateway_error'] else ""
+
+        _services(data["nodes"])
+
 
 class ReportToFile(object):
     def __init__(self, report, target):
diff --git a/scripts/sniffer.py b/scripts/sniffer.py
index 612ff20..9b6830c 100644
--- a/scripts/sniffer.py
+++ b/scripts/sniffer.py
@@ -112,23 +112,27 @@
 
 s = socket.socket(socket.PF_PACKET, socket.SOCK_RAW, socket.ntohs(0x0800))
 u = unpack()
-count = 5
+count = 32
 while count > 0:
     count -= 1
     # Capture packets from network
     pkt = s.recvfrom(65565)
 
-    print "\n\n===&gt;&gt; [+] ------------ Ethernet Header----- [+]"
+    print "\n\n=== [+] ------------ Ethernet Header----- [+]"
 
     # print data on terminal
     for i in u.eth_header(pkt[0][0:14]).iteritems():
         a, b = i
         print "{} : {} | ".format(a, b),
-    print "\n===&gt;&gt; [+] ------------ IP Header ------------[+]"
+    print "\n=== [+] ------------ IP Header ------------[+]"
     for i in u.ip_header(pkt[0][14:34]).iteritems():
         a, b = i
         print "{} : {} | ".format(a, b),
-    print "\n===&gt;&gt; [+] ------------ Tcp Header ----------- [+]"
+    print "\n== [+] ------------ Tcp Header ----------- [+]"
     for i in u.tcp_header(pkt[0][34:54]).iteritems():
         a, b = i
         print "{} : {} | ".format(a, b),
+    print "\n===== Data ===="
+    print pkt[0][54:]
+    print "\n======="
+    print pkt[1:]
diff --git a/setup.py b/setup.py
index 0659294..9c9fbf1 100644
--- a/setup.py
+++ b/setup.py
@@ -33,8 +33,8 @@
 
 
 setup(
-    name="Mirantis Cloud Configuration Checker",
-    version="0.4",
+    name="mcp-checker",
+    version="0.41a",
     author="Alex Savatieiev",
     author_email="osavatieiev@mirantis.com",
     classifiers=[
diff --git a/templates/network_check_tmpl.j2 b/templates/network_check_tmpl.j2
index 9f0f556..c26a115 100644
--- a/templates/network_check_tmpl.j2
+++ b/templates/network_check_tmpl.j2
@@ -14,30 +14,176 @@
     
         /* Node rows*/
 		.node {
+			font-family: "LaoSangamMN", Monaco, monospace;
+			font-size: 0.8em;
 			display: inline-block;
 			background-color: white;
 		}
+		.collapsable {
+			font-family: "LaoSangamMN", Monaco, monospace;
+			font-size: 0.8em;
+			display: none;
+            background-color: white;
+            visibility: hidden;
+        }
+        .collapsable.in {
+            visibility: visible;
+            display: inline-block;
+        }
+
+        div.services > .collapsable.in {
+            display: table-row;
+        }
 		
-        tr.node > td {
+        tr.node > td, tr.collapsable > td {
             display: block;
             float: left;
             padding: 1px;
-            padding-left: 5px;
-            padding-right: 5px;
-            color: black;
-            background-color: #A1BbA1;
-            text-align: center;
             margin: 2px;
         }
-        
-        .meters {
-			display: inline-block;        
+        td > .disk_group {
+            display: grid;
+            grid-template-columns: auto auto auto auto auto;
+            padding-left: 0px;
+            padding-right: 0px;
+            margin: 1px;
         }
+        td > .ram_group {
+            display: grid;
+            grid-template-columns: auto auto auto auto;
+            padding-left: 0px;
+            padding-right: 0px;
+            margin: 1px;
+        }
+        td > .vcpu_group {
+            display: grid;
+            grid-template-columns: auto;
+            padding-left: 0px;
+            padding-right: 0px;
+            margin: 1px;
+        }
+
+        .item {
+        	display: inline-grid;
+  			border-width: 1px;
+			border-style: solid;
+			margin: 1px 1px 1px 1px;
+            padding: 0px 1px 0px 1px;
+        }
+
+	    .status_none { border-radius: 10px; width: 8px; }
+	    .status_up { border-radius: 10px; width: 8px; background-color: #393; color: #393; }
+	    .status_down { border-radius: 10px; width: 8px; background-color: #933; color: #933; }
         
-        td.meters > .meter {
+        .head { height: 18px; }
+	    .col_name {	width: 250px; }
+	    .col_role {	width: 150px; }
+	    .col_vendor { width: 100px; }
+        .col_release { width: 100px; }
+        .col_kernel { min-width: 100px; }
+        .col_vcpu { min-width: 40px; }
+        .col_ram { min-width: 150px; }
+        .col_disk { min-width: 200px; }
+        
+        .col_notes { width: 618px; }
+        .meters {
+            display: inline-block;
+            margin: 1px;
+        }
+        .meters > .meter {
             display: block;
             float: left;
+  			border-width: 1px;
+			border-style: solid;
+			margin: 0px 1px 0px 1px;
+            padding: 0px 1px 0px 1px;
+            
         }
+        .meters > .ok, .disk_group > .ok, .ram_group > .ok{
+			border-color: #80a080;
+			background-color: #efe;
+        }
+        .meters > .warn, .disk_group > .warn, .ram_group > .warn {
+			border-color: #d3a200;
+			background-color: rgb(255, 216, 133);
+        }
+        .meters > .fail, .disk_group > .fail, .ram_group > .fail {
+			border-color: #bb0000;
+			background-color: rgb(250, 135, 135);
+        }
+        .cpu { border-color: #a0c0a0; background-color: rgb(252, 248, 248); }
+        .ram { border-color: #c0c0a0; background-color: rgb(255, 255, 251); }
+        .disk { border-color: #cedfdf; background-color: rgb(237, 241, 243); }
+
+        .map_grid {
+            display: grid;
+            grid-template-columns: auto auto auto auto auto auto auto auto auto auto;
+            grid-column-gap: 20px;
+            padding-left: 0px;
+            padding-right: 0px;
+            margin: 1px;
+            margin-left: 20px;
+
+        }
+        .map_item {
+        	display: inline-grid;
+            border-width: 0px;
+			border-style: solid;
+			margin: 1px 1px 1px 1px;
+            padding: 0px 1px 0px 1px;
+        }
+
+        .map_grid > .ok {
+            color: #80a080;
+        }
+        .map_grid > .warn {
+            color: #d3a200;
+        }
+        .map_grid > .fail {
+            color: #bb0000;
+        }
+
+        .services {
+			font-family: "LaoSangamMN", Monaco, monospace;
+			font-size: 1.1em;
+			background-color: white;
+        }
+        .service_node {
+            background-color: #ddd;
+            margin-bottom: 2px;
+        }
+        .service_grid {
+            display: grid;
+            grid-template-columns: repeat(8, auto);
+            grid-template-rows: repeat(10, auto);
+            grid-auto-flow: column;
+            grid-column-gap: 20px;
+            padding-left: 0px;
+            padding-right: 0px;
+            margin: 1px;
+            margin-left: 20px;
+          }
+        .service {
+            display: inline-grid;
+            text-align: center;
+            border-width: 0px;
+			border-style: solid;
+			margin: 1px 1px 1px 1px;
+            padding: 0px 1px 0px 1px;
+            min-width: 150px;
+            border-radius: 10px;
+        }
+
+        .service_grid > .on {
+            background-color: #8c8;
+        }
+        .service_grid > .off {
+            background-color: #9aa;
+        }
+        .service_grid > .fail {
+            background-color: rgb(250, 135, 135);
+        }
+
     </style>
 </head>
 <body onload="init()">
@@ -47,6 +193,10 @@
     <div class="text">{{ openstack_release }}</div>
     <div class="label">MCP Version:</div>
     <div class="text">{{ mcp_release }}</div>
+    <div class="label">RAM % Warning/Critical:</div>
+    <div class="text">{{ const['ram_warn'] }}/{{ const['ram_critical'] }}</div>
+    <div class="label">Disk % Warning/Critical:</div>
+    <div class="text">{{ const['disk_warn'] }}/{{ const['disk_critical'] }}</div>
     <div class="label date">generated on: {{ gen_date }}</div>
 </div>
 
@@ -61,16 +211,84 @@
     <h5>{{ caller() }}</h5>
     <hr>
     <table class="cluster_nodes">
+        <tr class="node">
+            <td class="status_none"></td>
+            <td class="head col_name">Name</td>
+            <td class="head col_role">Role</td>
+            <td class="head col_vendor">Virtual</td>
+            <td class="head col_release">Linux</td>
+            <td class="head col_kernel">Kernel</td>
+
+            <td class="head col_vcpu">
+                <div class="meters vcpu">
+                    <div class="meter cpu">vCPU</div>
+                </div>
+            </td>
+            <td class="head col_ram">
+                <div class="meters">
+                    <div class="meter ram">Total</div>
+                    <div class="meter ram">Used</div>
+                    <div class="meter ram">Free</div>
+                    <div class="meter ram">Available</div>
+                </div>
+            </td>
+            <td class="head col_disk">
+                <div class="meters">
+                    <div class="meter disk">device</div>
+                    <div class="meter disk">total</div>
+                    <div class="meter disk">used</div>
+                    <div class="meter disk">free</div>
+                    <div class="meter disk">percent</div>
+                </div>
+            </td>
+        </tr>
     {% for node in nodes.keys() | sort %}
         {% set _ndat = nodes[node] %}
-        <tr class="node virt">
-            <td class="status">{{ _ndat['status'] }}</td>
-            <td class="name">{{ node }}</td>
-            <td class="role">{{ _ndat['role'] }}</td>
-            <td class="vendor">QEMU</td>
-            <td class="meter cpu">vCPU: 12</td>
-            <td class="meter ram">RAM: 500GB</td>
-            <td class="meter disk">VDA: 150/140/135</td>
+        <tr class="node" onclick="toggleClassByID('info_{{ node }}')" id='info_{{ node }}_button'>
+            <td class="status_{{ _ndat['status'] | node_status_class }}">.</td>
+            <td class="head col_name">{{ node }}</td>
+            <td class="head col_role">{{ _ndat['role'] }}</td>
+            <td class="head col_vendor">{{ _ndat['virt_vendor'] }}/{{ _ndat['virt_mode'] }}/{{ _ndat['virt_type'] }}</td>
+            <td class="head col_release">{{ _ndat['linux_arch'] }}/{{ _ndat['linux_codename'] }}</td>
+            <td class="head col_kernel">{{ _ndat['kernel'] }}</td>
+            <td class="head col_vcpu">
+                <div class="meters vcpu">
+                    <div class="meter cpu">{{ _ndat['cpus'] }}</div>
+                </div>
+            </td>
+            <td class="head col_ram">
+                <div class="ram_group">
+                    <div class="item ram">{{ _ndat['ram_total'] }}</div>
+                    <div class="item ram">{{ _ndat['ram_used'] }}</div>
+                    <div class="item ram">{{ _ndat['ram_free'] }}</div>
+                    <div class="item ram {{ _ndat['ram_status'] }}">{{ _ndat['ram_available'] }}</div>
+                </div>
+            </td>
+            <td class="head col_disk">
+                <div class="disk_group">
+                    <div class="item disk">{{ _ndat['disk_max_dev'] }}</div>
+                    {% for val in _ndat['disk'][_ndat['disk_max_dev']]['v'] %}
+                    <div class="item disk {{ _ndat['disk'][_ndat['disk_max_dev']]['f'] }}">{{ val }}</div>
+                    {% endfor %}
+                </div>
+            </td>
+        </tr>
+        <tr class="collapsable" id="info_{{ node }}">
+            <td class="status_none"></td>
+            <td class="col_notes" colspan="4">.</td>
+            <td class="col_kernel"></td>
+            <td class="col_vcpu"></td>
+            <td class="col_ram"></td>
+            <td class="col_disk">
+                <div class="disk_group">
+                    {% for dev in _ndat['disk'].keys() | sort %}
+                    <div class="item disk">{{ dev }}</div>
+                    {% for val in _ndat['disk'][dev]['v'] %}
+                    <div class="item disk {{ _ndat['disk'][dev]['f'] }}">{{ val }}</div>
+                    {% endfor %}
+                    {% endfor %}
+                </div>
+            </td>
         </tr>
     {% endfor %}
     </table>
@@ -83,13 +301,29 @@
     <h5>{{ caller() }}</h5>
     <hr>
     <table class="networks">
-        <tr class="subnet">192.168.10.0/24</tr>
-        <tr class="net collapsable">
-            <td class="status">UP</td>
-            <td class="name">cfg01.internal.net</td>
-            <td class="ip">192.168.10.11</td>
-            <td class="param">1500</td>
+        {% for net in map.keys() %}
+        <tr class="subnet" onclick="toggleClassByID('net_{{ net }}')" id="{{ net }}_net_button">
+            <td>{{ net }}</td>
         </tr>
+        <tr class="collapsable" id="net_{{ net }}"><td>
+            <div class="map_grid">
+        {% for node in map[net].keys() | sort %}
+        {% for d in map[net][node] %}
+                <div class="map_item name">{{ node }}</div>
+                <div class="map_item interface {{ d['interface_error'] }}">{{ d['interface'] }}</div>
+                <div class="map_item note">{{ d['interface_note'] }}</div>
+                <div class="map_item ipaddr">{{ d['ip_address'] }}</div>
+                <div class="map_item ipaddr_type">{{ d['address_type'] }}</div>
+                <div class="map_item mtu {{ d['mtu_error'] }}">{{ d['rt_mtu'] }}</div>
+                <div class="map_item status {{ d['status_error'] }}">{{ d['status'] }}</div>
+                <div class="map_item gate {{ d['subnet_gateway_error'] }}">{{ d['subnet_gateway'] }}</div>
+                <div class="map_item gate">{{ d['default_gateway'] }}</div>
+                <div class="map_item error_note">{{ d['error_note'] }}</div>
+        {% endfor %}
+        {% endfor %}
+            </div>
+        </td></tr>
+        {% endfor %}
     </table>
     <hr>
 </div>
@@ -99,6 +333,23 @@
 <div id="{{ id_label }}" class="barcontent">
     <h5>{{ caller() }}</h5>
     <hr>
+    <div class="services">
+            {% for node in nodes.keys() | sort %}
+            <div class="service_node" onclick="toggleClassByID('svc_{{ node }}')" id="svc_{{ node }}_button">{{ node }}</div>
+            <div class="collapsable" id="svc_{{ node }}">
+                <div class="service_grid">
+            {% for service in nodes[node]['services'].keys() | sort -%}            
+                {% if nodes[node]['services'][service] %}
+                    <div class="service name on">{{ service }}</div>
+                {% else %}
+                    <div class="service name off">{{ service }}</div>
+                {% endif %}
+            {% endfor %}
+                </div>
+            </div>
+            {% endfor %}
+    </div>
+    <hr>
 </div>
 {% endmacro %}
 
diff --git a/templates/pkg_versions_csv.j2 b/templates/pkg_versions_csv.j2
index c754f63..a6690a9 100644
--- a/templates/pkg_versions_csv.j2
+++ b/templates/pkg_versions_csv.j2
@@ -5,7 +5,7 @@
         {% for action in p['results'][status].keys() | sort(reverse=true) %}
             {% for node in p['results'][status][action].keys() | sort %}
                 {% set nd = p['results'][status][action][node] %}
-{{ id_label }},{{ pkg_name }},{{ node }},{{ status | make_status_label }},{{ action | make_action_label }},{{ nd['i'].version }},{{ nd['c'].version }},{{ p['r'].version }}
+{{ id_label }},{{ pkg_name }},{{ node }},{{ status | pkg_status_label }},{{ action | pkg_action_label }},{{ nd['i'].version }},{{ nd['c'].version }},{{ p['r'].version }}
             {% endfor %}
         {% endfor %}
         {% endfor %}
diff --git a/templates/pkg_versions_html.j2 b/templates/pkg_versions_html.j2
index 91b21e7..aaedcbc 100644
--- a/templates/pkg_versions_html.j2
+++ b/templates/pkg_versions_html.j2
@@ -142,13 +142,13 @@
 {% macro prettify_version(v) %}
     <div class="version">
         {% if v.epoch %}
-        <div class="v_epoch {{ v.epoch_status | make_status_class }}">{{ v.epoch }}</div>
+        <div class="v_epoch {{ v.epoch_status | pkg_status_class }}">{{ v.epoch }}</div>
         <div class="colon">:</div>
         {% endif %}
-        <div class="v_upstream {{ v.upstream_status | make_status_class }}">{{ v.upstream }}{{ v.upstream_rev }}</div>
+        <div class="v_upstream {{ v.upstream_status | pkg_status_class }}">{{ v.upstream }}{{ v.upstream_rev }}</div>
         {% if v.debian %}
         <div class="dash">-</div>
-        <div class="v_debian {{ v.debian_status | make_status_class }}">{{ v.debian }}{{ v.debian_rev }}</div>
+        <div class="v_debian {{ v.debian_status | pkg_status_class }}">{{ v.debian }}{{ v.debian_rev }}</div>
         {% endif %}
         {{ caller() }}
     </div>
@@ -161,9 +161,9 @@
             <td class="app">{{ dat['desc']['app'] }}</td>
             <td class="package_name">{{ pkg_name }}</td>
             <td class="status_container" colspan="3">
-                <div class="status {{ status_shown | make_status_class }}">{{ status_shown | make_status_label }}</div>
-                {% if action_shown | make_action_label %}
-                    <div class="action {{ action_shown | make_action_class }}">{{ action_shown | make_action_label }}</div>
+                <div class="status {{ status_shown | pkg_status_class }}">{{ status_shown | pkg_status_label }}</div>
+                {% if action_shown | pkg_action_label %}
+                    <div class="action {{ action_shown | pkg_action_class }}">{{ action_shown | pkg_action_label }}</div>
                 {% endif %}
             </td>
         </tr>
@@ -179,9 +179,9 @@
             <td class="repo">{{ n_counter }}</td>
             <td class="node_name">{{ node }}</td>
             <td class="status_container">
-                <div class="status {{ status | make_status_class }}">{{ status | make_status_label }}</div>
-                {% if action | make_action_label %}
-                    <div class="action {{ action | make_action_class }}">{{ action | make_action_label }}</div>
+                <div class="status {{ status | pkg_status_class }}">{{ status | pkg_status_label }}</div>
+                {% if action | pkg_action_label %}
+                    <div class="action {{ action | pkg_action_class }}">{{ action | pkg_action_label }}</div>
                 {% endif %}
             </td>
             <td class="installed">
@@ -195,7 +195,7 @@
             <td class="release">
                 <div class="tooltip">
                     {{ dat['r'].version }}
-                    <pre class="repoinfotext">{{ dat['repos'] | make_repo_info }}</pre>
+                    <pre class="repoinfotext">{{ dat['repos'] | pkg_repo_info }}</pre>
                 </div>
             </td>
         </tr>
@@ -295,13 +295,13 @@
 		<tr>
 			<td width="50%">
 				<div class="status_container">
-					<div class="status {{ cs.ok | make_status_class }}">{{ cs.ok | make_status_label }}</div>
+					<div class="status {{ cs.ok | pkg_status_class }}">{{ cs.ok | pkg_status_label }}</div>
 					<div class="text">Installed and Candidate epoch:upstream version mach</div>
 				</div>
 			</td>
 			<td width="50%">
 				<div class="status_container">
-					<div class="action {{ ca.na | make_action_class }}">{{ ca.na | make_action_label }} (no action)</div>
+					<div class="action {{ ca.na | pkg_action_class }}">{{ ca.na | pkg_action_label }} (no action)</div>
 					<div class="text">No action suggested</div>
 				</div>
 			</td>
@@ -309,13 +309,13 @@
 		<tr>
 			<td width="50%">
 				<div class="status_container">
-					<div class="status {{ cs.up | make_status_class }}">{{ cs.up | make_status_label }}</div>
+					<div class="status {{ cs.up | pkg_status_class }}">{{ cs.up | pkg_status_label }}</div>
 					<div class="text">Installed version is newer that the one found in Repo (i.e. candidate) or Release notes recordset</div>
 				</div>
 			</td>
 			<td width="50%">
 				<div class="status_container">
-					<div class="action {{ ca.up | make_action_class }}">{{ ca.up | make_action_label }}</div>
+					<div class="action {{ ca.up | pkg_action_class }}">{{ ca.up | pkg_action_label }}</div>
 					<div class="text">There is an upgrade possible for the package. But it is not strictly required action</div>
 				</div>
 			</td>
@@ -323,13 +323,13 @@
 		<tr>
 			<td width="50%">
 				<div class="status_container">
-					<div class="status {{ cs.down | make_status_class }}">{{ cs.down | make_status_label }}</div>
+					<div class="status {{ cs.down | pkg_status_class }}">{{ cs.down | pkg_status_label }}</div>
 					<div class="text">Installed version is older that the one found in Repo (i.e. candidate) or Release notes recordset</div>
 				</div>
 			</td>
 			<td width="50%">
 				<div class="status_container">
-					<div class="action {{ ca.need_up | make_action_class }}">{{ ca.need_up | make_action_label }}</div>
+					<div class="action {{ ca.need_up | pkg_action_class }}">{{ ca.need_up | pkg_action_label }}</div>
 					<div class="text">Package should be upgraded to match version either in repo or in Release notes</div>
 				</div>
 			</td>
@@ -337,13 +337,13 @@
 		<tr>
 			<td width="50%">
 				<div class="status_container">
-					<div class="status {{ cs.err | make_status_class }}">{{ cs.err | make_status_label }}</div>
+					<div class="status {{ cs.err | pkg_status_class }}">{{ cs.err | pkg_status_label }}</div>
 					<div class="text">Installed version conflicts with a combination of Candidate and Release notes versions</div>
 				</div>
 			</td>
 			<td width="50%">
 				<div class="status_container">
-					<div class="action {{ ca.need_down | make_action_class }}">{{ ca.need_down | make_action_label }}</div>
+					<div class="action {{ ca.need_down | pkg_action_class }}">{{ ca.need_down | pkg_action_label }}</div>
 					<div class="text">Package should be downgraded to match version either in repo or in Release notes</div>
 				</div>
 			</td>
@@ -353,7 +353,7 @@
 			</td>
 			<td width="50%">
 				<div class="status_container">
-					<div class="action {{ ca.repo | make_action_class }}">{{ ca.repo | make_action_label }}</div>
+					<div class="action {{ ca.repo | pkg_action_class }}">{{ ca.repo | pkg_action_label }}</div>
 					<div class="text">Repo that is configured on the target node contains invalid version and should be updated</div>
 				</div>
 			</td>
@@ -362,55 +362,55 @@
     <hr>
     <h5>Versions status and Action combinations</h5>
     <div class="status_container">
-        <div class="status {{ cs.ok | make_status_class }}">{{ cs.ok | make_status_label }}</div>
-        <div class="action {{ ca.na | make_action_class }}">{{ ca.na | make_action_label }} (no action)</div>
+        <div class="status {{ cs.ok | pkg_status_class }}">{{ cs.ok | pkg_status_label }}</div>
+        <div class="action {{ ca.na | pkg_action_class }}">{{ ca.na | pkg_action_label }} (no action)</div>
         <div class="text">All versions are inline with each other</div>
     </div>
     <div class="status_container">
-        <div class="status {{ cs.up | make_status_class }}">{{ cs.up | make_status_label }}</div>
-        <div class="action {{ ca.na | make_action_class }}">{{ ca.na | make_action_label }} (no action)</div>
+        <div class="status {{ cs.up | pkg_status_class }}">{{ cs.up | pkg_status_label }}</div>
+        <div class="action {{ ca.na | pkg_action_class }}">{{ ca.na | pkg_action_label }} (no action)</div>
         <div class="text">Installed version is newer that Cadidate, Release version - unknown or not tracked</div>
     </div>
     <div class="status_container">
-        <div class="status {{ cs.ok | make_status_class }}">{{ cs.ok | make_status_label }}</div>
-        <div class="action {{ ca.up | make_action_class }}">{{ ca.up | make_action_label }}</div>
+        <div class="status {{ cs.ok | pkg_status_class }}">{{ cs.ok | pkg_status_label }}</div>
+        <div class="action {{ ca.up | pkg_action_class }}">{{ ca.up | pkg_action_label }}</div>
         <div class="text">Installed version is equal to Release, but there is newer in the repo</div>
     </div>
     <div class="status_container">
-        <div class="status {{ cs.up | make_status_class }}">{{ cs.up | make_status_label }}</div>
-        <div class="action {{ ca.up | make_action_class }}">{{ ca.up | make_action_label }}</div>
+        <div class="status {{ cs.up | pkg_status_class }}">{{ cs.up | pkg_status_label }}</div>
+        <div class="action {{ ca.up | pkg_action_class }}">{{ ca.up | pkg_action_label }}</div>
         <div class="text">Installed version is newer than Release, and there is even newer in the repo</div>
     </div>
     <div class="status_container">
-        <div class="status {{ cs.err | make_status_class }}">{{ cs.err | make_status_label }}</div>
-        <div class="action {{ ca.need_up | make_action_class }}">{{ ca.need_up | make_action_label }}</div>
+        <div class="status {{ cs.err | pkg_status_class }}">{{ cs.err | pkg_status_label }}</div>
+        <div class="action {{ ca.need_up | pkg_action_class }}">{{ ca.need_up | pkg_action_label }}</div>
         <div class="text">Installed version is older than Candidate and Release versions and must be upgraded</div>
     </div>
     <div class="status_container">
-        <div class="status {{ cs.err | make_status_class }}">{{ cs.err | make_status_label }}</div>
-        <div class="action {{ ca.need_down | make_action_class }}">{{ ca.need_down | make_action_label }}</div>
+        <div class="status {{ cs.err | pkg_status_class }}">{{ cs.err | pkg_status_label }}</div>
+        <div class="action {{ ca.need_down | pkg_action_class }}">{{ ca.need_down | pkg_action_label }}</div>
         <div class="text">Unknown version installed, Release and Candidate versions are older</div>
     </div>
     <div class="status_container">
-        <div class="status {{ cs.err | make_status_class }}">{{ cs.err | make_status_label }}</div>
-        <div class="action {{ ca.repo | make_action_class }}">{{ ca.repo | make_action_label }}</div>
+        <div class="status {{ cs.err | pkg_status_class }}">{{ cs.err | pkg_status_label }}</div>
+        <div class="action {{ ca.repo | pkg_action_class }}">{{ ca.repo | pkg_action_label }}</div>
         <div class="text">Installed and Candidate versions is older than release and repo must be updated</div>
     </div>
 
     <div class="status_container">
-        <div class="status {{ cs.up | make_status_class }}">{{ cs.up | make_status_label }}</div>
-        <div class="action {{ ca.repo | make_action_class }}">{{ ca.repo | make_action_label }}</div>
+        <div class="status {{ cs.up | pkg_status_class }}">{{ cs.up | pkg_status_label }}</div>
+        <div class="action {{ ca.repo | pkg_action_class }}">{{ ca.repo | pkg_action_label }}</div>
         <div class="text">Candidate version in repo is older vs Release and both older vs Installed</div>
     </div>
     <div class="status_container">
-        <div class="status {{ cs.ok | make_status_class }}">{{ cs.ok | make_status_label }}</div>
-        <div class="action {{ ca.repo | make_action_class }}">{{ ca.repo | make_action_label }}</div>
+        <div class="status {{ cs.ok | pkg_status_class }}">{{ cs.ok | pkg_status_label }}</div>
+        <div class="action {{ ca.repo | pkg_action_class }}">{{ ca.repo | pkg_action_label }}</div>
         <div class="text">Candidate version in Repo is older vs release, but release version installed</div>
     </div>
     
     <div class="status_container">
-        <div class="status {{ cs.down | make_status_class }}">{{ cs.down | make_status_label }}</div>
-        <div class="action {{ ca.repo | make_action_class }}">{{ ca.repo | make_action_label }}</div>
+        <div class="status {{ cs.down | pkg_status_class }}">{{ cs.down | pkg_status_label }}</div>
+        <div class="action {{ ca.repo | pkg_action_class }}">{{ ca.repo | pkg_action_label }}</div>
         <div class="text">Both Candidate in repo and Installed older vs release</div>
     </div>
     <div class="status_container">
diff --git a/versions/repo.versions.tgz b/versions/repo.versions.tgz
index ea020f3..00c36f0 100644
--- a/versions/repo.versions.tgz
+++ b/versions/repo.versions.tgz
Binary files differ