diff --git a/changelogs/fragments/106-helm_replace.yml b/changelogs/fragments/106-helm_replace.yml new file mode 100644 index 00000000..6fd7b654 --- /dev/null +++ b/changelogs/fragments/106-helm_replace.yml @@ -0,0 +1,2 @@ +bugfixes: +- helm - add replace parameter (https://github.com/ansible-collections/community.kubernetes/issues/106). diff --git a/molecule/default/roles/helm/tasks/tests_chart.yml b/molecule/default/roles/helm/tasks/tests_chart.yml index b0341330..26cf19f0 100644 --- a/molecule/default/roles/helm/tasks/tests_chart.yml +++ b/molecule/default/roles/helm/tasks/tests_chart.yml @@ -201,6 +201,63 @@ 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: Remove helm namespace k8s: api_version: v1 diff --git a/plugins/modules/helm.py b/plugins/modules/helm.py index 9045dc05..c6870efa 100644 --- a/plugins/modules/helm.py +++ b/plugins/modules/helm.py @@ -115,6 +115,13 @@ type: bool default: False version_added: "0.11.1" + replace: + description: + - Reuse the given name, only if that name is a deleted release which remains in the history. + - This is unsafe in production environment. + type: bool + default: False + version_added: "1.11.0" extends_documentation_fragment: - community.kubernetes.helm_common_options ''' @@ -320,14 +327,20 @@ def fetch_chart_info(command, chart_ref): return yaml.safe_load(out) -def deploy(command, release_name, release_values, chart_name, wait, wait_timeout, disable_hook, force, atomic=False, create_namespace=False): +def deploy(command, release_name, release_values, chart_name, wait, + wait_timeout, disable_hook, force, atomic=False, create_namespace=False, + replace=False): """ Install/upgrade/rollback release chart """ - deploy_command = command + " upgrade -i" # install/upgrade + if replace: + # '--replace' is not supported by 'upgrade -i' + deploy_command = command + " install" + else: + deploy_command = command + " upgrade -i" # install/upgrade - # Always reset values to keep release_values equal to values released - deploy_command += " --reset-values" + # Always reset values to keep release_values equal to values released + deploy_command += " --reset-values" if wait: deploy_command += " --wait" @@ -340,6 +353,9 @@ def deploy(command, release_name, release_values, chart_name, wait, wait_timeout if force: deploy_command += " --force" + if replace: + deploy_command += " --replace" + if disable_hook: deploy_command += " --no-hooks" @@ -399,6 +415,7 @@ def main(): wait_timeout=dict(type='str'), atomic=dict(type='bool', default=False), create_namespace=dict(type='bool', default=False), + replace=dict(type='bool', default=False), ), required_if=[ ('release_state', 'present', ['release_name', 'chart_ref']), @@ -432,6 +449,7 @@ def main(): wait_timeout = module.params.get('wait_timeout') atomic = module.params.get('atomic') create_namespace = module.params.get('create_namespace') + replace = module.params.get('replace') if bin_path is not None: helm_cmd_common = bin_path @@ -455,6 +473,9 @@ def main(): # keep helm_cmd_common for get_release_status in module_exit_json helm_cmd = helm_cmd_common if release_state == "absent" and release_status is not None: + if replace: + module.fail_json(msg="replace is not applicable when state is absent") + helm_cmd = delete(helm_cmd, release_name, purge, disable_hook) changed = True elif release_state == "present": @@ -470,13 +491,15 @@ def main(): if release_status is None: # Not installed helm_cmd = deploy(helm_cmd, release_name, release_values, chart_ref, wait, wait_timeout, - disable_hook, False, atomic=atomic, create_namespace=create_namespace) + disable_hook, False, atomic=atomic, create_namespace=create_namespace, + replace=replace) changed = True elif force or release_values != release_status['values'] \ or (chart_info['name'] + '-' + chart_info['version']) != release_status["chart"]: helm_cmd = deploy(helm_cmd, release_name, release_values, chart_ref, wait, wait_timeout, - disable_hook, force, atomic=atomic, create_namespace=create_namespace) + disable_hook, force, atomic=atomic, create_namespace=create_namespace, + replace=replace) changed = True if module.check_mode: