question

the_a_man avatar image
the_a_man asked reralnsleo commented

How do I connect to Astra with the gocql driver?

I've tried with this sample code but it's not working:

func sessionForRemote() (*gocql.Session, error) {
    log.Println("Connecting to the database")

    config := gocql.NewCluster("14043648-xxxx-469a-a1e0-8331f2739475-us-east1.db.astra.datastax.com") //from bundle's config.json

    config.Authenticator = gocql.PasswordAuthenticator{
        Username: "frameapp",
        Password: "db_password_here",
    }

    certPath, _ := filepath.Abs("./secure-connect-frame-db/cert") //extracted bundle
    caPath, _ := filepath.Abs("./secure-connect-frame-db/ca.crt")
    keyPath, _ := filepath.Abs("./secure-connect-frame-db/key")

    config.SslOpts = &gocql.SslOptions{
        CertPath: certPath,
        CaPath: caPath,
        KeyPath: keyPath,
    }

    config.ConnectTimeout = time.Second * 6
    config.ProtoVersion = 4 //Have tried all (0, 1, 2, 3, 4), to no avail!
    //config.CQLVersion = "3.0.0"
    config.Port = 30431 //From the bundle's config.json (it isn't 9042, rather 30xxx)

    config.Keyspace = "frame_ks"

    fmt.Println("Creating session")
    session, err := config.CreateSession()
    fmt.Println("That's all!")

    if err != nil {
        return nil, err
    }

    return session, nil
}

Output:

Connecting to the database
Creating session
2020/05/01 02:53:29 gocql: unable to dial control conn 34.74.218.22: gocql: unsupported protocol response version: 72
2020/05/01 02:53:34 gocql: unable to dial control conn 35.196.48.167: gocql: unsupported protocol response version: 72
2020/05/01 02:53:39 gocql: unable to dial control conn 35.196.198.226: gocql: unsupported protocol response version: 72

That's all

So it did discover the 3 nodes and passed auth too. It's just this protocol 72 that's annoying!!!!

On the remote, cqlsh'ing

$ show version
[cqlsh 6.8.0 | DSE 6.8.0 | CQL spec 3.4.5 | DSE protocol v2]

I hope you guys come up with some workaround soon... Our whole system is in Go and we can't afford to migrate to python just to be able to connect to Astra! And Astra was such a blessing for a small team of ours that we really don't want to setup DSE on GCP ourselves!

astragcpgocqlgolanggo
10 |1000

Up to 8 attachments (including images) can be used with a maximum of 1.0 MiB each and 10.0 MiB total.

1 Answer

Erick Ramirez avatar image
Erick Ramirez answered reralnsleo commented

@the_a_man Thanks for working through this with me. Here is the bare-bones minimum sample code that will let you connect to your DataStax Astra database:

package main

import (
    "fmt"
    "crypto/tls"
    "crypto/x509"
    "io/ioutil"
    "path/filepath"
    "github.com/gocql/gocql"
)

func main() {
    var _cqlshrc_host = "31fecf38-2491-4d43-b6ce-22562679f1b8-us-east1.db.astra.datastax.com"
    var _cqlshrc_port = "34567"
    var _username = "erickramirez"
    var _password = "SomeComp7exP4ssword"
    var _query = "SELECT rank, city, country FROM community.cities_by_rank WHERE rank IN ( 1, 2, 3, 4, 5 )"

    cluster := gocql.NewCluster(_cqlshrc_host)
    cluster.Authenticator = gocql.PasswordAuthenticator{
        Username:       _username,
        Password:       _password,
    }
    cluster.Hosts = []string{_cqlshrc_host + ":" + _cqlshrc_port }

    certPath, _ := filepath.Abs("/home/erick/astra-bundle/cert")
    keyPath, _ := filepath.Abs("/home/erick/astra-bundle/key")
    caPath, _ := filepath.Abs("/home/erick/astra-bundle/ca.crt")
    cert, _ := tls.LoadX509KeyPair(certPath, keyPath)
    caCert, _  := ioutil.ReadFile(caPath)
    caCertPool := x509.NewCertPool()
    caCertPool.AppendCertsFromPEM(caCert)
    tlsConfig := &tls.Config{
        Certificates: []tls.Certificate{cert},
        RootCAs:      caCertPool,
    }
    cluster.SslOpts = &gocql.SslOptions{
        Config: tlsConfig,
        EnableHostVerification: false,
    }

    session, _ := cluster.CreateSession()
    var _rank int
    var _city string
    var _country string

    fmt.Println("According to independent.co.uk, the top 5 most liveable cities in 2019 were:")
    iter := session.Query(_query).Iter()
    for iter.Scan(&_rank, &_city, &_country) {
        fmt.Printf("\tRank %d: %s, %s\n", _rank, _city, _country)
    }
}

