Skip to content

Commit

Permalink
Includes output.tf in generated terraform (#237)
Browse files Browse the repository at this point in the history
Signed-off-by: Sean Sundberg <seansund@us.ibm.com>
  • Loading branch information
seansund authored Oct 6, 2022
1 parent c4606b3 commit 64aee92
Show file tree
Hide file tree
Showing 5 changed files with 187 additions and 11 deletions.
14 changes: 14 additions & 0 deletions src/models/bill-of-material.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ export interface BillOfMaterialModuleVariable {
required?: boolean;
}

export interface BillOfMaterialModuleOutput {
name: string;
description?: string;
alias?: string;
scope?: string;
}

export interface BillOfMaterialModuleProvider {
name: string;
ref?: string;
Expand All @@ -30,6 +37,7 @@ export interface BaseBillOfMaterialModule {
version?: string;
default?: boolean;
variables?: BillOfMaterialModuleVariable[];
outputs?: BillOfMaterialModuleOutput[];
dependencies?: BillOfMaterialModuleDependency[];
providers?: BillOfMaterialModuleProvider[];
}
Expand Down Expand Up @@ -66,6 +74,11 @@ export interface BillOfMaterialVariable {
required?: boolean;
}

export interface BillOfMaterialOutput {
name: string;
alias?: string;
}

export interface BillOfMaterialProvider {
name: string;
alias?: string;
Expand All @@ -82,6 +95,7 @@ export interface BillOfMaterialProviderVariable {
export interface BillOfMaterialSpec {
modules: Array<string | BillOfMaterialModule>;
variables?: BillOfMaterialVariable[];
outputs?: BillOfMaterialOutput[];
providers?: BillOfMaterialProvider[];
}

Expand Down
11 changes: 6 additions & 5 deletions src/models/module.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,16 +113,17 @@ export interface ModuleVariable {
sensitive?: boolean;
}

export interface ModuleOutput {
name: string
description?: string
sensitive?: boolean
}

export interface ModuleOutputRef {
id: string;
output: string;
}

export interface ModuleOutput {
name: string;
description?: string;
}

export function dependsOnModule(module: Module, depModule: Module | undefined): boolean {
if (isUndefined(depModule)) {
return false;
Expand Down
32 changes: 30 additions & 2 deletions src/models/stages.model.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {
BaseVariable,
fromBaseVariable,
fromBaseVariable, IBaseOutput,
IBaseVariable,
StagePrinter,
StagePrinter, TerraformOutput, TerraformOutputImpl,
TerraformProvider,
TerraformTfvars,
TerraformVariable,
Expand Down Expand Up @@ -33,6 +33,7 @@ export interface Stage extends IStage, StagePrinter {
export interface TerraformComponentModel {
stages: { [source: string]: Stage };
baseVariables: IBaseVariable[];
baseOutputs: IBaseOutput[];
bomVariables?: BillOfMaterialVariable[];
modules?: SingleModuleVersion[];
providers?: TerraformProvider[];
Expand Down Expand Up @@ -181,6 +182,31 @@ export class TerraformVariablesFile implements OutputFile {
}
}

export class TerraformOutputFile implements OutputFile {
constructor(private outputs: TerraformOutput[]) {
}

name = 'output.tf';
type = OutputFileType.terraform;

get contents(): Promise<string | Buffer> {

const buffer: Buffer = this.outputs
.reduce((previousBuffer: Buffer, output: TerraformOutput) => {
if (!output.asString) {
output = new TerraformOutputImpl(output);
}

return Buffer.concat([
previousBuffer,
Buffer.from(output.asString())
]);
}, Buffer.from(''));

return Promise.resolve(buffer);
}
}

export class TerraformTfvarsFile implements OutputFile {

name : string;
Expand Down Expand Up @@ -226,6 +252,7 @@ export class TerraformTfvarsFile implements OutputFile {
export class TerraformComponent implements TerraformComponentModel {
stages: { [name: string]: Stage } = {};
baseVariables: TerraformVariable[] = [];
baseOutputs: TerraformOutput[] = [];
bomVariables?: BillOfMaterialVariable[] = []
modules?: SingleModuleVersion[];
providers?: TerraformProvider[];
Expand Down Expand Up @@ -256,6 +283,7 @@ export class TerraformComponent implements TerraformComponentModel {
const files: Array<OutputFile | undefined> = [
new TerraformStageFile(this.stages),
new TerraformVariablesFile(this.baseVariables, this.bomVariables),
new TerraformOutputFile(this.baseOutputs),
this.providers !== undefined && this.providers.length > 0 ? new TerraformProvidersFile(this.providers) : undefined,
this.providers !== undefined && this.providers.length > 0 ? new TerraformVersionFile(this.providers) : undefined,
tfvarsFile,
Expand Down
80 changes: 79 additions & 1 deletion src/models/variables.model.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {BillOfMaterialProviderVariable} from './bill-of-material.model';
import {ModuleVariable} from './module.model';
import {ModuleOutputRef, ModuleVariable} from './module.model';
import {ArrayUtil, of as arrayOf} from '../util/array-util/array-util';
import {isDefined} from '../util/object-util';
import {ModuleNotFound} from '../errors';
Expand All @@ -22,6 +22,13 @@ export interface IBaseVariable {
important?: boolean;
}

export interface IBaseOutput {
name: string;
description?: string;
value: string;
sensitive?: boolean;
}

export interface BaseVariable extends IBaseVariable, StagePrinter {
}

Expand All @@ -31,6 +38,11 @@ export interface IModuleVariable extends IBaseVariable {
mapper?: 'equality' | 'collect';
}

export interface IModuleOutput extends BaseOutput {
moduleRef: {stageName: string} | {stageName: string}[];
moduleOutputName: string;
}

export class ModuleRefVariable implements IModuleVariable, BaseVariable {
name: string;
description?: string;
Expand Down Expand Up @@ -267,6 +279,48 @@ ${this.variableString(' ')}
}
}

export interface TerraformOutput extends IBaseOutput {
asString(): string;
}

export class TerraformOutputImpl implements TerraformOutput {
name: string = '';
private _description: string = '';
value: string = '';
sensitive: boolean = false

constructor(values: {name: string, description?: string, value: string, sensitive?: boolean}) {
this.name = values.name
this.description = values.description || ''
this.value = values.value
this.sensitive = values.sensitive || false
}

get description() {
return this._description || `the value of ${this.name}`;
}
set description(description: string) {
this._description = description;
}

sensitiveValue() {
if (!this.sensitive) {
return ''
}

return `
sensitive = true`
}

asString(): string {
return `output "${this.name}" {
description = "${this.description}"
value = ${this.value}${this.sensitiveValue()}
}
`;
}
}

export interface TerraformVariable extends IBaseVariable {
asString(): string;
}
Expand Down Expand Up @@ -458,3 +512,27 @@ const typeFormatters: {[type: string]: Formatter} = {
}),
'string': buildTypeFormatter('string', defaultFormatter),
}

export interface BaseOutput extends IBaseOutput {
}

export class ModuleRefOutput implements BaseOutput {
name: string
description?: string
sensitive?: boolean

stageName: string
moduleOutputRef: ModuleOutputRef

constructor({name, description, sensitive, stageName, moduleOutputRef}: {name: string, description?: string, sensitive?: boolean, stageName: string, moduleOutputRef: ModuleOutputRef}) {
this.name = name
this.description = description
this.sensitive = sensitive
this.stageName = stageName
this.moduleOutputRef = moduleOutputRef
}

get value(): string {
return `module.${this.stageName}.${this.moduleOutputRef.output}`
}
}
61 changes: 58 additions & 3 deletions src/services/terraform-builder/terraform-builder.new.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
import {TerraformBuilderApi} from './terraform-builder.api';
import {
BaseOutput,
BaseVariable,
BillOfMaterialModel,
BillOfMaterialModule,
BillOfMaterialModuleOutput,
BillOfMaterialModuleVariable,
BillOfMaterialProvider,
BillOfMaterialVariable,
CatalogV2Model,
IBaseOutput,
IBaseVariable,
IPlaceholderVariable,
isPlaceholderVariable,
isSingleModuleVersion,
Module,
ModuleDependency,
ModuleDependency, ModuleOutput,
ModuleOutputRef,
ModuleProvider,
ModuleProvider, ModuleRefOutput,
ModuleRefVariable,
ModuleVariable,
PlaceholderVariable,
Expand All @@ -33,6 +36,7 @@ import {Optional} from '../../util/optional';
interface TerraformResult {
stages: {[name: string]: Stage}
baseVariables: IBaseVariable[],
baseOutputs: IBaseOutput[],
providers: TerraformProvider[]
}

Expand Down Expand Up @@ -73,6 +77,7 @@ export class TerraformBuilderNew implements TerraformBuilderApi {
const terraform: TerraformResult = modules.reduce(
(result: TerraformResult, module: SingleModuleVersion) => {
const stageVariables: BaseVariable[] = this.moduleVariablesToStageVariables(module)
const stageOutputs: BaseOutput[] = this.moduleOutputsToStageOutputs(module)
const {providers, providerVariables} = extractProvidersFromModule(module, result, billOfMaterial?.spec.providers)

const stage: Stage = new StageImpl({
Expand All @@ -84,21 +89,24 @@ export class TerraformBuilderNew implements TerraformBuilderApi {

result.stages[stage.name] = stage
result.baseVariables.push(...stageVariables)
result.baseOutputs.push(...stageOutputs)

result.providers.push(...providers)
result.baseVariables.push(...providerVariables)

return result
},
{stages: {}, baseVariables: [], providers: []}
{stages: {}, baseVariables: [], providers: [], baseOutputs: []}
)

const baseVariables: IBaseVariable[] = this.processBaseVariables(terraform.baseVariables, billOfMaterial?.spec.variables)
const baseOutputs: IBaseOutput[] = terraform.baseOutputs

const name: string | undefined = billOfMaterial?.metadata.name;
return new TerraformComponent({
stages: terraform.stages,
baseVariables,
baseOutputs,
providers: terraform.providers,
modules,
bomVariables: billOfMaterial?.spec.variables,
Expand All @@ -118,6 +126,16 @@ export class TerraformBuilderNew implements TerraformBuilderApi {
return stageVariables
}

moduleOutputsToStageOutputs(module: SingleModuleVersion): BaseOutput[] {

const stageOutputs: BaseOutput[] = module.version.outputs
.map(mergeBomOutputs(arrayOf(module.bomModule?.outputs)))
.map(mapModuleOutput(module))
.filter(isDefinedAndNotNull)

return stageOutputs
}

processBaseVariables(variables: IBaseVariable[], billOfMaterialVariables: BillOfMaterialVariable[] = []): IBaseVariable[] {

return variables
Expand Down Expand Up @@ -182,6 +200,26 @@ const mergeBomVariables = (bomVariables: ArrayUtil<BillOfMaterialModuleVariable>
};
}

const mergeBomOutputs = (bomOutputs: ArrayUtil<BillOfMaterialModuleOutput>) => {
return (outputs: ModuleOutput): ModuleOutput => {
const optionalBomOutput: Optional<BillOfMaterialModuleOutput> = bomOutputs
.filter(v => v.name === outputs.name)
.first();

if (!optionalBomOutput.isPresent()) {
return outputs;
}

const bomOutput: BillOfMaterialModuleOutput = optionalBomOutput.get();

return Object.assign(
{},
outputs,
bomOutput
);
};
}

function defaultValue(variable: ModuleVariable, bomModule?: BillOfMaterialModule): any {
return arrayOf(bomModule?.variables)
.filter(bomVariable => bomVariable.name === variable.name)
Expand Down Expand Up @@ -337,3 +375,20 @@ const mapModuleVariable = (module: SingleModuleVersion | ModuleProvider) => {
}
}
}

const mapModuleOutput = (module: SingleModuleVersion | ModuleProvider) => {
return (o: ModuleOutput): BaseOutput => {
const moduleName = module.alias || module.name

return new ModuleRefOutput({
name: `${moduleName}_${o.name}`,
description: o.description,
sensitive: o.sensitive,
stageName: moduleName,
moduleOutputRef: {
id: moduleName,
output: o.name,
}
})
}
}

0 comments on commit 64aee92

Please sign in to comment.