Skip to content

Commit

Permalink
helm - add support for in-memory kubeconfig
Browse files Browse the repository at this point in the history
  • Loading branch information
abikouo committed Aug 4, 2022
1 parent c4c12ca commit 0cb9645
Show file tree
Hide file tree
Showing 14 changed files with 457 additions and 246 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
minor_changes:
- helm, helm_plugin, helm_info, helm_plugin_info - add support for in-memory kubeconfig. (https://github.com/ansible-collections/kubernetes.core/issues/492).
3 changes: 2 additions & 1 deletion plugins/doc_fragments/helm_common_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ class ModuleDocFragment(object):
description:
- Helm option to specify kubeconfig path to use.
- If the value is not specified in the task, the value of environment variable C(K8S_AUTH_KUBECONFIG) will be used instead.
type: path
- The configuration can be provided as dictionary. Added in version 2.4.0.
type: raw
aliases: [ kubeconfig_path ]
host:
description:
Expand Down
37 changes: 23 additions & 14 deletions plugins/module_utils/helm.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@
__metaclass__ = type


from contextlib import contextmanager
import os
import tempfile
import traceback
import re
import json

from ansible.module_utils.basic import missing_required_lib

from ansible.module_utils.six import string_types

try:
import yaml
Expand All @@ -25,11 +25,18 @@
HAS_YAML = False


@contextmanager
def prepare_helm_environ_update(module):
environ_update = {}
file_to_cleam_up = None
kubeconfig_path = module.params.get("kubeconfig")
kubeconfig_path = None
if module.params.get("kubeconfig") is not None:
kubeconfig = module.params.get("kubeconfig")
if isinstance(kubeconfig, string_types):
kubeconfig_path = kubeconfig
elif isinstance(kubeconfig, dict):
fd, kubeconfig_path = tempfile.mkstemp()
with os.fdopen(fd, "w") as fp:
json.dump(kubeconfig, fp)
module.add_cleanup_file(kubeconfig_path)
if module.params.get("context") is not None:
environ_update["HELM_KUBECONTEXT"] = module.params.get("context")
if module.params.get("release_namespace"):
Expand All @@ -44,23 +51,19 @@ def prepare_helm_environ_update(module):
validate_certs=module.params["validate_certs"],
ca_cert=module.params["ca_cert"],
)
file_to_cleam_up = kubeconfig_path
module.add_cleanup_file(kubeconfig_path)
if kubeconfig_path is not None:
environ_update["KUBECONFIG"] = kubeconfig_path

try:
yield environ_update
finally:
if file_to_cleam_up:
os.remove(file_to_cleam_up)
return environ_update


def run_helm(module, command, fails_on_error=True):
if not HAS_YAML:
module.fail_json(msg=missing_required_lib("PyYAML"), exception=YAML_IMP_ERR)

