【AWS CDK】物理名が必須なリソースのL2コンストラクトで物理名をオプショナルにする
既存のL2コンストラクトに物理名を設定したい方はリソースのpropsにxxxName
というプロパティがあるので設定してください。
AWS::S3::Bucket
だと次のようになります。なお、AWS CDKでリソースに物理名を設定することは非推奨ですのでご注意ください。
new s3.Bucket(this, 'Bucket', {
bucketName: '付けたい物理名'
})
この記事の対象者
- L2コンストラクトを実装する初心者CDKコントリビュータ
- オリジナルコンストラクトをより良い設計にしたいCDKユーザ
何故必要なのか
CloudFormationリソースには物理名を明示的に指定しなければならないリソースがあります。次のリソースはその一例です。
AWS CDKのコンストラクト設計において、ユーザがこれらのリソースに物理名を指定しない場合はCDK側で値を設定する必要があります。この課題を解決するため、AWS CDKにはコンストラクト内でユニークなIDを生成する仕組みが組み込まれているので紹介します。
結論
コンストラクトをこのように実装します。
import { Lazy, Names, Resource } from '@aws-cdk/core';
export class Example extends Resource {
constructor(scope: Construct, id: string, props: ExampleProps) {
super(scope, id, {
physicalName: props.exampleName ??
Lazy.string({ produce: () => Names.uniqueId(this) }),
});
}
}
説明
@aws-cdk/core
パッケージのNames
クラスにはコンストラクト内でユニークなIDを生成する静的メソッドuniqueId
があります。こちらを利用することで任意のIDを生成することができます。
/**
* Functions for devising unique names for constructs. For example, those can be
* used to allocate unique physical names for resources.
*/
export class Names {
/**
* Returns a CloudFormation-compatible unique identifier for a construct based
* on its path. The identifier includes a human readable portion rendered
* from the path components and a hash suffix.
*
* @param construct The construct
* @returns a unique id based on the construct path
*/
public static uniqueId(construct: Construct): string {
const node = Node.of(construct);
const components = node.scopes.slice(1).map(c => Node.of(c).id);
return components.length > 0 ? makeUniqueId(components) : '';
}
}
なお、物理名はResource
クラスのコンストラクタに渡す必要がありますが、子クラスからsuper
呼び出しを完了するまでthis
の値は使用できません。そのため、Lazy
クラスを使用して評価タイミングを遅延させることが必要です。
Lazy.string({ produce: () => Names.uniqueId(this) })
経緯
AWS CDKでAmazon CloudWatch RUMの実装をしていた際、AWS::RUM::AppMonitorは物理名を明示的に設定する必要があったため、RFC時にappMonitorName
をユーザーから受け取るprops
の必須プロパティにしていました。RFCをレビューしていただいたところ、レビュアーから
物理名はオプショナル型とし、CDK側で物理名を設定してください。
とコメントを頂き、これに対処したので記事にしました。
AWS CDKのコントリビュートを始める方の手伝いになれば幸いです。
Discussion