Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/asset-publish.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
ref: ${{ github.event.release.tag_name }}

- uses: actions/setup-node@v3
- uses: actions/setup-node@v4
with:
node-version: '16'

- name: Set up QEMU
uses: docker/setup-qemu-action@v2
uses: docker/setup-qemu-action@v3

- name: Build
run: npm ci && npm run build
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/npm-publish.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ jobs:
echo "NPM_TAG=--tag beta" >> $GITHUB_OUTPUT
fi

- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
ref: ${{ github.event.release.tag_name }}

- uses: actions/setup-node@v3
- uses: actions/setup-node@v4
with:
node-version: '16'
registry-url: https://registry.npmjs.org/
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,12 @@ jobs:

# Steps represent a sequence of tasks that will be executed as part of the job
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4

# Drafts your next Release notes as Pull Requests are merged into "main"
- name: Create release
id: create-release
uses: release-drafter/release-drafter@v5
uses: release-drafter/release-drafter@v6
with:
# (Optional) specify config name to use, relative to .github/. Default: release-drafter.yml
config-name: release-drafter.yaml
Expand All @@ -67,7 +67,7 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- uses: actions/setup-node@v3
- uses: actions/setup-node@v4
with:
node-version: '16'

Expand All @@ -84,7 +84,7 @@ jobs:

- name: Publish release
id: publish-release
uses: release-drafter/release-drafter@v5
uses: release-drafter/release-drafter@v6
with:
# (Optional) specify config name to use, relative to .github/. Default: release-drafter.yml
config-name: release-drafter.yaml
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/verify-pr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
ref: ${{ github.event.release.tag_name }}

- uses: actions/setup-node@v3
- uses: actions/setup-node@v4
with:
node-version: '16'

- name: Set up QEMU
uses: docker/setup-qemu-action@v2
uses: docker/setup-qemu-action@v3

- name: Build
run: |
Expand Down
33 changes: 30 additions & 3 deletions src/commands/iascable-build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Container } from 'typescript-ioc'
import { Arguments, Argv, CommandBuilder, CommandModule } from 'yargs'
import { join } from 'path'
import uniq from 'lodash.uniq'
import {promises} from 'fs';

