Merge upstream version

Related-PROD: PROD-28199

Change-Id: I5d9dbde1c3ac577fb30fa5d6b1ff18bcee28a0d7
diff --git a/templates/common_scripts.j2 b/templates/common_scripts.j2
new file mode 100644
index 0000000..2ea3614
--- /dev/null
+++ b/templates/common_scripts.j2
@@ -0,0 +1,56 @@
+<script language="JavaScript">
+        function toggleClassByID(pkg) {
+            var element = document.getElementById(pkg);
+            //var button = document.getElementById(pkg+"_button");
+
+            if( element.className && element.className.indexOf("in") > -1 ) {
+                element.classList.remove("in");
+                //button.innerHTML = "&uarr;"
+            }
+            else {
+                element.classList.add("in");
+                //button.innerHTML = "&darr;"
+            }
+        }
+    </script>
+    <script language="JavaScript">
+        function init() {
+            // Declare all variables
+            var i, content, items;
+
+            // Get all elements with class="barcontent" and hide them
+            content = document.getElementsByClassName("barcontent");
+            for (i = 1; i < content.length; i++) {
+                content[i].style.display = "none";
+            }
+            content[0].style.display = "block";
+
+            // Get all elements with class="bar-item" and remove the class "active"
+            items = document.getElementsByClassName("bar-item");
+            for (i = 1; i < items.length; i++) {
+                items[i].className = items[i].className.replace(" active", "");
+            }
+            items[0].className += " active";
+
+        }
+        function openBar(evt, barName) {
+            // Declare all variables
+            var i, barcontent, baritems;
+
+            // Get all elements with class="barcontent" and hide them
+            barcontent = document.getElementsByClassName("barcontent");
+            for (i = 0; i < barcontent.length; i++) {
+                barcontent[i].style.display = "none";
+            }
+
+            // Get all elements with class="bar-item" and remove the class "active"
+            baritems = document.getElementsByClassName("bar-item");
+            for (i = 0; i < baritems.length; i++) {
+                baritems[i].className = baritems[i].className.replace(" active", "");
+            }
+
+            // Show the current tab, and add an "active" class to the link that opened the tab
+            document.getElementById(barName).style.display = "block";
+            evt.currentTarget.className += " active";
+        }
+    </script>
diff --git a/templates/common_styles.j2 b/templates/common_styles.j2
new file mode 100644
index 0000000..604564b
--- /dev/null
+++ b/templates/common_styles.j2
@@ -0,0 +1,95 @@
+<style>
+    body {
+        font-family: "Open Sans", Arial, Helvetica, sans-serif;
+        font-size: 90% !important;
+    }
+    h5 {padding-left: 1em; margin: 0.6em}
+    .note {font-style: italic; font-weight: normal; padding-left: 1em; margin: 0.2em; font-size: 0.7em; color: gray;}
+    /* Common */
+    .header {
+        display:block;
+    }
+    
+    .label {float: left; font-size: 0.7em; color: Black; line-height: 17px; padding-left: 10px;}
+    .text {float: left; font-size: 0.8em; color: Navy; padding-left: 2px;}
+    .date {float: right;}
+    
+    .smallgreytext {float: right; font-size: 0.5em; color: gray;}
+
+    /* Bar */
+    .bar{
+        background: linear-gradient(to bottom, #126666 0%, #284753 77%);
+        width:100%;
+        overflow:hidden;
+        display: inline-block;
+    }
+    .bar .bar-item{
+        padding:8px 16px;
+        float:left;
+        width:auto;
+        border:none;
+        display:block;
+        outline:0;
+        color: White;
+        background-color: transparent;
+    }
+    
+    .bar .bar-item:hover {
+        background-color: #328686;
+    }
+    
+    .bar .bar-item.active {
+        background-color: #328686;
+        color: white;
+    }
+
+    .collapsable {
+        visibility: collapse;
+        display: none;
+    }
+
+    .collapsable.in {
+        visibility: visible;
+        display: table-row;
+    }
+
+    table {
+        border: 0 hidden;
+        table-layout: fixed;
+        width: 100%;
+    }
+
+    .table_header {
+        background-color: #284753;
+        color: wheat;
+        text-align: center;
+        font-family: "Open Sans", Arial, Helvetica, sans-serif;
+    }
+
+    /* Tooltip container */
+    .tooltip {
+        position: relative;
+        display: inline-block;
+        border-bottom: 1px dotted black;
+    }
+
+    .tooltip .tooltiptext {
+        visibility: hidden;
+        background-color: black;
+        font-family: "Lucida Console", Monaco, monospace;
+        font-size: 0.5em;
+        width: auto;
+        color: #fff;
+        border-radius: 6px;
+        padding: 5px 5px;
+
+        /* Position the tooltip */
+        position: absolute;
+        z-index: 1;
+    }
+
+    .tooltip:hover .tooltiptext {
+        visibility: visible;
+    }
+
+</style>
diff --git a/templates/network_check_tmpl.j2 b/templates/network_check_tmpl.j2
index 553b554..9f0f556 100644
--- a/templates/network_check_tmpl.j2
+++ b/templates/network_check_tmpl.j2
@@ -2,207 +2,120 @@
 <html lang="en">
 <head>
     <meta charset="UTF-8">
-    <title>Model Tree Changes</title>
+    <title>Nodes and Networks report</title>
+    {% include 'common_styles.j2' %}
+    {% include 'common_scripts.j2' %}
     <style>
-        body {
-            font-family: Verdana, Geneva, Tahoma, sans-serif;
-            font-size: 90% !important;
+        table.cluster_nodes {
+            width: 90%;
+            margin-left: 5%;
+            margin-right: 5%;
         }
-        .dot_green {
-            float: left;
-            color: green;
-            margin-right: 0.5em;
-            margin-top: 0.2em;
-        }
-        .dot_red {
-            float: left;
-            color: red;
-            margin-right: 0.5em;
-            margin-top: 0.2em;
-        }
-        .dot_empty {
-            float: left;
-            color: darkgray;
-            margin-right: 0.5em;
-            margin-top: 0.2em;
-        }
-        /* Style the tab */
-        .tab {
-            float: left;
-            width: 130px;
-            border: 1px solid #fff;
-            background-color: #efe;
-        }
-
-        /* Style the buttons that are used to open the tab content */
-        .tab button {
+    
+        /* Node rows*/
+		.node {
+			display: inline-block;
+			background-color: white;
+		}
+		
+        tr.node > td {
             display: block;
-            background-color: inherit;
-            color: Black;
-            border: none;
-            outline: none;
-            font-family: "Lucida Console", Monaco, monospace;
-            text-align: left;
-            cursor: pointer;
-            transition: 0.3s;
-            font-size: 1.3em;
-            width: 100%;
-            padding: 1px;
-            margin: 1px;
-        }
-
-        button > div.node_name {
             float: left;
-            font-size: 1.3em;
-        }
-
-        .smallgreytext {
-            float: right;
-            font-size: 0.7em;
-            color: gray;
-        }
-
-        /* Change background color of buttons on hover */
-        .tab button:hover {
-            background-color: #7b7;
-        }
-
-        /* Create an active/current "tab button" class */
-        .tab button.active {
-            background-color: #8c8;
-            color: white;
-        }
-
-        /* Style the tab content */
-        .tabcontent {
-            display: none;
-            position: absolute;
-            font-size: 1em;
-            padding: 0.5em;
-            right: -10%;
-            top: 0%;
-            transform: translateX(-12%);
-            width: calc(100% - 170px);
-            overflow-x: scroll;
-            overflow-wrap: break-word;
-        }
-
-        table {
-            border: 0 hidden;
-            width: 100%;
-        }
-        tr:nth-child(even) {
-            background-color: #fff;
-        }
-        tr:nth-child(odd) {
-            background-color: #ddd;
-        }
-        .Header {
-            background-color: #bbb;
-            color: Black;
-            width: 30%;
-            text-align: center;
-        }
-        .param {
-            font-size: 0.8em;
-            color: #555;
-            padding-left: 50px;
-            padding-right: 10px;
-        }
-        .class_file {
-            font-size: 0.8em;
-            font-weight: bold;
-            min-width: 300px;
-            text-align: left;
+            padding: 1px;
+            padding-left: 5px;
+            padding-right: 5px;
             color: black;
+            background-color: #A1BbA1;
+            text-align: center;
+            margin: 2px;
         }
-
-        .pkgName {
-            font-size: 1em;
-            padding-left: 10px;
-            max-width: 800px;
+        
+        .meters {
+			display: inline-block;        
         }
-
-        .version {
-            font-size: 1em;
-            text-align: left;
-            max-width: 400px;
-            overflow-wrap: break-word;
+        
+        td.meters > .meter {
+            display: block;
+            float: left;
         }
-
-        .differ {
-            background-color: #eaa;
-        }
-        /* Tooltip container */
-        .tooltip {
-            position: relative;
-            display: inline-block;
-            border-bottom: 1px dotted black;
-        }
-
-        .tooltip .tooltiptext {
-            visibility: hidden;
-            background-color: black;
-            font-family: "Lucida Console", Monaco, monospace;
-            font-size: 0.5em;
-            width: auto;
-            color: #fff;
-            border-radius: 6px;
-            padding: 5px 5px;
-
-            /* Position the tooltip */
-            position: absolute;
-            z-index: 1;
-        }
-
-        .tooltip:hover .tooltiptext {
-            visibility: visible;
-        }
-
     </style>
-    <script language="JavaScript">
-        function init() {
-            // Declare all variables
-            var i, tabcontent, tablinks;
-
-            // Get all elements with class="tabcontent" and hide them
-            tabcontent = document.getElementsByClassName("tabcontent");
-            for (i = 1; i < tabcontent.length; i++) {
-                tabcontent[i].style.display = "none";
-            }
-            tabcontent[0].style.display = "block";
-
-            // Get all elements with class="tablinks" and remove the class "active"
-            tablinks = document.getElementsByClassName("tablinks");
-            for (i = 1; i < tablinks.length; i++) {
-                tablinks[i].className = tablinks[i].className.replace(" active", "");
-            }
-            tablinks[0].className += " active";
-
-        }
-        function openTab(evt, tabName) {
-            // Declare all variables
-            var i, tabcontent, tablinks;
-
-            // Get all elements with class="tabcontent" and hide them
-            tabcontent = document.getElementsByClassName("tabcontent");
-            for (i = 0; i < tabcontent.length; i++) {
-                tabcontent[i].style.display = "none";
-            }
-
-            // Get all elements with class="tablinks" and remove the class "active"
-            tablinks = document.getElementsByClassName("tablinks");
-            for (i = 0; i < tablinks.length; i++) {
-                tablinks[i].className = tablinks[i].className.replace(" active", "");
-            }
-
-            // Show the current tab, and add an "active" class to the link that opened the tab
-            document.getElementById(tabName).style.display = "block";
-            evt.currentTarget.className += " active";
-        }
-    </script>
 </head>
 <body onload="init()">
 
+<div class="header">
+    <div class="label">OpenStack release:</div>
+    <div class="text">{{ openstack_release }}</div>
+    <div class="label">MCP Version:</div>
+    <div class="text">{{ mcp_release }}</div>
+    <div class="label date">generated on: {{ gen_date }}</div>
+</div>
+
+<div class="bar">
+    <button class="bar-item" onclick="openBar(event, 'nodes')">Nodes</button>
+    <button class="bar-item" onclick="openBar(event, 'networks')">Networks</button>
+    <button class="bar-item" onclick="openBar(event, 'services')">Other</button>
+</div>
+
+{% macro nodes_page(nodes, id_label) %}
+<div id="{{ id_label }}" class="barcontent">
+    <h5>{{ caller() }}</h5>
+    <hr>
+    <table class="cluster_nodes">
+    {% 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>
+    {% endfor %}
+    </table>
+    <hr>
+</div>
+{% endmacro %}
+
+{% macro networks_page(networks, id_label) %}
+<div id="{{ id_label }}" class="barcontent">
+    <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>
+        </tr>
+    </table>
+    <hr>
+</div>
+{% endmacro %}
+
+{% macro services_page(services, id_label) %}
+<div id="{{ id_label }}" class="barcontent">
+    <h5>{{ caller() }}</h5>
+    <hr>
+</div>
+{% endmacro %}
+
+<!-- Cluster nodes page -->
+{% call nodes_page(nodes, "nodes") %}
+    Cluster nodes status and simple meterings
+{% endcall %}
+
+<!-- Cluster nodes page -->
+{% call networks_page(networks, "networks") %}
+    Networks in the cluster
+{% endcall %}
+
+<!-- Cluster nodes page -->
+{% call services_page(services, "services") %}
+    Services status in the cluster
+{% endcall %}
+
 </body>
 </html>
\ No newline at end of file
diff --git a/templates/pkg_versions_csv.j2 b/templates/pkg_versions_csv.j2
new file mode 100644
index 0000000..c754f63
--- /dev/null
+++ b/templates/pkg_versions_csv.j2
@@ -0,0 +1,23 @@
+{% macro package_list(pkg_dict, id_label) %}
+    {% for pkg_name in pkg_dict | get_sorted_keys %}
+        {% set p = pkg_dict[pkg_name] %}
+        {% for status in p['results'].keys() | sort(reverse=true) %}
+        {% 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 }}
+            {% endfor %}
+        {% endfor %}
+        {% endfor %}
+    {% endfor %}
+    {{ caller() }}
+{% endmacro %}
+type,package_name,node,status,action,installed,candidate,release
+{% call package_list(critical, "mirantis") %}
+{% endcall %}
+{% call package_list(system, "system") %}
+{%- endcall %}
+{% call package_list(other, "other") %}
+{%- endcall %}
+{% call package_list(unlisted, "unlisted") %}
+{%- endcall %}
diff --git a/templates/pkg_versions_html.j2 b/templates/pkg_versions_html.j2
new file mode 100644
index 0000000..d1b71bb
--- /dev/null
+++ b/templates/pkg_versions_html.j2
@@ -0,0 +1,328 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>Cloud Package versions check</title>
+    {% include 'common_styles.j2' %}
+    {% include 'common_scripts.j2' %}
+    <style>        
+        td.repo {width: 3em; text-align: center; font-size: 0.7em; color: #113b11; font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif;}
+        td.component, td.app, td.package_name {
+            font-size: 0.75em;
+            text-align: center;
+            color: #113b11;
+            font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif;
+        }
+        
+        td.repo {column-width: 50px;}
+        td.component {column-width: 130px;}
+        td.app {column-width: 80px;}
+        td.package_name {column-width: 200px; padding-left: 10px; text-align: left;}
+        td.node_name {column-width: 210px;}
+        td.installed {column-width: 16%;}
+        td.status_container {column-width: 200px;}
+        td.candidate {column-width: 16%;}
+        td.release {column-width: 13%;}
+
+        .status_container {
+            display: inline-block;
+        }
+
+        .status {
+            display: block;
+            float: left;
+            width: 80px;
+            padding: 1px;
+            padding-left: 5px;
+            padding-right: 5px;
+            color: white;
+            background-color: #113b11;
+            text-align: center;
+        }
+        .action {
+            display: block;
+            float: left;
+            width: 120px;
+            padding: 1px;
+            padding-left: 5px;
+            padding-right: 5px;
+            color: gray;
+            background-color: #d4dad9;
+            text-align: center;
+        }
+
+        .status_container .ok {
+            color: white;
+            background-color: #113b11;
+        }
+        .status_container .error {
+            color: white;
+            background-color: darkred;
+        }
+        .status_container .upgraded {
+            color: azure;
+            background-color: green;
+        }
+        .status_container .downgraded {
+            color: white;
+            background-color: darkolivegreen;
+        }
+
+        .status_container .needs_repo {
+            color: black;
+            background-color: #50aacc;
+        }
+
+        .status_container .needs_up {
+            color: black;
+            background-color: #aaccaa;
+        }
+
+        .status_container .needs_down {
+            color: black;
+            background-color: #ffcc48;
+        }
+
+        .status_container .possible {
+            color: gray;
+            background-color: #d4dad9;
+        }
+
+
+
+        .version {text-align: left; padding: 2px}
+        .v_epoch, .v_upstream, .v_debian, .colon, .dash {
+            color: darkslategray;
+            float: left;
+            display: block;
+        }
+
+        .ok {color: darkslategray;}
+        .error {color: white; background-color: darkred;}
+        .upgraded {color: whitesmoke; background-color: darkslategray;}
+        .downgraded {color: red;}
+
+        .smallgreytext {float: right; font-size: 0.5em; color: gray;}
+
+        /* Table specific */
+        .nodes tr:nth-child(even) {
+            background-color: #fff;
+        }
+        .nodes tr:nth-child(odd) {
+            background-color: #d4dad9;
+            
+        }
+    </style>
+</head>
+<body onload="init()">
+
+<div class="header">
+	<div class="label">OpenStack release:</div>
+	<div class="text">{{ openstack_release }}</div>
+	<div class="label">MCP Version:</div>
+    <div class="text">{{ mcp_release }}</div>
+    <div class="label date">generated on: {{ gen_date }}</div>
+</div>
+
+<div class="bar">
+	<button class="bar-item" onclick="openBar(event, 'mirantis')">Mirantis</button>
+	<button class="bar-item" onclick="openBar(event, 'system')">System</button>
+    <button class="bar-item" onclick="openBar(event, 'other')">Other</button>
+    <button class="bar-item" onclick="openBar(event, 'unlisted')">Unlisted</button>
+    <button class="bar-item" onclick="openBar(event, 'legend')">Legend</button>
+</div>
+
+{% 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="colon">:</div>
+        {% endif %}
+        <div class="v_upstream {{ v.upstream_status | make_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>
+        {% endif %}
+        {{ caller() }}
+    </div>
+{% endmacro %}
+
+{% macro render_package(pkg_name, dat, status_shown, action_shown, id_label) %}
+        <tr onclick="toggleClassByID('{{ id_label }}_{{ pkg_name }}_{{ status_shown }}_{{ action_shown }}')" id="{{ id_label }}_{{ pkg_name }}_{{ status_shown }}_{{ action_shown }}_button">
+            <td class="repo">{{ dat['desc']['repo'] }}</td>
+            <td class="component">{{ dat['desc']['component'] }}</td>
+            <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>
+                {% endif %}
+            </td>
+        </tr>
+        <tr class="collapsable" id="{{ id_label }}_{{ pkg_name }}_{{ status_shown }}_{{ action_shown }}"><td colspan="7">
+        <table class="nodes"><tbody>
+        {% for status in dat['results'].keys() | sort(reverse=true) %}
+        {% for action in dat['results'][status].keys() | sort(reverse=true) %}
+        {% set counter = 1 + loop.index0 %}
+        {% for node in dat['results'][status][action].keys() | sort %}
+        {% set n_counter = 1 + loop.index0 %}
+        {% set nd = dat['results'][status][action][node] %}
+        <tr>
+            <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>
+                {% endif %}
+            </td>
+            <td class="installed">
+                <div class="tooltip">
+                    {% call prettify_version(nd['i']) %}
+                    <pre class="tooltiptext">{{ nd['raw'] | linebreaks }}</pre>
+                    {% endcall %}
+                </div>
+            </td>
+            <td class="candidate">{{ nd['c'].version }}</td>
+            <td class="release">{{ dat['r'].version }}</td>
+        </tr>
+        {% endfor %}
+        {% endfor %}
+        {% endfor %}
+        </tbody></table>
+        </td></tr>
+    {{ caller() }}
+{% endmacro %}
+
+{% macro package_table(pkg_dict, id_label) %}
+<div id="{{ id_label }}" class="barcontent">
+    <h5>{{ caller() }}</h5>
+    <table class="pkgversions">
+            <tbody>
+            <tr>
+                <td class="table_header" width="50px">repo</td>
+                <td class="table_header" width="130px">Component</td>
+                <td class="table_header" width="80px">App</td>
+                <td class="table_header" width="200px">Package name</td>
+                <td class="table_header">Installed</td>
+                <td class="table_header">Candidate</td>
+                <td class="table_header">Release</td>
+            </tr>
+            <!-- Print errors -->
+            <tr><td colspan="7">Errors ({{ errors[id_label] }})</td></tr>
+            {% for pkg_name in pkg_dict | get_sorted_keys %}
+            {% set dat = pkg_dict[pkg_name] %}
+                {% if status_err in dat['results'] %}
+                    {% set action_to_show = dat['results'][status_err].keys() | get_max %}
+                    {% call render_package(pkg_name, dat, status_err, action_to_show, id_label) %}
+                    {% endcall %}
+                {% endif%}
+            {% endfor %}
+            {% if not errors[id_label] %}
+            <tr><td class="note" colspan="7">no errors found </td></tr>
+            {% endif %}
+
+            <!-- Print downgrades -->
+            <tr><td colspan="7">Downgrades ({{ downgrades[id_label] }})</td></tr>
+            {% for pkg_name in pkg_dict | get_sorted_keys %}
+            {% set dat = pkg_dict[pkg_name] %}
+                {% if status_down in dat['results'] %}
+                    {% set action_to_show = dat['results'][status_down].keys() | get_max %}
+                    {% call render_package(pkg_name, dat, status_down, action_to_show, id_label) %}
+                    {% endcall %}
+                {% endif %}
+            {% endfor %}
+            {% if not downgrades[id_label] %}
+            <tr><td class="note" colspan="7">no downgrades found</td></tr>
+            {% endif %}
+
+            <!-- Print all other -->
+            <tr><td colspan="7">All others</td></tr>
+            {% for pkg_name in pkg_dict | get_sorted_keys %}
+            {% set dat = pkg_dict[pkg_name] %}
+                {% set status_to_show = dat['results'].keys() | get_max %}
+                {% set action_to_show = dat['results'][status_to_show].keys() | get_max %}
+                {% if status_err != status_to_show and status_down !=  status_to_show %}
+                    {% call render_package(pkg_name, dat, status_to_show, action_to_show, id_label) %}
+                    {% endcall %}
+                {% endif %}
+            {% endfor %}
+            </tbody>
+        </table>
+</div>
+{%- endmacro %}
+
+<!-- Mirantis packages which version is critical for functionality -->
+{% call package_table(critical, "mirantis") %}
+    Packages maintained and updated by Mirantis
+{% endcall %}
+
+<!-- System labeled packages-->
+{% call package_table(system, "system") %}
+    System packages which versions are critical to proper cloud function
+{%- endcall %}
+
+<!-- Other packages -->
+{% call package_table(other, "other") %}
+    Packages with no description or not critical
+{%- endcall %}
+
+{% call package_table(unlisted, "unlisted") %}
+    Packages that are not listed in version map. I.e. unexpected on the environment
+{%- endcall %}
+
+<!-- Legend -->
+<div id="legend" class="barcontent">
+    <h5>Legend: status and action explanation and possible combinations</h5>
+    <table class="pkgversions">
+        <tbody>
+        <tr><td colspan="7">Version status desctiptions</td></tr>
+        <tr>
+            <td class="status_container"><div class="status {{ cs.ok | make_status_class }}">{{ cs.ok | make_status_label }}</div></td>
+            <td>Installed and Candidate epoch:upstream version mach</td>
+        </tr>
+        <tr>
+            <td class="status_container"><div class="status {{ cs.up | make_status_class }}">{{ cs.up | make_status_label }}</div></td>
+            <td>Installed version is newer that the one found in Repo (i.e. candidate) or Release notes recordset</td>
+        </tr>
+        <tr>
+            <td class="status_container"><div class="status {{ cs.down | make_status_class }}">{{ cs.down | make_status_label }}</div></td>
+            <td>Installed version is older that the one found in Repo (i.e. candidate) or Release notes recordset</td>
+        </tr>
+        <tr>
+            <td class="status_container"><div class="status {{ cs.err | make_status_class }}">{{ cs.err | make_status_label }}</div></td>
+            <td>Installed version conflicts with a combination of Candidate and Release notes versions</td>
+        </tr>
+        <tr><td colspan="7">Action descriptions</td></tr>
+        <tr>
+            <td class="status_container"><div class="action {{ ca.na | make_action_class }}">{{ ca.na | make_action_label }} (no action)</div></td>
+            <td>No action suggested</td>
+        </tr>
+        <tr>
+            <td class="status_container"><div class="action {{ ca.up | make_action_class }}">{{ ca.up | make_action_label }}</div></td>
+            <td>There is an upgrade possible for the package. But it is not strictly required action.</td>
+        </tr>
+        <tr>
+            <td class="status_container"><div class="action {{ ca.need_up | make_action_class }}">{{ ca.need_up | make_action_label }}</div></td>
+            <td>Package should be upgraded to match version either in repo or in Release notes</td>
+        </tr>
+        <tr>
+            <td class="status_container"><div class="action {{ ca.need_down | make_action_class }}">{{ ca.need_down | make_action_label }}</div></td>
+            <td>Package should be downgraded to match version either in repo or in Release notes</td>
+        </tr>
+        <tr>
+            <td class="status_container"><div class="action {{ ca.repo | make_action_class }}">{{ ca.repo | make_action_label }}</div></td>
+            <td>Repo that is configured on the target node contains invalid version and should be updated</td>
+        </tr>
+        <tr><td colspan="7">Versions status and Action combinations</td></tr>
+        <tr>
+            <td 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>
+            </td>
+        </tr>
+    </tbody></table>
+</div>
+</body>
+</html>
\ No newline at end of file
diff --git a/templates/pkg_versions_tmpl.j2 b/templates/pkg_versions_tmpl.j2
deleted file mode 100644
index b03e2ef..0000000
--- a/templates/pkg_versions_tmpl.j2
+++ /dev/null
@@ -1,327 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-<head>
-    <meta charset="UTF-8">
-    <title>Cloud Package versions check</title>
-    <style>
-        body {
-            font-family: Verdana, Geneva, Tahoma, sans-serif;
-            font-size: 90% !important;
-        }
-        .dot_green {
-            float: left;
-            color: green;
-            margin-right: 0.5em;
-            margin-top: 0.2em;
-        }
-        .dot_red {
-            float: left;
-            color: red;
-            margin-right: 0.5em;
-            margin-top: 0.2em;
-        }
-        .dot_empty {
-            float: left;
-            color: darkgray;
-            margin-right: 0.5em;
-            margin-top: 0.2em;
-        }
-        /* Style the tab */
-        .tab {
-            float: left;
-            width: 130px;
-            border: 1px solid #fff;
-            background-color: #efe;
-        }
-
-        /* Style the buttons that are used to open the tab content */
-        .tab button {
-            display: block;
-            background-color: inherit;
-            color: Black;
-            border: none;
-            outline: none;
-            font-family: "Lucida Console", Monaco, monospace;
-            text-align: left;
-            cursor: pointer;
-            transition: 0.3s;
-            font-size: 1.1em;
-            width: 100%;
-            padding: 1px;
-            margin: 1px;
-        }
-
-        button > div.node_name {
-            float: left;
-            font-size: 0.8em;
-        }
-
-        .smallgreytext {
-            float: right;
-            font-size: 0.5em;
-            color: gray;
-        }
-
-        /* Change background color of buttons on hover */
-        .tab button:hover {
-            background-color: #7b7;
-        }
-
-        /* Create an active/current "tab button" class */
-        .tab button.active {
-            background-color: #8c8;
-            color: white;
-        }
-
-        /* Style the tab content */
-        .tabcontent {
-            display: none;
-            position: absolute;
-            font-size: 1em;
-            padding: 0.5em;
-            right: -10%;
-            top: 0%;
-            transform: translateX(-12%);
-            width: calc(100% - 170px);
-            overflow-x: scroll;
-            overflow-wrap: break-word;
-        }
-        .collapsable {
-            visibility: collapse;
-            display: none;
-        }
-
-        .collapsable.in {
-            visibility: visible;
-            display: table-row;
-        }
-
-        table {
-            border: 0 hidden;
-            width: 100%;
-        }
-        tr:nth-child(even) {
-            background-color: #fff;
-        }
-        tr:nth-child(odd) {
-            background-color: #ddd;
-        }
-        .Header {
-            background-color: #bbb;
-            color: Black;
-            width: 30%;
-            text-align: center;
-        }
-        .pkgName {
-            font-size: 1em;
-            padding-left: 10px;
-        }
-
-        .version {
-            font-size: 1.1em;
-            text-align: left;
-        }
-
-        .differ {
-            background-color: #eaa;
-        }
-        /* Tooltip container */
-        .tooltip {
-            position: relative;
-            display: inline-block;
-            border-bottom: 1px dotted black;
-        }
-
-        .tooltip .tooltiptext {
-            visibility: hidden;
-            background-color: black;
-            font-family: "Lucida Console", Monaco, monospace;
-            font-size: 0.5em;
-            width: auto;
-            color: #fff;
-            border-radius: 6px;
-            padding: 5px 5px;
-
-            /* Position the tooltip */
-            position: absolute;
-            z-index: 1;
-        }
-
-        .tooltip:hover .tooltiptext {
-            visibility: visible;
-        }
-
-    </style>
-    <script language="JavaScript">
-        function toggleClassByID(pkg, number) {
-            var elements = document.querySelectorAll("#"+pkg+"_"+number);
-            var ii = elements.length;
-            var button = document.querySelector("#"+pkg+"_button"+number);
-
-            while (ii--) {
-                if( elements[ii].className && elements[ii].className.indexOf("in") > -1 ) {
-                    elements[ii].classList.remove("in");
-                    button.innerHTML = "&uarr;"
-                }
-                else {
-                    elements[ii].classList.add("in");
-                    button.innerHTML = "&darr;"
-                }
-            }
-
-
-        }
-    </script>
-    <script language="JavaScript">
-        function init() {
-            // Declare all variables
-            var i, tabcontent, tablinks;
-
-            // Get all elements with class="tabcontent" and hide them
-            tabcontent = document.getElementsByClassName("tabcontent");
-            for (i = 1; i < tabcontent.length; i++) {
-                tabcontent[i].style.display = "none";
-            }
-            tabcontent[0].style.display = "block";
-
-            // Get all elements with class="tablinks" and remove the class "active"
-            tablinks = document.getElementsByClassName("tablinks");
-            for (i = 1; i < tablinks.length; i++) {
-                tablinks[i].className = tablinks[i].className.replace(" active", "");
-            }
-            tablinks[0].className += " active";
-
-        }
-        function openTab(evt, tabName) {
-            // Declare all variables
-            var i, tabcontent, tablinks;
-
-            // Get all elements with class="tabcontent" and hide them
-            tabcontent = document.getElementsByClassName("tabcontent");
-            for (i = 0; i < tabcontent.length; i++) {
-                tabcontent[i].style.display = "none";
-            }
-
-            // Get all elements with class="tablinks" and remove the class "active"
-            tablinks = document.getElementsByClassName("tablinks");
-            for (i = 0; i < tablinks.length; i++) {
-                tablinks[i].className = tablinks[i].className.replace(" active", "");
-            }
-
-            // Show the current tab, and add an "active" class to the link that opened the tab
-            document.getElementById(tabName).style.display = "block";
-            evt.currentTarget.className += " active";
-        }
-    </script>
-</head>
-<body onload="init()">
-<div class="tab">
-  <button class="tablinks" onclick="openTab(event, 'All Diffs')")>
-      <div class="node_name">All Diffs</div>
-  </button>
-{% for node_name in nodes.keys() | sort %}
-    {% if counters[node_name]['package_diff'] %}
-  <button class="tablinks" onclick="openTab(event, '{{ node_name | shortname }}')">
-    <div class="dot_green">&#9679;</div>
-    <div class="node_name">{{ node_name | shortname }}</div>
-    <div class="smallgreytext">({{ counters[node_name]['package_diff'] }} / {{ counters[node_name]['packages'] }})</div>
-  </button>
-    {% endif %}    
-{% endfor %}
-{% for node_name in nodes.keys() | sort %}
-    {% if not counters[node_name]['package_diff'] %}
-  <button class="tablinks" onclick="openTab(event, '{{ node_name | shortname }}')">
-    <div class="dot_empty">&#9675;</div>
-    <div class="node_name">{{ node_name | shortname }}</div>
-    <div class="smallgreytext">({{ counters[node_name]['package_diff'] }} / {{ counters[node_name]['packages'] }})</div>
-  </button>
-    {% endif %}
-{% endfor %}
-</div>
-<div id="All Diffs" class="tabcontent">
-    <table class="pkgversions">
-        <tbody>
-        <tr>
-            <td class="Header">Node name</td>
-            <td class="Header">Installed</td>
-            <td class="Header">Candidate</td>
-        </tr>
-        {% for pkg_name in pkg_diffs.keys() | sort %}
-        {% if counters[pkg_name]['df_nodes'] %}
-        {% set pkg_counter = 1 + loop.index0 %}
-        <tr>
-            <td>
-            <a href="#" onclick="toggleClassByID('{{ pkg_name }}', '{{ pkg_counter }}')" id="{{ pkg_name }}_button{{ pkg_counter }}">&uarr;</a>
-            {{ pkg_name }}
-            </td>
-            <td>{{ counters[pkg_name]['df_nodes'] }}</td>
-            <td></td>
-        </tr>
-        <tr><td colspan=3>
-        <table class="nodes"><tbody>
-            {% for node in pkg_diffs[pkg_name]['df_nodes'].keys() | sort %}
-            <tr class="collapsable" id="{{ pkg_name }}_{{ pkg_counter }}">
-                <td class="pkgName">{{ node }}</td>
-                <td class="version differ">
-                    <div class="tooltip">{{ pkg_diffs[pkg_name]['df_nodes'][node]['i'] }}
-                        <pre class="tooltiptext">{{ pkg_diffs[pkg_name]['df_nodes'][node]['raw'] | linebreaks }}</pre>
-                    </div>
-                </td>
-                <td class="version">{{ pkg_diffs[pkg_name]['df_nodes'][node]['c'] }}</td>
-            </tr>
-            {% endfor %}
-        </tbody></table>
-        </td></tr>
-        {% endif%}
-        {% endfor %}
-        </tbody>
-    </table>
-</div>
-{% for node_name in nodes.keys() | sort %}
-<div id="{{ node_name | shortname }}" class="tabcontent">
-    <table class="pkgversions">
-        <tbody>
-        <tr>
-            <td class="Header">Package name</td>
-            <td class="Header">Installed</td>
-            <td class="Header">Candidate</td>
-        </tr>
-        <tr><td colspan=3>Package with different versions uniq for this node</td></tr>
-        {% for package_name in nodes[node_name]['packages'] | sort %}
-            {% if not nodes[node_name]['packages'][package_name]['is_equal'] %}
-            {% if nodes[node_name]['packages'][package_name]['fail_uniq'] %}
-        <tr>
-            <td class="pkgName">{{ package_name }}</td>
-            <td class="version differ">
-                <div class="tooltip">{{ nodes[node_name]['packages'][package_name]['installed'] }}
-                    <pre class="tooltiptext">{{ nodes[node_name]['packages'][package_name]['raw'] | linebreaks }}</pre>
-                </div>
-            </td>
-            <td class="version">{{ nodes[node_name]['packages'][package_name]['candidate'] }}</td>
-        </tr>
-            {% endif %}
-            {% endif %}
-        {% endfor %}
-        <tr><td colspan=3>Packages with different versions on nodes with similar role</td></tr>
-        {% for package_name in nodes[node_name]['packages'] | sort %}
-            {% if not nodes[node_name]['packages'][package_name]['is_equal'] %}
-            {% if not nodes[node_name]['packages'][package_name]['fail_uniq'] %}
-        <tr>
-            <td class="pkgName">{{ package_name }}</td>
-            <td class="version differ">
-                <div class="tooltip">{{ nodes[node_name]['packages'][package_name]['installed'] }}
-                    <pre class="tooltiptext">{{ nodes[node_name]['packages'][package_name]['raw'] | linebreaks }}</pre>
-                </div>
-            </td>
-            <td class="version">{{ nodes[node_name]['packages'][package_name]['candidate'] }}</td>
-        </tr>
-            {% endif %}
-            {% endif %}
-        {% endfor %}
-        <tr><td colspan=3>Packages with same versions (installed vs candidate): {{ counters[node_name]['package_eq'] }}</td></tr>
-        </tbody>
-    </table>
-</div>
-{% endfor %}
-</body>
-</html>
\ No newline at end of file