Network Module class structure for Kube support

Related-PROD: PROD-35903

Change-Id: I474a347452b472df3e2272357d1a036b4893e844
diff --git a/cfg_checker/common/settings.py b/cfg_checker/common/settings.py
index 89457d7..1a30ac0 100644
--- a/cfg_checker/common/settings.py
+++ b/cfg_checker/common/settings.py
@@ -252,9 +252,9 @@
                     self.kube_node_user
                 )
             else:
-                # Init keys for nodes in case of remote env
-                # KUBE_NODE_KEYPATH is provided in case of nodes key would be
-                # different to master nodes key, which is supplied
+                # Init key for nodes
+                # KUBE_NODE_KEYPATH is provided in case of node keys would be
+                # different to master node key, which is supplied
                 # using MCP_SSH_KEY (mandatory) and, for the most cases,
                 # should be the same for remote envs
                 if not self.kube_node_keypath and not self.force_no_key:
diff --git a/cfg_checker/modules/network/__init__.py b/cfg_checker/modules/network/__init__.py
index dd8cc98..0245e06 100644
--- a/cfg_checker/modules/network/__init__.py
+++ b/cfg_checker/modules/network/__init__.py
@@ -1,5 +1,6 @@
 from cfg_checker.common import logger_cli
 from cfg_checker.common.settings import ENV_TYPE_SALT
+from cfg_checker.common.exception import CheckerException
 from cfg_checker.helpers import args_utils
 from cfg_checker.modules.network import checker, mapper, pinger
 
@@ -8,6 +9,45 @@
 supported_envs = [ENV_TYPE_SALT]
 
 
+def _selectClass(_env, strClassHint="checker"):
+    _class = None
+    if _env == ENV_TYPE_SALT:
+        if strClassHint == "checker":
+            _class = checker.SaltNetworkChecker
+        elif strClassHint == "mapper":
+            _class = mapper.SaltNetworkMapper
+    elif _env == ENV_TYPE_KUBE:
+        if strClassHint == "checker":
+            _class = checker.KubeNetworkChecker
+        elif strClassHint == "mapper":
+            _class = mapper.KubeNetworkMapper
+    if not _class:
+        raise CheckerException(
+            "Unknown hint for selecting Network handler Class: '{}'".format(
+                strClassHint
+            )
+        )
+    else:
+        return _class
+
+
+def _selectChecker(_env):
+    pChecker = None
+    if _env == ENV_TYPE_SALT:
+        pChecker = checker.SaltNetworkChecker(
+            config,
+            skip_list=_skip,
+            skip_list_file=_skip_file
+        )
+    elif _env == ENV_TYPE_KUBE:
+        pChecker = checker.KubeNetworkChecker(
+            config,
+            skip_list=_skip,
+            skip_list_file=_skip_file
+        )
+    return pChecker
+
+
 def init_parser(_parser):
     # network subparser
     net_subparsers = _parser.add_subparsers(dest='type')
@@ -73,11 +113,12 @@
     # should not print map, etc...
     # Just bare summary and errors
     # Check if there is supported env found
-    args_utils.check_supported_env(ENV_TYPE_SALT, args, config)
+    _env = args_utils.check_supported_env(ENV_TYPE_SALT, args, config)
     # Start command
     logger_cli.info("# Network check to console")
     _skip, _skip_file = args_utils.get_skip_args(args)
