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/common/other.py b/cfg_checker/common/other.py
index 5a4c552..e3a3271 100644
--- a/cfg_checker/common/other.py
+++ b/cfg_checker/common/other.py
@@ -1,8 +1,11 @@
+import functools
import os
import re
import subprocess
-from cfg_checker.common.const import all_roles_map, uknown_code
+from cfg_checker.common import logger_cli
+from cfg_checker.common.const import all_salt_roles_map, uknown_code, \
+ truth
from cfg_checker.common.exception import ConfigException
pkg_dir = os.path.dirname(__file__)
@@ -11,10 +14,22 @@
pkg_dir = os.path.abspath(pkg_dir)
+# 'Dirty' and simple way to execute piped cmds
+def piped_shell(command):
+ logger_cli.debug("...cmd:'{}'".format(command))
+ _code, _out = subprocess.getstatusoutput(command)
+ if _code:
+ logger_cli.error("Non-zero return code: {}, '{}'".format(_code, _out))
+ return _out
+
+
+# 'Proper way to execute shell
def shell(command):
+ logger_cli.debug("...cmd:'{}'".format(command))
_ps = subprocess.Popen(
command.split(),
- stdout=subprocess.PIPE
+ stdout=subprocess.PIPE,
+ universal_newlines=False
).communicate()[0].decode()
return _ps
@@ -69,7 +84,7 @@
# node role code checks
_code = re.findall(r"[a-zA-Z]+", fqdn.split('.')[0])
if len(_code) > 0:
- if _code[0] in all_roles_map:
+ if _code[0] in all_salt_roles_map:
return _result()
else:
# log warning here
@@ -107,11 +122,11 @@
if _isvalid:
# try to match it with ones in map
_c = _code[0]
- match = any([r in _c for r in all_roles_map.keys()])
+ match = any([r in _c for r in all_salt_roles_map.keys()])
if match:
# no match, try to find it
match = False
- for r in all_roles_map.keys():
+ for r in all_salt_roles_map.keys():
_idx = _c.find(r)
if _idx > -1:
_c = _c[_idx:]
@@ -153,5 +168,25 @@
return _valid, _invalid
+ @staticmethod
+ def to_bool(value):
+ if value.lower() in truth:
+ return True
+ else:
+ return False
+
+ # helper functions to get nested attrs
+ # https://stackoverflow.com/questions/31174295/getattr-and-setattr-on-nested-subobjects-chained-properties
+ # using wonder's beautiful simplification:
+ # https://stackoverflow.com/questions/31174295/getattr-and-setattr-on-nested-objects/31174427?noredirect=1#comment86638618_31174427
+ def rsetattr(self, obj, attr, val):
+ pre, _, post = attr.rpartition('.')
+ return setattr(self.rgetattr(obj, pre) if pre else obj, post, val)
+
+ def rgetattr(self, obj, attr, *args):
+ def _getattr(obj, attr):
+ return getattr(obj, attr, *args)
+ return functools.reduce(_getattr, [obj] + attr.split('.'))
+
utils = Utils()