Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(ec2): Python class implementing aws_ec2.IConnectable fails when using connections.allow_ methods #4726

Open
1 task
cpitchford opened this issue Dec 13, 2024 · 2 comments
Labels
bug This issue is a bug. p2

Comments

@cpitchford
Copy link

Describe the bug

I have found that using an object created from Construct sub-class that implements ec2.IConnectable (by having an ec2.Connections property connections) doesn't work when used with other connections.

The connections property can be use directly but the IConnectable object causes an error.

This does not appear to be the case when re-written in typescript

from aws_cdk import Stack
from aws_cdk import aws_ec2 as ec2
from constructs import Construct

from typing import Any

# an ec2.IConnectable class, wrapping an ec2.Connections object

class MyIConnectable(Construct):
    connections: ec2.Connections
    def __init__(self, scope: Construct, id: str, connections: ec2.Connections):
        super().__init__(scope,id)
        self.connections = connections



class TestCdkConnectionsStack(Stack):

    def __init__(self, scope: Construct, construct_id: str, **kwargs:Any) -> None:
        super().__init__(scope, construct_id, **kwargs)

        # Create security groups

        service_sg = ec2.SecurityGroup.from_security_group_id(
            self, "service_sg",
            security_group_id="sg-123456789012",
            allow_all_outbound=True,
            mutable=True
        )

        clients_sg = ec2.SecurityGroup.from_security_group_id(
            self, "clients_sg",
            security_group_id="sg-111111111111",
            allow_all_outbound=True,
            mutable=True
        )

        # Create connections using the security groups

        service_connections=ec2.Connections(
            default_port=ec2.Port.tcp_range(
                start_port=8000,
                end_port=9000
            ),
            security_groups=[
                service_sg
            ]
        )

        clients_connections=ec2.Connections(
            default_port=ec2.Port.tcp(port=22),
            security_groups=[
                clients_sg
            ]
        )

        # Create IConnectable objects using the connections

        service: ec2.IConnectable = MyIConnectable(self, "service connections", service_connections)
        clients: ec2.IConnectable = MyIConnectable(self, "clients connections", clients_connections)

        # Try to connect to the IConnectable together. Error occurs

        service.connections.allow_default_port_from(
            other=clients,
            description="test"
        )

In Typescript:

import * as cdk from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2'
import { Construct } from 'constructs';



//an ec2.IConnectable class, wrapping an ec2.Connections object

class MyIConnectable extends Construct implements ec2.IConnectable {
  connections: cdk.aws_ec2.Connections;
  constructor(scope: Construct, id: string, connections: ec2.Connections) {
    super(scope, id)
    this.connections=connections
  }
}

export class TestCdkConnectionsStack extends cdk.Stack {

  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // Create security groups

    let service_sg = ec2.SecurityGroup.fromSecurityGroupId(
      this, "service_sg", "sg-111111111111", {
        allowAllOutbound: true,
        mutable: true
      }
    )

    let clients_sg = ec2.SecurityGroup.fromSecurityGroupId(
      this, "client_sg", "sg-222222222222", {
        allowAllOutbound: true,
        mutable: true
      }
    )

    // Create connections using the security groups

    let service_connections=new ec2.Connections({
      defaultPort:ec2.Port.tcpRange(
        22,
        65535
      ),
      securityGroups:[
        service_sg
      ]
    })

    let clients_connections=new ec2.Connections({
        defaultPort:ec2.Port.tcp(3389),
        securityGroups:[
          clients_sg
        ]
      })

    // Create IConnectable objects using the connections

    let service = new MyIConnectable(this, "service connection", service_connections)
    let clients = new MyIConnectable(this, "clients connection", clients_connections)

    // Try to connect to the IConnectable together. Works as expected

    service.connections.allowDefaultPortFrom(
      clients,
      "Test"
    )

  }
}

Regression Issue

  • Select this option if this issue appears to be a regression.

Last Known Working CDK Version

No response

Expected Behavior

I expect the python and typescript versions to behave in the same way. I expect to be able to pass my ec2.IConnectable class into ec2.Connections.allow_from(other=my_class_object)

Current Behavior

In python I see an error returned when I try to use my ec2.IConnectable class object:

