Open7

CDK for Terraformのスニペット

inomotoinomoto

Stack配下全体で使えるcontext的な値を取り回す

StackやConstructでは this.node.set|getContext という方法でそういう値を取り回せる。
しかしそのままでは型が無い・参照時に名前が長いので

main.ts
class MyStack extends TerraformStack {
  constructor(scope: Construct, id: string, env: EnvType) {
    super(scope, id);

    // TerraformVariableなどのリソース定義の後にsetContextができないという制約があるため
    // 一旦空オブジェクトをsetContextしておき、後から値を入れることで制約を回避する
    // TerraformVariableを使わない(環境変数を使うなど)ならsetContextの引数にそのまま値を全部入れればok
    const context: Partial<AppContext> = {};
    this.node.setContext('appContext', context);

    const projectId = new TerraformVariable(this, 'project_id', { type: 'string' });

    context.env = env;
    context.gcpProjectId = projectId;
    context.gcpLocation = 'asia-northeast1';
baseConstruct.ts
import {TerraformVariable} from 'cdktf';
import {Construct} from 'constructs/lib/construct';

export type AppContext = {
  env: EnvType;
  gcpProjectId: TerraformVariable;
  gcpLocation: string;
};

export class BaseConstruct extends Construct {
  constructor(scope: Construct, id: string) {
    super(scope, id);
  }

  get env() {
    return this.appContext.env;
  }

  get projectId() {
    return this.appContext.gcpProjectId;
  }

  get gcpLocation() {
    return this.appContext.gcpLocation;
  }

  private get appContext(): AppContext {
    return this.node.getContext('appContext') as AppContext;
  }
}

として上で、配下でリソースを作るConstructで

serviceAccount.ts
export class ServiceAccount extends BaseConstruct { // 作ったBaseConstructを継承
  constructor(scope: Construct, name: string, permissions: string[]) {
    super(scope, `ServiceAccount_${name}`);

    ...

    new ProjectIamMember(this, 'member', {
      project: this.projectId.value, // envならそのまま this.env で
      role: role.name,
      member: `serviceAccount:${account.email}`,
    });

Stackでの制約回避がゴリ押しだが、それでいいのかは知らない。

inomotoinomoto

synthの差分を見ながらパッケージをアップデート

#!/bin/bash

# cdktf関連のパッケージをアップデートする際に利用するヘルパースクリプト
#
# 実行するとnpmパッケージのフルアップデートを実行するが、その前後にnpm run synthを行い
# アップデート前後でその成果物にどんな差分があるかを表示する。
#
# 通常はjson内に記載されるプロバイダのバージョン差分しか出ないので、その場合は安心してcommitする。
# そうでない差分がある場合は詳細を調査して対応する。
#
# 前後差分表示のために、cdktfが生成するtf.jsonをgit stageに入れているが、差分を見終わったらcommitせずはずしておくこと。

set -eu

cd $(dirname $0)

npm ci

npm run synth
git add -f cdktf.out/stacks/**/cdk.tf.json

# @types/nodeはnodejsのバージョンを上げるときに合わせて上げる
npx npm-check-updates -u --reject @types/node

# 依存する子孫パッケージも含めて完全に最新化するため、現状バージョンの痕跡を消してからnpm installする
rm -rf node_modules package-lock.json
npm install

npm run synth

git add package.json package-lock.json
set +e
git diff
inomotoinomoto

まぁproviderのバージョンアップで非互換になる可能性が捨てられないので、理想的にはplanしたほうがいい

inomotoinomoto

convertのいい感じバージョン

typescript決め打ち・providerも決め打ち・providerSchemaのキャッシュあり・いらぬclass囲いとimportを捨てる版

convert.ts
import { convert } from "@cdktf/hcl2cdk";
import { TerraformProviderConstraint } from "@cdktf/provider-generator";
import { readSchema } from "@cdktf/provider-schema";
import { ConstructsMakerProviderTarget, LANGUAGES } from "@cdktf/commons";

import { readFileSync } from "fs";

async function main() {
  const hcl = readFileSync("/dev/stdin").toString(); // MacとLinux (WSL) がカバーできればいいでしょ

  const targets = [
    ConstructsMakerProviderTarget.from(
      new TerraformProviderConstraint("aws@ ~> 5.24.0"), // 適当に変える
      LANGUAGES[0],
    ),
  ];

  const { providerSchema } = await readSchema(targets, "./cache"); // 適当に変える

  const ts = await convert(hcl, {
    language: "typescript",
    providerSchema: providerSchema!,
  });
  console.log(ts.code);
}

main();

cat ../network.tf | ./node_modules/.bin/ts-node convert.ts みたいな感じで使う

inomotoinomoto

CDKTF側からHCLにあるリソースの参照を使いたい

CDKTFとHCLが混在してる場合。

HCLで

resource "aws_db_subnet_group" "production-rds" {
  name = "production-rds"
  subnet_ids = [
    aws_subnet.production-private-a.id,
    aws_subnet.production-private-c.id
  ]

みたいに書いてあり、subnetはHCLにおいたままsubnet_groupをcdktfにもっていく場合、

    const snGroupPrd = new DbSubnetGroup(this, 'subnet-group-production', {
      name: 'production-rds',
      subnetIds: [
        '${aws_subnet.production-private-a.id}',
        '${aws_subnet.production-private-c.id}',
      ],

のように '${xxx}' とすると参照できる。

inomotoinomoto

ちなみに lookup(var.cidrs, "production-private-a") みたいなやつのvar.cidrs部分はどうにもならないっぽい。cdktf側のTerraformVariableに展開しないといけないのかな。わからんけど。