如何使用 CDK 获取资源的逻辑 ID?

jre*_*ady 10 amazon-web-services aws-cloudformation aws-cdk

我正在尝试为 CDK 构造编写一些测试,以验证定义为构造一部分的安全组规则。

构造看起来类似于以下内容。

export interface SampleConstructProps extends StackProps {
  srcSecurityGroupId: string;
}

export class SampleConstruct extends Construct {
  securityGroup: SecurityGroup;

  constructor(scope: Construct, id: string, props: SampleConstructProps) {
    super(scope, id, props);

    // const vpc = Vpc.fromLookup(...);
    this.securityGroup = new SecurityGroup(this, "SecurityGroup", {
      vpc: vpc,
      allowAllOutbound: true,
    });

    const srcSecurityGroupId = SecurityGroup.fromSecurityGroupId(stack, "SrcSecurityGroup", props.srcSecurityGroupId);

    this.securityGroup.addIngressRule(srcSecurityGroup, Port.tcp(22));
  }
}
Run Code Online (Sandbox Code Playgroud)

我想编写一个类似于以下内容的测试。

test("Security group config is correct", () => {
  const stack = new Stack();
  const srcSecurityGroupId = "id-123";
  const testConstruct = new SampleConstruct(stack, "TestConstruct", {
    srcSecurityGroupId: srcSecurityGroupId
  });

  expect(stack).to(
    haveResource(
      "AWS::EC2::SecurityGroupIngress",
      {
        IpProtocol: "tcp",
        FromPort: 22,
        ToPort: 22,
        SourceSecurityGroupId: srcSecurityGroupId,
        GroupId: {
          "Fn::GetAtt": [testConstruct.securityGroup.logicalId, "GroupId"], // Can't do this
        },
      },
      undefined,
      true
    )
  );
});

Run Code Online (Sandbox Code Playgroud)

这里的问题是测试是针对合成的 CloudFormation 模板进行验证的,因此如果您想验证此构造创建的安全组是否具有允许从 访问的规则srcSecurityGroup,您需要作为一部分创建的安全组的逻辑 ID的构造。

您可以在此处生成的 CloudFormation 模板中看到这一点。

{
  "Type": "AWS::EC2::SecurityGroupIngress",
  "Properties": {
    "IpProtocol": "tcp",
    "FromPort": 22,
    "GroupId": {
      "Fn::GetAtt": [
        "TestConstructSecurityGroup95EF3F0F", <-- This
        "GroupId"
      ]
    },
    "SourceSecurityGroupId": "id-123",
    "ToPort": 22
  }
}
Run Code Online (Sandbox Code Playgroud)

Fn::GetAtt就是这个问题的症结所在。由于这些测试实际上只是进行对象比较,因此您需要能够复制Fn::Get调用,这需要 CloudFormation 逻辑 ID。


请注意,CDK确实为您提供了一些标识符

  • 唯一 ID 提供了非常接近的信息,但它与 CloudFormation 堆栈中使用的标识符不同。例如,securityGroup.uniqueId返回TestStackTestConstructSecurityGroup10D493A7而 CloudFormation 模板显示TestConstructSecurityGroup95EF3F0F。您可以注意到不同之处在于uniqueId将构造 ID 附加到逻辑标识符,并且每个附加的散列都不同。
  • 构造 ID 只是您在实例化构造时提供的标识符。它也不是逻辑 ID,尽管它被用作逻辑 ID 的一部分。我也没有看到直接从构造中以编程方式检索此 ID 的方法。您当然可以在某处定义 ID 并重复使用它,但这仍然不能解决它与逻辑 ID 不完全匹配的问题。在这种情况下,它与合成模板中SecurityGroup的构造 ID 和TestConstructSecurityGroup95EF3F0F逻辑 ID 不同。

有没有一种直接的方法可以获取 CDK 资源的逻辑 ID?

jre*_*ady 14

在写完整篇文章并深入研究 CDK 代码后,我偶然发现了我正在寻找的答案。如果有人有更好的方法从更高级别的 CDK 构造中获取逻辑 ID,我们将不胜感激。

如果需要获取 CDK 资源的逻辑 ID,可以执行以下操作:

const stack = new Stack();
const construct = new SampleConstruct(stack, "SampleConstruct");
const logicalId = stack.getLogicalId(construct.securityGroup.node.defaultChild as CfnSecurityGroup);
Run Code Online (Sandbox Code Playgroud)

请注意,您已经拥有一个 CloudFormation 资源(例如以 开头的资源Cfn),那么它会更容易一些。

// Pretend construct.securityGroup is of type CfnSecurityGroup
const logicalId = stack.getLogicalId(construct.securityGroup);
Run Code Online (Sandbox Code Playgroud)


Lia*_*amD 8

从我的测试来看,似乎stack.getLogicalId总是返回原始的、CDK分配的逻辑Id,如果你调用它不会改变overrideLogicalId,所以它并不总是与合成的输出匹配。

即使设置了 LogicalId 覆盖,这对我也有用:

stack.resolve((construct.node.defaultChild as cdk.CfnElement).logicalId)
Run Code Online (Sandbox Code Playgroud)

stack.resolve是必要的,因为它.logicalId是一个令牌。