import { IascableInput } from './inputs/iascable.input'
import { CommandLineInput } from './inputs/command-line.input'
Expand Down Expand Up @@ -75,7 +76,7 @@ export const builder: CommandBuilder<any, any> = (yargs: Argv<any>) => {
type: 'array'
})
.option('tileDescription', {
description: 'The description of the tile.',
description: 'The description of the tile on IBM Cloud.',
demandOption: false,
})
.option('flattenOutput', {
Expand All @@ -88,6 +89,16 @@ export const builder: CommandBuilder<any, any> = (yargs: Argv<any>) => {
type: 'boolean',
describe: 'Flag to turn on more detailed output message',
})
.option('backend', {
alias: ['b'],
choices: ['kubernetes', 'cos'],
demandOption: false,
describe: 'The type of backend that should be included in the terraform. If not provided the backend will default to the filesystem'
})
.option('backendConfig', {
demandOption: false,
describe: 'JSON configuration values or @filename of JSON configuration for the defined backend. If backend value not defined then value is ignored'
})
.middleware(setupCatalogUrls(DEFAULT_CATALOG_URLS))
.check((argv) => {
if (!(argv.reference && argv.reference.length > 0) && !(argv.input && argv.input.length > 0)) {
Expand All @@ -114,7 +125,7 @@ export const handler = async (argv: Arguments<BuilderArgs>) => {

const catalogUrls: string[] = loadCatalogUrls(boms, argv.catalogUrls)

const options: IascableOptions = buildCatalogBuilderOptions(argv);
const options: IascableOptions = await buildCatalogBuilderOptions(argv);

try {
const result: IascableBundle = await cmd.buildBoms(catalogUrls, boms, options);
Expand Down Expand Up @@ -193,7 +204,7 @@ async function loadBoms(referenceNames?: string[], inputNames?: string[], names:
return boms;
}

function buildCatalogBuilderOptions(input: IascableInput): IascableOptions {
const buildCatalogBuilderOptions = async (input: IascableInput): Promise<IascableOptions> => {
const tileConfig = {
label: input.tileLabel,
name: input.name,
Expand All @@ -207,9 +218,25 @@ function buildCatalogBuilderOptions(input: IascableInput): IascableOptions {
provider: input.provider,
},
tileConfig: isTileConfig(tileConfig) ? tileConfig : undefined,
backend: input.backend,
backendConfig: await processBackendConfig(input.backendConfig),
};
}

const processBackendConfig = async (configInput?: string): Promise<unknown | undefined> => {
if (!configInput) {
return
}

if (configInput.startsWith('@')) {
const configFile = configInput.slice(1)

configInput = await promises.readFile(configFile, 'utf8');
}

return JSON.parse(configInput)
}

export const iascableBuild: CommandModule = {
command,
describe: desc,
Expand Down
2 changes: 2 additions & 0 deletions src/commands/inputs/iascable.input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ export interface IascableInput {
name?: string[];
tileDescription?: string;
outDir?: string;
backend?: string;
backendConfig?: string;
}

export interface IascableDocsInput {
Expand Down
117 changes: 117 additions & 0 deletions src/models/terragrunt.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ export interface TerragruntDependencyModel {
outputs: string[]
}

export interface TerragruntBackendModel {
name: string;
config?: unknown;
}

export class TerragruntLayer implements TerragruntLayerModel, OutputFile {
name: string = 'terragrunt.hcl';
type: OutputFileType = OutputFileType.terraform;
Expand Down Expand Up @@ -184,6 +189,11 @@ export interface TerragruntBaseModel {
export class TerragruntBase implements TerragruntBaseModel, OutputFile {
name: string = 'terragrunt.hcl';
type: OutputFileType = OutputFileType.terraform;
backend?: TerragruntBackendModel;

constructor({backend}: {backend?: TerragruntBackendModel} = {}) {
this.backend = backend;
}

contents(): Promise<string | Buffer> {
return Promise.resolve(`skip = true
Expand All @@ -205,6 +215,113 @@ terraform {
]
}
}
${this.generateBackend()}
`)
}

generateBackend(): string {
if (!this.backend) {
return ''
}

const backend: TerragruntBackendBase = backends[this.backend.name]

if (!backend) {
console.log('Unknown backend configuration: ' + this.backend.name)
return ''
}

return backend.contents(this.backend.config)
}

generateBackendConfig(config: any, indent: string = ''): string {
return Object
.keys(config)
.map(key => `${indent}${key} = ${valueToString(config[key])}`)
.join('\n')
}
}

const valueToString = (value: any): string => {
if (typeof value === 'boolean') {
return value.toString()
}

return `"${value.toString()}"`
}

abstract class TerragruntBackendBase implements TerragruntBackendModel {
name: string;

constructor(name: string) {
this.name = name;
}

contents(backendConfig: unknown): string {
const config = this.buildConfig(backendConfig)

return `
generate "backend" {
path = "backend.tf"
if_exists = "overwrite_terragrunt"
contents = <<EOF
terraform {
backend "${this.name}" {
${this.generateBackendConfig(config, ' ')}
}
}
EOF
}
`
}

abstract buildConfig(backendConfig: unknown): any;

generateBackendConfig(config: any, indent: string = ''): string {
return Object
.keys(config)
.map(key => `${indent}${key} = ${valueToString(config[key])}`)
.join('\n')
}
}

class TerragruntKubernetesBackend extends TerragruntBackendBase implements TerragruntBackendModel {
constructor() {
super('kubernetes')
}

buildConfig(backendConfig: unknown): any {
const config = Object.assign(
{
secret_suffix: '\${replace(replace(path_relative_to_include(), "/terraform", ""), "/", "-")}',
in_cluster_config: true,
},
backendConfig || {}
)

return config
}
}

class CosKubernetesBackend extends TerragruntBackendBase implements TerragruntBackendModel {
constructor() {
super('cos')
}

buildConfig(backendConfig: unknown): any {
const config = Object.assign(
{
prefix: '\${replace(replace(path_relative_to_include(), "/terraform", ""), "/", "-")}',
bucket: `bucket-for-terraform-state-${new Date().getTime()}`
},
backendConfig || {}
)

return config
}
}

const backends: {[key: string]: TerragruntBackendBase} = {
'kubernetes': new TerragruntKubernetesBackend(),
'cos': new CosKubernetesBackend(),
}
7 changes: 5 additions & 2 deletions src/services/iascable/iascable.api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import {
BillOfMaterialModel,
CatalogFilter,
OutputFile,
TerraformComponentModel,
TerraformComponentModel, TerragruntBackendModel,
Tile,
TileConfig
} from '../../models';
} from '../../models'
import {DotGraphFile} from '../../models/graph.model';
import {SolutionModel} from '../../models/solution.model';
import {BundleWriter} from '../../util/bundle-writer';
Expand Down Expand Up @@ -41,6 +41,7 @@ export const isIascableBomResult = (result: IasableResult<any>): result is Iasca
export interface IascableSolutionResultBase extends IasableResult<SolutionModel> {
results: IascableBomResult[]
capabilities: CapabilityModel[]
backend?: TerragruntBackendModel;
}

export interface IascableSolutionResult extends IascableSolutionResultBase, WritableBundle {
Expand All @@ -62,6 +63,8 @@ export interface IascableOptions {
tileConfig?: TileConfig;
filter?: CatalogFilter;
interactive?: boolean;
backend?: string;
backendConfig?: unknown;
}

export abstract class IascableApi {
Expand Down
Loading