2
votes

Good day everyone, I am having trouble in connecting my golang application to a cloud sql postgres instance. I have just followed through their tutorial in Google Cloud Platform and sample code but it seems to be not working. I have just two files the app.yaml and main.go just to test the connection:

app.yaml

runtime: go api_version: go1 env: standard

env_variables:   CLOUDSQL_CONNECTION_NAME: bxustl2019proj:asia-east1:sqlstlbxu   CLOUDSQL_USER: ustldbbxu   CLOUDSQL_PASSWORD: bxuuserstldb   CLOUDSQL_DB: stlbxudbs

beta_settings:
      cloud_sql_instances: bxustl2019proj:asia-east1:sqlstlbxu

handlers:

- url: /(.*\.(gif|png|jpg))$   static_files: static/\1   upload: static/.*\.(gif|png|jpg)

- url: /.*   script: _go_app

main.go

package dptest

import (
    _"bytes"
    "database/sql"
    "fmt"
    "log"
    "net/http"
    "os"

     _ "github.com/lib/pq"
)

var db *sql.DB

func init() {
    db = DB()

    http.HandleFunc("/", indexHandler)
}

// DB gets a connection to the database.
// This can panic for malformed database connection strings, invalid credentials, or non-existance database instance.
func DB() *sql.DB {
    /*
    var (
        connectionName = mustGetenv("CLOUDSQL_CONNECTION_NAME")
        user           = mustGetenv("CLOUDSQL_USER")
        dbname           = mustGetenv("CLOUDSQL_DB")
        password       = os.Getenv("CLOUDSQL_PASSWORD") // NOTE: password may be empty
        socket         = os.Getenv("CLOUDSQL_SOCKET_PREFIX")
    )

    //cloudsql is used on App Engine.
    if socket == "" {
        socket = "/cloudsql"
    }
    */
    // PostgreSQL Connection, uncomment to use.
    // connection string format: user=USER password=PASSWORD host=/cloudsql/PROJECT_ID:REGION_ID:INSTANCE_ID/[ dbname=DB_NAME]
    //dbURI := fmt.Sprintf("user=%s password=%s host=/cloudsql/%s database=%s", user, password, connectionName, dbname)
    dbURI := fmt.Sprintf("user=ustldbbxu password=bxuuserstldb host=/cloudsql/bxustl2019proj:asia-east1:sqlstlbxu/stlbxudbs")

    conn, err := sql.Open("postgres", dbURI)
    log.Printf("CONNECTION: %v", conn)
    if err != nil {
        panic(fmt.Sprintf("DB: %v", err))
    }

    rows, err := conn.Query("SELECT * FROM GAMES")
    log.Printf("ROW: %v", rows)
    if err != nil {
        log.Printf("Could not query db: %v", err)
    }
    defer rows.Close()

    return conn
}

func indexHandler(w http.ResponseWriter, r *http.Request) {
    if r.URL.Path != "/" {
        http.NotFound(w, r)
        return
    }

    w.Header().Set("Content-Type", "text/plain")

    log.Printf("CONNECTION: %v", db)
    rows, err := db.Query("SELECT * FROM GAMES")
    log.Printf("ROW: %v", rows)
    if err != nil {
        log.Printf("Could not query db: %v", err)
        http.Error(w, "Internal Error", 500)
        return
    }
    defer rows.Close()
}

func mustGetenv(k string) string {
    v := os.Getenv(k)
    if v == "" {
        log.Panicf("%s environment variable not set.", k)
    }
    return v
}

I tried using go run . and goapp serve. I have tried adding appengine imports also but none seems to be working and it keeps on giving me the error:

Could not query db: dial unix /cloudsql/bxustl2019proj:asia-east1:sqlstlbxu/stlbxudbs/.s.PGSQL.5432: connect: no such file or directory

Cloud SQL Admin is also enabled. I just commented out the env for easier run the error seems to be the same regardless of hardcoding the query path or importing from yaml.

I am hoping someone could help me on this.Thank you.

2
thank you for the response, the error is really related..i have tried to follow through the documentation with the standard environment but still no avail..been stuck in this error for days now.. - Elijah Garcia

2 Answers

0
votes

It looks like you are connecting with App Engine (but you don't specify Standard or Flexible environments).

If you are on Standard, the unix socket is automatically available at /cloudsql/<INSTANCE_CONNECTION_NAME>.

If you are on Flexible, you need to specify the instance you want to connect to in the app.yaml, which will need create the unix socket at /cloudsql/<INSTANCE_CONNECTION_NAME>.

These unix sockets are only provided in the runtimes themselves. If you are running locally and want to connect, you will need to use the Cloud SQL proxy to create the unix socket at /cloudsql/<INSTANCE_CONNECTION_NAME> (or update your connection string to use Public IP and authenticate a different way).

0
votes

Anyone that is using this setup. I've got a similar layout.

  • GCR using Docker.
  • Golang version 1.15
  • ORM sqlboiler
  • golang dbapi
  • CloudSQL using postgresql with a public IP that you can only reach using the cloudsql proxy, but the connection between GCR -> CloudSQL was being rejected with models: unable to insert into user: dial tcp cloudsql-ip:5432: connect: connection timed out

First step

When you deploy the instance

gcloud run deploy foo --add-cloudsql-instances the-literal-instance-connection-name --update-env-vars INSTANCE_CONNECTION_NAME="the-literal-instance-connection-name" --image your-image-name --region $REGION --project your-project-id --service-account=the-service-account-you-run-your-things --platform managed --no-allow-unauthenticated

The service account that is running that container has the IAM role Cloud SQL Client

Toml format for sqlboiler

  • host = "/cloudsql/the-literal-instance-connection-name/"

Golang lib/pq + golang db API connection using named unix sock

  • host=/cloudsql/the-literal-instance-connection-name/

What is the-literal-instance-connection-name ?

Go to your CloudSQL instance and see the column Instance connection name and use that as a value.

Sources

The python example in the google cloud documentation

query_string = dict({"unix_sock": "/cloudsql/{}/.s.PGSQL.5432".format(connection_name)})

if you use a similar format in Golang, it won't work, after several trials and errors, I got the proper version working.

For example, adding .s.PGSQL.5432 in both connections ended up with an error like this

 unable to insert into user: dial unix /cloudsql/the-literal-instance-connection-name/.s.PGSQL.5432/.s.PGSQL.5432: connect: not a directory