Ceph Info command

 Updates
 - ceph module with 'info', 'report' and 'bench' commands
 - mcp-checker ceph info command is collecting Ceph config
   and creates an archive
 - ceph report command creates HTML document with
   info collected from Ceph cluster
 - Basic SMART data output in info and full output in report
 - skeleton of the ceph bench command to run synced tests

 Fixes
 - kube helper commands uses proper naming

Change-Id: Ia5aaa343f7d1c38a67d34e60215801bbb0fea097
Related-PROD: PROD-36605
diff --git a/cfg_checker/reports/reporter.py b/cfg_checker/reports/reporter.py
index 7ddbc4f..1f54ff3 100644
--- a/cfg_checker/reports/reporter.py
+++ b/cfg_checker/reports/reporter.py
@@ -32,6 +32,11 @@
     return text.replace("\n", "<br />")
 
 
+def tabstops(text):
+    # replace python linebreaks with html breaks
+    return text.replace("\t", "&#9;")
+
+
 def get_sorted_keys(td):
     # detect if we can sort by desc
     # Yes, this is slow, but bullet-proof from empty desc
@@ -116,6 +121,78 @@
     return _text
 
 
+def to_gb(bytes_str):
+    _bytes = int(bytes_str)
+    _gb = _bytes / 1024 / 1024 / 1024
+    return "{}".format(round(_gb, 2))
+
+
+def to_mb(bytes_str):
+    _bytes = int(bytes_str)
+    _mb = _bytes / 1024 / 1024
+    return "{}".format(round(_mb, 2))
+
+
+def get_bucket_item_name(id, cmap):
+    for buck in cmap["buckets"]:
+        if id == buck["id"]:
+            return buck["name"]
+    for dev in cmap["devices"]:
+        if id == dev["id"]:
+            return dev["name"]
+    return id
+
+
+def get_rule_steps(steps):
+    _steps = []
+    for step in steps:
+        _ops = step.pop("op").split('_')
+        if "take" in _ops:
+            _steps.append(
+                "step {} {}".format(
+                    " ".join(_ops),
+                    step["item_name"]
+                )
+            )
+        else:
+            _steps.append(
+                "step {} {}".format(
+                    " ".join(_ops),
+                    " ".join(["{} {}".format(k, v) for k, v in step.items()])
+                )
+            )
+    return _steps
+
+
+def get_osdmap(cs):
+    _osdmap = cs
+    while True:
+        _keys = list(_osdmap.keys())
+        for _k in _keys:
+            if _k == "osdmap":
+                _osdmap = _osdmap[_k]
+                break
+            elif _k == 'epoch':
+                return _osdmap
+    return {
+        "epoch": 0,
+        "num_osds": 0,
+        "num_up_osds": 0,
+        "osd_up_since": 0,
+        "num_in_osds": 0,
+        "osd_in_since": 0,
+        "num_remapped_pgs": 0
+    }
+
+
+def get_pool_stats(id, pgdump):
+    _stats = {}
+    for pool in pgdump["pg_map"]["pool_stats"]:
+        if id == pool["poolid"]:
+            _stats = pool
+    return _stats
+
+
 @six.add_metaclass(abc.ABCMeta)
 class _Base(object):
     def __init__(self, master=None):
@@ -167,6 +244,12 @@
         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['pkg_repo_info'] = make_repo_info
+        self.jinja2_env.filters['to_gb'] = to_gb
+        self.jinja2_env.filters['to_mb'] = to_mb
+        self.jinja2_env.filters['get_bucket_item_name'] = get_bucket_item_name
+        self.jinja2_env.filters['get_rule_steps'] = get_rule_steps
+        self.jinja2_env.filters['get_pool_stats'] = get_pool_stats
+        self.jinja2_env.filters['get_osdmap'] = get_osdmap
 
         # render!
         logger_cli.info("-> Using template: {}".format(self.tmpl))
@@ -195,6 +278,11 @@
     tmpl = "pkg_versions_html.j2"
 
 
+# HTML Ceph information report
+class HTMLCephInfo(_TMPLBase):
+    tmpl = "ceph_info_html.j2"
+
+
 # Package versions report
 class HTMLModelCompare(_TMPLBase):
     tmpl = "model_tree_cmp_tmpl.j2"