-    netChecker = checker.NetworkChecker(
+    _class = _selectClass(_env)
+    netChecker = _class(
         config,
         skip_list=_skip,
         skip_list_file=_skip_file
@@ -98,13 +139,14 @@
 def do_report(args, config):
     # Network Report
     # Check if there is supported env found
-    args_utils.check_supported_env(ENV_TYPE_SALT, args, config)
+    _env = args_utils.check_supported_env(ENV_TYPE_SALT, args, config)
     # Start command
     logger_cli.info("# Network report (check, node map")
 
     _filename = args_utils.get_arg(args, 'html')
     _skip, _skip_file = args_utils.get_skip_args(args)
-    netChecker = checker.NetworkChecker(
+    _class = _selectClass(_env)
+    netChecker = _class(
         config,
         skip_list=_skip,
         skip_list_file=_skip_file
@@ -121,11 +163,12 @@
 def do_map(args, config):
     # Network Map
     # Check if there is supported env found
-    args_utils.check_supported_env(ENV_TYPE_SALT, args, config)
+    _env = args_utils.check_supported_env(ENV_TYPE_SALT, args, config)
     # Start command
     logger_cli.info("# Network report")
     _skip, _skip_file = args_utils.get_skip_args(args)
-    networkMap = mapper.NetworkMapper(
+    _class = _selectClass(_env, strClassHint="mapper")
+    networkMap = _class(
         config,
         skip_list=_skip,
         skip_list_file=_skip_file
@@ -140,10 +183,11 @@
 def do_list(args, config):
     # Network List
     # Check if there is supported env found
-    args_utils.check_supported_env(ENV_TYPE_SALT, args, config)
+    _env = args_utils.check_supported_env(ENV_TYPE_SALT, args, config)
     # Start command
     _skip, _skip_file = args_utils.get_skip_args(args)
-    _map = mapper.NetworkMapper(
+    _class = _selectClass(_env, strClassHint="mapper")
+    _map = _class(
         config,
         skip_list=_skip,
         skip_list_file=_skip_file
@@ -166,7 +210,7 @@
     # Checks if selected nodes are pingable
     # with a desireble parameters: MTU, Frame, etc
     # Check if there is supported env found
-    args_utils.check_supported_env(ENV_TYPE_SALT, args, config)
+    _env = args_utils.check_supported_env(ENV_TYPE_SALT, args, config)
     # Start command
     if not args.cidr:
         logger_cli.error("\n# Use mcp-check network list to get list of CIDRs")
diff --git a/cfg_checker/modules/network/checker.py b/cfg_checker/modules/network/checker.py
index eaa2428..f7b55db 100644
--- a/cfg_checker/modules/network/checker.py
+++ b/cfg_checker/modules/network/checker.py
@@ -1,24 +1,14 @@
 from cfg_checker.common import logger_cli
-from cfg_checker.modules.network.mapper import NetworkMapper
+from cfg_checker.modules.network.mapper import SaltNetworkMapper, \
+    KubeNetworkMapper
 from cfg_checker.modules.network.network_errors import NetworkErrors
 from cfg_checker.reports import reporter
 
 
 class NetworkChecker(object):
-    def __init__(
-        self,
-        config,
-        skip_list=None,
-        skip_list_file=None
-    ):
+    def __init__(self):
         logger_cli.debug("... init error logs folder")
         self.errors = NetworkErrors()
-        self.mapper = NetworkMapper(
-            config,
-            errors_class=self.errors,
-            skip_list=skip_list,
-            skip_list_file=skip_list_file
-        )
 
     def check_networks(self, map=True):
         self.mapper.map_network(self.mapper.RECLASS)
@@ -47,7 +37,7 @@
         """
         logger_cli.info("### Generating report to '{}'".format(filename))
         _report = reporter.ReportToFile(
-            reporter.HTMLNetworkReport(self.mapper.salt_master),
+            reporter.HTMLNetworkReport(self.mapper.master),
             filename
         )
         _report(
@@ -60,3 +50,34 @@
             }
         )
         logger_cli.info("-> Done")
+
+
+class SaltNetworkChecker(NetworkChecker):
+    def __init__(
+        self,
+        config,
+        skip_list=None,
+        skip_list_file=None
+    ):
+        super(SaltNetworkChecker, self).__init__()
+        self.mapper = SaltNetworkMapper(
+            config,
+            errors_class=self.errors,
+            skip_list=skip_list,
+            skip_list_file=skip_list_file
+        )
+
+class KubeNetworkChecker(NetworkChecker):
+    def __init__(
+        self,
+        config,
+        skip_list=None,
+        skip_list_file=None
+    ):
+        super(SaltNetworkChecker, self).__init__()
+        self.mapper = KubeNetworkMapper(
+            config,
+            errors_class=self.errors,
+            skip_list=skip_list,
+            skip_list_file=skip_list_file
+        )
\ No newline at end of file
diff --git a/cfg_checker/modules/network/mapper.py b/cfg_checker/modules/network/mapper.py
index fd19864..2e925f2 100644
--- a/cfg_checker/modules/network/mapper.py
+++ b/cfg_checker/modules/network/mapper.py
@@ -5,7 +5,7 @@
 from cfg_checker.common import logger_cli
 from cfg_checker.common.exception import InvalidReturnException
 from cfg_checker.modules.network.network_errors import NetworkErrors
-from cfg_checker.nodes import SaltNodes
+from cfg_checker.nodes import SaltNodes, KubeNodes
 
 # TODO: use templated approach
 # net interface structure should be the same
@@ -38,16 +38,16 @@
         skip_list=None,
         skip_list_file=None
     ):
-        self.salt_master = SaltNodes(config)
         logger_cli.info("# Initializing mapper")
+        self.env_config = config
         # init networks and nodes
         self.networks = {}
-        self.nodes = self.salt_master.get_nodes(
+        self.nodes = self.master.get_nodes(
             skip_list=skip_list,
             skip_list_file=skip_list_file
         )
-        self.cluster = self.salt_master.get_info()
-        self.domain = self.salt_master.domain
+        self.cluster = self.master.get_info()
+        self.domain = self.master.domain
         # init and pre-populate interfaces
         self.interfaces = {k: {} for k in self.nodes}
         # Init errors class
@@ -115,14 +115,14 @@
         # class uses nodes from self.nodes dict
         _reclass = {}
         # Get required pillars
-        self.salt_master.get_specific_pillar_for_nodes("linux:network")
-        for node in self.salt_master.nodes.keys():
+        self.master.get_specific_pillar_for_nodes("linux:network")
+        for node in self.master.nodes.keys():
             # check if this node
-            if not self.salt_master.is_node_available(node):
+            if not self.master.is_node_available(node):
                 continue
             # get the reclass value
             _pillar = \
-                self.salt_master.nodes[node]['pillars']['linux']['network']
+                self.master.nodes[node]['pillars']['linux']['network']
             # we should be ready if there is no interface in reclass for a node
             # for example on APT node
             if 'interface' in _pillar:
@@ -172,16 +172,16 @@
         # class uses nodes from self.nodes dict
         _runtime = {}
         logger_cli.info("# Mapping node runtime network data")
-        self.salt_master.prepare_script_on_active_nodes("ifs_data.py")
-        _result = self.salt_master.execute_script_on_active_nodes(
+        self.master.prepare_script_on_active_nodes("ifs_data.py")
+        _result = self.master.execute_script_on_active_nodes(
             "ifs_data.py",
             args=["json"]
         )
-        for key in self.salt_master.nodes.keys():
+        for key in self.master.nodes.keys():
             # check if we are to work with this node
-            if not self.salt_master.is_node_available(key):
+            if not self.master.is_node_available(key):
                 continue
-            # due to much data to be passed from salt_master,
+            # due to much data to be passed from master,
             # it is happening in order
             if key in _result:
                 _text = _result[key]
@@ -194,21 +194,21 @@
                         )
                     )
                 _dict = json.loads(_text[_text.find('{'):])
-                self.salt_master.nodes[key]['routes'] = _dict.pop("routes")
-                self.salt_master.nodes[key]['networks'] = _dict
+                self.master.nodes[key]['routes'] = _dict.pop("routes")
+                self.master.nodes[key]['networks'] = _dict
             else:
-                self.salt_master.nodes[key]['networks'] = {}
-                self.salt_master.nodes[key]['routes'] = {}
+                self.master.nodes[key]['networks'] = {}
+                self.master.nodes[key]['routes'] = {}
             logger_cli.debug("... {} has {} networks".format(
                 key,
-                len(self.salt_master.nodes[key]['networks'].keys())
+                len(self.master.nodes[key]['networks'].keys())
             ))
         logger_cli.info("-> done collecting networks data")
 
         logger_cli.info("-> mapping IPs")
         # match interfaces by IP subnets
-        for host, node_data in self.salt_master.nodes.items():
-            if not self.salt_master.is_node_available(host):
+        for host, node_data in self.master.nodes.items():
+            if not self.master.is_node_available(host):
                 continue
 
             for net_name, net_data in node_data['networks'].items():
@@ -463,7 +463,7 @@
             for hostname in names:
                 _notes = []
                 node = hostname.split('.')[0]
-                if not self.salt_master.is_node_available(hostname, log=False):
+                if not self.master.is_node_available(hostname, log=False):
                     logger_cli.info(
                         "    {0:8} {1}".format(node, "node not available")
                     )
@@ -516,7 +516,7 @@
                 # get gate and routes if proto is static
                 if _proto == 'static':
                     # get the gateway for current net
-                    _routes = self.salt_master.nodes[hostname]['routes']
+                    _routes = self.master.nodes[hostname]['routes']
                     _route = _routes[_net] if _net in _routes else None
                     # get the default gateway
                     if 'default' in _routes:
@@ -732,3 +732,37 @@
         #                 "    {0:8} {1}".format(hostname.split('.')[0], _text)
         #             )
         # logger_cli.info("\n")
+
+
+class SaltNetworkMapper(NetworkMapper):
+    def __init__(
+        self,
+        config,
+        errors_class=None,
+        skip_list=None,
+        skip_list_file=None
+    ):
+        self.master = SaltNodes(config)
+        super(SaltNetworkMapper, self).__init__(
+            config,
+            errors_class=errors_class,
+            skip_list=skip_list,
+            skip_list_file=skip_list_file
+        )
+
+
+class KubeNetworkMapper(NetworkMapper):
+    def __init__(
+        self,
+        config,
+        errors_class=None,
+        skip_list=None,
+        skip_list_file=None
+    ):
+        self.master = KubeNodes(config)
+        super(KubeNetworkMapper, self).__init__(
+            config,
+            errors_class=errors_class,
+            skip_list=skip_list,
+            skip_list_file=skip_list_file
+        )
diff --git a/cfg_checker/nodes.py b/cfg_checker/nodes.py
index e568cec..615a1a4 100644
--- a/cfg_checker/nodes.py
+++ b/cfg_checker/nodes.py
@@ -196,6 +196,9 @@
             logger_cli.warning(
                 "Multiple domains detected: {}".format(",".join(_domains))
             )
+            # TODO: Use domain with biggest node count by default
+            # or force it via config option
+            
         else:
             self.domain = _domains[0]
         logger_cli.info("-> {} nodes inactive".format(len(self.skip_list)))