Search code examples
pythonibm-cloudcompose-dbscyllacassandra-python-driver

How to do port translation when using an address translation map with cassandra?


I'm trying to connect to a scylladb cluster on compose using the Address Translation Map.

I can only get the code working if I hard code the port when instantiating the Cluster instance:

from cassandra.cluster import Cluster
from cassandra.policies import AddressTranslator
from cassandra.auth import PlainTextAuthProvider

################################################################################
# our variables

address_map = {
    "10.0.24.69:9042": "sl-eu-lon-2-portal.3.dblayer.com:15227",
    "10.0.24.71:9042": "sl-eu-lon-2-portal.2.dblayer.com:15229",
    "10.0.24.70:9042": "sl-eu-lon-2-portal.1.dblayer.com:15228"
}

username = 'scylla'
password = 'changeme'

port = 15227

################################################################################

Next a class for translating the addresses:

class ComposeAddressTranslator(AddressTranslator):

    def set_map(self, address_map):
        # strip ports from both source and destination as the cassandra python
        # client doesn't appear to support ports translation
        self.address_map = {key.split(':')[0]: value.split(':')[0] for (key, value) in address_map.items()}

    def contact_points(self):
        return [value.split(':')[0] for (key, value) in address_map.items()]

    def translate(self, addr):

        # print some debug output
        print('in translate(self, addr) method', type(addr), addr)

        trans_addr = self.address_map[addr]
        return trans_addr

Now let's connect:

compose_translator = ComposeAddressTranslator()
compose_translator.set_map(address_map)

auth_provider = PlainTextAuthProvider(
                            username=username, 
                            password=password
                            )

# if the port parameter value is removed from below, we are unable 
# to establish a connection

cluster = Cluster(
            contact_points = compose_translator.contact_points(),
            address_translator = compose_translator,
            auth_provider = auth_provider,
            cql_version = '3.2.1',
            protocol_version = 2,
            port = port
            )

session = cluster.connect()
session.execute("USE my_keyspace;")
session.shutdown()

It appears that the cassandra python library does not support port translation with the translate method? You can see below in my debug output that the addr passed into the translate method is a string ip address value without the port:

in translate(self, addr) method <class 'str'> 10.0.24.69
in translate(self, addr) method <class 'str'> 10.0.24.71

My Environment:

$ pip freeze | grep cassandra
cassandra-driver==3.10

$ pip freeze | grep cassandra
cassandra-driver==3.10

Solution

  • Other Cassandra drivers such as the node driver support port translation. The nodejs translator documentation:

    MyAddressTranslator.prototype.translate = function (address, port, callback) {
       // Your custom translation logic.
    }; 
    

    Above you can see that the translator receives both the ip address and the port.

    However, I don't believe the current Cassandra python driver supports port address translation:

    translate(addr)
    

    Accepts the node ip address, and returns a translated address to be used connecting to this node.

    Here you can see that the translator only receives the ip address.