Skip to content

Commit

Permalink
Initialising commit
Browse files Browse the repository at this point in the history
  • Loading branch information
dmitri-lerko committed Dec 11, 2020
0 parents commit 7f00922
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
cloudsql-proxy-is-up
11 changes: 11 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
FROM golang:1.15 as golang
WORKDIR /go/src/github.com/loveholidays/cloudsql-proxy-is-up/
COPY . .
RUN go mod tidy
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o cloudsql-proxy-is-up .


FROM gcr.io/distroless/base-debian10

COPY --from=golang /go/src/github.com/loveholidays/cloudsql-proxy-is-up/cloudsql-proxy-is-up .
ENTRYPOINT ["/cloudsql-proxy-is-up"]
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# cloudsql-proxy-is-up

Built on top of (https://github.com/monzo/envoy-preflight)[https://github.com/monzo/envoy-preflight].

`cloudsql-proxy-is-up` is a simple wrapper application which makes it easier to run applications which depend on Cloud SQL Proxy as a sidecar container for Cloud SQL access. It ensures that your application doesn't start until Cloud SQL Proxy is ready, and that Cloud SQL Proxy shuts down when the application exits. It is best used as a prefix to your existing Docker entrypoint. It executes any argument passed to it, doing a simple path lookup:
```
cloudsql-proxy-is-up echo "hi"
cloudsql-proxy-is-up /bin/ls -a
```

The `cloudsql-proxy-is-up` wrapper won't do anything special unless you provide at least the `CLOUDSQL_PROXY_API` environment variable. This makes, _e.g._, local development of your app easy.

If you do provide the `CLOUDSQL_PROXY_API` environment variable, `cloudsql-proxy-is-up`
will poll the proxy indefinitely with backoff, waiting for Cloud SQL Proxy to report itself as live. Only then will it execute the command provided as an argument, so that your app can immediately start accessing the Cloud SQL.

All signals are passed to the underlying application. Be warned that `SIGKILL` cannot be passed, so this can leave behind a orphaned process.

When the application exits, as long as it does so with exit code 0, `cloudsql-proxy-is-up` will instruct Cloud SQL Proxy to shut down immediately.

## Environment variables

| Variable | Purpose |
|-----------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `CLOUDSQL_PROXY_API` | This is the path to Cloud SQL Proxy port, in the format `http://127.0.0.1:3306`. If provided, `cloudsql-proxy-is-up` will poll this port until it opens. If provided and local (`127.0.0.1` or `localhost`), then Cloud SQL Proxy will be instructed to shut down if the application exits cleanly. |
| `START_WITHOUT_CLOUDSQL_PROXY_API` | If provided and set to `true`, `cloudsql-proxy-is-up` will not wait for Cloud SQL Proxy to be LIVE before starting the main application. However, it will still instruct Cloud SQL Proxy to exit. |
9 changes: 9 additions & 0 deletions cloudbuild.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
steps:
- name: gcr.io/cloud-builders/docker
args: ['build', '-t', 'europe-west2-docker.pkg.dev/$PROJECT_ID/platform-infrastructure/cloudsql-proxy-is-up:$SHORT_SHA', '.']

images:
- 'europe-west2-docker.pkg.dev/$PROJECT_ID/platform-infrastructure/cloudsql-proxy-is-up:$SHORT_SHA'
tags: ['cloudsql-proxy-is-up']

logsBucket: lh-cloud-build-logs
5 changes: 5 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module github.com/loveholidays/cloudsql-proxy-is-up

go 1.15

require github.com/cenk/backoff v2.2.1+incompatible
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
github.com/cenk/backoff v2.2.1+incompatible h1:djdFT7f4gF2ttuzRKPbMOWgZajgesItGLwG5FTQKmmE=
github.com/cenk/backoff v2.2.1+incompatible/go.mod h1:7FtoeaSnHoZnmZzz47cM35Y9nSW7tNyaidugnHTaFDE=
116 changes: 116 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package main

import (
"errors"
"fmt"
"os"
"os/exec"
"os/signal"
"strings"
"net"
"time"
"github.com/cenk/backoff"
)

type ServerInfo struct {
State string `json:"state"`
}

func main() {
// Should be in format `http://127.0.0.1:9010`
host, ok := os.LookupEnv("CLOUDSQL_PROXY_API")
if ok && os.Getenv("START_WITHOUT_CLOUDSQL_PROXY_API") != "true" {
block(host)
}

if len(os.Args) < 2 {
return
}

binary, err := exec.LookPath(os.Args[1])
if err != nil {
panic(err)
}

var proc *os.Process

// Pass signals to the child process
go func() {
stop := make(chan os.Signal, 2)
signal.Notify(stop)
for sig := range stop {
if proc != nil {
proc.Signal(sig)
} else {
// Signal received before the process even started. Let's just exit.
os.Exit(1)
}
}
}()

proc, err = os.StartProcess(binary, os.Args[1:], &os.ProcAttr{
Files: []*os.File{os.Stdin, os.Stdout, os.Stderr},
})
if err != nil {
panic(err)
}

state, err := proc.Wait()
if err != nil {
panic(err)
}

exitCode := state.ExitCode()

switch {
case !ok:
// We don't have an CLOUDSQL_PROXY_API env var, do nothing
case !strings.Contains(host, "127.0.0.1") && !strings.Contains(host, "localhost"):
// Cloud SQL Proxy is not local; do nothing
}

os.Exit(exitCode)
}

func block(host string) {
if os.Getenv("START_WITHOUT_CLOUDSQL_PROXY_API") == "true" {
return
}

b := backoff.NewExponentialBackOff()
// We wait forever for Cloud SQL Proxy to start. In practice k8s will kill the pod if we take too long.
b.MaxElapsedTime = 0



_ = backoff.Retry(func() error {
timeout := time.Second
conn, err := net.DialTimeout("tcp", host, timeout)

if conn != nil {
defer conn.Close()
fmt.Println("Opened", host)
} else {
fmt.Println("Cloud SQL Proxy not live yet")
}

if err != nil {
return errors.New("Cloud SQL Proxy not live yet")
}

return nil
}, b)
}

func raw_connect(host string, port string) {

timeout := time.Second
conn, err := net.DialTimeout("tcp", net.JoinHostPort(host, port), timeout)
if err != nil {
fmt.Println("Connecting error:", err)
}
if conn != nil {
defer conn.Close()
fmt.Println("Opened", net.JoinHostPort(host, port))
}
}

0 comments on commit 7f00922

Please sign in to comment.