diff --git a/packages/@aws-cdk/aws-eks/lib/helm-chart.ts b/packages/@aws-cdk/aws-eks/lib/helm-chart.ts index 4ac6e5f176cbd..5d01af82f3ee5 100644 --- a/packages/@aws-cdk/aws-eks/lib/helm-chart.ts +++ b/packages/@aws-cdk/aws-eks/lib/helm-chart.ts @@ -73,6 +73,13 @@ export interface HelmChartOptions { */ readonly timeout?: Duration; + /** + * Whether or not Helm should treat this operation as atomic; if set, upgrade process rolls back changes + * made in case of failed upgrade. The --wait flag will be set automatically if --atomic is used. + * @default false + */ + readonly atomic?: boolean; + /** * create namespace if not exist * @default true @@ -129,6 +136,8 @@ export class HelmChart extends Construct { const wait = props.wait ?? false; // default to create new namespace const createNamespace = props.createNamespace ?? true; + // default to not use atomic operations + const atomic = props.atomic ?? false; props.chartAsset?.grantRead(provider.handlerRole); @@ -143,6 +152,7 @@ export class HelmChart extends Construct { ChartAssetURL: props.chartAsset?.s3ObjectUrl, Version: props.version, Wait: wait || undefined, // props are stringified so we encode “false” as undefined + Atomic: atomic || undefined, // props are stringified so we encode “false” as undefined Timeout: timeout ? `${timeout.toString()}s` : undefined, // Helm v3 expects duration instead of integer Values: (props.values ? stack.toJsonString(props.values) : undefined), Namespace: props.namespace ?? 'default', diff --git a/packages/@aws-cdk/aws-eks/lib/kubectl-handler/helm/__init__.py b/packages/@aws-cdk/aws-eks/lib/kubectl-handler/helm/__init__.py index b9a741c8972c4..8abb4851dd3a4 100644 --- a/packages/@aws-cdk/aws-eks/lib/kubectl-handler/helm/__init__.py +++ b/packages/@aws-cdk/aws-eks/lib/kubectl-handler/helm/__init__.py @@ -42,6 +42,7 @@ def helm_handler(event, context): chart_asset_url = props.get('ChartAssetURL', None) version = props.get('Version', None) wait = props.get('Wait', False) + atomic = props.get('Atomic', False) timeout = props.get('Timeout', None) namespace = props.get('Namespace', None) create_namespace = props.get('CreateNamespace', None) @@ -146,7 +147,7 @@ def get_chart_from_oci(tmpdir, release, repository = None, version = None): raise Exception(f'Operation failed after {maxAttempts} attempts: {output}') -def helm(verb, release, chart = None, repo = None, file = None, namespace = None, version = None, wait = False, timeout = None, create_namespace = None): +def helm(verb, release, chart = None, repo = None, file = None, namespace = None, version = None, wait = False, atomic = False, timeout = None, create_namespace = None): import subprocess cmnd = ['helm', verb, release] @@ -166,6 +167,8 @@ def helm(verb, release, chart = None, repo = None, file = None, namespace = None cmnd.extend(['--namespace', namespace]) if wait: cmnd.append('--wait') + if atomic: + cmnd.append("--atomic") if not timeout is None: cmnd.extend(['--timeout', timeout]) cmnd.extend(['--kubeconfig', kubeconfig]) diff --git a/packages/@aws-cdk/aws-eks/test/helm-chart.test.ts b/packages/@aws-cdk/aws-eks/test/helm-chart.test.ts index e9542f9c14484..1def5ac9828eb 100644 --- a/packages/@aws-cdk/aws-eks/test/helm-chart.test.ts +++ b/packages/@aws-cdk/aws-eks/test/helm-chart.test.ts @@ -187,6 +187,29 @@ describe('helm chart', () => { // THEN Template.fromStack(stack).hasResourceProperties(eks.HelmChart.RESOURCE_TYPE, { Wait: true }); }); + + test('should disable atomic operations by default', () => { + // GIVEN + const { stack, cluster } = testFixtureCluster(); + + // WHEN + new eks.HelmChart(stack, 'MyChart', { cluster, chart: 'chart' }); + + // THEN + const charts = Template.fromStack(stack).findResources(eks.HelmChart.RESOURCE_TYPE, { Atomic: true }); + expect(Object.keys(charts).length).toEqual(0); + }); + test('should enable atomic operations when specified', () => { + // GIVEN + const { stack, cluster } = testFixtureCluster(); + + // WHEN + new eks.HelmChart(stack, 'MyAtomicChart', { cluster, chart: 'chart', atomic: true }); + + // THEN + Template.fromStack(stack).hasResourceProperties(eks.HelmChart.RESOURCE_TYPE, { Atomic: true }); + }); + test('should disable waiting when specified as false', () => { // GIVEN const { stack, cluster } = testFixtureCluster();