From bc17b33d442a3d420155d9d11a7ca8b37dacee1a Mon Sep 17 00:00:00 2001 From: Yuriy Novostavskiy Date: Wed, 1 Jul 2026 20:30:52 +0200 Subject: [PATCH] helm: use --rollback-on-failure for atomic on Helm v4 (#1144) * helm: use --rollback-on-failure for atomic on Helm v4 Helm v4 renamed the `--atomic` flag to `--rollback-on-failure`. The old flag is deprecated on `helm upgrade` and removed entirely from `helm install`, so `atomic: true` failed against Helm v4 (issue #1143). Emit the version-appropriate flag from deploy() using the existing is_helm_v4() helper, covering both the upgrade and the replace/install code paths. The public `atomic` option is unchanged. Fixes: https://github.com/ansible-collections/kubernetes.core/issues/1143 Co-Authored-By: Claude Opus 4.8 * fix wrong link in the changelog fragment Signed-off-by: Yuriy Novostavskiy --------- Signed-off-by: Yuriy Novostavskiy --- .../20260611-helm-atomic-helm-v4.yml | 2 + plugins/modules/helm.py | 11 ++- tests/unit/modules/test_module_helm.py | 78 +++++++++++++++++++ 3 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 changelogs/fragments/20260611-helm-atomic-helm-v4.yml diff --git a/changelogs/fragments/20260611-helm-atomic-helm-v4.yml b/changelogs/fragments/20260611-helm-atomic-helm-v4.yml new file mode 100644 index 00000000..aed63489 --- /dev/null +++ b/changelogs/fragments/20260611-helm-atomic-helm-v4.yml @@ -0,0 +1,2 @@ +bugfixes: + - helm - use the ``--rollback-on-failure`` flag instead of the deprecated/removed ``--atomic`` flag when ``atomic=true`` is used with Helm v4 (https://github.com/ansible-collections/kubernetes.core/pull/1144). diff --git a/plugins/modules/helm.py b/plugins/modules/helm.py index 9ac209ad..536165aa 100644 --- a/plugins/modules/helm.py +++ b/plugins/modules/helm.py @@ -202,6 +202,9 @@ options: atomic: description: - If set, the installation process deletes the installation on failure. + - With Helm v4 this is translated to the C(--rollback-on-failure) flag, since + C(--atomic) was renamed; with Helm v3 the C(--atomic) flag is used. The + O(atomic) option works the same way regardless of the installed Helm version. type: bool default: False server_side: @@ -656,7 +659,13 @@ def deploy( deploy_command += " --timeout " + wait_timeout if atomic: - deploy_command += " --atomic" + # Helm v4 renamed '--atomic' to '--rollback-on-failure'. The old flag is + # deprecated on 'helm upgrade' and removed from 'helm install', so always + # emit the version-appropriate flag. + if module.is_helm_v4(): + deploy_command += " --rollback-on-failure" + else: + deploy_command += " --atomic" if timeout: deploy_command += " --timeout " + timeout diff --git a/tests/unit/modules/test_module_helm.py b/tests/unit/modules/test_module_helm.py index 6dd63889..3b219bdf 100644 --- a/tests/unit/modules/test_module_helm.py +++ b/tests/unit/modules/test_module_helm.py @@ -710,3 +710,81 @@ class TestForceFlagHelmVersion(unittest.TestCase): } ) helm.main() + + +class TestAtomicFlagHelmVersion(unittest.TestCase): + """Helm v4 renamed '--atomic' to '--rollback-on-failure' (issue #1143).""" + + def setUp(self): + self.mock_module_helper = patch.multiple( + basic.AnsibleModule, + exit_json=exit_json, + fail_json=fail_json, + get_bin_path=get_bin_path, + ) + self.mock_module_helper.start() + self.addCleanup(self.mock_module_helper.stop) + + self.chart_info = { + "apiVersion": "v2", + "appVersion": "default", + "description": "A chart used in molecule tests", + "name": "test-chart", + "type": "application", + "version": "0.1.0", + } + + def _run_with_version(self, args, helm_version): + set_module_args(args) + helm.get_release_status = MagicMock(return_value=None) + helm.fetch_chart_info = MagicMock(return_value=self.chart_info) + with patch.object( + helm.AnsibleHelmModule, "get_helm_version", return_value=helm_version + ): + with patch.object(basic.AnsibleModule, "run_command") as mock_run_command: + mock_run_command.return_value = (0, "configuration updated", "") + with self.assertRaises(AnsibleExitJson) as result: + helm.main() + return result.exception.args[0]["command"] + + def test_atomic_uses_atomic_flag_on_helm_v3(self): + command = self._run_with_version( + { + "release_name": "test", + "release_namespace": "test", + "chart_ref": "chart1", + "atomic": True, + }, + "3.17.0", + ) + assert "--atomic" in command + assert "--rollback-on-failure" not in command + + def test_atomic_uses_rollback_on_failure_on_helm_v4(self): + command = self._run_with_version( + { + "release_name": "test", + "release_namespace": "test", + "chart_ref": "chart1", + "atomic": True, + }, + "4.0.0", + ) + assert "--rollback-on-failure" in command + assert "--atomic" not in command + + def test_atomic_with_replace_uses_rollback_on_failure_on_helm_v4(self): + # 'replace' uses 'helm install', where '--atomic' is removed in v4. + command = self._run_with_version( + { + "release_name": "test", + "release_namespace": "test", + "chart_ref": "chart1", + "atomic": True, + "replace": True, + }, + "4.0.0", + ) + assert " install " in command + assert "--rollback-on-failure" in command + assert "--atomic" not in command