timonel 2.10.1 → 2.11.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/README.md +5 -9
- package/dist/cli.js +22 -48
- package/dist/index.d.ts +1 -2
- package/dist/index.js +1 -2
- package/dist/lib/helmChartWriter.js +17 -2
- package/dist/lib/rutter.d.ts +1 -0
- package/dist/lib/rutter.js +64 -11
- package/dist/lib/templates/flexible-subchart.d.ts +1 -0
- package/dist/lib/templates/flexible-subchart.js +101 -0
- package/dist/lib/templates/umbrella-chart.d.ts +13 -2
- package/dist/lib/templates/umbrella-chart.js +128 -42
- package/dist/lib/utils/helmHelpers/envHelpers.d.ts +2 -0
- package/dist/lib/utils/helmHelpers/envHelpers.js +97 -0
- package/dist/lib/utils/helmHelpers/gitopsHelpers.d.ts +2 -0
- package/dist/lib/utils/helmHelpers/gitopsHelpers.js +132 -0
- package/dist/lib/utils/helmHelpers/index.d.ts +23 -0
- package/dist/lib/utils/helmHelpers/index.js +132 -0
- package/dist/lib/utils/helmHelpers/observabilityHelpers.d.ts +2 -0
- package/dist/lib/utils/helmHelpers/observabilityHelpers.js +221 -0
- package/dist/lib/utils/helmHelpers/types.d.ts +16 -0
- package/dist/lib/utils/helmHelpers/types.js +1 -0
- package/dist/lib/utils/helmHelpers/validationHelpers.d.ts +2 -0
- package/dist/lib/utils/helmHelpers/validationHelpers.js +201 -0
- package/dist/lib/utils/helmHelpers.d.ts +11 -1
- package/dist/lib/utils/helmHelpers.js +20 -7
- package/dist/lib/utils/helmYamlSerializer.d.ts +53 -1
- package/dist/lib/utils/helmYamlSerializer.js +325 -29
- package/dist/lib/utils/logger.d.ts +49 -0
- package/dist/lib/utils/logger.js +418 -0
- package/package.json +24 -12
- package/dist/lib/templates/basic-chart.d.ts +0 -19
- package/dist/lib/templates/basic-chart.js +0 -210
- package/dist/lib/templates/subchart.d.ts +0 -27
- package/dist/lib/templates/subchart.js +0 -219
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
# [2.11.0](https://github.com/KenkoGeek/timonel/compare/v2.10.2...v2.11.0) (2025-09-26)
|
|
2
|
+
|
|
3
|
+
### Features
|
|
4
|
+
|
|
5
|
+
- **helm:** add comprehensive helm helpers with Helm template validation ([#123](https://github.com/KenkoGeek/timonel/issues/123)) ([bda8115](https://github.com/KenkoGeek/timonel/commit/bda811546d308eaa3ee5aec7fd8356b4a508940e))
|
|
6
|
+
|
|
7
|
+
## [2.10.2](https://github.com/KenkoGeek/timonel/compare/v2.10.1...v2.10.2) (2025-09-20)
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
- **cli:** consolidate path validation and improve error handling ([239a50f](https://github.com/KenkoGeek/timonel/commit/239a50fb30be451301d2af6a586b77748a3db6ec))
|
|
12
|
+
|
|
1
13
|
## [2.10.1](https://github.com/KenkoGeek/timonel/compare/v2.10.0...v2.10.1) (2025-09-20)
|
|
2
14
|
|
|
3
15
|
### Bug Fixes
|
package/README.md
CHANGED
|
@@ -15,22 +15,18 @@ Helm charts using cdk8s. Define Kubernetes resources with type-safe classes and
|
|
|
15
15
|
Helm charts with `Chart.yaml`, `values.yaml`, environment-specific values files, and `templates/`
|
|
16
16
|
directory.
|
|
17
17
|
|
|
18
|
-
> 🚀 **New in v2.9.2**: Enhanced umbrella chart support with flexible subchart templates, improved
|
|
19
|
-
> CLI version handling, and optimized GitHub workflows.
|
|
20
|
-
|
|
21
18
|
## ✨ Key Features
|
|
22
19
|
|
|
23
20
|
- **🔒 Type-safe API** with strict TypeScript and cdk8s constructs
|
|
24
21
|
- **🔧 Flexible resource creation** with built-in methods and `addManifest()` for custom resources
|
|
25
22
|
- **🌍 Multi-environment support** with automatic values files generation
|
|
26
23
|
- **☂️ Umbrella Charts** for managing multiple subcharts as a single unit
|
|
24
|
+
- **🛠️ Enhanced Helm Helpers** with environment, GitOps, observability, and validation helpers
|
|
27
25
|
- **☁️ Cloud integrations**:
|
|
28
|
-
- **AWS**: EBS/EFS StorageClass, ALB Ingress, IRSA ServiceAccount
|
|
29
|
-
- **Azure**: Azure Disk, Azure Files, AKS integrations
|
|
30
|
-
- **GCP**: GCE Persistent Disk, GKE integrations
|
|
26
|
+
- **AWS**: EBS/EFS StorageClass, ALB Ingress, IRSA ServiceAccount, ECR, and Karpenter
|
|
31
27
|
- **🛡️ Security-first approach** with NetworkPolicies and best practices
|
|
32
28
|
- **⚡ Minimal CLI** (`tl`) for scaffolding and chart generation
|
|
33
|
-
- **📦 Flexible subchart templates** supporting cdk8s
|
|
29
|
+
- **📦 Flexible subchart templates** supporting cdk8s and cdk8s-plus-33
|
|
34
30
|
|
|
35
31
|
## 🚀 Quick Start
|
|
36
32
|
|
|
@@ -246,5 +242,5 @@ MIT
|
|
|
246
242
|
[maintained-url]: https://github.com/kenkogeek/
|
|
247
243
|
[ci-badge]: https://github.com/KenkoGeek/timonel/actions/workflows/test.yaml/badge.svg?branch=main
|
|
248
244
|
[ci-url]: https://github.com/KenkoGeek/timonel/actions/workflows/test.yaml
|
|
249
|
-
[codeql-badge]: https://github.com/KenkoGeek/timonel/actions/workflows/codeql.
|
|
250
|
-
[codeql-url]: https://github.com/KenkoGeek/timonel/actions/workflows/codeql.
|
|
245
|
+
[codeql-badge]: https://github.com/KenkoGeek/timonel/actions/workflows/codeql.yml/badge.svg
|
|
246
|
+
[codeql-url]: https://github.com/KenkoGeek/timonel/actions/workflows/codeql.yml
|
package/dist/cli.js
CHANGED
|
@@ -4,28 +4,12 @@ import fs from 'fs';
|
|
|
4
4
|
import path from 'path';
|
|
5
5
|
import { fileURLToPath } from 'url';
|
|
6
6
|
import { SecurityUtils } from './lib/security.js';
|
|
7
|
+
import { createLogger } from './lib/utils/logger.js';
|
|
7
8
|
const __filename = fileURLToPath(import.meta.url);
|
|
8
9
|
const __dirname = path.dirname(__filename);
|
|
9
10
|
const UMBRELLA_CONFIG_FILE = 'umbrella.config.json';
|
|
10
11
|
const UMBRELLA_FILE_NAME = 'umbrella.ts';
|
|
11
12
|
const PACKAGE_JSON_FILE = 'package.json';
|
|
12
|
-
function isValidPath(filePath, expectedFileName) {
|
|
13
|
-
try {
|
|
14
|
-
const resolvedPath = path.resolve(filePath);
|
|
15
|
-
const normalizedPath = path.normalize(resolvedPath);
|
|
16
|
-
if (normalizedPath.includes('..') || normalizedPath.includes('~')) {
|
|
17
|
-
return false;
|
|
18
|
-
}
|
|
19
|
-
if (!normalizedPath.endsWith(expectedFileName)) {
|
|
20
|
-
return false;
|
|
21
|
-
}
|
|
22
|
-
const suspiciousPatterns = ['\\', '..', '~', '$', '`', '|', '&', ';', '(', ')'];
|
|
23
|
-
return !suspiciousPatterns.some((pattern) => normalizedPath.includes(pattern));
|
|
24
|
-
}
|
|
25
|
-
catch {
|
|
26
|
-
return false;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
13
|
function getVersion() {
|
|
30
14
|
try {
|
|
31
15
|
const possiblePaths = [
|
|
@@ -35,18 +19,21 @@ function getVersion() {
|
|
|
35
19
|
path.resolve(__dirname, PACKAGE_JSON_FILE),
|
|
36
20
|
];
|
|
37
21
|
for (const packagePath of possiblePaths) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
22
|
+
try {
|
|
23
|
+
const validatedPath = SecurityUtils.validatePath(packagePath, process.cwd());
|
|
24
|
+
if (fs.existsSync(validatedPath)) {
|
|
25
|
+
try {
|
|
26
|
+
const packageJson = JSON.parse(fs.readFileSync(validatedPath, 'utf8'));
|
|
27
|
+
return packageJson.version || 'unknown';
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
48
32
|
}
|
|
49
33
|
}
|
|
34
|
+
catch {
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
50
37
|
}
|
|
51
38
|
if (process.env.npm_package_version) {
|
|
52
39
|
return process.env.npm_package_version;
|
|
@@ -57,14 +44,15 @@ function getVersion() {
|
|
|
57
44
|
return 'unknown';
|
|
58
45
|
}
|
|
59
46
|
}
|
|
47
|
+
const cliLogger = createLogger('cli');
|
|
60
48
|
function log(msg, silent = false) {
|
|
61
49
|
if (!silent) {
|
|
62
|
-
|
|
50
|
+
cliLogger.info(msg, { operation: 'cli_log' });
|
|
63
51
|
}
|
|
64
52
|
}
|
|
65
53
|
function logError(msg, silent = false) {
|
|
66
54
|
if (!silent) {
|
|
67
|
-
|
|
55
|
+
cliLogger.error(msg, { operation: 'cli_error' });
|
|
68
56
|
}
|
|
69
57
|
}
|
|
70
58
|
function usageAndExit(msg, silent = false) {
|
|
@@ -94,7 +82,6 @@ function usageAndExit(msg, silent = false) {
|
|
|
94
82
|
' --env <environment> Use environment-specific values',
|
|
95
83
|
' --set <key=value> Override values (can be used multiple times)',
|
|
96
84
|
' --help, -h Show this help message',
|
|
97
|
-
' --version, -v Show version information',
|
|
98
85
|
'',
|
|
99
86
|
'Examples:',
|
|
100
87
|
' tl init my-app',
|
|
@@ -118,8 +105,8 @@ async function cmdInit(name, silent = false) {
|
|
|
118
105
|
const base = path.join(process.cwd(), validName);
|
|
119
106
|
const chartFile = path.join(base, 'chart.ts');
|
|
120
107
|
fs.mkdirSync(base, { recursive: true });
|
|
121
|
-
const {
|
|
122
|
-
fs.writeFileSync(chartFile,
|
|
108
|
+
const { generateFlexibleSubchartTemplate } = await import('./lib/templates/flexible-subchart.js');
|
|
109
|
+
fs.writeFileSync(chartFile, generateFlexibleSubchartTemplate(validName));
|
|
123
110
|
log(`Chart created at ${base}`, silent);
|
|
124
111
|
log(`Generated chart.ts file`, silent);
|
|
125
112
|
log(`Run 'tl synth ${validName}' to generate complete Helm chart`, silent);
|
|
@@ -359,8 +346,8 @@ async function cmdUmbrellaAdd(subchartPath, silent = false) {
|
|
|
359
346
|
const subchartDir = path.join(process.cwd(), 'charts', validSubchartPath);
|
|
360
347
|
fs.mkdirSync(subchartDir, { recursive: true });
|
|
361
348
|
const chartFile = path.join(subchartDir, 'chart.ts');
|
|
362
|
-
const {
|
|
363
|
-
const subchartContent =
|
|
349
|
+
const { generateFlexibleSubchartTemplate } = await import('./lib/templates/flexible-subchart.js');
|
|
350
|
+
const subchartContent = generateFlexibleSubchartTemplate(subchartName);
|
|
364
351
|
fs.writeFileSync(chartFile, subchartContent);
|
|
365
352
|
config.subcharts.push({
|
|
366
353
|
name: subchartName,
|
|
@@ -443,13 +430,6 @@ function parseFlags(args) {
|
|
|
443
430
|
}
|
|
444
431
|
break;
|
|
445
432
|
}
|
|
446
|
-
case '--version':
|
|
447
|
-
case '-v':
|
|
448
|
-
if (!flags.silent) {
|
|
449
|
-
console.log(`Timonel v${getVersion()}`);
|
|
450
|
-
}
|
|
451
|
-
process.exit(0);
|
|
452
|
-
break;
|
|
453
433
|
case '--help':
|
|
454
434
|
case '-h':
|
|
455
435
|
usageAndExit(undefined, flags.silent);
|
|
@@ -495,12 +475,6 @@ async function main() {
|
|
|
495
475
|
usageAndExit(undefined, isSilent);
|
|
496
476
|
return;
|
|
497
477
|
}
|
|
498
|
-
if (args.includes('--version') || args.includes('-v')) {
|
|
499
|
-
if (!isSilent) {
|
|
500
|
-
console.log(`Timonel v${getVersion()}`);
|
|
501
|
-
}
|
|
502
|
-
process.exit(0);
|
|
503
|
-
}
|
|
504
478
|
const command = args.shift();
|
|
505
479
|
const flags = parseFlags(args);
|
|
506
480
|
await executeCommand(command, args, flags);
|
|
@@ -508,7 +482,7 @@ async function main() {
|
|
|
508
482
|
main().catch((error) => {
|
|
509
483
|
const flags = parseFlags(process.argv.slice(2));
|
|
510
484
|
if (!flags.silent) {
|
|
511
|
-
console.error('Error:', error.message);
|
|
485
|
+
console.error('Error:', SecurityUtils.sanitizeLogMessage(error.message));
|
|
512
486
|
}
|
|
513
487
|
process.exit(1);
|
|
514
488
|
});
|
package/dist/index.d.ts
CHANGED
|
@@ -3,12 +3,11 @@ export * from './lib/helmChartWriter.js';
|
|
|
3
3
|
export * from './lib/rutter.js';
|
|
4
4
|
export * from './lib/security.js';
|
|
5
5
|
export * from './lib/umbrella.js';
|
|
6
|
-
export { BasicChart } from './lib/templates/basic-chart.js';
|
|
7
6
|
export { FlexibleSubchart, createFlexibleSubchart } from './lib/templates/flexible-subchart.js';
|
|
8
|
-
export { Subchart } from './lib/templates/subchart.js';
|
|
9
7
|
export { UmbrellaChartTemplate as UmbrellaChart } from './lib/templates/umbrella-chart.js';
|
|
10
8
|
export type { ChartProps, SubchartProps } from './lib/types.js';
|
|
11
9
|
export type { AWSALBIngressSpec, AWSEBSStorageClassSpec, AWSEFSStorageClassSpec, AWSIRSAServiceAccountSpec, } from './lib/resources/cloud/aws/awsResources.js';
|
|
12
10
|
export type { KarpenterDisruption, KarpenterDisruptionBudget, KarpenterEC2NodeClassSpec, KarpenterNodeClaimSpec, KarpenterNodePoolSpec, } from './lib/resources/cloud/aws/karpenterResources.js';
|
|
13
11
|
export { DEFAULT_TERMINATION_GRACE_PERIOD, isValidDisruptionBudget, isValidKubernetesDuration, KarpenterVersionUtils, } from './lib/resources/cloud/aws/karpenterResources.js';
|
|
14
12
|
export { AWS_HELPERS, createHelper, FILE_ACCESS_HELPERS, formatHelpers, generateHelpersTemplate, getDefaultHelpers, getHelpersByCategory, KUBERNETES_HELPERS, SPRIG_HELPERS, STANDARD_HELPERS, TEMPLATE_FUNCTION_HELPERS, type HelperDefinition, } from './lib/utils/helmHelpers.js';
|
|
13
|
+
export { createLogger, logger, LogLevel, TimonelLogger, type LogContext, type LoggerConfig, } from './lib/utils/logger.js';
|
package/dist/index.js
CHANGED
|
@@ -3,9 +3,8 @@ export * from './lib/helmChartWriter.js';
|
|
|
3
3
|
export * from './lib/rutter.js';
|
|
4
4
|
export * from './lib/security.js';
|
|
5
5
|
export * from './lib/umbrella.js';
|
|
6
|
-
export { BasicChart } from './lib/templates/basic-chart.js';
|
|
7
6
|
export { FlexibleSubchart, createFlexibleSubchart } from './lib/templates/flexible-subchart.js';
|
|
8
|
-
export { Subchart } from './lib/templates/subchart.js';
|
|
9
7
|
export { UmbrellaChartTemplate as UmbrellaChart } from './lib/templates/umbrella-chart.js';
|
|
10
8
|
export { DEFAULT_TERMINATION_GRACE_PERIOD, isValidDisruptionBudget, isValidKubernetesDuration, KarpenterVersionUtils, } from './lib/resources/cloud/aws/karpenterResources.js';
|
|
11
9
|
export { AWS_HELPERS, createHelper, FILE_ACCESS_HELPERS, formatHelpers, generateHelpersTemplate, getDefaultHelpers, getHelpersByCategory, KUBERNETES_HELPERS, SPRIG_HELPERS, STANDARD_HELPERS, TEMPLATE_FUNCTION_HELPERS, } from './lib/utils/helmHelpers.js';
|
|
10
|
+
export { createLogger, logger, LogLevel, TimonelLogger, } from './lib/utils/logger.js';
|
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
2
|
import * as path from 'path';
|
|
3
3
|
import { SecurityUtils } from './security.js';
|
|
4
|
+
import { createLogger } from './utils/logger.js';
|
|
4
5
|
import { dumpHelmAwareYaml } from './utils/helmYamlSerializer.js';
|
|
5
6
|
export class HelmChartWriter {
|
|
6
7
|
static write(opts) {
|
|
7
8
|
const { outDir, meta, defaultValues = {}, envValues = {}, assets, helpersTpl, notesTpl, valuesSchema, } = opts;
|
|
8
|
-
|
|
9
|
+
const logger = createLogger('helm-chart-writer');
|
|
10
|
+
const timer = logger.time('helm_chart_write');
|
|
11
|
+
logger.info('Starting Helm chart write operation', {
|
|
12
|
+
chartName: meta.name,
|
|
13
|
+
version: meta.version,
|
|
14
|
+
outputDirectory: outDir,
|
|
15
|
+
assetCount: assets.length,
|
|
16
|
+
operation: 'helm_write_start',
|
|
17
|
+
});
|
|
9
18
|
const validatedOutDir = SecurityUtils.validatePath(outDir, process.cwd());
|
|
10
19
|
this.createDirectories(validatedOutDir);
|
|
11
20
|
this.writeChartYaml(validatedOutDir, meta);
|
|
@@ -15,7 +24,13 @@ export class HelmChartWriter {
|
|
|
15
24
|
this.writeNotes(validatedOutDir, notesTpl);
|
|
16
25
|
this.writeSchema(validatedOutDir, valuesSchema);
|
|
17
26
|
this.writeHelmIgnore(validatedOutDir);
|
|
18
|
-
|
|
27
|
+
logger.info('Helm chart write operation completed successfully', {
|
|
28
|
+
chartName: meta.name,
|
|
29
|
+
version: meta.version,
|
|
30
|
+
outputDirectory: validatedOutDir,
|
|
31
|
+
operation: 'helm_write_complete',
|
|
32
|
+
});
|
|
33
|
+
timer();
|
|
19
34
|
}
|
|
20
35
|
static createDirectories(outDir) {
|
|
21
36
|
fs.mkdirSync(path.join(outDir, 'templates'), { recursive: true });
|
package/dist/lib/rutter.d.ts
CHANGED
|
@@ -16,6 +16,7 @@ export declare class Rutter {
|
|
|
16
16
|
private readonly karpenterResources;
|
|
17
17
|
private readonly meta;
|
|
18
18
|
private readonly props;
|
|
19
|
+
private readonly logger;
|
|
19
20
|
constructor(props: RutterProps);
|
|
20
21
|
addAWSEBSStorageClass(spec: AWSEBSStorageClassSpec): ApiObject;
|
|
21
22
|
addAWSEFSStorageClass(spec: AWSEFSStorageClassSpec): ApiObject;
|
package/dist/lib/rutter.js
CHANGED
|
@@ -3,17 +3,24 @@ import * as jsYaml from 'js-yaml';
|
|
|
3
3
|
import { include } from './helm.js';
|
|
4
4
|
import { HelmChartWriter } from './helmChartWriter.js';
|
|
5
5
|
import { AWSResources } from './resources/cloud/aws/awsResources.js';
|
|
6
|
+
import { createLogger } from './utils/logger.js';
|
|
6
7
|
import { KarpenterResources } from './resources/cloud/aws/karpenterResources.js';
|
|
7
8
|
import { dumpHelmAwareYaml } from './utils/helmYamlSerializer.js';
|
|
8
9
|
import { generateHelpersTemplate } from './utils/helmHelpers.js';
|
|
9
10
|
export class Rutter {
|
|
10
11
|
constructor(props) {
|
|
11
12
|
this.assets = [];
|
|
12
|
-
|
|
13
|
+
this.logger = createLogger('rutter');
|
|
13
14
|
this.defaultValues = props.defaultValues ?? {};
|
|
14
15
|
this.envValues = props.envValues ?? {};
|
|
15
16
|
this.meta = props.meta;
|
|
16
17
|
this.props = props;
|
|
18
|
+
this.logger.info('Initializing chart', {
|
|
19
|
+
chartName: props.meta.name,
|
|
20
|
+
version: props.meta.version,
|
|
21
|
+
namespace: props.namespace,
|
|
22
|
+
operation: 'chart_initialization',
|
|
23
|
+
});
|
|
17
24
|
this.app = new App();
|
|
18
25
|
this.chart = new Chart(this.app, props.meta.name, {
|
|
19
26
|
...props.chartProps,
|
|
@@ -134,24 +141,40 @@ ${yamlContent.trim()}
|
|
|
134
141
|
}
|
|
135
142
|
validateManifestStructure(manifest) {
|
|
136
143
|
if (!manifest.apiVersion) {
|
|
137
|
-
|
|
144
|
+
this.logger.error('Validation failed: Missing apiVersion', {
|
|
145
|
+
operation: 'manifest_validation',
|
|
146
|
+
issue: 'missing_api_version',
|
|
147
|
+
});
|
|
138
148
|
throw new Error('Manifest must have an apiVersion');
|
|
139
149
|
}
|
|
140
150
|
if (!manifest.kind) {
|
|
141
|
-
|
|
151
|
+
this.logger.error('Validation failed: Missing kind', {
|
|
152
|
+
operation: 'manifest_validation',
|
|
153
|
+
issue: 'missing_kind',
|
|
154
|
+
});
|
|
142
155
|
throw new Error('Manifest must have a kind');
|
|
143
156
|
}
|
|
144
157
|
if (!manifest.metadata) {
|
|
145
|
-
|
|
158
|
+
this.logger.error('Validation failed: Missing metadata', {
|
|
159
|
+
operation: 'manifest_validation',
|
|
160
|
+
issue: 'missing_metadata',
|
|
161
|
+
});
|
|
146
162
|
throw new Error('Manifest must have metadata');
|
|
147
163
|
}
|
|
148
164
|
const metadata = manifest.metadata;
|
|
149
165
|
if (!metadata.name) {
|
|
150
|
-
|
|
166
|
+
this.logger.error('Validation failed: Missing metadata.name', {
|
|
167
|
+
operation: 'manifest_validation',
|
|
168
|
+
issue: 'missing_metadata_name',
|
|
169
|
+
});
|
|
151
170
|
throw new Error('Manifest metadata must have a name');
|
|
152
171
|
}
|
|
153
172
|
if (typeof metadata.name !== 'string') {
|
|
154
|
-
|
|
173
|
+
this.logger.error('Validation failed: metadata.name must be a string', {
|
|
174
|
+
operation: 'manifest_validation',
|
|
175
|
+
issue: 'invalid_metadata_name_type',
|
|
176
|
+
actual_type: typeof metadata.name,
|
|
177
|
+
});
|
|
155
178
|
throw new Error('Manifest metadata.name must be a string');
|
|
156
179
|
}
|
|
157
180
|
}
|
|
@@ -168,7 +191,11 @@ ${yamlContent.trim()}
|
|
|
168
191
|
return [...this.assets];
|
|
169
192
|
}
|
|
170
193
|
toSynthArray() {
|
|
171
|
-
|
|
194
|
+
const timer = this.logger.time('chart_synthesis');
|
|
195
|
+
this.logger.debug('Starting chart synthesis', {
|
|
196
|
+
chartName: this.meta.name,
|
|
197
|
+
operation: 'synthesis_start',
|
|
198
|
+
});
|
|
172
199
|
const apiObjectIds = [];
|
|
173
200
|
for (const child of this.chart.node.children) {
|
|
174
201
|
if (child instanceof ApiObject && !child.node.id.endsWith('-placeholder')) {
|
|
@@ -184,7 +211,12 @@ ${yamlContent.trim()}
|
|
|
184
211
|
}
|
|
185
212
|
return true;
|
|
186
213
|
});
|
|
187
|
-
|
|
214
|
+
this.logger.info('Processing manifest objects', {
|
|
215
|
+
chartName: this.meta.name,
|
|
216
|
+
manifestCount: manifestObjs.length,
|
|
217
|
+
apiObjectCount: apiObjectIds.length,
|
|
218
|
+
operation: 'manifest_processing',
|
|
219
|
+
});
|
|
188
220
|
const enriched = manifestObjs.map((obj) => {
|
|
189
221
|
if (obj && typeof obj === 'object') {
|
|
190
222
|
const o = obj;
|
|
@@ -229,6 +261,13 @@ ${yamlContent.trim()}
|
|
|
229
261
|
this.assets.forEach((asset) => {
|
|
230
262
|
synthAssets.push({ id: asset.id, yaml: asset.yaml });
|
|
231
263
|
});
|
|
264
|
+
this.logger.info('Chart synthesis completed', {
|
|
265
|
+
chartName: this.meta.name,
|
|
266
|
+
totalAssets: synthAssets.length,
|
|
267
|
+
additionalAssets: this.assets.length,
|
|
268
|
+
operation: 'synthesis_complete',
|
|
269
|
+
});
|
|
270
|
+
timer();
|
|
232
271
|
return synthAssets;
|
|
233
272
|
}
|
|
234
273
|
processHelmTemplates(yaml) {
|
|
@@ -399,7 +438,12 @@ ${yamlContent.trim()}
|
|
|
399
438
|
return processed;
|
|
400
439
|
}
|
|
401
440
|
write(outDir) {
|
|
402
|
-
|
|
441
|
+
const timer = this.logger.time('chart_write');
|
|
442
|
+
this.logger.info('Starting chart write operation', {
|
|
443
|
+
chartName: this.meta.name,
|
|
444
|
+
outputDirectory: outDir,
|
|
445
|
+
operation: 'chart_write_start',
|
|
446
|
+
});
|
|
403
447
|
let helpersContent;
|
|
404
448
|
if (this.props.helpersTpl) {
|
|
405
449
|
if (typeof this.props.helpersTpl === 'string') {
|
|
@@ -420,7 +464,11 @@ ${helper.template}
|
|
|
420
464
|
helpersContent = generateHelpersTemplate(this.props.cloudProvider);
|
|
421
465
|
}
|
|
422
466
|
const synthAssets = this.toSynthArray();
|
|
423
|
-
|
|
467
|
+
this.logger.info('Generated assets for chart', {
|
|
468
|
+
chartName: this.meta.name,
|
|
469
|
+
assetCount: synthAssets.length,
|
|
470
|
+
operation: 'assets_generated',
|
|
471
|
+
});
|
|
424
472
|
HelmChartWriter.write({
|
|
425
473
|
outDir,
|
|
426
474
|
meta: this.meta,
|
|
@@ -429,7 +477,12 @@ ${helper.template}
|
|
|
429
477
|
assets: synthAssets,
|
|
430
478
|
helpersTpl: helpersContent,
|
|
431
479
|
});
|
|
432
|
-
|
|
480
|
+
this.logger.info('Chart write operation completed successfully', {
|
|
481
|
+
chartName: this.meta.name,
|
|
482
|
+
outputDirectory: outDir,
|
|
483
|
+
operation: 'chart_write_complete',
|
|
484
|
+
});
|
|
485
|
+
timer();
|
|
433
486
|
}
|
|
434
487
|
}
|
|
435
488
|
Rutter.HELPER_NAME = 'chart.name';
|
|
@@ -105,3 +105,104 @@ export class FlexibleSubchart extends Chart {
|
|
|
105
105
|
export function createFlexibleSubchart(scope, id, config) {
|
|
106
106
|
return new FlexibleSubchart(scope, id, config);
|
|
107
107
|
}
|
|
108
|
+
export function generateFlexibleSubchartTemplate(name) {
|
|
109
|
+
return `import { App } from 'cdk8s';
|
|
110
|
+
import { Rutter } from 'timonel';
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Creates a new chart with simple Rutter implementation
|
|
114
|
+
* @returns Rutter instance for Helm chart generation
|
|
115
|
+
* @since 2.11.0
|
|
116
|
+
*/
|
|
117
|
+
export default function createChart() {
|
|
118
|
+
const app = new App({ outdir: 'dist' });
|
|
119
|
+
|
|
120
|
+
const rutter = new Rutter({
|
|
121
|
+
meta: {
|
|
122
|
+
name: '${name}',
|
|
123
|
+
version: '1.0.0',
|
|
124
|
+
description: '${name} subchart'
|
|
125
|
+
},
|
|
126
|
+
scope: app,
|
|
127
|
+
defaultValues: {
|
|
128
|
+
appName: '${name}',
|
|
129
|
+
image: 'nginx:latest',
|
|
130
|
+
port: 80,
|
|
131
|
+
replicas: 1,
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// Add simple deployment
|
|
136
|
+
rutter.addManifest({
|
|
137
|
+
apiVersion: 'apps/v1',
|
|
138
|
+
kind: 'Deployment',
|
|
139
|
+
metadata: {
|
|
140
|
+
name: '${name}',
|
|
141
|
+
labels: {
|
|
142
|
+
'app.kubernetes.io/name': '${name}'
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
spec: {
|
|
146
|
+
replicas: 1,
|
|
147
|
+
selector: {
|
|
148
|
+
matchLabels: {
|
|
149
|
+
'app.kubernetes.io/name': '${name}'
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
template: {
|
|
153
|
+
metadata: {
|
|
154
|
+
labels: {
|
|
155
|
+
'app.kubernetes.io/name': '${name}'
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
spec: {
|
|
159
|
+
containers: [{
|
|
160
|
+
name: '${name}',
|
|
161
|
+
image: 'nginx:latest',
|
|
162
|
+
ports: [{
|
|
163
|
+
containerPort: 80
|
|
164
|
+
}],
|
|
165
|
+
env: [
|
|
166
|
+
{ name: 'APP_NAME', value: '${name}' },
|
|
167
|
+
{ name: 'PORT', value: '80' }
|
|
168
|
+
]
|
|
169
|
+
}]
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}, 'deployment');
|
|
174
|
+
|
|
175
|
+
// Add Service
|
|
176
|
+
rutter.addManifest({
|
|
177
|
+
apiVersion: 'v1',
|
|
178
|
+
kind: 'Service',
|
|
179
|
+
metadata: {
|
|
180
|
+
name: '${name}',
|
|
181
|
+
labels: {
|
|
182
|
+
'app.kubernetes.io/name': '${name}'
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
spec: {
|
|
186
|
+
type: 'ClusterIP',
|
|
187
|
+
ports: [{
|
|
188
|
+
port: 80,
|
|
189
|
+
targetPort: 80,
|
|
190
|
+
protocol: 'TCP',
|
|
191
|
+
name: 'http'
|
|
192
|
+
}],
|
|
193
|
+
selector: {
|
|
194
|
+
'app.kubernetes.io/name': '${name}'
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}, 'service');
|
|
198
|
+
|
|
199
|
+
return rutter;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Auto-execute when run directly
|
|
203
|
+
if (import.meta.url === new URL(import.meta.url).href) {
|
|
204
|
+
const chart = createChart();
|
|
205
|
+
chart.write('dist');
|
|
206
|
+
}
|
|
207
|
+
`;
|
|
208
|
+
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { Chart } from 'cdk8s';
|
|
1
|
+
import { App, Chart } from 'cdk8s';
|
|
3
2
|
import type { ChartProps } from '../types.js';
|
|
4
3
|
export declare function generateUmbrellaChart(name: string): string;
|
|
5
4
|
export declare class UmbrellaChartTemplate extends Chart {
|
|
@@ -9,6 +8,18 @@ export declare class UmbrellaChartTemplate extends Chart {
|
|
|
9
8
|
private configure;
|
|
10
9
|
private _addService;
|
|
11
10
|
private _addSubchart;
|
|
11
|
+
private _createFlexibleSubchart;
|
|
12
|
+
private _createFallbackSubchart;
|
|
13
|
+
private _handleFunctionChart;
|
|
14
|
+
private _handleObjectChart;
|
|
15
|
+
private _isRutterInstance;
|
|
16
|
+
private _isChartInstance;
|
|
17
|
+
private _processRutterInstance;
|
|
18
|
+
private _processChartInstance;
|
|
19
|
+
private _copyTemplates;
|
|
20
|
+
private _ensureDirectoryExists;
|
|
21
|
+
private _processAssets;
|
|
22
|
+
private _cleanupTempDir;
|
|
12
23
|
private _createBasicSubchart;
|
|
13
24
|
writeHelmChart(outputDir: string): void;
|
|
14
25
|
}
|