Skip to content

Commit

Permalink
feat: add flag to specify API endpoint (GoogleCloudPlatform#67)
Browse files Browse the repository at this point in the history
  • Loading branch information
nancynh authored Jul 14, 2022
1 parent 16a85b5 commit c63b7b4
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 7 deletions.
14 changes: 14 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,8 @@ When this flag is not set, there is no limit.`)
to close after receiving a TERM signal. The proxy will shut
down when the number of open connections reaches 0 or when
the maximum time has passed. Defaults to 0s.`)
cmd.PersistentFlags().StringVar(&c.conf.APIEndpointURL, "alloydbadmin-api-endpoint", "https://alloydb.googleapis.com/v1beta",
"When set, the proxy uses this host as the base API path.")

cmd.PersistentFlags().StringVar(&c.telemetryProject, "telemetry-project", "",
"Enable Cloud Monitoring and Cloud Trace integration with the provided project ID.")
Expand Down Expand Up @@ -226,6 +228,18 @@ func parseConfig(cmd *Command, conf *proxy.Config, args []string) error {
if conf.CredentialsFile != "" && conf.GcloudAuth {
return newBadCommandError("cannot specify --credentials-file and --gcloud-auth flags at the same time")
}
if userHasSet("alloydbadmin-api-endpoint") {
_, err := url.Parse(conf.APIEndpointURL)
if err != nil {
return newBadCommandError(fmt.Sprintf("provided value for --alloydbadmin-api-endpoint is not a valid url, %v", conf.APIEndpointURL))
}

// Remove trailing '/' if included
if strings.HasSuffix(conf.APIEndpointURL, "/") {
conf.APIEndpointURL = strings.TrimSuffix(conf.APIEndpointURL, "/")
}
cmd.logger.Infof("Using API Endpoint %v", conf.APIEndpointURL)
}

if userHasSet("http-port") && !userHasSet("prometheus-namespace") {
return newBadCommandError("cannot specify --http-port without --prometheus-namespace")
Expand Down
21 changes: 21 additions & 0 deletions cmd/root_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ func TestNewCommandArguments(t *testing.T) {
if i := &c.Instances[0]; i.Name == "" {
i.Name = "/projects/proj/locations/region/clusters/clust/instances/inst"
}
if c.APIEndpointURL == "" {
c.APIEndpointURL = "https://alloydb.googleapis.com/v1beta"
}
return c
}
tcs := []struct {
Expand Down Expand Up @@ -184,6 +187,20 @@ func TestNewCommandArguments(t *testing.T) {
StructuredLogs: true,
}),
},
{
desc: "using the alloydbadmin-api-endpoint flag with the trailing slash",
args: []string{"--alloydbadmin-api-endpoint", "https://test.googleapis.com/", "/projects/proj/locations/region/clusters/clust/instances/inst"},
want: withDefaults(&proxy.Config{
APIEndpointURL: "https://test.googleapis.com",
}),
},
{
desc: "using the alloydbadmin-api-endpoint flag without the trailing slash",
args: []string{"--alloydbadmin-api-endpoint", "https://test.googleapis.com", "/projects/proj/locations/region/clusters/clust/instances/inst"},
want: withDefaults(&proxy.Config{
APIEndpointURL: "https://test.googleapis.com",
}),
},
}

for _, tc := range tcs {
Expand Down Expand Up @@ -337,6 +354,10 @@ func TestNewCommandWithErrors(t *testing.T) {
desc: "enabling a Prometheus port without a namespace",
args: []string{"--http-port", "1111", "proj:region:inst"},
},
{
desc: "using an invalid url for host flag",
args: []string{"--host", "https://invalid:url[/]", "proj:region:inst"},
},
}

