timonel 2.8.3 → 2.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/README.md +35 -0
- package/dist/cli.js +255 -680
- package/dist/index.d.ts +4 -1
- package/dist/index.js +4 -1
- package/dist/lib/helmChartWriter.js +26 -4
- package/dist/lib/rutter.d.ts +28 -16
- package/dist/lib/rutter.js +250 -48
- package/dist/lib/templates/basic-chart.d.ts +19 -0
- package/dist/lib/templates/basic-chart.js +189 -0
- package/dist/lib/templates/subchart.d.ts +27 -0
- package/dist/lib/templates/subchart.js +221 -0
- package/dist/lib/templates/umbrella-chart.d.ts +13 -0
- package/dist/lib/templates/umbrella-chart.js +222 -0
- package/dist/lib/types.d.ts +20 -0
- package/dist/lib/types.js +1 -0
- package/dist/lib/utils/helmHelpers.d.ts +18 -2
- package/dist/lib/utils/helmHelpers.js +246 -3
- package/package.json +4 -5
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { Chart, ApiObject } from 'cdk8s';
|
|
2
|
+
import { Rutter } from '../rutter.js';
|
|
3
|
+
export class BasicChart extends Chart {
|
|
4
|
+
constructor(scope, id, props = {}) {
|
|
5
|
+
super(scope, id, props);
|
|
6
|
+
this.props = props;
|
|
7
|
+
this.initializeRutter();
|
|
8
|
+
this.generateKubernetesManifests();
|
|
9
|
+
}
|
|
10
|
+
initializeRutter() {
|
|
11
|
+
const { appName = 'my-app', image = 'nginx:latest', port = 80, replicas = 1, createNamespace = false, } = this.props;
|
|
12
|
+
const meta = {
|
|
13
|
+
name: appName,
|
|
14
|
+
version: '1.0.0',
|
|
15
|
+
description: `Helm chart for ${appName}`,
|
|
16
|
+
};
|
|
17
|
+
this.rutter = new Rutter({
|
|
18
|
+
meta,
|
|
19
|
+
scope: this,
|
|
20
|
+
defaultValues: {
|
|
21
|
+
appName,
|
|
22
|
+
image,
|
|
23
|
+
port,
|
|
24
|
+
replicas,
|
|
25
|
+
createNamespace,
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
if (createNamespace) {
|
|
29
|
+
this.rutter.addConditionalManifest({
|
|
30
|
+
apiVersion: 'v1',
|
|
31
|
+
kind: 'Namespace',
|
|
32
|
+
metadata: {
|
|
33
|
+
name: `{{ .Values.appName }}`,
|
|
34
|
+
},
|
|
35
|
+
}, 'createNamespace', 'namespace');
|
|
36
|
+
}
|
|
37
|
+
this.rutter.addManifest({
|
|
38
|
+
apiVersion: 'apps/v1',
|
|
39
|
+
kind: 'Deployment',
|
|
40
|
+
metadata: {
|
|
41
|
+
name: `{{ .Values.appName }}`,
|
|
42
|
+
labels: {
|
|
43
|
+
app: `{{ .Values.appName }}`,
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
spec: {
|
|
47
|
+
replicas: `{{ .Values.replicas }}`,
|
|
48
|
+
selector: {
|
|
49
|
+
matchLabels: {
|
|
50
|
+
app: `{{ .Values.appName }}`,
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
template: {
|
|
54
|
+
metadata: {
|
|
55
|
+
labels: {
|
|
56
|
+
app: `{{ .Values.appName }}`,
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
spec: {
|
|
60
|
+
containers: [
|
|
61
|
+
{
|
|
62
|
+
name: 'app',
|
|
63
|
+
image: `{{ .Values.image }}`,
|
|
64
|
+
ports: [
|
|
65
|
+
{
|
|
66
|
+
containerPort: `{{ .Values.port }}`,
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
}, 'deployment');
|
|
75
|
+
this.rutter.addManifest({
|
|
76
|
+
apiVersion: 'v1',
|
|
77
|
+
kind: 'Service',
|
|
78
|
+
metadata: {
|
|
79
|
+
name: `{{ .Values.appName }}`,
|
|
80
|
+
labels: {
|
|
81
|
+
app: `{{ .Values.appName }}`,
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
spec: {
|
|
85
|
+
ports: [
|
|
86
|
+
{
|
|
87
|
+
port: `{{ .Values.port }}`,
|
|
88
|
+
targetPort: `{{ .Values.port }}`,
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
selector: {
|
|
92
|
+
app: `{{ .Values.appName }}`,
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
}, 'service');
|
|
96
|
+
}
|
|
97
|
+
writeHelmChart(outDir) {
|
|
98
|
+
this.rutter.write(outDir);
|
|
99
|
+
}
|
|
100
|
+
generateKubernetesManifests() {
|
|
101
|
+
const { appName = 'my-app', image = 'nginx:latest', port = 80, replicas = 1, createNamespace = false, } = this.props;
|
|
102
|
+
if (createNamespace) {
|
|
103
|
+
new ApiObject(this, 'namespace', {
|
|
104
|
+
apiVersion: 'v1',
|
|
105
|
+
kind: 'Namespace',
|
|
106
|
+
metadata: {
|
|
107
|
+
name: appName,
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
new ApiObject(this, 'deployment', {
|
|
112
|
+
apiVersion: 'apps/v1',
|
|
113
|
+
kind: 'Deployment',
|
|
114
|
+
metadata: {
|
|
115
|
+
name: appName,
|
|
116
|
+
labels: {
|
|
117
|
+
app: appName,
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
spec: {
|
|
121
|
+
replicas,
|
|
122
|
+
selector: {
|
|
123
|
+
matchLabels: {
|
|
124
|
+
app: appName,
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
template: {
|
|
128
|
+
metadata: {
|
|
129
|
+
labels: {
|
|
130
|
+
app: appName,
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
spec: {
|
|
134
|
+
containers: [
|
|
135
|
+
{
|
|
136
|
+
name: 'app',
|
|
137
|
+
image,
|
|
138
|
+
ports: [
|
|
139
|
+
{
|
|
140
|
+
containerPort: port,
|
|
141
|
+
},
|
|
142
|
+
],
|
|
143
|
+
},
|
|
144
|
+
],
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
});
|
|
149
|
+
new ApiObject(this, 'service', {
|
|
150
|
+
apiVersion: 'v1',
|
|
151
|
+
kind: 'Service',
|
|
152
|
+
metadata: {
|
|
153
|
+
name: appName,
|
|
154
|
+
labels: {
|
|
155
|
+
app: appName,
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
spec: {
|
|
159
|
+
ports: [
|
|
160
|
+
{
|
|
161
|
+
port,
|
|
162
|
+
targetPort: port,
|
|
163
|
+
},
|
|
164
|
+
],
|
|
165
|
+
selector: {
|
|
166
|
+
app: appName,
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
export function generateBasicChart(appName = 'my-app') {
|
|
173
|
+
return `import { App } from 'cdk8s';
|
|
174
|
+
import { BasicChart } from 'timonel';
|
|
175
|
+
|
|
176
|
+
const app = new App();
|
|
177
|
+
|
|
178
|
+
const chart = new BasicChart(app, '${appName}', {
|
|
179
|
+
appName: '${appName}',
|
|
180
|
+
image: 'nginx:latest',
|
|
181
|
+
port: 80,
|
|
182
|
+
replicas: 1,
|
|
183
|
+
createNamespace: true // Set to true to create namespace, false to skip
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
// Generate complete Helm chart structure (Chart.yaml, values.yaml, templates/, _helpers.tpl)
|
|
187
|
+
chart.writeHelmChart('dist');
|
|
188
|
+
`;
|
|
189
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Chart } from 'cdk8s';
|
|
2
|
+
import type { ChartProps } from 'cdk8s';
|
|
3
|
+
import type { Construct } from 'constructs';
|
|
4
|
+
import { Rutter } from '../rutter.js';
|
|
5
|
+
export interface SubchartProps extends ChartProps {
|
|
6
|
+
appName?: string;
|
|
7
|
+
image?: string;
|
|
8
|
+
port?: number;
|
|
9
|
+
replicas?: number;
|
|
10
|
+
serviceType?: string;
|
|
11
|
+
enableIngress?: boolean;
|
|
12
|
+
ingressHost?: string;
|
|
13
|
+
env?: Record<string, string>;
|
|
14
|
+
persistentVolume?: {
|
|
15
|
+
enabled: boolean;
|
|
16
|
+
size: string;
|
|
17
|
+
storageClass?: string;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export declare class Subchart extends Chart {
|
|
21
|
+
private rutter;
|
|
22
|
+
constructor(scope: Construct, id: string, props?: SubchartProps);
|
|
23
|
+
get rutterInstance(): Rutter;
|
|
24
|
+
writeHelmChart(outDir: string): void;
|
|
25
|
+
}
|
|
26
|
+
export declare function generateSubchart(props?: SubchartProps, outDir?: string): void;
|
|
27
|
+
export declare function generateSubchartTemplate(name: string): string;
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { App, Chart } from 'cdk8s';
|
|
2
|
+
import { Rutter } from '../rutter.js';
|
|
3
|
+
export class Subchart extends Chart {
|
|
4
|
+
constructor(scope, id, props = {}) {
|
|
5
|
+
super(scope, id, props);
|
|
6
|
+
const { appName = 'subchart-app', image = 'nginx:latest', port = 80, replicas = 1, serviceType = 'ClusterIP', enableIngress = false, ingressHost = 'example.com', env = {}, persistentVolume = { enabled: false, size: '1Gi' }, } = props;
|
|
7
|
+
const meta = {
|
|
8
|
+
name: appName,
|
|
9
|
+
version: '1.0.0',
|
|
10
|
+
description: `Helm chart for ${appName}`,
|
|
11
|
+
};
|
|
12
|
+
this.rutter = new Rutter({
|
|
13
|
+
meta,
|
|
14
|
+
scope: this,
|
|
15
|
+
defaultValues: {
|
|
16
|
+
appName,
|
|
17
|
+
image,
|
|
18
|
+
port,
|
|
19
|
+
replicas,
|
|
20
|
+
serviceType,
|
|
21
|
+
enableIngress,
|
|
22
|
+
ingressHost,
|
|
23
|
+
env,
|
|
24
|
+
persistentVolume,
|
|
25
|
+
ingress: {
|
|
26
|
+
annotations: {},
|
|
27
|
+
className: '',
|
|
28
|
+
hosts: [
|
|
29
|
+
{
|
|
30
|
+
host: ingressHost,
|
|
31
|
+
paths: [
|
|
32
|
+
{
|
|
33
|
+
path: '/',
|
|
34
|
+
pathType: 'Prefix',
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
tls: [],
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
this.rutter.addManifest({
|
|
44
|
+
apiVersion: 'v1',
|
|
45
|
+
kind: 'ConfigMap',
|
|
46
|
+
metadata: {
|
|
47
|
+
name: `{{ .Values.appName }}-config`,
|
|
48
|
+
labels: {
|
|
49
|
+
app: `{{ .Values.appName }}`,
|
|
50
|
+
component: 'config',
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
data: {
|
|
54
|
+
'app.name': `{{ .Values.appName }}`,
|
|
55
|
+
'app.port': `{{ .Values.port }}`,
|
|
56
|
+
'app.environment': 'production',
|
|
57
|
+
},
|
|
58
|
+
}, 'configmap');
|
|
59
|
+
this.rutter.addManifest({
|
|
60
|
+
apiVersion: 'v1',
|
|
61
|
+
kind: 'Secret',
|
|
62
|
+
metadata: {
|
|
63
|
+
name: `{{ .Values.appName }}-secret`,
|
|
64
|
+
labels: {
|
|
65
|
+
app: `{{ .Values.appName }}`,
|
|
66
|
+
component: 'secret',
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
stringData: {
|
|
70
|
+
'database.password': 'changeme',
|
|
71
|
+
'api.key': 'your-api-key-here',
|
|
72
|
+
},
|
|
73
|
+
}, 'secret');
|
|
74
|
+
this.rutter.addManifest({
|
|
75
|
+
apiVersion: 'apps/v1',
|
|
76
|
+
kind: 'Deployment',
|
|
77
|
+
metadata: {
|
|
78
|
+
name: `{{ .Values.appName }}`,
|
|
79
|
+
labels: {
|
|
80
|
+
app: `{{ .Values.appName }}`,
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
spec: {
|
|
84
|
+
replicas: `{{ .Values.replicas }}`,
|
|
85
|
+
selector: {
|
|
86
|
+
matchLabels: {
|
|
87
|
+
app: `{{ .Values.appName }}`,
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
template: {
|
|
91
|
+
metadata: {
|
|
92
|
+
labels: {
|
|
93
|
+
app: `{{ .Values.appName }}`,
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
spec: {
|
|
97
|
+
containers: [
|
|
98
|
+
{
|
|
99
|
+
name: 'app',
|
|
100
|
+
image: `{{ .Values.image }}`,
|
|
101
|
+
ports: [
|
|
102
|
+
{
|
|
103
|
+
containerPort: `{{ .Values.port }}`,
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
},
|
|
107
|
+
],
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
}, 'deployment');
|
|
112
|
+
this.rutter.addManifest({
|
|
113
|
+
apiVersion: 'v1',
|
|
114
|
+
kind: 'Service',
|
|
115
|
+
metadata: {
|
|
116
|
+
name: `{{ .Values.appName }}`,
|
|
117
|
+
labels: {
|
|
118
|
+
app: `{{ .Values.appName }}`,
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
spec: {
|
|
122
|
+
type: `{{ .Values.serviceType }}`,
|
|
123
|
+
ports: [
|
|
124
|
+
{
|
|
125
|
+
port: `{{ .Values.port }}`,
|
|
126
|
+
targetPort: `{{ .Values.port }}`,
|
|
127
|
+
},
|
|
128
|
+
],
|
|
129
|
+
selector: {
|
|
130
|
+
app: `{{ .Values.appName }}`,
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
}, 'service');
|
|
134
|
+
this.rutter.addTemplateManifest(`{{- if .Values.enableIngress }}
|
|
135
|
+
apiVersion: networking.k8s.io/v1
|
|
136
|
+
kind: Ingress
|
|
137
|
+
metadata:
|
|
138
|
+
name: {{ include "chart.fullname" . }}
|
|
139
|
+
labels:
|
|
140
|
+
{{- include "chart.labels" . | nindent 4 }}
|
|
141
|
+
{{- with .Values.ingress.annotations }}
|
|
142
|
+
annotations:
|
|
143
|
+
{{- toYaml . | nindent 4 }}
|
|
144
|
+
{{- end }}
|
|
145
|
+
spec:
|
|
146
|
+
{{- if and .Values.ingress.className (not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class")) }}
|
|
147
|
+
ingressClassName: {{ .Values.ingress.className }}
|
|
148
|
+
{{- end }}
|
|
149
|
+
{{- if .Values.ingress.tls }}
|
|
150
|
+
tls:
|
|
151
|
+
{{- range .Values.ingress.tls }}
|
|
152
|
+
- hosts:
|
|
153
|
+
{{- range .hosts }}
|
|
154
|
+
- {{ . | quote }}
|
|
155
|
+
{{- end }}
|
|
156
|
+
secretName: {{ .secretName }}
|
|
157
|
+
{{- end }}
|
|
158
|
+
{{- end }}
|
|
159
|
+
rules:
|
|
160
|
+
{{- range .Values.ingress.hosts }}
|
|
161
|
+
- host: {{ .host | quote }}
|
|
162
|
+
http:
|
|
163
|
+
paths:
|
|
164
|
+
{{- range .paths }}
|
|
165
|
+
- path: {{ .path }}
|
|
166
|
+
{{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }}
|
|
167
|
+
pathType: {{ .pathType }}
|
|
168
|
+
{{- end }}
|
|
169
|
+
backend:
|
|
170
|
+
{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
|
|
171
|
+
service:
|
|
172
|
+
name: {{ include "chart.fullname" $ }}
|
|
173
|
+
port:
|
|
174
|
+
number: {{ $.Values.port | int }}
|
|
175
|
+
{{- else }}
|
|
176
|
+
serviceName: {{ include "chart.fullname" $ }}
|
|
177
|
+
servicePort: {{ $.Values.port | int }}
|
|
178
|
+
{{- end }}
|
|
179
|
+
{{- end }}
|
|
180
|
+
{{- end }}
|
|
181
|
+
{{- end }}`, 'ingress');
|
|
182
|
+
}
|
|
183
|
+
get rutterInstance() {
|
|
184
|
+
return this.rutter;
|
|
185
|
+
}
|
|
186
|
+
writeHelmChart(outDir) {
|
|
187
|
+
this.rutter.write(outDir);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
export function generateSubchart(props = {}, outDir = 'dist') {
|
|
191
|
+
const app = new App();
|
|
192
|
+
const subchart = new Subchart(app, 'subchart', props);
|
|
193
|
+
subchart.writeHelmChart(outDir);
|
|
194
|
+
}
|
|
195
|
+
export function generateSubchartTemplate(name) {
|
|
196
|
+
return `import { App } from 'cdk8s';
|
|
197
|
+
import { Subchart } from 'timonel';
|
|
198
|
+
|
|
199
|
+
export default function createChart() {
|
|
200
|
+
const app = new App({
|
|
201
|
+
outdir: 'dist'
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
return new Subchart(app, '${name}', {
|
|
205
|
+
appName: '${name}',
|
|
206
|
+
image: 'nginx:latest',
|
|
207
|
+
port: 80,
|
|
208
|
+
replicas: 1,
|
|
209
|
+
serviceType: 'ClusterIP',
|
|
210
|
+
enableIngress: false,
|
|
211
|
+
ingressHost: 'example.com'
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Auto-execute when run directly
|
|
216
|
+
if (import.meta.url === new URL(import.meta.url).href) {
|
|
217
|
+
const chart = createChart();
|
|
218
|
+
chart.node.root.synth();
|
|
219
|
+
}
|
|
220
|
+
`;
|
|
221
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { App } from 'cdk8s';
|
|
2
|
+
import { Chart } from 'cdk8s';
|
|
3
|
+
import type { ChartProps } from '../types.js';
|
|
4
|
+
export declare function generateUmbrellaChart(name: string): string;
|
|
5
|
+
export declare class UmbrellaChartTemplate extends Chart {
|
|
6
|
+
private readonly config;
|
|
7
|
+
private _umbrellaRutter?;
|
|
8
|
+
constructor(scope: App, id: string, config: ChartProps);
|
|
9
|
+
private configure;
|
|
10
|
+
private _addService;
|
|
11
|
+
private _addSubchart;
|
|
12
|
+
writeHelmChart(outputDir: string): void;
|
|
13
|
+
}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { writeFileSync, mkdirSync, existsSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import { Chart, ApiObject } from 'cdk8s';
|
|
4
|
+
import YAML from 'yaml';
|
|
5
|
+
export function generateUmbrellaChart(name) {
|
|
6
|
+
return `import { App } from 'cdk8s';
|
|
7
|
+
import { UmbrellaChart } from 'timonel';
|
|
8
|
+
|
|
9
|
+
export function synth(outDir: string) {
|
|
10
|
+
const app = new App({
|
|
11
|
+
outdir: outDir,
|
|
12
|
+
outputFileExtension: '.yaml',
|
|
13
|
+
yamlOutputType: 'FILE_PER_RESOURCE'
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const chart = new UmbrellaChart(app, '${name}', {
|
|
17
|
+
name: '${name}',
|
|
18
|
+
version: '0.1.0',
|
|
19
|
+
description: '${name} umbrella chart',
|
|
20
|
+
services: [],
|
|
21
|
+
subcharts: []
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// Generate Helm chart files
|
|
25
|
+
chart.writeHelmChart(outDir);
|
|
26
|
+
|
|
27
|
+
// Also generate CDK8s YAML files
|
|
28
|
+
app.synth();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Auto-execute when run directly
|
|
32
|
+
if (import.meta.url === new URL(import.meta.url).href) {
|
|
33
|
+
synth(process.argv[2] || 'dist');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export default synth;`;
|
|
37
|
+
}
|
|
38
|
+
export class UmbrellaChartTemplate extends Chart {
|
|
39
|
+
constructor(scope, id, config) {
|
|
40
|
+
super(scope, id);
|
|
41
|
+
this.config = config;
|
|
42
|
+
this.configure();
|
|
43
|
+
}
|
|
44
|
+
configure() {
|
|
45
|
+
new ApiObject(this, 'umbrella-info', {
|
|
46
|
+
apiVersion: 'v1',
|
|
47
|
+
kind: 'ConfigMap',
|
|
48
|
+
metadata: {
|
|
49
|
+
name: `${this.config.name}-info`,
|
|
50
|
+
labels: {
|
|
51
|
+
'app.kubernetes.io/name': this.config.name,
|
|
52
|
+
'app.kubernetes.io/component': 'umbrella-chart',
|
|
53
|
+
'app.kubernetes.io/version': this.config.version,
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
data: {
|
|
57
|
+
'chart.name': this.config.name,
|
|
58
|
+
'chart.version': this.config.version,
|
|
59
|
+
'chart.description': this.config.description || '',
|
|
60
|
+
'subcharts.count': String(this.config.subcharts?.length || 0),
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
this.config.services?.forEach((svc, index) => {
|
|
64
|
+
this._addService(svc, index);
|
|
65
|
+
});
|
|
66
|
+
this.config.subcharts?.forEach((subchart, index) => {
|
|
67
|
+
this._addSubchart(subchart, index);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
_addService(svc, index) {
|
|
71
|
+
new ApiObject(this, `service-${index}`, {
|
|
72
|
+
apiVersion: 'v1',
|
|
73
|
+
kind: 'Service',
|
|
74
|
+
metadata: {
|
|
75
|
+
name: svc.name,
|
|
76
|
+
labels: {
|
|
77
|
+
'app.kubernetes.io/name': this.config.name,
|
|
78
|
+
'app.kubernetes.io/component': 'service',
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
spec: {
|
|
82
|
+
ports: [
|
|
83
|
+
{
|
|
84
|
+
port: svc.port,
|
|
85
|
+
targetPort: svc.targetPort,
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
selector: {
|
|
89
|
+
'app.kubernetes.io/name': svc.name,
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
_addSubchart(_subchart, _index) {
|
|
95
|
+
}
|
|
96
|
+
writeHelmChart(outputDir) {
|
|
97
|
+
if (!existsSync(outputDir)) {
|
|
98
|
+
mkdirSync(outputDir, { recursive: true });
|
|
99
|
+
}
|
|
100
|
+
const chartYaml = {
|
|
101
|
+
apiVersion: 'v2',
|
|
102
|
+
name: this.config.name,
|
|
103
|
+
description: this.config.description || 'A Helm umbrella chart',
|
|
104
|
+
type: 'application',
|
|
105
|
+
version: this.config.version,
|
|
106
|
+
appVersion: this.config.version,
|
|
107
|
+
dependencies: this.config.subcharts?.map((subchart) => ({
|
|
108
|
+
name: subchart.name,
|
|
109
|
+
version: '1.0.0',
|
|
110
|
+
repository: 'file://./charts/' + subchart.name,
|
|
111
|
+
})) || [],
|
|
112
|
+
};
|
|
113
|
+
writeFileSync(join(outputDir, 'Chart.yaml'), YAML.stringify(chartYaml));
|
|
114
|
+
const valuesYaml = {
|
|
115
|
+
global: {
|
|
116
|
+
namespace: this.config.name,
|
|
117
|
+
},
|
|
118
|
+
...Object.fromEntries(this.config.subcharts?.map((subchart) => [
|
|
119
|
+
subchart.name,
|
|
120
|
+
{
|
|
121
|
+
enabled: true,
|
|
122
|
+
},
|
|
123
|
+
]) || []),
|
|
124
|
+
};
|
|
125
|
+
writeFileSync(join(outputDir, 'values.yaml'), YAML.stringify(valuesYaml));
|
|
126
|
+
const chartsDir = join(outputDir, 'charts');
|
|
127
|
+
if (!existsSync(chartsDir)) {
|
|
128
|
+
mkdirSync(chartsDir, { recursive: true });
|
|
129
|
+
}
|
|
130
|
+
this.config.subcharts?.forEach((subchart) => {
|
|
131
|
+
const subchartDir = join(chartsDir, subchart.name);
|
|
132
|
+
if (!existsSync(subchartDir)) {
|
|
133
|
+
mkdirSync(subchartDir, { recursive: true });
|
|
134
|
+
}
|
|
135
|
+
let subchartInstance = null;
|
|
136
|
+
if (typeof subchart.chart === 'function') {
|
|
137
|
+
try {
|
|
138
|
+
subchartInstance = subchart.chart();
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
console.warn(`Failed to create subchart ${subchart.name}:`, error);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
subchartInstance = subchart.chart;
|
|
147
|
+
}
|
|
148
|
+
if (subchartInstance && typeof subchartInstance.writeHelmChart === 'function') {
|
|
149
|
+
subchartInstance.writeHelmChart(subchartDir);
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
const templatesDir = join(outputDir, 'templates');
|
|
153
|
+
if (!existsSync(templatesDir)) {
|
|
154
|
+
mkdirSync(templatesDir, { recursive: true });
|
|
155
|
+
}
|
|
156
|
+
const namespaceYaml = {
|
|
157
|
+
apiVersion: 'v1',
|
|
158
|
+
kind: 'Namespace',
|
|
159
|
+
metadata: {
|
|
160
|
+
name: '{{ .Values.global.namespace | default .Release.Name }}',
|
|
161
|
+
labels: {
|
|
162
|
+
'app.kubernetes.io/name': '{{ include "chart.name" . }}',
|
|
163
|
+
'app.kubernetes.io/instance': '{{ .Release.Name }}',
|
|
164
|
+
'app.kubernetes.io/version': '{{ .Chart.AppVersion }}',
|
|
165
|
+
'app.kubernetes.io/managed-by': '{{ .Release.Service }}',
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
writeFileSync(join(templatesDir, 'namespace.yaml'), YAML.stringify(namespaceYaml));
|
|
170
|
+
const helpersTpl = `{{/*
|
|
171
|
+
Expand the name of the chart.
|
|
172
|
+
*/}}
|
|
173
|
+
{{- define "chart.name" -}}
|
|
174
|
+
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
|
175
|
+
{{- end }}
|
|
176
|
+
|
|
177
|
+
{{/*
|
|
178
|
+
Create a default fully qualified app name.
|
|
179
|
+
*/}}
|
|
180
|
+
{{- define "chart.fullname" -}}
|
|
181
|
+
{{- if .Values.fullnameOverride }}
|
|
182
|
+
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
|
|
183
|
+
{{- else }}
|
|
184
|
+
{{- $name := default .Chart.Name .Values.nameOverride }}
|
|
185
|
+
{{- if contains $name .Release.Name }}
|
|
186
|
+
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
|
|
187
|
+
{{- else }}
|
|
188
|
+
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
|
|
189
|
+
{{- end }}
|
|
190
|
+
{{- end }}
|
|
191
|
+
{{- end }}
|
|
192
|
+
|
|
193
|
+
{{/*
|
|
194
|
+
Create chart name and version as used by the chart label.
|
|
195
|
+
*/}}
|
|
196
|
+
{{- define "chart.chart" -}}
|
|
197
|
+
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
|
198
|
+
{{- end }}
|
|
199
|
+
|
|
200
|
+
{{/*
|
|
201
|
+
Common labels
|
|
202
|
+
*/}}
|
|
203
|
+
{{- define "chart.labels" -}}
|
|
204
|
+
helm.sh/chart: {{ include "chart.chart" . }}
|
|
205
|
+
{{ include "chart.selectorLabels" . }}
|
|
206
|
+
{{- if .Chart.AppVersion }}
|
|
207
|
+
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
|
208
|
+
{{- end }}
|
|
209
|
+
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
|
210
|
+
{{- end }}
|
|
211
|
+
|
|
212
|
+
{{/*
|
|
213
|
+
Selector labels
|
|
214
|
+
*/}}
|
|
215
|
+
{{- define "chart.selectorLabels" -}}
|
|
216
|
+
app.kubernetes.io/name: {{ include "chart.name" . }}
|
|
217
|
+
app.kubernetes.io/instance: {{ .Release.Name }}
|
|
218
|
+
{{- end }}
|
|
219
|
+
`;
|
|
220
|
+
writeFileSync(join(templatesDir, '_helpers.tpl'), helpersTpl);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Chart } from 'cdk8s';
|
|
2
|
+
export interface ChartProps {
|
|
3
|
+
name: string;
|
|
4
|
+
version: string;
|
|
5
|
+
description: string;
|
|
6
|
+
services?: Array<{
|
|
7
|
+
name: string;
|
|
8
|
+
port: number;
|
|
9
|
+
targetPort: number;
|
|
10
|
+
}>;
|
|
11
|
+
subcharts?: Array<{
|
|
12
|
+
name: string;
|
|
13
|
+
chart: Chart | (() => Chart);
|
|
14
|
+
}>;
|
|
15
|
+
}
|
|
16
|
+
export interface SubchartProps {
|
|
17
|
+
name: string;
|
|
18
|
+
version: string;
|
|
19
|
+
path: string;
|
|
20
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|