Skip to content

Commit

Permalink
feat: chart.toJson() and apiObject.toJson() (#63)
Browse files Browse the repository at this point in the history
To simplify interoperability, expose `toJson()` methods on `ApiObject` and on `Chart` which render the Kubernetes JSON for the resource/chart.

Related to #48
  • Loading branch information
Elad Ben-Israel committed Mar 10, 2020
1 parent fcb81a8 commit 80e8402
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 35 deletions.
13 changes: 9 additions & 4 deletions packages/cdk8s/lib/api-object.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { Construct } from '@aws-cdk/core';
import { Chart } from './chart';
import { removeEmpty } from './_util';
import { resolve } from './_tokens';

/**
* Metadata associated with this object.
Expand Down Expand Up @@ -106,17 +108,20 @@ export class ApiObject extends Construct {
}

/**
* Renders the object to Kubernetes config.
* @internal
* Renders the object to Kubernetes JSON.
*/
public _render(): any {
return {
public toJson(): any {
const data = {
...this.options,
metadata: {
...this.options.metadata,
name: this.name
}
};

// convert to "pure data" so, for example, when we convert to yaml these
// references are not converted to anchors.
return JSON.parse(JSON.stringify(removeEmpty(resolve(this, data))));
}
}

32 changes: 12 additions & 20 deletions packages/cdk8s/lib/chart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import * as fs from 'fs';
import * as path from 'path';
import { ApiObject } from './api-object';
import * as YAML from 'yaml';
import { resolve } from './_tokens';
import { removeEmpty } from './_util';
import { Names } from './names';

export class Chart extends Construct {
Expand Down Expand Up @@ -61,26 +59,20 @@ export class Chart extends Construct {
return Names.toDnsLabel(apiObject.node.path);
}

protected synthesize(session: ISynthesisSession) {
const resources = new Array<any>();

for (const resource of this.node.findAll()) {
if (!(resource instanceof ApiObject)) {
continue;
}

const manifest = removeEmpty(resolve(this, resource._render()));
resources.push(manifest);
}
/**
* Renders this chart to a set of Kubernetes JSON resources.
* @returns array of resource manifests
*/
public toJson(): any[] {
return this.node.findAll().filter(x => x instanceof ApiObject).map(x => (x as ApiObject).toJson());
}

/**
* Called by the app to synthesize the chart as a YAML file in the output directory/
*/
protected synthesize(session: ISynthesisSession) {
// convert each resource to yaml and separate with a '---' line
const doc = resources.map(r => toYaml(r)).join('---\n');
const doc = this.toJson().map(r => YAML.stringify(r)).join('---\n');
fs.writeFileSync(path.join(session.assembly.outdir, this.manifestFile), doc);
}
}

function toYaml(o: any) {
// lose anchors which are based on reference equality
const x = JSON.parse(JSON.stringify(o));
return YAML.stringify(x);
}
7 changes: 1 addition & 6 deletions packages/cdk8s/lib/testing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import fs = require('fs');
import path = require('path');
import os = require('os');
import { App, Chart } from '../lib';
import * as YAML from 'yaml';

/**
* Testing utilities for cdk8s applications.
Expand All @@ -21,11 +20,7 @@ export class Testing {
* Returns the Kubernetes manifest synthesized from this chart.
*/
public static synth(chart: Chart) {
const app = chart.node.root as App;
app.synth();

const filePath = path.join(app.outdir, chart.manifestFile);
return YAML.parseAllDocuments(fs.readFileSync(filePath, 'utf-8')).map((doc: any) => doc.toJSON());
return chart.toJson();
}

/* istanbul ignore next */
Expand Down
25 changes: 20 additions & 5 deletions packages/cdk8s/test/__snapshots__/chart.test.js.snap
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`empty stack 1`] = `
Array [
null,
]
`;
exports[`empty stack 1`] = `Array []`;

exports[`output includes all synthesized resources 1`] = `
Array [
Expand Down Expand Up @@ -46,6 +42,25 @@ Array [
]
`;

exports[`synthesizeManifest() can be used to synthesize a specific chart 1`] = `
Array [
Object {
"apiVersion": "v1",
"kind": "Kind1",
"metadata": Object {
"name": "chart-obj1-f2e469b6",
},
},
Object {
"apiVersion": "v1",
"kind": "Kind2",
"metadata": Object {
"name": "chart-obj2-e10626fd",
},
},
]
`;

exports[`tokens are resolved during synth 1`] = `
Array [
Object {
Expand Down
14 changes: 14 additions & 0 deletions packages/cdk8s/test/chart.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,20 @@ test('Chart.of(node) fails when there is no chart in the tree', () => {
expect(() => Chart.of(child)).toThrow(/cannot find a parent chart \(directly or indirectly\)/);
});

test('synthesizeManifest() can be used to synthesize a specific chart', () => {
// GIVEN
const app = Testing.app();
const chart = new Chart(app, 'chart');
new ApiObject(chart, 'obj1', { apiVersion: 'v1', kind: 'Kind1' });
new ApiObject(chart, 'obj2', { apiVersion: 'v1', kind: 'Kind2' });

// WHEN
const manifest = chart.toJson();

// THEN
expect(manifest).toMatchSnapshot();
});

function createImplictToken(value: any) {
const implicit = {};
Object.defineProperty(implicit, 'resolve', { value: () => value });
Expand Down

0 comments on commit 80e8402

Please sign in to comment.