【问题标题】:How to get logical ID of resource with CDK?如何使用 CDK 获取资源的逻辑 ID?
【发布时间】:2020-08-31 07:49:27
【问题描述】:

我正在尝试为 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 的作为 Construct 的一部分创建的安全组。

您可以在此处生成的 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。

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

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

【问题讨论】:

    标签: amazon-web-services amazon-cloudformation aws-cdk


    【解决方案1】:

    写完整篇文章并深入研究 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);
    

    【讨论】:

      【解决方案2】:

      除了来自 jaredready 的出色回答,您还可以使用 resource.node.default_child.overrideLogicalId("AnyStringHere") 显式设置逻辑 ID

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

      【讨论】:

        【解决方案3】:

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

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

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-11-27
          • 2020-11-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-03-29
          相关资源
          最近更新 更多