Log collector module

New:
  - [Done] multiple namespace selector
  - [Done] keyword-based pod selector
  - [Done] per-pod logs syntax detection and parsing
  - [Differed] in-place filtering for shorter logs
  - [Done] individual logs timestamp detection
  - [Done] Unix time bases Timestamp sorting
  - [Done] Single file logs output using common format
  - [Done] add all log types from all MOS namespaces and pods

Update:
  - resource preparation can be skipped per module
  - updated log collection using multiple threads
  - new setting LOG_COLLECT_THREADS

Fixes:
  - Network MTU fix
  - Faster cmd execution on single pod
  - Ceph benchmark validations
  - Ceph benchmark report sorting
  - Daemonset deployment with nodes skipped
  - Network tree debugging script
  - Tree depth limiter, i.e. stackoverflow prevention

  Related-PROD: PROD-36845

Change-Id: Icf229ac62078c6418ab4dbdff12b0d27ed42af1d
diff --git a/cfg_checker/modules/ceph/__init__.py b/cfg_checker/modules/ceph/__init__.py
index 5c9357b..31c6b7a 100644
--- a/cfg_checker/modules/ceph/__init__.py
+++ b/cfg_checker/modules/ceph/__init__.py
@@ -1,9 +1,13 @@
 #    Author: Alex Savatieiev (osavatieiev@mirantis.com; a.savex@gmail.com)
 #    Copyright 2019-2022 Mirantis, Inc.
+import os
+
 from cfg_checker.agent.fio_runner import get_fio_options
-from cfg_checker.agent.fio_runner import seq_modes, mix_modes
+from cfg_checker.agent.fio_runner import seq_modes, mix_modes, rand_modes
 from cfg_checker.common import logger_cli
+from cfg_checker.common.other import utils
 from cfg_checker.common.settings import ENV_TYPE_KUBE
+from cfg_checker.common.exception import CheckerException
 from cfg_checker.helpers import args_utils
 from cfg_checker.modules.ceph import info, bench
 
@@ -33,6 +37,32 @@
 #     else:
 #         return _class
 
+
+def _validate_option_type(value, type_list):
+    _s, _t = utils.split_option_type(value)
+    if _t not in type_list:
+        raise CheckerException(
+            "Invalid option type '{}'. Expected types: {}".format(
+                value,
+                ", ".join(type_list)
+            )
+        )
+    else:
+        return
+
+
+def _validate_option(value, type_list):
+    if value not in type_list:
+        raise CheckerException(
+            "Invalid option '{}'. Expected one of: {}".format(
+                value,
+                ", ".join(type_list)
+            )
+        )
+    else:
+        return
+
+
 def _get_param_and_log(arg, param_str):
     _value = args_utils.get_arg(arg, param_str)
     logger_cli.info("    {}={}".format(param_str, _value))
@@ -242,6 +272,10 @@
     # dump results options
     _dump_path = args_utils.get_arg(args, "dump_path")
     if _dump_path:
+        if not os.path.exists(_dump_path):
+            raise CheckerException(
+                "ERROR: Dump path invalid: '{}'".format(_dump_path)
+            )
         logger_cli.info("# Results will be dumped to '{}'".format(_dump_path))
         config.bench_results_dump_path = _dump_path
     else:
@@ -345,6 +379,38 @@
     # init the Bench class
     ceph_bench = bench.KubeCephBench(config)
     ceph_bench.set_ceph_info_class(ceph_info)
+
+    # Validate options
+    logger_cli.info("-> Validating options")
+    # size
+    _validate_option_type(_opts["size"], ["G", "M"])
+    _validate_option_type(_opts["ramp_time"], ["s", "m"])
+    _validate_option_type(_opts["runtime"], ["s", "m"])
+    _modes = seq_modes + mix_modes + rand_modes
+    _validate_option(_opts["readwrite"], _modes)
+
+    if _task_file:
+        _s, _ = utils.split_option_type(_opts["size"])
+        for idx in range(len(ceph_bench.tasks)):
+            # size
+            _ts, _ = utils.split_option_type(ceph_bench.tasks[idx]["size"])
+            if _s < _ts:
+                logger_cli.error(
+                    "ERROR: Task #{} file size is to big:"
+                    " {} (volume) < {} (testfile)".format(
+                        idx,
+                        _opts["size"],
+                        ceph_bench.tasks[idx]["size"]
+                    )
+                )
+            # other
+            _validate_option(ceph_bench.tasks[idx]["readwrite"], _modes)
+        # Print defaults
+        logger_cli.debug("... default/selected options for fio:")
+        for _k in _opts.keys():
+            # TODO: Update options for single run
+            logger_cli.debug("    {} = {}".format(_k, _opts[_k]))
+
     # Preload previous results for this name
     ceph_bench.preload_results()
     # Do the testrun