如何在不触发类型转换异常的情况下重写AWS CDK资源Logical ID
问题
之前一直用某篇文章里的方法重写AWS CDK资源的Logical ID,该方法正常运行数月,代码如下:
class MyConstruct(scope: Construct, id: String) extends Construct(scope, id) { val barFunc = lambda .Function .Builder .create(this, "bar") .handler("blah.blah") .code(lambda.Code.fromInline("blah")) .runtime(lambda.Runtime.PYTHON_3_10) .build barFunc .getNode .getDefaultChild .asInstanceOf[CfnFunction] .overrideLogicalId("mylogicalid") } class MyStack(scope: Construct, id: String, stackProps: StackProps) extends Stack(scope, id, stackProps) { val barConstruct = new MyConstruct(this, "bar") }
近期未修改代码,但执行synth时突然失败,报错:
java.lang.ClassCastException: class software.constructs.Construct cannot be cast to class software.amazon.awscdk.services.lambda.CfnFunction
推测是CDK破坏性更新导致,已尝试回退cdk和aws-cdk-lib版本但无效,当前依赖版本:
lazy val awsCdkLib = "software.amazon.awscdk" % "aws-cdk-lib" % "2.89.0" lazy val awsConstructs = "software.constructs" % "constructs" % "10.2.69"
需要找到修改已实例化Function的Logical ID且不触发异常的方法。
解决方案
之前通过getDefaultChild强转的方式失效,是因为CDK部分高层construct的默认子节点结构发生了变化,现在可以通过以下两种可靠方法修改Lambda Function的Logical ID:
方法1:直接获取底层Cfn资源(推荐)
Lambda的Function construct提供了getCfnFunction()方法,可直接获取对应的CfnFunction实例,无需强转:
class MyConstruct(scope: Construct, id: String) extends Construct(scope, id) { val barFunc = lambda .Function .Builder .create(this, "bar") .handler("blah.blah") .code(lambda.Code.fromInline("blah")) .runtime(lambda.Runtime.PYTHON_3_10) .build // 直接调用官方方法获取底层CFN资源 barFunc.getCfnFunction.overrideLogicalId("mylogicalid") } class MyStack(scope: Construct, id: String, stackProps: StackProps) extends Stack(scope, id, stackProps) { val barConstruct = new MyConstruct(this, "bar") }
方法2:遍历子节点筛选CfnFunction
如果getCfnFunction()方法不可用,可遍历Function的子节点,筛选出CfnFunction类型的实例:
class MyConstruct(scope: Construct, id: String) extends Construct(scope, id) { val barFunc = lambda .Function .Builder .create(this, "bar") .handler("blah.blah") .code(lambda.Code.fromInline("blah")) .runtime(lambda.Runtime.PYTHON_3_10) .build // 遍历子节点找到目标CfnFunction val cfnFunc = barFunc.getNode.getChildren .find(_.isInstanceOf[CfnFunction]) .getOrElse(throw new RuntimeException("Failed to locate CfnFunction instance")) .asInstanceOf[CfnFunction] cfnFunc.overrideLogicalId("mylogicalid") } class MyStack(scope: Construct, id: String, stackProps: StackProps) extends Stack(scope, id, stackProps) { val barConstruct = new MyConstruct(this, "bar") }
关键说明
- 方法1是最稳妥的方案,因为这是CDK官方提供的访问底层CFN资源的接口,不会因内部结构调整而失效。
- 避免依赖
getDefaultChild这类内部实现细节,CDK的节点结构可能随版本更新发生变化,导致强转异常。
内容的提问来源于stack exchange,提问作者Ramón J Romero y Vigil
相关产品推荐
相关产品推荐

