Skip to content

Add pgx Cloud SQL Proxy in-process example #433

@StevenACoffman

Description

@StevenACoffman

The authors of the lib/pq library are encouraging new projects to use pgx instead:

This package is effectively in maintenance mode and is not actively developed. Small patches and features are only rarely reviewed and merged. We recommend using pgx which is actively maintained.

I am connecting to cloudsql from GKE, but I would prefer not to run a sidecar. However, I am using pgx, rather than pg. I have modified the hook_test.go file to use pgx as follows:

package main

import (
	"context"
	"fmt"
	"log"
	"net"
	"os"
	"regexp"
	"time"

	"github.com/GoogleCloudPlatform/cloudsql-proxy/proxy/proxy"
	"github.com/jackc/pgx/v4"
)

var (
	host = os.Getenv("DBHOST") // DBHOST for GCP cloudsql is in format project:region:instance
	name = os.Getenv("DBNAME")
	user = os.Getenv("DBUSER")
	pass = os.Getenv("DBPASS")
)

// parses an addr like "[project:region:instance]:port"
var instanceRegexp = regexp.MustCompile(`^\[(.+)\]:[0-9]+$`)

// Example shows how to use cloudsqlpostgres dialer
func main() {

	// In-process Proxy
	// Note that sslmode=disable is required it does not mean that the connection
	// is unencrypted. All connections via the proxy are completely encrypted.
	dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s sslmode=disable", host, user, pass, name)

	config, configErr := pgx.ParseConfig(dsn)
	if configErr != nil {
		log.Fatal(configErr)
	}

	config.DialFunc = func(ctx context.Context, network string, addr string) (net.Conn, error) {
		matches := instanceRegexp.FindStringSubmatch(addr)
		if len(matches) != 2 {
			return nil, fmt.Errorf("failed to parse addr: %q. It should conform to the regular expression %q", addr, instanceRegexp)
		}
		instance := matches[1]
		return proxy.Dial(instance)
	}

	config.LookupFunc = func(ctx context.Context, host string) ([]string, error) {
		return []string{host}, nil
	}

	conn, connErr := pgx.ConnectConfig(context.Background(), config)
	if connErr != nil {
		log.Fatal(connErr)
	}

	defer conn.Close(context.Background())

	var now time.Time
	err := conn.QueryRow(context.Background(), "SELECT NOW()").Scan(&now)
	if err != nil {
		fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
		os.Exit(1)
	}
	fmt.Println(now)
}

I think an example like this might be helpful to include in this project. If there is a better mechanism (perhaps using the pgx/stdlib ?), I would be very interested to know that.

Metadata

Metadata

Assignees

No one assigned

    Labels

    priority: p3Desirable enhancement or fix. May not be included in next release.type: feature request‘Nice-to-have’ improvement, new feature or different behavior or design.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions