diff --git a/changelogs/fragments/368-helm_template.yaml b/changelogs/fragments/368-helm_template.yaml new file mode 100644 index 00000000..32ddb313 --- /dev/null +++ b/changelogs/fragments/368-helm_template.yaml @@ -0,0 +1,2 @@ +minor_changes: + - helm_template - add helm_template module to support template functionality (https://github.com/ansible-collections/community.kubernetes/issues/367). diff --git a/molecule/default/roles/helm/tasks/tests_chart.yml b/molecule/default/roles/helm/tasks/tests_chart.yml index ae9275ef..e0644048 100644 --- a/molecule/default/roles/helm/tasks/tests_chart.yml +++ b/molecule/default/roles/helm/tasks/tests_chart.yml @@ -1,321 +1,365 @@ --- -- name: Check helm_info empty - helm_info: - binary_path: "{{ helm_binary }}" - name: test - namespace: "{{ helm_namespace }}" - register: empty_info - -- name: "Assert that no charts are installed with helm_info" - assert: - that: - - empty_info.status is undefined - -- name: "Install fail {{ chart_test }} from {{ source }}" - helm: - binary_path: "{{ helm_binary }}" - name: test - chart_ref: "{{ chart_source }}" - chart_version: "{{ chart_source_version | default(omit) }}" - namespace: "{{ helm_namespace }}" - ignore_errors: yes - register: install_fail - -- name: "Assert that Install fail {{ chart_test }} from {{ source }}" - assert: - that: - - install_fail is failed - - "'Error: create: failed to create: namespaces \"' + helm_namespace + '\" not found' in install_fail.stderr" - -- name: "Install {{ chart_test }} from {{ source }} in check mode" - helm: - binary_path: "{{ helm_binary }}" - name: test - chart_ref: "{{ chart_source }}" - chart_version: "{{ chart_source_version | default(omit) }}" - namespace: "{{ helm_namespace }}" - create_namespace: true - register: install_check_mode - check_mode: true - -- name: "Assert that {{ chart_test }} chart is installed from {{ source }} in check mode" - assert: - that: - - install_check_mode is changed - - install_check_mode.status is defined - - install_check_mode.status.values is defined - -- name: "Install {{ chart_test }} from {{ source }}" - helm: - binary_path: "{{ helm_binary }}" - name: test - chart_ref: "{{ chart_source }}" - chart_version: "{{ chart_source_version | default(omit) }}" - namespace: "{{ helm_namespace }}" - create_namespace: true - register: install - -- name: "Assert that {{ chart_test }} chart is installed from {{ source }}" - assert: - that: - - install is changed - - install.status.chart == "{{ chart_test }}-{{ chart_test_version }}" - - install.status.status | lower == 'deployed' - -- name: Check helm_info content - helm_info: - binary_path: "{{ helm_binary }}" - name: test - namespace: "{{ helm_namespace }}" - register: content_info - -- name: "Assert that {{ chart_test }} is installed from {{ source }} with helm_info" - assert: - that: - - content_info.status.chart == "{{ chart_test }}-{{ chart_test_version }}" - - content_info.status.status | lower == 'deployed' - -- name: Check idempotency - helm: - binary_path: "{{ helm_binary }}" - name: test - chart_ref: "{{ chart_source }}" - chart_version: "{{ chart_source_version | default(omit) }}" - namespace: "{{ helm_namespace }}" - register: install - -- name: Assert idempotency - assert: - that: - - install is not changed - - install.status.chart == "{{ chart_test }}-{{ chart_test_version }}" - - install.status.status | lower == 'deployed' - -- name: "Add vars to {{ chart_test }} from {{ source }}" - helm: - binary_path: "{{ helm_binary }}" - name: test - chart_ref: "{{ chart_source }}" - chart_version: "{{ chart_source_version | default(omit) }}" - namespace: "{{ helm_namespace }}" - values: "{{ chart_test_values }}" - register: install - -- name: "Assert that {{ chart_test }} chart is upgraded with new var from {{ source }}" - assert: - that: - - install is changed - - install.status.status | lower == 'deployed' - - install.status.chart == "{{ chart_test }}-{{ chart_test_version }}" - - "install.status['values'].revisionHistoryLimit == 0" - -- name: Check idempotency after adding vars - helm: - binary_path: "{{ helm_binary }}" - name: test - chart_ref: "{{ chart_source }}" - chart_version: "{{ chart_source_version | default(omit) }}" - namespace: "{{ helm_namespace }}" - values: "{{ chart_test_values }}" - register: install - -- name: Assert idempotency after add vars - assert: - that: - - install is not changed - - install.status.status | lower == 'deployed' - - install.status.chart == "{{ chart_test }}-{{ chart_test_version }}" - - "install.status['values'].revisionHistoryLimit == 0" - -- name: "Remove Vars to {{ chart_test }} from {{ source }}" - helm: - binary_path: "{{ helm_binary }}" - name: test - chart_ref: "{{ chart_source }}" - chart_version: "{{ chart_source_version | default(omit) }}" - namespace: "{{ helm_namespace }}" - register: install - -- name: "Assert that {{ chart_test }} chart is upgraded with new var from {{ source }}" - assert: - that: - - install is changed - - install.status.status | lower == 'deployed' - - install.status.chart == "{{ chart_test }}-{{ chart_test_version }}" - - install.status['values'] == {} - -- name: Check idempotency after removing vars - helm: - binary_path: "{{ helm_binary }}" - name: test - chart_ref: "{{ chart_source }}" - chart_version: "{{ chart_source_version | default(omit) }}" - namespace: "{{ helm_namespace }}" - register: install - -- name: Assert idempotency after removing vars - assert: - that: - - install is not changed - - install.status.status | lower == 'deployed' - - install.status.chart == "{{ chart_test }}-{{ chart_test_version }}" - - install.status['values'] == {} - -- name: "Upgrade {{ chart_test }} from {{ source }}" - helm: - binary_path: "{{ helm_binary }}" - name: test - chart_ref: "{{ chart_source_upgrade | default(chart_source) }}" - chart_version: "{{ chart_source_version_upgrade | default(omit) }}" - namespace: "{{ helm_namespace }}" - register: install - -- name: "Assert that {{ chart_test }} chart is upgraded with new version from {{ source }}" - assert: - that: - - install is changed - - install.status.status | lower == 'deployed' - - install.status.chart == "{{ chart_test }}-{{ chart_test_version_upgrade }}" - -- name: Check idempotency after upgrade - helm: - binary_path: "{{ helm_binary }}" - name: test - chart_ref: "{{ chart_source_upgrade | default(chart_source) }}" - chart_version: "{{ chart_source_version_upgrade | default(omit) }}" - namespace: "{{ helm_namespace }}" - register: install - -- name: Assert idempotency after upgrade - assert: - that: - - install is not changed - - install.status.status | lower == 'deployed' - - install.status.chart == "{{ chart_test }}-{{ chart_test_version_upgrade }}" - -- name: "Remove {{ chart_test }} from {{ source }}" - helm: - binary_path: "{{ helm_binary }}" - state: absent - name: test - namespace: "{{ helm_namespace }}" - register: install - -- name: "Assert that {{ chart_test }} chart is removed from {{ source }}" - assert: - that: - - install is changed - -- name: Check idempotency after remove - helm: - binary_path: "{{ helm_binary }}" - state: absent - name: test - namespace: "{{ helm_namespace }}" - register: install - -- name: Assert idempotency - assert: - that: - - install is not changed - -# Test --replace -- name: Install chart for replace option - helm: - binary_path: "{{ helm_binary }}" - name: test-0001 - chart_ref: "{{ chart_source }}" - chart_version: "{{ chart_source_version | default(omit) }}" - namespace: "{{ helm_namespace }}" - register: install - -- name: "Assert that {{ chart_test }} chart is installed from {{ source }}" - assert: - that: - - install is changed - -- name: Remove {{ chart_test }} with --purge - helm: - binary_path: "{{ helm_binary }}" - state: absent - name: test-0001 - purge: False - namespace: "{{ helm_namespace }}" - register: install - -- name: Check if chart is removed - assert: - that: - - install is changed - -- name: Install chart again with same name test-0001 - helm: - binary_path: "{{ helm_binary }}" - name: test-0001 - chart_ref: "{{ chart_source }}" - chart_version: "{{ chart_source_version | default(omit) }}" - namespace: "{{ helm_namespace }}" - replace: True - register: install - -- name: "Assert that {{ chart_test }} chart is installed from {{ source }}" - assert: - that: - - install is changed - -- name: Remove {{ chart_test }} (cleanup) - helm: - binary_path: "{{ helm_binary }}" - state: absent - name: test-0001 - namespace: "{{ helm_namespace }}" - register: install - -- name: Check if chart is removed - assert: - that: - - install is changed - -- name: "Install {{ chart_test }} from {{ source }} with values_files" - helm: - binary_path: "{{ helm_binary }}" - name: test - chart_ref: "{{ chart_source }}" - chart_version: "{{ chart_source_version | default(omit) }}" - namespace: "{{ helm_namespace }}" - values_files: - - "{{ role_path }}/files/values.yaml" - register: install - -- name: "Assert that {{ chart_test }} chart has var from {{ source }}" - assert: - that: - - install is changed - - install.status.status | lower == 'deployed' - - install.status.chart == "{{ chart_test }}-{{ chart_test_version }}" - - "install.status['values'].revisionHistoryLimit == 0" - -- name: "Install {{ chart_test }} from {{ source }} with values_files (again)" - helm: - binary_path: "{{ helm_binary }}" - name: test - chart_ref: "{{ chart_source }}" - chart_version: "{{ chart_source_version | default(omit) }}" - namespace: "{{ helm_namespace }}" - values_files: - - "{{ role_path }}/files/values.yaml" - register: install - -- name: "Assert the result is consistent" - assert: - that: - - not (install is changed) - -- name: Remove helm namespace - k8s: - api_version: v1 - kind: Namespace - name: "{{ helm_namespace }}" - state: absent - wait: true - wait_timeout: 180 +- name: Chart tests + block: + - name: Create temp directory + tempfile: + state: directory + register: tmpdir + + - name: Set temp directory fact + set_fact: + temp_dir: "{{ tmpdir.path }}" + + - name: Check helm_info empty + helm_info: + binary_path: "{{ helm_binary }}" + name: test + namespace: "{{ helm_namespace }}" + register: empty_info + + - name: "Assert that no charts are installed with helm_info" + assert: + that: + - empty_info.status is undefined + + - name: "Install fail {{ chart_test }} from {{ source }}" + helm: + binary_path: "{{ helm_binary }}" + name: test + chart_ref: "{{ chart_source }}" + chart_version: "{{ chart_source_version | default(omit) }}" + namespace: "{{ helm_namespace }}" + ignore_errors: yes + register: install_fail + + - name: "Assert that Install fail {{ chart_test }} from {{ source }}" + assert: + that: + - install_fail is failed + - "'Error: create: failed to create: namespaces \"' + helm_namespace + '\" not found' in install_fail.stderr" + + - name: "Install {{ chart_test }} from {{ source }} in check mode" + helm: + binary_path: "{{ helm_binary }}" + name: test + chart_ref: "{{ chart_source }}" + chart_version: "{{ chart_source_version | default(omit) }}" + namespace: "{{ helm_namespace }}" + create_namespace: true + register: install_check_mode + check_mode: true + + - name: "Assert that {{ chart_test }} chart is installed from {{ source }} in check mode" + assert: + that: + - install_check_mode is changed + - install_check_mode.status is defined + - install_check_mode.status.values is defined + + - name: "Install {{ chart_test }} from {{ source }}" + helm: + binary_path: "{{ helm_binary }}" + name: test + chart_ref: "{{ chart_source }}" + chart_version: "{{ chart_source_version | default(omit) }}" + namespace: "{{ helm_namespace }}" + create_namespace: true + register: install + + - name: "Assert that {{ chart_test }} chart is installed from {{ source }}" + assert: + that: + - install is changed + - install.status.chart == "{{ chart_test }}-{{ chart_test_version }}" + - install.status.status | lower == 'deployed' + + - name: Check helm_info content + helm_info: + binary_path: "{{ helm_binary }}" + name: test + namespace: "{{ helm_namespace }}" + register: content_info + + - name: "Assert that {{ chart_test }} is installed from {{ source }} with helm_info" + assert: + that: + - content_info.status.chart == "{{ chart_test }}-{{ chart_test_version }}" + - content_info.status.status | lower == 'deployed' + + - name: Check idempotency + helm: + binary_path: "{{ helm_binary }}" + name: test + chart_ref: "{{ chart_source }}" + chart_version: "{{ chart_source_version | default(omit) }}" + namespace: "{{ helm_namespace }}" + register: install + + - name: Assert idempotency + assert: + that: + - install is not changed + - install.status.chart == "{{ chart_test }}-{{ chart_test_version }}" + - install.status.status | lower == 'deployed' + + - name: "Add vars to {{ chart_test }} from {{ source }}" + helm: + binary_path: "{{ helm_binary }}" + name: test + chart_ref: "{{ chart_source }}" + chart_version: "{{ chart_source_version | default(omit) }}" + namespace: "{{ helm_namespace }}" + values: "{{ chart_test_values }}" + register: install + + - name: "Assert that {{ chart_test }} chart is upgraded with new var from {{ source }}" + assert: + that: + - install is changed + - install.status.status | lower == 'deployed' + - install.status.chart == "{{ chart_test }}-{{ chart_test_version }}" + - "install.status['values'].revisionHistoryLimit == 0" + + - name: Check idempotency after adding vars + helm: + binary_path: "{{ helm_binary }}" + name: test + chart_ref: "{{ chart_source }}" + chart_version: "{{ chart_source_version | default(omit) }}" + namespace: "{{ helm_namespace }}" + values: "{{ chart_test_values }}" + register: install + + - name: Assert idempotency after add vars + assert: + that: + - install is not changed + - install.status.status | lower == 'deployed' + - install.status.chart == "{{ chart_test }}-{{ chart_test_version }}" + - "install.status['values'].revisionHistoryLimit == 0" + + - name: "Remove Vars to {{ chart_test }} from {{ source }}" + helm: + binary_path: "{{ helm_binary }}" + name: test + chart_ref: "{{ chart_source }}" + chart_version: "{{ chart_source_version | default(omit) }}" + namespace: "{{ helm_namespace }}" + register: install + + - name: "Assert that {{ chart_test }} chart is upgraded with new var from {{ source }}" + assert: + that: + - install is changed + - install.status.status | lower == 'deployed' + - install.status.chart == "{{ chart_test }}-{{ chart_test_version }}" + - install.status['values'] == {} + + - name: Check idempotency after removing vars + helm: + binary_path: "{{ helm_binary }}" + name: test + chart_ref: "{{ chart_source }}" + chart_version: "{{ chart_source_version | default(omit) }}" + namespace: "{{ helm_namespace }}" + register: install + + - name: Assert idempotency after removing vars + assert: + that: + - install is not changed + - install.status.status | lower == 'deployed' + - install.status.chart == "{{ chart_test }}-{{ chart_test_version }}" + - install.status['values'] == {} + + - name: "Upgrade {{ chart_test }} from {{ source }}" + helm: + binary_path: "{{ helm_binary }}" + name: test + chart_ref: "{{ chart_source_upgrade | default(chart_source) }}" + chart_version: "{{ chart_source_version_upgrade | default(omit) }}" + namespace: "{{ helm_namespace }}" + register: install + + - name: "Assert that {{ chart_test }} chart is upgraded with new version from {{ source }}" + assert: + that: + - install is changed + - install.status.status | lower == 'deployed' + - install.status.chart == "{{ chart_test }}-{{ chart_test_version_upgrade }}" + + - name: Check idempotency after upgrade + helm: + binary_path: "{{ helm_binary }}" + name: test + chart_ref: "{{ chart_source_upgrade | default(chart_source) }}" + chart_version: "{{ chart_source_version_upgrade | default(omit) }}" + namespace: "{{ helm_namespace }}" + register: install + + - name: Assert idempotency after upgrade + assert: + that: + - install is not changed + - install.status.status | lower == 'deployed' + - install.status.chart == "{{ chart_test }}-{{ chart_test_version_upgrade }}" + + - name: "Remove {{ chart_test }} from {{ source }}" + helm: + binary_path: "{{ helm_binary }}" + state: absent + name: test + namespace: "{{ helm_namespace }}" + register: install + + - name: "Assert that {{ chart_test }} chart is removed from {{ source }}" + assert: + that: + - install is changed + + - name: Check idempotency after remove + helm: + binary_path: "{{ helm_binary }}" + state: absent + name: test + namespace: "{{ helm_namespace }}" + register: install + + - name: Assert idempotency + assert: + that: + - install is not changed + + # Test --replace + - name: Install chart for replace option + helm: + binary_path: "{{ helm_binary }}" + name: test-0001 + chart_ref: "{{ chart_source }}" + chart_version: "{{ chart_source_version | default(omit) }}" + namespace: "{{ helm_namespace }}" + register: install + + - name: "Assert that {{ chart_test }} chart is installed from {{ source }}" + assert: + that: + - install is changed + + - name: Remove {{ chart_test }} with --purge + helm: + binary_path: "{{ helm_binary }}" + state: absent + name: test-0001 + purge: False + namespace: "{{ helm_namespace }}" + register: install + + - name: Check if chart is removed + assert: + that: + - install is changed + + - name: Install chart again with same name test-0001 + helm: + binary_path: "{{ helm_binary }}" + name: test-0001 + chart_ref: "{{ chart_source }}" + chart_version: "{{ chart_source_version | default(omit) }}" + namespace: "{{ helm_namespace }}" + replace: True + register: install + + - name: "Assert that {{ chart_test }} chart is installed from {{ source }}" + assert: + that: + - install is changed + + - name: Remove {{ chart_test }} (cleanup) + helm: + binary_path: "{{ helm_binary }}" + state: absent + name: test-0001 + namespace: "{{ helm_namespace }}" + register: install + + - name: Check if chart is removed + assert: + that: + - install is changed + + - name: "Install {{ chart_test }} from {{ source }} with values_files" + helm: + binary_path: "{{ helm_binary }}" + name: test + chart_ref: "{{ chart_source }}" + chart_version: "{{ chart_source_version | default(omit) }}" + namespace: "{{ helm_namespace }}" + values_files: + - "{{ role_path }}/files/values.yaml" + register: install + + - name: "Assert that {{ chart_test }} chart has var from {{ source }}" + assert: + that: + - install is changed + - install.status.status | lower == 'deployed' + - install.status.chart == "{{ chart_test }}-{{ chart_test_version }}" + - "install.status['values'].revisionHistoryLimit == 0" + + - name: "Install {{ chart_test }} from {{ source }} with values_files (again)" + helm: + binary_path: "{{ helm_binary }}" + name: test + chart_ref: "{{ chart_source }}" + chart_version: "{{ chart_source_version | default(omit) }}" + namespace: "{{ helm_namespace }}" + values_files: + - "{{ role_path }}/files/values.yaml" + register: install + + - name: "Assert the result is consistent" + assert: + that: + - not (install is changed) + + - name: Render templates + helm_template: + binary_path: "{{ helm_binary }}" + chart_ref: "{{ chart_source }}" + chart_version: "{{ chart_source_version | default(omit) }}" + output_dir: "{{ temp_dir }}" + values_files: + - "{{ role_path }}/files/values.yaml" + register: result + + - assert: + that: + - result is changed + - result is not failed + - result.rc == 0 + - result.command is match("{{ helm_binary }} template {{ chart_source }}") + + - name: Check templates created + stat: + path: "{{ temp_dir }}/{{ chart_test }}/templates" + register: result + + - assert: + that: + result.stat.exists + + always: + - name: Clean up temp dir + file: + state: absent + path: "{{ temp_dir }}" + ignore_errors: true + + - name: Remove helm namespace + k8s: + api_version: v1 + kind: Namespace + name: "{{ helm_namespace }}" + state: absent + wait: true + wait_timeout: 180 diff --git a/plugins/modules/helm_template.py b/plugins/modules/helm_template.py new file mode 100644 index 00000000..0a699f48 --- /dev/null +++ b/plugins/modules/helm_template.py @@ -0,0 +1,220 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r''' + +module: helm_template + +short_description: Render chart templates + +author: + - Mike Graves (@gravesm) + +description: + - Render chart templates to an output directory or as text of concatenated yaml documents. + +options: + binary_path: + description: + - The path of a helm binary to use. + required: false + type: path + chart_ref: + description: + - Chart reference with repo prefix, for example, C(nginx-stable/nginx-ingress). + - Path to a packaged chart. + - Path to an unpacked chart directory. + - Absolute URL. + required: true + type: path + chart_repo_url: + description: + - Chart repository URL where the requested chart is located. + required: false + type: str + chart_version: + description: + - Chart version to use. If this is not specified, the latest version is installed. + required: false + type: str + include_crds: + description: + - Include custom resource descriptions in rendered templates. + required: false + type: bool + default: false + output_dir: + description: + - Output directory where templates will be written. + - If the directory already exists, it will be overwritten. + required: false + type: path + release_values: + description: + - Values to pass to chart. + required: false + default: {} + aliases: [ values ] + type: dict + values_files: + description: + - Value files to pass to chart. + - Paths will be read from the target host's filesystem, not the host running ansible. + - I(values_files) option is evaluated before I(values) option if both are used. + - Paths are evaluated in the order the paths are specified. + required: false + default: [] + type: list + elements: str + update_repo_cache: + description: + - Run C(helm repo update) before the operation. Can be run as part of the template generation or as a separate step. + default: false + type: bool +''' + +EXAMPLES = r''' +- name: Render templates to specified directory + community.kubernetes.helm_template: + chart_ref: stable/prometheus + output_dir: mycharts + +- name: Render templates + community.kubernetes.helm_template: + chart_ref: stable/prometheus + register: result + +- name: Write templates to file + copy: + dest: myfile.yaml + content: "{{ result.stdout }}" +''' + +RETURN = r''' +stdout: + type: str + description: Full C(helm) command stdout. If no I(output_dir) has been provided this will contain the rendered templates as concatenated yaml documents. + returned: always + sample: '' +stderr: + type: str + description: Full C(helm) command stderr, in case you want to display it or examine the event log. + returned: always + sample: '' +command: + type: str + description: Full C(helm) command run by this module, in case you want to re-run the command outside the module or debug a problem. + returned: always + sample: helm template --output-dir mychart nginx-stable/nginx-ingress +''' + +import tempfile +import traceback + +try: + import yaml + IMP_YAML = True +except ImportError: + IMP_YAML_ERR = traceback.format_exc() + IMP_YAML = False + +from ansible.module_utils.basic import AnsibleModule, missing_required_lib +from ansible_collections.community.kubernetes.plugins.module_utils.helm import run_helm + + +def template(cmd, chart_ref, chart_repo_url=None, chart_version=None, output_dir=None, + release_values=None, values_files=None, include_crds=False): + cmd += " template " + chart_ref + + if chart_repo_url: + cmd += " --repo=" + chart_repo_url + + if chart_version: + cmd += " --version=" + chart_version + + if output_dir: + cmd += " --output-dir=" + output_dir + + if release_values: + fd, path = tempfile.mkstemp(suffix='.yml') + with open(path, 'w') as yaml_file: + yaml.dump(release_values, yaml_file, default_flow_style=False) + cmd += " -f=" + path + + if values_files: + for values_file in values_files: + cmd += " -f=" + values_file + + if include_crds: + cmd += " --include-crds" + + return cmd + + +def main(): + module = AnsibleModule( + argument_spec=dict( + binary_path=dict(type='path'), + chart_ref=dict(type='path', required=True), + chart_repo_url=dict(type='str'), + chart_version=dict(type='str'), + include_crds=dict(type='bool', default=False), + output_dir=dict(type='path'), + release_values=dict(type='dict', default={}, aliases=['values']), + values_files=dict(type='list', default=[], elements='str'), + update_repo_cache=dict(type='bool', default=False) + ), + supports_check_mode=True + ) + + check_mode = module.check_mode + 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') + include_crds = module.params.get('include_crds') + output_dir = module.params.get('output_dir') + release_values = module.params.get('release_values') + values_files = module.params.get('values_files') + update_repo_cache = module.params.get('update_repo_cache') + + if not IMP_YAML: + module.fail_json(msg=missing_required_lib("yaml"), exception=IMP_YAML_ERR) + + helm_cmd = bin_path or module.get_bin_path('helm', required=True) + + if update_repo_cache: + update_cmd = helm_cmd + " repo update" + run_helm(module, update_cmd) + + tmpl_cmd = template(helm_cmd, chart_ref, chart_repo_url=chart_repo_url, + chart_version=chart_version, output_dir=output_dir, + release_values=release_values, values_files=values_files, + include_crds=include_crds) + + if not check_mode: + rc, out, err = run_helm(module, tmpl_cmd) + else: + out = err = "" + rc = 0 + + module.exit_json( + failed=False, + changed=True, + command=tmpl_cmd, + stdout=out, + stderr=err, + rc=rc + ) + + +if __name__ == '__main__': + main()