cdk synth
jsii.errors.JavaScriptError: 
  @jsii/kernel.RuntimeError: TypeError: Cannot read properties of undefined (reading '_securityGroupRules')
      at Kernel._Kernel_ensureSync (/tmp/tmp1mctuqbv/lib/program.js:9510:23)
      at Kernel.invoke (/tmp/tmp1mctuqbv/lib/program.js:8874:102)
      at KernelHost.processRequest (/tmp/tmp1mctuqbv/lib/program.js:10715:36)
      at KernelHost.run (/tmp/tmp1mctuqbv/lib/program.js:10675:22)
      at Immediate._onImmediate (/tmp/tmp1mctuqbv/lib/program.js:10676:46)
      at process.processImmediate (node:internal/timers:491:21)

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/cdk/test_cdk_connections/app.py", line 10, in <module>
    TestCdkConnectionsStack(app, "TestCdkConnectionsStack",
  File "/cdk/test_cdk_connections/.venv/lib/python3.12/site-packages/jsii/_runtime.py", line 118, in __call__
    inst = super(JSIIMeta, cast(JSIIMeta, cls)).__call__(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/cdk/test_cdk_connections/test_cdk_connections/test_cdk_connections_stack.py", line 64, in __init__
    service.connections.allow_default_port_from(
  File "/cdk/test_cdk_connections/.venv/lib/python3.12/site-packages/aws_cdk/aws_ec2/__init__.py", line 93016, in allow_default_port_from
    return typing.cast(None, jsii.invoke(self, "allowDefaultPortFrom", [other, description]))
                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/cdk/test_cdk_connections/.venv/lib/python3.12/site-packages/jsii/_kernel/__init__.py", line 149, in wrapped
    return _recursize_dereference(kernel, fn(kernel, *args, **kwargs))
                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/cdk/test_cdk_connections/.venv/lib/python3.12/site-packages/jsii/_kernel/__init__.py", line 399, in invoke
    response = self.provider.invoke(
               ^^^^^^^^^^^^^^^^^^^^^
  File "/cdk/test_cdk_connections/.venv/lib/python3.12/site-packages/jsii/_kernel/providers/process.py", line 380, in invoke
    return self._process.send(request, InvokeResponse)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/cdk/test_cdk_connections/.venv/lib/python3.12/site-packages/jsii/_kernel/providers/process.py", line 342, in send
    raise RuntimeError(resp.error) from JavaScriptError(resp.stack)
RuntimeError: TypeError: Cannot read properties of undefined (reading '_securityGroupRules')

Reproduction Steps

Checkout https://github.com/cpitchford/cdk-iconnectable-python

bash test_python.py

see error line here: python/iconnectable-test/iconnectable_test/iconnectable_test_stack.py

Possible Solution

No response

Additional Information/Context

No response

CDK CLI Version

2.173.0 (build b5c2189)

Framework Version

No response

Node.js Version

v22.12.0

OS

Linux (Ubuntu 24.04) and MacOS (15.2)

Language

Python

Language Version

python (3.12.3)

Other information

No response

@cpitchford cpitchford added bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. labels Dec 13, 2024
@khushail khushail added needs-reproduction This issue needs reproduction. p2 and removed needs-triage This issue or PR still needs to be triaged. labels Dec 13, 2024
@khushail khushail self-assigned this Dec 13, 2024
@khushail khushail added investigating This issue is being investigated and/or work is in progress to resolve the issue. and removed needs-reproduction This issue needs reproduction. labels Dec 13, 2024
@khushail
Copy link
Contributor

Hi @cpitchford , thanks for reaching out. I am able to repro the error in Python, sharing the snippet -

Screenshot 2024-12-13 at 3 57 26 PM

However Typescript code succeeds with synthesis.

I would also request you to shed some light on your usecase which might be helpful in understanding the issue.

Since this seems to be a JSII Runtime error, I am transferring this issue to JSII Repo for further investigation and resolution.

@khushail khushail transferred this issue from aws/aws-cdk Dec 14, 2024
@khushail khushail removed their assignment Dec 14, 2024
@khushail khushail removed the investigating This issue is being investigated and/or work is in progress to resolve the issue. label Dec 14, 2024
@cpitchford
Copy link
Author

Hey @khushail

I am working on a number of L2 constructs for teams using Python and teams using TypeScript. I would like to keep the code as similar as possible.

I want my constructs to implement IConnectable so they can be passed into connection methods in the same way as other familiar contracts:

my_rds_cluster.connections.allow_default_port_from(my_construct_object)

versus:

my_rds_cluster.connections.allow_default_port_from(my_construct_object.connections)

In particular, the type checker (pylance) doesn't see a problem with the first, but the code fails and the second works but it isn't clear why it was necessary (until the stack is synthesised)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug This issue is a bug. p2
Projects
None yet
Development

No branches or pull requests

2 participants