Refactored to include varios reports and checks
diff --git a/ci_checker/pkg_check.py b/ci_checker/pkg_check.py
new file mode 100644
index 0000000..b9d9ed3
--- /dev/null
+++ b/ci_checker/pkg_check.py
@@ -0,0 +1,185 @@
+import json
+import os
+import sys
+
+from copy import deepcopy
+
+import common.const as const
+import reporter
+from ci_checker.common import utils
+from ci_checker.common import base_config, logger, logger_cli, PKG_DIR
+from ci_checker.common import salt_utils
+
+node_tmpl = {
+    'role': '',
+    'node_group': '',
+    'status': const.NODE_DOWN,
+    'pillars': {},
+    'grains': {}
+}
+
+
+class CloudPackageChecker(object):
+    _config = base_config
+
+    def __init__(self):
+        logger_cli.info("Collecting nodes for package check")
+        # simple salt rest client
+        self.salt = salt_utils.SaltRemote()
+
+        # Keys for all nodes
+        # this is not working in scope of 2016.8.3, will overide with list
+        # cls.node_keys = cls.salt.list_keys()
+
+        logger_cli.info("Collecting node names existing in the cloud")
+        self.node_keys = {
+            'minions': base_config.all_nodes
+        }
+
+        # all that answer ping
+        _active = self.salt.get_active_nodes()
+        logger_cli.info("Nodes responded: {}".format(_active))
+        # just inventory for faster interaction
+        # iterate through all accepted nodes and create a dict for it
+        self.nodes = {}
+        for _name in self.node_keys['minions']:
+            _nc = utils.get_node_code(_name)
+            _rmap = const.all_roles_map
+            _role = _rmap[_nc] if _nc in _rmap else 'unknown'
+            _status = const.NODE_UP if _name in _active else const.NODE_DOWN
+
+            self.nodes[_name] = deepcopy(node_tmpl)
+            self.nodes[_name]['node_group'] = _nc
+            self.nodes[_name]['role'] = _role
+            self.nodes[_name]['status'] = _status
+
+        logger_cli.info("{} nodes collected".format(len(self.nodes)))
+
+    def collect_installed_packages(self):
+        """
+        Collect installed packages on each node
+        sets 'installed' dict property in the class
+
+        :return: none
+        """
+        logger_cli.info("Collecting installed packages")
+        # form an all nodes compound string to use in salt
+        _active_nodes_string = self.salt.compound_string_from_list(
+            filter(
+                lambda nd: self.nodes[nd]['status'] == const.NODE_UP,
+                self.nodes
+            )
+        )
+        # Prepare script
+        _script_filename = "pkg_versions.py"
+        _p = os.path.join(PKG_DIR, 'scripts', _script_filename)
+        with open(_p, 'rt') as fd:
+            _script = fd.read().splitlines()
+        _storage_path = os.path.join(
+            base_config.salt_file_root, base_config.salt_scripts_folder
+        )
+        logger_cli.info(
+            "Uploading script {} to master's file cache folder: '{}'".format(
+                _script_filename,
+                _storage_path
+            )
+        )
+        _result = self.salt.mkdir("cfg01*", _storage_path)
+        # Form cache, source and target path
+        _cache_path = os.path.join(_storage_path, _script_filename)
+        _source_path = os.path.join(
+            'salt://',
+            base_config.salt_scripts_folder,
+            _script_filename
+        )
+        _target_path = os.path.join(
+            '/root',
+            base_config.salt_scripts_folder,
+            _script_filename
+        )
+
+        logger.debug("Creating file in cache '{}'".format(_cache_path))
+        _result = self.salt.f_touch_master(_cache_path)
+        _result = self.salt.f_append_master(_cache_path, _script)
+        # command salt to copy file to minions
+        logger.debug("Creating script target folder '{}'".format(_cache_path))
+        _result = self.salt.mkdir(
+            _active_nodes_string,
+            os.path.join(
+                '/root',
+                base_config.salt_scripts_folder
+            ),
+            tgt_type="compound"
+        )
+        logger_cli.info("Running script to all active nodes")
+        _result = self.salt.get_file(
+            _active_nodes_string,
+            _source_path,
+            _target_path,
+            tgt_type="compound"
+        )
+        # execute pkg collecting script
+        logger.debug("Running script to all nodes")
+        # handle results for each node
+        _result = self.salt.cmd(
+            _active_nodes_string,
+            'cmd.run',
+            param='python {}'.format(_target_path),
+            expr_form="compound"
+        )
+        for key in self.nodes.keys():
+            # due to much data to be passed from salt, it is happening in order
+            if key in _result:
+                _text = _result[key]
+                _dict = json.loads(_text[_text.find('{'):])
+                self.nodes[key]['packages'] = _dict
+            else:
+                self.nodes[key]['packages'] = {}
+            logger_cli.info("{} has {} packages installed".format(
+                key,
+                len(self.nodes[key]['packages'].keys())
+            ))
+
+    def collect_packages(self):
+        """
+        Check package versions in repos vs installed
+
+        :return: no return values, all date put to dict in place
+        """
+        _all_packages = {}
+        for node_name, node_value in self.nodes.iteritems():
+            for package_name in node_value['packages']:
+                if package_name not in _all_packages:
+                    _all_packages[package_name] = {}
+                _all_packages[package_name][node_name] = node_value
+
+        # TODO: process data for per-package basis
+
+        self.all_packages = _all_packages
+
+    def create_html_report(self, filename):
+        """
+        Create static html showing packages diff per node
+
+        :return: buff with html
+        """
+        _report = reporter.ReportToFile(
+            reporter.HTMLPackageCandidates(),
+            filename
+        )
+        _report(nodes=self.nodes)
+
+
+# init connection to salt and collect minion data
+cl = CloudPackageChecker()
+
+# collect data on installed packages
+cl.collect_installed_packages()
+
+# diff installed and candidates
+# cl.collect_packages()
+
+# report it
+cl.create_html_report("./pkg_versions.html")
+
+sys.exit(0)