in internal/cloudsql/refresh.go [59:169]
func fetchMetadata(
ctx context.Context, client *sqladmin.Service, inst instance.ConnName,
) (m metadata, err error) {
var end trace.EndSpanFunc
ctx, end = trace.StartSpan(ctx, "cloud.google.com/go/cloudsqlconn/internal.FetchMetadata")
defer func() { end(err) }()
db, err := retry50x(ctx, func(ctx2 context.Context) (*sqladmin.ConnectSettings, error) {
return client.Connect.Get(
inst.Project(), inst.Name(),
).Context(ctx2).Do()
}, exponentialBackoff)
if err != nil {
return metadata{}, errtype.NewRefreshError("failed to get instance metadata", inst.String(), err)
}
// validate the instance is supported for authenticated connections
if db.Region != inst.Region() {
msg := fmt.Sprintf(
"provided region was mismatched - got %s, want %s",
inst.Region(), db.Region,
)
return metadata{}, errtype.NewConfigError(msg, inst.String())
}
if db.BackendType != "SECOND_GEN" {
return metadata{}, errtype.NewConfigError(
"unsupported instance - only Second Generation instances are supported",
inst.String(),
)
}
// parse any ip addresses that might be used to connect
ipAddrs := make(map[string]string)
for _, ip := range db.IpAddresses {
switch ip.Type {
case "PRIMARY":
ipAddrs[PublicIP] = ip.IpAddress
case "PRIVATE":
ipAddrs[PrivateIP] = ip.IpAddress
}
}
// resolve DnsName into IP address for PSC
// Note that we have to check for PSC enablement first because CAS instances also set the DnsName.
if db.PscEnabled {
// Search the dns_names field for the PSC DNS Name.
pscDNSName := ""
for _, dnm := range db.DnsNames {
if dnm.Name != "" &&
dnm.ConnectionType == "PRIVATE_SERVICE_CONNECT" && dnm.DnsScope == "INSTANCE" {
pscDNSName = dnm.Name
break
}
}
// If the psc dns name was not found, use the legacy dns_name field
if pscDNSName == "" && db.DnsName != "" {
pscDNSName = db.DnsName
}
// If the psc dns name was found, add it to the ipaddrs map.
if pscDNSName != "" {
ipAddrs[PSC] = pscDNSName
}
}
if len(ipAddrs) == 0 {
return metadata{}, errtype.NewConfigError(
"cannot connect to instance - it has no supported IP addresses",
inst.String(),
)
}
// parse the server-side CA certificate
caCerts := []*x509.Certificate{}
for b, rest := pem.Decode([]byte(db.ServerCaCert.Cert)); b != nil; b, rest = pem.Decode(rest) {
if b == nil {
return metadata{}, errtype.NewRefreshError("failed to decode valid PEM cert", inst.String(), nil)
}
caCert, err := x509.ParseCertificate(b.Bytes)
if err != nil {
return metadata{}, errtype.NewRefreshError(
fmt.Sprintf("failed to parse as X.509 certificate: %v", err),
inst.String(),
nil,
)
}
caCerts = append(caCerts, caCert)
}
// Find a DNS name to use to validate the certificate from the dns_names field. Any
// name in the list may be used to validate the server TLS certificate.
// Fall back to legacy dns_name field if necessary.
var serverName string
if len(db.DnsNames) > 0 {
serverName = db.DnsNames[0].Name
}
if serverName == "" {
serverName = db.DnsName
}
m = metadata{
ipAddrs: ipAddrs,
serverCACert: caCerts,
version: db.DatabaseVersion,
dnsName: serverName,
serverCAMode: db.ServerCaMode,
}
return m, nil
}