Sample output

According to independent.co.uk, the top 5 most liveable cities in 2019 were:
    Rank 1: Vienna, Austria
    Rank 2: Melbourne, Australia
    Rank 3: Sydney, Australia
    Rank 4: Osaka, Japan
    Rank 5: Calgary, Canada

Things to note

I've deliberately not coded any error-handling as I wanted to provide a minimum viable sample. I've also intentionally not placed any in-line comments but tried to be as descriptive as possible with the variable names for brevity.

For developers wanting to re-use the code above, you will need to download the secure-connect zipped bundle for your Astra database.

Unzip your copy of secure-connect-your_astra_db.zip which will contain the following files:

ca.crt
cert
cert.pfx
config.json
cqlshrc
identity.jks
key
trustStore.jks

You will need these files to configure the SSL/TLS options. The cqlshrc file contains the connection details for _cqlshrc_host and _cqlshrc_port in the code above. For example:

[connection]
hostname = 31fecf38-2491-4d43-b6ce-22562679f1b8-us-east1.db.astra.datastax.com
port = 34567
ssl = true

Sample data

Here is the test schema I used:

CREATE KEYSPACE community WITH replication = {'class': 'NetworkTopologyStrategy', 'caas-dc': '1'};
CREATE TABLE community.cities_by_rank (
    rank int PRIMARY KEY,
    city text,
    country text
)

The table contents:

 rank | city       | country
------+------------+-----------
    5 |    Calgary |    Canada
   10 |   Adelaide | Australia
    1 |     Vienna |   Austria
    8 |      Tokyo |     Japan
    2 |  Melbourne | Australia
    4 |      Osaka |     Japan
    7 |    Toronto |    Canada
    6 |  Vancouver |    Canada
    9 | Copenhagen |   Denmark
    3 |     Sydney | Australia

Source: "This is the world's most liveable city", independent.co.uk, published 4 September 2019, retrieved 2 May 2020.

Github

I've published the full code and sample data for easier download -- https://github.com/flightc/astra_gocql_connect.

Credits

Huge thanks to Doug Wettlaufer at DataStax Cloud Engineering for his help with the solution. Cheers!

11 comments Share
10 |1000

Up to 8 attachments (including images) can be used with a maximum of 1.0 MiB each and 10.0 MiB total.

the_a_man avatar image the_a_man commented ·

Thank you so much! It worked!!!!!!!!!

I was using the port given in the config.json file, rather than the one given in cqlshrc file in the bundle. I sort of avoided the cqlshrc file all this time, thinking it was some "binary-gibberish"!

For anyone reading this:

Use the port from the cqlshrc file.

1 Like 1 ·
Erick Ramirez avatar image Erick Ramirez ♦♦ the_a_man commented ·

I did mention that in the "Things to note" section of my answer. :)

1 Like 1 ·
the_a_man avatar image the_a_man Erick Ramirez ♦♦ commented ·

Yeah, that's where I saw it. Thanks mate, you just saved us days of debugging.

2 Likes 2 ·
Show more comments
the_a_man avatar image the_a_man commented ·

Sure, let me give it a try.

0 Likes 0 ·
Erick Ramirez avatar image Erick Ramirez ♦♦ the_a_man commented ·

Awesome! You'll see that I've stripped out all the other configs like protocol and CQL versions since they're not required. gocql discovers all that info once it has successfully connected to a node.

It's late Saturday here but I'll be around for a few more hours. Let me know how you go. Cheers!

0 Likes 0 ·
the_a_man avatar image the_a_man Erick Ramirez ♦♦ commented ·

Yeah, that's what I noticed. Looks like the ":port" in hosts is all we were missing all this time! No idea why I didn't think about that all this time!

Unparking Astra. Would let you know asap.


0 Likes 0 ·
the_a_man avatar image the_a_man commented ·

I don't think one can create a keyspace on Astra, can one?

Or is the keyspace code just for an explanation?

0 Likes 0 ·
Erick Ramirez avatar image Erick Ramirez ♦♦ the_a_man commented ·

It's just to show you how I created the sample data. You can use your own keyspace and table.

Not to be taken literally. :) It was just purely for demonstration purposes. Cheers!

0 Likes 0 ·
reralnsleo avatar image reralnsleo Erick Ramirez ♦♦ commented ·

@Erick Ramirez I know this has been ages, but I have followed every line of code here and I keep getting this error below:

gocql: error: failed to connect to 18.236.250.37:29042 due to error: x509: cannot validate certificate for 18.236.250.37 because it doesn't contain any IP SANs

Please let me know how to overcome this! Thanks so much!

0 Likes 0 ·