如何使用 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。
- 唯一 ID 提供了非常接近的东西,但它与 CloudFormation 堆栈中使用的标识符不同。例如,
securityGroup.uniqueId
returns TestStackTestConstructSecurityGroup10D493A7
而 CloudFormation 模板显示 TestConstructSecurityGroup95EF3F0F
。您可以注意到不同之处在于 uniqueId
将 Construct ID 前置到逻辑标识符,并且附加的散列在每个中都不同。
- 构造 ID 只是您在实例化构造时提供的标识符。它也不是逻辑 ID,尽管它被用作逻辑 ID 的一部分。我也没有看到以编程方式直接从构造中检索此 ID 的方法。你当然可以在某个地方定义ID,然后再使用它,但这仍然不能解决它与逻辑ID不完全匹配的问题。在这种情况下,
SecurityGroup
作为构造 ID 和 TestConstructSecurityGroup95EF3F0F
作为合成模板中的逻辑 ID 是不同的。
有没有直接获取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
是一个令牌。
我正在尝试为 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。
- 唯一 ID 提供了非常接近的东西,但它与 CloudFormation 堆栈中使用的标识符不同。例如,
securityGroup.uniqueId
returnsTestStackTestConstructSecurityGroup10D493A7
而 CloudFormation 模板显示TestConstructSecurityGroup95EF3F0F
。您可以注意到不同之处在于uniqueId
将 Construct ID 前置到逻辑标识符,并且附加的散列在每个中都不同。 - 构造 ID 只是您在实例化构造时提供的标识符。它也不是逻辑 ID,尽管它被用作逻辑 ID 的一部分。我也没有看到以编程方式直接从构造中检索此 ID 的方法。你当然可以在某个地方定义ID,然后再使用它,但这仍然不能解决它与逻辑ID不完全匹配的问题。在这种情况下,
SecurityGroup
作为构造 ID 和TestConstructSecurityGroup95EF3F0F
作为合成模板中的逻辑 ID 是不同的。
有没有直接获取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")
这可能会更容易,因为您可以设置一次并使用 hard-coded 个字符串,而不是为每个测试查找值。
根据我的测试,似乎stack.getLogicalId
总是return原来的,CDK分配的logicalId,调用overrideLogicalId
不会改变,所以不会始终匹配合成输出。
这对我有用,即使设置了 logicalId 覆盖:
stack.resolve((construct.node.defaultChild as cdk.CfnElement).logicalId)
stack.resolve
是必需的,因为 .logicalId
是一个令牌。