Skip to content

Commit

Permalink
feat: fail on startup if instance uri is invalid (#210)
Browse files Browse the repository at this point in the history
  • Loading branch information
kurtisvg committed Dec 14, 2022
1 parent f275bcf commit 49b9efd
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 14 deletions.
12 changes: 7 additions & 5 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -534,13 +534,15 @@ func parseConfig(cmd *Command, conf *proxy.Config, args []string) error {

var ics []proxy.InstanceConnConfig
for _, a := range args {
// Assume no query params initially
ic := proxy.InstanceConnConfig{
Name: a,
// split into instance uri and query parameters
res := strings.SplitN(a, "?", 2)
_, _, _, _, err := proxy.ParseInstanceURI(res[0])
if err != nil {
return newBadCommandError(fmt.Sprintf("could not parse instance uri: %q", res[0]))
}
ic := proxy.InstanceConnConfig{Name: res[0]}
// If there are query params, update instance config.
if res := strings.SplitN(a, "?", 2); len(res) > 1 {
ic.Name = res[0]
if len(res) > 1 {
q, err := url.ParseQuery(res[1])
if err != nil {
return newBadCommandError(fmt.Sprintf("could not parse query: %q", res[1]))
Expand Down
6 changes: 5 additions & 1 deletion cmd/root_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,10 @@ func TestNewCommandWithErrors(t *testing.T) {
desc: "basic invocation missing instance connection name",
args: []string{},
},
{
desc: "when the instance uri is bogus",
args: []string{"projects/proj/locations/region/clusters/clust/"},
},
{
desc: "when the query string is bogus",
args: []string{"projects/proj/locations/region/clusters/clust/instances/inst?%=foo"},
Expand Down Expand Up @@ -832,7 +836,7 @@ func TestPrometheusMetricsEndpoint(t *testing.T) {
// Keep the test output quiet
c.SilenceUsage = true
c.SilenceErrors = true
c.SetArgs([]string{"--prometheus", "my-project:my-region:my-instance"})
c.SetArgs([]string{"--prometheus", "projects/my-project/locations/my-region/clusters/my-cluster/instances/my-instance"})

ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
Expand Down
21 changes: 13 additions & 8 deletions internal/proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,24 +235,29 @@ var (
unixRegex = regexp.MustCompile(`([^:]+(?:-[^:]+)?)\.(.+)\.(.+)\.(.+)`)
)

// ParseInstanceURI validates the instance uri is in the proper format and
// returns the project, region, cluster, and instance name.
func ParseInstanceURI(inst string) (string, string, string, string, error) {
m := instURIRegex.FindSubmatch([]byte(inst))
if m == nil {
return "", "", "", "", fmt.Errorf("invalid instance name: %v", inst)
}
return string(m[1]), string(m[2]), string(m[3]), string(m[4]), nil
}

// UnixSocketDir returns a shorted instance connection name to prevent
// exceeding the Unix socket length, e.g., project.region.cluster.instance
func UnixSocketDir(dir, inst string) (string, error) {
inst = strings.ToLower(inst)
m := instURIRegex.FindSubmatch([]byte(inst))
if m == nil {
return "", fmt.Errorf("invalid instance name: %v", inst)
project, region, cluster, name, err := ParseInstanceURI(strings.ToLower(inst))
if err != nil {
return "", err
}
project := string(m[1])
// Colons are not allowed on Windows, but are present in legacy project
// names (e.g., google.com:myproj). Replace any colon with an underscore to
// support Windows. Underscores are not allowed in project names. So use an
// underscore to have a Windows-friendly delimitor that can serve as a
// marker to recover the legacy project name when necessary (e.g., FUSE).
project = strings.ReplaceAll(project, ":", "_")
region := string(m[2])
cluster := string(m[3])
name := string(m[4])
shortName := strings.Join([]string{project, region, cluster, name}, ".")
return filepath.Join(dir, shortName), nil
}
Expand Down

0 comments on commit 49b9efd

Please sign in to comment.