add support for in-memory kubeconfig (#212)

add support for in-memory kubeconfig

SUMMARY

k8s module support now authentication with kubeconfig parameter as file and dict.

Closes #139
ISSUE TYPE


Feature Pull Request

COMPONENT NAME

ADDITIONAL INFORMATION

Reviewed-by: Mike Graves <mgraves@redhat.com>
Reviewed-by: None <None>
This commit is contained in:
abikouo
2021-08-30 11:31:07 +02:00
committed by GitHub
parent e21ad0212d
commit d78b64d792
7 changed files with 85 additions and 17 deletions

View File

@@ -194,6 +194,24 @@ class ActionModule(ActionBase):
except AnsibleError:
raise AnsibleActionFail("%s does not exist in local filesystem" % local_path)
def get_kubeconfig(self, kubeconfig, remote_transport, new_module_args):
if isinstance(kubeconfig, string_types):
# find the kubeconfig in the expected search path
if not remote_transport:
# kubeconfig is local
# find in expected paths
kubeconfig = self._find_needle('files', kubeconfig)
# decrypt kubeconfig found
actual_file = self._loader.get_real_file(kubeconfig, decrypt=True)
new_module_args['kubeconfig'] = actual_file
elif isinstance(kubeconfig, dict):
new_module_args['kubeconfig'] = kubeconfig
else:
raise AnsibleActionFail("Error while reading kubeconfig parameter - "
"a string or dict expected, but got %s instead" % type(kubeconfig))
def run(self, tmp=None, task_vars=None):
''' handler for k8s options '''
if task_vars is None:
@@ -211,22 +229,15 @@ class ActionModule(ActionBase):
new_module_args = copy.deepcopy(self._task.args)
kubeconfig = self._task.args.get('kubeconfig', None)
# find the kubeconfig in the expected search path
if kubeconfig and not remote_transport:
# kubeconfig is local
if kubeconfig:
try:
# find in expected paths
kubeconfig = self._find_needle('files', kubeconfig)
self.get_kubeconfig(kubeconfig, remote_transport, new_module_args)
except AnsibleError as e:
result['failed'] = True
result['msg'] = to_text(e)
result['exception'] = traceback.format_exc()
return result
# decrypt kubeconfig found
actual_file = self._loader.get_real_file(kubeconfig, decrypt=True)
new_module_args['kubeconfig'] = actual_file
# find the file in the expected search path
src = self._task.args.get('src', None)

View File

@@ -27,7 +27,8 @@ options:
options are provided, the Kubernetes client will attempt to load the default
configuration file from I(~/.kube/config). Can also be specified via K8S_AUTH_KUBECONFIG environment
variable.
type: path
- The kubernetes configuration can be provided as dictionary. This feature requires a python kubernetes client version >= 17.17.0. Added in version 2.2.0.
type: raw
context:
description:
- The name of a context found in the config file. Can also be specified via K8S_AUTH_CONTEXT environment variable.

View File

@@ -19,7 +19,7 @@ AUTH_PROXY_HEADERS_SPEC = dict(
AUTH_ARG_SPEC = {
'kubeconfig': {
'type': 'path',
'type': 'raw',
},
'context': {},
'host': {},

View File

@@ -120,9 +120,8 @@ def get_api_client(module=None, **kwargs):
def _raise_or_fail(exc, msg):
if module:
module.fail_json(msg % to_native(exc))
module.fail_json(msg=msg % to_native(exc))
raise exc
# If authorization variables aren't defined, look for them in environment variables
for true_name, arg_name in AUTH_ARG_MAP.items():
if module and module.params.get(arg_name) is not None:
@@ -150,6 +149,22 @@ def get_api_client(module=None, **kwargs):
def auth_set(*names):
return all(auth.get(name) for name in names)
def _load_config():
kubeconfig = auth.get('kubeconfig')
optional_arg = {
'context': auth.get('context'),
'persist_config': auth.get('persist_config'),
}
if kubeconfig:
if isinstance(kubeconfig, string_types):
kubernetes.config.load_kube_config(config_file=kubeconfig, **optional_arg)
elif isinstance(kubeconfig, dict):
if LooseVersion(kubernetes.__version__) < LooseVersion("17.17"):
_raise_or_fail(Exception("kubernetes >= 17.17.0 is required to use in-memory kubeconfig."), 'Failed to load kubeconfig due to: %s')
kubernetes.config.load_kube_config_from_dict(config_dict=kubeconfig, **optional_arg)
else:
kubernetes.config.load_kube_config(config_file=None, **optional_arg)
if auth_set('host'):
# Removing trailing slashes if any from hostname
auth['host'] = auth.get('host').rstrip('/')
@@ -159,7 +174,7 @@ def get_api_client(module=None, **kwargs):
pass
elif auth_set('kubeconfig') or auth_set('context'):
try:
kubernetes.config.load_kube_config(auth.get('kubeconfig'), auth.get('context'), persist_config=auth.get('persist_config'))
_load_config()
except Exception as err:
_raise_or_fail(err, 'Failed to load kubeconfig due to %s')
@@ -169,7 +184,7 @@ def get_api_client(module=None, **kwargs):
kubernetes.config.load_incluster_config()
except kubernetes.config.ConfigException:
try:
kubernetes.config.load_kube_config(auth.get('kubeconfig'), auth.get('context'), persist_config=auth.get('persist_config'))
_load_config()
except Exception as err:
_raise_or_fail(err, 'Failed to load kubeconfig due to %s')