Open timothy-cloudopsguy opened 1 month ago
NOTE: I just tried using .from_network_load_balancer_attributes()
and it synthesized just fine. I'll update this if it deploys successfully.
@timothy-cloudopsguy Good morning. Thanks for reporting the issue. I was able to reproduce the issue when executing cdk synth
for the first time using below TypeScript CDK code:
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as elbv2 from 'aws-cdk-lib/aws-elasticloadbalancingv2';
import { debug } from 'console';
export class Issue30806Stack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// Manually created IPV4 NLB in AWS console.
const nlbArn = 'arn:aws:elasticloadbalancing:us-east-2:REDACTED:loadbalancer/net/testnlb/REDACTED';
const nlb = elbv2.NetworkLoadBalancer.fromLookup(this, 'testnlb', { loadBalancerArn: nlbArn});
debug(`IP_ADDRESS_TYPE 1: ${nlb.ipAddressType}`);
}
}
Running cdk synth
for the first time produced below output:
IP_ADDRESS_TYPE 1: dualstack
IP_ADDRESS_TYPE 1: ipv4
IP_ADDRESS_TYPE 1: ipv4
Resources:
CDKMetadata:
Type: AWS::CDK::Metadata
Properties:
Analytics: v2:deflate64:H4sIAAAAAAAA/zPSMzSx0DNQTCwv1k1OydbNyUzSqw4uSUzO1glKLc4vLUpO1XFOy4Oxa3Xy8lNS9bKK9cuMDPQMDfUMFbOKMzN1i0rzSjJzU/WCIDQA2v7akFYAAAA=
Metadata:
aws:cdk:path: Issue30806Stack/CDKMetadata/Default
Parameters:
BootstrapVersion:
Type: AWS::SSM::Parameter::Value<String>
Default: /cdk-bootstrap/hnb659fds/version
Description: Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]
Rules:
CheckBootstrapVersion:
Assertions:
- Assert:
Fn::Not:
- Fn::Contains:
- - "1"
- "2"
- "3"
- "4"
- "5"
- Ref: BootstrapVersion
AssertDescription: CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI.
Then running cdk context
produced below output (REDACTED):
Context found in cdk.json:
┌────┬───────────────────────────────────────────────────────────────────────────┬───────────────────────────────────────────────────────────────────────────┐
│ # │ Key │ Value │
├────┼───────────────────────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────┤
│ 1 │ @aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver │ true │
├────┼───────────────────────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────┤
│ 50 │ load-balancer:account=REDACTED:loadBalancerArn=arn$:aws$:elasticloadb │ { "loadBalancerArn": "arn:aws:elasticloadbalancing:us-east-2:REDACTED │
│ │ alancing$:us-east-2$:REDACTED$:loadbalancer/net/testnlb/REDACTED │ :loadbalancer/net/testnlb/REDACTED", "loadBalancerCanonicalHosted │
│ │ 79b:loadBalancerType=network:region=us-east-2 │ ZoneId": "REDACTED", "loadBalancerDnsName": "testnlb-REDACTED │
│ │ │ b.elb.us-east-2.amazonaws.com", "vpcId": "vpc-REDACTED", "securi │
│ │ │ tyGroupIds": [ "sg-REDACTED" ], "ipAddressType": "ipv4" } │
└────┴───────────────────────────────────────────────────────────────────────────┴───────────────────────────────────────────────────────────────────────────┘
Run cdk context --reset KEY_OR_NUMBER to remove a context key. It will be refreshed on the next CDK synthesis run.
Running cdk synth
again produces below output:
IP_ADDRESS_TYPE 1: ipv4
Resources:
CDKMetadata:
Type: AWS::CDK::Metadata
Properties:
Analytics: v2:deflate64:H4sIAAAAAAAA/zPSMzSx0DNQTCwv1k1OydbNyUzSqw4uSUzO1glKLc4vLUpO1XFOy4Oxa3Xy8lNS9bKK9cuMDPQMDfUMFbOKMzN1i0rzSjJzU/WCIDQA2v7akFYAAAA=
Metadata:
aws:cdk:path: Issue30806Stack/CDKMetadata/Default
Parameters:
BootstrapVersion:
Type: AWS::SSM::Parameter::Value<String>
Default: /cdk-bootstrap/hnb659fds/version
Description: Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]
Rules:
CheckBootstrapVersion:
Assertions:
- Assert:
Fn::Not:
- Fn::Contains:
- - "1"
- "2"
- "3"
- "4"
- "5"
- Ref: BootstrapVersion
AssertDescription: CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI.
So cdk synth
would cache CF resources during synthesis time, refer below links for more details:
So if after running cdk synth
for the first time, if I add the below code and run cdk synth
again, it synthesizes properly.
const targetGroupArn = 'arn:aws:elasticloadbalancing:us-east-2:REDACTED:targetgroup/testtargetgroupfornlb/REDACTED';
const listener = nlb.addListener('listener', {
port: nlbListernerPort,
protocol: elbv2.Protocol.UDP,
defaultTargetGroups: [elbv2.NetworkTargetGroup.fromTargetGroupAttributes(this, 'tg', {targetGroupArn: targetGroupArn})]
});
The reason why NetworkLoadBalancer.fromNetworkLoadBalancerAttributes()
could be working is that it defaults to IPV4
here (this could be incorrect if using DUALSTACK
balancer). The context value for load balancer is somehow not populated when using NetworkLoadBalancer.fromNetworkLoadBalancerAttributes()
.
In CDK, all L2 constructs have the fromXxxx() methods and they could be implemented in two major patterns:
Just returns the interface of the resource with all required attributes we provide in the options. Such as arn
or other attributes. CDK would NOT call AWS SDKs to retrieve additional information. All information has to be provided by user.
Query additional attributes via context provider, such as Vpc.fromLookup(), and cache additional information in the context variables i.e. cdk.context.json
.
elbv2.NetworkLoadBalancer.from_lookup() falls into the 2nd category that returns a new LookedUpNetworkLoadBalancer for you, which is literally a INetworkLoadBalancer
. If you look at its implementation, it determines the IpAddressType
from here:
And additional props
are determined here:
The query logic is defined here:
OK. When dealing with context provider, if that value does not exist in local cdk.context.json, CDK would initially insert a placeholder dummy value and replace it after it stores the real value into the cdk.context.json. This is a little bit tricky though. Unfortunately, the dummy value of ipAddressType is currently defined as
This would be confusing because user code would not be able to initially determine if the value is a dummy value or real value. But CDK would eventually replace that value with correct value. This explains why we see this from the sample @ashishdhingra provided above.
IP_ADDRESS_TYPE 1: dualstack
IP_ADDRESS_TYPE 1: ipv4
IP_ADDRESS_TYPE 1: ipv4
Now my question is - given the value would be eventually replaced with correct value. Would this still be an issue for you? Off the top of my head, the only problem is that if you have a check on the type in your CDK code and execute different logic accordingly, that might be an issue but if you simply CfnOutput that, it should not be an issue.
Also, this only happens when your cdk.context.json
does not have that cache. If you execute the 2nd time, it would simply return the cached value from cdk.context.json
I am afraid the only way to work it around is:
if (isHavingDummyValue()) {
// we got dummy values, skip everything for now.
} else {
listener = nlb.addListener(…)
}
Full sample in TypeScript
export class DummyStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
const nlbArn = 'arn:aws:elasticloadbalancing:us-east-1:AWS_ACCOUNT_ID:loadbalancer/net/testnlb/xxxxxxxxxx';
const nlb = elbv2.NetworkLoadBalancer.fromLookup(this, 'testnlb', { loadBalancerArn: nlbArn});
const vpc = ec2.Vpc.fromLookup(this, 'vpc', { isDefault: true });
if (nlb.securityGroups && nlb.securityGroups[0] === 'sg-1234') {
// https://github.com/aws/aws-cdk/blob/8d55d864183803e2e6cfb3991edced7496eaadeb/packages/aws-cdk-lib/aws-elasticloadbalancingv2/lib/shared/base-load-balancer.ts#L154C28-L154C37
debug('got dummy value, skip adding listener');
} else {
nlb.addListener('mylistener', {
port: 80,
defaultTargetGroups: [
new elbv2.NetworkTargetGroup(this, 'TG', { port: 80, vpc }),
]
});
}
}
Describe the bug
When running this block of code:
Example 1
The print statement shows DUAL_STACK and not IPV4
When in reality ... This is not a dual stack NLB.
Expected Behavior
Expected behavior is for the
.from_lookup()
function to correctly determine theip_address_type
instead of assume DUAL_STACK, and then properly attach theadd_listener()
as requested without errors.NOTE: When using
.from_network_load_balancer_attributes()
, it works fine.Current Behavior
Because the returned INetworkLoadBalancer does not actually grab the truthiness of ip_address_type, but assumes it to be DUAL_STACK, the CDK stack FAILS to add the listener with this message:
NOTE: When using
.from_network_load_balancer_attributes()
, it works fine.Reproduction Steps
Create an NLB in another stack or manually, and save the ARN into an SSM Parameter. Read in the parameter in a CDK stack and use from_lookup() to get an INetworkLoadBalancer object and add_listener() to add a UDP listener.
Possible Solution
When pulling in information about the NLB using the ARN, pull in the ip_address_type as well using
describe-load-balancers
?Additional Information/Context
No response
CDK CLI Version
2.142.1 (build ed4e152)
Framework Version
python
Node.js Version
v18.19.0
OS
macOs 14.5 (23F79)
Language
Python
Language Version
Python 3.12.4
Other information