Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add vtsql flags to vtadmin #13674

Merged
merged 8 commits into from
Aug 31, 2023
11 changes: 10 additions & 1 deletion doc/vtadmin/clusters.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,16 @@ defaults:
vtsql-discovery-tags: "tag1,tag2"
# Username to send queries on behalf of. See package callerid.
vtsql-effective-user: "my-effective-user"

# Username used to make requests against vtgates in the cluster. Can be used with
# vtsql-credentials-password in place of vtsql-credentials-path-tmpl.
# If both vtsql-credentials-username and vtsql-credentials-path-tmpl are
# provided, vtsql-credentials-username takes precedent over username from vtsql-credentials-path-tmpl.
vtsql-credentials-username: "my-username"
# Password used to make requests against vtgates in the cluster. Used with
# vtsql-credentials-username in place of vtsql-credentials-path-tmpl.
# If both vtsql-credentials-password and vtsql-credentials-path-tmpl are
# provided, vtsql-credentials-password takes precedent over password from vtsql-credentials-path-tmpl.
vtsql-credentials-password: "my-password"
# VTAdmin also provides different RPC pools to gate the number of concurrent
# requests it will make against vtctlds/vtgates in a given cluster, to prevent
# overwhelming those components.
Expand Down
47 changes: 34 additions & 13 deletions go/vt/vtadmin/vtsql/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,34 +97,55 @@ func (c *Config) Parse(args []string) error {
"a Username and Password. Templates are given the context of the vtsql.Config, and primarily "+
"interoplate the cluster name and ID variables.")
effectiveUser := fs.String("effective-user", "", "username to send queries on behalf of")

credentialsUsername := fs.String("credentials-username", "",
"A string specifying the Username to use for authenticating with vtgate. "+
"Used with credentials-password in place of credentials-path-tmpl, in cases where providing a static file cannot be done.")
credentialsPassword := fs.String("credentials-password", "",
"A string specifying a Password to use for authenticating with vtgate. "+
"Used with credentials-username in place of credentials-path-tmpl, in cases where providing a static file cannot be done.")
if err := fs.Parse(args); err != nil {
return err
}

var creds *grpcclient.StaticAuthClientCreds
var username, password string

// First load credentials from credentials-path-tmpl, if provided
var tmplStrCreds *grpcclient.StaticAuthClientCreds
if *credentialsTmplStr != "" {
_creds, path, err := credentials.LoadFromTemplate(*credentialsTmplStr, c)
if err != nil {
return fmt.Errorf("cannot load credentials from path template %s: %w", *credentialsTmplStr, err)
}

c.CredentialsPath = path
creds = _creds
tmplStrCreds = _creds
}
if tmplStrCreds != nil {
username = tmplStrCreds.Username
password = tmplStrCreds.Password
}

if creds != nil {
// If we did not receive an effective user, but loaded credentials, then the
// immediate user is the effective user.
if *effectiveUser == "" {
*effectiveUser = creds.Username
}
// If credentials-username and credentials-password are provided, use those credentials instead
if *credentialsUsername != "" {
username = *credentialsUsername
}
if *credentialsPassword != "" {
password = *credentialsPassword
}

c.Credentials = &StaticAuthCredentials{
EffectiveUser: *effectiveUser,
StaticAuthClientCreds: creds,
}
// If we did not receive an effective user, but loaded user credentials, then the
// immediate user is the effective user.
if *effectiveUser == "" {
*effectiveUser = username
}

// Set credentials to values potentially supplied by credentials-password and credentials-username
c.Credentials = &StaticAuthCredentials{
EffectiveUser: *effectiveUser,
StaticAuthClientCreds: &grpcclient.StaticAuthClientCreds{
Username: username,
Password: password,
},
}

return nil
Expand Down
91 changes: 91 additions & 0 deletions go/vt/vtadmin/vtsql/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,97 @@ func TestConfigParse(t *testing.T) {
assert.Equal(t, expectedCreds, cfg.Credentials)
})

t.Run("uses vtsql-credentials-password", func(t *testing.T) {
t.Parallel()

f, err := os.CreateTemp("", "vtsql-config-test-testcluster-*") // testcluster is going to appear in the template
require.NoError(t, err)

_, err = f.Write([]byte(`{
"Username": "vtadmin",
"Password": "hunter2"
}`))
require.NoError(t, err)

path := f.Name()
defer os.Remove(path)
f.Close()

dir := filepath.Dir(path)
baseParts := strings.Split(filepath.Base(path), "-")
tmplParts := append(baseParts[:3], "{{ .Cluster.Name }}", baseParts[4])

cfg := &Config{
Cluster: &vtadminpb.Cluster{
Name: "testcluster",
},
}

credsTmplStr := filepath.Join(dir, strings.Join(tmplParts, "-"))

args := []string{
"--discovery-tags=a:1,b:2",
"--effective-user=vt_appdebug",
"--discovery-tags=c:3",
"--credentials-password=my_password",
fmt.Sprintf("--credentials-path-tmpl=%s", credsTmplStr),
}

expectedCreds := &StaticAuthCredentials{
EffectiveUser: "vt_appdebug",
StaticAuthClientCreds: &grpcclient.StaticAuthClientCreds{
Username: "vtadmin",
Password: "my_password",
},
}
expectedTags := []string{
"a:1",
"b:2",
"c:3",
}

err = cfg.Parse(args)
assert.NoError(t, err)
assert.Equal(t, expectedTags, cfg.ResolverOptions.DiscoveryTags)
assert.Equal(t, expectedCreds, cfg.Credentials)
})

t.Run("it uses vtsql credentials passed as flags", func(t *testing.T) {
t.Parallel()

cfg := &Config{
Cluster: &vtadminpb.Cluster{
Name: "testcluster",
},
}

args := []string{
"--discovery-tags=a:1,b:2",
"--effective-user=vt_appdebug",
"--discovery-tags=c:3",
"--credentials-username=vtadmin",
"--credentials-password=my_password",
}

expectedCreds := &StaticAuthCredentials{
EffectiveUser: "vt_appdebug",
StaticAuthClientCreds: &grpcclient.StaticAuthClientCreds{
Username: "vtadmin",
Password: "my_password",
},
}
expectedTags := []string{
"a:1",
"b:2",
"c:3",
}

err = cfg.Parse(args)
assert.NoError(t, err)
assert.Equal(t, expectedTags, cfg.ResolverOptions.DiscoveryTags)
assert.Equal(t, expectedCreds, cfg.Credentials)
})

t.Run("", func(t *testing.T) {
t.Parallel()

Expand Down
Loading