Packages report updates

- All Errors are warnings by default
- If package version differs across nodes
  warning becomes error

Change-Id: I1e6d338cfae252cc5d8ee6ededdd757ec070eb2c
Related-PROD: PROD-38972
diff --git a/cfg_checker/modules/packages/checker.py b/cfg_checker/modules/packages/checker.py
index 631c992..92d9e1c 100644
--- a/cfg_checker/modules/packages/checker.py
+++ b/cfg_checker/modules/packages/checker.py
@@ -2,6 +2,7 @@
 
 from cfg_checker.common import const, logger_cli
 from cfg_checker.common.exception import ConfigException
+from cfg_checker.common.other import merge_dict
 from cfg_checker.helpers.console_utils import Progress
 from cfg_checker.modules.packages.repos import RepoManager
 from cfg_checker.nodes import salt_master
@@ -42,6 +43,7 @@
                 "ok": const.VERSION_OK,
                 "up": const.VERSION_UP,
                 "down": const.VERSION_DOWN,
+                "warn": const.VERSION_WARN,
                 "err": const.VERSION_ERR
             },
             "ca": {
@@ -53,6 +55,7 @@
             }
         }
         _data['status_err'] = const.VERSION_ERR
+        _data['status_warn'] = const.VERSION_WARN
         _data['status_down'] = const.VERSION_DOWN
 
         # Presort packages
@@ -66,6 +69,7 @@
         _progress_index = 0
         # counters
         _ec = _es = _eo = _eu = 0
+        _wc = _ws = _wo = _wu = 0
         _dc = _ds = _do = _du = 0
         while _progress_index < _l:
             # progress bar
@@ -86,12 +90,43 @@
                         # ...just skip it from report
                         continue
 
+            _differ = len(set(_val['results'].keys())) > 1
+            if _differ:
+                # in case package has different status across nodes
+                # Warning becomes Error.
+                if const.VERSION_WARN in _val['results']:
+                    if const.VERSION_ERR in _val['results']:
+                        # add warns to err
+                        # should never happen, though
+                        merge_dict(
+                            _val['results'].pop(const.VERSION_WARN),
+                            _val['results'][const.VERSION_ERR]
+                        )
+                    else:
+                        _val['results'][const.VERSION_ERR] = \
+                            _val['results'].pop(const.VERSION_WARN)
+            else:
+                # in case package has same status on all nodes
+                # Error becomes Warning
+                if const.VERSION_ERR in _val['results']:
+                    if const.VERSION_WARN in _val['results']:
+                        # add warns to err
+                        # should never happen, though
+                        merge_dict(
+                            _val['results'].pop(const.VERSION_ERR),
+                            _val['results'][const.VERSION_WARN]
+                        )
+                    else:
+                        _val['results'][const.VERSION_WARN] = \
+                            _val['results'].pop(const.VERSION_ERR)
+
             if len(_c) > 0 and _val['is_mirantis'] is None:
                 # not listed package in version lib
                 _data['unlisted'].update({
                     _pn: _val
                 })
                 _eu += _val['results'].keys().count(const.VERSION_ERR)
+                _wu += _val['results'].keys().count(const.VERSION_WARN)
                 _du += _val['results'].keys().count(const.VERSION_DOWN)
             # mirantis/critical
             # elif len(_c) > 0 and _c != 'System':
@@ -101,6 +136,7 @@
                     _pn: _val
                 })
                 _ec += _val['results'].keys().count(const.VERSION_ERR)
+                _wc += _val['results'].keys().count(const.VERSION_WARN)
                 _dc += _val['results'].keys().count(const.VERSION_DOWN)
             # system
             elif _c == 'System':
@@ -108,6 +144,7 @@
                     _pn: _val
                 })
                 _es += _val['results'].keys().count(const.VERSION_ERR)
+                _ws += _val['results'].keys().count(const.VERSION_WARN)
                 _ds += _val['results'].keys().count(const.VERSION_DOWN)
             # rest
             else:
@@ -115,6 +152,7 @@
                     _pn: _val
                 })
                 _eo += _val['results'].keys().count(const.VERSION_ERR)
+                _wo += _val['results'].keys().count(const.VERSION_WARN)
                 _do += _val['results'].keys().count(const.VERSION_DOWN)
 
         _progress.end()
@@ -125,6 +163,12 @@
             'other': _eo,
             'unlisted': _eu
         }
+        _data['warnings'] = {
+            'mirantis': _wc,
+            'system': _ws,
+            'other': _wo,
+            'unlisted': _wu
+        }
         _data['downgrades'] = {
             'mirantis': _dc,
             'system': _ds,