timonel 2.8.1 → 2.9.0
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 +12 -0
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +274 -634
- package/dist/index.d.ts +4 -6
- package/dist/index.js +4 -7
- package/dist/lib/helm.d.ts +0 -472
- package/dist/lib/helm.js +0 -481
- package/dist/lib/helmChartWriter.d.ts +0 -178
- package/dist/lib/helmChartWriter.js +27 -180
- package/dist/lib/resources/baseResourceProvider.d.ts +0 -46
- package/dist/lib/resources/baseResourceProvider.js +1 -47
- package/dist/lib/resources/cloud/aws/awsResources.d.ts +0 -144
- package/dist/lib/resources/cloud/aws/awsResources.js +1 -163
- package/dist/lib/resources/cloud/aws/karpenterResources.d.ts +0 -132
- package/dist/lib/resources/cloud/aws/karpenterResources.js +0 -75
- package/dist/lib/rutter.d.ts +28 -340
- package/dist/lib/rutter.js +291 -371
- package/dist/lib/security.d.ts +0 -119
- package/dist/lib/security.js +4 -160
- 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 +224 -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/umbrella.d.ts +0 -24
- package/dist/lib/umbrella.js +0 -24
- package/dist/lib/umbrellaRutter.d.ts +0 -71
- package/dist/lib/umbrellaRutter.js +2 -82
- package/dist/lib/utils/helmHelpers.d.ts +18 -41
- package/dist/lib/utils/helmHelpers.js +246 -35
- package/package.json +9 -7
- package/README.md +0 -74
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/lib/helm.d.ts.map +0 -1
- package/dist/lib/helm.js.map +0 -1
- package/dist/lib/helmChartWriter.d.ts.map +0 -1
- package/dist/lib/helmChartWriter.js.map +0 -1
- package/dist/lib/resources/baseResourceProvider.d.ts.map +0 -1
- package/dist/lib/resources/baseResourceProvider.js.map +0 -1
- package/dist/lib/resources/cloud/aws/awsResources.d.ts.map +0 -1
- package/dist/lib/resources/cloud/aws/awsResources.js.map +0 -1
- package/dist/lib/resources/cloud/aws/karpenterResources.d.ts.map +0 -1
- package/dist/lib/resources/cloud/aws/karpenterResources.js.map +0 -1
- package/dist/lib/rutter.d.ts.map +0 -1
- package/dist/lib/rutter.js.map +0 -1
- package/dist/lib/security.d.ts.map +0 -1
- package/dist/lib/security.js.map +0 -1
- package/dist/lib/umbrella.d.ts.map +0 -1
- package/dist/lib/umbrella.js.map +0 -1
- package/dist/lib/umbrellaRutter.d.ts.map +0 -1
- package/dist/lib/umbrellaRutter.js.map +0 -1
- package/dist/lib/utils/helmHelpers.d.ts.map +0 -1
- package/dist/lib/utils/helmHelpers.js.map +0 -1
package/dist/lib/rutter.js
CHANGED
|
@@ -1,304 +1,59 @@
|
|
|
1
1
|
import { ApiObject, App, Chart, Testing } from 'cdk8s';
|
|
2
|
+
import Handlebars from 'handlebars';
|
|
2
3
|
import YAML from 'yaml';
|
|
3
4
|
import { helm, include } from './helm.js';
|
|
4
5
|
import { HelmChartWriter } from './helmChartWriter.js';
|
|
5
6
|
import { AWSResources } from './resources/cloud/aws/awsResources.js';
|
|
6
7
|
import { KarpenterResources } from './resources/cloud/aws/karpenterResources.js';
|
|
7
8
|
import { generateHelpersTemplate } from './utils/helmHelpers.js';
|
|
8
|
-
/**
|
|
9
|
-
* Rutter class with modular architecture
|
|
10
|
-
* Provides a clean API while delegating to specialized resource providers
|
|
11
|
-
* Maintains full backward compatibility with the original Rutter class
|
|
12
|
-
*
|
|
13
|
-
* @since 2.4.0
|
|
14
|
-
*/
|
|
15
9
|
export class Rutter {
|
|
16
10
|
constructor(props) {
|
|
17
11
|
this.assets = [];
|
|
18
|
-
this.props = props;
|
|
19
|
-
this.meta = props.meta;
|
|
20
12
|
this.defaultValues = props.defaultValues ?? {};
|
|
21
13
|
this.envValues = props.envValues ?? {};
|
|
22
|
-
|
|
14
|
+
this.meta = props.meta;
|
|
15
|
+
this.props = props;
|
|
23
16
|
this.app = new App();
|
|
24
17
|
this.chart = new Chart(this.app, props.meta.name, {
|
|
25
18
|
...props.chartProps,
|
|
26
19
|
...(props.namespace ? { namespace: props.namespace } : {}),
|
|
27
20
|
});
|
|
28
|
-
// Initialize resource providers
|
|
29
21
|
this.awsResources = new AWSResources(this.chart);
|
|
30
22
|
this.karpenterResources = new KarpenterResources(this.chart);
|
|
31
23
|
}
|
|
32
|
-
// AWS Resources
|
|
33
|
-
/**
|
|
34
|
-
* Creates an AWS EBS StorageClass
|
|
35
|
-
* @param spec - EBS StorageClass specification
|
|
36
|
-
* @returns Created StorageClass ApiObject
|
|
37
|
-
*
|
|
38
|
-
* @example
|
|
39
|
-
* ```typescript
|
|
40
|
-
* rutter.addAWSEBSStorageClass({
|
|
41
|
-
* name: 'fast-ebs',
|
|
42
|
-
* volumeType: 'gp3',
|
|
43
|
-
* encrypted: true,
|
|
44
|
-
* allowVolumeExpansion: true
|
|
45
|
-
* });
|
|
46
|
-
* ```
|
|
47
|
-
*
|
|
48
|
-
* @since 1.0.0
|
|
49
|
-
*/
|
|
50
24
|
addAWSEBSStorageClass(spec) {
|
|
51
25
|
return this.awsResources.addEBSStorageClass(spec);
|
|
52
26
|
}
|
|
53
|
-
/**
|
|
54
|
-
* Creates an AWS EFS StorageClass
|
|
55
|
-
* @param spec - EFS StorageClass specification
|
|
56
|
-
* @returns Created StorageClass ApiObject
|
|
57
|
-
*
|
|
58
|
-
* @example
|
|
59
|
-
* ```typescript
|
|
60
|
-
* rutter.addAWSEFSStorageClass({
|
|
61
|
-
* name: 'efs-storage',
|
|
62
|
-
* fileSystemId: 'fs-12345678',
|
|
63
|
-
* directoryPerms: '0755'
|
|
64
|
-
* });
|
|
65
|
-
* ```
|
|
66
|
-
*
|
|
67
|
-
* @since 1.0.0
|
|
68
|
-
*/
|
|
69
27
|
addAWSEFSStorageClass(spec) {
|
|
70
28
|
return this.awsResources.addEFSStorageClass(spec);
|
|
71
29
|
}
|
|
72
|
-
/**
|
|
73
|
-
* Creates an AWS IRSA ServiceAccount
|
|
74
|
-
* @param spec - IRSA ServiceAccount specification
|
|
75
|
-
* @returns Created ServiceAccount ApiObject
|
|
76
|
-
*
|
|
77
|
-
* @example
|
|
78
|
-
* ```typescript
|
|
79
|
-
* rutter.addAWSIRSAServiceAccount({
|
|
80
|
-
* name: 'my-service-account',
|
|
81
|
-
* roleArn: 'arn:aws:iam::ACCOUNT_ID:role/MyRole'
|
|
82
|
-
* });
|
|
83
|
-
* ```
|
|
84
|
-
*
|
|
85
|
-
* @since 1.0.0
|
|
86
|
-
*/
|
|
87
30
|
addAWSIRSAServiceAccount(spec) {
|
|
88
31
|
return this.awsResources.addIRSAServiceAccount(spec);
|
|
89
32
|
}
|
|
90
|
-
/**
|
|
91
|
-
* Creates an AWS ALB Ingress
|
|
92
|
-
* @param spec - ALB Ingress specification
|
|
93
|
-
* @returns Created Ingress ApiObject
|
|
94
|
-
*
|
|
95
|
-
* @example
|
|
96
|
-
* ```typescript
|
|
97
|
-
* rutter.addAWSALBIngress({
|
|
98
|
-
* name: 'web-ingress',
|
|
99
|
-
* rules: [{
|
|
100
|
-
* paths: [{
|
|
101
|
-
* path: '/',
|
|
102
|
-
* pathType: 'Prefix',
|
|
103
|
-
* backend: { service: { name: 'web-service', port: { number: 80 } } }
|
|
104
|
-
* }]
|
|
105
|
-
* }],
|
|
106
|
-
* scheme: 'internet-facing'
|
|
107
|
-
* });
|
|
108
|
-
* ```
|
|
109
|
-
*
|
|
110
|
-
* @since 1.0.0
|
|
111
|
-
*/
|
|
112
33
|
addAWSALBIngress(spec) {
|
|
113
34
|
return this.awsResources.addALBIngress(spec);
|
|
114
35
|
}
|
|
115
|
-
// AWS Karpenter Resources
|
|
116
|
-
/**
|
|
117
|
-
* Creates a Karpenter NodePool resource
|
|
118
|
-
* @param spec - NodePool specification
|
|
119
|
-
* @returns Created NodePool ApiObject
|
|
120
|
-
*
|
|
121
|
-
* @example
|
|
122
|
-
* ```typescript
|
|
123
|
-
* rutter.addKarpenterNodePool({
|
|
124
|
-
* name: 'default-nodepool',
|
|
125
|
-
* template: {
|
|
126
|
-
* spec: {
|
|
127
|
-
* nodeClassRef: {
|
|
128
|
-
* apiVersion: 'karpenter.k8s.aws/v1beta1',
|
|
129
|
-
* kind: 'EC2NodeClass',
|
|
130
|
-
* name: 'default'
|
|
131
|
-
* }
|
|
132
|
-
* }
|
|
133
|
-
* }
|
|
134
|
-
* });
|
|
135
|
-
* ```
|
|
136
|
-
*
|
|
137
|
-
* @since 2.7.0
|
|
138
|
-
*/
|
|
139
36
|
addKarpenterNodePool(spec) {
|
|
140
37
|
return this.karpenterResources.addKarpenterNodePool(spec);
|
|
141
38
|
}
|
|
142
|
-
/**
|
|
143
|
-
* Creates a Karpenter NodeClaim resource
|
|
144
|
-
* @param spec - NodeClaim specification
|
|
145
|
-
* @returns Created NodeClaim ApiObject
|
|
146
|
-
*
|
|
147
|
-
* @example
|
|
148
|
-
* ```typescript
|
|
149
|
-
* rutter.addKarpenterNodeClaim({
|
|
150
|
-
* name: 'my-node-claim',
|
|
151
|
-
* nodeClassRef: {
|
|
152
|
-
* apiVersion: 'karpenter.k8s.aws/v1beta1',
|
|
153
|
-
* kind: 'EC2NodeClass',
|
|
154
|
-
* name: 'default'
|
|
155
|
-
* }
|
|
156
|
-
* });
|
|
157
|
-
* ```
|
|
158
|
-
*
|
|
159
|
-
* @since 2.7.0
|
|
160
|
-
*/
|
|
161
39
|
addKarpenterNodeClaim(spec) {
|
|
162
40
|
return this.karpenterResources.addKarpenterNodeClaim(spec);
|
|
163
41
|
}
|
|
164
|
-
/**
|
|
165
|
-
* Creates a Karpenter EC2NodeClass resource
|
|
166
|
-
* @param spec - EC2NodeClass specification
|
|
167
|
-
* @returns Created EC2NodeClass ApiObject
|
|
168
|
-
*
|
|
169
|
-
* @example
|
|
170
|
-
* ```typescript
|
|
171
|
-
* rutter.addKarpenterEC2NodeClass({
|
|
172
|
-
* name: 'default',
|
|
173
|
-
* amiFamily: 'AL2',
|
|
174
|
-
* subnetSelectorTerms: [{ tags: { 'karpenter.sh/discovery': 'my-cluster' } }],
|
|
175
|
-
* securityGroupSelectorTerms: [{ tags: { 'karpenter.sh/discovery': 'my-cluster' } }]
|
|
176
|
-
* });
|
|
177
|
-
* ```
|
|
178
|
-
*
|
|
179
|
-
* @since 2.7.0
|
|
180
|
-
*/
|
|
181
42
|
addKarpenterEC2NodeClass(spec) {
|
|
182
43
|
return this.karpenterResources.addKarpenterEC2NodeClass(spec);
|
|
183
44
|
}
|
|
184
|
-
/**
|
|
185
|
-
* Creates a Karpenter NodePool with optimized disruption settings for cost efficiency
|
|
186
|
-
* @param spec - NodePool specification with disruption optimization
|
|
187
|
-
* @returns Created NodePool ApiObject
|
|
188
|
-
*
|
|
189
|
-
* @example
|
|
190
|
-
* ```typescript
|
|
191
|
-
* rutter.addKarpenterNodePoolWithDisruption({
|
|
192
|
-
* name: 'cost-optimized',
|
|
193
|
-
* nodeClassRef: {
|
|
194
|
-
* apiVersion: 'karpenter.k8s.aws/v1beta1',
|
|
195
|
-
* kind: 'EC2NodeClass',
|
|
196
|
-
* name: 'default'
|
|
197
|
-
* },
|
|
198
|
-
* consolidationPolicy: 'WhenEmptyOrUnderutilized',
|
|
199
|
-
* consolidateAfter: '30s',
|
|
200
|
-
* expireAfter: '24h',
|
|
201
|
-
* disruptionBudgets: [
|
|
202
|
-
* { nodes: '20%' },
|
|
203
|
-
* { nodes: '0', schedule: '0 9 * * 1-5', duration: '8h' }
|
|
204
|
-
* ]
|
|
205
|
-
* });
|
|
206
|
-
* ```
|
|
207
|
-
*
|
|
208
|
-
* @since 2.7.1
|
|
209
|
-
*/
|
|
210
45
|
addKarpenterNodePoolWithDisruption(spec) {
|
|
211
46
|
return this.karpenterResources.addKarpenterNodePoolWithDisruption(spec);
|
|
212
47
|
}
|
|
213
|
-
/**
|
|
214
|
-
* Creates a Karpenter NodePool with scheduling constraints and priorities
|
|
215
|
-
* @param spec - NodePool specification with scheduling optimization
|
|
216
|
-
* @returns Created NodePool ApiObject
|
|
217
|
-
*
|
|
218
|
-
* @example
|
|
219
|
-
* ```typescript
|
|
220
|
-
* rutter.addKarpenterNodePoolWithScheduling({
|
|
221
|
-
* name: 'gpu-workloads',
|
|
222
|
-
* nodeClassRef: {
|
|
223
|
-
* apiVersion: 'karpenter.k8s.aws/v1beta1',
|
|
224
|
-
* kind: 'EC2NodeClass',
|
|
225
|
-
* name: 'gpu-nodeclass'
|
|
226
|
-
* },
|
|
227
|
-
* requirements: [
|
|
228
|
-
* { key: 'node.kubernetes.io/instance-type', operator: 'In', values: ['g4dn.xlarge', 'g4dn.2xlarge'] }
|
|
229
|
-
* ],
|
|
230
|
-
* taints: [
|
|
231
|
-
* { key: 'nvidia.com/gpu', effect: 'NoSchedule' }
|
|
232
|
-
* ],
|
|
233
|
-
* terminationGracePeriod: '60s',
|
|
234
|
-
* weight: 100
|
|
235
|
-
* });
|
|
236
|
-
* ```
|
|
237
|
-
*
|
|
238
|
-
* @since 2.7.1
|
|
239
|
-
*/
|
|
240
48
|
addKarpenterNodePoolWithScheduling(spec) {
|
|
241
49
|
return this.karpenterResources.addKarpenterNodePoolWithScheduling(spec);
|
|
242
50
|
}
|
|
243
|
-
// AWS ECR ServiceAccount
|
|
244
|
-
/**
|
|
245
|
-
* Creates a ServiceAccount with ECR access annotations
|
|
246
|
-
* @param spec - ECR ServiceAccount specification
|
|
247
|
-
* @returns Created ServiceAccount ApiObject
|
|
248
|
-
*
|
|
249
|
-
* @example
|
|
250
|
-
* ```typescript
|
|
251
|
-
* rutter.addAWSECRServiceAccount({
|
|
252
|
-
* name: 'ecr-service-account',
|
|
253
|
-
* roleArn: 'arn:aws:iam::ACCOUNT_ID:role/ECRAccessRole'
|
|
254
|
-
* });
|
|
255
|
-
* ```
|
|
256
|
-
*
|
|
257
|
-
* @since 2.7.0
|
|
258
|
-
*/
|
|
259
51
|
addAWSECRServiceAccount(spec) {
|
|
260
52
|
return this.awsResources.addECRServiceAccount(spec);
|
|
261
53
|
}
|
|
262
|
-
// Utility methods
|
|
263
|
-
/**
|
|
264
|
-
* Adds a Kubernetes manifest to the chart using CDK8S
|
|
265
|
-
*
|
|
266
|
-
* This method allows you to add any Kubernetes manifest (CRDs, custom resources, etc.)
|
|
267
|
-
* either as YAML strings or as objects. The manifest will be processed using CDK8S
|
|
268
|
-
* for better type safety and validation.
|
|
269
|
-
*
|
|
270
|
-
* @param yamlOrObject - Kubernetes manifest as YAML string or object
|
|
271
|
-
* @param id - Unique identifier for the manifest (required for multiple manifests)
|
|
272
|
-
*
|
|
273
|
-
* @example
|
|
274
|
-
* ```typescript
|
|
275
|
-
* // Using YAML string for CRD
|
|
276
|
-
* rutter.addManifest(`
|
|
277
|
-
* apiVersion: apiextensions.k8s.io/v1
|
|
278
|
-
* kind: CustomResourceDefinition
|
|
279
|
-
* metadata:
|
|
280
|
-
* name: example.com
|
|
281
|
-
* spec:
|
|
282
|
-
* group: example.com
|
|
283
|
-
* versions: []
|
|
284
|
-
* `, 'my-crd');
|
|
285
|
-
*
|
|
286
|
-
* // Using object for any Kubernetes resource
|
|
287
|
-
* rutter.addManifest({
|
|
288
|
-
* apiVersion: 'v1',
|
|
289
|
-
* kind: 'ConfigMap',
|
|
290
|
-
* metadata: { name: 'my-config' },
|
|
291
|
-
* data: { key: 'value' }
|
|
292
|
-
* }, 'my-configmap');
|
|
293
|
-
* ```
|
|
294
|
-
*
|
|
295
|
-
* @since 3.0.0
|
|
296
|
-
* @note Consider using cdk8s-plus constructs for better type safety when available
|
|
297
|
-
*/
|
|
298
54
|
addManifest(yamlOrObject, id) {
|
|
299
55
|
let manifestObject;
|
|
300
56
|
if (typeof yamlOrObject === 'string') {
|
|
301
|
-
// Parse YAML string to object
|
|
302
57
|
try {
|
|
303
58
|
manifestObject = YAML.parse(yamlOrObject);
|
|
304
59
|
}
|
|
@@ -307,15 +62,12 @@ export class Rutter {
|
|
|
307
62
|
}
|
|
308
63
|
}
|
|
309
64
|
else if (typeof yamlOrObject === 'object' && yamlOrObject !== null) {
|
|
310
|
-
// Use object directly
|
|
311
65
|
manifestObject = yamlOrObject;
|
|
312
66
|
}
|
|
313
67
|
else {
|
|
314
68
|
throw new Error('addManifest() requires either a YAML string or an object');
|
|
315
69
|
}
|
|
316
|
-
// Validate basic Kubernetes manifest structure
|
|
317
70
|
this.validateManifestStructure(manifestObject);
|
|
318
|
-
// Create CDK8S ApiObject from the manifest
|
|
319
71
|
return new ApiObject(this.chart, id, {
|
|
320
72
|
apiVersion: manifestObject['apiVersion'],
|
|
321
73
|
kind: manifestObject['kind'],
|
|
@@ -323,55 +75,57 @@ export class Rutter {
|
|
|
323
75
|
spec: manifestObject['spec'],
|
|
324
76
|
});
|
|
325
77
|
}
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
* ```typescript
|
|
340
|
-
* // Add a namespace that's only created if .Values.createNamespace is true
|
|
341
|
-
* rutter.addConditionalManifest(
|
|
342
|
-
* {
|
|
343
|
-
* apiVersion: 'v1',
|
|
344
|
-
* kind: 'Namespace',
|
|
345
|
-
* metadata: {
|
|
346
|
-
* name: valuesRef('namespace'),
|
|
347
|
-
* labels: {
|
|
348
|
-
* environment: conditionalRef('environment', 'environment')
|
|
349
|
-
* }
|
|
350
|
-
* }
|
|
351
|
-
* },
|
|
352
|
-
* 'createNamespace',
|
|
353
|
-
* 'namespace'
|
|
354
|
-
* );
|
|
355
|
-
* ```
|
|
356
|
-
*
|
|
357
|
-
* @since 2.7.4
|
|
358
|
-
*/
|
|
78
|
+
addTemplateManifest(yamlTemplate, id) {
|
|
79
|
+
const templateAsset = {
|
|
80
|
+
id,
|
|
81
|
+
yaml: yamlTemplate,
|
|
82
|
+
target: 'templates',
|
|
83
|
+
};
|
|
84
|
+
this.assets.push(templateAsset);
|
|
85
|
+
return new ApiObject(this.chart, id, {
|
|
86
|
+
apiVersion: 'v1',
|
|
87
|
+
kind: 'ConfigMap',
|
|
88
|
+
metadata: { name: id },
|
|
89
|
+
});
|
|
90
|
+
}
|
|
359
91
|
addConditionalManifest(manifestObject, condition, id) {
|
|
360
|
-
// Validate condition path
|
|
361
92
|
if (!condition || typeof condition !== 'string') {
|
|
362
93
|
throw new Error('Condition must be a non-empty string');
|
|
363
94
|
}
|
|
364
|
-
// Validate basic Kubernetes manifest structure
|
|
365
95
|
this.validateManifestStructure(manifestObject);
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
96
|
+
let helmCondition;
|
|
97
|
+
if (condition.startsWith('{{') && condition.endsWith('}}')) {
|
|
98
|
+
helmCondition = condition.slice(2, -2).trim();
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
helmCondition = `.Values.${condition}`;
|
|
102
|
+
}
|
|
103
|
+
try {
|
|
104
|
+
const yamlContent = YAML.stringify(manifestObject, {
|
|
105
|
+
lineWidth: 0,
|
|
106
|
+
doubleQuotedAsJSON: false,
|
|
107
|
+
simpleKeys: true,
|
|
108
|
+
});
|
|
109
|
+
const conditionalTemplate = `\\{{- if ${helmCondition} }}
|
|
110
|
+
{{{manifestYaml}}}
|
|
111
|
+
\\{{- end }}`;
|
|
112
|
+
const template = Handlebars.compile(conditionalTemplate, {
|
|
113
|
+
noEscape: true,
|
|
114
|
+
});
|
|
115
|
+
const conditionalYaml = template({
|
|
116
|
+
manifestYaml: yamlContent.trim(),
|
|
117
|
+
});
|
|
118
|
+
const conditionalAsset = {
|
|
119
|
+
id,
|
|
120
|
+
yaml: conditionalYaml,
|
|
121
|
+
target: 'templates',
|
|
122
|
+
};
|
|
123
|
+
this.assets.push(conditionalAsset);
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
throw new Error(`Failed to compile Handlebars template for manifest '${id}': ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
127
|
+
}
|
|
128
|
+
return new ApiObject(this.chart, `${id}-placeholder`, {
|
|
375
129
|
apiVersion: manifestObject['apiVersion'],
|
|
376
130
|
kind: manifestObject['kind'],
|
|
377
131
|
metadata: {
|
|
@@ -379,17 +133,12 @@ export class Rutter {
|
|
|
379
133
|
annotations: {
|
|
380
134
|
...(manifestObject['metadata']?.['annotations'] || {}),
|
|
381
135
|
'timonel.sh/conditional': condition,
|
|
136
|
+
'timonel.sh/placeholder': 'true',
|
|
382
137
|
},
|
|
383
138
|
},
|
|
384
139
|
spec: manifestObject['spec'],
|
|
385
140
|
});
|
|
386
141
|
}
|
|
387
|
-
/**
|
|
388
|
-
* Validates the structure of a Kubernetes manifest object
|
|
389
|
-
* @param manifest - The manifest object to validate
|
|
390
|
-
* @private
|
|
391
|
-
* @since 3.0.0
|
|
392
|
-
*/
|
|
393
142
|
validateManifestStructure(manifest) {
|
|
394
143
|
if (!manifest['apiVersion'] || typeof manifest['apiVersion'] !== 'string') {
|
|
395
144
|
throw new Error('Kubernetes manifest must have a valid apiVersion');
|
|
@@ -406,7 +155,6 @@ export class Rutter {
|
|
|
406
155
|
if (!metadata['name'] || typeof metadata['name'] !== 'string') {
|
|
407
156
|
throw new Error('Kubernetes manifest metadata must have a valid name');
|
|
408
157
|
}
|
|
409
|
-
// Additional validation for specific resource types
|
|
410
158
|
const kind = manifest['kind'];
|
|
411
159
|
if (kind === 'CustomResourceDefinition') {
|
|
412
160
|
if (!manifest['spec'] || typeof manifest['spec'] !== 'object' || manifest['spec'] === null) {
|
|
@@ -421,59 +169,35 @@ export class Rutter {
|
|
|
421
169
|
}
|
|
422
170
|
}
|
|
423
171
|
}
|
|
424
|
-
/**
|
|
425
|
-
* Gets chart metadata
|
|
426
|
-
* @returns Chart metadata
|
|
427
|
-
*
|
|
428
|
-
* @since 1.0.0
|
|
429
|
-
*/
|
|
430
172
|
getMeta() {
|
|
431
173
|
return { ...this.meta };
|
|
432
174
|
}
|
|
433
|
-
/**
|
|
434
|
-
* Gets default values
|
|
435
|
-
* @returns Default values object
|
|
436
|
-
*
|
|
437
|
-
* @since 1.0.0
|
|
438
|
-
*/
|
|
439
175
|
getDefaultValues() {
|
|
440
176
|
return { ...this.defaultValues };
|
|
441
177
|
}
|
|
442
|
-
/**
|
|
443
|
-
* Gets environment-specific values
|
|
444
|
-
* @returns Environment values object
|
|
445
|
-
*
|
|
446
|
-
* @since 1.0.0
|
|
447
|
-
*/
|
|
448
178
|
getEnvValues() {
|
|
449
179
|
return { ...this.envValues };
|
|
450
180
|
}
|
|
451
|
-
/**
|
|
452
|
-
* Gets all assets (CRDs, etc.)
|
|
453
|
-
* @returns Array of assets
|
|
454
|
-
*
|
|
455
|
-
* @since 1.0.0
|
|
456
|
-
*/
|
|
457
181
|
getAssets() {
|
|
458
182
|
return [...this.assets];
|
|
459
183
|
}
|
|
460
|
-
/**
|
|
461
|
-
* Converts the chart to SynthAsset array for HelmChartWriter
|
|
462
|
-
* @returns Array of synthesized assets
|
|
463
|
-
*
|
|
464
|
-
* @since 2.4.0
|
|
465
|
-
*/
|
|
466
184
|
toSynthArray() {
|
|
467
|
-
|
|
185
|
+
console.log('🔍 toSynthArray called');
|
|
468
186
|
const apiObjectIds = [];
|
|
469
187
|
for (const child of this.chart.node.children) {
|
|
470
|
-
if (child instanceof ApiObject) {
|
|
188
|
+
if (child instanceof ApiObject && !child.node.id.endsWith('-placeholder')) {
|
|
471
189
|
apiObjectIds.push(child.node.id);
|
|
472
190
|
}
|
|
473
191
|
}
|
|
474
|
-
|
|
475
|
-
const manifestObjs =
|
|
476
|
-
|
|
192
|
+
const allManifestObjs = Testing.synth(this.chart);
|
|
193
|
+
const manifestObjs = allManifestObjs.filter((obj) => {
|
|
194
|
+
if (obj && typeof obj === 'object') {
|
|
195
|
+
const o = obj;
|
|
196
|
+
const annotations = o.metadata?.annotations || {};
|
|
197
|
+
return annotations['timonel.sh/placeholder'] !== 'true';
|
|
198
|
+
}
|
|
199
|
+
return true;
|
|
200
|
+
});
|
|
477
201
|
const enriched = manifestObjs.map((obj) => {
|
|
478
202
|
if (obj && typeof obj === 'object') {
|
|
479
203
|
const o = obj;
|
|
@@ -488,10 +212,8 @@ export class Rutter {
|
|
|
488
212
|
'app.kubernetes.io/managed-by': '{{ .Release.Service }}',
|
|
489
213
|
'app.kubernetes.io/part-of': helm.chartName,
|
|
490
214
|
};
|
|
491
|
-
// Apply defaults only if not already set
|
|
492
215
|
for (const [key, value] of Object.entries(defaults)) {
|
|
493
216
|
if (!(key in labels)) {
|
|
494
|
-
// eslint-disable-next-line security/detect-object-injection -- Safe: controlled label assignment
|
|
495
217
|
labels[key] = value;
|
|
496
218
|
}
|
|
497
219
|
}
|
|
@@ -499,8 +221,8 @@ export class Rutter {
|
|
|
499
221
|
return obj;
|
|
500
222
|
});
|
|
501
223
|
const synthAssets = [];
|
|
224
|
+
console.log('🔍 singleManifestFile:', this.props.singleManifestFile);
|
|
502
225
|
if (this.props.singleManifestFile) {
|
|
503
|
-
// Combine all resources into single manifest
|
|
504
226
|
const combinedYaml = enriched
|
|
505
227
|
.map((obj) => this.processHelmTemplates(YAML.stringify(obj).trim()))
|
|
506
228
|
.filter(Boolean)
|
|
@@ -509,47 +231,245 @@ export class Rutter {
|
|
|
509
231
|
synthAssets.push({ id: manifestId, yaml: combinedYaml });
|
|
510
232
|
}
|
|
511
233
|
else {
|
|
512
|
-
// Create separate files for each resource (default behavior)
|
|
513
234
|
enriched.forEach((obj, index) => {
|
|
235
|
+
const apiObjectId = apiObjectIds[index];
|
|
236
|
+
const manifestId = apiObjectId || `manifest-${index + 1}`;
|
|
237
|
+
console.log(`🔍 Processing asset ${manifestId} (index ${index})`);
|
|
514
238
|
const yaml = this.processHelmTemplates(YAML.stringify(obj).trim());
|
|
515
239
|
if (yaml) {
|
|
516
|
-
// Use descriptive name from ApiObject ID if available, otherwise fallback to generic name
|
|
517
|
-
// eslint-disable-next-line security/detect-object-injection
|
|
518
|
-
const apiObjectId = apiObjectIds[index];
|
|
519
|
-
const manifestId = apiObjectId || `manifest-${index + 1}`;
|
|
520
240
|
synthAssets.push({ id: manifestId, yaml });
|
|
521
241
|
}
|
|
522
242
|
});
|
|
523
243
|
}
|
|
524
|
-
// Add any additional assets (CRDs, etc.)
|
|
525
244
|
this.assets.forEach((asset) => {
|
|
526
245
|
synthAssets.push({ id: asset.id, yaml: asset.yaml });
|
|
527
246
|
});
|
|
528
247
|
return synthAssets;
|
|
529
248
|
}
|
|
530
|
-
/**
|
|
531
|
-
* Process YAML content to remove quotes from Helm templates
|
|
532
|
-
* This fixes the issue where YAML.stringify adds quotes around Helm template expressions
|
|
533
|
-
* Removes quotes from all Helm template expressions
|
|
534
|
-
*/
|
|
535
249
|
processHelmTemplates(yaml) {
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
.
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
250
|
+
console.log('🔍 processHelmTemplates called with YAML length:', yaml.length);
|
|
251
|
+
if (yaml.includes('{{ .Values.port }}')) {
|
|
252
|
+
console.log('🎯 Found YAML with port template:');
|
|
253
|
+
const portIndex = yaml.indexOf('{{ .Values.port }}');
|
|
254
|
+
console.log(yaml.substring(Math.max(0, portIndex - 50), portIndex + 100));
|
|
255
|
+
}
|
|
256
|
+
let processed = this.fixCharacterMappingIssues(yaml);
|
|
257
|
+
processed = this.applyHelmTemplateReplacements(processed);
|
|
258
|
+
console.log('✅ processHelmTemplates completed');
|
|
259
|
+
return processed;
|
|
260
|
+
}
|
|
261
|
+
fixCharacterMappingIssues(yaml) {
|
|
262
|
+
const lines = yaml.split('\n');
|
|
263
|
+
const fixedLines = [];
|
|
264
|
+
let i = 0;
|
|
265
|
+
while (i < lines.length) {
|
|
266
|
+
const line = lines[i];
|
|
267
|
+
if (!line) {
|
|
268
|
+
i++;
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
const charKeyMatch = line.match(/^(\s*)"(\d+)":\s*(.+)$/);
|
|
272
|
+
if (charKeyMatch && charKeyMatch[2] && parseInt(charKeyMatch[2]) === 0) {
|
|
273
|
+
const indent = charKeyMatch[1] || '';
|
|
274
|
+
const result = this.processCharacterMapping(lines, i, indent);
|
|
275
|
+
if (result.reconstructed) {
|
|
276
|
+
fixedLines.push(result.reconstructed);
|
|
277
|
+
i = result.nextIndex;
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
if (line) {
|
|
282
|
+
fixedLines.push(line);
|
|
283
|
+
}
|
|
284
|
+
i++;
|
|
285
|
+
}
|
|
286
|
+
return fixedLines.join('\n');
|
|
287
|
+
}
|
|
288
|
+
processCharacterMapping(lines, startIndex, indent) {
|
|
289
|
+
const charMappings = [];
|
|
290
|
+
let j = startIndex;
|
|
291
|
+
while (j < lines.length) {
|
|
292
|
+
const currentLine = lines[j];
|
|
293
|
+
if (!currentLine) {
|
|
294
|
+
break;
|
|
295
|
+
}
|
|
296
|
+
const currentMatch = currentLine.match(/^(\s*)"(\d+)":\s*(.+)$/);
|
|
297
|
+
if (currentMatch && currentMatch[1] === indent && currentMatch[2] && currentMatch[3]) {
|
|
298
|
+
const index = parseInt(currentMatch[2]);
|
|
299
|
+
let char = currentMatch[3];
|
|
300
|
+
if (char && char.startsWith('"') && char.endsWith('"')) {
|
|
301
|
+
char = char.slice(1, -1);
|
|
302
|
+
}
|
|
303
|
+
charMappings.push({ index, char });
|
|
304
|
+
j++;
|
|
305
|
+
}
|
|
306
|
+
else {
|
|
307
|
+
break;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
if (charMappings.length > 3) {
|
|
311
|
+
charMappings.sort((a, b) => a.index - b.index);
|
|
312
|
+
const reconstructed = charMappings.map((m) => m.char).join('');
|
|
313
|
+
if (reconstructed.includes('{{') && reconstructed.includes('}}')) {
|
|
314
|
+
return { reconstructed: `${indent}${reconstructed}`, nextIndex: j };
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
return { nextIndex: j };
|
|
318
|
+
}
|
|
319
|
+
applyHelmTemplateReplacements(processed) {
|
|
320
|
+
processed = this.fixIncludeStatements(processed);
|
|
321
|
+
processed = this.fixFunctionCalls(processed);
|
|
322
|
+
processed = this.fixChartReferences(processed);
|
|
323
|
+
processed = this.removeHelmExpressionQuotes(processed);
|
|
324
|
+
if (processed.includes('number:')) {
|
|
325
|
+
console.log('DEBUG: Before fixConditionalBlocks:', processed.split('\n').filter((line) => line.includes('number:')));
|
|
326
|
+
}
|
|
327
|
+
processed = this.fixConditionalBlocks(processed);
|
|
328
|
+
if (processed.includes('number:')) {
|
|
329
|
+
console.log('DEBUG: After fixConditionalBlocks:', processed.split('\n').filter((line) => line.includes('number:')));
|
|
330
|
+
}
|
|
331
|
+
if (processed.includes('number:')) {
|
|
332
|
+
console.log('DEBUG: Before fixPipeExpressions:', processed.split('\n').filter((line) => line.includes('number:')));
|
|
333
|
+
}
|
|
334
|
+
processed = this.fixPipeExpressions(processed);
|
|
335
|
+
if (processed.includes('number:')) {
|
|
336
|
+
console.log('DEBUG: After fixPipeExpressions:', processed.split('\n').filter((line) => line.includes('number:')));
|
|
337
|
+
}
|
|
338
|
+
if (processed.includes('number:')) {
|
|
339
|
+
console.log('DEBUG: Before fixNestedQuotes:', processed.split('\n').filter((line) => line.includes('number:')));
|
|
340
|
+
}
|
|
341
|
+
processed = this.fixNestedQuotes(processed);
|
|
342
|
+
if (processed.includes('number:')) {
|
|
343
|
+
console.log('DEBUG: After fixNestedQuotes:', processed.split('\n').filter((line) => line.includes('number:')));
|
|
344
|
+
}
|
|
345
|
+
if (processed.includes('number:')) {
|
|
346
|
+
console.log('DEBUG: Before cleanupArtifacts:', processed.split('\n').filter((line) => line.includes('number:')));
|
|
347
|
+
}
|
|
348
|
+
processed = this.cleanupArtifacts(processed);
|
|
349
|
+
if (processed.includes('number:')) {
|
|
350
|
+
console.log('DEBUG: After cleanupArtifacts:', processed.split('\n').filter((line) => line.includes('number:')));
|
|
351
|
+
}
|
|
352
|
+
return processed;
|
|
353
|
+
}
|
|
354
|
+
fixIncludeStatements(processed) {
|
|
355
|
+
processed = processed.replace(/\{\{ include \\"([^"]+)\\" \. \| nindent (\d+) \}\}/g, '{{ include "$1" . | nindent $2 }}');
|
|
356
|
+
processed = processed.replace(/\{\{ include \\"([^"]+)\\" \. \}\}/g, '{{ include "$1" . }}');
|
|
357
|
+
return processed;
|
|
358
|
+
}
|
|
359
|
+
fixFunctionCalls(processed) {
|
|
360
|
+
return processed.replace(/\{\{ (\w+) \\"([^"]*)\\" ([^}]*) \}\}/g, '{{ $1 "$2" $3 }}');
|
|
361
|
+
}
|
|
362
|
+
fixChartReferences(processed) {
|
|
363
|
+
return processed.replace(/\{\{ \.Chart\.(\w+) \| replace \\"([^"]*)\\" \\"([^"]*)\\" ([^}]*) \}\}/g, '{{ .Chart.$1 | replace "$2" "$3" $4 }}');
|
|
364
|
+
}
|
|
365
|
+
removeHelmExpressionQuotes(processed) {
|
|
366
|
+
const HELM_EXPRESSION_REPLACEMENT = '$1$2: {{$3}}';
|
|
367
|
+
console.log('🔧 removeHelmExpressionQuotes called');
|
|
368
|
+
if (processed.includes('number:')) {
|
|
369
|
+
console.log('DEBUG: removeHelmExpressionQuotes input contains number:', processed.split('\n').filter((line) => line.includes('number:')));
|
|
370
|
+
}
|
|
371
|
+
processed = processed.replace(/^(\s*)([^:\s]+):\s*"\{\{([^}]*\|\s*(?:int|float|bool|number)[^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
372
|
+
processed = processed.replace(/^(\s*)(port):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
373
|
+
processed = processed.replace(/^(\s*)(port\.number):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
374
|
+
processed = processed.replace(/^(\s*)(service\.port):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
375
|
+
processed = processed.replace(/^(\s*)(backend\.service\.port\.number):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
376
|
+
processed = processed.replace(/^(\s*)(spec\.port):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
377
|
+
processed = processed.replace(/^(\s*)([^:\s]*\.number):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
378
|
+
const numberMatches = processed.match(/^(\s*)(number):\s*"\{\{([^}]*)\}\}"/gm);
|
|
379
|
+
if (numberMatches) {
|
|
380
|
+
console.log('DEBUG: Found number pattern matches:', numberMatches);
|
|
381
|
+
}
|
|
382
|
+
else {
|
|
383
|
+
const anyNumberFields = processed.match(/number:\s*"[^"]*"/gm);
|
|
384
|
+
if (anyNumberFields) {
|
|
385
|
+
console.log('DEBUG: Found number fields but regex did not match:', anyNumberFields);
|
|
386
|
+
const lines = processed.split('\n');
|
|
387
|
+
const numberLines = lines.filter((line) => line.includes('number:'));
|
|
388
|
+
console.log('DEBUG: Number field lines:', numberLines);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
processed = processed.replace(/^(\s*)(number):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
392
|
+
if (processed.includes('number:')) {
|
|
393
|
+
console.log('DEBUG: removeHelmExpressionQuotes after number replacement:', processed.split('\n').filter((line) => line.includes('number:')));
|
|
394
|
+
}
|
|
395
|
+
processed = processed.replace(/^(\s*)(replicas):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
396
|
+
processed = processed.replace(/^(\s*)(targetPort):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
397
|
+
processed = processed.replace(/^(\s*)(nodePort):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
398
|
+
processed = processed.replace(/^(\s*)(containerPort):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
399
|
+
processed = processed.replace(/^(\s*)(hostPort):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
400
|
+
processed = processed.replace(/^(\s*)(weight):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
401
|
+
processed = processed.replace(/^(\s*)(priority):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
402
|
+
processed = processed.replace(/^(\s*)(timeoutSeconds):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
403
|
+
processed = processed.replace(/^(\s*)(periodSeconds):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
404
|
+
processed = processed.replace(/^(\s*)(successThreshold):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
405
|
+
processed = processed.replace(/^(\s*)(failureThreshold):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
406
|
+
processed = processed.replace(/^(\s*)(initialDelaySeconds):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
407
|
+
processed = processed.replace(/^(\s*)(terminationGracePeriodSeconds):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
408
|
+
processed = processed.replace(/^(\s*)(activeDeadlineSeconds):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
409
|
+
processed = processed.replace(/^(\s*)(backoffLimit):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
410
|
+
processed = processed.replace(/^(\s*)(parallelism):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
411
|
+
processed = processed.replace(/^(\s*)(completions):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
412
|
+
processed = processed.replace(/^(\s*)(revisionHistoryLimit):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
413
|
+
processed = processed.replace(/^(\s*)(progressDeadlineSeconds):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
414
|
+
processed = processed.replace(/^(\s*)(minReadySeconds):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
415
|
+
processed = processed.replace(/^(\s*)(maxUnavailable):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
416
|
+
processed = processed.replace(/^(\s*)(maxSurge):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
417
|
+
processed = processed.replace(/^(\s*)(cpu):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
418
|
+
processed = processed.replace(/^(\s*)(memory):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
419
|
+
processed = processed.replace(/^(\s*)(enabled):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
420
|
+
processed = processed.replace(/^(\s*)(create):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
421
|
+
processed = processed.replace(/^(\s*)(allow):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
422
|
+
processed = processed.replace(/^(\s*)(disable):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
423
|
+
processed = processed.replace(/^(\s*)(force):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
424
|
+
processed = processed.replace(/^(\s*)(required):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
425
|
+
processed = processed.replace(/^(\s*)(optional):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
426
|
+
processed = processed.replace(/^(\s*)(readOnly):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
427
|
+
processed = processed.replace(/^(\s*)(runAsNonRoot):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
428
|
+
processed = processed.replace(/^(\s*)(privileged):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
429
|
+
processed = processed.replace(/^(\s*)(allowPrivilegeEscalation):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
430
|
+
processed = processed.replace(/^(\s*)(readOnlyRootFilesystem):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
431
|
+
processed = processed.replace(/^(\s*)([^:\s]+):\s*"\{\{([^}]*true[^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
432
|
+
processed = processed.replace(/^(\s*)([^:\s]+):\s*"\{\{([^}]*false[^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
433
|
+
processed = processed.replace(/^(\s*)([^:\s]+):\s*"\{\{([^}]*\d+[^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
434
|
+
processed = processed.replace(/^(\s*)([^:\s]+):\s*"\{\{([^}]*\beq\b[^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
435
|
+
processed = processed.replace(/^(\s*)([^:\s]+):\s*"\{\{([^}]*\bne\b[^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
436
|
+
processed = processed.replace(/^(\s*)([^:\s]+):\s*"\{\{([^}]*\blt\b[^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
437
|
+
processed = processed.replace(/^(\s*)([^:\s]+):\s*"\{\{([^}]*\ble\b[^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
438
|
+
processed = processed.replace(/^(\s*)([^:\s]+):\s*"\{\{([^}]*\bgt\b[^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
439
|
+
processed = processed.replace(/^(\s*)([^:\s]+):\s*"\{\{([^}]*\bge\b[^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
440
|
+
processed = processed.replace(/^(\s*)([^:\s]+):\s*"\{\{([^}]*\band\b[^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
441
|
+
processed = processed.replace(/^(\s*)([^:\s]+):\s*"\{\{([^}]*\bor\b[^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
442
|
+
processed = processed.replace(/^(\s*)([^:\s]+):\s*"\{\{([^}]*\bnot\b[^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
443
|
+
processed = processed.replace(/^(\s*)([^:\s]+):\s*"\{\{([^}]*[+][^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
444
|
+
processed = processed.replace(/^(\s*)([^:\s]+):\s*"\{\{([^}]*[-][^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
445
|
+
processed = processed.replace(/^(\s*)([^:\s]+):\s*"\{\{([^}]*[*][^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
446
|
+
processed = processed.replace(/:\s*"([^"]*\{\{[^}]+\}\}[^"]*)"/g, ': $1');
|
|
447
|
+
processed = processed.replace(/^(\s*)([^:\s]+):\s*"(true|false)"$/gm, '$1$2: $3');
|
|
448
|
+
processed = processed.replace(/^(\s*)([^:\s]+):\s*"(-?\d+)"$/gm, '$1$2: $3');
|
|
449
|
+
processed = processed.replace(/^(\s*)([^:\s]+):\s*"(-?\d+\.\d+)"$/gm, '$1$2: $3');
|
|
450
|
+
processed = processed.replace(/^(\s*)([^:\s]+):\s*"(-?\d+\.?\d*[eE][+-]?\d+)"$/gm, '$1$2: $3');
|
|
451
|
+
processed = processed.replace(/^(\s*)([^:\s]+):\s*"\{\{([^}]*)\}\}"/gm, HELM_EXPRESSION_REPLACEMENT);
|
|
452
|
+
processed = processed.replace(/"\{\{([^}]*)\}\}"/g, '{{$1}}');
|
|
453
|
+
processed = processed.replace(/^(\s*)-\s*"\{\{([^}]*)\}\}"/gm, '$1- {{$2}}');
|
|
454
|
+
return processed;
|
|
455
|
+
}
|
|
456
|
+
fixConditionalBlocks(processed) {
|
|
457
|
+
return processed.replace(/"\{\{-\s*(if|with|range)([^}]*)\}\}([^"]*)\{\{-\s*end\s*\}\}"/g, '{{- $1$2}}$3{{- end }}');
|
|
458
|
+
}
|
|
459
|
+
fixPipeExpressions(processed) {
|
|
460
|
+
return processed.replace(/"\{\{([^}]*\|[^}]*)\}\}"/g, '{{$1}}');
|
|
461
|
+
}
|
|
462
|
+
fixNestedQuotes(processed) {
|
|
463
|
+
return processed.replace(/\{\{([^}]*)\\"([^"]*)\\"([^}]*)\}\}/g, '{{$1"$2"$3}}');
|
|
464
|
+
}
|
|
465
|
+
cleanupArtifacts(processed) {
|
|
466
|
+
processed = processed.replace(/": "\.nan"/g, ': .nan');
|
|
467
|
+
processed = processed.replace(/: \{\{([^}]+)\}\}$/gm, ': {{$1}}');
|
|
468
|
+
return processed;
|
|
469
|
+
}
|
|
551
470
|
write(outDir) {
|
|
552
|
-
|
|
471
|
+
console.log('🚀 Rutter.write called with outDir:', outDir);
|
|
472
|
+
console.log('📊 Assets count:', this.assets.length);
|
|
553
473
|
let helpersContent;
|
|
554
474
|
if (this.props.helpersTpl) {
|
|
555
475
|
if (typeof this.props.helpersTpl === 'string') {
|
|
@@ -567,19 +487,19 @@ ${helper.template}
|
|
|
567
487
|
}
|
|
568
488
|
}
|
|
569
489
|
else {
|
|
570
|
-
// Auto-generate standard helpers
|
|
571
490
|
helpersContent = generateHelpersTemplate(this.props.cloudProvider);
|
|
572
491
|
}
|
|
492
|
+
const synthAssets = this.toSynthArray();
|
|
493
|
+
console.log('📦 Generated synth assets:', synthAssets.length);
|
|
573
494
|
HelmChartWriter.write({
|
|
574
495
|
outDir,
|
|
575
496
|
meta: this.meta,
|
|
576
497
|
defaultValues: this.defaultValues,
|
|
577
498
|
envValues: this.envValues,
|
|
578
|
-
assets:
|
|
499
|
+
assets: synthAssets,
|
|
579
500
|
helpersTpl: helpersContent,
|
|
580
501
|
});
|
|
502
|
+
console.log('✅ Rutter.write completed');
|
|
581
503
|
}
|
|
582
504
|
}
|
|
583
|
-
// Constants for labels
|
|
584
505
|
Rutter.HELPER_NAME = 'chart.name';
|
|
585
|
-
//# sourceMappingURL=rutter.js.map
|