in dialer.go [203:323]
func NewDialer(ctx context.Context, opts ...Option) (*Dialer, error) {
cfg := &dialerConfig{
refreshTimeout: cloudsql.RefreshTimeout,
dialFunc: proxy.Dial,
logger: nullLogger{},
useragents: []string{userAgent},
failoverPeriod: cloudsql.FailoverPeriod,
}
for _, opt := range opts {
opt(cfg)
if cfg.err != nil {
return nil, cfg.err
}
}
if cfg.useIAMAuthN && cfg.setTokenSource && !cfg.setIAMAuthNTokenSource {
return nil, errUseIAMTokenSource
}
if cfg.setIAMAuthNTokenSource && !cfg.useIAMAuthN {
return nil, errUseTokenSource
}
// If callers have not provided a credential source, either explicitly with
// WithTokenSource or implicitly with WithCredentialsJSON etc., then use
// default credentials
if !cfg.setCredentials {
c, err := credentials.DetectDefault(&credentials.DetectOptions{
Scopes: []string{sqladmin.SqlserviceAdminScope},
})
if err != nil {
return nil, fmt.Errorf("failed to create default credentials: %v", err)
}
cfg.authCredentials = c
// create second set of credentials, scoped for IAM AuthN login only
scoped, err := credentials.DetectDefault(&credentials.DetectOptions{
Scopes: []string{iamLoginScope},
})
if err != nil {
return nil, fmt.Errorf("failed to create scoped credentials: %v", err)
}
cfg.iamLoginTokenProvider = scoped.TokenProvider
}
// For all credential paths, use auth library's built-in
// httptransport.NewClient
if cfg.authCredentials != nil {
// Set headers for auth client as below WithHTTPClient will ignore
// WithQuotaProject and WithUserAgent Options
headers := http.Header{}
headers.Set("User-Agent", strings.Join(cfg.useragents, " "))
if cfg.quotaProject != "" {
headers.Set("X-Goog-User-Project", cfg.quotaProject)
}
authClient, err := httptransport.NewClient(&httptransport.Options{
Headers: headers,
Credentials: cfg.authCredentials,
UniverseDomain: cfg.getClientUniverseDomain(),
})
if err != nil {
return nil, fmt.Errorf("failed to create auth client: %v", err)
}
// If callers have not provided an HTTPClient explicitly with
// WithHTTPClient, then use auth client
if !cfg.setHTTPClient {
cfg.sqladminOpts = append(cfg.sqladminOpts, option.WithHTTPClient(authClient))
}
} else {
// Add this to the end to make sure it's not overridden
cfg.sqladminOpts = append(cfg.sqladminOpts, option.WithUserAgent(strings.Join(cfg.useragents, " ")))
if cfg.quotaProject != "" {
cfg.sqladminOpts = append(cfg.sqladminOpts, option.WithQuotaProject(cfg.quotaProject))
}
}
client, err := sqladmin.NewService(ctx, cfg.sqladminOpts...)
if err != nil {
return nil, fmt.Errorf("failed to create sqladmin client: %v", err)
}
dc := dialConfig{
ipType: cloudsql.PublicIP,
tcpKeepAlive: defaultTCPKeepAlive,
useIAMAuthN: cfg.useIAMAuthN,
}
for _, opt := range cfg.dialOpts {
opt(&dc)
}
if err := trace.InitMetrics(); err != nil {
return nil, err
}
g, err := newKeyGenerator(cfg.rsaKey, cfg.lazyRefresh,
func() (*rsa.PrivateKey, error) {
return rsa.GenerateKey(rand.Reader, 2048)
})
if err != nil {
return nil, err
}
var r instance.ConnectionNameResolver = cloudsql.DefaultResolver
if cfg.resolver != nil {
r = cfg.resolver
}
d := &Dialer{
closed: make(chan struct{}),
cache: make(map[cacheKey]*monitoredCache),
lazyRefresh: cfg.lazyRefresh,
keyGenerator: g,
refreshTimeout: cfg.refreshTimeout,
sqladmin: client,
logger: cfg.logger,
defaultDialConfig: dc,
dialerID: uuid.New().String(),
iamTokenProvider: cfg.iamLoginTokenProvider,
dialFunc: cfg.dialFunc,
resolver: r,
failoverPeriod: cfg.failoverPeriod,
}
return d, nil
}