/
helm-chart.ts
153 lines (130 loc) · 4.69 KB
/
helm-chart.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
import { Asset } from '@aws-cdk/aws-s3-assets';
import { CustomResource, Duration, Names, Stack } from '@aws-cdk/core';
import { Construct } from 'constructs';
import { ICluster } from './cluster';
import { KubectlProvider } from './kubectl-provider';
// v2 - keep this import as a separate section to reduce merge conflict when forward merging with the v2 branch.
// eslint-disable-next-line
import { Construct as CoreConstruct } from '@aws-cdk/core';
/**
* Helm Chart options.
*/
export interface HelmChartOptions {
/**
* The name of the chart.
* Either this or `chartAsset` must be specified.
*
* @default - No chart name. Implies `chartAsset` is used.
*/
readonly chart?: string;
/**
* The name of the release.
* @default - If no release name is given, it will use the last 53 characters of the node's unique id.
*/
readonly release?: string;
/**
* The chart version to install.
* @default - If this is not specified, the latest version is installed
*/
readonly version?: string;
/**
* The repository which contains the chart. For example: https://kubernetes-charts.storage.googleapis.com/
* @default - No repository will be used, which means that the chart needs to be an absolute URL.
*/
readonly repository?: string;
/**
* The chart in the form of an asset.
* Either this or `chart` must be specified.
*
* @default - No chart asset. Implies `chart` is used.
*/
readonly chartAsset?: Asset;
/**
* The Kubernetes namespace scope of the requests.
* @default default
*/
readonly namespace?: string;
/**
* The values to be used by the chart.
* @default - No values are provided to the chart.
*/
readonly values?: {[key: string]: any};
/**
* Whether or not Helm should wait until all Pods, PVCs, Services, and minimum number of Pods of a
* Deployment, StatefulSet, or ReplicaSet are in a ready state before marking the release as successful.
* @default - Helm will not wait before marking release as successful
*/
readonly wait?: boolean;
/**
* Amount of time to wait for any individual Kubernetes operation. Maximum 15 minutes.
* @default Duration.minutes(5)
*/
readonly timeout?: Duration;
/**
* create namespace if not exist
* @default true
*/
readonly createNamespace?: boolean;
}
/**
* Helm Chart properties.
*/
export interface HelmChartProps extends HelmChartOptions {
/**
* The EKS cluster to apply this configuration to.
*
* [disable-awslint:ref-via-interface]
*/
readonly cluster: ICluster;
}
/**
* Represents a helm chart within the Kubernetes system.
*
* Applies/deletes the resources using `kubectl` in sync with the resource.
*/
export class HelmChart extends CoreConstruct {
/**
* The CloudFormation resource type.
*/
public static readonly RESOURCE_TYPE = 'Custom::AWSCDK-EKS-HelmChart';
constructor(scope: Construct, id: string, props: HelmChartProps) {
super(scope, id);
const stack = Stack.of(this);
const provider = KubectlProvider.getOrCreate(this, props.cluster);
const timeout = props.timeout?.toSeconds();
if (timeout && timeout > 900) {
throw new Error('Helm chart timeout cannot be higher than 15 minutes.');
}
if (!props.chart && !props.chartAsset) {
throw new Error("Either 'chart' or 'chartAsset' must be specified to install a helm chart");
}
if (props.chartAsset && (props.repository || props.version)) {
throw new Error(
"Neither 'repository' nor 'version' can be used when configuring 'chartAsset'",
);
}
// default not to wait
const wait = props.wait ?? false;
// default to create new namespace
const createNamespace = props.createNamespace ?? true;
props.chartAsset?.grantRead(provider.handlerRole);
new CustomResource(this, 'Resource', {
serviceToken: provider.serviceToken,
resourceType: HelmChart.RESOURCE_TYPE,
properties: {
ClusterName: props.cluster.clusterName,
RoleArn: provider.roleArn, // TODO: bake into the provider's environment
Release: props.release ?? Names.uniqueId(this).slice(-53).toLowerCase(), // Helm has a 53 character limit for the name
Chart: props.chart,
ChartAssetURL: props.chartAsset?.s3ObjectUrl,
Version: props.version,
Wait: wait || 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',
Repository: props.repository,
CreateNamespace: createNamespace || undefined,
},
});
}
}