with prepare_helm_environ_update(module) as environ_update:
rc, out, err = module.run_command(command, environ_update=environ_update)
environ_update = prepare_helm_environ_update(module)
rc, out, err = module.run_command(command, environ_update=environ_update)
if fails_on_error and rc != 0:
module.fail_json(
msg="Failure when executing Helm command. Exited {0}.\nstdout: {1}\nstderr: {2}".format(
Expand Down Expand Up @@ -118,7 +121,7 @@ def get_helm_plugin_list(module, helm_bin=None):
"""
if not helm_bin:
return []
helm_plugin_list = helm_bin + " list"
helm_plugin_list = helm_bin + " plugin list"
rc, out, err = run_helm(module, helm_plugin_list)
if rc != 0 or (out == "" and err == ""):
module.fail_json(
Expand Down Expand Up @@ -162,3 +165,9 @@ def get_helm_version(module, helm_bin):
if m:
return m.group(1)
return None


def get_helm_binary(module):
return module.params.get("binary_path") or module.get_bin_path(
"helm", required=True
)
44 changes: 44 additions & 0 deletions plugins/module_utils/helm_args_common.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from __future__ import absolute_import, division, print_function

from ansible.module_utils.basic import env_fallback

__metaclass__ = type


HELM_AUTH_ARG_SPEC = dict(
binary_path=dict(type="path"),
context=dict(
type="str",
aliases=["kube_context"],
fallback=(env_fallback, ["K8S_AUTH_CONTEXT"]),
),
kubeconfig=dict(
type="raw",
aliases=["kubeconfig_path"],
fallback=(env_fallback, ["K8S_AUTH_KUBECONFIG"]),
),
host=dict(type="str", fallback=(env_fallback, ["K8S_AUTH_HOST"])),
ca_cert=dict(
type="path",
aliases=["ssl_ca_cert"],
fallback=(env_fallback, ["K8S_AUTH_SSL_CA_CERT"]),
),
validate_certs=dict(
type="bool",
default=True,
aliases=["verify_ssl"],
fallback=(env_fallback, ["K8S_AUTH_VERIFY_SSL"]),
),
api_key=dict(
type="str",
no_log=True,
fallback=(env_fallback, ["K8S_AUTH_API_KEY"]),
),
)

HELM_AUTH_MUTUALLY_EXCLUSIVE = [
("context", "ca_cert"),
("context", "validate_certs"),
("kubeconfig", "ca_cert"),
("kubeconfig", "validate_certs"),
]
82 changes: 33 additions & 49 deletions plugins/modules/helm.py
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,7 @@
import re
import tempfile
import traceback
import copy
from ansible_collections.kubernetes.core.plugins.module_utils.version import (
LooseVersion,
)
Expand All @@ -348,13 +349,18 @@
IMP_YAML_ERR = traceback.format_exc()
IMP_YAML = False

from ansible.module_utils.basic import AnsibleModule, missing_required_lib, env_fallback
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible_collections.kubernetes.core.plugins.module_utils.helm import (
run_helm,
get_values,
get_helm_plugin_list,
parse_helm_plugin_list,
get_helm_version,
get_helm_binary,
)
from ansible_collections.kubernetes.core.plugins.module_utils.helm_args_common import (
HELM_AUTH_ARG_SPEC,
HELM_AUTH_MUTUALLY_EXCLUSIVE,
)


Expand Down Expand Up @@ -531,13 +537,12 @@ def load_values_files(values_files):
return values


def get_plugin_version(command, plugin):
def get_plugin_version(helm_bin, plugin):
"""
Check if helm plugin is installed and return corresponding version
"""

cmd = command + " plugin"
rc, output, err = get_helm_plugin_list(module, helm_bin=cmd)
rc, output, err = get_helm_plugin_list(module, helm_bin=helm_bin)
out = parse_helm_plugin_list(module, output=output.splitlines())

if not out:
Expand Down Expand Up @@ -612,11 +617,10 @@ def default_check(release_status, chart_info, values=None, values_files=None):
)


def main():
global module
module = AnsibleModule(
argument_spec=dict(
binary_path=dict(type="path"),
def argument_spec():
arg_spec = copy.deepcopy(HELM_AUTH_ARG_SPEC)
arg_spec.update(
dict(
chart_ref=dict(type="path"),
chart_repo_url=dict(type="str"),
chart_version=dict(type="str"),
Expand All @@ -629,19 +633,8 @@ def main():
release_values=dict(type="dict", default={}, aliases=["values"]),
values_files=dict(type="list", default=[], elements="str"),
update_repo_cache=dict(type="bool", default=False),
# Helm options
disable_hook=dict(type="bool", default=False),
force=dict(type="bool", default=False),
context=dict(
type="str",
aliases=["kube_context"],
fallback=(env_fallback, ["K8S_AUTH_CONTEXT"]),
),
kubeconfig=dict(
type="path",
aliases=["kubeconfig_path"],
fallback=(env_fallback, ["K8S_AUTH_KUBECONFIG"]),
),
purge=dict(type="bool", default=True),
wait=dict(type="bool", default=False),
wait_timeout=dict(type="str"),
Expand All @@ -652,33 +645,27 @@ def main():
replace=dict(type="bool", default=False),
skip_crds=dict(type="bool", default=False),
history_max=dict(type="int"),
# Generic auth key
host=dict(type="str", fallback=(env_fallback, ["K8S_AUTH_HOST"])),
ca_cert=dict(
type="path",
aliases=["ssl_ca_cert"],
fallback=(env_fallback, ["K8S_AUTH_SSL_CA_CERT"]),
),
validate_certs=dict(
type="bool",
default=True,
aliases=["verify_ssl"],
fallback=(env_fallback, ["K8S_AUTH_VERIFY_SSL"]),
),
api_key=dict(
type="str", no_log=True, fallback=(env_fallback, ["K8S_AUTH_API_KEY"])
),
),
)
)
return arg_spec


def mutually_exclusive():
mutual_ex = copy.deepcopy(HELM_AUTH_MUTUALLY_EXCLUSIVE)
mutual_ex.append(("replace", "history_max"))
mutual_ex.append(("wait_timeout", "timeout"))
return mutual_ex


def main():
global module
module = AnsibleModule(
argument_spec=argument_spec(),
required_if=[
("release_state", "present", ["release_name", "chart_ref"]),
("release_state", "absent", ["release_name"]),
],
mutually_exclusive=[
("context", "ca_cert"),
("kubeconfig", "ca_cert"),
("replace", "history_max"),
("wait_timeout", "timeout"),
],
mutually_exclusive=mutually_exclusive(),
supports_check_mode=True,
)

Expand All @@ -687,7 +674,6 @@ def main():

changed = False

bin_path = module.params.get("binary_path")
chart_ref = module.params.get("chart_ref")
chart_repo_url = module.params.get("chart_repo_url")
chart_version = module.params.get("chart_version")
Expand All @@ -712,10 +698,8 @@ def main():
history_max = module.params.get("history_max")
timeout = module.params.get("timeout")

if bin_path is not None:
helm_cmd_common = bin_path
else:
helm_cmd_common = module.get_bin_path("helm", required=True)
helm_cmd_common = get_helm_binary(module)
helm_bin = helm_cmd_common

if update_repo_cache:
run_repo_update(module, helm_cmd_common)
Expand Down Expand Up @@ -808,7 +792,7 @@ def main():

else:

helm_diff_version = get_plugin_version(helm_cmd_common, "diff")
helm_diff_version = get_plugin_version(helm_bin, "diff")
if helm_diff_version and (
not chart_repo_url
or (
Expand Down
Loading

0 comments on commit 0cb9645

Please sign in to comment.