AWS CDK NetworkLoadBalancer - add target group (add_targets) fails with target.attachToNetworkTargetGroup is not a function - aws-cloudformation

Basically I'm trying to get an nlb (network load balancer) to point to a alb (application load balancer) but cdk fails at the .add_targets call with the error jsii.errors.JSIIError: target.attachToNetworkTargetGroup is not a function
Here's a snippet of my cdk:
nlb = elbv2.NetworkLoadBalancer(
stack,
id="nlb",
load_balancer_name="my-nlb",
vpc=vpc,
)
cert = elbv2.ListenerCertificate.from_arn(certificate_arn)
listener_80 = nlb.add_listener("listener", port=80)
alb_target_group = elbv2.ApplicationTargetGroup(
stack,
id="alb_target_group",
target_type=elbv2.TargetType.ALB,
protocol=elbv2.ApplicationProtocol.HTTP,
vpc=vpc,
)
listener_80.add_targets(id="target", port=80, targets=[alb_target_group])
I get the following error and it's due to the call to
listener_80.add_targets(id="target", port=80, targets=[alb_target_group])
cdk diff --app "python3 fargate.py"
cluster sec group <class 'NoneType'>
connections <aws_cdk.aws_ec2.Connections object at 0x10c0c91f0>
jsii.errors.JavaScriptError:
TypeError: target.attachToNetworkTargetGroup is not a function
at NetworkTargetGroup.addTarget (/private/var/folders/v0/6bvb2_m975jd380hx464rtzm0000gq/T/
jsii-kernel-wnPJIQ/node_modules/aws-cdk-lib/
aws-elasticloadbalancingv2/lib/nlb/network-target-group.js:1:1547)```
TypeError: target.attachToNetworkTargetGroup is not a function
I'm using
cdk version 2.20.0 and
python v 3.8.0 and
aws-cli/2.3.4
Any idea why I'm getting the
TypeError: target.attachToNetworkTargetGroup is not a function ?
Thanks!

.add_targets and .add_target_group are different, and in your scenario, you should use .add_target_group.
By the way, in AWS CDK, the constants and classes for ALB and NLB are different.
If your architecture is
Crete a network load balancer
Add a listener for port 80
Create a target group which target type is ALB
Attach the target group to the listener
Your snippet would be:
nlb = elbv2.NetworkLoadBalancer(
stack,
id="nlb",
load_balancer_name="my-nlb",
vpc=vpc,
)
listener_80 = nlb.add_listener("listener", port=80)
alb_target_group = elbv2.NetworkTargetGroup(
stack,
id="alb_target_group",
target_type=elbv2.TargetType.ALB,
protocol=elbv2.Protocol.TCP,
vpc=vpc,
)
listener_80.add_target_group("target", alb_target_group)

Related

409 (request "Conflict") when creating second Endpoint connection in MongoDB Atlas using Terraform

I need to create many MongoDB Atlas endpoint connections using terraform.
I successfully create first, using this code:
#Private endpoint connection
resource "mongodbatlas_private_endpoint" "dbpe" {
project_id = var.prj_id
provider_name = "AWS"
region = var.aws_region
}
#AWS endpoint for secure connect to mongo db
resource "aws_vpc_endpoint" "ec2" {
vpc_id = var.sh_vpc
#service_name = "com.amazonaws.${var.aws_region}.ec2"
service_name = mongodbatlas_private_endpoint.dbpe.endpoint_service_name
vpc_endpoint_type = "Interface"
security_group_ids = [
aws_security_group.lb_sg.id,
]
subnet_ids = [
aws_subnet.subnet1.id,
var.sh_subnet
]
tags = {
"Name" = local.tname
}
#private_dns_enabled = true
}
But when I try to use this code second time in another folder (another tfstate) it failed cause error:
Error: error creating MongoDB Private Endpoints Connection: POST https://cloud.mongodb.com/api/atlas/v1.0/groups/***/privateEndpoint: 409 (request "Conflict") A PrivateLink Endpoint Service already exists for AWS region US_EAST_2.
As I understand, a second "mongodbatlas_private_endpoint" "dbpe" trying to create another one Endpoint service. But, when I creating second Endpoint manually through WebUI, it using the same service like first Endpoint.
How I can tell to second Endpoint to use the existing service?
Or maybe it all wrong?
Please, help!
Thank you!
I found the solution.
Creating the "Endpoint Connection" really creates Endpoint only when you do it at first time. All of next times is creating an only association between Atlas endpoint and new AWS Endpoint.
In terraform I tried to create an Atlas endpoint second time and catch an error (because of limit - 1 endpoint per region). All I need to do - is create "Basic Endpoint" one time (by separate folder with own tfstate) and don't delete it. And for each new AWS endpoint need to create a new link from AWS Endpoint to "Basic". I do it by a terraform resource:
mongodbatlas_private_endpoint_interface_link
Resource "mongodbatlas_private_endpoint" is not need now. A "service_name" parameter in "aws_vpc_endpoint" you can hardcoded from "Basic" Endpoint. Use "output" to see mongodbatlas_private_endpoint.test.private_link_id - this is what you need.

gRPC Node microservice talking to another microservice in istio mesh

I've got several gRPC microservices deployed via Istio in my k8s pod behind a gateway that handles the routing for web clients. Things work great when I need to send an RPC from client (browser) to any of these services.
I'm now at the point where I want to call service A from service B directly. How do I go about doing that?
Code for how both the servers are instantiated:
const server = new grpc.Server();
server.addService(MyService, new MyServiceImpl());
server.bindAsync(`0.0.0.0:${PORT_A}`, grpc.ServerCredentials.createInsecure(), () => {
server.start();
});
A Service Account is being used with GOOGLE_APPLICATION_CREDENTIALS and a secret in my deployment YAML.
To call service A from service B, I was thinking the code in service B would look something like:
const serviceAClient: MyServiceClient = new MyServiceClient(`0.0.0.0:${PORT_A}`, creds);
const req = new SomeRpcRequest()...;
serviceAClient.someRpc(req, (err: grpc.ServiceError, response: SomeRpcResponse) => {
// yay!
});
Is that naive? One thing I'm not sure about is the creds that I need to pass when instantiating the client. I get complaints that I need to pass ChannelCredentials, but every mechanism I've tried to create those creds has not worked.
Another thing I'm realizing is that 0.0.0.0 can't be correct because each service is in its own container paired with a sidecar proxy... so how do I route RPCs properly and attach proper creds?
I'm trying to construct the creds this way:
let callCreds = grpc.CallCredentials.createFromGoogleCredential(myOauthClient);
let channelCreds = grpc.ChannelCredentials.createSsl().compose(callCreds);
const serviceAClient = new MyServiceClient(`0.0.0.0:${PORT_A}`, channcelCreds);
and I'm mysteriously getting the following error stack:
UnhandledPromiseRejectionWarning: TypeError: Channel credentials must be a ChannelCredentials object
at new ChannelImplementation (/bish/proto/activities/node_modules/#grpc/grpc-js/build/src/channel.js:69:19)
at new Client (/bish/proto/activities/node_modules/#grpc/grpc-js/build/src/client.js:58:36)
at new ServiceClientImpl (/bish/proto/activities/node_modules/#grpc/grpc-js/build/src/make-client.js:58:5)
at PresenceService.<anonymous> (/bish/src/servers/presence/dist/presence.js:348:44)
at step (/bish/src/servers/presence/dist/presence.js:33:23)
at Object.next (/bish/src/servers/presence/dist/presence.js:14:53)
at fulfilled (/bish/src/servers/presence/dist/presence.js:5:58)
at processTicksAndRejections (internal/process/task_queues.js:97:5)
Which is odd because channelCreds is a ComposedChannelCredentialsImpl which, in fact, extends ChannelCredentials
Ok, at least the root cause of the "Channel credentials must be a ChannelCredentials object" error is now known. I'm developing node packages side-by-side as symlinks and each of the dependencies has their own copy of grpc-js in it.
https://github.com/npm/npm/issues/7742#issuecomment-257186653

Importing ALBName from StackA to use in StackB

I am creating an ALB in amazon with StackA named StackA and I export the ALB name and value using
Export=Export((Join("", [Ref("AWS::StackName"), "-ALB"]))),
Value = GetAtt(ApplicationElasticLB, "DNSName")
I can see in AWS Console that the value is being export for ALB "internal-alb-test-12345678.us-east-1.elb.amazonaws.com"
So now I want to use this ALB name from StackB while creating ECSService.
I am using it like this
LoadBalancerName=ImportValue('StackA-ALB')
But then the AWS throws an error saying
elb name longer than 32. (Service: AmazonECS; Status Code: 400; Error Code: InvalidParameterException
Am I doing anything wrong here ? please help me understand the cause.
I think that you need to export the ALB:ARN not the ALB:Name

AWS-ECS - Communication between containers - Unknown host error

I have two Docker containers.
TestWeb (Expose: 80)
TestAPI (Expose: 80)
Testweb container calls TestApi container. Host can communicate with TestWeb container from port 8080. Host can communicate with TestApi using 8081.
I can get TestWeb to call TestApi in my dev box (Windows 10) but when I deploy the code to AWS (ECS) I get "unknown host" exception. Both the containers work just fine and I can call them individually. But when I call a method that internally makes a Rest call using HttpClient to a method in Container2, it gives the error:
An error occurred while sending the request. ---> System.Net.Http.CurlException: Couldn't resolve host name.
Code:
using (var client = new HttpClient())
{
try
{
string url = "http://testapi/api/Tenant/?i=" + id;
var response = client.GetAsync(url).Result;
if (response.IsSuccessStatusCode)
{
var responseContent = response.Content;
string responseString = responseContent.ReadAsStringAsync().Result;
return responseString;
}
return response.StatusCode.ToString();
}
catch (HttpRequestException httpRequestException)
{
return httpRequestException.Message;
}
}
The following are the things I have tried:
The two containers (TestWeb, TestAPI) are in the same Task definition in AWS ECS. When I inspect the containers, I get the IP address of each of the containers. I can ping container2 from container1 with their IP address. But I can't ping using container2 name. It gives me "unknown host" error.
It appears ECS doesn't use legit docker-compose under the hood, however, their implementation does support the Compose V2 "links" feature.
Here is a portion of my compose file I just ran on ECS that needed this same functionality AND had the same "could not resolve host" error you were getting. The "links" I added fixed my hostname resolution issue on Elastic Container Service!
version: '3'
services:
appserver:
links:
- database:database
- socks-proxy:socks-proxy
This allowed my appserver to communicate TO the database and socks-proxy hostnames. The format is "SERVICE:ALIAS" and it is fine to keep them both the same as a default practice.
In your example it would be:
version: '3'
services:
testapi:
links:
- testweb:testweb
testweb:
links:
- testapi:testapi
AWS does not use Docker compose but provides a interface to add Task Definitions.
Containers that need to communicate together can be put on the same Task definition. Then we can also specify in the links section the containers that will be called from the current container. Each container can be given its container name on the "Host" section of Task Definition. Once I added the container name to the "Host" field, Container1 (TestWeb) was able to communicate with Container2 (TestAPI).

ex_modify_instance_attribute and create_node has AuthFailure error use apache-libcloud AWS EC2 driver

When I use AWS EC2 driver invoke create_node and ex_modify_instance_attribute API , I got this error:
raise InvalidCredsError(err_list[-1])
libcloud.common.types.InvalidCredsError: 'AuthFailure: AWS was not able to validate the provided access credentials'
But ex_create_subnet/ list_nodes API success , and I'm sure about I have the permission on AWS IAM to create EC2 instance.
By the way , I am using AWC cn-north-1 region.
I find create node with some parameters will got AuthFailure
The Code:
node = self.conn.create_node(name=instance_name,
image=image,
size=size,
ex_keyname=ex_keyname,
ex_iamprofile=ex_iamprofile,
ex_subnet=ex_subnet,
ex_security_group_ids=ex_security_group_ids,
ex_mincount=ex_mincount,
ex_maxcount=ex_mincount,
ex_blockdevicemappings=config['block_devices'],
ex_assign_public_ip=config['eth0']['need_eip']
)
I just delete some parameters and works:
node = self.conn.create_node(name=instance_name,
image=image,
size=size,
ex_keyname=ex_keyname,
# ex_iamprofile=ex_iamprofile,
ex_subnet=ex_subnet,
# ex_security_group_ids=ex_security_group_ids,
ex_mincount=ex_mincount,
ex_maxcount=ex_mincount,
# ex_blockdevicemappings=config['block_devices'],
# ex_assign_public_ip=config['eth0']['need_eip']
)