for _, tc := range tcs {
Expand Down
6 changes: 5 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ require (
github.com/spf13/cobra v1.5.0
go.opencensus.io v0.23.0
go.uber.org/zap v1.21.0
golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2
golang.org/x/net v0.0.0-20220708220712-1185a9018129 // indirect
golang.org/x/oauth2 v0.0.0-20220630143837-2104d58473e0
golang.org/x/sys v0.0.0-20220712014510-0a85c31ab51e
google.golang.org/api v0.87.0 // indirect
google.golang.org/genproto v0.0.0-20220712132514-bdd2acd4974d // indirect
google.golang.org/grpc v1.48.0 // indirect
)
15 changes: 10 additions & 5 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1350,8 +1350,9 @@ golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su
golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e h1:TsQ7F31D3bUCLeqPT0u+yjp1guoArKaNKmCr22PYgTQ=
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220708220712-1185a9018129 h1:vucSRfWwTsoXro7P+3Cjlr6flUMtzCwzlvkxEQtHHB0=
golang.org/x/net v0.0.0-20220708220712-1185a9018129/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
Expand All @@ -1372,8 +1373,9 @@ golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2 h1:+jnHzr9VPj32ykQVai5DNahi9+NSp7yYuCsl5eAQtL0=
golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
golang.org/x/oauth2 v0.0.0-20220630143837-2104d58473e0 h1:VnGaRqoLmqZH/3TMLJwYCEWkR4j1nuIU1U9TvbqsDUw=
golang.org/x/oauth2 v0.0.0-20220630143837-2104d58473e0/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
Expand Down Expand Up @@ -1676,8 +1678,9 @@ google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69
google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw=
google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg=
google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o=
google.golang.org/api v0.86.0 h1:ZAnyOHQFIuWso1BodVfSaRyffD74T9ERGFa3k1fNk/U=
google.golang.org/api v0.86.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw=
google.golang.org/api v0.87.0 h1:pUQVF/F+X7Tl1lo4LJoJf5BOpjtmINU80p9XpYTU2p4=
google.golang.org/api v0.87.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
Expand Down Expand Up @@ -1775,8 +1778,9 @@ google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP
google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
google.golang.org/genproto v0.0.0-20220627151210-f754eecb4be7 h1:Mv5rePwTdFhAcnC6zznhkrXLz1okln7fXAVh/J7t/gQ=
google.golang.org/genproto v0.0.0-20220627151210-f754eecb4be7/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
google.golang.org/genproto v0.0.0-20220712132514-bdd2acd4974d h1:YbuF5+kdiC516xIP60RvlHeFbY9sRDR73QsAGHpkeVw=
google.golang.org/genproto v0.0.0-20220712132514-bdd2acd4974d/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
Expand Down Expand Up @@ -1813,8 +1817,9 @@ google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ5
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/grpc v1.47.0 h1:9n77onPX5F3qfFCqjy9dhn8PbNQsIKeVU04J9G7umt8=
google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/grpc v1.48.0 h1:rQOsyJ/8+ufEDJd/Gdsz7HG220Mh9HAhFHRGnIjda0w=
google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
Expand Down
6 changes: 5 additions & 1 deletion internal/proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ type Config struct {
// connected to any Instances. If set, takes precedence over Addr and Port.
UnixSocket string

// APIEndpointURL is the URL of the AlloyDB Admin API.
APIEndpointURL string

// Instances are configuration for individual instances. Instance
// configuration takes precedence over global configuration.
Instances []InstanceConnConfig
Expand All @@ -100,6 +103,7 @@ func (c *Config) DialerOptions(l alloydb.Logger) ([]alloydbconn.Option, error) {
opts := []alloydbconn.Option{
alloydbconn.WithUserAgent(c.UserAgent),
}
opts = append(opts, alloydbconn.WithAdminAPIEndpoint(c.APIEndpointURL))
switch {
case c.Token != "":
l.Infof("Authorizing with the -token flag")
Expand Down Expand Up @@ -217,7 +221,7 @@ func NewClient(ctx context.Context, d alloydb.Dialer, l alloydb.Logger, conf *Co
return nil, fmt.Errorf("[%v] Unable to mount socket: %v", inst.Name, err)
}

l.Infof("[%s] Listening on %s\n", inst.Name, m.Addr())
l.Infof("[%s] Listening on %s", inst.Name, m.Addr())
mnts = append(mnts, m)
}

Expand Down
66 changes: 66 additions & 0 deletions internal/proxy/proxy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import (
"io"
"io/ioutil"
"net"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"sync"
Expand Down Expand Up @@ -459,3 +461,67 @@ func TestClientInitializationWorksRepeatedly(t *testing.T) {
}
c.Close()
}

type spyHandler struct {
once sync.Once
done chan struct{}
}

func (s *spyHandler) ServeHTTP(res http.ResponseWriter, req *http.Request) {
s.once.Do(func() { close(s.done) })
res.WriteHeader(http.StatusNotImplemented)
}

func (s *spyHandler) wasCalled() bool {
select {
case <-s.done:
return true
default:
return false
}
}

func TestClientInitializationWithCustomHost(t *testing.T) {
if testing.Short() {
t.Skip("skipping client initialization test that requires valid credentials")
}
spy := &spyHandler{done: make(chan struct{})}
s := httptest.NewServer(spy)
in := &proxy.Config{
Instances: []proxy.InstanceConnConfig{
{Name: "projects/proj/locations/region/clusters/clust/instances/inst1"},
},
APIEndpointURL: s.URL,
Port: 7000,
}
logger := log.NewStdLogger(os.Stdout, os.Stdout)
c, err := proxy.NewClient(context.Background(), nil, logger, in)
if err != nil {
t.Fatalf("want error = nil, got = %v", err)
}
defer c.Close()

go c.Serve(context.Background())

conn := tryTCPDial(t, "localhost:7000")
defer conn.Close()

spyWasCalled := func(t *testing.T) {
var attempts int
for {
if attempts > 10 {
t.Fatal("expected spy API Handler to have been called, but it was not")
return
}
if !spy.wasCalled() {
t.Logf("spy API Handler was not called after %v attempts", attempts)
attempts++
time.Sleep(100 * time.Millisecond)
continue
}
return
}
}

spyWasCalled(t)
}

0 comments on commit c63b7b4

Please sign in to comment.