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

How to get logical ID of resource with CDK?

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

构建体如下所示。

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));
  }
}

我想编写一个如下所示的测试。

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
    )
  );
});

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

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

{
  "Type": "AWS::EC2::SecurityGroupIngress",
  "Properties": {
    "IpProtocol": "tcp",
    "FromPort": 22,
    "GroupId": {
      "Fn::GetAtt": [
        "TestConstructSecurityGroup95EF3F0F", <-- This
        "GroupId"
      ]
    },
    "SourceSecurityGroupId": "id-123",
    "ToPort": 22
  }
}

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


请注意,CDK 确实 为您提供 handful of identifiers

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

写完整个 post 并深入研究 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);

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

// Pretend construct.securityGroup is of type CfnSecurityGroup
const logicalId = stack.getLogicalId(construct.securityGroup);

除了 jaredready 的出色回答之外,您还可以使用 resource.node.default_child.overrideLogicalId("AnyStringHere")

显式设置逻辑 ID

这可能会更容易,因为您可以设置一次并使用 hard-coded 个字符串,而不是为每个测试查找值。

根据我的测试,似乎stack.getLogicalId总是return原来的,CDK分配的logicalId,调用overrideLogicalId不会改变,所以不会始终匹配合成输出。

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

stack.resolve((construct.node.defaultChild as cdk.CfnElement).logicalId)

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