Multi env support and Kube client integration

Kube friendly Beta

Package versions supports Kube env

Added:
  - Env type detection
  - New option: --use-env, for selecting env
    when function supports multiple detected envs
  - Updated config loading
  - Each module and command type has supported env check
    and stops execution if it is on unsupported env
  - Functions can support multiple envs
  - Kubernetes dependency
  - Kubenernetes API detection: local and remote
  - Package checking class hierachy for using Salt or Kube
  - Remote pod execution routine
  - Flexible SSH/SSH Forwarder classes: with, ssh,do(), etc
  - Multithreaded SSH script execution
  - Number of workers parameter, default 5

Fixed:
  - Config dependency
  - Command loading with supported envs list
  - Unittests structure and execution flow updated
  - Unittests fixes
  - Fixed debug mode handling
  - Unified command type/support routine
  - Nested attrs getter/setter

Change-Id: I3ade693ac21536e2b5dcee4b24d511749dc72759
Related-PROD: PROD-35811
diff --git a/cfg_checker/modules/network/mapper.py b/cfg_checker/modules/network/mapper.py
index 51f52bb..fd19864 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 salt_master
+from cfg_checker.nodes import SaltNodes
 
 # TODO: use templated approach
 # net interface structure should be the same
@@ -33,19 +33,21 @@
 
     def __init__(
         self,
+        config,
         errors_class=None,
         skip_list=None,
         skip_list_file=None
     ):
+        self.salt_master = SaltNodes(config)
         logger_cli.info("# Initializing mapper")
         # init networks and nodes
         self.networks = {}
-        self.nodes = salt_master.get_nodes(
+        self.nodes = self.salt_master.get_nodes(
             skip_list=skip_list,
             skip_list_file=skip_list_file
         )
-        self.cluster = salt_master.get_info()
-        self.domain = salt_master.domain
+        self.cluster = self.salt_master.get_info()
+        self.domain = self.salt_master.domain
         # init and pre-populate interfaces
         self.interfaces = {k: {} for k in self.nodes}
         # Init errors class
@@ -113,13 +115,14 @@
         # class uses nodes from self.nodes dict
         _reclass = {}
         # Get required pillars
-        salt_master.get_specific_pillar_for_nodes("linux:network")
-        for node in salt_master.nodes.keys():
+        self.salt_master.get_specific_pillar_for_nodes("linux:network")
+        for node in self.salt_master.nodes.keys():
             # check if this node
-            if not salt_master.is_node_available(node):
+            if not self.salt_master.is_node_available(node):
                 continue
             # get the reclass value
-            _pillar = salt_master.nodes[node]['pillars']['linux']['network']
+            _pillar = \
+                self.salt_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:
@@ -169,14 +172,14 @@
         # class uses nodes from self.nodes dict
         _runtime = {}
         logger_cli.info("# Mapping node runtime network data")
-        salt_master.prepare_script_on_active_nodes("ifs_data.py")
-        _result = salt_master.execute_script_on_active_nodes(
+        self.salt_master.prepare_script_on_active_nodes("ifs_data.py")
+        _result = self.salt_master.execute_script_on_active_nodes(
             "ifs_data.py",
             args=["json"]
         )
-        for key in salt_master.nodes.keys():
+        for key in self.salt_master.nodes.keys():
             # check if we are to work with this node
-            if not salt_master.is_node_available(key):
+            if not self.salt_master.is_node_available(key):
                 continue
             # due to much data to be passed from salt_master,
             # it is happening in order
@@ -191,21 +194,21 @@
                         )
                     )
                 _dict = json.loads(_text[_text.find('{'):])
-                salt_master.nodes[key]['routes'] = _dict.pop("routes")
-                salt_master.nodes[key]['networks'] = _dict
+                self.salt_master.nodes[key]['routes'] = _dict.pop("routes")
+                self.salt_master.nodes[key]['networks'] = _dict
             else:
-                salt_master.nodes[key]['networks'] = {}
-                salt_master.nodes[key]['routes'] = {}
+                self.salt_master.nodes[key]['networks'] = {}
+                self.salt_master.nodes[key]['routes'] = {}
             logger_cli.debug("... {} has {} networks".format(
                 key,
-                len(salt_master.nodes[key]['networks'].keys())
+                len(self.salt_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 salt_master.nodes.items():
-            if not salt_master.is_node_available(host):
+        for host, node_data in self.salt_master.nodes.items():
+            if not self.salt_master.is_node_available(host):
                 continue
 
             for net_name, net_data in node_data['networks'].items():
@@ -460,7 +463,7 @@
             for hostname in names:
                 _notes = []
                 node = hostname.split('.')[0]
-                if not salt_master.is_node_available(hostname, log=False):
+                if not self.salt_master.is_node_available(hostname, log=False):
                     logger_cli.info(
                         "    {0:8} {1}".format(node, "node not available")
                     )
@@ -513,7 +516,7 @@
                 # get gate and routes if proto is static
                 if _proto == 'static':
                     # get the gateway for current net
-                    _routes = salt_master.nodes[hostname]['routes']
+                    _routes = self.salt_master.nodes[hostname]['routes']
                     _route = _routes[_net] if _net in _routes else None
                     # get the default gateway
                     if 'default' in _routes: