diff --git a/docs/java.md b/docs/java.md
index 8706be4608..ec5850e394 100644
--- a/docs/java.md
+++ b/docs/java.md
@@ -205,6 +205,7 @@ import org.cdk8s.App;
App.Builder.create()
// .outdir(java.lang.String)
// .outputFileExtension(java.lang.String)
+// .recordConstructMetadata(java.lang.Boolean)
// .yamlOutputType(YamlOutputType)
.build();
```
@@ -227,6 +228,15 @@ The file extension to use for rendered YAML files.
---
+##### `recordConstructMetadata`Optional
+
+- *Type:* `java.lang.Boolean`
+- *Default:* false
+
+When set to true, the output directory will contain a `construct-metadata.json` file that holds construct related metadata on every resource in the app.
+
+---
+
##### `yamlOutputType`Optional
- *Type:* [`org.cdk8s.YamlOutputType`](#org.cdk8s.YamlOutputType)
@@ -818,6 +828,7 @@ import org.cdk8s.AppProps;
AppProps.builder()
// .outdir(java.lang.String)
// .outputFileExtension(java.lang.String)
+// .recordConstructMetadata(java.lang.Boolean)
// .yamlOutputType(YamlOutputType)
.build();
```
@@ -848,6 +859,19 @@ The file extension to use for rendered YAML files.
---
+##### `recordConstructMetadata`Optional
+
+```java
+public java.lang.Boolean getRecordConstructMetadata();
+```
+
+- *Type:* `java.lang.Boolean`
+- *Default:* false
+
+When set to true, the output directory will contain a `construct-metadata.json` file that holds construct related metadata on every resource in the app.
+
+---
+
##### `yamlOutputType`Optional
```java
diff --git a/docs/python.md b/docs/python.md
index 4dee7ce439..2832aabe7e 100644
--- a/docs/python.md
+++ b/docs/python.md
@@ -213,6 +213,7 @@ import cdk8s
cdk8s.App(
outdir: str = None,
output_file_extension: str = None,
+ record_construct_metadata: bool = None,
yaml_output_type: YamlOutputType = None
)
```
@@ -235,6 +236,15 @@ The file extension to use for rendered YAML files.
---
+##### `record_construct_metadata`Optional
+
+- *Type:* `bool`
+- *Default:* false
+
+When set to true, the output directory will contain a `construct-metadata.json` file that holds construct related metadata on every resource in the app.
+
+---
+
##### `yaml_output_type`Optional
- *Type:* [`cdk8s.YamlOutputType`](#cdk8s.YamlOutputType)
@@ -840,6 +850,7 @@ import cdk8s
cdk8s.AppProps(
outdir: str = None,
output_file_extension: str = None,
+ record_construct_metadata: bool = None,
yaml_output_type: YamlOutputType = None
)
```
@@ -870,6 +881,19 @@ The file extension to use for rendered YAML files.
---
+##### `record_construct_metadata`Optional
+
+```python
+record_construct_metadata: bool
+```
+
+- *Type:* `bool`
+- *Default:* false
+
+When set to true, the output directory will contain a `construct-metadata.json` file that holds construct related metadata on every resource in the app.
+
+---
+
##### `yaml_output_type`Optional
```python
@@ -2818,6 +2842,7 @@ import cdk8s
cdk8s.Testing.app(
outdir: str = None,
output_file_extension: str = None,
+ record_construct_metadata: bool = None,
yaml_output_type: YamlOutputType = None
)
```
@@ -2840,6 +2865,15 @@ The file extension to use for rendered YAML files.
---
+###### `record_construct_metadata`Optional
+
+- *Type:* `bool`
+- *Default:* false
+
+When set to true, the output directory will contain a `construct-metadata.json` file that holds construct related metadata on every resource in the app.
+
+---
+
###### `yaml_output_type`Optional
- *Type:* [`cdk8s.YamlOutputType`](#cdk8s.YamlOutputType)
diff --git a/docs/typescript.md b/docs/typescript.md
index 432c5faeaa..117a43e12c 100644
--- a/docs/typescript.md
+++ b/docs/typescript.md
@@ -717,6 +717,19 @@ The file extension to use for rendered YAML files.
---
+##### `recordConstructMetadata`Optional
+
+```typescript
+public readonly recordConstructMetadata: boolean;
+```
+
+- *Type:* `boolean`
+- *Default:* false
+
+When set to true, the output directory will contain a `construct-metadata.json` file that holds construct related metadata on every resource in the app.
+
+---
+
##### `yamlOutputType`Optional
```typescript
diff --git a/src/api-object.ts b/src/api-object.ts
index 48ae38e2ef..10640830e9 100644
--- a/src/api-object.ts
+++ b/src/api-object.ts
@@ -136,6 +136,7 @@ export class ApiObject extends Construct {
...props.metadata?.labels,
},
});
+
}
/**
diff --git a/src/app.ts b/src/app.ts
index 7f26bde13f..04ea890a30 100644
--- a/src/app.ts
+++ b/src/app.ts
@@ -36,6 +36,14 @@ export interface AppProps {
* @default YamlOutputType.FILE_PER_CHART
*/
readonly yamlOutputType?: YamlOutputType;
+
+ /**
+ * When set to true, the output directory will contain a `construct-metadata.json` file
+ * that holds construct related metadata on every resource in the app.
+ *
+ * @default false
+ */
+ readonly recordConstructMetadata?: boolean;
}
/**
@@ -99,6 +107,8 @@ export class App extends Construct {
*/
public readonly yamlOutputType: YamlOutputType;
+ private readonly recordConstructMetadata: boolean;
+
/**
* Returns all the charts in this app, sorted topologically.
*/
@@ -118,6 +128,9 @@ export class App extends Construct {
this.outdir = props.outdir ?? process.env.CDK8S_OUTDIR ?? 'dist';
this.outputFileExtension = props.outputFileExtension ?? '.k8s.yaml';
this.yamlOutputType = props.yamlOutputType ?? YamlOutputType.FILE_PER_CHART;
+
+ this.recordConstructMetadata = props.recordConstructMetadata ?? (process.env.CDK8S_RECORD_CONSTRUCT_METADATA === 'true' ? true : false);
+
}
/**
@@ -154,11 +167,9 @@ export class App extends Construct {
case YamlOutputType.FILE_PER_CHART:
const namer: ChartNamer = hasDependantCharts ? new IndexedChartNamer() : new SimpleChartNamer();
-
for (const chart of charts) {
const chartName = namer.name(chart);
const objects = chartToKube(chart);
-
Yaml.save(path.join(this.outdir, chartName+this.outputFileExtension), objects.map(obj => obj.toJson()));
}
break;
@@ -199,6 +210,11 @@ export class App extends Construct {
break;
}
+ if (this.recordConstructMetadata) {
+ const allObjects = this.charts.flatMap(chartToKube);
+ this.writeConstructMetadata(allObjects);
+ }
+
}
/**
@@ -219,6 +235,17 @@ export class App extends Construct {
return Yaml.stringify(...docs);
}
+
+ private writeConstructMetadata(apiObjects: ApiObject[]) {
+ const resources: { [key: string]: any } = {};
+ for (const apiObject of apiObjects) {
+ resources[apiObject.name] = { path: Node.of(apiObject).path };
+ }
+ fs.writeFileSync(path.join(this.outdir, 'construct-metadata.json'), JSON.stringify({
+ version: '1.0.0',
+ resources: resources,
+ }));
+ }
}
function validate(app: App) {
diff --git a/src/chart.ts b/src/chart.ts
index 8027972374..e4adb3b35c 100644
--- a/src/chart.ts
+++ b/src/chart.ts
@@ -21,6 +21,7 @@ export interface ChartProps {
* @default - no common labels
*/
readonly labels?: { [name: string]: string };
+
}
export class Chart extends Construct {
diff --git a/test/chart.test.ts b/test/chart.test.ts
index 154b9928ce..f4fe5d3c8e 100644
--- a/test/chart.test.ts
+++ b/test/chart.test.ts
@@ -1,3 +1,5 @@
+import * as fs from 'fs';
+import * as path from 'path';
import { Construct, Node, Dependency } from 'constructs';
import { Chart, ApiObject, Testing } from '../src';
import { Lazy } from '../src/lazy';
@@ -313,6 +315,76 @@ describe('toJson', () => {
});
+test('construct metadata is recorded when requested by api', () => {
+
+ const app = Testing.app({ recordConstructMetadata: true });
+ const chart = new Chart(app, 'chart1');
+
+ new ApiObject(chart, 'obj1', {
+ kind: 'Deployment',
+ apiVersion: 'v1',
+ });
+
+ app.synth();
+
+ const constructMetadata = JSON.parse(fs.readFileSync(path.join(app.outdir, 'construct-metadata.json'), { encoding: 'utf-8' }));
+ expect(constructMetadata).toEqual({
+ version: '1.0.0',
+ resources: {
+ 'chart1-obj1-c818e77f': {
+ path: 'chart1/obj1',
+ },
+ },
+ });
+
+
+});
+
+test('construct metadata is recoreded when requested by env variable', () => {
+
+ try {
+ process.env.CDK8S_RECORD_CONSTRUCT_METADATA = 'true';
+ const app = Testing.app();
+ const chart = new Chart(app, 'chart1');
+
+ new ApiObject(chart, 'obj1', {
+ kind: 'Deployment',
+ apiVersion: 'v1',
+ });
+
+ app.synth();
+
+ const constructMetadata = JSON.parse(fs.readFileSync(path.join(app.outdir, 'construct-metadata.json'), { encoding: 'utf-8' }));
+ expect(constructMetadata).toEqual({
+ version: '1.0.0',
+ resources: {
+ 'chart1-obj1-c818e77f': {
+ path: 'chart1/obj1',
+ },
+ },
+ });
+ } finally {
+ delete process.env.CDK8S_RECORD_CONSTRUCT_METADATA;
+ }
+
+});
+
+test('construct metadata is not recorded when not requested', () => {
+
+ const app = Testing.app();
+ const chart = new Chart(app, 'chart1');
+
+ new ApiObject(chart, 'obj1', {
+ kind: 'Deployment',
+ apiVersion: 'v1',
+ });
+
+ app.synth();
+
+ expect(fs.existsSync(path.join(app.outdir, 'construct-metadata.json'))).toBeFalsy();
+
+});
+
function createImplictToken(value: any) {
const implicit = {};
Object.defineProperty(implicit, 'resolve', { value: () => value });