vitess.io/vitess@v0.16.2/go/vt/vtadmin/vtsql/config.go (about) 1 /* 2 Copyright 2020 The Vitess Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package vtsql 18 19 import ( 20 "database/sql" 21 "fmt" 22 23 "github.com/spf13/pflag" 24 25 "vitess.io/vitess/go/vt/grpcclient" 26 "vitess.io/vitess/go/vt/vitessdriver" 27 "vitess.io/vitess/go/vt/vtadmin/cluster/discovery" 28 "vitess.io/vitess/go/vt/vtadmin/cluster/resolver" 29 "vitess.io/vitess/go/vt/vtadmin/credentials" 30 31 vtadminpb "vitess.io/vitess/go/vt/proto/vtadmin" 32 ) 33 34 // Config represents the options that modify the behavior of a vtqsl.VTGateProxy. 35 type Config struct { 36 Credentials Credentials 37 // CredentialsPath is used only to power vtadmin debug endpoints; there may 38 // be a better way where we don't need to put this in the config, because 39 // it's not really an "option" in normal use. 40 CredentialsPath string 41 42 Cluster *vtadminpb.Cluster 43 ResolverOptions *resolver.Options 44 45 dialFunc func(c vitessdriver.Configuration) (*sql.DB, error) 46 } 47 48 // ConfigOption is a function that mutates a Config. It should return the same 49 // Config structure, in a builder-pattern style. 50 type ConfigOption func(cfg *Config) *Config 51 52 // WithDialFunc returns a ConfigOption that applies the given dial function to 53 // a Config. 54 // 55 // It is used to support dependency injection in tests, and needs to be exported 56 // for higher-level tests (for example, package vtadmin/cluster). 57 func WithDialFunc(f func(c vitessdriver.Configuration) (*sql.DB, error)) ConfigOption { 58 return func(cfg *Config) *Config { 59 cfg.dialFunc = f 60 return cfg 61 } 62 } 63 64 // Parse returns a new config with the given cluster ID and name, after 65 // attempting to parse the command-line pflags into that Config. See 66 // (*Config).Parse() for more details. 67 func Parse(cluster *vtadminpb.Cluster, disco discovery.Discovery, args []string) (*Config, error) { 68 cfg := &Config{ 69 Cluster: cluster, 70 ResolverOptions: &resolver.Options{ 71 Discovery: disco, 72 }, 73 } 74 75 err := cfg.Parse(args) 76 if err != nil { 77 return nil, err 78 } 79 80 return cfg, nil 81 } 82 83 // Parse reads options specified as command-line pflags (--key=value, note the 84 // double-dash!) into a vtsql.Config. It is meant to be called from 85 // (*cluster.Cluster).New(). 86 func (c *Config) Parse(args []string) error { 87 fs := pflag.NewFlagSet("", pflag.ContinueOnError) 88 89 if c.ResolverOptions == nil { 90 c.ResolverOptions = &resolver.Options{} 91 } 92 93 c.ResolverOptions.InstallFlags(fs) 94 95 credentialsTmplStr := fs.String("credentials-path-tmpl", "", 96 "Go template used to specify a path to a credentials file, which is a json file containing "+ 97 "a Username and Password. Templates are given the context of the vtsql.Config, and primarily "+ 98 "interoplate the cluster name and ID variables.") 99 effectiveUser := fs.String("effective-user", "", "username to send queries on behalf of") 100 101 if err := fs.Parse(args); err != nil { 102 return err 103 } 104 105 var creds *grpcclient.StaticAuthClientCreds 106 107 if *credentialsTmplStr != "" { 108 _creds, path, err := credentials.LoadFromTemplate(*credentialsTmplStr, c) 109 if err != nil { 110 return fmt.Errorf("cannot load credentials from path template %s: %w", *credentialsTmplStr, err) 111 } 112 113 c.CredentialsPath = path 114 creds = _creds 115 } 116 117 if creds != nil { 118 // If we did not receive an effective user, but loaded credentials, then the 119 // immediate user is the effective user. 120 if *effectiveUser == "" { 121 *effectiveUser = creds.Username 122 } 123 124 c.Credentials = &StaticAuthCredentials{ 125 EffectiveUser: *effectiveUser, 126 StaticAuthClientCreds: creds, 127 } 128 } 129 130 return nil 131 }