我正在尝试为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
访问的规则,则需要{{3 }},该安全组是在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 确实为您提供了Logical ID。
securityGroup.uniqueId
返回TestStackTestConstructSecurityGroup10D493A7
,而CloudFormation模板显示TestConstructSecurityGroup95EF3F0F
。您可以注意到不同之处在于uniqueId
将Construct ID附加到逻辑标识符上,并且每个附加的哈希值也不同。SecurityGroup
作为构造ID与TestConstructSecurityGroup95EF3F0F
作为逻辑ID有所不同。是否有一种直接的方法来获取CDK资源的逻辑ID?
答案 0 :(得分:5)
在撰写了整篇文章并仔细研究了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);
答案 1 :(得分:2)
除了jaredready的出色答案外,您还可以使用resource.node.default_child.overrideLogicalId("AnyStringHere")
这可能会更容易,因为您只需设置一次并使用硬编码的字符串,而不是为每个测试查找值。
答案 2 :(得分:0)
从我的测试来看,似乎 stack.getLogicalId
将始终返回原始的、CDK 分配的 logicalId,如果您调用 overrideLogicalId
,它不会改变,因此它不会总是与合成输出匹配。
这对我有用,即使设置了 logicalId 覆盖:
stack.resolve((construct.node.defaultChild as cdk.CfnElement).logicalId)
stack.resolve
是必需的,因为 .logicalId
是一个令牌。