From 50c82056b3f34c0e9325a937e01e03fe74a4c5b8 Mon Sep 17 00:00:00 2001 From: Nathan Loika Date: Wed, 7 Oct 2020 13:40:59 -0700 Subject: [PATCH] Add appVersion check to Helm (#247) When upgrading a Helm release include the chart's appVersion in the idempotence check. Fixes #246 --- .../files/appversionless-chart/Chart.yaml | 5 ++ .../roles/helm/files/test-chart/Chart.yaml | 6 ++ .../tasks/tests_chart/from_local_path.yml | 61 +++++++++++++++++++ plugins/modules/helm.py | 21 +++++-- 4 files changed, 87 insertions(+), 6 deletions(-) create mode 100644 molecule/default/roles/helm/files/appversionless-chart/Chart.yaml create mode 100644 molecule/default/roles/helm/files/test-chart/Chart.yaml diff --git a/molecule/default/roles/helm/files/appversionless-chart/Chart.yaml b/molecule/default/roles/helm/files/appversionless-chart/Chart.yaml new file mode 100644 index 00000000..c308a00a --- /dev/null +++ b/molecule/default/roles/helm/files/appversionless-chart/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v2 +name: appversionless-chart +description: A chart used in molecule tests +type: application +version: 0.1.0 diff --git a/molecule/default/roles/helm/files/test-chart/Chart.yaml b/molecule/default/roles/helm/files/test-chart/Chart.yaml new file mode 100644 index 00000000..5d09a08c --- /dev/null +++ b/molecule/default/roles/helm/files/test-chart/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +name: test-chart +description: A chart used in molecule tests +type: application +version: 0.1.0 +appVersion: "default" diff --git a/molecule/default/roles/helm/tasks/tests_chart/from_local_path.yml b/molecule/default/roles/helm/tasks/tests_chart/from_local_path.yml index 8b874718..58409809 100644 --- a/molecule/default/roles/helm/tasks/tests_chart/from_local_path.yml +++ b/molecule/default/roles/helm/tasks/tests_chart/from_local_path.yml @@ -18,6 +18,66 @@ chart_source: "/tmp/helm_test_repo/stable/{{ chart_test }}/" chart_source_upgrade: "/tmp/helm_test_repo_upgrade/stable/{{ chart_test }}/" +- name: Test appVersion idempotence + vars: + chart_test: "test-chart" + chart_test_version: "0.1.0" + chart_test_version_upgrade: "0.1.0" + chart_test_app_version: "v1" + chart_test_upgrade_app_version: "v2" + block: + - name: Copy test chart + copy: + src: "{{ chart_test }}" + dest: "/tmp/helm_test_appversion/test-chart/" + + # create package with appVersion v1 + - name: "Package chart into archive with appVersion {{ chart_test_app_version }}" + command: "{{ helm_binary }} package --app-version {{ chart_test_app_version }} /tmp/helm_test_appversion/test-chart/{{ chart_test }}" + - name: "Move appVersion {{ chart_test_app_version }} chart archive" + copy: + remote_src: true + src: "test-chart-{{ chart_test_version }}.tgz" + dest: "/tmp/helm_test_appversion/test-chart/{{ chart_test }}-{{ chart_test_app_version }}-{{ chart_test_version }}.tgz" + + # create package with appVersion v2 + - name: "Package chart into archive with appVersion {{ chart_test_upgrade_app_version }}" + command: "{{ helm_binary }} package --app-version {{ chart_test_upgrade_app_version }} /tmp/helm_test_appversion/test-chart/{{ chart_test }}" + - name: "Move appVersion {{ chart_test_upgrade_app_version }} chart archive" + copy: + remote_src: true + src: "test-chart-{{ chart_test_version }}.tgz" + dest: "/tmp/helm_test_appversion/test-chart/{{ chart_test }}-{{ chart_test_upgrade_app_version }}-{{ chart_test_version }}.tgz" + + - name: Install Chart from local path + include_tasks: "../tests_chart.yml" + vars: + source: local_path + chart_source: "/tmp/helm_test_appversion/test-chart/{{ chart_test }}-{{ chart_test_app_version }}-{{ chart_test_version }}.tgz" + chart_source_upgrade: "/tmp/helm_test_appversion/test-chart/{{ chart_test }}-{{ chart_test_upgrade_app_version }}-{{ chart_test_version }}.tgz" + +- name: Test appVersion handling when null + vars: + chart_test: "appversionless-chart" + chart_test_version: "0.1.0" + chart_test_version_upgrade: "0.1.0" + block: + - name: Copy test chart + copy: + src: "{{ chart_test }}" + dest: "/tmp/helm_test_appversion/test-null/" + + # create package with appVersion v1 + - name: "Package chart into archive with appVersion v1" + command: "{{ helm_binary }} package --app-version v1 /tmp/helm_test_appversion/test-null/{{ chart_test }}" + + - name: Install Chart from local path + include_tasks: "../tests_chart.yml" + vars: + source: local_path + chart_source: "/tmp/helm_test_appversion/test-null/{{ chart_test }}/" + chart_source_upgrade: "{{ chart_test }}-{{ chart_test_version }}.tgz" + - name: Remove clone repos file: path: "{{ item }}" @@ -25,3 +85,4 @@ with_items: - /tmp/helm_test_repo - /tmp/helm_test_repo_upgrade + - /tmp/helm_test_appversion diff --git a/plugins/modules/helm.py b/plugins/modules/helm.py index 9a796b1c..9df885c9 100644 --- a/plugins/modules/helm.py +++ b/plugins/modules/helm.py @@ -520,12 +520,21 @@ def main(): 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, values_files=values_files, atomic=atomic, - create_namespace=create_namespace, replace=replace) - changed = True + else: + # the 'appVersion' specification is optional in a chart + chart_app_version = chart_info.get('appVersion', None) + released_app_version = release_status.get('app_version', None) + + # when deployed without an 'appVersion' chart value the 'helm list' command will return the entry `app_version: ""` + appversion_is_same = (chart_app_version == released_app_version) or (chart_app_version is None and released_app_version == "") + + if force or release_values != release_status['values'] \ + or (chart_info['name'] + '-' + chart_info['version']) != release_status["chart"] \ + or not appversion_is_same: + helm_cmd = deploy(helm_cmd, release_name, release_values, chart_ref, wait, wait_timeout, + disable_hook, force, values_files=values_files, atomic=atomic, + create_namespace=create_namespace, replace=replace) + changed = True if module.check_mode: check_status = {'values': {